From 6fc849c6d93a556b06ed457aa6acad4a225b9b6e Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 12 Nov 2025 15:13:09 -1000 Subject: [PATCH 1/5] Make /run-skipped-ci persistent using full-ci label MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .github/workflows/examples.yml | 30 +++++- .github/workflows/main.yml | 40 +++++-- .github/workflows/pro-integration-tests.yml | 24 ++++- .github/workflows/pro-lint.yml | 24 ++++- .github/workflows/pro-package-tests.yml | 24 ++++- .github/workflows/run-skipped-ci.yml | 20 +++- .github/workflows/stop-run-skipped-ci.yml | 111 ++++++++++++++++++++ 7 files changed, 249 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/stop-run-skipped-ci.yml diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 455d4cdbb3..94b7c1b88c 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -29,17 +29,37 @@ jobs: run_ruby_tests: ${{ steps.detect.outputs.run_ruby_tests }} run_dummy_tests: ${{ steps.detect.outputs.run_dummy_tests }} run_generators: ${{ steps.detect.outputs.run_generators }} + has_full_ci_label: ${{ steps.check-label.outputs.has_label }} steps: - uses: actions/checkout@v4 with: # Fetch enough history for change detection (50 commits is usually sufficient for PRs) fetch-depth: 50 persist-credentials: false + - name: Check for full-ci label + id: check-label + uses: actions/github-script@v7 + with: + script: | + // Only check labels on pull requests + if (!context.payload.pull_request) { + return false; + } + + const { data: labels } = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number + }); + + const hasLabel = labels.some(label => label.name === 'full-ci'); + console.log(`full-ci label present: ${hasLabel}`); + return hasLabel; - name: Detect relevant changes id: detect run: | - # If force_run is true, run everything - if [ "${{ inputs.force_run }}" = "true" ]; then + # If force_run is true OR full-ci label is present, run everything + if [ "${{ inputs.force_run }}" = "true" ] || [ "${{ steps.check-label.outputs.result }}" = "true" ]; then echo "run_lint=true" >> "$GITHUB_OUTPUT" echo "run_js_tests=true" >> "$GITHUB_OUTPUT" echo "run_ruby_tests=true" >> "$GITHUB_OUTPUT" @@ -69,9 +89,9 @@ jobs: - ruby-version: '3.2' dependency-level: 'minimum' exclude: - # Skip minimum dependency matrix on regular PRs (run only on master/workflow_dispatch/force_run) - - ruby-version: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && '3.2' || '' }} - dependency-level: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && 'minimum' || '' }} + # Skip minimum dependency matrix on regular PRs (run only on master/workflow_dispatch/force_run/full-ci label) + - 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' || '' }} + 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' || '' }} env: SKIP_YARN_COREPACK_CHECK: 0 BUNDLE_FROZEN: ${{ matrix.dependency-level == 'minimum' && 'false' || 'true' }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0b02d517ba..c77f79947c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,17 +29,37 @@ jobs: run_ruby_tests: ${{ steps.detect.outputs.run_ruby_tests }} run_dummy_tests: ${{ steps.detect.outputs.run_dummy_tests }} run_generators: ${{ steps.detect.outputs.run_generators }} + has_full_ci_label: ${{ steps.check-label.outputs.has_label }} steps: - uses: actions/checkout@v4 with: # Fetch enough history for change detection (50 commits is usually sufficient for PRs) fetch-depth: 50 persist-credentials: false + - name: Check for full-ci label + id: check-label + uses: actions/github-script@v7 + with: + script: | + // Only check labels on pull requests + if (!context.payload.pull_request) { + return false; + } + + const { data: labels } = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number + }); + + const hasLabel = labels.some(label => label.name === 'full-ci'); + console.log(`full-ci label present: ${hasLabel}`); + return hasLabel; - name: Detect relevant changes id: detect run: | - # If force_run is true, run everything - if [ "${{ inputs.force_run }}" = "true" ]; then + # If force_run is true OR full-ci label is present, run everything + if [ "${{ inputs.force_run }}" = "true" ] || [ "${{ steps.check-label.outputs.result }}" = "true" ]; then echo "run_lint=true" >> "$GITHUB_OUTPUT" echo "run_js_tests=true" >> "$GITHUB_OUTPUT" echo "run_ruby_tests=true" >> "$GITHUB_OUTPUT" @@ -70,10 +90,10 @@ jobs: node-version: '20' dependency-level: 'minimum' exclude: - # Skip minimum dependency matrix on regular PRs (run only on master/workflow_dispatch/force_run) - - ruby-version: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && '3.2' || '' }} - node-version: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && '20' || '' }} - dependency-level: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && 'minimum' || '' }} + # Skip minimum dependency matrix on regular PRs (run only on master/workflow_dispatch/force_run/full-ci label) + - 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' || '' }} + 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' || '' }} + 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' || '' }} runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 @@ -160,10 +180,10 @@ jobs: node-version: '20' dependency-level: 'minimum' exclude: - # Skip minimum dependency matrix on regular PRs (run only on master/workflow_dispatch/force_run) - - ruby-version: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && '3.2' || '' }} - node-version: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && '20' || '' }} - dependency-level: ${{ github.event_name == 'pull_request' && github.ref != 'refs/heads/master' && inputs.force_run != true && 'minimum' || '' }} + # Skip minimum dependency matrix on regular PRs (run only on master/workflow_dispatch/force_run/full-ci label) + - 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' || '' }} + 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' || '' }} + 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' || '' }} runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/pro-integration-tests.yml b/.github/workflows/pro-integration-tests.yml index a8c0a149db..35ed57640c 100644 --- a/.github/workflows/pro-integration-tests.yml +++ b/.github/workflows/pro-integration-tests.yml @@ -24,17 +24,37 @@ jobs: docs_only: ${{ steps.detect.outputs.docs_only }} run_pro_lint: ${{ steps.detect.outputs.run_pro_lint }} run_pro_tests: ${{ steps.detect.outputs.run_pro_tests }} + has_full_ci_label: ${{ steps.check-label.outputs.has_label }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 persist-credentials: false + - name: Check for full-ci label + id: check-label + uses: actions/github-script@v7 + with: + script: | + // Only check labels on pull requests + if (!context.payload.pull_request) { + return false; + } + + const { data: labels } = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number + }); + + const hasLabel = labels.some(label => label.name === 'full-ci'); + console.log(`full-ci label present: ${hasLabel}`); + return hasLabel; - name: Detect relevant changes id: detect working-directory: . run: | - # If force_run is true, run everything - if [ "${{ inputs.force_run }}" = "true" ]; then + # If force_run is true OR full-ci label is present, run everything + if [ "${{ inputs.force_run }}" = "true" ] || [ "${{ steps.check-label.outputs.result }}" = "true" ]; then echo "run_pro_lint=true" >> "$GITHUB_OUTPUT" echo "run_pro_tests=true" >> "$GITHUB_OUTPUT" echo "docs_only=false" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/pro-lint.yml b/.github/workflows/pro-lint.yml index 92be479934..c5c49faf1c 100644 --- a/.github/workflows/pro-lint.yml +++ b/.github/workflows/pro-lint.yml @@ -24,17 +24,37 @@ jobs: docs_only: ${{ steps.detect.outputs.docs_only }} run_pro_lint: ${{ steps.detect.outputs.run_pro_lint }} run_pro_tests: ${{ steps.detect.outputs.run_pro_tests }} + has_full_ci_label: ${{ steps.check-label.outputs.has_label }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 persist-credentials: false + - name: Check for full-ci label + id: check-label + uses: actions/github-script@v7 + with: + script: | + // Only check labels on pull requests + if (!context.payload.pull_request) { + return false; + } + + const { data: labels } = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number + }); + + const hasLabel = labels.some(label => label.name === 'full-ci'); + console.log(`full-ci label present: ${hasLabel}`); + return hasLabel; - name: Detect relevant changes id: detect working-directory: . run: | - # If force_run is true, run everything - if [ "${{ inputs.force_run }}" = "true" ]; then + # If force_run is true OR full-ci label is present, run everything + if [ "${{ inputs.force_run }}" = "true" ] || [ "${{ steps.check-label.outputs.result }}" = "true" ]; then echo "run_pro_lint=true" >> "$GITHUB_OUTPUT" echo "run_pro_tests=true" >> "$GITHUB_OUTPUT" echo "docs_only=false" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/pro-package-tests.yml b/.github/workflows/pro-package-tests.yml index 13a3dfe5f4..fcdb920b3d 100644 --- a/.github/workflows/pro-package-tests.yml +++ b/.github/workflows/pro-package-tests.yml @@ -24,17 +24,37 @@ jobs: docs_only: ${{ steps.detect.outputs.docs_only }} run_pro_lint: ${{ steps.detect.outputs.run_pro_lint }} run_pro_tests: ${{ steps.detect.outputs.run_pro_tests }} + has_full_ci_label: ${{ steps.check-label.outputs.has_label }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 persist-credentials: false + - name: Check for full-ci label + id: check-label + uses: actions/github-script@v7 + with: + script: | + // Only check labels on pull requests + if (!context.payload.pull_request) { + return false; + } + + const { data: labels } = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number + }); + + const hasLabel = labels.some(label => label.name === 'full-ci'); + console.log(`full-ci label present: ${hasLabel}`); + return hasLabel; - name: Detect relevant changes id: detect working-directory: . run: | - # If force_run is true, run everything - if [ "${{ inputs.force_run }}" = "true" ]; then + # If force_run is true OR full-ci label is present, run everything + if [ "${{ inputs.force_run }}" = "true" ] || [ "${{ steps.check-label.outputs.result }}" = "true" ]; then echo "run_pro_lint=true" >> "$GITHUB_OUTPUT" echo "run_pro_tests=true" >> "$GITHUB_OUTPUT" echo "docs_only=false" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/run-skipped-ci.yml b/.github/workflows/run-skipped-ci.yml index e589cf9a43..2348e6e2c7 100644 --- a/.github/workflows/run-skipped-ci.yml +++ b/.github/workflows/run-skipped-ci.yml @@ -81,6 +81,18 @@ jobs: sha: pr.data.head.sha }; + - name: Add full-ci label + uses: actions/github-script@v7 + with: + script: | + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ['full-ci'] + }); + console.log('✅ Added full-ci label to PR'); + - name: Get skipped checks and trigger workflows id: trigger_workflows uses: actions/github-script@v7 @@ -216,17 +228,19 @@ jobs: const notFoundList = notFound.length > 0 ? `\n\n**Triggered but not yet queued (may still start):**\n${notFound.map(w => `- âŗ ${w.name}`).join('\n')}` : ''; const failedList = failed.length > 0 ? `\n\n**Failed to trigger:**\n${failed.map(f => `- ❌ ${f.workflow}: ${f.error}`).join('\n')}` : ''; - const body = `🚀 **Skipped CI Checks - Trigger Results** + const body = `🚀 **Full CI Mode Enabled** ${status} ${skippedChecksList} ${verifiedList}${notFoundList}${failedList} - ${verified.length > 0 ? `\n**Note:** These workflows will run with \`force_run: true\` to bypass detect-changes logic that caused them to skip. + ${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. + + To disable full CI mode, use the \`/stop-run-skipped-ci\` command. View progress in the [Actions tab](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions).` : ''} - ${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.` : ''}`; + ${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.` : ''}`; // Post the comment await github.rest.issues.createComment({ diff --git a/.github/workflows/stop-run-skipped-ci.yml b/.github/workflows/stop-run-skipped-ci.yml new file mode 100644 index 0000000000..5ff5b8f8e8 --- /dev/null +++ b/.github/workflows/stop-run-skipped-ci.yml @@ -0,0 +1,111 @@ +name: Stop Full CI Suite + +on: + issue_comment: + types: [created] + +jobs: + stop-full-ci: + # Only run on PR comments that match the command + if: | + github.event.issue.pull_request && + ( + startsWith(github.event.comment.body, '/stop-run-skipped-ci') || + contains(github.event.comment.body, '\n/stop-run-skipped-ci') + ) + runs-on: ubuntu-22.04 + permissions: + contents: read + pull-requests: write + issues: write + steps: + - name: Check if user has write access + id: check_access + uses: actions/github-script@v7 + with: + script: | + try { + const { data: permission } = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: context.repo.owner, + repo: context.repo.repo, + username: context.actor + }); + + const hasAccess = ['admin', 'write'].includes(permission.permission); + console.log(`User ${context.actor} has permission: ${permission.permission}`); + + if (!hasAccess) { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: `@${context.actor} Sorry, only repository collaborators with write access can stop full CI runs. 🔒` + }); + } + + return hasAccess; + } catch (error) { + console.error('Error checking permissions:', error); + return false; + } + + - name: Exit if no access + if: steps.check_access.outputs.result == 'false' + run: | + echo "User does not have permission to stop full CI" + exit 1 + + - name: Add reaction to comment + uses: peter-evans/create-or-update-comment@v4 + with: + comment-id: ${{ github.event.comment.id }} + reactions: 'eyes' + + - name: Remove full-ci label + uses: actions/github-script@v7 + with: + script: | + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + name: 'full-ci' + }); + console.log('✅ Removed full-ci label from PR'); + + // Post success comment + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: `✅ **Full CI Mode Disabled** + +The \`full-ci\` label has been removed. Future commits will use the standard CI suite (skipping tests for unchanged code). + +To re-enable full CI mode, use the \`/run-skipped-ci\` command.` + }); + } catch (error) { + if (error.status === 404) { + console.log('â„šī¸ Label not found - already removed or never added'); + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: `â„šī¸ **Full CI Mode Already Disabled** + +The \`full-ci\` label is not present on this PR. CI is already running in standard mode.` + }); + } else { + console.error('❌ Failed to remove label:', error); + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: `❌ **Error Removing Label** + +Failed to remove the \`full-ci\` label: ${error.message}` + }); + throw error; + } + } From 400bb8026a5ca47aa8bf8ce2e740c1647f6192f6 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 12 Nov 2025 15:25:27 -1000 Subject: [PATCH 2/5] Fix YAML syntax error in stop-run-skipped-ci workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace template literals with array.join() to avoid YAML multiline key parsing issues. This fixes the knip CI failure. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/stop-run-skipped-ci.yml | 36 ++++++++++++++++------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/.github/workflows/stop-run-skipped-ci.yml b/.github/workflows/stop-run-skipped-ci.yml index 5ff5b8f8e8..80312cedf8 100644 --- a/.github/workflows/stop-run-skipped-ci.yml +++ b/.github/workflows/stop-run-skipped-ci.yml @@ -75,36 +75,50 @@ jobs: console.log('✅ Removed full-ci label from PR'); // Post success comment + const successBody = [ + '✅ **Full CI Mode Disabled**', + '', + 'The `full-ci` label has been removed. Future commits will use the standard CI suite (skipping tests for unchanged code).', + '', + 'To re-enable full CI mode, use the `/run-skipped-ci` command.' + ].join('\n'); + await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, - body: `✅ **Full CI Mode Disabled** - -The \`full-ci\` label has been removed. Future commits will use the standard CI suite (skipping tests for unchanged code). - -To re-enable full CI mode, use the \`/run-skipped-ci\` command.` + body: successBody }); } catch (error) { if (error.status === 404) { console.log('â„šī¸ Label not found - already removed or never added'); + + const notFoundBody = [ + 'â„šī¸ **Full CI Mode Already Disabled**', + '', + 'The `full-ci` label is not present on this PR. CI is already running in standard mode.' + ].join('\n'); + await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, - body: `â„šī¸ **Full CI Mode Already Disabled** - -The \`full-ci\` label is not present on this PR. CI is already running in standard mode.` + body: notFoundBody }); } else { console.error('❌ Failed to remove label:', error); + + const errorBody = [ + '❌ **Error Removing Label**', + '', + 'Failed to remove the `full-ci` label: ' + error.message + ].join('\n'); + await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, - body: `❌ **Error Removing Label** - -Failed to remove the \`full-ci\` label: ${error.message}` + body: errorBody }); throw error; } From 1015fe9aa46976e1518e3723cdb564f8da176235 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 12 Nov 2025 15:26:37 -1000 Subject: [PATCH 3/5] Fix critical bug: incorrect output reference in workflow files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The check-label step returns `result` output, but workflows were incorrectly referencing it as `has_label`, causing the full-ci label feature to be completely broken. Fixed in all 5 workflows: - .github/workflows/main.yml - .github/workflows/examples.yml - .github/workflows/pro-integration-tests.yml - .github/workflows/pro-lint.yml - .github/workflows/pro-package-tests.yml 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/examples.yml | 2 +- .github/workflows/main.yml | 2 +- .github/workflows/pro-integration-tests.yml | 2 +- .github/workflows/pro-lint.yml | 2 +- .github/workflows/pro-package-tests.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 94b7c1b88c..8239e0e8e4 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -29,7 +29,7 @@ jobs: run_ruby_tests: ${{ steps.detect.outputs.run_ruby_tests }} run_dummy_tests: ${{ steps.detect.outputs.run_dummy_tests }} run_generators: ${{ steps.detect.outputs.run_generators }} - has_full_ci_label: ${{ steps.check-label.outputs.has_label }} + has_full_ci_label: ${{ steps.check-label.outputs.result }} steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c77f79947c..37e6cd426b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -29,7 +29,7 @@ jobs: run_ruby_tests: ${{ steps.detect.outputs.run_ruby_tests }} run_dummy_tests: ${{ steps.detect.outputs.run_dummy_tests }} run_generators: ${{ steps.detect.outputs.run_generators }} - has_full_ci_label: ${{ steps.check-label.outputs.has_label }} + has_full_ci_label: ${{ steps.check-label.outputs.result }} steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/pro-integration-tests.yml b/.github/workflows/pro-integration-tests.yml index 35ed57640c..31b6af2ee3 100644 --- a/.github/workflows/pro-integration-tests.yml +++ b/.github/workflows/pro-integration-tests.yml @@ -24,7 +24,7 @@ jobs: docs_only: ${{ steps.detect.outputs.docs_only }} run_pro_lint: ${{ steps.detect.outputs.run_pro_lint }} run_pro_tests: ${{ steps.detect.outputs.run_pro_tests }} - has_full_ci_label: ${{ steps.check-label.outputs.has_label }} + has_full_ci_label: ${{ steps.check-label.outputs.result }} steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/pro-lint.yml b/.github/workflows/pro-lint.yml index c5c49faf1c..de15c4841b 100644 --- a/.github/workflows/pro-lint.yml +++ b/.github/workflows/pro-lint.yml @@ -24,7 +24,7 @@ jobs: docs_only: ${{ steps.detect.outputs.docs_only }} run_pro_lint: ${{ steps.detect.outputs.run_pro_lint }} run_pro_tests: ${{ steps.detect.outputs.run_pro_tests }} - has_full_ci_label: ${{ steps.check-label.outputs.has_label }} + has_full_ci_label: ${{ steps.check-label.outputs.result }} steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/pro-package-tests.yml b/.github/workflows/pro-package-tests.yml index fcdb920b3d..99e8fa7cba 100644 --- a/.github/workflows/pro-package-tests.yml +++ b/.github/workflows/pro-package-tests.yml @@ -24,7 +24,7 @@ jobs: docs_only: ${{ steps.detect.outputs.docs_only }} run_pro_lint: ${{ steps.detect.outputs.run_pro_lint }} run_pro_tests: ${{ steps.detect.outputs.run_pro_tests }} - has_full_ci_label: ${{ steps.check-label.outputs.has_label }} + has_full_ci_label: ${{ steps.check-label.outputs.result }} steps: - uses: actions/checkout@v4 with: From aac7121ed74a4e88abc70c02533348d4d5b6e15a Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 12 Nov 2025 15:35:24 -1000 Subject: [PATCH 4/5] Improve full-ci label implementation with better output handling and UX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit enhances the /run-skipped-ci feature based on code review feedback: **Critical Fixes:** - Fix GitHub Actions output encoding to use explicit string values - Add result-encoding: string to all label check steps - Return 'true'/'false' strings instead of booleans for consistent shell comparison - Fixes potential silent failures in label detection across 6 workflow files **New Features:** - Add automatic full-ci label cleanup when PRs are merged - Add welcome message to new PRs explaining CI control commands - Comprehensive documentation in CONTRIBUTING.md **Files Changed:** - .github/workflows/main.yml - Fixed output encoding - .github/workflows/examples.yml - Fixed output encoding - .github/workflows/pro-*.yml (3 files) - Fixed output encoding - .github/workflows/cleanup-full-ci-label.yml - New: Auto-remove label on merge - .github/workflows/pr-welcome-message.yml - New: Welcome message for PRs - CONTRIBUTING.md - Added CI Control Commands documentation The full-ci label now persists correctly across commits and provides clear user guidance through automated messages. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/cleanup-full-ci-label.yml | 35 +++++++++++++++ .github/workflows/examples.yml | 5 ++- .github/workflows/main.yml | 5 ++- .github/workflows/pr-welcome-message.yml | 45 +++++++++++++++++++ .github/workflows/pro-integration-tests.yml | 5 ++- .github/workflows/pro-lint.yml | 5 ++- .github/workflows/pro-package-tests.yml | 5 ++- CONTRIBUTING.md | 49 +++++++++++++++++++++ 8 files changed, 144 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/cleanup-full-ci-label.yml create mode 100644 .github/workflows/pr-welcome-message.yml diff --git a/.github/workflows/cleanup-full-ci-label.yml b/.github/workflows/cleanup-full-ci-label.yml new file mode 100644 index 0000000000..493b724c5a --- /dev/null +++ b/.github/workflows/cleanup-full-ci-label.yml @@ -0,0 +1,35 @@ +name: Cleanup full-ci label on PR merge + +on: + pull_request: + types: [closed] + +jobs: + remove-label: + # Only run when PR is actually merged (not just closed) + if: github.event.pull_request.merged == true + runs-on: ubuntu-22.04 + permissions: + issues: write + pull-requests: write + steps: + - name: Remove full-ci label + uses: actions/github-script@v7 + with: + script: | + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + name: 'full-ci' + }); + console.log('✅ Removed full-ci label from merged PR'); + } catch (error) { + if (error.status === 404) { + console.log('â„šī¸ Label not present - nothing to clean up'); + } else { + console.error('âš ī¸ Failed to remove label:', error.message); + // Don't fail the workflow - this is just cleanup + } + } diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 8239e0e8e4..68ef4210f4 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -40,10 +40,11 @@ jobs: id: check-label uses: actions/github-script@v7 with: + result-encoding: string script: | // Only check labels on pull requests if (!context.payload.pull_request) { - return false; + return 'false'; } const { data: labels } = await github.rest.issues.listLabelsOnIssue({ @@ -54,7 +55,7 @@ jobs: const hasLabel = labels.some(label => label.name === 'full-ci'); console.log(`full-ci label present: ${hasLabel}`); - return hasLabel; + return hasLabel ? 'true' : 'false'; - name: Detect relevant changes id: detect run: | diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 37e6cd426b..7d25700aad 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -40,10 +40,11 @@ jobs: id: check-label uses: actions/github-script@v7 with: + result-encoding: string script: | // Only check labels on pull requests if (!context.payload.pull_request) { - return false; + return 'false'; } const { data: labels } = await github.rest.issues.listLabelsOnIssue({ @@ -54,7 +55,7 @@ jobs: const hasLabel = labels.some(label => label.name === 'full-ci'); console.log(`full-ci label present: ${hasLabel}`); - return hasLabel; + return hasLabel ? 'true' : 'false'; - name: Detect relevant changes id: detect run: | diff --git a/.github/workflows/pr-welcome-message.yml b/.github/workflows/pr-welcome-message.yml new file mode 100644 index 0000000000..349153e33f --- /dev/null +++ b/.github/workflows/pr-welcome-message.yml @@ -0,0 +1,45 @@ +name: PR Welcome Message + +on: + pull_request: + types: [opened] + +jobs: + welcome: + runs-on: ubuntu-22.04 + permissions: + issues: write + pull-requests: write + steps: + - name: Post welcome message + uses: actions/github-script@v7 + with: + script: | + const welcomeMessage = [ + '👋 **Thanks for your contribution!**', + '', + 'This PR will run CI tests based on the files you changed. If some tests are skipped and you want to run the full test suite (including minimum dependency tests), you can use these commands:', + '', + '### CI Control Commands', + '', + '- **`/run-skipped-ci`** - Runs all skipped CI checks and enables full CI mode for this PR', + ' - Adds the `full-ci` label to ensure future commits also run the full test suite', + ' - Useful when you want comprehensive testing across all configurations', + '', + '- **`/stop-run-skipped-ci`** - Disables full CI mode and returns to standard CI', + ' - Removes the `full-ci` label', + ' - Future commits will only run tests for changed files', + '', + '💡 **Note:** The `full-ci` label will be automatically removed when this PR is merged.', + '', + 'View CI progress in the [Actions tab](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions).' + ].join('\n'); + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: welcomeMessage + }); + + console.log('✅ Posted welcome message to PR'); diff --git a/.github/workflows/pro-integration-tests.yml b/.github/workflows/pro-integration-tests.yml index 31b6af2ee3..bafa0472a3 100644 --- a/.github/workflows/pro-integration-tests.yml +++ b/.github/workflows/pro-integration-tests.yml @@ -34,10 +34,11 @@ jobs: id: check-label uses: actions/github-script@v7 with: + result-encoding: string script: | // Only check labels on pull requests if (!context.payload.pull_request) { - return false; + return 'false'; } const { data: labels } = await github.rest.issues.listLabelsOnIssue({ @@ -48,7 +49,7 @@ jobs: const hasLabel = labels.some(label => label.name === 'full-ci'); console.log(`full-ci label present: ${hasLabel}`); - return hasLabel; + return hasLabel ? 'true' : 'false'; - name: Detect relevant changes id: detect working-directory: . diff --git a/.github/workflows/pro-lint.yml b/.github/workflows/pro-lint.yml index de15c4841b..41fbb650b2 100644 --- a/.github/workflows/pro-lint.yml +++ b/.github/workflows/pro-lint.yml @@ -34,10 +34,11 @@ jobs: id: check-label uses: actions/github-script@v7 with: + result-encoding: string script: | // Only check labels on pull requests if (!context.payload.pull_request) { - return false; + return 'false'; } const { data: labels } = await github.rest.issues.listLabelsOnIssue({ @@ -48,7 +49,7 @@ jobs: const hasLabel = labels.some(label => label.name === 'full-ci'); console.log(`full-ci label present: ${hasLabel}`); - return hasLabel; + return hasLabel ? 'true' : 'false'; - name: Detect relevant changes id: detect working-directory: . diff --git a/.github/workflows/pro-package-tests.yml b/.github/workflows/pro-package-tests.yml index 99e8fa7cba..421894d19f 100644 --- a/.github/workflows/pro-package-tests.yml +++ b/.github/workflows/pro-package-tests.yml @@ -34,10 +34,11 @@ jobs: id: check-label uses: actions/github-script@v7 with: + result-encoding: string script: | // Only check labels on pull requests if (!context.payload.pull_request) { - return false; + return 'false'; } const { data: labels } = await github.rest.issues.listLabelsOnIssue({ @@ -48,7 +49,7 @@ jobs: const hasLabel = labels.some(label => label.name === 'full-ci'); console.log(`full-ci label present: ${hasLabel}`); - return hasLabel; + return hasLabel ? 'true' : 'false'; - name: Detect relevant changes id: detect working-directory: . diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9d7700c3ee..339ace5c75 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -421,6 +421,55 @@ The CI system intelligently skips unnecessary work: For more details, see [`docs/CI_OPTIMIZATION.md`](./docs/CI_OPTIMIZATION.md). +### CI Control Commands + +React on Rails provides PR comment commands to control CI behavior: + +#### `/run-skipped-ci` - Enable Full CI Mode + +Runs all skipped CI checks and enables full CI mode for the PR: + +``` +/run-skipped-ci +``` + +**What it does:** + +- Triggers all CI workflows that were skipped due to unchanged code +- Adds the `full-ci` label to the PR +- **Persists across future commits** - all subsequent pushes will run the full test suite +- Runs minimum dependency tests (Ruby 3.2, Node 20, Shakapacker 8.2.0, React 18) + +**When to use:** + +- You want comprehensive testing across all configurations +- Testing changes that might affect minimum supported versions +- Validating generator changes or core functionality +- Before merging PRs that touch critical paths + +#### `/stop-run-skipped-ci` - Disable Full CI Mode + +Removes the `full-ci` label and returns to standard CI behavior: + +``` +/stop-run-skipped-ci +``` + +**What it does:** + +- Removes the `full-ci` label from the PR +- Future commits will use the optimized CI suite (tests only changed code) +- Does not stop currently running workflows + +**When to use:** + +- You've validated changes with full CI and want to return to faster feedback +- Reducing CI time during rapid iteration on a PR + +#### Automatic Cleanup + +The `full-ci` label is automatically removed when a PR is merged, so you don't need to manually clean it up. + ### Install Generator In your Rails app add this gem with a path to your fork. From f9da7d36db83890d0b6ddbd5da3f2681e2e94758 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Wed, 12 Nov 2025 15:50:42 -1000 Subject: [PATCH 5/5] Refactor full-ci label implementation and fix code review issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove cleanup workflow: Preserve full-ci label on merged PRs as historical record - Reduce code duplication: Create reusable composite action for label checking - Fix label addition timing: Add label within main workflow step with better error handling - Improve UX: Add permissions note to welcome message and clarify label persistence - Better error handling: Use core.setFailed() instead of throw in stop workflow 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../actions/check-full-ci-label/action.yml | 29 +++++++++++++++ .github/workflows/cleanup-full-ci-label.yml | 35 ------------------- .github/workflows/examples.yml | 19 +--------- .github/workflows/main.yml | 19 +--------- .github/workflows/pr-welcome-message.yml | 4 ++- .github/workflows/pro-integration-tests.yml | 19 +--------- .github/workflows/pro-lint.yml | 19 +--------- .github/workflows/pro-package-tests.yml | 19 +--------- .github/workflows/run-skipped-ci.yml | 31 ++++++++-------- .github/workflows/stop-run-skipped-ci.yml | 3 +- CONTRIBUTING.md | 4 +-- 11 files changed, 57 insertions(+), 144 deletions(-) create mode 100644 .github/actions/check-full-ci-label/action.yml delete mode 100644 .github/workflows/cleanup-full-ci-label.yml diff --git a/.github/actions/check-full-ci-label/action.yml b/.github/actions/check-full-ci-label/action.yml new file mode 100644 index 0000000000..60a37e44c7 --- /dev/null +++ b/.github/actions/check-full-ci-label/action.yml @@ -0,0 +1,29 @@ +name: Check for full-ci label +description: Checks if the PR has the full-ci label to enable full CI mode +outputs: + result: + description: 'Whether the full-ci label is present (string: "true" or "false")' + value: ${{ steps.check.outputs.result }} +runs: + using: composite + steps: + - name: Check for full-ci label + id: check + uses: actions/github-script@v7 + with: + result-encoding: string + script: | + // Only check labels on pull requests + if (!context.payload.pull_request) { + return 'false'; + } + + const { data: labels } = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number + }); + + const hasLabel = labels.some(label => label.name === 'full-ci'); + console.log(`full-ci label present: ${hasLabel}`); + return hasLabel ? 'true' : 'false'; diff --git a/.github/workflows/cleanup-full-ci-label.yml b/.github/workflows/cleanup-full-ci-label.yml deleted file mode 100644 index 493b724c5a..0000000000 --- a/.github/workflows/cleanup-full-ci-label.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: Cleanup full-ci label on PR merge - -on: - pull_request: - types: [closed] - -jobs: - remove-label: - # Only run when PR is actually merged (not just closed) - if: github.event.pull_request.merged == true - runs-on: ubuntu-22.04 - permissions: - issues: write - pull-requests: write - steps: - - name: Remove full-ci label - uses: actions/github-script@v7 - with: - script: | - try { - await github.rest.issues.removeLabel({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - name: 'full-ci' - }); - console.log('✅ Removed full-ci label from merged PR'); - } catch (error) { - if (error.status === 404) { - console.log('â„šī¸ Label not present - nothing to clean up'); - } else { - console.error('âš ī¸ Failed to remove label:', error.message); - // Don't fail the workflow - this is just cleanup - } - } diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 68ef4210f4..6a639a2b6b 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -38,24 +38,7 @@ jobs: persist-credentials: false - name: Check for full-ci label id: check-label - uses: actions/github-script@v7 - with: - result-encoding: string - script: | - // Only check labels on pull requests - if (!context.payload.pull_request) { - return 'false'; - } - - const { data: labels } = await github.rest.issues.listLabelsOnIssue({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number - }); - - const hasLabel = labels.some(label => label.name === 'full-ci'); - console.log(`full-ci label present: ${hasLabel}`); - return hasLabel ? 'true' : 'false'; + uses: ./.github/actions/check-full-ci-label - name: Detect relevant changes id: detect run: | diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7d25700aad..8983bbe9fd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -38,24 +38,7 @@ jobs: persist-credentials: false - name: Check for full-ci label id: check-label - uses: actions/github-script@v7 - with: - result-encoding: string - script: | - // Only check labels on pull requests - if (!context.payload.pull_request) { - return 'false'; - } - - const { data: labels } = await github.rest.issues.listLabelsOnIssue({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number - }); - - const hasLabel = labels.some(label => label.name === 'full-ci'); - console.log(`full-ci label present: ${hasLabel}`); - return hasLabel ? 'true' : 'false'; + uses: ./.github/actions/check-full-ci-label - name: Detect relevant changes id: detect run: | diff --git a/.github/workflows/pr-welcome-message.yml b/.github/workflows/pr-welcome-message.yml index 349153e33f..4d00fca5cb 100644 --- a/.github/workflows/pr-welcome-message.yml +++ b/.github/workflows/pr-welcome-message.yml @@ -30,7 +30,9 @@ jobs: ' - Removes the `full-ci` label', ' - Future commits will only run tests for changed files', '', - '💡 **Note:** The `full-ci` label will be automatically removed when this PR is merged.', + '**Note:**', + '- These commands require write access to the repository', + '- The `full-ci` label is preserved on merged PRs as a historical record', '', 'View CI progress in the [Actions tab](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions).' ].join('\n'); diff --git a/.github/workflows/pro-integration-tests.yml b/.github/workflows/pro-integration-tests.yml index bafa0472a3..05f58fff1a 100644 --- a/.github/workflows/pro-integration-tests.yml +++ b/.github/workflows/pro-integration-tests.yml @@ -32,24 +32,7 @@ jobs: persist-credentials: false - name: Check for full-ci label id: check-label - uses: actions/github-script@v7 - with: - result-encoding: string - script: | - // Only check labels on pull requests - if (!context.payload.pull_request) { - return 'false'; - } - - const { data: labels } = await github.rest.issues.listLabelsOnIssue({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number - }); - - const hasLabel = labels.some(label => label.name === 'full-ci'); - console.log(`full-ci label present: ${hasLabel}`); - return hasLabel ? 'true' : 'false'; + uses: ./.github/actions/check-full-ci-label - name: Detect relevant changes id: detect working-directory: . diff --git a/.github/workflows/pro-lint.yml b/.github/workflows/pro-lint.yml index 41fbb650b2..41b10e2f21 100644 --- a/.github/workflows/pro-lint.yml +++ b/.github/workflows/pro-lint.yml @@ -32,24 +32,7 @@ jobs: persist-credentials: false - name: Check for full-ci label id: check-label - uses: actions/github-script@v7 - with: - result-encoding: string - script: | - // Only check labels on pull requests - if (!context.payload.pull_request) { - return 'false'; - } - - const { data: labels } = await github.rest.issues.listLabelsOnIssue({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number - }); - - const hasLabel = labels.some(label => label.name === 'full-ci'); - console.log(`full-ci label present: ${hasLabel}`); - return hasLabel ? 'true' : 'false'; + uses: ./.github/actions/check-full-ci-label - name: Detect relevant changes id: detect working-directory: . diff --git a/.github/workflows/pro-package-tests.yml b/.github/workflows/pro-package-tests.yml index 421894d19f..99afb186d3 100644 --- a/.github/workflows/pro-package-tests.yml +++ b/.github/workflows/pro-package-tests.yml @@ -32,24 +32,7 @@ jobs: persist-credentials: false - name: Check for full-ci label id: check-label - uses: actions/github-script@v7 - with: - result-encoding: string - script: | - // Only check labels on pull requests - if (!context.payload.pull_request) { - return 'false'; - } - - const { data: labels } = await github.rest.issues.listLabelsOnIssue({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number - }); - - const hasLabel = labels.some(label => label.name === 'full-ci'); - console.log(`full-ci label present: ${hasLabel}`); - return hasLabel ? 'true' : 'false'; + uses: ./.github/actions/check-full-ci-label - name: Detect relevant changes id: detect working-directory: . diff --git a/.github/workflows/run-skipped-ci.yml b/.github/workflows/run-skipped-ci.yml index 2348e6e2c7..688c62f111 100644 --- a/.github/workflows/run-skipped-ci.yml +++ b/.github/workflows/run-skipped-ci.yml @@ -81,18 +81,6 @@ jobs: sha: pr.data.head.sha }; - - name: Add full-ci label - uses: actions/github-script@v7 - with: - script: | - await github.rest.issues.addLabels({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - labels: ['full-ci'] - }); - console.log('✅ Added full-ci label to PR'); - - name: Get skipped checks and trigger workflows id: trigger_workflows uses: actions/github-script@v7 @@ -228,19 +216,34 @@ jobs: const notFoundList = notFound.length > 0 ? `\n\n**Triggered but not yet queued (may still start):**\n${notFound.map(w => `- âŗ ${w.name}`).join('\n')}` : ''; const failedList = failed.length > 0 ? `\n\n**Failed to trigger:**\n${failed.map(f => `- ❌ ${f.workflow}: ${f.error}`).join('\n')}` : ''; + // Add full-ci label only if we actually triggered workflows or if checks are already running + let labelAdded = false; + try { + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + labels: ['full-ci'] + }); + labelAdded = true; + console.log('✅ Added full-ci label to PR'); + } catch (error) { + console.error('âš ī¸ Failed to add label:', error.message); + } + const body = `🚀 **Full CI Mode Enabled** ${status} ${skippedChecksList} ${verifiedList}${notFoundList}${failedList} - ${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. + ${labelAdded && 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. To disable full CI mode, use the \`/stop-run-skipped-ci\` command. View progress in the [Actions tab](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions).` : ''} - ${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.` : ''}`; + ${labelAdded && notApplicable.length > 0 ? `\nAll CI checks are already running on this PR. Added the \`full-ci\` label - future commits will run the full CI suite.` : ''}`; // Post the comment await github.rest.issues.createComment({ diff --git a/.github/workflows/stop-run-skipped-ci.yml b/.github/workflows/stop-run-skipped-ci.yml index 80312cedf8..ae06fb471c 100644 --- a/.github/workflows/stop-run-skipped-ci.yml +++ b/.github/workflows/stop-run-skipped-ci.yml @@ -120,6 +120,7 @@ jobs: issue_number: context.issue.number, body: errorBody }); - throw error; + // Use core.setFailed instead of throw to properly fail the workflow + core.setFailed(`Failed to remove label: ${error.message}`); } } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 339ace5c75..d7176df925 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -466,9 +466,7 @@ Removes the `full-ci` label and returns to standard CI behavior: - You've validated changes with full CI and want to return to faster feedback - Reducing CI time during rapid iteration on a PR -#### Automatic Cleanup - -The `full-ci` label is automatically removed when a PR is merged, so you don't need to manually clean it up. +**Note:** The `full-ci` label is preserved on merged PRs as a historical record of which PRs ran with comprehensive testing. ### Install Generator