Skip to content

Commit e8f62c1

Browse files
justin808claude
andcommitted
Fix /run-skipped-ci to detect and run only actually skipped checks
The previous implementation tried to guess which tests to run based on a hardcoded list. This fix makes it smarter: 1. **Fetches actual skipped checks from the PR** - Uses GitHub API to find checks with conclusion='SKIPPED' - Maps workflow names to workflow files - Only triggers workflows that have skipped checks 2. **Added force_run input to ALL workflows** - main.yml, examples.yml, pro-integration-tests.yml, pro-package-tests.yml, pro-lint.yml - When force_run=true, detect-changes outputs true for all checks - Bypasses file change detection that causes skips 3. **Fixed matrix exclusion logic** - When force_run=true, runs BOTH latest and minimum matrices - Ensures comprehensive testing of skipped configurations 4. **Improved PR comments** - Lists all skipped checks that were detected - Shows which workflows were triggered - Clear explanation that force_run bypasses detect-changes Example comment: ``` 🚀 Skipped CI Checks - Trigger Results ✅ Successfully triggered skipped CI checks **Skipped checks detected:** - build-dummy-app-webpack-test-bundles (React on Rails Pro - Integration Tests) - lint-js-and-ruby (React on Rails Pro - Lint) **Triggered workflows:** - ✅ React on Rails Pro - Integration Tests - ✅ React on Rails Pro - Lint **Note:** These workflows will run with `force_run: true` to bypass detect-changes. ``` This fixes the issue where Pro tests were being skipped on PRs without Pro file changes, and ensures the command only runs what's actually needed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent a96800d commit e8f62c1

File tree

6 files changed

+151
-52
lines changed

6 files changed

+151
-52
lines changed

.github/workflows/examples.yml

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ on:
1313
- 'docs/**'
1414
workflow_dispatch:
1515
inputs:
16-
run_minimum_tests:
17-
description: 'Run minimum dependency matrix (Ruby 3.2)'
16+
force_run:
17+
description: 'Force run all jobs (bypass detect-changes)'
1818
required: false
1919
type: boolean
2020
default: false
@@ -38,6 +38,17 @@ jobs:
3838
- name: Detect relevant changes
3939
id: detect
4040
run: |
41+
# If force_run is true, run everything
42+
if [ "${{ inputs.force_run }}" = "true" ]; then
43+
echo "run_lint=true" >> "$GITHUB_OUTPUT"
44+
echo "run_js_tests=true" >> "$GITHUB_OUTPUT"
45+
echo "run_ruby_tests=true" >> "$GITHUB_OUTPUT"
46+
echo "run_dummy_tests=true" >> "$GITHUB_OUTPUT"
47+
echo "run_generators=true" >> "$GITHUB_OUTPUT"
48+
echo "docs_only=false" >> "$GITHUB_OUTPUT"
49+
exit 0
50+
fi
51+
4152
BASE_REF="${{ github.event.pull_request.base.sha || github.event.before || 'origin/master' }}"
4253
script/ci-changes-detector "$BASE_REF"
4354
shell: bash
@@ -58,10 +69,9 @@ jobs:
5869
- ruby-version: '3.2'
5970
dependency-level: 'minimum'
6071
exclude:
61-
# When run_minimum_tests is true, skip latest (run only minimum)
62-
- ${{ inputs.run_minimum_tests && fromJSON('{"ruby-version": "3.4", "dependency-level": "latest"}') || fromJSON('{}') }}
63-
# When run_minimum_tests is false, skip minimum on regular PRs (run only on master/workflow_dispatch)
64-
- ${{ !inputs.run_minimum_tests && github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && fromJSON('{"ruby-version": "3.2", "dependency-level": "minimum"}') || fromJSON('{}') }}
72+
# Skip minimum dependency matrix on regular PRs (run only on master/workflow_dispatch/force_run)
73+
- ruby-version: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && '3.2' || '' }}
74+
dependency-level: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && 'minimum' || '' }}
6575
env:
6676
SKIP_YARN_COREPACK_CHECK: 0
6777
BUNDLE_FROZEN: ${{ matrix.dependency-level == 'minimum' && 'false' || 'true' }}

