fix(triage): greptile — fail-safe fetch_pr_comments so a single API hiccup doesn't abort the sweep
Some checks are pending
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / schema-migration (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests: Security / security (push) Waiting to run

fetch_pr_author_association already wraps gh api in a try/except
CalledProcessError to keep the daily sweep moving when the lookup for
one PR transiently fails. fetch_pr_comments lacked the same guard — a
single 5xx mid-loop would crash the run before later PRs were
evaluated. Mirror the fail-safe pattern: return [] on CalledProcessError
or malformed paginated JSON; downstream that becomes a conservative
skip-no-greptile-score for the affected PR and the sweep continues to
the next one (which will be re-evaluated tomorrow).

Pinned with two new TestFetchPrComments tests.
This commit is contained in:
mateo-berri 2026-05-18 15:03:46 +00:00
parent b7578817f8
commit c5d5968e90
No known key found for this signature in database
2 changed files with 40 additions and 3 deletions

View file

@ -154,19 +154,31 @@ def is_external_pr_author(pr: dict, repo: str | None) -> bool:
def fetch_pr_comments(pr_number: int, repo: str | None) -> list[dict]:
"""Fetch issue-level comments on a PR (where Greptile posts its summary)."""
"""Fetch issue-level comments on a PR (where Greptile posts its summary).
Returns [] on API failure so a transient hiccup on any single PR doesn't
abort the whole daily sweep mid-loop. Matches the fail-safe pattern in
`fetch_pr_author_association`; downstream the empty list becomes a
`skip-no-greptile-score` action and the PR is re-evaluated on the next run.
"""
endpoint = (
f"repos/{repo}/issues/{pr_number}/comments?per_page=100"
if repo
else f"repos/{{owner}}/{{repo}}/issues/{pr_number}/comments?per_page=100"
)
raw = gh("api", "--paginate", endpoint)
try:
raw = gh("api", "--paginate", endpoint)
except subprocess.CalledProcessError:
return []
comments: list[dict] = []
for line in raw.strip().splitlines():
line = line.strip()
if not line:
continue
parsed = json.loads(line)
try:
parsed = json.loads(line)
except json.JSONDecodeError:
return []
if isinstance(parsed, list):
comments.extend(parsed)
else:

View file

@ -113,6 +113,31 @@ class TestExtractGreptileScore:
assert closer_module.extract_greptile_score([]) is None
class TestFetchPrComments:
"""`fetch_pr_comments` must fail-safe so a transient `gh api` error on
one PR doesn't abort the whole daily sweep mid-loop. Pinning the
empty-list return matches the fail-safe pattern in
`fetch_pr_author_association`.
"""
def test_should_return_empty_list_when_gh_api_fails(
self, closer_module, monkeypatch
):
import subprocess
def _failing_gh(*args, **kwargs):
raise subprocess.CalledProcessError(1, ["gh", *args])
monkeypatch.setattr(closer_module, "gh", _failing_gh)
assert closer_module.fetch_pr_comments(123, repo="x/y") == []
def test_should_return_empty_list_when_paginated_output_is_malformed(
self, closer_module, monkeypatch
):
monkeypatch.setattr(closer_module, "gh", lambda *a, **kw: "not json\n")
assert closer_module.fetch_pr_comments(123, repo="x/y") == []
class TestEvaluatePr:
@pytest.fixture(autouse=True)
def _now(self):