1 Commits
Author SHA1 Message Date
sneak 6932e3adce Run the linter only in Docker (closes #20)
check / check (push) Successful in 56s
check / check (pull_request) Successful in 51s
script/lint now builds the new Dockerfile.lint, whose last step runs
golangci-lint. The build cache is off, so every run executes the
linter, and no image is kept. The Dockerfile lint stage calls
golangci-lint directly, since make lint is now a docker build of its
own. script/fmt no longer runs golangci-lint --fix, and
script/bootstrap no longer installs it. golangci-lint config verify is
left out: it fetches its schema over the network, unpinned. The README,
TODO.md and the script/cibuild comment say what now runs.

Model: opus-5-5
2026-10-06 03:11:54 +00:00
8 changed files with 32 additions and 17 deletions
+2 -1
View File
@@ -6,7 +6,8 @@ COPY go.mod go.sum ./
RUN go mod download RUN go mod download
COPY . . COPY . .
RUN make fmt-check RUN make fmt-check
RUN make lint # Called directly: make lint is itself a docker build (Dockerfile.lint).
RUN golangci-lint run --config .golangci.yml ./...
# Test stage: run full test suite # Test stage: run full test suite
# golang 1.22.12 (2025-02-04) # golang 1.22.12 (2025-02-04)
+13
View File
@@ -0,0 +1,13 @@
# Built by script/lint. The build runs golangci-lint, so a successful build
# is a clean lint.
#
# `golangci-lint config verify` is left out on purpose: it downloads its
# schema over the network on every run, unpinned.
#
# golangci/golangci-lint:v2.12.2 (Debian-based), 2026-08-07
FROM golangci/golangci-lint:v2.12.2@sha256:5cceeef04e53efe1470638d4b4b4f5ceefd574955ab3941b2d9a68a8c9ad5240
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN golangci-lint run --config .golangci.yml ./...
+6 -5
View File
@@ -113,16 +113,17 @@ development workflow, and the Makefile targets are thin shims that call them.
The scripts are POSIX sh (not bash) so they run in minimal containers such as The scripts are POSIX sh (not bash) so they run in minimal containers such as
alpine. We provide: alpine. We provide:
- `script/bootstrap` — install all dependencies (go and golangci-lint if - `script/bootstrap` — install all dependencies (go if missing, then
missing, then `go mod download`) `go mod download`); golangci-lint is not installed, since it runs only in
Docker
- `script/setup` — set up the repo for development after a fresh clone: runs - `script/setup` — set up the repo for development after a fresh clone: runs
`script/bootstrap`, then `script/install-precommit` `script/bootstrap`, then `script/install-precommit`
- `script/projectname` — output the project name (our own extension); used by - `script/projectname` — output the project name (our own extension); used by
`script/docker` for the image tag `script/docker` for the image tag
- `script/test` — run the test suite (`go test -v ./...`) - `script/test` — run the test suite (`go test -v ./...`)
- `script/lint` — run golangci-lint - `script/lint` — run golangci-lint in Docker by building `Dockerfile.lint`
- `script/fmt` — format all files (goimports plus `golangci-lint run --fix`; without the build cache, so every run lints; keeps no image
writes) - `script/fmt` — format all files with goimports (writes)
- `script/fmt-check` — check formatting (read-only); fails if `gofmt -l` - `script/fmt-check` — check formatting (read-only); fails if `gofmt -l`
reports files reports files
- `script/check` — run all checks: `test`, `lint`, `fmt-check` (our own - `script/check` — run all checks: `test`, `lint`, `fmt-check` (our own
+3
View File
@@ -24,6 +24,9 @@ files it depends on: .golangci.yml, REPO_POLICIES.md, .editorconfig,
# Completed Steps # Completed Steps
* 2026-10-06: the linter runs only in Docker: `script/lint` builds
`Dockerfile.lint` without the build cache, and `script/bootstrap` no
longer installs golangci-lint
* 2026-08-10: fixed every handler discarding slog attributes: console, * 2026-08-10: fixed every handler discarding slog attributes: console,
JSON and webhook handlers now emit record attributes, accumulate JSON and webhook handlers now emit record attributes, accumulate
WithAttrs without mutating the receiver, and honour WithGroup; WithAttrs without mutating the receiver, and honour WithGroup;
+1 -6
View File
@@ -54,12 +54,7 @@ main() {
if missing git; then pkg_install git git git git; fi if missing git; then pkg_install git git git git; fi
if missing go; then pkg_install go golang go go; fi if missing go; then pkg_install go golang go go; fi
# golangci-lint is packaged in nix, brew, and apk; there is no apt # golangci-lint is not installed: it runs only in docker (script/lint).
# package (on apt hosts, install it from a hash-verified GitHub
# release archive manually, never curl | sh).
if missing golangci-lint; then
pkg_install golangci-lint golangci-lint golangci-lint golangci-lint
fi
go mod download go mod download
+2 -2
View File
@@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# script/cibuild: run the CI build. The Dockerfile runs script/check, so # script/cibuild: run the CI build. The Dockerfile runs the format check,
# a successful build implies all checks pass. # the linter and the tests, so a successful build means they all pass.
set -eu set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
-1
View File
@@ -7,7 +7,6 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
main() { main() {
cd "$ROOT" cd "$ROOT"
goimports -l -w . goimports -l -w .
golangci-lint run --fix
} }
main "$@" main "$@"
+5 -2
View File
@@ -1,12 +1,15 @@
#!/bin/sh #!/bin/sh
# script/lint: run the linter. # script/lint: run the linter, in docker only, by building Dockerfile.lint;
# the build fails on any finding. --no-cache makes every run execute the
# linter: a cached build of an unchanged tree succeeds without linting
# anything. --output type=cacheonly keeps no image.
set -eu set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
main() { main() {
cd "$ROOT" cd "$ROOT"
golangci-lint run docker build --no-cache --output type=cacheonly -f Dockerfile.lint .
} }
main "$@" main "$@"