Re-vendor the canonical files from sneak/prompts at dd4027b (closes #213)
check / check (push) Successful in 16m13s
check / check (push) Successful in 16m13s
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, which now fetches apt package lists so a fresh CI runner can install Go. The image takes its version from the VERSION build arg or git describe, dev without .git, and still stamps the commit and its date. This repo's own entries follow the canonical content in .gitignore and .editorconfig. 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". Model: opus-5-5
This commit is contained in:
+18
-68
@@ -1,78 +1,28 @@
|
||||
#!/bin/sh
|
||||
# script/cibuild: run the CI build. This is the full gate, and it is two
|
||||
# builds, in this order:
|
||||
#
|
||||
# Dockerfile.lint the linter, as a build step (a clean build IS a
|
||||
# clean lint)
|
||||
# Dockerfile `make fmt-check` and `make test` in the builder
|
||||
# stage, then the product image
|
||||
#
|
||||
# Either one failing fails this script. Note what follows from the
|
||||
# split: script/docker builds only the product image and so no longer
|
||||
# lints -- this script and script/check (which runs script/lint) are the
|
||||
# things that decide whether the tree is clean.
|
||||
#
|
||||
# Generic apart from the two Dockerfiles: the Gitea workflow runs this
|
||||
# on push.
|
||||
# script/cibuild: run the CI build. It bootstraps first: a CI runner
|
||||
# checks out and runs this and nothing else, and script/fmt-check runs
|
||||
# the formatter on the host, which a pristine checkout cannot do.
|
||||
# --no-cache for the same reason as script/docker: the gate phases the
|
||||
# final stage depends on are RUN steps, and a cached one is a check that
|
||||
# did not run.
|
||||
set -eu
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd -P)"
|
||||
ROOT="$(cd "$SCRIPT_DIR/.." && pwd -P)"
|
||||
|
||||
main() {
|
||||
cd "$ROOT"
|
||||
# Both Dockerfiles key their check layers on CHECK_EPOCH, so a fresh
|
||||
# value is what forces those layers to re-run: without it an
|
||||
# unchanged tree replays them from cache, the checks never execute,
|
||||
# and the build still exits 0. Each ARG sits immediately above the
|
||||
# check RUNs, so dependency and module layers still cache.
|
||||
# Dockerfile.lint also refuses to build at all when CHECK_EPOCH is
|
||||
# empty, so a missing value fails its build loudly rather than passing
|
||||
# quietly; the product Dockerfile does not, because a plain `docker
|
||||
# build .` must succeed.
|
||||
#
|
||||
# The value must be unique per invocation, not per second. `date +%s`
|
||||
# is second-granular, so two concurrent invocations in the same
|
||||
# second get identical epochs and the later one can be served from
|
||||
# cache -- the original defect in miniature. `%N` alone does not fix
|
||||
# it: 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 the epoch 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 CHECK_EPOCH is exactly the cached-check false green this
|
||||
# script exists to prevent -- so the guard would disarm itself and
|
||||
# still exit 0. As a bare assignment, `set -e` catches a failing
|
||||
# `date` and no build starts.
|
||||
#
|
||||
# A separate value per build, because they are separate builds: one
|
||||
# `date` shared between them would still be fresh, but reusing it
|
||||
# invites the two to be collapsed into a single value that is
|
||||
# computed somewhere else and passed in.
|
||||
epoch="$(date +%s%N)$$"
|
||||
# cacheonly for the lint build: its verdict is the exit status and
|
||||
# the image is never run, so exporting it is pure cost. See
|
||||
# script/lint.
|
||||
docker build --output=type=cacheonly \
|
||||
--build-arg CHECK_EPOCH="$epoch" -f Dockerfile.lint .
|
||||
|
||||
# Version, commit and build date are computed here on the host, the
|
||||
# same way script/docker does, and passed into the product build,
|
||||
# where they take precedence over what the build would derive from
|
||||
# the .git in its context. VERSION comes from script/version, as in
|
||||
# the Makefile.
|
||||
version="$("$ROOT/script/version")"
|
||||
commit="$(git rev-parse HEAD 2>/dev/null || echo unknown)"
|
||||
commit_date="$(git show -s --format=%cs HEAD 2>/dev/null || echo unknown)"
|
||||
|
||||
epoch="$(date +%s%N)$$"
|
||||
docker build --build-arg CHECK_EPOCH="$epoch" \
|
||||
"$SCRIPT_DIR/bootstrap"
|
||||
"$SCRIPT_DIR/check"
|
||||
# Own line: a failing command substitution inside an argument does
|
||||
# not trip `set -e`, so the inline form degrades silently to an
|
||||
# empty constant. The VERSION build argument takes precedence over
|
||||
# the version a build stage derives from the .git in the context.
|
||||
version="$(git describe --tags --always --dirty 2>/dev/null || true)"
|
||||
[ -n "$version" ] || version="unknown"
|
||||
docker build --no-cache \
|
||||
--build-arg VERSION="$version" \
|
||||
--build-arg COMMIT="$commit" \
|
||||
--build-arg COMMIT_DATE="$commit_date" \
|
||||
.
|
||||
-t "$("$SCRIPT_DIR/projectname")" .
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
Reference in New Issue
Block a user