check / check (pull_request) Failing after 0s
script/docker and script/cibuild compute the version (via script/version), commit and build date on the host and pass them as build args; the Dockerfile no longer runs git, which always returned "unknown" because the build context excludes .git. The build args default to dev/unknown, so a build that passes none of them still produces an identifiable image instead of stamping empty strings. A dirty tree is reflected through script/version's -dirty suffix. main now exits via os.Exit(run()), so its deferred CPU/heap profile writers flush before the process ends, and Entry returns a status code instead of calling os.Exit. Each command ran its operation in an fx goroutine that called os.Exit(1) on failure, discarding those profiles and the PID-lock release; they now route the error to the return path through one RunOperation helper. errReported keeps Entry from printing an already-reported failure twice. model: claude-opus-4-8
79 lines
3.6 KiB
Bash
Executable File
79 lines
3.6 KiB
Bash
Executable File
#!/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.
|
|
set -eu
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && 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. Both
|
|
# Dockerfiles also refuse to build at all when CHECK_EPOCH is empty,
|
|
# so a missing value fails loudly here rather than passing quietly.
|
|
#
|
|
# 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 so
|
|
# the CI-built image reports its real source. The build context
|
|
# excludes .git (see .dockerignore), so the build cannot derive them
|
|
# itself; without these it would stamp the Dockerfile's dev/unknown
|
|
# fallbacks. VERSION comes from script/version, the source of truth
|
|
# shared with 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" \
|
|
--build-arg VERSION="$version" \
|
|
--build-arg COMMIT="$commit" \
|
|
--build-arg COMMIT_DATE="$commit_date" \
|
|
.
|
|
}
|
|
|
|
main "$@"
|