diff --git a/Makefile b/Makefile index d23221e..3e8bb4d 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -.PHONY: bootstrap setup test lint fmt fmt-check tidy check docker hooks build \ - run example-app gitea-requests gitea-setup +.PHONY: bootstrap setup test lint fmt fmt-check tidy check docker publish \ + hooks build run example-app gitea-requests gitea-setup # Makefile targets are thin shims; the implementations live in script/ # per the scripts-to-rule-them-all pattern (see the Entrypoints section @@ -7,7 +7,8 @@ # which test checks. build and run are for working on the code by hand; # example-app checks the image with an app built on it; gitea-requests # reports the gitea requests the Core Rule Set refuses at the defaults; -# gitea-setup checks the setup in deploy/gitea. +# gitea-setup checks the setup in deploy/gitea; publish builds the image +# on the Docker host and pushes it to the registry. bootstrap: @script/bootstrap @@ -36,6 +37,9 @@ check: docker: @script/docker +publish: + @script/publish + hooks: @script/install-precommit diff --git a/README.md b/README.md index bf6cdb6..8a848a9 100644 --- a/README.md +++ b/README.md @@ -743,6 +743,11 @@ on the host. `make check`. - `script/docker`: builds the image, whose build runs the tests and the linter first. `make docker`. +- `script/publish`: runs `script/docker` on the Docker host `DOCKER_HOST` + (`ssh://root@fsn1app1` unless set) and pushes the image to `PUBLISH_IMAGE` + (`git.eeqj.de/sneak/smallwebwaf` unless set) under four tags: the UTC date as + `YYYY-MM-DD`, the short commit hash, the branch name and `latest`. Refuses a + working tree with uncommitted changes. `make publish`. - `script/cibuild`: what CI runs: `script/bootstrap`, `script/check`, then the image build. - `script/precommit`: run by the git pre-commit hook; runs `script/check`. diff --git a/script/publish b/script/publish new file mode 100755 index 0000000..07a26ce --- /dev/null +++ b/script/publish @@ -0,0 +1,51 @@ +#!/bin/sh +# script/publish: build the image on the Docker host and push it to the +# registry under four tags: the UTC date (YYYY-MM-DD), the short commit +# hash, the branch name and latest. The build is script/docker's, so the +# tests and the linter run first. The host and the registry name are +# environment variables with defaults, for running it against another. +# +# The working tree must be clean: the hash tag names a commit, and an +# image built from uncommitted changes would carry a hash that does not +# describe it. +set -eu + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)" +ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)" + +: "${DOCKER_HOST:=ssh://root@fsn1app1}" +: "${PUBLISH_IMAGE:=git.eeqj.de/sneak/smallwebwaf}" +export DOCKER_HOST + +main() { + cd "$ROOT" + + if [ -n "$(git status --porcelain)" ]; then + echo "script/publish: the working tree is not clean; commit or stash first" >&2 + exit 1 + fi + + date="$(date -u +%Y-%m-%d)" + hash="$(git rev-parse --short HEAD)" + branch="$(git rev-parse --abbrev-ref HEAD)" + if [ "$branch" = "HEAD" ]; then + echo "script/publish: detached HEAD; check out a branch first" >&2 + exit 1 + fi + # A tag is [A-Za-z0-9_.-]; a branch name such as feature/x is not. + branch="$(printf '%s' "$branch" | tr -c 'A-Za-z0-9_.-' '-')" + + local_tag="$("$SCRIPT_DIR/projectname")" + "$SCRIPT_DIR/docker" + + for tag in "$date" "$hash" "$branch" latest; do + docker tag "$local_tag" "$PUBLISH_IMAGE:$tag" + done + for tag in "$date" "$hash" "$branch" latest; do + docker push "$PUBLISH_IMAGE:$tag" + done + + echo "pushed $PUBLISH_IMAGE with tags: $date $hash $branch latest" +} + +main "$@"