.github/workflows/main.yml

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ on:
1313
- 'docs/**'
1414
workflow_dispatch:
1515
inputs:
16-
run_minimum_tests:
17-
description: 'Run minimum dependency matrix (Ruby 3.2, Node 20)'
16+
force_run:
17+
description: 'Force run all jobs (bypass detect-changes)'
1818
required: false
1919
type: boolean
2020
default: false
@@ -38,6 +38,17 @@ jobs:
3838
- name: Detect relevant changes
3939
id: detect
4040
run: |
41+
# If force_run is true, run everything
42+
if [ "${{ inputs.force_run }}" = "true" ]; then
43+
echo "run_lint=true" >> "$GITHUB_OUTPUT"
44+
echo "run_js_tests=true" >> "$GITHUB_OUTPUT"
45+
echo "run_ruby_tests=true" >> "$GITHUB_OUTPUT"
46+
echo "run_dummy_tests=true" >> "$GITHUB_OUTPUT"
47+
echo "run_generators=true" >> "$GITHUB_OUTPUT"
48+
echo "docs_only=false" >> "$GITHUB_OUTPUT"
49+
exit 0
50+
fi
51+
4152
BASE_REF="${{ github.event.pull_request.base.sha || github.event.before || 'origin/master' }}"
4253
script/ci-changes-detector "$BASE_REF"
4354
shell: bash
@@ -59,10 +70,10 @@ jobs:
5970
node-version: '20'
6071
dependency-level: 'minimum'
6172
exclude:
62-
# When run_minimum_tests is true, skip latest (run only minimum)
63-
- ${{ inputs.run_minimum_tests && fromJSON('{"ruby-version": "3.4", "node-version": "22", "dependency-level": "latest"}') || fromJSON('{}') }}
64-
# When run_minimum_tests is false, skip minimum on regular PRs (run only on master/workflow_dispatch)
65-
- ${{ !inputs.run_minimum_tests && github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && fromJSON('{"ruby-version": "3.2", "node-version": "20", "dependency-level": "minimum"}') || fromJSON('{}') }}
73+
# Skip minimum dependency matrix on regular PRs (run only on master/workflow_dispatch/force_run)
74+
- ruby-version: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && '3.2' || '' }}
75+
node-version: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && '20' || '' }}
76+
dependency-level: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && 'minimum' || '' }}
6677
runs-on: ubuntu-22.04
6778
steps:
6879
- uses: actions/checkout@v4
@@ -149,10 +160,10 @@ jobs:
149160
node-version: '20'
150161
dependency-level: 'minimum'
151162
exclude:
152-
# When run_minimum_tests is true, skip latest (run only minimum)
153-
- ${{ inputs.run_minimum_tests && fromJSON('{"ruby-version": "3.4", "node-version": "22", "dependency-level": "latest"}') || fromJSON('{}') }}
154-
# When run_minimum_tests is false, skip minimum on regular PRs (run only on master/workflow_dispatch)
155-
- ${{ !inputs.run_minimum_tests && github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && fromJSON('{"ruby-version": "3.2", "node-version": "20", "dependency-level": "minimum"}') || fromJSON('{}') }}
163+
# Skip minimum dependency matrix on regular PRs (run only on master/workflow_dispatch/force_run)
164+
- ruby-version: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && '3.2' || '' }}
165+
node-version: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && '20' || '' }}
166+
dependency-level: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && 'minimum' || '' }}
156167
runs-on: ubuntu-22.04
157168
steps:
158169
- uses: actions/checkout@v4

.github/workflows/pro-integration-tests.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ on:
66
- 'master'
77
pull_request:
88
workflow_dispatch:
9+
inputs:
10+
force_run:
11+
description: 'Force run all jobs (bypass detect-changes)'
12+
required: false
13+
type: boolean
14+
default: false
915

1016
defaults:
1117
run:
@@ -27,6 +33,14 @@ jobs:
2733
id: detect
2834
working-directory: .
2935
run: |
36+
# If force_run is true, run everything
37+
if [ "${{ inputs.force_run }}" = "true" ]; then
38+
echo "run_pro_lint=true" >> "$GITHUB_OUTPUT"
39+
echo "run_pro_tests=true" >> "$GITHUB_OUTPUT"
40+
echo "docs_only=false" >> "$GITHUB_OUTPUT"
41+
exit 0
42+
fi
43+
3044
BASE_REF="${{ github.event.pull_request.base.sha || github.event.before || 'origin/master' }}"
3145
script/ci-changes-detector "$BASE_REF"
3246
shell: bash

.github/workflows/pro-lint.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ on:
66
- 'master'
77
pull_request:
88
workflow_dispatch:
9+
inputs:
10+
force_run:
11+
description: 'Force run all jobs (bypass detect-changes)'
12+
required: false
13+
type: boolean
14+
default: false
915

