Files
pixa/script/lint
T
sneak 66bf9a589d
check / check (push) Successful in 2m45s
build: run all linting in Docker via Dockerfile.lint (closes #104)
golangci-lint now runs only inside a container, never on the host.
script/lint builds a hash-pinned root Dockerfile.lint; the nix-shell and
host golangci-lint paths are gone. A per-run CACHEBUST build-arg is
folded into the lint step's cache key, so the linter re-executes on every
run and an unchanged tree cannot return a cached success having linted
nothing; script/lint fails a build that did not run the linter.

Dockerfile's lint stage runs golangci-lint directly, since make lint now
builds a container and there is no Docker inside a build. It is the same
image and config. golangci-lint config verify is left out: it fetches its
schema over an unpinned live HTTPS call, which REPO_POLICIES.md forbids.

Model: opus-4-8
2026-09-21 18:21:25 +00:00

56 lines
2.0 KiB
Bash
Executable File

#!/bin/sh
# script/lint: run golangci-lint over the whole tree.
#
# The linter is never installed on the host: it runs only inside the
# Dockerfile.lint build, one way, everywhere. A clean build is a clean
# lint. See Dockerfile.lint for why the lint step cannot be cached.
set -eu
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
main() {
cd "$ROOT"
# A value no other run repeats. Dockerfile.lint folds it into the
# lint step's cache key, so the linter re-executes every run instead
# of an unchanged tree returning a cached success having linted
# nothing.
cachebust="$(date +%s)-$$"
tmp="$(mktemp -d "${TMPDIR:-/tmp}/pixa-lint.XXXXXX")"
trap 'rm -rf "$tmp"' EXIT INT TERM
# --progress=plain so the lint step's own output reaches the log we
# check below; --output=type=cacheonly because we want the linter's
# verdict, not an image left in the local store. The build status
# travels through a file: a pipeline's exit status is tee's, not the
# build's.
(
set +e
docker build \
--progress=plain \
--build-arg CACHEBUST="$cachebust" \
--output=type=cacheonly \
-f Dockerfile.lint . 2>&1
echo "$?" >"$tmp/status"
) | tee "$tmp/build.log"
status="$(cat "$tmp/status" 2>/dev/null || echo 1)"
[ "${status:-1}" -eq 0 ] || exit "${status:-1}"
# The linter's start line must appear as build output, not only in
# the build's echo of the RUN instruction. A step served from cache
# prints the instruction and none of its output; a step that runs
# prints a "#<n> <elapsed> ..." output line. Requiring that output
# line means a future edit dropping the CACHEBUST reference from
# Dockerfile.lint fails here rather than passing having linted
# nothing.
if ! grep -Eq '^#[0-9]+ +[0-9]+\.[0-9]+ +pixa-lint: running golangci-lint' \
"$tmp/build.log"; then
echo "script/lint: golangci-lint did not execute (cached step?)." >&2
exit 1
fi
}
main "$@"