Re-vendor the canonical files from sneak/prompts at dd4027b (closes #213)
check / check (push) Successful in 12m47s
check / check (push) Successful in 12m47s
Linting and testing become the lint and test phases of the Dockerfile, and the build stage depends on both. Dockerfile.lint, CHECK_EPOCH and the tests that checked them are removed. Every docker build in script/ passes --no-cache, and script/cibuild runs script/bootstrap first. A host without Go gets the go.mod version from script/install-go in .tool/go, which bootstrap, the Makefile, fmt, fmt-check, precommit and release add to PATH; fmt-check skips .tool. The image takes its version from the VERSION build arg or git describe, dev without .git. This repo's own entries follow the canonical content in .gitignore and .editorconfig. The golangci-lint v2.14.0 findings are fixed. The rules in CLAUDE.md move into AGENTS.md. IsDevVersion counts "unknown". Model: opus-5-5
This commit was merged in pull request #236.
This commit is contained in:
+13
-98
@@ -1,108 +1,23 @@
|
||||
#!/bin/sh
|
||||
# script/lint: run the linter.
|
||||
# script/lint: run the linter. Linting is a phase of the Dockerfile and
|
||||
# this builds that phase alone; the linter is never installed or run on
|
||||
# a developer host, where a shared result cache and a host-global lock
|
||||
# make its answer untrustworthy.
|
||||
#
|
||||
# The linter runs inside the image built by Dockerfile.lint, and it runs
|
||||
# there as a BUILD STEP: a successful build of that file IS a clean
|
||||
# lint. Nothing lints on the host, at any version, ever. That FROM line
|
||||
# is the single source of truth for the linter version in this repo, so
|
||||
# a local run and a CI run of the same tree cannot disagree.
|
||||
#
|
||||
# One container per run means one lint cache and one golangci-lint lock
|
||||
# per run, both private to that run and thrown away with it. That is
|
||||
# what makes concurrent runs on a shared host safe, and it is why this
|
||||
# script no longer carries per-worktree cache directories, a lock-retry
|
||||
# loop, or an output audit: there is no shared state left for them to
|
||||
# defend (issue https://git.eeqj.de/sneak/vaultik/issues/113).
|
||||
#
|
||||
# To watch the linter execute, set BUILDKIT_PROGRESS=plain, which docker
|
||||
# honours directly:
|
||||
#
|
||||
# BUILDKIT_PROGRESS=plain script/lint
|
||||
#
|
||||
# The check layers -- `golangci-lint config verify` and then
|
||||
# `golangci-lint run` -- must appear as executing rather than CACHED on
|
||||
# every run; see the CHECK_EPOCH comment in Dockerfile.lint.
|
||||
# The phase is not the last stage in the file, so it is built only when
|
||||
# --target names it. --no-cache because a cached lint layer is a lint
|
||||
# that did not run. The tag makes each build replace the previous image
|
||||
# instead of leaving a dangling one behind.
|
||||
set -eu
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||
DOCKERFILE="$ROOT/Dockerfile.lint"
|
||||
|
||||
require_docker() {
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
cat >&2 <<EOF
|
||||
lint: docker is required to run the pinned linter.
|
||||
|
||||
lint image declared by: $DOCKERFILE
|
||||
|
||||
Install docker. Linting with any other golangci-lint is not supported:
|
||||
it is what lets a local run pass while CI fails. A golangci-lint on
|
||||
PATH is never used, whatever its version.
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
if ! docker info >/dev/null 2>&1; then
|
||||
cat >&2 <<EOF
|
||||
lint: the docker daemon is not reachable, so the pinned linter cannot
|
||||
run.
|
||||
|
||||
lint image declared by: $DOCKERFILE
|
||||
|
||||
Start the daemon (and check DOCKER_HOST / your group membership). This
|
||||
script will not fall back to a different linter version or to an
|
||||
unpinned binary on PATH.
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat >&2 <<EOF
|
||||
usage: $(basename "$0")
|
||||
|
||||
script/lint takes no arguments. The linter runs as a build step, so
|
||||
there is no command line to pass flags to; anything accepted here would
|
||||
have to be silently dropped. To apply autofixes, use script/lint-fix,
|
||||
which runs the same pinned image as a container for exactly this
|
||||
reason.
|
||||
EOF
|
||||
exit 2
|
||||
}
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
|
||||
ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
|
||||
|
||||
main() {
|
||||
[ "$#" -eq 0 ] || usage
|
||||
|
||||
cd "$ROOT"
|
||||
require_docker
|
||||
|
||||
# A fresh epoch per invocation is what forces the check layers to
|
||||
# execute; the layers above the ARG in Dockerfile.lint still cache,
|
||||
# so a run is not cold. The value must be unique per invocation, not
|
||||
# per second: `date +%s` is second-granular, so two concurrent
|
||||
# invocations in the same second would get identical epochs and the
|
||||
# later one could be served from cache -- the false green in
|
||||
# miniature. `%N` alone does not fix it either, because busybox
|
||||
# silently drops %N, exits 0, and hands back second granularity with
|
||||
# no warning. `$$` is what makes this correct regardless, since
|
||||
# concurrent invocations have different pids.
|
||||
#
|
||||
# Assign it on its own line rather than inline in the argument.
|
||||
# Under `set -eu` a command substitution that fails inside an
|
||||
# argument does NOT abort the script: CHECK_EPOCH would become an
|
||||
# empty string, an empty string is a constant, and a constant epoch
|
||||
# is exactly the cached-lint false green this guards against. As a
|
||||
# bare assignment, `set -e` catches a failing `date` and no build
|
||||
# starts.
|
||||
epoch="$(date +%s%N)$$"
|
||||
|
||||
# cacheonly: the lint verdict is the build's exit status, and the
|
||||
# image it would otherwise produce is never run. Exporting it costs
|
||||
# most of the wall time of a warm run and leaves a dangling image
|
||||
# behind on every invocation, on a host that may be running many.
|
||||
docker build \
|
||||
--output=type=cacheonly \
|
||||
--build-arg CHECK_EPOCH="$epoch" \
|
||||
-f "$DOCKERFILE" \
|
||||
"$ROOT"
|
||||
docker build --no-cache \
|
||||
--target lint \
|
||||
-t "$("$SCRIPT_DIR/projectname")-lint" .
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
Reference in New Issue
Block a user