Make the CI gate execute the checks it reports on (closes #119)
All checks were successful
check / check (push) Successful in 3m0s

The check workflow ran `script/cibuild`, a plain `docker build .`. With a
warm layer cache the lint and builder stages replayed instead of running,
so a commit could report "Successful in 4s" without being formatted,
linted, tested, or built. Squash-merging an already-built branch onto
`next` hits exactly that path, so no merge was actually validated.

The workflow now writes `.ci-fingerprint` into the build context: the
hash of the last commit that touched the context. Any commit that
changes code gets a new value, invalidates the `COPY . .` layer of both
check stages, and really runs `make fmt-check`, `make lint`, `make test`
and `make build`. A docs-only commit leaves it unchanged and still
replays from cache in seconds, as `.dockerignore` already intends. The
module download layer sits above `COPY . .` and stays cached either way,
so this is cheaper than a scoped `--no-cache-filter`. `script/cibuild`
is a model script shared across repos and is left untouched.

The second half of the problem was that Gitea cancels the in-flight run
when a newer commit lands on the same branch and records the
cancellation as `failure`, marking commits red that were never tested.
That cancellation is unconditional server-side for push events, so the
superseding run now rewrites the exact `Has been cancelled` status to
`skipped`. Genuine failures are never touched.
This commit is contained in:
2026-08-12 09:49:51 +00:00
parent 543005c0c2
commit 5ac43e6b96
5 changed files with 90 additions and 3 deletions

View File

@@ -1,3 +1,6 @@
# .ci-fingerprint is deliberately NOT excluded: it is the CI cache barrier
# that keeps the check stages from replaying a cached pass. See the lint
# stage of the Dockerfile.
.git/
bin/
*.md