|
24 | 24 | from collections import defaultdict |
25 | 25 | from dataclasses import dataclass |
26 | 26 | from datetime import datetime, timedelta, timezone |
27 | | -from typing import DefaultDict, Dict, Iterable, List, Optional, Tuple, Union |
| 27 | +from typing import DefaultDict, Dict, Iterable, List, Optional, Tuple |
28 | 28 |
|
29 | 29 | import numpy as np |
30 | 30 | from tabulate import tabulate |
@@ -69,29 +69,6 @@ def label_combo_key(labels: Iterable[str]) -> Tuple[str, ...]: |
69 | 69 | return tuple(sorted(labels)) |
70 | 70 |
|
71 | 71 |
|
72 | | -# |
73 | | -# PyGithub requester helper: handle variable return shapes from requestJsonAndCheck |
74 | | -# |
75 | | -def _req_json_and_headers(requester, path: str): |
76 | | - try: |
77 | | - res = requester.requestJsonAndCheck("GET", path, headers={}) |
78 | | - except Exception: |
79 | | - raise |
80 | | - if isinstance(res, (tuple, list)): |
81 | | - if len(res) == 3: |
82 | | - data, _, headers = res |
83 | | - return data, headers or {} |
84 | | - elif len(res) == 2: |
85 | | - data, headers = res |
86 | | - return data, headers or {} |
87 | | - else: |
88 | | - data = res[0] |
89 | | - headers = res[-1] if len(res) > 1 else {} |
90 | | - return data, headers or {} |
91 | | - else: |
92 | | - return res, {} |
93 | | - |
94 | | - |
95 | 72 | def get_workflow_id_by_path(repo, workflow_ref: str) -> int: |
96 | 73 | LOG.info("Resolving workflow reference: %r", workflow_ref) |
97 | 74 |
|
@@ -190,47 +167,6 @@ def iter_successful_runs( |
190 | 167 | ) |
191 | 168 |
|
192 | 169 |
|
193 | | -def iter_jobs_for_run(run) -> Iterable[Union[dict, object]]: |
194 | | - """ |
195 | | - Yield job dicts or PyGithub Job objects for the run. |
196 | | - Prefer run.jobs() (PyGithub), else fallback to raw jobs endpoint with pagination. |
197 | | - """ |
198 | | - try: |
199 | | - yield from run.jobs() |
200 | | - return |
201 | | - except Exception as e: |
202 | | - LOG.debug( |
203 | | - "run.jobs() failed for run %s: %s. Falling back to raw jobs API.", |
204 | | - getattr(run, "id", None), |
205 | | - e, |
206 | | - ) |
207 | | - |
208 | | - try: |
209 | | - requester = run._requester |
210 | | - owner = run.repository.owner.login |
211 | | - repo = run.repository.name |
212 | | - path = f"/repos/{owner}/{repo}/actions/runs/{run.id}/jobs?per_page=100" |
213 | | - while path: |
214 | | - data, headers = _req_json_and_headers(requester, path) |
215 | | - yield from data.get("jobs", []) |
216 | | - |
217 | | - link = headers.get("link") or headers.get("Link") |
218 | | - next_url = None |
219 | | - if link: |
220 | | - parts = [p.strip() for p in link.split(",")] |
221 | | - for p in parts: |
222 | | - if 'rel="next"' in p: |
223 | | - next_url = p.split(";")[0].strip().strip("<>") |
224 | | - break |
225 | | - |
226 | | - if next_url and next_url.startswith("https://api.github.com"): |
227 | | - path = next_url.replace("https://api.github.com", "") |
228 | | - else: |
229 | | - path = None |
230 | | - except Exception as e: |
231 | | - LOG.error("Raw jobs API failed for run %s: %s", getattr(run, "id", None), e) |
232 | | - |
233 | | - |
234 | 170 | def _extract_steps_from_job(job_obj) -> List[Dict]: |
235 | 171 | if isinstance(job_obj, dict): |
236 | 172 | return job_obj.get("steps") or [] |
@@ -341,7 +277,7 @@ def matches(n: Optional[str]) -> bool: |
341 | 277 |
|
342 | 278 |
|
343 | 279 | def get_job_duration_seconds(run, job_name: str, match_mode: str) -> Optional[float]: |
344 | | - jobs = list(iter_jobs_for_run(run)) |
| 280 | + jobs = list(run.jobs(_filter="latest")) |
345 | 281 | LOG.debug( |
346 | 282 | "Run %s has %d jobs (via chosen method)", getattr(run, "id", None), len(jobs) |
347 | 283 | ) |
|
0 commit comments