#!/bin/sh # script/cibuild: run the CI build. The Dockerfile does not run # script/check; it runs `make fmt-check` and `make lint` in its lint # stage and `make test` in its builder stage. A successful build # implies those three passed, provided they actually ran -- which is # what the CHECK_EPOCH below is for. # Generic: needs no adaptation. The Gitea workflow runs this on push. set -eu ROOT="$(cd "$(dirname "$0")/.." && pwd -P)" main() { cd "$ROOT" # The Dockerfile's check layers are keyed on CHECK_EPOCH, so a # fresh value here is what forces them to re-run: without it an # unchanged tree replays them from cache, the checks never execute, # and the build still exits 0. The ARG sits immediately above the # check RUNs, so dependency and module layers still cache. The # Dockerfile also refuses 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. epoch="$(date +%s%N)$$" docker build --build-arg CHECK_EPOCH="$epoch" . } main "$@"