Skip to content

Commit 457455a

Browse files
committed
[CI] Add rerun bot
1 parent 5025c97 commit 457455a

File tree

1 file changed

+149
-0
lines changed

1 file changed

+149
-0
lines changed
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
name: Rerun Workflows
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
7+
jobs:
8+
rerun:
9+
name: Rerun CI Workflows
10+
# Only run on PR comments (not issue comments) with /rerun command
11+
if: |
12+
github.event.issue.pull_request &&
13+
contains(github.event.comment.body, '/rerun')
14+
runs-on: ubuntu-latest
15+
permissions:
16+
actions: write
17+
pull-requests: read
18+
contents: read
19+
20+
steps:
21+
- name: Get PR SHA
22+
id: pr
23+
uses: actions/github-script@v7
24+
with:
25+
script: |
26+
const { data: pr } = await github.rest.pulls.get({
27+
owner: context.repo.owner,
28+
repo: context.repo.repo,
29+
pull_number: context.issue.number
30+
});
31+
core.setOutput('sha', pr.head.sha);
32+
core.setOutput('head_ref', pr.head.ref);
33+
console.log(`PR #${context.issue.number} SHA: ${pr.head.sha}`);
34+
console.log(`PR head ref: ${pr.head.ref}`);
35+
36+
- name: Add reaction to comment
37+
uses: actions/github-script@v7
38+
with:
39+
script: |
40+
await github.rest.reactions.createForIssueComment({
41+
owner: context.repo.owner,
42+
repo: context.repo.repo,
43+
comment_id: context.payload.comment.id,
44+
content: 'rocket'
45+
});
46+
47+
- name: Post start comment
48+
uses: actions/github-script@v7
49+
with:
50+
script: |
51+
const comment = context.payload.comment.body;
52+
const rerunMatch = comment.match(/\/rerun\s*(\S+)?/);
53+
const rerunArg = rerunMatch && rerunMatch[1] ? rerunMatch[1] : 'failed';
54+
55+
await github.rest.issues.createComment({
56+
owner: context.repo.owner,
57+
repo: context.repo.repo,
58+
issue_number: context.issue.number,
59+
body: `🚀 **Workflow rerun started**\n\nMode: \`${rerunArg}\`\nTriggered by: @${context.payload.comment.user.login}\n\n[View Actions](https://github.com/${context.repo.owner}/${context.repo.repo}/actions)`
60+
});
61+
62+
- name: Rerun failed workflows
63+
uses: actions/github-script@v7
64+
with:
65+
script: |
66+
const sha = '${{ steps.pr.outputs.sha }}';
67+
const headRef = '${{ steps.pr.outputs.head_ref }}';
68+
69+
// Get all workflow runs for this PR's head SHA
70+
const { data: runs } = await github.rest.actions.listWorkflowRunsForRepo({
71+
owner: context.repo.owner,
72+
repo: context.repo.repo,
73+
head_sha: sha,
74+
per_page: 100
75+
});
76+
77+
console.log(`Found ${runs.total_count} workflow runs for SHA ${sha}`);
78+
79+
if (runs.total_count === 0) {
80+
console.log('No workflow runs found for this PR');
81+
return;
82+
}
83+
84+
// Parse command for specific workflow filter
85+
// Supports: /rerun, /rerun all, /rerun failed, /rerun <workflow-name>
86+
const comment = context.payload.comment.body;
87+
const rerunMatch = comment.match(/\/rerun\s*(\S+)?/);
88+
const rerunArg = rerunMatch && rerunMatch[1] ? rerunMatch[1].toLowerCase() : 'failed';
89+
90+
console.log(`Rerun mode: ${rerunArg}`);
91+
92+
let rerunCount = 0;
93+
94+
for (const run of runs.workflow_runs) {
95+
const shouldRerun =
96+
rerunArg === 'all' ||
97+
(rerunArg === 'failed' && ['failure', 'cancelled', 'timed_out'].includes(run.conclusion)) ||
98+
run.name.toLowerCase().includes(rerunArg);
99+
100+
if (!shouldRerun) {
101+
console.log(`Skipping ${run.name} (status: ${run.status}, conclusion: ${run.conclusion})`);
102+
continue;
103+
}
104+
105+
// Only rerun completed workflows
106+
if (run.status !== 'completed') {
107+
console.log(`Skipping ${run.name} - still ${run.status}`);
108+
continue;
109+
}
110+
111+
try {
112+
console.log(`Rerunning workflow: ${run.name} (ID: ${run.id})`);
113+
114+
// Use rerun-failed-jobs if available and workflow failed, otherwise full rerun
115+
if (['failure', 'cancelled', 'timed_out'].includes(run.conclusion)) {
116+
await github.rest.actions.reRunWorkflowFailedJobs({
117+
owner: context.repo.owner,
118+
repo: context.repo.repo,
119+
run_id: run.id
120+
});
121+
} else {
122+
await github.rest.actions.reRunWorkflow({
123+
owner: context.repo.owner,
124+
repo: context.repo.repo,
125+
run_id: run.id
126+
});
127+
}
128+
rerunCount++;
129+
} catch (error) {
130+
console.log(`Failed to rerun ${run.name}: ${error.message}`);
131+
}
132+
}
133+
134+
console.log(`Reran ${rerunCount} workflow(s)`);
135+
136+
- name: Post completion comment
137+
if: always()
138+
uses: actions/github-script@v7
139+
with:
140+
script: |
141+
const status = '${{ job.status }}';
142+
const emoji = status === 'success' ? '✅' : '❌';
143+
144+
await github.rest.issues.createComment({
145+
owner: context.repo.owner,
146+
repo: context.repo.repo,
147+
issue_number: context.issue.number,
148+
body: `${emoji} **Workflow rerun ${status}**\n\n[View Actions](https://github.com/${context.repo.owner}/${context.repo.repo}/actions)`
149+
});

0 commit comments

Comments
 (0)