-
Notifications
You must be signed in to change notification settings - Fork 11
170 lines (163 loc) · 7.48 KB
/
ready_to_merge.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
name: Ready to Merge
on:
pull_request:
workflow_dispatch:
concurrency:
group: ${{ github.ref }}-ready-to-merge
cancel-in-progress: true
jobs:
ready_to_merge:
runs-on: ubuntu-latest
steps:
- name: Check if PR is ready to merge
uses: actions/github-script@v7
with:
script: |
// Define a list of workflows that need to finish successfully if run before merging
workflows_to_check = [
"all_packages.yml",
"linter.yml",
"mega-linter.yml",
"e2e_tests.yml",
"supabase-test.yml",
];
console.log("Initializing with workflows to check: " + workflows_to_check);
const { owner, repo } = context.repo;
let branch_name;
if (context.payload.pull_request !== undefined) {
// PR event detected
branch_name = context.payload.pull_request.head.ref;
} else {
// Workflow dispatch event detected
branch_name = context.ref.split("/").pop();
}
console.log("Branch name: " + branch_name);
const maxRetries = 15; // Maximum number of retries
async function fetchLatestWorkflowRun(workflowId) {
console.log("Fetching workflow runs for: " + workflowId);
try {
const response = await github.rest.actions.listWorkflowRuns({
owner,
repo,
workflow_id: workflowId,
branch: branch_name,
per_page: 1,
});
return response.data.workflow_runs[0];
} catch (error) {
if (error.status === 404) {
console.warn("Workflow not found: " + workflowId + ". It will be ignored.");
return;
}
core.setFailed("Error fetching workflow runs for: " + workflowId + ". Error: " + error.message);
process.exit();
}
}
async function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
console.log("Sleeping 10s to give other runs a chance to start");
await sleep(10000);
for (const workflowId of workflows_to_check) {
let retryCount = 0;
let inProgressFound = false;
let workflowRun = await fetchLatestWorkflowRun(workflowId);
if (!workflowRun) {
console.log("No workflow runs found for: " + workflowId);
continue;
}
do {
console.log("Checking workflow run: " + workflowRun.name + " with status: " + workflowRun.status + " and conclusion: " + workflowRun.conclusion);
if (retryCount >= maxRetries) {
core.setFailed(
"Maximum retries reached with check runs still in progress."
);
break;
}
if (workflowRun.conclusion === "success" || workflowRun.conclusion === "skipped" || workflowRun.conclusion === "cancelled") {
console.log("Workflow run completed successfully: " + workflowRun.name + " with conclusion: " + workflowRun.conclusion);
break;
}
if (workflowRun.conclusion === "failure") {
console.log("Workflow run failed: " + workflowRun.name);
const checkSuiteId = workflowRun.check_suite_id;
const urlOfFailedCheckSuite = workflowRun.html_url;
const checkRuns = await github.rest.checks.listForSuite({
owner,
repo,
check_suite_id: checkSuiteId,
});
const failedCheckNames = checkRuns.data.check_runs
.filter((checkRun) => checkRun.conclusion === "failure")
.map((checkRun) => checkRun.name);
core.setFailed("The workflow run '" +
workflowRun.name + "' has failed. Please fix the failed checks: '" +
failedCheckNames.join(", ") + "'. Check suite URL: " +
urlOfFailedCheckSuite
);
break;
}
console.log("Waiting for 1 minute before rechecking...");
await sleep(60000);
workflowRun = await fetchLatestWorkflowRun(workflowId);
retryCount++;
} while (true);
}
console.log("All given workflow runs completed.");
// Do not check the check runs for now, since fetchCheckRuns also
// includes the workflows we checked above for the latest commit.
// Todo: find another way to check for checks that are not part
// of this repository e.g. GitGuardian
/*
const commit_sha = context.payload.pull_request.head.sha; // Get the SHA of the head commit of the PR
console.log("commit_sha " + commit_sha);
// exclude the current workflow from the list of workflows to check
const excludedCheckRunName = 'check_commit_status'
// console.log("context sha: " + context.sha);
// console.log("github sha: " + github.sha);
async function fetchCheckRuns() {
const response = await github.rest.checks.listForRef({
owner,
repo,
ref: commit_sha,
per_page: 100,
});
console.log("Found " + response.data.check_runs.length + " check runs.");
return response.data.check_runs;
}
console.log("Checking check runs...");
let checkRuns = await fetchCheckRuns();
let inProgressFound = false;
for (const checkRun of checkRuns) {
let retryCount = 0;
do {
inProgressFound = false;
console.log("Checking check run: " + checkRun.name + " with status: " + checkRun.status + " and conclusion: " + checkRun.conclusion);
if (checkRun.name === excludedCheckRunName) {
console.log("Skipping excluded check run: " + checkRun.name);
break;
}
if (checkRun.status === "in_progress") {
console.log("Check run in progress: " + checkRun.name);
if (retryCount >= maxRetries) {
core.setFailed(
"Maximum retries reached with check runs still in progress."
);
break;
}
console.log("Waiting for 1 minute before rechecking...");
await sleep(60000);
checkRuns = await fetchCheckRuns();
retryCount++;
inProgressFound = true;
}
if (checkRun.conclusion === "failure") {
core.setFailed("The check run '" +
checkRun.name + "' has failed. Please fix the failed checks. Check run URL: " +
checkRun.html_url
);
}
} while (inProgressFound);
}
console.log("All check runs completed successfully.");
*/