igneum/tools/ci/mirror-reset-check.sh
igneum-labs 0e6f5bce6b Stale-overlay class closes with its check: tools/ci/mirror-reset-check.sh in the pre-push gate
The reset itself has been master's behaviour since 9df9688 (remote-run.sh checkout_tree: git checkout -- . and git clean of the
overlay files, target dirs and stamps kept, before the branch checkout); the UI lane met the class again from worktrees whose
tools predate it (remote-run.sh is piped to the box from each worktree per build). The check reads checkout_tree() and fails
when the reset and the clean do not both come before the branch checkout; self-test: the real script passes, a copy without the
reset fails, the same lines moved after the checkout fail. cargo-audit: already owned by provision.sh step_cargo_tools
(b2262e5), confirmed ok (0.22.2) on the box; nothing added. Gate GREEN, 33 checks.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 22:47:16 +00:00

47 lines
3.8 KiB
Bash
Executable file

#!/usr/bin/env bash
# The stale-overlay class (6 October 2026, the PC 1 worker at 18:4x UTC, the UI lane twice later the same night): tools/build-remote.sh
# rsyncs a worktree's uncommitted files over the box's checkout; once those files are committed and HEAD moves, the next run's
# `git checkout -B <branch> <sha>` on the box refuses with "Your local changes would be overwritten" and nothing builds until
# someone clears the tree by hand. Rule: the remote checkout RESETS the working tree first (`git checkout -- .` and a `git clean`
# of the untracked overlay files, target dirs and stamps kept), then checks the branch out; the overlay re-applies the Mac's
# working-tree state afterwards anyway. The code lives in infra/build-server/remote-run.sh checkout_tree() and is piped to the box
# from each Mac worktree per build, so a worktree whose tools predate the fix keeps the old behaviour until it has master.
# This check reads checkout_tree() and fails when the reset and the clean do not both come BEFORE the branch checkout.
#
# tools/ci/mirror-reset-check.sh # exit 1 with the reason
# tools/ci/mirror-reset-check.sh --self-test # the real script passes; a copy with the reset lines removed fails
set -euo pipefail
cd "$(dirname "$0")/../.."
check() { # <file>: exit 0 when checkout_tree resets and cleans before the branch checkout
local f="$1" body reset clean co
body=$(sed -n '/^checkout_tree()/,/^}/p' "$f")
[ -n "$body" ] || { echo "mirror-reset: $f has no checkout_tree() function"; return 1; }
reset=$(printf '%s\n' "$body" | grep -nE '^\s*git checkout -q -- \.' | head -1 | cut -d: -f1)
clean=$(printf '%s\n' "$body" | grep -nE '^\s*git clean -q?f' | head -1 | cut -d: -f1)
co=$(printf '%s\n' "$body" | grep -nE '^\s*git checkout -q -B ' | head -1 | cut -d: -f1)
[ -n "$co" ] || { echo "mirror-reset: $f: no branch checkout (git checkout -q -B) in checkout_tree"; return 1; }
[ -n "$reset" ] && [ "$reset" -lt "$co" ] || { echo "mirror-reset: $f: no 'git checkout -- .' before the branch checkout (line $co of checkout_tree)"; return 1; }
[ -n "$clean" ] && [ "$clean" -lt "$co" ] || { echo "mirror-reset: $f: no 'git clean' of the overlay before the branch checkout (line $co of checkout_tree)"; return 1; }
printf '%s\n' "$body" | grep -qE "git clean .*-e target" || { echo "mirror-reset: $f: the clean must keep target dirs (-e target)"; return 1; }
echo "mirror-reset: $f resets (line $reset) and cleans (line $clean) before the branch checkout (line $co)"
}
if [ "${1:-}" = --self-test ]; then
t=$(mktemp -d); trap 'rm -rf "$t"' EXIT
check infra/build-server/remote-run.sh >/dev/null || { echo "mirror-reset self-test: the real script FAILED the check"; exit 1; }
grep -vE '^\s*git (checkout -q -- \.|clean -q?f)' infra/build-server/remote-run.sh > "$t/no-reset.sh"
if check "$t/no-reset.sh" >/dev/null 2>&1; then echo "mirror-reset self-test: a script without the reset PASSED (the check is blind)"; exit 1; fi
# the order matters: the same lines after the branch checkout must fail too
python3 - infra/build-server/remote-run.sh "$t/wrong-order.sh" <<'PY'
import re, sys
s = open(sys.argv[1]).read()
body = re.search(r'^checkout_tree\(\).*?^}', s, flags=re.S | re.M).group(0)
lines = body.split("\n"); moved = [l for l in lines if re.match(r'\s*git (checkout -q -- \.|clean -q?f)', l)]
rest = [l for l in lines if l not in moved]
i = next(k for k, l in enumerate(rest) if re.match(r'\s*git checkout -q -B ', l))
rest[i + 1:i + 1] = moved
open(sys.argv[2], "w").write(s.replace(body, "\n".join(rest)))
PY
if check "$t/wrong-order.sh" >/dev/null 2>&1; then echo "mirror-reset self-test: a reset AFTER the branch checkout PASSED (the check ignores order)"; exit 1; fi
echo "mirror-reset self-test: the real script passes; no reset fails; reset after the checkout fails"; exit 0
fi
check infra/build-server/remote-run.sh