feat: add workflow run URL to /rerun-stage comment (#16825)

This commit is contained in:
Alison Shao
2026-01-10 10:41:20 +08:00
committed by GitHub
parent e91a717632
commit 9c64a15ad4
+91 -2
View File
@@ -2,6 +2,7 @@ import json
import os import os
import sys import sys
import time import time
from datetime import datetime, timezone
import requests import requests
from github import Auth, Github from github import Auth, Github
@@ -10,6 +11,74 @@ from github import Auth, Github
PERMISSIONS_FILE_PATH = ".github/CI_PERMISSIONS.json" PERMISSIONS_FILE_PATH = ".github/CI_PERMISSIONS.json"
def find_workflow_run_url(
gh_repo, workflow_id, ref, target_stage, token, dispatch_time, max_wait=30
):
"""
Poll for the workflow run URL after dispatch.
Args:
gh_repo: PyGithub repository object
workflow_id: ID of the workflow that was dispatched
ref: Branch/ref the workflow was dispatched on
target_stage: The stage name we're looking for
token: GitHub API token
dispatch_time: Unix timestamp when dispatch was triggered
max_wait: Maximum seconds to wait for the run to appear
Returns:
The workflow run URL if found, None otherwise.
"""
for attempt in range(max_wait // 5):
time.sleep(5)
# Get recent workflow_dispatch runs for this workflow
runs_url = f"https://api.github.com/repos/{gh_repo.full_name}/actions/workflows/{workflow_id}/runs"
runs_resp = requests.get(
runs_url,
params={"event": "workflow_dispatch", "branch": ref, "per_page": 10},
headers={
"Authorization": f"Bearer {token}",
"Accept": "application/vnd.github+json",
},
)
if runs_resp.status_code != 200:
print(f"Failed to fetch workflow runs: {runs_resp.status_code}")
continue
for run in runs_resp.json().get("workflow_runs", []):
# Skip runs created before our dispatch (with 10s tolerance)
run_created = datetime.fromisoformat(
run["created_at"].replace("Z", "+00:00")
).timestamp()
if run_created < dispatch_time - 10:
continue
# Verify: check if target_stage job exists and is NOT skipped
# This distinguishes our run from other workflow_dispatch runs
jobs_resp = requests.get(
f"https://api.github.com/repos/{gh_repo.full_name}/actions/runs/{run['id']}/jobs",
headers={
"Authorization": f"Bearer {token}",
"Accept": "application/vnd.github+json",
},
)
if jobs_resp.status_code == 200:
for job in jobs_resp.json().get("jobs", []):
# Match job name containing target_stage
# Job names may include partition suffix like "stage-b-test-small-1-gpu (0)"
if target_stage in job["name"] and job["conclusion"] != "skipped":
print(
f"Found matching workflow run: {run['id']} with job {job['name']}"
)
return run["html_url"]
print(f"Could not find workflow run after {max_wait} seconds")
return None
def get_env_var(name): def get_env_var(name):
val = os.getenv(name) val = os.getenv(name)
if not val: if not val:
@@ -250,6 +319,9 @@ def handle_rerun_stage(
else: else:
inputs = {"version": "release", "target_stage": stage_name} inputs = {"version": "release", "target_stage": stage_name}
# Record dispatch time before triggering
dispatch_time = time.time()
# Use requests directly as PyGithub's create_dispatch only accepts HTTP 204 # Use requests directly as PyGithub's create_dispatch only accepts HTTP 204
dispatch_url = f"https://api.github.com/repos/{gh_repo.full_name}/actions/workflows/{target_workflow.id}/dispatches" dispatch_url = f"https://api.github.com/repos/{gh_repo.full_name}/actions/workflows/{target_workflow.id}/dispatches"
dispatch_resp = requests.post( dispatch_resp = requests.post(
@@ -269,9 +341,26 @@ def handle_rerun_stage(
if react_on_success: if react_on_success:
comment.create_reaction("+1") comment.create_reaction("+1")
pr.create_issue_comment( pr.create_issue_comment(
f"✅ Triggered `{stage_name}` to run independently (skipping dependencies).\n\n" f"✅ Triggered `{stage_name}` to run independently (skipping dependencies)."
f"It will not be shown in this page. Check the [Actions tab](https://github.com/{gh_repo.full_name}/actions) for progress."
) )
# Poll for the workflow run URL and post follow-up comment
run_url = find_workflow_run_url(
gh_repo,
target_workflow.id,
ref,
stage_name,
token,
dispatch_time,
max_wait=30,
)
if run_url:
pr.create_issue_comment(f"🔗 [View workflow run]({run_url})")
else:
pr.create_issue_comment(
f"⚠️ Could not retrieve workflow run URL. "
f"Check the [Actions tab](https://github.com/{gh_repo.full_name}/actions) for progress."
)
return True return True
else: else:
print("Failed to trigger workflow_dispatch") print("Failed to trigger workflow_dispatch")