1 Commits
Author SHA1 Message Date
sneak da79c587c0 Run the linter only in Docker (closes #20)
check / check (push) Successful in 38s
check / check (pull_request) Successful in 38s
script/lint now builds only the lint stage of the Dockerfile, without
the build cache, so every run executes the linter; the image is tagged
simplelog-lint. The lint stage calls golangci-lint directly, since make
lint is itself a docker build of that stage. script/cibuild and
script/docker also build without the cache, so their check steps always
run. script/fmt no longer runs golangci-lint --fix, and script/bootstrap
no longer installs it. golangci-lint config verify is left out, on the
owner's ruling. The README, TODO.md and the script/cibuild comment say
what now runs.

Model: opus-5-5
2026-10-06 04:34:31 +00:00
8 changed files with 34 additions and 24 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 of this stage.
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)
+11 -9
View File
@@ -113,24 +113,26 @@ 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 only the `lint`
- `script/fmt` — format all files (goimports plus `golangci-lint run --fix`; stage of the `Dockerfile` (which also runs the format check), without the
writes) build cache, so every run lints; the image is tagged `simplelog-lint`
- `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
extension) extension)
- `script/docker` — build the Docker image, tagged via `script/projectname` - `script/docker` — build the Docker image without the build cache, tagged
(byte-identical across repos) via `script/projectname` (byte-identical across repos)
- `script/cibuild` — cd to the repo root and `docker build .` (what CI runs; - `script/cibuild` — cd to the repo root and `docker build --no-cache .` (what
the image build runs the checks) CI runs; the image build runs the checks)
- `script/precommit` — run by the git pre-commit hook (our own extension); - `script/precommit` — run by the git pre-commit hook (our own extension);
runs a `go mod tidy` guard, then `script/check` runs a `go mod tidy` guard, then `script/check`
- `script/install-precommit` — installs the git pre-commit hook (our own - `script/install-precommit` — installs the git pre-commit hook (our own
+4
View File
@@ -24,6 +24,10 @@ 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 the
`lint` stage of the `Dockerfile`, every `docker build` in `script/`
runs 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
+4 -3
View File
@@ -1,13 +1,14 @@
#!/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.
# --no-cache because a cached check step is a check that did not run.
set -eu set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
main() { main() {
cd "$ROOT" cd "$ROOT"
docker build . docker build --no-cache .
} }
main "$@" main "$@"
+2 -1
View File
@@ -1,6 +1,7 @@
#!/bin/sh #!/bin/sh
# script/docker: build the Docker image tagged with the project name. # script/docker: build the Docker image tagged with the project name.
# Identical in all repos; the tag comes from script/projectname. # Identical in all repos; the tag comes from script/projectname.
# --no-cache because a cached check step is a check that did not run.
set -eu set -eu
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
@@ -8,7 +9,7 @@ ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
main() { main() {
cd "$ROOT" cd "$ROOT"
docker build -t "$("$SCRIPT_DIR/projectname")" . docker build --no-cache -t "$("$SCRIPT_DIR/projectname")" .
} }
main "$@" main "$@"
-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 "$@"
+10 -3
View File
@@ -1,12 +1,19 @@
#!/bin/sh #!/bin/sh
# script/lint: run the linter. # script/lint: run the linter, in docker only, by building the lint stage
# of the Dockerfile and nothing else; 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. The tag makes each
# build replace the previous image instead of leaving an untagged one.
set -eu set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
main() { main() {
cd "$ROOT" cd "$ROOT"
golangci-lint run docker build --no-cache \
--target lint \
-t "$("$SCRIPT_DIR/projectname")-lint" .
} }
main "$@" main "$@"