A rotted action pin skipped the publish job rather than failing it, so edge stopped publishing and the phone sat on an old build for a working day with nothing saying why. The runner journal logs task pickup and never outcome, which is what was being read. ci-status.sh asks Gitea instead, drilling run -> job -> log tail on a failure. claude-hook-push-ci.sh runs it after every git push so the answer arrives without anyone choosing to look. TASK-42 has the three-layer plan; this is layer 1.
50 lines
1.9 KiB
Shell
Executable file
50 lines
1.9 KiB
Shell
Executable file
#!/usr/bin/env bash
|
|
# Claude Code PostToolUse hook: after a `git push`, say what CI did.
|
|
#
|
|
# Wired in ~/.claude/settings.json as a PostToolUse hook on Bash. Reads the
|
|
# tool-call JSON on stdin, does nothing unless the command was a push, and
|
|
# otherwise prints the pushed repo's CI status so the answer arrives without
|
|
# anyone deciding to ask for it.
|
|
#
|
|
# WHY. A pinned action SHA rotted on 2026-07-28 and stopped `edge` publishing
|
|
# for a working day. Nothing failed loudly — the publish job was *skipped* —
|
|
# and the habit in place was to read the runner journal, which reports task
|
|
# pickup and never outcome. Remembering to check is not a mechanism; this is.
|
|
#
|
|
# WHAT IT CANNOT DO. A cross build takes ~20 minutes, so immediately after a
|
|
# push the honest answer is usually "running". That still catches the whole
|
|
# fail-fast class — pin rot, lint, attribution, a bad workflow edit — which is
|
|
# what actually bites. Anything slower needs the layer-2 staleness check in
|
|
# TASK-42, not a longer sleep here.
|
|
#
|
|
# Never fails the tool call: exit 0 always. A status reporter that can block a
|
|
# push is a worse problem than the one it solves.
|
|
set -uo pipefail
|
|
|
|
SELF_DIR="$(dirname "$(realpath "$0")")"
|
|
payload=$(cat 2>/dev/null || true)
|
|
|
|
cmd=$(printf '%s' "$payload" | python3 -c '
|
|
import json, sys
|
|
try:
|
|
print(json.load(sys.stdin).get("tool_input", {}).get("command", ""))
|
|
except Exception:
|
|
pass
|
|
' 2>/dev/null)
|
|
|
|
case "$cmd" in
|
|
*"git push"*) ;;
|
|
*) exit 0 ;;
|
|
esac
|
|
|
|
# Which repo. The push may have run in any directory, so prefer the cwd's
|
|
# remote and fall back to whatever the command named.
|
|
repo=""
|
|
url=$(git remote -v 2>/dev/null | awk 'NR==1{print $2}')
|
|
[ -n "$url" ] && repo=$(basename "${url%.git}")
|
|
[ -n "$repo" ] || exit 0
|
|
|
|
echo "--- CI (auto, after git push) ---"
|
|
"$SELF_DIR/ci-status.sh" "$repo" 2 2>&1 | head -30
|
|
echo "--- a build in progress needs a second look; see TASK-42 ---"
|
|
exit 0
|