diff --git a/scripts/agent_poller.py b/scripts/agent_poller.py index 717896f..b2e5595 100644 --- a/scripts/agent_poller.py +++ b/scripts/agent_poller.py @@ -56,6 +56,27 @@ def _req(method, path, data=None): sys.exit(1) +def _req_safe(method, path, data=None): + """Like _req but returns None on HTTPError instead of crashing. + Used for probing issue/PR existence where the caller can handle absence. + """ + url = f"{BASE}{path}" + payload = json.dumps(data).encode("utf-8") if data else None + req = urllib.request.Request(url, data=payload, method=method) + req.add_header("Authorization", f"token {GITEA_TOKEN}") + req.add_header("Content-Type", "application/json") + try: + with urllib.request.urlopen(req) as resp: + raw = resp.read() + if not raw: + return {} + return json.loads(raw) + except urllib.error.HTTPError as e: + body = e.read().decode() + print(f"API Error {e.code}: {body}", file=sys.stderr) + return None + + # ── Issue operations ───────────────────────────────────────────────────────── def list_issues(labels: list[str] | None = None): @@ -82,17 +103,17 @@ def _get_blocking_refs(issue_num: int) -> set[int]: """ refs: set[int] = set() # Body - issue = _req("GET", f"/issues/{issue_num}") + issue = _req_safe("GET", f"/issues/{issue_num}") + if issue is None: + return refs # API error → return empty set, keep blocked body = issue.get("body", "") or "" refs.update(int(m.group(1)) for m in re.finditer(r'#(\d+)', body)) # Comments - try: - comments = _req("GET", f"/issues/{issue_num}/comments") + comments = _req_safe("GET", f"/issues/{issue_num}/comments") + if comments: for c in comments: cbody = c.get("body", "") or "" refs.update(int(m.group(1)) for m in re.finditer(r'#(\d+)', cbody)) - except SystemExit: - pass return refs @@ -103,12 +124,7 @@ def blocked_check(): If no references found or all referenced issues are closed, removes the 'blocked' label. """ - try: - all_blocked = _req("GET", "/issues?state=open&labels=blocked") - except SystemExit: - print("No blocked issues found.") - return - + all_blocked = _req_safe("GET", "/issues?state=open&labels=blocked") if not all_blocked: print("No blocked issues found.") return @@ -119,13 +135,13 @@ def blocked_check(): all_resolved = True for blk in blocking_nums: - try: - blk_issue = _req("GET", f"/issues/{blk}") - if blk_issue.get("state") != "closed": - all_resolved = False - break - except SystemExit: - pass + blk_issue = _req_safe("GET", f"/issues/{blk}") + if blk_issue is None: + all_resolved = False # API error → keep blocked + break + if blk_issue.get("state") != "closed": + all_resolved = False + break if all_resolved: current_label_names = [l["name"] for l in issue.get("labels", [])] @@ -179,10 +195,7 @@ def _unblock_issues_blocked_by(closed_num): in any blocked issue and all referenced issues are now closed, removes the 'blocked' label and comments on the unblocked issue. """ - try: - all_blocked = _req("GET", "/issues?state=open&labels=blocked") - except SystemExit: - return + all_blocked = _req_safe("GET", "/issues?state=open&labels=blocked") if not all_blocked: return @@ -196,13 +209,13 @@ def _unblock_issues_blocked_by(closed_num): for blk in blocking_nums: if blk == closed_num: continue - try: - blk_issue = _req("GET", f"/issues/{blk}") - if blk_issue.get("state") != "closed": - all_resolved = False - break - except SystemExit: - pass # Inaccessible → treat as resolved + blk_issue = _req_safe("GET", f"/issues/{blk}") + if blk_issue is None: + all_resolved = False # API error → keep blocked + break + if blk_issue.get("state") != "closed": + all_resolved = False + break if all_resolved: current_label_names = [l["name"] for l in issue.get("labels", [])]