diff --git a/Dockerfile b/Dockerfile index 711588c..a76cbb6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,8 +34,11 @@ COPY . . # Run the tests - build fails if any test fails RUN make test -# Build the binary -RUN make build +# Build the binary. .dockerignore leaves out .git, so `git describe` in +# the Makefile cannot find the version here: script/docker passes it as +# --build-arg VERSION, and a build that passes none reports `dev`. +ARG VERSION=dev +RUN make build VERSION="${VERSION}" # Runtime stage # alpine 3.21, 2026-02-28 diff --git a/Makefile b/Makefile index 7b2447f..5d36bc7 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ .PHONY: all bootstrap setup build lint fmt fmt-check test check clean hooks docker BINARY := dnswatcher +# `make build VERSION=...` overrides this; the Dockerfile does so, as the +# image has no .git to describe. VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev") LDFLAGS := -X main.Version=$(VERSION) diff --git a/README.md b/README.md index f971096..a074dbe 100644 --- a/README.md +++ b/README.md @@ -480,7 +480,8 @@ them. We provide: - `script/check` — run test, lint, and fmt-check - `script/docker` — build the Docker image tagged via `script/projectname`, with `--no-cache-filter=lint,builder` so the lint stage and the builder stage, - which runs the tests, run on every invocation + which runs the tests, run on every invocation, and with the version from + `git describe` passed as `--build-arg VERSION` - `script/cibuild` — CI entrypoint: `docker build` with `--no-cache-filter=lint,builder`, so the lint stage and the builder stage, which runs the tests, run on every invocation, because a cached build lints @@ -502,11 +503,14 @@ make clean # Remove build artifacts ### Build-Time Variables -Version is injected via `-ldflags`: +`make build` sets the version with `-ldflags "-X main.Version=..."`, taking +it from `git describe --tags --always --dirty`, or from `VERSION` when given +on the command line (`make build VERSION=1.2.3`). The version appears in the +startup log and in the health check response. -```sh -go build -ldflags "-X main.Version=$(git describe --tags --always)" ./cmd/dnswatcher -``` +The Docker image has no `.git`, so the `Dockerfile` takes the version as +`--build-arg VERSION`. `make docker` passes it; a plain `docker build` +passes none, and that image reports `dev`. --- diff --git a/TODO.md b/TODO.md index e0c114a..1e32630 100644 --- a/TODO.md +++ b/TODO.md @@ -20,6 +20,8 @@ https://git.eeqj.de/sneak/dnswatcher/issues/104 # Completed Steps +- 2026-10-01: the image built by `make docker` reports the `git describe` + version, not `dev`, and the startup log now shows it (closes #109). - 2026-10-01: two notify shutdown tests always release the delivery they hold, so a drain that returns early fails them instead of hanging (closes #176). - 2026-10-01: `script/install-precommit` asks git for the repository's git @@ -97,7 +99,6 @@ https://git.eeqj.de/sneak/dnswatcher/issues/104 https://git.eeqj.de/sneak/dnswatcher/issues/177 - rate limit on `/metrics` Basic Auth: https://git.eeqj.de/sneak/dnswatcher/issues/101 -- images report version `dev`: https://git.eeqj.de/sneak/dnswatcher/issues/109 - trial run of the finished image: https://git.eeqj.de/sneak/dnswatcher/issues/149 - 1.0 readiness: run it with a real config and read the logs: diff --git a/cmd/dnswatcher/main.go b/cmd/dnswatcher/main.go index baff13b..11e6780 100644 --- a/cmd/dnswatcher/main.go +++ b/cmd/dnswatcher/main.go @@ -63,6 +63,7 @@ func main() { return n }, ), + fx.Invoke(func(l *logger.Logger) { l.Identify() }), fx.Invoke(func(*server.Server, *watcher.Watcher) {}), ).Run() } diff --git a/script/docker b/script/docker index 4f1fd14..93d2408 100755 --- a/script/docker +++ b/script/docker @@ -12,7 +12,15 @@ ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)" main() { cd "$ROOT" - docker build --no-cache-filter=lint,builder -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. VERSION is computed here because .dockerignore + # excludes .git, so `git describe` in a build stage cannot find it. + version="$(git describe --tags --always --dirty 2>/dev/null || true)" + [ -n "$version" ] || version="unknown" + docker build --no-cache-filter=lint,builder \ + --build-arg VERSION="$version" \ + -t "$("$SCRIPT_DIR/projectname")" . } main "$@"