# The lint phase, the test phase and a development environment. # script/lint and script/test each build one phase alone; a plain # `docker build .` builds both, because the last stage copies a file from # each. Formatting is checked on the host by script/fmt-check, not here. # Lint phase # golangci/golangci-lint:v2.14.0, 2026-10-04 FROM golangci/golangci-lint@sha256:ad862ba6b3798cbe0fd9fd7408d498fd74fbd2623a92406b2fd3898faf0bf98f AS lint WORKDIR /src COPY go.mod go.sum ./ RUN go mod download COPY . . RUN golangci-lint run --config .golangci.yml ./... # Test phase. -race needs cgo and so a C compiler, which the Debian Go # image ships. # golang:1.26.8-trixie, 2026-10-04. It carries Go 1.26.8, the version # script/bootstrap installs on the host; change both together, and the # same image in the last stage. FROM golang@sha256:eae2aaa6add2936cbf350dd0d2628b363461542f0c4b3c0b558957e0f2997379 AS test 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; } # Development environment, and the last stage: a plain `docker build .` # builds this one. It holds the source tree in /src, what # script/bootstrap installs, and keyfunc built from that tree on the # PATH. 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. # golang:1.26.8-trixie, 2026-10-04 FROM golang@sha256:eae2aaa6add2936cbf350dd0d2628b363461542f0c4b3c0b558957e0f2997379 COPY --from=lint /src/go.sum /dev/null COPY --from=test /src/go.sum /dev/null # A tar-stream context keeps the sender's file owners, which git refuses. RUN git config --system --add safe.directory /src WORKDIR /src # script/bootstrap needs only script/ and the dependency manifests. COPY script/ script/ COPY go.mod go.sum package.json yarn.lock ./ RUN script/bootstrap COPY . . # The version stamped into the binary: the VERSION build argument when one # is given, otherwise `git describe --tags --always` of the .git in the # build context. A context that carries .git and still yields no version # fails the build; with neither, as from a source tarball, it is "dev". ARG VERSION RUN version="${VERSION:-$(git describe --tags --always || echo dev)}"; \ if [ -e .git ] && { [ -z "$version" ] || [ "$version" = dev ] || \ [ "$version" = unknown ]; }; then \ echo "no version could be derived although the build context carries .git" >&2; \ exit 1; \ fi; \ make build VERSION="$version" && mv keyfunc /usr/local/bin/keyfunc