From cbda101a37e570888769be01db4c4c4acfe4321f Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 1 Mar 2026 23:26:11 +0000 Subject: [PATCH] Add PR preview deploys via Cloudflare Workers Extend build.yml to also trigger on pull_request events, deploying preview builds to Cloudflare Workers (static assets). Each PR gets its own worker (toys-pr-{number}) with a bot comment linking to the preview URL. A separate cleanup workflow deletes the worker when the PR closes. - build.yml: add pull_request trigger, conditional VITE_BASE ("/" for PRs, "/toys/" for main), deploy-preview job with wrangler + PR comment - preview-cleanup.yml: delete worker on PR close - wrangler.toml: minimal assets-only config for Cloudflare Workers https://claude.ai/code/session_015vs1SrQi7gY45GQJBn23w7 --- .github/workflows/build.yml | 85 ++++++++++++++++++++++++--- .github/workflows/preview-cleanup.yml | 18 ++++++ wrangler.toml | 5 ++ 3 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/preview-cleanup.yml create mode 100644 wrangler.toml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 63e0d9ba..85c0f01e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,19 +6,20 @@ on: push: branches: - main + pull_request: + types: [opened, synchronize, reopened] -# Allow one concurrent deployment concurrency: - group: "pages" + group: deploy-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true -env: - VITE_BASE: "/toys/" - jobs: build: runs-on: ubuntu-latest timeout-minutes: 30 + env: + VITE_BASE: + ${{ github.event_name == 'pull_request' && '/' || '/toys/' }} steps: - name: Setup Node uses: actions/setup-node@v3 @@ -85,9 +86,10 @@ jobs: uses: actions/upload-artifact@v4 with: path: dist/ - name: github-pages + name: build-output - deploy: + deploy-pages: + if: github.event_name == 'push' environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} @@ -112,7 +114,7 @@ jobs: - name: Download uses: actions/download-artifact@v4 with: - name: github-pages + name: build-output - name: Commit & push changes run: | @@ -123,3 +125,70 @@ jobs: commit_ref="$(git commit-tree "$tree_ref" -p HEAD -p "$GITHUB_SHA" -m "[automated] publish from $GITHUB_SHA on $(date)")" git update-ref refs/heads/gh-pages "$commit_ref" git push + + deploy-preview: + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + needs: build + permissions: + pull-requests: write + steps: + - uses: actions/checkout@v3 + + - uses: actions/download-artifact@v4 + with: + name: build-output + path: dist/ + + - name: Deploy to Cloudflare Workers + id: deploy + uses: cloudflare/wrangler-action@v3 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + command: + deploy --name toys-pr-${{ github.event.pull_request.number + }} + + - name: Comment preview URL on PR + uses: actions/github-script@v7 + with: + script: | + const marker = ''; + const workerName = `toys-pr-${context.payload.pull_request.number}`; + const url = `https://${workerName}.${process.env.CLOUDFLARE_ACCOUNT_ID}.workers.dev`; + const deployUrl = '${{ steps.deploy.outputs.deployment-url }}'; + const previewUrl = deployUrl || url; + const body = [ + marker, + `**Preview deploy** is ready!`, + '', + `${previewUrl}`, + '', + `_Built from ${context.sha.slice(0, 7)}_`, + ].join('\n'); + + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + }); + + const existing = comments.find(c => c.body.includes(marker)); + if (existing) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: existing.id, + body, + }); + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.pull_request.number, + body, + }); + } + env: + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} diff --git a/.github/workflows/preview-cleanup.yml b/.github/workflows/preview-cleanup.yml new file mode 100644 index 00000000..0c27adc2 --- /dev/null +++ b/.github/workflows/preview-cleanup.yml @@ -0,0 +1,18 @@ +name: Cleanup preview deploy + +on: + pull_request: + types: [closed] + +jobs: + cleanup: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Delete preview worker + uses: cloudflare/wrangler-action@v3 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + command: delete --name toys-pr-${{ github.event.pull_request.number }} --force diff --git a/wrangler.toml b/wrangler.toml new file mode 100644 index 00000000..2fed8af9 --- /dev/null +++ b/wrangler.toml @@ -0,0 +1,5 @@ +name = "toys-preview" +compatibility_date = "2025-01-01" + +[assets] +directory = "./dist"