From 6f0134bf5db7d7f658406f4625af962e216c51df Mon Sep 17 00:00:00 2001 From: clawbot <35+clawbot@noreply.example.org> Date: Fri, 2 Oct 2026 04:14:50 +0000 Subject: [PATCH] Stamp the git tag or short commit in a plain docker build (closes #46) A plain `docker build .` stamped `unknown` into the page footer: .dockerignore left out .git, and the Dockerfile built without the -X flags. The context now carries .git without .git/config, which can hold a credential. The build stage takes the VERSION build argument when one is given, otherwise `git describe --tags --always`, fails the build if .git is present and no version comes out, and stamps it together with the full commit the footer links to. `make build` now uses `git describe` as well, and script/docker is the current shared copy. Model: opus-5-5 --- .dockerignore | 6 +++++- Dockerfile | 19 +++++++++++++++++-- Makefile | 2 +- TODO.md | 5 +++++ internal/version/version.go | 3 ++- script/docker | 13 +++++++++++-- 6 files changed, 41 insertions(+), 7 deletions(-) diff --git a/.dockerignore b/.dockerignore index 063d4cc..89e43ce 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,7 +1,11 @@ # Docker does not read .gitignore, and a pattern here matches from the root of # the build context only: a pattern meant for every directory needs `**/`. -.git +# .git is sent without its config. Without a VERSION build argument the +# stage that compiles runs `git describe --tags --always` on .git, which +# does not need .git/config; that file can hold a credential, such as a +# password in a remote URL or the token the CI checkout step stores there. +.git/config # Local build and debug output: `make build`, `make run`, `make asupdate`, test # binaries, coverage profiles and source archives. diff --git a/Dockerfile b/Dockerfile index cedd1c9..dfd9d5a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,8 +40,23 @@ RUN go mod download && go mod vendor # installed above. The suite is offline (the live-feed test is opt-in). RUN make test -# Build the binary with CGO enabled (required for sqlite3) -RUN CGO_ENABLED=1 GOOS=linux go build -o /routewatch ./cmd/routewatch +# Build the binary with CGO enabled (required for sqlite3). The version the +# page footer shows is the VERSION build argument when one is given, otherwise +# `git describe --tags --always` of the .git in the build context (git comes +# with this image): the tag on a tagged commit, tag-N-gHASH after one, the +# short commit when no tag is reachable. A context that carries .git and still +# yields no version fails the build. The footer links to the full commit. +ARG VERSION +RUN version="${VERSION:-$(git describe --tags --always || echo unknown)}"; \ + if [ -e .git ] && { [ -z "$version" ] || [ "$version" = dev ] || \ + [ "$version" = unknown ]; }; then \ + echo "no version could be derived although the build context carries .git" >&2; \ + exit 1; \ + fi; \ + CGO_ENABLED=1 GOOS=linux go build -o /routewatch -ldflags "\ + -X git.eeqj.de/sneak/routewatch/internal/version.GitRevision=$(git rev-parse --verify HEAD || echo unknown) \ + -X git.eeqj.de/sneak/routewatch/internal/version.GitRevisionShort=$version" \ + ./cmd/routewatch # Create source archive with vendored dependencies RUN tar --zstd -cf /routewatch-source.tar.zst \ diff --git a/Makefile b/Makefile index 86fe21b..4c39949 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ export DEBUG = routewatch # Git revision for version embedding GIT_REVISION := $(shell git rev-parse HEAD 2>/dev/null || echo "unknown") -GIT_REVISION_SHORT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown") +GIT_REVISION_SHORT := $(shell git describe --tags --always 2>/dev/null || echo "unknown") VERSION_PKG := git.eeqj.de/sneak/routewatch/internal/version LDFLAGS := -X $(VERSION_PKG).GitRevision=$(GIT_REVISION) -X $(VERSION_PKG).GitRevisionShort=$(GIT_REVISION_SHORT) diff --git a/TODO.md b/TODO.md index b967d9a..b329b6e 100644 --- a/TODO.md +++ b/TODO.md @@ -28,6 +28,11 @@ The other open issue is https://git.eeqj.de/sneak/routewatch/issues/30. # Completed Steps +- 2026-10-02: a plain `docker build .` stamps the commit's tag or short + commit (`git describe --tags --always`) into the page footer instead of + `unknown`: `.dockerignore` sends `.git` without `.git/config`, a `VERSION` + build argument takes precedence, and `make build` stamps the same value + (closes #46) - 2026-09-29: the entrypoint creates the data directory if it is missing and stops the start if a step fails; README "Running under upaas" no longer asks for the host directory to be created first (closes #42) diff --git a/internal/version/version.go b/internal/version/version.go index 995c314..b32b2d8 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -7,7 +7,8 @@ package version var ( // GitRevision is the git commit hash GitRevision = "unknown" - // GitRevisionShort is the short git commit hash (7 chars) + // GitRevisionShort is the version the page footer shows: the tag or + // short commit hash from `git describe --tags --always` GitRevisionShort = "unknown" ) diff --git a/script/docker b/script/docker index 2884e41..07b626c 100755 --- a/script/docker +++ b/script/docker @@ -1,7 +1,8 @@ #!/bin/sh # script/docker: build the Docker image tagged with the project name. # Identical in all repos; the tag comes from script/projectname. -# Generic: needs no adaptation. +# --no-cache because the gate phases the final stage depends on are RUN +# steps, and a cached one is a check that did not run. set -eu SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)" @@ -9,7 +10,15 @@ ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)" main() { cd "$ROOT" - docker build -t "$("$SCRIPT_DIR/projectname")" . + # Own line: a failing command substitution inside an argument does + # not trip `set -e`, so the inline form degrades silently to an + # empty constant. The VERSION build argument takes precedence over + # the version a build stage derives from the .git in the context. + version="$(git describe --tags --always --dirty 2>/dev/null || true)" + [ -n "$version" ] || version="unknown" + docker build --no-cache \ + --build-arg VERSION="$version" \ + -t "$("$SCRIPT_DIR/projectname")" . } main "$@" -- 2.54.0