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]>
61 lines
2.1 KiB
Python
61 lines
2.1 KiB
Python
"""Merge approval must pin the current PR head SHA (#471).
|
|
|
|
Formal APPROVED reviews that predate the live PR head must not satisfy
|
|
``gitea_merge_pr`` eligibility. Pure assessment helpers are isolated here
|
|
for hermetic unit tests apart from MCP HTTP calls.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
def assess_merge_approval_head(
|
|
*,
|
|
current_head_sha: str | None,
|
|
latest_by_reviewer: dict,
|
|
) -> dict:
|
|
"""Return whether a visible approval applies to the live PR head.
|
|
|
|
Args:
|
|
current_head_sha: Current PR head commit SHA.
|
|
latest_by_reviewer: Map of reviewer login → review entry dicts with
|
|
``verdict``, ``dismissed``, and ``reviewed_head_sha`` keys.
|
|
|
|
Returns:
|
|
dict with ``approval_at_current_head``, ``latest_approved_head_sha``,
|
|
and ``stale_approval_block_reason`` (set when merge must fail closed).
|
|
"""
|
|
current = (current_head_sha or "").strip()
|
|
approved_entries = [
|
|
entry
|
|
for entry in (latest_by_reviewer or {}).values()
|
|
if (entry.get("verdict") or "").upper() == "APPROVED"
|
|
and not entry.get("dismissed")
|
|
]
|
|
at_current = any(
|
|
(entry.get("reviewed_head_sha") or "").strip() == current
|
|
for entry in approved_entries
|
|
if current
|
|
)
|
|
latest_approved = None
|
|
if approved_entries:
|
|
latest_entry = sorted(
|
|
approved_entries,
|
|
key=lambda entry: (
|
|
entry.get("submitted_at") or "",
|
|
entry.get("reviewed_head_sha") or "",
|
|
),
|
|
)[-1]
|
|
latest_approved = (latest_entry.get("reviewed_head_sha") or "").strip() or None
|
|
reason = None
|
|
if approved_entries and not at_current:
|
|
reason = (
|
|
f"stale approval: approved SHA '{latest_approved}' does not match "
|
|
f"current live PR head SHA '{current or '(unknown)'}' (fail closed); "
|
|
"required next action: re-review PR at current head before merge"
|
|
)
|
|
|
|
return {
|
|
"approval_at_current_head": at_current,
|
|
"latest_approved_head_sha": latest_approved,
|
|
"stale_approval_block_reason": reason,
|
|
} |