Skip to content

Commit 6fc849c

Browse files
justin808claude
andcommitted
Make /run-skipped-ci persistent using full-ci label
Changes: - Add full-ci label when /run-skipped-ci is triggered - Create /stop-run-skipped-ci command to remove the label - Update all workflows to check for full-ci label in addition to force_run input - Label persists across commits, ensuring full CI runs until explicitly stopped This fixes the issue where /run-skipped-ci would start tests but they'd stop when committing. Now the label keeps full CI enabled across all future commits until /stop-run-skipped-ci is run. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 5d938af commit 6fc849c

File tree

7 files changed

+249
-24
lines changed

7 files changed

+249
-24
lines changed

.github/workflows/examples.yml

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,37 @@ jobs:
2929
run_ruby_tests: ${{ steps.detect.outputs.run_ruby_tests }}
3030
run_dummy_tests: ${{ steps.detect.outputs.run_dummy_tests }}
3131
run_generators: ${{ steps.detect.outputs.run_generators }}
32+
has_full_ci_label: ${{ steps.check-label.outputs.has_label }}
3233
steps:
3334
- uses: actions/checkout@v4
3435
with:
3536
# Fetch enough history for change detection (50 commits is usually sufficient for PRs)
3637
fetch-depth: 50
3738
persist-credentials: false
39+
- name: Check for full-ci label
40+
id: check-label
41+
uses: actions/github-script@v7
42+
with:
43+
script: |
44+
// Only check labels on pull requests
45+
if (!context.payload.pull_request) {
46+
return false;
47+
}
48+
49+
const { data: labels } = await github.rest.issues.listLabelsOnIssue({
50+
owner: context.repo.owner,
51+
repo: context.repo.repo,
52+
issue_number: context.payload.pull_request.number
53+
});
54+
55+
const hasLabel = labels.some(label => label.name === 'full-ci');
56+
console.log(`full-ci label present: ${hasLabel}`);
57+
return hasLabel;
3858
- name: Detect relevant changes
3959
id: detect
4060
run: |
41-
# If force_run is true, run everything
42-
if [ "${{ inputs.force_run }}" = "true" ]; then
61+
# If force_run is true OR full-ci label is present, run everything
62+
if [ "${{ inputs.force_run }}" = "true" ] || [ "${{ steps.check-label.outputs.result }}" = "true" ]; then
4363
echo "run_lint=true" >> "$GITHUB_OUTPUT"
4464
echo "run_js_tests=true" >> "$GITHUB_OUTPUT"
4565
echo "run_ruby_tests=true" >> "$GITHUB_OUTPUT"
@@ -69,9 +89,9 @@ jobs:
6989
- ruby-version: '3.2'
7090
dependency-level: 'minimum'
7191
exclude:
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' || '' }}
92+
# Skip minimum dependency matrix on regular PRs (run only on master/workflow_dispatch/force_run/full-ci label)
93+
- ruby-version: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && needs.detect-changes.outputs.has_full_ci_label != 'true' && '3.2' || '' }}
94+
dependency-level: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && needs.detect-changes.outputs.has_full_ci_label != 'true' && 'minimum' || '' }}
7595
env:
7696
SKIP_YARN_COREPACK_CHECK: 0
7797
BUNDLE_FROZEN: ${{ matrix.dependency-level == 'minimum' && 'false' || 'true' }}

