Stamp the build version into the binary (closes #253)
All checks were successful
check / check (push) Successful in 3m20s

The binary reported "dev" in every deployment: main.version carried a
placeholder and nothing ever set it. Neither `make build` nor the
Dockerfile passed -X, so a tagged release produced an artifact that
could not say which commit it was, and the upgrade procedure's "confirm
the new build is live" step had nothing to confirm against.

script/version is now the single source of the value: $VERSION when
set, else `git describe --tags --always --dirty`, else "unknown". A
clean checkout at a tag reports exactly that tag; a tree with no git
metadata reports "unknown" rather than failing or naming a tag it may
not be at. Nothing time- or host-dependent is stamped, so two builds of
one commit stay byte-identical.

The Makefile's build target composes the flags -- `-X main.version` plus
whatever GO_LDFLAGS adds -- and every compile goes through it, including
the Dockerfile's static relink, which now contributes its -extldflags
through GO_LDFLAGS instead of replacing -ldflags wholesale. Since
.dockerignore excludes .git/, the image cannot derive the version: it
takes a VERSION build arg, defaulted to "unknown", that script/docker
fills in from the host checkout.

The UI footer needed the other half of the fix. It renders .Version,
which nothing ever put in the template data, so it printed its literal
"dev" fallback no matter what the binary was built as; renderTemplate
now supplies the value on both the map and the wrapper path.
This commit is contained in:
2026-08-23 23:11:56 +00:00
parent 89f3b984d2
commit ec92992450
9 changed files with 507 additions and 14 deletions

View File

@@ -61,14 +61,28 @@ RUN script/fetch-assets
# Run tests and build
RUN make test
RUN make build
# Version stamped into the binary. .dockerignore excludes .git/, so
# nothing in this stage can derive it: script/docker resolves it on the
# host and passes it in. The default is what a bare `docker build .`
# with no --build-arg gets, and it names no tag the tree may not be at.
#
# Declared here, below the test and asset steps, so a changed version
# does not invalidate their cached layers.
ARG VERSION=unknown
RUN make build VERSION="$VERSION"
# Rebuild with static linking for Alpine runtime.
# make build already verified compilation.
# The CGO binary from `make build` is dynamically linked against glibc,
# which doesn't exist on Alpine (musl). Rebuild with static linking so
# the binary runs on Alpine without glibc.
RUN CGO_ENABLED=1 go build -ldflags '-extldflags "-static"' -o bin/webhooker ./cmd/webhooker
#
# The static flags go in through GO_LDFLAGS rather than a -ldflags of
# their own: the build target composes them with the -X that stamps the
# version, so this relink cannot silently drop the stamp.
RUN CGO_ENABLED=1 make build VERSION="$VERSION" GO_LDFLAGS='-extldflags "-static"'
# Runtime stage
# alpine:3.21, 2026-03-17