make tidy, and make check failing on an untidy go.mod or go.sum (closes #99)
check / check (push) Waiting to run

script/tidy runs `go mod tidy` in a new tidy stage of the Dockerfile,
on the test phase's Go image, and writes go.mod and go.sum back into the
working tree with `docker build --output`. The test phase now runs
`go mod tidy -diff` before the tests and fails naming `make tidy`; it
comes first because a missing go.sum line otherwise fails the tests with
Go's own message.

Judgement call: script/tidy's build has no tag, unlike the other builds
in script/: it makes no image.

Model: opus-5-5
This commit was merged in pull request #100.
This commit is contained in:
2026-10-07 10:30:46 +02:00
parent c80753c56e
commit 0dc26041dc
4 changed files with 60 additions and 9 deletions
+25 -1
View File
@@ -29,6 +29,12 @@ RUN go mod download
COPY . . COPY . .
# go.mod and go.sum must be as `go mod tidy` writes them, which is what
# `make tidy` does. Checked before the tests, which a missing go.sum line
# fails with a message that does not name `make tidy`.
RUN go mod tidy -diff || \
{ echo "go.mod or go.sum is not tidy: run make tidy" >&2; exit 1; }
# Go's build cache is kept on a tmpfs, out of the image: nothing uses it # Go's build cache is kept on a tmpfs, out of the image: nothing uses it
# after this step, and writing it into the image takes seconds. # after this step, and writing it into the image takes seconds.
RUN --mount=type=tmpfs,target=/root/.cache/go-build \ RUN --mount=type=tmpfs,target=/root/.cache/go-build \
@@ -36,7 +42,25 @@ RUN --mount=type=tmpfs,target=/root/.cache/go-build \
{ echo "--- Rerunning with -v for details ---"; \ { echo "--- Rerunning with -v for details ---"; \
go test -timeout 90s -race -v ./...; exit 1; } go test -timeout 90s -race -v ./...; exit 1; }
# Build stage. Nothing is wanted from the two phases above; the copies # Tidy stage: `go mod tidy` in the test phase's Go, so that the files it
# writes pass the test phase's check. Nothing else depends on it, so only
# script/tidy, which names the stage after it, builds it.
#
# golang 1.27.1-trixie, 2026-09-19
FROM golang@sha256:3b77fc618ec235a1ab412de7737f120dd507c57e8d87de4cbb7994fb94275ed5 AS tidy
WORKDIR /src
COPY . .
RUN go mod tidy
# go.mod and go.sum alone, which script/tidy writes into the working tree.
FROM scratch AS tidy-files
COPY --from=tidy /src/go.mod /src/go.sum /
# Build stage. Nothing is wanted from the lint and test phases; the copies
# are what make BuildKit build them first, so the image, which needs this # are what make BuildKit build them first, so the image, which needs this
# stage, cannot be produced unless lint and test passed. # stage, cannot be produced unless lint and test passed.
# #
+7 -3
View File
@@ -1,9 +1,10 @@
.PHONY: bootstrap setup test lint fmt fmt-check check docker hooks build run \ .PHONY: bootstrap setup test lint fmt fmt-check tidy check docker hooks build \
example-app run example-app
# Makefile targets are thin shims; the implementations live in script/ # Makefile targets are thin shims; the implementations live in script/
# per the scripts-to-rule-them-all pattern (see the Entrypoints section # per the scripts-to-rule-them-all pattern (see the Entrypoints section
# of README.md). build and run are for working on the code by hand; # of README.md). tidy writes go.mod and go.sum as `go mod tidy` does,
# which test checks. build and run are for working on the code by hand;
# example-app checks the image with an app built on it. # example-app checks the image with an app built on it.
bootstrap: bootstrap:
@@ -24,6 +25,9 @@ fmt:
fmt-check: fmt-check:
@script/fmt-check @script/fmt-check
tidy:
@script/tidy
check: check:
@script/check @script/check
+9 -5
View File
@@ -1401,10 +1401,10 @@ addresses are never sent to GeoJS.
- `internal/alerts`: takes the alerts the other parts raise, holds back repeats - `internal/alerts`: takes the alerts the other parts raise, holds back repeats
and those past the hourly limit, and sends the others to the webhook, Slack and those past the hourly limit, and sends the others to the webhook, Slack
and ntfy, each from a queue of its own. and ntfy, each from a queue of its own.
- `Dockerfile`: the lint and test phases, then the image, whose last stage - `Dockerfile`: the lint and test phases, the stages `script/tidy` builds, then
installs Ubuntu's packages, nixpkgs, `runsvinit` and `smallwebwaf`, with the image, whose last stage installs Ubuntu's packages, nixpkgs, `runsvinit`
`share/smallwebwaf.run` as runit's `run` script for `smallwebwaf` and and `smallwebwaf`, with `share/smallwebwaf.run` as runit's `run` script for
`share/rules.d/00-default.rules` as its default rule file. `smallwebwaf` and `share/rules.d/00-default.rules` as its default rule file.
- `deploy/example-app`: an app built on the image, which `script/example-app` - `deploy/example-app`: an app built on the image, which `script/example-app`
checks. checks.
@@ -1433,7 +1433,11 @@ so that they run in minimal containers.
`script/install-precommit`. `script/install-precommit`.
- `script/projectname`: prints the project's name, `smallwebwaf`, which - `script/projectname`: prints the project's name, `smallwebwaf`, which
`script/docker` and the others tag their images with. `script/docker` and the others tag their images with.
- `script/test`: runs the tests, as the `test` phase of the `Dockerfile`. - `script/test`: checks that `go.mod` and `go.sum` are as `go mod tidy` writes
them, then runs the tests, as the `test` phase of the `Dockerfile`.
- `script/tidy`: writes `go.mod` and `go.sum` as `go mod tidy` writes them, with
the Go of the `test` phase, in the `tidy` stage of the `Dockerfile`;
`make tidy` runs it.
- `script/lint`: runs golangci-lint, as the `lint` phase of the `Dockerfile`. - `script/lint`: runs golangci-lint, as the `lint` phase of the `Dockerfile`.
- `script/fmt`: formats the Go code with `gofmt` and the Markdown with prettier. - `script/fmt`: formats the Go code with `gofmt` and the Markdown with prettier.
- `script/fmt-check`: checks the formatting, and changes nothing. - `script/fmt-check`: checks the formatting, and changes nothing.
Executable
+19
View File
@@ -0,0 +1,19 @@
#!/bin/sh
# script/tidy: write go.mod and go.sum as `go mod tidy` writes them, which
# the test phase of the Dockerfile checks. This builds the Dockerfile's
# tidy-files stage, which holds the two files alone, and --output writes
# them into the working tree. The build makes no image, so it has no tag.
# --no-cache because `go mod tidy` asks the module proxy, whose answers a
# cached layer would repeat.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
main() {
cd "$ROOT"
docker build --no-cache \
--target tidy-files \
--output "type=local,dest=$ROOT" .
}
main "$@"