Skip to content

Commit 4132f5d

Browse files
authored
Merge pull request #4 from ESPToolKit/release-after-ci-gate
Gate tag releases on successful CI
2 parents 6dce138 + ca28818 commit 4132f5d

2 files changed

Lines changed: 68 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ name: CI
33
on:
44
push:
55
branches: [ main, master ]
6+
tags: ['v*']
67
pull_request:
78
workflow_dispatch:
89

.github/workflows/release.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,76 @@ on:
88
jobs:
99
create-release:
1010
runs-on: ubuntu-latest
11+
concurrency:
12+
group: release-${{ github.ref }}
13+
cancel-in-progress: false
1114
permissions:
15+
actions: read
1216
contents: write
1317
steps:
18+
- name: Wait for CI workflow success
19+
uses: actions/github-script@v7
20+
with:
21+
script: |
22+
const owner = context.repo.owner;
23+
const repo = context.repo.repo;
24+
const targetSha = context.sha;
25+
const targetRef = context.ref;
26+
const targetTag = targetRef.replace('refs/tags/', '');
27+
const workflowId = 'ci.yml';
28+
const pollMs = 20000;
29+
const timeoutMs = 45 * 60 * 1000;
30+
const startedAt = Date.now();
31+
const failingConclusions = new Set(['failure', 'cancelled', 'timed_out', 'action_required']);
32+
33+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
34+
35+
core.info(`Waiting for CI workflow (${workflowId}) success on ${targetRef} (${targetSha})`);
36+
37+
while (true) {
38+
const { data } = await github.rest.actions.listWorkflowRuns({
39+
owner,
40+
repo,
41+
workflow_id: workflowId,
42+
event: 'push',
43+
head_sha: targetSha,
44+
per_page: 100,
45+
});
46+
47+
const matchingRuns = data.workflow_runs
48+
.filter((run) => run.ref === targetRef)
49+
.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
50+
51+
if (matchingRuns.length > 0) {
52+
const run = matchingRuns[0];
53+
core.info(`Found CI run #${run.run_number}: status=${run.status}, conclusion=${run.conclusion ?? 'n/a'}`);
54+
55+
if (run.status === 'completed') {
56+
if (run.conclusion === 'success') {
57+
core.info(`CI succeeded for ${targetTag}. Continuing release.`);
58+
return;
59+
}
60+
61+
if (failingConclusions.has(run.conclusion)) {
62+
core.setFailed(`CI did not succeed for ${targetTag}. Conclusion: ${run.conclusion}.`);
63+
return;
64+
}
65+
66+
core.setFailed(`CI completed without success for ${targetTag}. Conclusion: ${run.conclusion ?? 'unknown'}.`);
67+
return;
68+
}
69+
} else {
70+
core.info('CI run for this tag is not visible yet. Waiting...');
71+
}
72+
73+
if (Date.now() - startedAt >= timeoutMs) {
74+
core.setFailed(`Timed out after ${timeoutMs / 60000} minutes waiting for successful CI on ${targetTag}.`);
75+
return;
76+
}
77+
78+
await sleep(pollMs);
79+
}
80+
1481
- name: Checkout
1582
uses: actions/checkout@v4
1683

0 commit comments

Comments
 (0)