feat: require approval at current PR head for merge (#471)
Add merge_approval_gate assessment so gitea_merge_pr fails closed when visible APPROVED reviews do not pin the live head SHA. Expose approval_at_current_head and stale_approval_block_reason in review feedback. Document re-review requirement in canonical merge workflow. Closes #471. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
"""Hermetic tests for merge approval head pinning (#471)."""
|
||||
import sys
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||
|
||||
from merge_approval_gate import assess_merge_approval_head # noqa: E402
|
||||
|
||||
HEAD_OLD = "8b61c4b41f1b49b271ed3b99657431cf06eeda3e"
|
||||
HEAD_NEW = "3e4b721d60e97147ba0704773cf57cd0d42cbe31"
|
||||
|
||||
|
||||
class TestMergeApprovalGate(unittest.TestCase):
|
||||
def test_fresh_approval_at_current_head(self):
|
||||
result = assess_merge_approval_head(
|
||||
current_head_sha=HEAD_NEW,
|
||||
latest_by_reviewer={
|
||||
"reviewer1": {
|
||||
"verdict": "APPROVED",
|
||||
"dismissed": False,
|
||||
"reviewed_head_sha": HEAD_NEW,
|
||||
"submitted_at": "2026-07-06T12:00:00Z",
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertTrue(result["approval_at_current_head"])
|
||||
self.assertIsNone(result["stale_approval_block_reason"])
|
||||
|
||||
def test_stale_approval_after_rebase(self):
|
||||
result = assess_merge_approval_head(
|
||||
current_head_sha=HEAD_NEW,
|
||||
latest_by_reviewer={
|
||||
"reviewer1": {
|
||||
"verdict": "APPROVED",
|
||||
"dismissed": False,
|
||||
"reviewed_head_sha": HEAD_OLD,
|
||||
"submitted_at": "2026-07-06T10:00:00Z",
|
||||
}
|
||||
},
|
||||
)
|
||||
self.assertFalse(result["approval_at_current_head"])
|
||||
self.assertEqual(result["latest_approved_head_sha"], HEAD_OLD)
|
||||
self.assertIn("stale approval", result["stale_approval_block_reason"])
|
||||
self.assertIn(HEAD_OLD, result["stale_approval_block_reason"])
|
||||
self.assertIn(HEAD_NEW, result["stale_approval_block_reason"])
|
||||
self.assertIn("re-review PR at current head", result["stale_approval_block_reason"])
|
||||
|
||||
def test_no_approval_entries(self):
|
||||
result = assess_merge_approval_head(
|
||||
current_head_sha=HEAD_NEW,
|
||||
latest_by_reviewer={},
|
||||
)
|
||||
self.assertFalse(result["approval_at_current_head"])
|
||||
self.assertIsNone(result["latest_approved_head_sha"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user