Skip to content

Commit a15e68c

Browse files
committed
Fix daily workflow failure notifications
1 parent f3bc077 commit a15e68c

2 files changed

Lines changed: 84 additions & 0 deletions

File tree

.github/scripts/rerun-failed-workflow-jobs.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def main() -> None:
2828
rerun_attempts = run["run_attempt"] - 1
2929
if rerun_attempts >= max_rerun_attempts:
3030
print(f"Skipped {label}: already rerun {rerun_attempts} times.")
31+
open_issue_if_missing(owner, repo, run)
3132
return
3233

3334
ignored_job_suffixes = tuple(
@@ -54,6 +55,7 @@ def main() -> None:
5455
f"Skipped {label}: {len(failed_real_jobs)} failed jobs"
5556
f" exceeded limit {max_failed_jobs}."
5657
)
58+
open_issue_or_add_comment(owner, repo, run)
5759
return
5860

5961
subprocess.run(
@@ -92,6 +94,87 @@ def gh_get(path: str, query: dict[str, str] | None = None):
9294
return json.loads(result.stdout) if result.stdout.strip() else {}
9395

9496

97+
def open_issue_if_missing(owner: str, repo: str, run: dict) -> None:
98+
if find_workflow_issue_number(owner, repo, run) is not None:
99+
return
100+
create_workflow_issue(owner, repo, run)
101+
102+
103+
def open_issue_or_add_comment(owner: str, repo: str, run: dict) -> None:
104+
number = find_workflow_issue_number(owner, repo, run)
105+
if number is None:
106+
create_workflow_issue(owner, repo, run)
107+
else:
108+
subprocess.run(
109+
[
110+
"gh",
111+
"issue",
112+
"comment",
113+
str(number),
114+
"--repo",
115+
f"{owner}/{repo}",
116+
"--body",
117+
workflow_issue_body(owner, repo, run),
118+
],
119+
check=True,
120+
)
121+
122+
123+
def find_workflow_issue_number(owner: str, repo: str, run: dict) -> int | None:
124+
title = workflow_issue_title(run)
125+
result = subprocess.run(
126+
[
127+
"gh",
128+
"issue",
129+
"list",
130+
"--repo",
131+
f"{owner}/{repo}",
132+
"--search",
133+
f"in:title {title}",
134+
"--limit",
135+
"20",
136+
"--json",
137+
"number,title",
138+
],
139+
capture_output=True,
140+
text=True,
141+
check=True,
142+
)
143+
for issue in json.loads(result.stdout):
144+
issue_title = issue.get("title") or ""
145+
if issue_title == title or issue_title.startswith(f"{title} (#"):
146+
return issue["number"]
147+
return None
148+
149+
150+
def create_workflow_issue(owner: str, repo: str, run: dict) -> None:
151+
subprocess.run(
152+
[
153+
"gh",
154+
"issue",
155+
"create",
156+
"--repo",
157+
f"{owner}/{repo}",
158+
"--title",
159+
f"{workflow_issue_title(run)} (#{run['run_number']})",
160+
"--body",
161+
workflow_issue_body(owner, repo, run),
162+
],
163+
check=True,
164+
)
165+
166+
167+
def workflow_issue_title(run: dict) -> str:
168+
return f"Workflow failed: {run['name']}"
169+
170+
171+
def workflow_issue_body(owner: str, repo: str, run: dict) -> str:
172+
return (
173+
f"See [{run['name']} #{run['run_number']}]"
174+
f"(https://github.com/{owner}/{repo}/actions/runs/{run['id']})."
175+
)
176+
177+
95178
def resolve_pr_number(owner: str, repo: str, run: dict) -> int | None:
96179
pull_requests = run.get("pull_requests") or []
97180
if pull_requests:

.github/workflows/rerun-failed-daily-jobs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ jobs:
2121
permissions:
2222
contents: read
2323
actions: write
24+
issues: write
2425
runs-on: ubuntu-latest
2526
timeout-minutes: 10
2627
if: github.event.workflow_run.conclusion == 'failure'

0 commit comments

Comments
 (0)