Skip to content
23 changes: 17 additions & 6 deletions scripts/pr_queue_health.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@
from collections import defaultdict
from typing import Any

BOUNTY_REF_RE = re.compile(r"\b(?:bounty|refs?|fixes|closes|claims?)\s+#(\d+)", re.IGNORECASE)
BOUNTY_REF_RE = re.compile(
r"\b(?:(?P<native_prefix>live|mrwk|native|internal)\s+)?"
r"(?P<keyword>bounty|issues?|refs?|fixes|closes|claims?)\s+#(?P<number>\d+)",
re.IGNORECASE,
)
Comment thread
coderabbitai[bot] marked this conversation as resolved.
NOISY_TITLE_PREFIX_RE = re.compile(r"^\s*(?:\[[^\]]+\]\s*)+")
UNSTABLE_MERGE_STATES = {"blocked", "conflicting", "dirty", "unknown", "unstable"}
GH_TIMEOUT_SECONDS = 30
Expand Down Expand Up @@ -47,15 +51,22 @@ def _scope_key(raw: dict[str, Any]) -> str:
def _bounty_refs(raw: dict[str, Any]) -> list[int]:
explicit = raw.get("bounty_refs")
if isinstance(explicit, list):
refs = [item for item in explicit if isinstance(item, int)]
if refs:
return sorted(set(refs))
explicit_refs = [
item for item in explicit if isinstance(item, int) and not isinstance(item, bool)
]
if explicit_refs:
return sorted(set(explicit_refs))
text = "\n".join(
str(raw.get(key) or "")
for key in ("title", "body", "description")
if raw.get(key) is not None
)
return sorted({int(match) for match in BOUNTY_REF_RE.findall(text)})
refs: set[int] = set()
for match in BOUNTY_REF_RE.finditer(text):
if match.group("native_prefix") and match.group("keyword").lower() == "bounty":
continue
refs.add(int(match.group("number")))
return sorted(refs)


def _is_open_bounty(raw: dict[str, Any]) -> bool:
Expand Down Expand Up @@ -116,7 +127,7 @@ def analyze_queue(data: dict[str, Any]) -> dict[str, Any]:
_issue(
pr,
"missing_bounty_reference",
"No Bounty #<issue>, Refs #<issue>, or /claim #<issue> found",
"No Bounty #<issue>, Issue #<issue>, Refs #<issue>, or /claim #<issue> found",
)
)
for ref in pr["refs"]:
Expand Down
117 changes: 116 additions & 1 deletion tests/test_pr_queue_health.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,120 @@ def test_pr_queue_health_accepts_claim_command_reference() -> None:
assert report["missing_bounty_references"] == []


def test_pr_queue_health_ignores_boolean_explicit_bounty_refs() -> None:
report = analyze_queue(
{
"bounties": [{"number": 406, "state": "OPEN", "awards_remaining": 1}],
"pull_requests": [
{
"number": 531,
"title": "Boolean refs are not issue refs",
"body": "",
"bounty_refs": [True, False],
"merge_state": "clean",
"labels": [],
},
{
"number": 532,
"title": "Valid explicit issue ref still counts",
"body": "",
"bounty_refs": [True, 406],
"merge_state": "clean",
"labels": [],
},
],
}
)

assert report["summary"]["missing_bounty_references"] == 1
assert report["missing_bounty_references"][0]["pull_request"] == 531
assert report["closed_bounty_references"] == []


def test_pr_queue_health_ignores_native_bounty_ids_when_issue_ref_is_present() -> None:
report = analyze_queue(
{
"bounties": [{"number": 406, "state": "OPEN", "awards_remaining": 16}],
"pull_requests": [
{
"number": 524,
"title": "Refs #406: Reject malformed IPv4 public URLs",
"body": (
"Focused #406 small fix. Evidence: live bounty #66 / issue #406 "
"preflight returned status=open."
),
"merge_state": "clean",
"labels": [],
},
{
"number": 525,
"title": "Guard another #406 edge case",
"body": "MRWK bounty #66 maps to issue #406.",
"merge_state": "clean",
"labels": [],
},
{
"number": 528,
"title": "Ignore spaced live bounty evidence ids",
"body": (
"Evidence: live bounty #66 and live\tbounty #67 both map to issue #406."
),
"merge_state": "clean",
"labels": [],
},
{
"number": 526,
"title": "Ignore native #406 evidence ids",
"body": (
"Evidence: native bounty #66 / issue #406 preflight returned status=open."
),
"merge_state": "clean",
"labels": [],
},
{
"number": 527,
"title": "Ignore internal #406 evidence ids",
"body": "Evidence: internal bounty #66, issue #406 is the GitHub bounty.",
"merge_state": "clean",
"labels": [],
},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
],
}
)

assert report["summary"]["closed_bounty_references"] == 0
assert report["summary"]["missing_bounty_references"] == 0
assert report["closed_bounty_references"] == []
assert report["missing_bounty_references"] == []

Comment thread
coderabbitai[bot] marked this conversation as resolved.

def test_pr_queue_health_requires_issue_ref_when_only_native_bounty_id_is_present() -> None:
report = analyze_queue(
{
"bounties": [{"number": 406, "state": "OPEN", "awards_remaining": 16}],
"pull_requests": [
{
"number": 529,
"title": "Needs GitHub issue reference",
"body": "Evidence: live bounty #66 returned status=open.",
"merge_state": "clean",
"labels": [],
},
{
"number": 530,
"title": "Longer words still count as bounty refs",
"body": "Evidence: relive bounty #406 returned status=open.",
"merge_state": "clean",
"labels": [],
},
],
}
)

assert report["summary"]["missing_bounty_references"] == 1
assert report["missing_bounty_references"][0]["pull_request"] == 529


def test_pr_queue_health_markdown_report_includes_required_sections() -> None:
report = analyze_queue(
{
Expand Down Expand Up @@ -183,7 +297,8 @@ def test_pr_queue_health_markdown_report_includes_required_sections() -> None:
assert "### Missing bounty references" in markdown
assert (
"- [PR #2](https://github.com/ramimbo/mergework/pull/2): "
"Improve bounty filters (No Bounty #<issue>, Refs #<issue>, or /claim #<issue> found)"
"Improve bounty filters "
"(No Bounty #<issue>, Issue #<issue>, Refs #<issue>, or /claim #<issue> found)"
) in markdown
assert "### Dirty or unstable merge state" in markdown
assert "Merge state is dirty" in markdown
Expand Down