.github/workflows/main.yml

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,37 @@ jobs:
2929
run_ruby_tests: ${{ steps.detect.outputs.run_ruby_tests }}
3030
run_dummy_tests: ${{ steps.detect.outputs.run_dummy_tests }}
3131
run_generators: ${{ steps.detect.outputs.run_generators }}
32+
has_full_ci_label: ${{ steps.check-label.outputs.has_label }}
3233
steps:
3334
- uses: actions/checkout@v4
3435
with:
3536
# Fetch enough history for change detection (50 commits is usually sufficient for PRs)
3637
fetch-depth: 50
3738
persist-credentials: false
39+
- name: Check for full-ci label
40+
id: check-label
41+
uses: actions/github-script@v7
42+
with:
43+
script: |
44+
// Only check labels on pull requests
45+
if (!context.payload.pull_request) {
46+
return false;
47+
}
48+
49+
const { data: labels } = await github.rest.issues.listLabelsOnIssue({
50+
owner: context.repo.owner,
51+
repo: context.repo.repo,
52+
issue_number: context.payload.pull_request.number
53+
});
54+
55+
const hasLabel = labels.some(label => label.name === 'full-ci');
56+
console.log(`full-ci label present: ${hasLabel}`);
57+
return hasLabel;
3858
- name: Detect relevant changes
3959
id: detect
4060
run: |
41-
# If force_run is true, run everything
42-
if [ "${{ inputs.force_run }}" = "true" ]; then
61+
# If force_run is true OR full-ci label is present, run everything
62+
if [ "${{ inputs.force_run }}" = "true" ] || [ "${{ steps.check-label.outputs.result }}" = "true" ]; then
4363
echo "run_lint=true" >> "$GITHUB_OUTPUT"
4464
echo "run_js_tests=true" >> "$GITHUB_OUTPUT"
4565
echo "run_ruby_tests=true" >> "$GITHUB_OUTPUT"
@@ -70,10 +90,10 @@ jobs:
7090
node-version: '20'
7191
dependency-level: 'minimum'
7292
exclude:
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' || '' }}
93+
# Skip minimum dependency matrix on regular PRs (run only on master/workflow_dispatch/force_run/full-ci label)
94+
- ruby-version: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && needs.detect-changes.outputs.has_full_ci_label != 'true' && '3.2' || '' }}
95+
node-version: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && needs.detect-changes.outputs.has_full_ci_label != 'true' && '20' || '' }}
96+
dependency-level: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && needs.detect-changes.outputs.has_full_ci_label != 'true' && 'minimum' || '' }}
7797
runs-on: ubuntu-22.04
7898
steps:
7999
- uses: actions/checkout@v4
@@ -160,10 +180,10 @@ jobs:
160180
node-version: '20'
161181
dependency-level: 'minimum'
162182
exclude:
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' || '' }}
183+
# Skip minimum dependency matrix on regular PRs (run only on master/workflow_dispatch/force_run/full-ci label)
184+
- ruby-version: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && needs.detect-changes.outputs.has_full_ci_label != 'true' && '3.2' || '' }}
185+
node-version: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && needs.detect-changes.outputs.has_full_ci_label != 'true' && '20' || '' }}
186+
dependency-level: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && needs.detect-changes.outputs.has_full_ci_label != 'true' && 'minimum' || '' }}
167187
runs-on: ubuntu-22.04
168188
steps:
169189
- uses: actions/checkout@v4

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,37 @@ jobs:
2424
docs_only: ${{ steps.detect.outputs.docs_only }}
2525
run_pro_lint: ${{ steps.detect.outputs.run_pro_lint }}
2626
run_pro_tests: ${{ steps.detect.outputs.run_pro_tests }}
27+
has_full_ci_label: ${{ steps.check-label.outputs.has_label }}
2728
steps:
2829
- uses: actions/checkout@v4
2930
with:
3031
fetch-depth: 0
3132
persist-credentials: false
33+
- name: Check for full-ci label
34+
id: check-label
35+
uses: actions/github-script@v7
36+
with:
37+
script: |
38+
// Only check labels on pull requests
39+
if (!context.payload.pull_request) {
40+
return false;
41+
}
42+
43+
const { data: labels } = await github.rest.issues.listLabelsOnIssue({
44+
owner: context.repo.owner,
45+
repo: context.repo.repo,
46+
issue_number: context.payload.pull_request.number
47+
});
48+
49+
const hasLabel = labels.some(label => label.name === 'full-ci');
50+
console.log(`full-ci label present: ${hasLabel}`);
51+
return hasLabel;
3252
- name: Detect relevant changes
3353
id: detect
3454
working-directory: .
3555
run: |
36-
# If force_run is true, run everything
37-
if [ "${{ inputs.force_run }}" = "true" ]; then
56+
# If force_run is true OR full-ci label is present, run everything
57+
if [ "${{ inputs.force_run }}" = "true" ] || [ "${{ steps.check-label.outputs.result }}" = "true" ]; then
3858
echo "run_pro_lint=true" >> "$GITHUB_OUTPUT"
3959
echo "run_pro_tests=true" >> "$GITHUB_OUTPUT"
4060
echo "docs_only=false" >> "$GITHUB_OUTPUT"

