Files
clawbot f5c7614768
check / check (push) Waiting to run
Stamp the git tag or short commit into the binary (closes #4)
A plain `docker build .` now stamps bsdaily's version: the VERSION
build argument when one is given, otherwise `git describe --tags
--always` on the .git in the build context, as the canonical
Dockerfile does. The build fails if .git is there and the version
still comes out empty, dev or unknown. A host `make` build stamps the
same `git describe`, or dev. bsdaily logs the version on the first
line of every run and prints it with --version; a build that stamps
nothing, or an empty value, reports dev.

Judgement call: the build line also takes the canonical -trimpath and
-s -w.
One //nolint (gochecknoglobals): -X can only set a package-level
variable.

Model: opus-5-5
Co-authored-by: clawbot <sneak+clawbot@sneak.cloud>
2026-10-06 18:41:51 +02:00

91 lines
3.1 KiB
Docker

# Lint phase. The linter is invoked directly rather than through `make
# lint` or `script/lint`, which are themselves a docker build and would
# recurse into a daemon that does not exist in a build step.
# golangci/golangci-lint:v2.14.0 (Debian-based), 2026-10-06
FROM golangci/golangci-lint@sha256:ad862ba6b3798cbe0fd9fd7408d498fd74fbd2623a92406b2fd3898faf0bf98f AS lint
WORKDIR /src
# Copy go mod files first for better layer caching
COPY go.mod go.sum ./
RUN go mod download
# Copy source code
COPY . .
RUN golangci-lint run ./...
# Test phase, invoking `go test` directly for the same reason. -race
# needs cgo and so a C compiler, which the Debian Go image ships and the
# alpine one does not. The tool shells out to sqlite3, zstdmt and
# zstdcat, so tests that run it need them installed.
# golang:1.26.4-trixie, 2026-10-05
FROM golang:1.26.4-trixie@sha256:68b7145ec43d1820b9a56704554b53d1520aa2a15cb5233e374188a31b2a1bce AS test
RUN apt-get update \
&& apt-get install -y --no-install-recommends sqlite3 zstd \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN go test -timeout 90s -race -cover ./... || \
{ echo "--- Rerunning with -v for details ---"; \
go test -timeout 90s -race -v ./...; exit 1; }
# Build stage. Nothing is wanted from either phase above; the copies
# are what make BuildKit build them first, so this stage cannot run
# unless lint and test passed. A plain `docker build .` builds only the
# last stage and what it depends on, so the runtime stage stays last.
# golang:1.26.4-alpine, 2026-06-28
FROM golang:1.26.4-alpine@sha256:3ad57304ad93bbec8548a0437ad9e06a455660655d9af011d58b993f6f615648 AS builder
COPY --from=lint /src/go.sum /dev/null
COPY --from=test /src/go.sum /dev/null
RUN apk add --no-cache git
# A tar-stream context keeps the sender's file owners, which git refuses.
RUN git config --system --add safe.directory /src
WORKDIR /src
# Copy go mod files first for better layer caching
COPY go.mod go.sum ./
RUN go mod download
# Copy source code
COPY . .
# Build (pure Go, no CGO required since we use modernc.org/sqlite).
# 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 /bsdaily ./cmd/bsdaily
# Runtime stage
# alpine:3.21, 2026-06-28
FROM alpine:3.21@sha256:48b0309ca019d89d40f670aa1bc06e426dc0931948452e8491e3d65087abc07d
# bsdaily shells out to sqlite3, zstdmt, zstdcat at runtime
RUN apk add --no-cache ca-certificates sqlite zstd
# Copy binary from builder
COPY --from=builder /bsdaily /usr/local/bin/bsdaily
ENTRYPOINT ["/usr/local/bin/bsdaily"]