a73x

.githooks/pre-push

Ref:   Size: 2.1 KiB   History

#!/usr/bin/env bash
#
# pre-push — the merge gate. Any push that updates the shared `main` branch must
# carry a RETRO.md line and pass `make ci` first (the same gate CI enforces).
# This is the guard that was missing when work merged to main red.
#
# Scope: ONLY pushes that update the remote refs/heads/main are gated. Feature-
# branch pushes and branch deletions run free. In a genuine emergency, bypass
# with `git push --no-verify`.
#
# Enable once per clone with: make hooks
set -euo pipefail

protected="refs/heads/main"
zero="0000000000000000000000000000000000000000"

# git feeds pre-push one line per ref being pushed:
#   <local ref> <local oid> <remote ref> <remote oid>
gate=0
range=""
while read -r _local_ref local_oid remote_ref remote_oid; do
	[ "$remote_ref" = "$protected" ] || continue   # not touching main
	[ "$local_oid" = "$zero" ] && continue          # deleting main — nothing to test
	gate=1
	# What this push actually adds. A remote that does not have main yet reports
	# the zero oid, and there is no range to diff — fall back to the last commit,
	# which is all a first push can be asked for.
	if [ "$remote_oid" = "$zero" ]; then
		range="$local_oid~1..$local_oid"
	else
		range="$remote_oid..$local_oid"
	fi
done

[ "$gate" -eq 1 ] || exit 0

# One line per push, not per commit: a push of eight commits owes one retro, and
# the range is the whole push. The gate is the ritual, not the prose — it cannot
# tell an honest line from a space. It only makes sure the moment is not skipped.
if ! git diff --name-only "$range" | grep -qx RETRO.md; then
	echo >&2
	echo "pre-push: BLOCKED — nothing in this push touches RETRO.md." >&2
	echo "  Append one line to RETRO.md: what slowed this work down." >&2
	echo "  Then commit or amend it, and push again (override: git push --no-verify)." >&2
	exit 1
fi

echo "pre-push: '$protected' is being updated — running 'make ci' (bypass: git push --no-verify)"
if ! make ci; then
	echo >&2
	echo "pre-push: BLOCKED — 'make ci' failed. Fix it, or override with 'git push --no-verify'." >&2
	exit 1
fi
echo "pre-push: make ci is green — allowing the push to $protected"