From 8f30835e9e90c8f23969da3bc9ca4fb1cfb8f806 Mon Sep 17 00:00:00 2001 From: Pan YANG Date: Tue, 6 Jan 2026 09:37:00 +0800 Subject: [PATCH 1/3] ci(workflow): remove URL validation job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the tests-urls job as URLs may be temporarily unavailable and cause false negatives. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/ci.yml | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9bb71e3..6d96544 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,26 +68,6 @@ jobs: - name: Run validation tests run: npm run test:validate - tests-urls: - name: Tests (URLs) - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Setup Node.js - uses: actions/setup-node@v6 - with: - node-version: '22' - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Validate URLs in manifests - run: npm run test:urls - continue-on-error: true # URLs may be temporarily unavailable - spell-check: name: Spell Check runs-on: ubuntu-latest @@ -140,7 +120,7 @@ jobs: ci-success: name: CI Success runs-on: ubuntu-latest - needs: [lint, type-check, tests-validate, tests-urls, spell-check, build] + needs: [lint, type-check, tests-validate, spell-check, build] if: always() steps: - name: Check all jobs From c3b6e73f0b9ad9709385cc11cad646febab6bb02 Mon Sep 17 00:00:00 2001 From: Pan YANG Date: Tue, 6 Jan 2026 10:15:24 +0800 Subject: [PATCH 2/3] ci(workflow): add guard logic for fork and dependabot Pull Requests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add deploy_guard and cleanup_guard steps to skip preview deployment and cleanup for fork PRs and Dependabot PRs, which don't have access to repository secrets. - Add deploy_guard step to skip preview deployment for fork PRs and Dependabot PRs - Add cleanup_guard step to skip preview cleanup for fork PRs and Dependabot PRs - Update PR comments to show deployment/cleanup status with skip reasons - Fix wrangler command to use --env "" for preview aliases 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/cleanup-preview.yml | 46 +++++++++++++++++++++- .github/workflows/deploy-preview.yml | 55 +++++++++++++++++++++++++-- 2 files changed, 97 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cleanup-preview.yml b/.github/workflows/cleanup-preview.yml index 318a2bb..29acb2f 100644 --- a/.github/workflows/cleanup-preview.yml +++ b/.github/workflows/cleanup-preview.yml @@ -12,7 +12,44 @@ jobs: pull-requests: write steps: + - name: Determine whether preview cleanup should run + id: cleanup_guard + shell: bash + env: + CF_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CF_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + PR_HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} + BASE_REPO: ${{ github.repository }} + ACTOR: ${{ github.actor }} + run: | + # Fork PRs do not receive repository secrets, so cleanup must be skipped. + SHOULD_CLEANUP="true" + REASON="" + + if [[ -n "$PR_HEAD_REPO" && "$PR_HEAD_REPO" != "$BASE_REPO" ]]; then + SHOULD_CLEANUP="false" + REASON="Fork pull requests do not have access to repository secrets in GitHub Actions." + fi + + if [[ "$ACTOR" == "dependabot[bot]" ]]; then + SHOULD_CLEANUP="false" + REASON="Dependabot pull requests do not have access to repository secrets in this workflow." + fi + + if [[ "$SHOULD_CLEANUP" == "true" ]]; then + if [[ -z "$CF_API_TOKEN" || -z "$CF_ACCOUNT_ID" ]]; then + echo "Missing required Cloudflare secrets. Please configure CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID in repository secrets." + exit 1 + fi + fi + + { + echo "should_cleanup=$SHOULD_CLEANUP" + echo "reason=$REASON" + } >> "$GITHUB_OUTPUT" + - name: Delete Preview Deployment + if: steps.cleanup_guard.outputs.should_cleanup == 'true' uses: cloudflare/wrangler-action@v3 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} @@ -22,13 +59,20 @@ jobs: - name: Comment Cleanup Status uses: actions/github-script@v7 + env: + SHOULD_CLEANUP: ${{ steps.cleanup_guard.outputs.should_cleanup }} + SKIP_REASON: ${{ steps.cleanup_guard.outputs.reason }} with: script: | const prNumber = context.payload.pull_request.number; + const shouldCleanup = process.env.SHOULD_CLEANUP === 'true'; + const skipReason = process.env.SKIP_REASON || 'Cleanup was skipped.'; await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNumber, - body: `### Preview deployment cleaned up\n\nThe preview deployment for PR #${prNumber} has been removed.` + body: shouldCleanup + ? `### Preview deployment cleaned up\n\nThe preview deployment for PR #${prNumber} has been removed.` + : `### Preview deployment cleanup skipped\n\n**Reason:** ${skipReason}` }); diff --git a/.github/workflows/deploy-preview.yml b/.github/workflows/deploy-preview.yml index c60f54b..e620919 100644 --- a/.github/workflows/deploy-preview.yml +++ b/.github/workflows/deploy-preview.yml @@ -22,6 +22,46 @@ jobs: - name: Checkout code uses: actions/checkout@v6 + - name: Determine whether preview deploy should run + id: deploy_guard + shell: bash + env: + CF_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CF_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + PR_HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }} + BASE_REPO: ${{ github.repository }} + EVENT_NAME: ${{ github.event_name }} + ACTOR: ${{ github.actor }} + run: | + # Decide whether we can deploy a preview safely. + # Fork PRs do not receive repository secrets, so deployment must be skipped. + SHOULD_DEPLOY="true" + REASON="" + + if [[ "$EVENT_NAME" == "pull_request" ]]; then + if [[ -n "$PR_HEAD_REPO" && "$PR_HEAD_REPO" != "$BASE_REPO" ]]; then + SHOULD_DEPLOY="false" + REASON="Fork pull requests do not have access to repository secrets in GitHub Actions." + fi + + if [[ "$ACTOR" == "dependabot[bot]" ]]; then + SHOULD_DEPLOY="false" + REASON="Dependabot pull requests do not have access to repository secrets in this workflow." + fi + fi + + if [[ "$SHOULD_DEPLOY" == "true" ]]; then + if [[ -z "$CF_API_TOKEN" || -z "$CF_ACCOUNT_ID" ]]; then + echo "Missing required Cloudflare secrets. Please configure CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID in repository secrets." + exit 1 + fi + fi + + { + echo "should_deploy=$SHOULD_DEPLOY" + echo "reason=$REASON" + } >> "$GITHUB_OUTPUT" + - name: Compute preview identifiers id: preview_meta run: | @@ -71,21 +111,26 @@ jobs: BUILD_TIME: ${{ github.event.pull_request.updated_at || github.event.head_commit.timestamp }} - name: Deploy Preview + if: steps.deploy_guard.outputs.should_deploy == 'true' uses: cloudflare/wrangler-action@v3 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - command: versions upload --preview-alias ${{ steps.preview_meta.outputs.preview_alias }} + command: versions upload --env "" --preview-alias ${{ steps.preview_meta.outputs.preview_alias }} - name: Comment Preview URL if: github.event_name == 'pull_request' uses: actions/github-script@v7 env: PREVIEW_URL: ${{ steps.preview_meta.outputs.preview_url }} + SHOULD_DEPLOY: ${{ steps.deploy_guard.outputs.should_deploy }} + SKIP_REASON: ${{ steps.deploy_guard.outputs.reason }} with: script: | const prNumber = context.payload.pull_request.number; const previewUrl = process.env.PREVIEW_URL; + const shouldDeploy = process.env.SHOULD_DEPLOY === 'true'; + const skipReason = process.env.SKIP_REASON || 'Preview deployment was skipped.'; const commitSha = context.sha.substring(0, 7); // Find existing bot comment @@ -99,14 +144,18 @@ jobs: c.user.type === 'Bot' && c.body.includes('Preview deployment') ); + const status = shouldDeploy ? 'Ready' : 'Skipped'; + const urlCell = shouldDeploy ? `[${previewUrl}](${previewUrl})` : '-'; + const reasonBlock = shouldDeploy ? '' : `\n\n**Reason:** ${skipReason}\n\nIf you want a preview deployment, please ask a maintainer to run this from a branch within the main repository.`; + const body = `### Preview deployment | Status | URL | |--------|-----| - | Ready | [${previewUrl}](${previewUrl}) | + | ${status} | ${urlCell} | **Commit:** \`${commitSha}\` - **Updated:** ${new Date().toISOString()}`; + **Updated:** ${new Date().toISOString()}${reasonBlock}`; if (botComment) { await github.rest.issues.updateComment({ From 973c14d98979e92c1efac38f514bcf42366d95e3 Mon Sep 17 00:00:00 2001 From: Pan YANG Date: Tue, 6 Jan 2026 10:30:43 +0800 Subject: [PATCH 3/3] ci(workflow): simplify Cloudflare Pages deploy command by removing empty env flag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed the --env "" flag from the versions upload command as it's unnecessary. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .github/workflows/deploy-preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-preview.yml b/.github/workflows/deploy-preview.yml index e620919..9a5b300 100644 --- a/.github/workflows/deploy-preview.yml +++ b/.github/workflows/deploy-preview.yml @@ -116,7 +116,7 @@ jobs: with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - command: versions upload --env "" --preview-alias ${{ steps.preview_meta.outputs.preview_alias }} + command: versions upload --preview-alias ${{ steps.preview_meta.outputs.preview_alias }} - name: Comment Preview URL if: github.event_name == 'pull_request'