docker: a plain docker build . stamps the git version (closes #210)
check / check (push) Failing after 1m54s
check / check (push) Failing after 1m54s
A plain `docker build .`, which is how upaas builds, stamped `dev`: `.dockerignore` left out `.git` and the builder declared `ARG VERSION=dev`. `.dockerignore` now sends `.git` without `.git/config`, which can hold a credential, and lists no tracked file, which git in the build would count as deleted and mark `-dirty`. `ARG VERSION` has no default. The Makefile takes a non-empty `VERSION` from the command line or the environment, so a build arg still wins (`script/docker` keeps passing one); otherwise `git describe` runs in the builder. A new `make version` prints the version, and the builder fails when the context carries `.git`, directory or file, and it comes out empty, `dev` or `unknown`. Model: opus-5-5
This commit is contained in:
+7
-7
@@ -1,9 +1,9 @@
|
|||||||
.git/
|
# .git is sent, without its config: the builder stage derives the version it
|
||||||
|
# stamps into the binary from it, and `git describe` does not need the config,
|
||||||
|
# which can hold a credential (a password in the remote URL, a CI token). No
|
||||||
|
# tracked file may be listed here: git in the build would see it as deleted
|
||||||
|
# and mark the version -dirty, and an excluded .md would silently drop out of
|
||||||
|
# the prettier check in Dockerfile.fmt.
|
||||||
|
.git/config
|
||||||
bin/
|
bin/
|
||||||
node_modules/
|
node_modules/
|
||||||
# No .md may be excluded: Dockerfile.fmt checks every document with
|
|
||||||
# prettier, and an exclusion here would drop a file from that check while
|
|
||||||
# prettier still reports every file it was handed clean.
|
|
||||||
LICENSE
|
|
||||||
.editorconfig
|
|
||||||
.gitignore
|
|
||||||
|
|||||||
+20
-5
@@ -36,11 +36,26 @@ COPY . .
|
|||||||
# Run the tests - build fails if any test fails
|
# Run the tests - build fails if any test fails
|
||||||
RUN make test
|
RUN make test
|
||||||
|
|
||||||
# Build the binary. .dockerignore leaves out .git, so `git describe` in
|
# Version stamped into the binary: the VERSION build arg when one is
|
||||||
# the Makefile cannot find the version here: script/docker passes it as
|
# given and not empty (script/docker passes one), otherwise what
|
||||||
# --build-arg VERSION, and a build that passes none reports `dev`.
|
# `git describe` says of the .git in the build context, so a plain
|
||||||
ARG VERSION=dev
|
# `docker build .` of a clone stamps its tag or short commit. The build
|
||||||
RUN make build VERSION="${VERSION}"
|
# arg reaches make through the environment.
|
||||||
|
ARG VERSION
|
||||||
|
|
||||||
|
# A context that carries .git, as a directory or as a file, must yield a
|
||||||
|
# real version: one that is empty, `dev` or `unknown` cannot be traced
|
||||||
|
# back to a commit.
|
||||||
|
RUN version="$(make version)"; \
|
||||||
|
if [ -e .git ]; then \
|
||||||
|
case "$version" in \
|
||||||
|
"" | dev | unknown) \
|
||||||
|
echo "version is \"$version\" although the build context carries .git" >&2; \
|
||||||
|
exit 1 ;; \
|
||||||
|
esac; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
RUN make build
|
||||||
|
|
||||||
# Runtime stage
|
# Runtime stage
|
||||||
# alpine 3.21, 2026-02-28
|
# alpine 3.21, 2026-02-28
|
||||||
|
|||||||
+2
-3
@@ -30,9 +30,8 @@ COPY . .
|
|||||||
# --config, not discovery: a .prettierrc that failed to arrive would
|
# --config, not discovery: a .prettierrc that failed to arrive would
|
||||||
# otherwise leave prettier on its defaults, where proseWrap is "preserve"
|
# otherwise leave prettier on its defaults, where proseWrap is "preserve"
|
||||||
# and every wrap this check exists to enforce passes. Missing the file is
|
# and every wrap this check exists to enforce passes. Missing the file is
|
||||||
# a hard error instead. --no-editorconfig for the same reason in reverse:
|
# a hard error instead. --no-editorconfig so that .prettierrc alone sets
|
||||||
# .editorconfig is not in the build context, so honouring it here and on
|
# the style.
|
||||||
# a developer's machine would be two different answers.
|
|
||||||
RUN prettier --config .prettierrc --no-editorconfig --check "**/*.md"
|
RUN prettier --config .prettierrc --no-editorconfig --check "**/*.md"
|
||||||
|
|
||||||
# Write path. Not a check: script/fmt builds this and takes the files.
|
# Write path. Not a check: script/fmt builds this and takes the files.
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
.PHONY: all bootstrap setup build lint fmt fmt-check test check clean hooks docker
|
.PHONY: all bootstrap setup build version lint fmt fmt-check test check clean hooks docker
|
||||||
|
|
||||||
BINARY := dnswatcher
|
BINARY := dnswatcher
|
||||||
# `make build VERSION=...` overrides this; the Dockerfile does so, as the
|
# VERSION given on the command line (`make build VERSION=...`) or in the
|
||||||
# image has no .git to describe.
|
# environment, which is how the Dockerfile's VERSION build arg arrives,
|
||||||
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
|
# wins over what `git describe` says of this checkout. An empty one counts
|
||||||
|
# as not given; `override` is what replaces an empty command-line value.
|
||||||
|
ifeq ($(VERSION),)
|
||||||
|
override VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
|
||||||
|
endif
|
||||||
LDFLAGS := -X main.Version=$(VERSION)
|
LDFLAGS := -X main.Version=$(VERSION)
|
||||||
|
|
||||||
# Standard targets are thin shims; the implementations live in script/
|
# Standard targets are thin shims; the implementations live in script/
|
||||||
@@ -21,6 +25,10 @@ setup:
|
|||||||
build:
|
build:
|
||||||
go build -ldflags "$(LDFLAGS)" -o bin/$(BINARY) ./cmd/dnswatcher
|
go build -ldflags "$(LDFLAGS)" -o bin/$(BINARY) ./cmd/dnswatcher
|
||||||
|
|
||||||
|
# Prints the version `make build` stamps; the Dockerfile checks it.
|
||||||
|
version:
|
||||||
|
@echo "$(VERSION)"
|
||||||
|
|
||||||
test:
|
test:
|
||||||
@script/test
|
@script/test
|
||||||
|
|
||||||
|
|||||||
@@ -574,6 +574,7 @@ provide:
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
make build # Build binary to bin/dnswatcher
|
make build # Build binary to bin/dnswatcher
|
||||||
|
make version # Print the version make build stamps
|
||||||
make test # Run tests with race detector
|
make test # Run tests with race detector
|
||||||
make lint # Run golangci-lint in Docker (requires docker)
|
make lint # Run golangci-lint in Docker (requires docker)
|
||||||
make fmt # Format code and Markdown (requires docker)
|
make fmt # Format code and Markdown (requires docker)
|
||||||
@@ -584,13 +585,22 @@ make clean # Remove build artifacts
|
|||||||
### Build-Time Variables
|
### Build-Time Variables
|
||||||
|
|
||||||
`make build` sets the version with `-ldflags "-X main.Version=..."`, taking it
|
`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
|
from `VERSION` when given on the command line (`make build VERSION=1.2.3`) or in
|
||||||
command line (`make build VERSION=1.2.3`). The version appears in the startup
|
the environment, otherwise from `git describe --tags --always --dirty`, and
|
||||||
log and in the health check response.
|
`dev` without git metadata. An empty `VERSION` counts as not given. The version
|
||||||
|
appears in the startup log and in the health check response.
|
||||||
|
|
||||||
The Docker image has no `.git`, so the `Dockerfile` takes the version as
|
The image takes it the same way, from the `.git` the build context carries, so a
|
||||||
`--build-arg VERSION`. `make docker` passes it; a plain `docker build` passes
|
plain `docker build .` of a clone stamps the commit it was built from; a clone
|
||||||
none, and that image reports `dev`.
|
without tags stamps the short commit. A shallow clone carries only a tag on its
|
||||||
|
own commit, so a shallow clone of an untagged commit stamps the short commit.
|
||||||
|
`.dockerignore` sends `.git` without `.git/config`, which `git describe` does
|
||||||
|
not need and which can hold a credential. A non-empty `--build-arg VERSION=...`
|
||||||
|
takes precedence; `make docker` passes the version `git describe` gives on the
|
||||||
|
host. The build fails when the context carries `.git`, as a directory or as a
|
||||||
|
file, and the version comes out empty, `dev` or `unknown`. `.dockerignore` must
|
||||||
|
list no tracked file: git in the build would see it as deleted and mark the
|
||||||
|
version `-dirty`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ trial run of the finished image: https://git.eeqj.de/sneak/dnswatcher/issues/149
|
|||||||
|
|
||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
|
- 2026-10-02: a plain `docker build .` of a clone stamps its tag or short
|
||||||
|
commit, not `dev`: the build context now carries `.git` (closes #210).
|
||||||
- 2026-10-02: the resolver tries root servers, and every other server list it
|
- 2026-10-02: the resolver tries root servers, and every other server list it
|
||||||
walks, in a random order each time, not always from the top (closes #138).
|
walks, in a random order each time, not always from the top (closes #138).
|
||||||
- 2026-10-02: a name listed more than once in `DNSWATCHER_TARGETS`, in any
|
- 2026-10-02: a name listed more than once in `DNSWATCHER_TARGETS`, in any
|
||||||
|
|||||||
+2
-2
@@ -14,8 +14,8 @@ main() {
|
|||||||
cd "$ROOT"
|
cd "$ROOT"
|
||||||
# Own line: a failing command substitution inside an argument does
|
# Own line: a failing command substitution inside an argument does
|
||||||
# not trip `set -e`, so the inline form degrades silently to an
|
# not trip `set -e`, so the inline form degrades silently to an
|
||||||
# empty constant. VERSION is computed here because .dockerignore
|
# empty constant. The VERSION build arg takes precedence over what
|
||||||
# excludes .git, so `git describe` in a build stage cannot find it.
|
# the build would derive from the .git in its context.
|
||||||
version="$(git describe --tags --always --dirty 2>/dev/null || true)"
|
version="$(git describe --tags --always --dirty 2>/dev/null || true)"
|
||||||
[ -n "$version" ] || version="unknown"
|
[ -n "$version" ] || version="unknown"
|
||||||
docker build --no-cache-filter=lint,builder \
|
docker build --no-cache-filter=lint,builder \
|
||||||
|
|||||||
Reference in New Issue
Block a user