Re-vendor the canonical files from sneak/prompts at dd4027b (closes #213)
check / check (push) Failing after 4s
check / check (push) Failing after 4s
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. The image takes its version from the VERSION build arg or git describe, and still stamps the commit and its date from .git. The golangci-lint v2.14.0 findings are fixed in the code. The rules in CLAUDE.md move into AGENTS.md. IsDevVersion now counts "unknown", the version script/docker stamps outside a git checkout. Model: opus-5-5
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