testsAndMisc/meta/scripts/check_ci_green.sh
Krzysztof kuhy Rudnicki 1d7271f023 Phase 2: enforce the 250-line cap and stop pushing red
Two pre-commit hooks and one pre-push extension, plus the _glyph_art split
that had to land first — the cap gate cannot be wired while any file is over
it, and the lyricanki note-ascender glyph had taken _glyph_art.py to 253.

file-length-cap runs check_file_length.sh --all repo-wide rather than on
staged files, so a file that grows past the cap in some other commit is still
caught. Proven to block, not assumed: with a deliberate 261-line file staged
the hook exits 1 and names it; with the file removed it passes.

ci-baseline-green is the user's option (a): refuse to build on a main that is
already red. It fails closed on a definitively failing baseline and warns-and-
passes on anything it cannot determine — offline, no gh, unauthenticated, no
settled runs — each call capped at 5s. Blocking every commit on network
reachability buys nothing when (b) is the real per-change guarantee.
CI_GREEN_SKIP=1 is the escape for a fix-forward commit. python-tests.yml is
excluded on purpose: it is path-filtered, so a shell-only commit never
triggers it and its "latest run" would produce false reds.

This hook already earned its place. Run against a red main earlier in this
session it refused with "Shell tests (failure)", which is how the broken
SETUP_SOURCES was found instead of being pushed over.

ci_mirror gains the shell-tests workflow's side-effect-free half — every
lib/tests/run_all.sh plus the workflow's own test list, the user's option (b).
That list is parsed out of shell-tests.yml rather than copied: a hardcoded
duplicate drifts the moment someone adds a test, and a mirror that quietly
checks less than CI is worse than no mirror because it reports safe. The
Arch-container half stays unmirrored — it wants root and an Arch userland.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3PzGc75gBcdxP3PkHXGcV
2026-08-21 16:41:31 +02:00

83 lines
2.9 KiB
Bash
Executable File

#!/bin/bash
# ============================================================================
# Refuse to build on a known-broken baseline.
#
# Checks the most recent completed GitHub Actions run for each required
# workflow on main. A definitively RED baseline blocks the commit; anything
# this cannot determine (offline, no gh, not authenticated, no runs yet) warns
# and passes.
#
# Why fail open on "unknown": this runs on EVERY commit. The real guarantee
# that a change does not break CI is the pre-push ci-mirror hook, which runs
# the workflows' local equivalent against the actual diff. This hook is only
# the broken-baseline net, and making every commit depend on network
# reachability would cost far more than it catches.
#
# Why fail closed on "red": committing more work onto a main that is already
# failing is how a red baseline gets buried under changes that make it harder
# to bisect.
#
# Bypass for a deliberate fix-forward commit:
# CI_GREEN_SKIP=1 git commit ...
# ============================================================================
set -euo pipefail
readonly SCRIPT_NAME="${0##*/}"
# Workflows that must be green. python-tests.yml is deliberately absent: it is
# path-filtered, so a shell-only commit never triggers it and its "latest run"
# can legitimately be an old one.
readonly REQUIRED_WORKFLOWS=("Pre-commit checks" "Shell tests")
readonly TIMEOUT_SECONDS=5
warn_and_pass() {
printf '%s: %s\n' "$SCRIPT_NAME" "$1" >&2
printf '%s: skipping the CI-baseline check (pre-push ci-mirror is the real gate).\n' \
"$SCRIPT_NAME" >&2
exit 0
}
if [[ -n ${CI_GREEN_SKIP:-} ]]; then
warn_and_pass "CI_GREEN_SKIP is set"
fi
# Inside CI itself there is no useful "previous run on main" to consult, and
# the runner may not have a token with the right scope.
if [[ -n ${GITHUB_ACTIONS:-} ]]; then
warn_and_pass "running inside GitHub Actions"
fi
if ! command -v gh >/dev/null 2>&1; then
warn_and_pass "gh is not installed"
fi
if ! timeout "$TIMEOUT_SECONDS" gh auth status >/dev/null 2>&1; then
warn_and_pass "gh is not authenticated or GitHub is unreachable"
fi
failed=()
for workflow in "${REQUIRED_WORKFLOWS[@]}"; do
# --status completed so an in-progress run does not read as a failure; the
# question is whether the last SETTLED run was red.
conclusion="$(timeout "$TIMEOUT_SECONDS" gh run list \
--workflow "$workflow" --branch main --status completed \
--limit 1 --json conclusion --jq '.[0].conclusion // empty' 2>/dev/null || true)"
case "$conclusion" in
success | "") : ;; # green, or no settled run to judge
*) failed+=("$workflow ($conclusion)") ;;
esac
done
if [[ ${#failed[@]} -gt 0 ]]; then
printf '%s: main is RED on GitHub Actions:\n' "$SCRIPT_NAME" >&2
printf ' - %s\n' "${failed[@]}" >&2
printf '\nCommitting more work onto a failing baseline buries the breakage.\n' >&2
printf 'Fix it first, or if THIS commit is the fix:\n' >&2
printf ' CI_GREEN_SKIP=1 git commit ...\n' >&2
exit 1
fi
exit 0