mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-10 22:27:13 +01:00
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
file length / file-length (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
palette drift / palette (push) Waiting to run
shared gate tests / gate unit tests (push) Waiting to run
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
117 lines
3.9 KiB
Bash
Executable File
117 lines
3.9 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# ============================================================================
|
|
# gate_stamp.sh — prove the tree being pushed passed the local gate, in ~1 s.
|
|
#
|
|
# The pre-push stage used to re-run every suite (clean-venv pytest, pre-commit
|
|
# --all-files, flutter/vitest coverage) on every push: 10+ minutes under the
|
|
# resource cap, and OOM-killed twice on 2026-09-20. All of that had already run
|
|
# minutes earlier in finish_auto.sh's gate. So the gate now leaves a receipt:
|
|
# the tree hash it passed on, in $GIT_DIR/gate-stamp. pre-push only compares
|
|
# the pushed commit's tree against that receipt and never runs anything heavy.
|
|
#
|
|
# check pre-push hook: exit 0 iff the pushed tree is stamped
|
|
# write [--dirty-ok] record HEAD^{tree} — for finish_auto.sh, right after its
|
|
# gate + commit; refuses a dirty tree unless told the gate
|
|
# saw the working copy (narrow staging leaves other files)
|
|
# full run the repo's manual-stage hooks (the old pre-push set)
|
|
# on --all-files, then write; the on-demand heavy gate
|
|
#
|
|
# The heavy suites still run in CI on every push; this only decides whether a
|
|
# tree may leave the machine, not whether it is fully green.
|
|
# ============================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_NAME="$(basename "$0")"
|
|
readonly SCRIPT_NAME
|
|
|
|
usage() {
|
|
echo "Usage: $SCRIPT_NAME check | write [--dirty-ok] | full"
|
|
exit 2
|
|
}
|
|
|
|
stamp_path() {
|
|
printf '%s/gate-stamp\n' "$(git rev-parse --git-dir)"
|
|
}
|
|
|
|
tree_of() {
|
|
git rev-parse --verify --quiet "$1^{tree}"
|
|
}
|
|
|
|
# First field of the stamp is the tree hash; the rest is for humans.
|
|
stamped_tree() {
|
|
local path
|
|
path="$(stamp_path)"
|
|
[[ -f "$path" ]] || return 0
|
|
read -r tree _ < "$path"
|
|
printf '%s\n' "$tree"
|
|
}
|
|
|
|
cmd_check() {
|
|
# pre-commit consumes the hook's stdin and exports the ref being pushed;
|
|
# a manual run has neither, so fall back to HEAD.
|
|
local ref="${PRE_COMMIT_TO_REF:-HEAD}"
|
|
local tree stamped
|
|
tree="$(tree_of "$ref")" || {
|
|
echo "$SCRIPT_NAME: cannot resolve $ref^{tree}" >&2
|
|
exit 1
|
|
}
|
|
stamped="$(stamped_tree)"
|
|
if [[ "$tree" == "$stamped" ]]; then
|
|
echo "gate-stamp: tree ${tree:0:12} passed the local gate"
|
|
return 0
|
|
fi
|
|
{
|
|
echo "gate-stamp: tree ${tree:0:12} of $ref has NOT passed the local gate"
|
|
if [[ -n "$stamped" ]]; then
|
|
echo " stamped tree is ${stamped:0:12} — something was committed after the gate"
|
|
else
|
|
echo " no stamp in $(stamp_path)"
|
|
fi
|
|
echo " Either: ~/.claude/scripts/finish_auto.sh (gate + commit + push)"
|
|
echo " or: scripts/check_gate_stamp.sh full (old pre-push suites, then push again)"
|
|
} >&2
|
|
exit 1
|
|
}
|
|
|
|
cmd_write() {
|
|
local dirty_ok=0
|
|
[[ "${1:-}" == "--dirty-ok" ]] && dirty_ok=1
|
|
local dirty
|
|
dirty="$(git status --porcelain --untracked-files=no)"
|
|
if [[ -n "$dirty" && $dirty_ok -eq 0 ]]; then
|
|
echo "$SCRIPT_NAME: working tree differs from HEAD — the gate ran on" >&2
|
|
echo " content that is not what HEAD holds. Commit first, then stamp." >&2
|
|
exit 1
|
|
fi
|
|
local tree
|
|
tree="$(tree_of HEAD)"
|
|
printf '%s %s %s\n' "$tree" "$(date -Is)" "$SCRIPT_NAME" > "$(stamp_path)"
|
|
echo "gate-stamp: recorded tree ${tree:0:12} for $(git rev-parse --short HEAD)"
|
|
if [[ -n "$dirty" ]]; then
|
|
echo " (worktree also holds $(wc -l <<<"$dirty") uncommitted tracked change(s) the gate saw)"
|
|
fi
|
|
}
|
|
|
|
cmd_full() {
|
|
echo "gate-stamp: running the manual-stage hooks on all files (the old pre-push set)"
|
|
pre-commit run --hook-stage manual --all-files
|
|
cmd_write
|
|
}
|
|
|
|
main() {
|
|
local cmd="${1:-}"
|
|
[[ -n "$cmd" ]] || usage
|
|
shift
|
|
cd "$(git rev-parse --show-toplevel)"
|
|
case "$cmd" in
|
|
check) cmd_check "$@" ;;
|
|
write) cmd_write "$@" ;;
|
|
full) cmd_full "$@" ;;
|
|
*) usage ;;
|
|
esac
|
|
}
|
|
|
|
main "$@"
|