fix(triage): warn when fetch_open_prs hits the gh CLI 1000-row cap

Addresses greptile-apps P2 review note: 'gh pr list --limit 1000' is
the CLI's hard ceiling. If BerriAI/litellm ever exceeds 1000 open PRs,
fetch_open_prs silently returns a truncated list and the daily sweep
quietly misses everything beyond the cap.

Extract the cap value as GH_PR_LIST_LIMIT and emit a GitHub Actions
':⚠️:' annotation (to stderr, where Actions surfaces it in the
job log) whenever the result count reaches the cap. This is the minimal
defensive change — a real fix (paginated 'gh api' calls) is left as a
follow-up because the repo is nowhere near the cap today and an
unnecessary pagination loop would slow every run.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
This commit is contained in:
Cursor Agent 2026-05-18 05:54:57 +00:00
parent 28ba9f7c6b
commit d976504534
No known key found for this signature in database
2 changed files with 53 additions and 2 deletions

View file

@ -78,6 +78,12 @@ def gh(*args: str) -> str:
return result.stdout
# `gh pr list --limit` caps at 1000 (the CLI's documented hard ceiling).
# Surface a warning if we ever hit that cap so the silent truncation is
# visible in workflow logs instead of just being a missed close.
GH_PR_LIST_LIMIT = 1000
def fetch_open_prs(repo: str | None) -> list[dict]:
"""Fetch all open PRs (number, createdAt, isDraft, labels, author).
@ -94,12 +100,22 @@ def fetch_open_prs(repo: str | None) -> list[dict]:
"--state",
"open",
"--limit",
"1000",
str(GH_PR_LIST_LIMIT),
"--json",
fields,
*repo_args,
)
return json.loads(raw)
prs = json.loads(raw)
if len(prs) >= GH_PR_LIST_LIMIT:
# `gh pr list --limit N` returns at most N rows even if more exist;
# log a GitHub Actions warning so the truncation isn't silent.
message = (
f"fetch_open_prs hit the gh CLI cap ({GH_PR_LIST_LIMIT}); "
"the open-PR list is likely truncated. Switch to paginated "
"`gh api` calls if the repo regularly exceeds this cap."
)
print(f"::warning::{message}", file=sys.stderr)
return prs
def fetch_pr_author_association(pr_number: int, repo: str | None) -> str:

View file

@ -422,6 +422,41 @@ class TestMainOptoutLabelDefault:
assert default not in captured["optout_labels"], default
class TestFetchOpenPrsLimitWarning:
"""`fetch_open_prs` must surface a warning when the gh CLI cap is hit."""
def test_should_warn_when_at_cap(self, closer_module, monkeypatch, capsys):
# Pretend `gh pr list --limit 1000` returned exactly 1000 PRs —
# this is the silent-truncation case the warning is meant to catch.
cap = closer_module.GH_PR_LIST_LIMIT
synthetic = [{"number": i} for i in range(cap)]
import json as _json
monkeypatch.setattr(
closer_module, "gh", lambda *a, **kw: _json.dumps(synthetic)
)
result = closer_module.fetch_open_prs(None)
assert len(result) == cap
captured = capsys.readouterr()
# GitHub Actions `::warning::` annotations go to stderr by
# convention; just check the marker appears somewhere visible.
combined = captured.out + captured.err
assert "::warning::" in combined
assert str(cap) in combined
def test_should_not_warn_when_under_cap(self, closer_module, monkeypatch, capsys):
synthetic = [{"number": i} for i in range(5)]
import json as _json
monkeypatch.setattr(
closer_module, "gh", lambda *a, **kw: _json.dumps(synthetic)
)
result = closer_module.fetch_open_prs(None)
assert len(result) == 5
captured = capsys.readouterr()
assert "::warning::" not in (captured.out + captured.err)
class TestHasOptoutLabel:
def test_should_match_label_case_insensitively(self, closer_module):
pr = {"labels": [{"name": "Do Not Close"}, {"name": "bug"}]}