.github/workflows/pro-lint.yml

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,37 @@ jobs:
2424
docs_only: ${{ steps.detect.outputs.docs_only }}
2525
run_pro_lint: ${{ steps.detect.outputs.run_pro_lint }}
2626
run_pro_tests: ${{ steps.detect.outputs.run_pro_tests }}
27+
has_full_ci_label: ${{ steps.check-label.outputs.has_label }}
2728
steps:
2829
- uses: actions/checkout@v4
2930
with:
3031
fetch-depth: 0
3132
persist-credentials: false
33+
- name: Check for full-ci label
34+
id: check-label
35+
uses: actions/github-script@v7
36+
with:
37+
script: |
38+
// Only check labels on pull requests
39+
if (!context.payload.pull_request) {
40+
return false;
41+
}
42+
43+
const { data: labels } = await github.rest.issues.listLabelsOnIssue({
44+
owner: context.repo.owner,
45+
repo: context.repo.repo,
46+
issue_number: context.payload.pull_request.number
47+
});
48+
49+
const hasLabel = labels.some(label => label.name === 'full-ci');
50+
console.log(`full-ci label present: ${hasLabel}`);
51+
return hasLabel;
3252
- name: Detect relevant changes
3353
id: detect
3454
working-directory: .
3555
run: |
36-
# If force_run is true, run everything
37-
if [ "${{ inputs.force_run }}" = "true" ]; then
56+
# If force_run is true OR full-ci label is present, run everything
57+
if [ "${{ inputs.force_run }}" = "true" ] || [ "${{ steps.check-label.outputs.result }}" = "true" ]; then
3858
echo "run_pro_lint=true" >> "$GITHUB_OUTPUT"
3959
echo "run_pro_tests=true" >> "$GITHUB_OUTPUT"
4060
echo "docs_only=false" >> "$GITHUB_OUTPUT"

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,37 @@ jobs:
2424
docs_only: ${{ steps.detect.outputs.docs_only }}
2525
run_pro_lint: ${{ steps.detect.outputs.run_pro_lint }}
2626
run_pro_tests: ${{ steps.detect.outputs.run_pro_tests }}
27+
has_full_ci_label: ${{ steps.check-label.outputs.has_label }}
2728
steps:
2829
- uses: actions/checkout@v4
2930
with:
3031
fetch-depth: 0
3132
persist-credentials: false
33+
- name: Check for full-ci label
34+
id: check-label
35+
uses: actions/github-script@v7
36+
with:
37+
script: |
38+
// Only check labels on pull requests
39+
if (!context.payload.pull_request) {
40+
return false;
41+
}
42+
43+
const { data: labels } = await github.rest.issues.listLabelsOnIssue({
44+
owner: context.repo.owner,
45+
repo: context.repo.repo,
46+
issue_number: context.payload.pull_request.number
47+
});
48+
49+
const hasLabel = labels.some(label => label.name === 'full-ci');
50+
console.log(`full-ci label present: ${hasLabel}`);
51+
return hasLabel;
3252
- name: Detect relevant changes
3353
id: detect
3454
working-directory: .
3555
run: |
36-
# If force_run is true, run everything
37-
if [ "${{ inputs.force_run }}" = "true" ]; then
56+
# If force_run is true OR full-ci label is present, run everything
57+
if [ "${{ inputs.force_run }}" = "true" ] || [ "${{ steps.check-label.outputs.result }}" = "true" ]; then
3858
echo "run_pro_lint=true" >> "$GITHUB_OUTPUT"
3959
echo "run_pro_tests=true" >> "$GITHUB_OUTPUT"
4060
echo "docs_only=false" >> "$GITHUB_OUTPUT"

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

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,18 @@ jobs:
8181
sha: pr.data.head.sha
8282
};
8383
84+
- name: Add full-ci label
85+
uses: actions/github-script@v7
86+
with:
87+
script: |
88+
await github.rest.issues.addLabels({
89+
owner: context.repo.owner,
90+
repo: context.repo.repo,
91+
issue_number: context.issue.number,
92+
labels: ['full-ci']
93+
});
94+
console.log('✅ Added full-ci label to PR');
95+
8496
- name: Get skipped checks and trigger workflows
8597
id: trigger_workflows
8698
uses: actions/github-script@v7
@@ -216,17 +228,19 @@ jobs:
216228
const notFoundList = notFound.length > 0 ? `\n\n**Triggered but not yet queued (may still start):**\n${notFound.map(w => `- ⏳ ${w.name}`).join('\n')}` : '';
217229
const failedList = failed.length > 0 ? `\n\n**Failed to trigger:**\n${failed.map(f => `- ❌ ${f.workflow}: ${f.error}`).join('\n')}` : '';
218230
219-
const body = `🚀 **Skipped CI Checks - Trigger Results**
231+
const body = `🚀 **Full CI Mode Enabled**
220232
221233
${status}
222234
${skippedChecksList}
223235
${verifiedList}${notFoundList}${failedList}
224236
225-
${verified.length > 0 ? `\n**Note:** These workflows will run with \`force_run: true\` to bypass detect-changes logic that caused them to skip.
237+
${verified.length > 0 ? `\n**Note:** Added the \`full-ci\` label to this PR. All future commits will run the full CI suite (including minimum dependency tests) until the label is removed.
238+
239+
To disable full CI mode, use the \`/stop-run-skipped-ci\` command.
226240
227241
View progress in the [Actions tab](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions).` : ''}
228242
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.` : ''}`;
243+
${notApplicable.length > 0 ? `\nAll CI checks are already running on this PR. The \`full-ci\` label has been added - future commits will run the full CI suite.` : ''}`;
230244
231245
// Post the comment
232246
await github.rest.issues.createComment({
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
name: Stop Full CI Suite
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
7+
jobs:
8+
stop-full-ci:
9+
# Only run on PR comments that match the command
10+
if: |
11+
github.event.issue.pull_request &&
12+
(
13+
startsWith(github.event.comment.body, '/stop-run-skipped-ci') ||
14+
contains(github.event.comment.body, '\n/stop-run-skipped-ci')
15+
)
16+
runs-on: ubuntu-22.04
17+
permissions:
18+
contents: read
19+
pull-requests: write
20+
issues: write
21+
steps:
22+
- name: Check if user has write access
23+
id: check_access
24+
uses: actions/github-script@v7
25+
with:
26+
script: |
27+
try {
28+
const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({
29+
owner: context.repo.owner,
30+
repo: context.repo.repo,
31+
username: context.actor
32+
});
33+
34+
const hasAccess = ['admin', 'write'].includes(permission.permission);
35+
console.log(`User ${context.actor} has permission: ${permission.permission}`);
36+
37+
if (!hasAccess) {
38+
await github.rest.issues.createComment({
39+
owner: context.repo.owner,
40+
repo: context.repo.repo,
41+
issue_number: context.issue.number,
42+
body: `@${context.actor} Sorry, only repository collaborators with write access can stop full CI runs. 🔒`
43+
});
44+
}
45+
46+
return hasAccess;
47+
} catch (error) {
48+
console.error('Error checking permissions:', error);
49+
return false;
50+
}
51+
52+
- name: Exit if no access
53+
if: steps.check_access.outputs.result == 'false'
54+
run: |
55+
echo "User does not have permission to stop full CI"
56+
exit 1
57+
58+
- name: Add reaction to comment
59+
uses: peter-evans/create-or-update-comment@v4
60+
with:
61+
comment-id: ${{ github.event.comment.id }}
62+
reactions: 'eyes'
63+
64+
- name: Remove full-ci label
65+
uses: actions/github-script@v7
66+
with:
67+
script: |
68+
try {
69+
await github.rest.issues.removeLabel({
70+
owner: context.repo.owner,
71+
repo: context.repo.repo,
72+
issue_number: context.issue.number,
73+
name: 'full-ci'
74+
});
75+
console.log('✅ Removed full-ci label from PR');
76+
77+
// Post success comment
78+
await github.rest.issues.createComment({
79+
owner: context.repo.owner,
80+
repo: context.repo.repo,
81+
issue_number: context.issue.number,
82+
body: `✅ **Full CI Mode Disabled**
83+
84+
The \`full-ci\` label has been removed. Future commits will use the standard CI suite (skipping tests for unchanged code).
85+
86+
To re-enable full CI mode, use the \`/run-skipped-ci\` command.`
87+
});
88+
} catch (error) {
89+
if (error.status === 404) {
90+
console.log('ℹ️ Label not found - already removed or never added');
91+
await github.rest.issues.createComment({
92+
owner: context.repo.owner,
93+
repo: context.repo.repo,
94+
issue_number: context.issue.number,
95+
body: `ℹ️ **Full CI Mode Already Disabled**
96+
97+
The \`full-ci\` label is not present on this PR. CI is already running in standard mode.`
98+
});
99+
} else {
100+
console.error('❌ Failed to remove label:', error);
101+
await github.rest.issues.createComment({
102+
owner: context.repo.owner,
103+
repo: context.repo.repo,
104+
issue_number: context.issue.number,
105+
body: `❌ **Error Removing Label**
106+
107+
Failed to remove the \`full-ci\` label: ${error.message}`
108+
});
109+
throw error;
110+
}
111+
}

0 commit comments

Comments
 (0)