2222 timeout-minutes : 180
2323 permissions :
2424 checks : read
25+ pull-requests : read
2526 steps :
2627 - name : Wait for CI checks to complete
2728 uses : actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
@@ -43,19 +44,47 @@ jobs:
4344 const excludedApps = new Set(['mergify']);
4445
4546 const terminalStatuses = new Set(['completed']);
46- const successConclusions = new Set(['success', 'skipped', 'neutral', 'cancelled']);
47- const failureConclusions = new Set(['failure', 'timed_out']);
47+ const successConclusions = new Set(['success', 'skipped', 'neutral']);
48+ const failureConclusions = new Set(['failure', 'timed_out', 'cancelled', 'action_required', 'startup_failure', 'stale']);
49+ const replayCheckPrefix = 'Integration Tests (';
50+ const recordCheckPrefix = 'record-providers (';
51+
52+ function pathTriggersReplay(path) {
53+ if (path.startsWith('src/ogx_ui/')) return false;
54+ return path.startsWith('src/ogx/') ||
55+ path.startsWith('tests/') ||
56+ path === 'uv.lock' ||
57+ path === 'pyproject.toml' ||
58+ path === '.github/workflows/integration-tests.yml' ||
59+ path === '.github/actions/setup-ollama/action.yml' ||
60+ path === '.github/actions/setup-test-environment/action.yml' ||
61+ path === '.github/actions/run-and-record-tests/action.yml' ||
62+ path === 'scripts/integration-tests.sh' ||
63+ path === 'scripts/generate_ci_matrix.py';
64+ }
65+
66+ let replayRequired = context.eventName === 'merge_group';
67+ if (context.payload.pull_request) {
68+ const changedFiles = await github.paginate(github.rest.pulls.listFiles, {
69+ owner,
70+ repo,
71+ pull_number: context.payload.pull_request.number,
72+ per_page: 100,
73+ });
74+ replayRequired = changedFiles.some(file => pathTriggersReplay(file.filename));
75+ core.info(`Replay required: ${replayRequired} (${changedFiles.length} changed file(s) checked)`);
76+ }
4877
4978 while (true) {
50- const { data: checkRuns } = await github.rest.checks.listForRef( {
79+ const checkRuns = await github.paginate(github. rest.checks.listForRef, {
5180 owner,
5281 repo,
5382 ref: sha,
5483 per_page: 100,
5584 });
5685
5786 // Filter to only GitHub Actions checks, excluding ourselves and bots
58- const relevant = checkRuns.check_runs. filter(cr => {
87+ const relevant = checkRuns.filter(cr => {
5988 if (excludedChecks.has(cr.name)) return false;
6089 if (cr.app && excludedApps.has(cr.app.slug)) return false;
6190 // Only include GitHub Actions checks
@@ -71,8 +100,11 @@ jobs:
71100
72101 const pending = relevant.filter(cr => !terminalStatuses.has(cr.status));
73102 const completed = relevant.filter(cr => terminalStatuses.has(cr.status));
103+ const replayChecks = relevant.filter(cr => cr.name.startsWith(replayCheckPrefix));
104+ const recordChecks = relevant.filter(cr => cr.name.startsWith(recordCheckPrefix));
74105
75106 core.info(`Checks: ${completed.length} completed, ${pending.length} pending out of ${relevant.length} total`);
107+ core.info(`Replay checks: ${replayChecks.length}; record checks: ${recordChecks.length}`);
76108
77109 for (const cr of completed) {
78110 core.info(` ✓ ${cr.name}: ${cr.conclusion}`);
@@ -87,6 +119,15 @@ jobs:
87119 continue;
88120 }
89121
122+ if (replayRequired && replayChecks.length === 0) {
123+ if (recordChecks.length > 0) {
124+ core.warning('Record checks are present, but no replay matrix checks were found for this SHA.');
125+ }
126+ core.info('Replay checks are required for this change. Waiting 30s for the replay workflow to appear...');
127+ await new Promise(r => setTimeout(r, 30000));
128+ continue;
129+ }
130+
90131 // All checks completed — evaluate conclusions
91132 const failed = completed.filter(cr => failureConclusions.has(cr.conclusion));
92133
0 commit comments