1016
defaults:
1117
run:
@@ -27,6 +33,14 @@ jobs:
2733
id: detect
2834
working-directory: .
2935
run: |
36+
# If force_run is true, run everything
37+
if [ "${{ inputs.force_run }}" = "true" ]; then
38+
echo "run_pro_lint=true" >> "$GITHUB_OUTPUT"
39+
echo "run_pro_tests=true" >> "$GITHUB_OUTPUT"
40+
echo "docs_only=false" >> "$GITHUB_OUTPUT"
41+
exit 0
42+
fi
43+
3044
BASE_REF="${{ github.event.pull_request.base.sha || github.event.before || 'origin/master' }}"
3145
script/ci-changes-detector "$BASE_REF"
3246
shell: bash

.github/workflows/pro-package-tests.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ on:
66
- 'master'
77
pull_request:
88
workflow_dispatch:
9+
inputs:
10+
force_run:
11+
description: 'Force run all jobs (bypass detect-changes)'
12+
required: false
13+
type: boolean
14+
default: false
915

1016
defaults:
1117
run:
@@ -27,6 +33,14 @@ jobs:
2733
id: detect
2834
working-directory: .
2935
run: |
36+
# If force_run is true, run everything
37+
if [ "${{ inputs.force_run }}" = "true" ]; then
38+
echo "run_pro_lint=true" >> "$GITHUB_OUTPUT"
39+
echo "run_pro_tests=true" >> "$GITHUB_OUTPUT"
40+
echo "docs_only=false" >> "$GITHUB_OUTPUT"
41+
exit 0
42+
fi
43+
3044
BASE_REF="${{ github.event.pull_request.base.sha || github.event.before || 'origin/master' }}"
3145
script/ci-changes-detector "$BASE_REF"
3246
shell: bash

.github/workflows/run-skipped-ci.yml

