fix(governance): align pre-push guard with CI

This commit is contained in:
pulse-triage[bot]
2026-08-27 17:07:58 +01:00
parent 5ead2f8748
commit 553592d2bd
2 changed files with 91 additions and 8 deletions
+22 -8
View File
@@ -43,14 +43,28 @@ fi
CHANGED=$(git diff --name-only "$BASE"...HEAD)
CHANGED_GO=$(printf '%s\n' "$CHANGED" | grep -E '\.go$' || true)
step "Canonical completion guard (HEAD commit, CI mode)"
if [ "$AHEAD" -gt 1 ]; then
echo "Note: $AHEAD commits ahead; the guard is checked for HEAD only here, CI checks each commit."
fi
if ! git diff --name-only HEAD~1 HEAD | \
python3 scripts/release_control/canonical_completion_guard.py --files-from-stdin --diff-base HEAD~1; then
fail "canonical completion guard"
fi
step "Canonical completion guard (per commit, CI mode)"
while IFS= read -r commit; do
if [ -z "$commit" ]; then
continue
fi
if ! git rev-parse --verify --quiet "${commit}^" >/dev/null; then
echo "Skipping root commit $commit (no parent to diff against)."
continue
fi
# Match canonical-governance.yml exactly: the prepare-commit-msg hook
# persists an intentional local bypass as a trailer, so recover that
# reason when validating already-created commits before push.
reason=$(git log -1 --format='%(trailers:key=Contract-Neutral,valueonly,separator=; )' "$commit" | tr '\n' ' ')
echo "Checking $commit"
if ! git diff-tree --no-commit-id --name-only -r "$commit" | \
PULSE_ALLOW_CONTRACT_NEUTRAL_COMMIT="$reason" \
python3 scripts/release_control/canonical_completion_guard.py \
--files-from-stdin --diff-base "${commit}^"; then
fail "canonical completion guard @ $commit"
fi
done < <(git rev-list --reverse --no-merges "$BASE"..HEAD)
if printf '%s\n' "$CHANGED" | grep -q 'docs/release-control/v6/internal/subsystems/registry.json'; then
step "Registry snapshot tests (registry.json changed)"
@@ -1,6 +1,7 @@
import io
import os
import subprocess
import tempfile
import unittest
from contextlib import redirect_stderr
from pathlib import Path
@@ -3746,5 +3747,73 @@ class ReleaseCycleArtifactGuardTest(unittest.TestCase):
)
class DevPrepushScriptTest(unittest.TestCase):
def test_checks_every_commit_with_its_contract_neutral_trailer(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir:
repo = Path(temp_dir)
(repo / "scripts" / "release_control").mkdir(parents=True)
(repo / "scripts" / "dev-prepush.sh").write_text(
(REPO_ROOT / "scripts" / "dev-prepush.sh").read_text(encoding="utf-8"),
encoding="utf-8",
)
(repo / "scripts" / "release_control" / "canonical_completion_guard.py").write_text(
"""#!/usr/bin/env python3
import os
import sys
files = ",".join(line.strip() for line in sys.stdin if line.strip())
with open(os.environ["PULSE_TEST_GUARD_LOG"], "a", encoding="utf-8") as log:
reason = os.environ.get("PULSE_ALLOW_CONTRACT_NEUTRAL_COMMIT", "").strip()
log.write(f"{reason}\\t{files}\\n")
""",
encoding="utf-8",
)
def git(*args: str) -> None:
subprocess.run(
["git", *args],
cwd=repo,
check=True,
capture_output=True,
text=True,
)
git("init", "-q", "-b", "main")
git("config", "user.name", "Pulse Test")
git("config", "user.email", "pulse-test@example.invalid")
git("add", "scripts")
git("commit", "-q", "-m", "base")
git("tag", "base")
(repo / "first.txt").write_text("first\n", encoding="utf-8")
git("add", "first.txt")
git(
"commit",
"-q",
"-m",
"first change\n\nContract-Neutral: dependency-only test",
)
(repo / "second.txt").write_text("second\n", encoding="utf-8")
git("add", "second.txt")
git("commit", "-q", "-m", "second change")
guard_log = repo / "guard.log"
env = os.environ.copy()
env["PULSE_TEST_GUARD_LOG"] = str(guard_log)
result = subprocess.run(
["bash", "scripts/dev-prepush.sh", "base"],
cwd=repo,
env=env,
capture_output=True,
text=True,
)
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
self.assertEqual(
guard_log.read_text(encoding="utf-8").splitlines(),
["dependency-only test\tfirst.txt", "\tsecond.txt"],
)
if __name__ == "__main__":
unittest.main()