Skip to content

Commit d7cea5c

Browse files
Add --run-id option to process specific workflow run
This commit enhances `print_workflow_run_errors.py` by adding a `--run-id` command-line option. This allows users to specify a particular workflow run ID for processing, bypassing the default behavior of searching for the latest run by workflow name and branch. Key changes: - Added `--run-id <ID>` optional argument. - If `--run-id` is provided, the script fetches details for that specific run using a new helper function `get_workflow_run_details_by_id`. The `--workflow` and `--branch` arguments are ignored in this mode. - If `--run-id` is not provided, the script retains its existing behavior of using `--workflow` and `--branch` to find the latest run. - The new helper function includes error handling for invalid or non-existent run IDs. - Standard error messages have been updated to reflect whether the script is processing a run by specified ID or by search criteria.
1 parent e1ce17a commit d7cea5c

File tree

1 file changed

+66
-7
lines changed

1 file changed

+66
-7
lines changed

scripts/print_workflow_run_errors.py

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,37 @@ def _process_and_display_logs_for_failed_jobs(args, list_of_failed_jobs, workflo
223223
sys.stderr.write(f"INFO: Log processing complete for this batch. Successfully fetched and processed logs for {successful_log_fetches}/{total_failed_jobs_to_process} job(s) from pattern '{current_pattern_str}'.\n")
224224

225225

226+
def get_workflow_run_details_by_id(token, run_id_to_fetch):
227+
"""Fetches details for a specific workflow run ID from GitHub API."""
228+
url = f'{GITHUB_API_URL}/actions/runs/{run_id_to_fetch}'
229+
headers = {'Accept': 'application/vnd.github.v3+json', 'Authorization': f'token {token}'}
230+
231+
sys.stderr.write(f"INFO: Fetching details for workflow run ID: {run_id_to_fetch} from {url}\n")
232+
try:
233+
with requests_retry_session().get(url, headers=headers, timeout=TIMEOUT) as response:
234+
response.raise_for_status()
235+
return response.json() # Returns the full run object
236+
except requests.exceptions.HTTPError as e:
237+
if e.response.status_code == 404:
238+
sys.stderr.write(f"ERROR: Workflow run ID {run_id_to_fetch} not found.\n")
239+
else:
240+
sys.stderr.write(f"ERROR: HTTP error fetching details for run ID {run_id_to_fetch}: {e}\n")
241+
if e.response is not None:
242+
# Avoid printing potentially very large HTML error pages from GitHub
243+
try:
244+
error_detail = e.response.json() # Check if there's a JSON error message
245+
sys.stderr.write(f"Response JSON: {json.dumps(error_detail, indent=2)}\n")
246+
except json.JSONDecodeError:
247+
sys.stderr.write(f"Response Text (first 500 chars): {e.response.text[:500]}...\n")
248+
return None
249+
except requests.exceptions.RequestException as e:
250+
sys.stderr.write(f"ERROR: Request failed while fetching details for run ID {run_id_to_fetch}: {e}\n")
251+
return None
252+
except json.JSONDecodeError as e: # Should be caught by RequestException or HTTPError if response is bad
253+
sys.stderr.write(f"ERROR: Failed to parse JSON response for run ID {run_id_to_fetch} details: {e}\n")
254+
return None
255+
256+
226257
def main():
227258
"""Main function to parse arguments and orchestrate the script."""
228259
determined_owner = None
@@ -320,6 +351,12 @@ def parse_repo_url_arg(url_string):
320351
help="Regular expression to filter job names. Can be specified multiple times to check patterns in order. "
321352
"If no patterns are specified, defaults to checking: '^build.*', then '^test.*', then '.*'."
322353
)
354+
parser.add_argument(
355+
"--run-id",
356+
type=int,
357+
default=None,
358+
help="Specify a specific workflow run ID to process. If provided, --workflow and --branch are ignored."
359+
)
323360

324361
args = parser.parse_args()
325362
error_suffix = " (use --help for more details)"
@@ -393,18 +430,40 @@ def parse_repo_url_arg(url_string):
393430
sys.stderr.write(f"Error: Branch name is required. Please specify --branch or ensure it can be detected from your current git repository.{error_suffix}\n")
394431
sys.exit(1)
395432

396-
sys.stderr.write(f"Processing workflow '{args.workflow}' on branch '{args.branch}' for repo {OWNER}/{REPO}\n")
433+
run_details = None # This will hold the workflow run information
434+
435+
if args.run_id:
436+
sys.stderr.write(f"INFO: Attempting to process directly specified workflow run ID: {args.run_id}\n")
437+
# When run_id is given, --workflow and --branch are ignored as per help text.
438+
# We need to fetch the run details to get its html_url and confirm existence.
439+
run_details = get_workflow_run_details_by_id(args.token, args.run_id)
440+
if not run_details:
441+
# get_workflow_run_details_by_id already prints specific errors
442+
sys.stderr.write(f"ERROR: Could not retrieve details for specified run ID {args.run_id}. Exiting.\n")
443+
sys.exit(1)
444+
sys.stderr.write(f"INFO: Successfully fetched details for run ID: {run_details['id']} (Status: {run_details.get('status')}, Conclusion: {run_details.get('conclusion')}, URL: {run_details.get('html_url')})\n")
445+
else:
446+
# Original logic: find run by workflow name and branch
447+
if not args.branch: # This check might be redundant if get_current_branch_name always provides one or script exits
448+
sys.stderr.write(f"Error: --branch is required when --run-id is not specified.{error_suffix}\n")
449+
sys.exit(1)
450+
if not args.workflow: # Should not happen due to default, but good practice
451+
sys.stderr.write(f"Error: --workflow is required when --run-id is not specified.{error_suffix}\n")
452+
sys.exit(1)
397453

398-
run = get_latest_workflow_run(args.token, args.workflow, args.branch)
399-
if not run:
400-
sys.stderr.write(f"No workflow run found for workflow '{args.workflow}' on branch '{args.branch}'.\n")
401-
sys.exit(0)
454+
sys.stderr.write(f"INFO: Searching for latest workflow run for '{args.workflow}' on branch '{args.branch}' in repo {OWNER}/{REPO}...\n")
455+
run_details = get_latest_workflow_run(args.token, args.workflow, args.branch)
456+
if not run_details:
457+
sys.stderr.write(f"INFO: No workflow run found for workflow '{args.workflow}' on branch '{args.branch}'.\n")
458+
sys.exit(0)
459+
sys.stderr.write(f"INFO: Found latest workflow run ID: {run_details['id']} (Status: {run_details.get('status')}, Conclusion: {run_details.get('conclusion')})\n")
402460

403-
sys.stderr.write(f"Found workflow run ID: {run['id']} (Status: {run.get('status')}, Conclusion: {run.get('conclusion')})\n")
461+
# At this point, run_details should be populated either from --run-id or by search
462+
# The rest of the script uses run_details['id'] and run_details.get('html_url')
404463

405464
patterns_to_check = args.job_pattern if args.job_pattern else DEFAULT_JOB_PATTERNS
406465

407-
all_jobs_api_response = get_all_jobs_for_run(args.token, run['id'])
466+
all_jobs_api_response = get_all_jobs_for_run(args.token, run_details['id'])
408467
if all_jobs_api_response is None:
409468
sys.stderr.write(f"Could not retrieve jobs for workflow run ID: {run['id']}. Exiting.\n")
410469
sys.exit(1)

0 commit comments

Comments
 (0)