From 1b7a939c11011f7e6244ea9416dead37bd2d6449 Mon Sep 17 00:00:00 2001 From: clawbot Date: Fri, 2 Oct 2026 04:24:43 +0000 Subject: [PATCH] Stamp the tag or short commit in a plain docker build (closes #21) A plain `docker build .` of a clone stamped `dev`: `.dockerignore` left out `.git` and the build stage declared `ARG VERSION=dev`. `.git` now reaches the build context without `.git/config`, which can hold a credential, and the build stage takes the VERSION build argument when given, otherwise `git describe --tags --always`. A context that carries `.git` but yields no version fails the build. `script/docker` is replaced with the current canonical copy, which passes the version it derives on the host. Model: opus-5-5 --- .dockerignore | 7 ++++++- Dockerfile | 20 ++++++++++++++++---- docs/TODO.md | 4 ++++ script/docker | 13 +++++++++++-- 4 files changed, 37 insertions(+), 7 deletions(-) diff --git a/.dockerignore b/.dockerignore index 27510ca..c26fbd5 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,7 +3,6 @@ # an exclusion here makes them pass over a tree that is missing a # package. script/assert-context-complete exists to catch exactly that, # and will fail the build rather than let it happen silently. -.git/ .gitea/ bin/ data/ @@ -24,3 +23,9 @@ LICENSE .vscode/ tmp/ temp/ + +# .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 diff --git a/Dockerfile b/Dockerfile index a4ce457..2f1e27c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -72,10 +72,22 @@ RUN go test -count=1 -timeout 90s -race -cover ./... || \ go test -count=1 -timeout 90s -race -v ./...; exit 1; } # Static build, so the binary runs on any runtime base. -ARG VERSION=dev -RUN CGO_ENABLED=0 go build -trimpath \ - -ldflags "-s -w -X main.version=${VERSION}" \ - -o bin/simplexcalc ./cmd/simplexcalc +# +# The VERSION build arg when one is given, otherwise +# `git describe --tags --always` on the .git in the build context. With +# .git present, a version that is still empty, dev or unknown fails the +# build: git is missing or could not read the checkout. +ARG VERSION +RUN VERSION="${VERSION:-$(git describe --tags --always)}"; \ + if [ -e .git ]; then \ + case "$VERSION" in ""|dev|unknown) \ + echo "version is '$VERSION' although .git is present" >&2; \ + exit 1 ;; \ + esac; \ + fi; \ + CGO_ENABLED=0 go build -trimpath \ + -ldflags "-s -w -X main.version=${VERSION}" \ + -o bin/simplexcalc ./cmd/simplexcalc # Runtime stage, and the last one: script/cibuild passes no --target, so # BuildKit builds whichever stage is last and appending one drops lint, diff --git a/docs/TODO.md b/docs/TODO.md index 1c1ef96..323299e 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -27,6 +27,10 @@ with no deprecation warning. # Completed Steps +- 2026-10-02 A plain `docker build .` of a clone stamps the commit's tag + or short commit instead of `dev`: `.dockerignore` sends `.git` without + `.git/config`, and the build stage takes the `VERSION` build argument + when given, otherwise `git describe --tags --always` - 2026-09-29 Exact results past the range of a double, such as `2^1200`, are written to 17 significant digits instead of being refused, and a fractional power of such a number, such as `(2^1200)^0.5`, is answered 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 "$@"