1+ name : Waiting Coverage project
2+
3+ on :
4+ pull_request :
5+ branches : [ 'develop', 'release_**' ]
6+ types : [ opened, synchronize, reopened ]
7+
8+ permissions :
9+ contents : read
10+ checks : read
11+ statuses : read
12+ pull-requests : read
13+
14+ concurrency :
15+ group : ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
16+ cancel-in-progress : true
17+
18+ jobs :
19+ waiting-coverage-project :
20+ name : waiting-coverage-report
21+ runs-on : ubuntu-latest
22+ timeout-minutes : 70
23+
24+ steps :
25+ - name : Wait for codecov/project status
26+ uses : actions/github-script@v8
27+ with :
28+ script : |
29+ const owner = context.repo.owner;
30+ const repo = context.repo.repo;
31+ const ref = context.payload.pull_request.head.sha;
32+
33+ const targetContext = 'codecov/project';
34+ const maxAttempts = 120; // 120 * 30s = 60 minutes
35+ const intervalMs = 30 * 1000;
36+
37+ function sleep(ms) {
38+ return new Promise(resolve => setTimeout(resolve, ms));
39+ }
40+
41+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
42+ core.info(`Polling attempt ${attempt}/${maxAttempts} for ${targetContext} on ${ref}`);
43+
44+ try {
45+ // Check legacy commit statuses
46+ const combined = await github.rest.repos.getCombinedStatusForRef({
47+ owner,
48+ repo,
49+ ref,
50+ per_page: 100
51+ });
52+
53+ const statuses = combined.data.statuses || [];
54+ const matchedStatus = statuses.find(s => s.context === targetContext);
55+
56+ if (matchedStatus) {
57+ core.info(`Found commit status: ${matchedStatus.context} = ${matchedStatus.state}`);
58+
59+ if (matchedStatus.state === 'success') {
60+ core.info(`${targetContext} succeeded.`);
61+ return;
62+ }
63+
64+ if (matchedStatus.state === 'failure' || matchedStatus.state === 'error') {
65+ core.setFailed(`${targetContext} is ${matchedStatus.state}.`);
66+ return;
67+ }
68+
69+ // pending
70+ await sleep(intervalMs);
71+ continue;
72+ }
73+
74+ // Check check-runs as a fallback
75+ const checks = await github.rest.checks.listForRef({
76+ owner,
77+ repo,
78+ ref
79+ });
80+
81+ const checkRuns = checks.data.check_runs || [];
82+ const matchedCheck = checkRuns.find(c => c.name === targetContext);
83+
84+ if (matchedCheck) {
85+ core.info(
86+ `Found check run: ${matchedCheck.name}, status=${matchedCheck.status}, conclusion=${matchedCheck.conclusion}`
87+ );
88+
89+ if (matchedCheck.status === 'completed') {
90+ if (matchedCheck.conclusion === 'success') {
91+ core.info(`${targetContext} succeeded.`);
92+ return;
93+ }
94+
95+ core.setFailed(
96+ `${targetContext} completed with conclusion=${matchedCheck.conclusion}.`
97+ );
98+ return;
99+ }
100+
101+ // queued / in_progress
102+ await sleep(intervalMs);
103+ continue;
104+ }
105+
106+ core.info(`${targetContext} not reported yet. Waiting...`);
107+ } catch (error) {
108+ core.warning(
109+ `Attempt ${attempt}/${maxAttempts} failed with transient error: ${error.message}. Retrying in ${intervalMs / 1000}s...`
110+ );
111+ }
112+
113+ await sleep(intervalMs);
114+ }
115+
116+ core.setFailed(
117+ `Timed out waiting for ${targetContext} to report success on commit ${ref}.`
118+ );
0 commit comments