From 3745227b921f247247718c936f67eed3ffcd8806 Mon Sep 17 00:00:00 2001 From: sneak Date: Tue, 6 Oct 2026 05:25:30 +0000 Subject: [PATCH] Keep Go's build cache between builds (closes #124) make test and make build in the Dockerfile now share one Go build cache, kept in a BuildKit cache mount with this repository's own id, so they compile only what changed. script/test passes -count=1. Model: opus-5-5 --- Dockerfile | 10 ++++++++-- README.md | 6 ++++-- TODO.md | 10 ++++++++++ script/cibuild | 3 ++- script/test | 4 +++- 5 files changed, 27 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index d0afa31..16f0162 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,7 +50,12 @@ ARG CHECK_EPOCH COPY . . -RUN make test +# This cache mount keeps Go's build cache between builds for make test and +# make build; -count=1 in script/test keeps test results out of it. Go's cache +# does not notice C header changes, so the mount has its own id: change the id +# when the C packages installed above change. +RUN --mount=type=cache,id=sneak/secret/go-build,target=/root/.cache/go-build \ + make test # The version stamped into the binary: the VERSION build argument when one # is given, otherwise `git describe --tags --always` of the .git the build @@ -58,7 +63,8 @@ RUN make test # one, the short commit when no tag is reachable. A context that carries .git # and still yields no version fails the build. ARG VERSION -RUN version="${VERSION:-$(git describe --tags --always)}"; \ +RUN --mount=type=cache,id=sneak/secret/go-build,target=/root/.cache/go-build \ + version="${VERSION:-$(git describe --tags --always)}"; \ if [ -e .git ] && { [ -z "$version" ] || [ "$version" = dev ] || \ [ "$version" = unknown ]; }; then \ echo "no version could be derived although the build context carries .git" >&2; \ diff --git a/README.md b/README.md index 29d38f7..0f44d03 100644 --- a/README.md +++ b/README.md @@ -604,7 +604,8 @@ provide: - `script/build` — build the `secret` binary into the repo root, stamping the version (`VERSION` from the environment, else `git describe`) and the git commit -- `script/test` — run `go vet` and the test suite (verbose rerun on failure) +- `script/test` — run `go vet` and the test suite (verbose rerun on failure), + every test on every run, never a result from Go's test cache - `script/lint` — run `golangci-lint` in docker only: builds `Dockerfile.lint`, where the linter is a build step that runs on every call, also on an unchanged tree @@ -624,7 +625,8 @@ provide: - `script/cibuild` — CI entrypoint: `docker build --ulimit memlock=-1:-1 .` (memguard needs mlock; the Dockerfile runs the checks), with a new `CHECK_EPOCH` build argument on every run so the checks run again on an - unchanged tree + unchanged tree; the `Dockerfile` keeps Go's build cache between builds, so + `make test` and `make build` compile only what changed - `script/precommit` — pre-commit checks: `go mod tidy` verification, then `script/check` - `script/install-precommit` — install the git pre-commit hook that runs diff --git a/TODO.md b/TODO.md index 287ff4d..e386516 100644 --- a/TODO.md +++ b/TODO.md @@ -18,6 +18,16 @@ https://git.eeqj.de/sneak/secret/milestone/12 # Completed Steps +- 2026-10-06: `make test` in `script/cibuild` no longer compiles the standard + library and every dependency from nothing on every build + (https://git.eeqj.de/sneak/secret/issues/124). The `Dockerfile` runs it and + `make build` with Go's build cache in a BuildKit cache mount, which docker + keeps between builds, so each compiles only what changed since the last build. + The mount has an id of its own, so other repositories' builds do not share it. + `script/test` passes `-count=1`, so every test runs on every build and no + result comes from Go's test cache. A build with an empty cache, such as the + first after docker's build cache is cleared, compiles everything in + `make test` as before. - 2026-10-06: `TestRemoveIgnoresTerminalOnStdout` and `TestRemoveAsksAtTerminalOnStdin` no longer wait until Go's test timeout (https://git.eeqj.de/sneak/secret/issues/126). On Linux, `pty.Open` of diff --git a/script/cibuild b/script/cibuild index bb21515..feaf540 100755 --- a/script/cibuild +++ b/script/cibuild @@ -6,7 +6,8 @@ # the lower limit of a plain `docker build .`. # A cached build checks nothing: a new CHECK_EPOCH on every run makes the # Dockerfile's check steps run again on an unchanged tree, while its base -# images and module downloads stay cached. +# images, module downloads and the Go build cache that make test and make +# build use stay cached. set -eu ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" diff --git a/script/test b/script/test index 3735b43..7a48c8b 100755 --- a/script/test +++ b/script/test @@ -9,7 +9,9 @@ main() { # CGO is required (Makefile exports this too) export CGO_ENABLED=1 go vet ./... - go test ./... || go test -v ./... + # -count=1: run every test, never take a result from Go's test cache, + # which the Dockerfile keeps between builds + go test -count=1 ./... || go test -count=1 -v ./... } main "$@" -- 2.54.0