Lines changed: 72 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -81,53 +81,83 @@ jobs:
8181
sha: pr.data.head.sha
8282
};
8383
84-
- name: Trigger all workflows and collect results
84+
- name: Get skipped checks and trigger workflows
8585
id: trigger_workflows
8686
uses: actions/github-script@v7
8787
with:
8888
script: |
8989
const prData = ${{ steps.pr.outputs.result }};
9090
91-
// Workflows that support minimum dependency testing
92-
const workflowsWithMinimum = [
93-
{ id: 'main.yml', name: 'Main Tests' },
94-
{ id: 'examples.yml', name: 'Generator Tests' }
95-
];
91+
// Fetch PR checks to find skipped ones
92+
const { data: pr } = await github.rest.pulls.get({
93+
owner: context.repo.owner,
94+
repo: context.repo.repo,
95+
pull_number: context.issue.number
96+
});
9697
97-
// Pro workflows always run (no minimum matrix)
98-
const proWorkflows = [
99-
{ id: 'pro-integration-tests.yml', name: 'Pro Integration Tests' },
100-
{ id: 'pro-package-tests.yml', name: 'Pro Package Tests' }
101-
];
98+
const checks = await github.rest.checks.listForRef({
99+
owner: context.repo.owner,
100+
repo: context.repo.repo,
101+
ref: pr.head.sha,
102+
per_page: 100
103+
});
104+
105+
// Find all skipped checks
106+
const skippedChecks = checks.data.check_runs.filter(check =>
107+
check.conclusion === 'SKIPPED' && check.status === 'COMPLETED'
108+
);
109+
110+
console.log(`Found ${skippedChecks.length} skipped checks:`);
111+
skippedChecks.forEach(check => {
112+
console.log(` - ${check.name} (${check.workflow_name})`);
113+
});
114+
115+
// Map workflow names to workflow files
116+
const workflowMap = {
117+
'Main test': 'main.yml',
118+
'Generator tests': 'examples.yml',
119+
'React on Rails Pro - Integration Tests': 'pro-integration-tests.yml',
120+
'React on Rails Pro - Package Tests': 'pro-package-tests.yml',
121+
'React on Rails Pro - Lint': 'pro-lint.yml'
122+
};
123+
124+
// Get unique workflows that have skipped checks
125+
const uniqueWorkflows = new Set();
126+
skippedChecks.forEach(check => {
127+
if (workflowMap[check.workflow_name]) {
128+
uniqueWorkflows.add(check.workflow_name);
129+
}
130+
});
102131
103132
const succeeded = [];
104133
const failed = [];
105-
const skipped = [];
134+
const notApplicable = [];
106135
107-
// Trigger workflows with minimum dependency testing
108-
for (const workflow of workflowsWithMinimum) {
136+
// Trigger each workflow that has skipped checks
137+
for (const workflowName of uniqueWorkflows) {
138+
const workflowFile = workflowMap[workflowName];
109139
try {
110140
await github.rest.actions.createWorkflowDispatch({
111141
owner: context.repo.owner,
112142
repo: context.repo.repo,
113-
workflow_id: workflow.id,
143+
workflow_id: workflowFile,
114144
ref: prData.ref,
115145
inputs: {
116-
run_minimum_tests: 'true'
146+
force_run: 'true'
117147
}
118148
});
119-
console.log(`✅ Triggered ${workflow.id} with run_minimum_tests=true`);
120-
succeeded.push(workflow);
149+
console.log(`✅ Triggered ${workflowFile} (${workflowName})`);
150+
succeeded.push({ id: workflowFile, name: workflowName });
121151
} catch (error) {
122-
console.error(`❌ Failed to trigger ${workflow.id}:`, error.message);
123-
failed.push({ workflow: workflow.name, error: error.message });
152+
console.error(`❌ Failed to trigger ${workflowFile}:`, error.message);
153+
failed.push({ workflow: workflowName, error: error.message });
124154
}
125155
}
126156
127-
// Skip Pro workflows (they don't have minimum matrix, always run on PRs if needed)
128-
for (const workflow of proWorkflows) {
129-
console.log(`⏭️ Skipping ${workflow.id} (no minimum dependency matrix)`);
130-
skipped.push(workflow);
157+
// Note workflows with no skipped checks
158+
if (uniqueWorkflows.size === 0) {
159+
console.log('ℹ️ No skipped checks found - all tests already running on this PR');
160+
notApplicable.push('No skipped checks to run');
131161
}
132162
133163
// Wait a bit for workflows to queue
@@ -164,33 +194,39 @@ jobs:
164194
}
165195
166196
// Build the comment body based on actual results
167-
let status = '✅ **Successfully triggered skipped CI tests**';
168-
if (failed.length > 0 && notFound.length > 0) {
197+
let status;
198+
if (notApplicable.length > 0) {
199+
status = '✅ **All checks are already running - nothing to do!**';
200+
} else if (failed.length > 0 && notFound.length > 0) {
169201
status = '❌ **Failed to trigger or verify workflows**';
170202
} else if (failed.length > 0) {
171203
status = '⚠️ **Some workflows failed to trigger**';
172204
} else if (notFound.length > 0) {
173205
status = '⚠️ **Workflows triggered but not yet verified**';
206+
} else {
207+
status = '✅ **Successfully triggered skipped CI checks**';
174208
}
175209
176-
const verifiedList = verified.length > 0 ? verified.map(w => `- ✅ ${w.name}`).join('\n') : '';
210+
// List the skipped checks we found
211+
const skippedChecksList = skippedChecks.length > 0
212+
? `\n**Skipped checks detected:**\n${skippedChecks.map(c => `- ${c.name} (${c.workflow_name})`).join('\n')}`
213+
: '';
214+
215+
const verifiedList = verified.length > 0 ? `\n**Triggered workflows:**\n${verified.map(w => `- ✅ ${w.name}`).join('\n')}` : '';
177216
const notFoundList = notFound.length > 0 ? `\n\n**Triggered but not yet queued (may still start):**\n${notFound.map(w => `- ⏳ ${w.name}`).join('\n')}` : '';
178217
const failedList = failed.length > 0 ? `\n\n**Failed to trigger:**\n${failed.map(f => `- ❌ ${f.workflow}: ${f.error}`).join('\n')}` : '';
179-
const skippedList = skipped.length > 0 ? `\n\n**Skipped (already run on PRs):**\n${skipped.map(w => `- ⏭️ ${w.name}`).join('\n')}` : '';
180218
181-
const body = `🚀 **Skipped CI Tests Triggered**
219+
const body = `🚀 **Skipped CI Checks - Trigger Results**
182220
183221
${status}
222+
${skippedChecksList}
223+
${verifiedList}${notFoundList}${failedList}
184224
185-
${verifiedList ? `**Running minimum dependency tests:**\n${verifiedList}` : ''}${notFoundList}${failedList}${skippedList}
186-
187-
${verified.length > 0 ? `\n**What's running:**
188-
- ✅ Minimum dependency versions (Ruby 3.2, Node 20)
189-
- ✅ Generator tests with minimum dependencies
225+
${verified.length > 0 ? `\n**Note:** These workflows will run with \`force_run: true\` to bypass detect-changes logic that caused them to skip.
190226
191-
**Note:** Pro package tests and latest dependency tests are skipped because they already run on all PRs.
227+
View progress in the [Actions tab](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions).` : ''}
192228
193-
View progress in the [Actions tab](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions).` : ''}`;
229+
${notApplicable.length > 0 ? `\nAll CI checks are already running on this PR. Use this command when you see skipped checks that you want to run.` : ''}`;
194230
195231
// Post the comment
196232
await github.rest.issues.createComment({

0 commit comments

Comments
 (0)