From 53779a66ae8e55f537e2f570bfc72ec436e56667 Mon Sep 17 00:00:00 2001 From: Nooc Date: Mon, 9 Mar 2026 21:05:35 +0800 Subject: [PATCH 1/8] test: PR preview test --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c403366..a0e7cb8 100644 --- a/README.md +++ b/README.md @@ -34,3 +34,4 @@ You can check out [the Next.js GitHub repository](https://github.com/vercel/next The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. +# Test From c48ad4d52fef8296885c725761b0609a1b32e6d0 Mon Sep 17 00:00:00 2001 From: Nooc Date: Mon, 9 Mar 2026 21:10:17 +0800 Subject: [PATCH 2/8] fix: simplify workflow command --- .github/workflows/deploy.yml | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 1cc9e56..6521ff9 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -30,20 +30,12 @@ jobs: env: NODE_ENV: production - - name: Deploy to Cloudflare (Preview for PR / Production for main) + - name: Deploy to Cloudflare uses: cloudflare/wrangler-action@v3 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - command: | - if [ "${{ github.event_name }}" = "pull_request" ]; then - # Deploy to preview with unique name based on PR number - opennextjs-cloudflare build - wrangler deploy --env preview --name sparkmemos-pr-${{ github.event.pull_request.number }} - else - # Deploy to production - opennextjs-cloudflare deploy - fi + command: wrangler deploy - name: Deploy status comment if: github.event_name == 'pull_request' From 5c7690caa6f9dac616d868f9e0fb5013a9c0fc2f Mon Sep 17 00:00:00 2001 From: Nooc Date: Mon, 9 Mar 2026 21:16:54 +0800 Subject: [PATCH 3/8] fix: use direct wrangler command --- .github/workflows/deploy.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 6521ff9..9d11e40 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -30,12 +30,14 @@ jobs: env: NODE_ENV: production + - name: Install Wrangler + run: npm install -g wrangler + - name: Deploy to Cloudflare - uses: cloudflare/wrangler-action@v3 - with: - apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} - accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - command: wrangler deploy + run: wrangler deploy + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - name: Deploy status comment if: github.event_name == 'pull_request' From d4261503c4127671ccf5eaba74e4692ef3e208ef Mon Sep 17 00:00:00 2001 From: Nooc Date: Mon, 9 Mar 2026 21:21:36 +0800 Subject: [PATCH 4/8] fix: add opennextjs-cloudflare build step --- .github/workflows/deploy.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9d11e40..07bbeda 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -25,11 +25,14 @@ jobs: - name: Install dependencies run: npm ci - - name: Build + - name: Build Next.js run: npm run build env: NODE_ENV: production + - name: Build OpenNext + run: npx opennextjs-cloudflare build + - name: Install Wrangler run: npm install -g wrangler From 93e2f906daa3870d923ece4c169756a12c499822 Mon Sep 17 00:00:00 2001 From: Nooc Date: Mon, 9 Mar 2026 21:28:24 +0800 Subject: [PATCH 5/8] fix: add permissions for issues write --- .github/workflows/deploy.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 07bbeda..26c40da 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -12,6 +12,8 @@ jobs: permissions: contents: read deployments: write + issues: write + pull-requests: write steps: - uses: actions/checkout@v4 From 707ded3ceeda3cae3ff489881a8cdecad90b0f39 Mon Sep 17 00:00:00 2001 From: Nooc Date: Mon, 9 Mar 2026 21:38:02 +0800 Subject: [PATCH 6/8] feat: deploy PR to preview subdomain, main only for production --- .github/workflows/deploy.yml | 54 ++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 26c40da..0d06825 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -5,6 +5,10 @@ on: branches: - main pull_request: + types: + - opened + - synchronize + - reopened jobs: deploy: @@ -38,21 +42,59 @@ jobs: - name: Install Wrangler run: npm install -g wrangler - - name: Deploy to Cloudflare + # Deploy to main domain (main branch only) + - name: Deploy to Cloudflare (Main) + if: github.event_name == 'push' && github.ref == 'refs/heads/main' run: wrangler deploy env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + # Deploy to preview subdomain (PR only) + - name: Deploy to Cloudflare (Preview) + if: github.event_name == 'pull_request' + run: | + wrangler deploy --name sparkmemos-pr-${{ github.event.pull_request.number }} + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + + # Comment preview link on PR - name: Deploy status comment if: github.event_name == 'pull_request' uses: actions/github-script@v7 with: script: | const previewUrl = `https://sparkmemos-pr-${{ github.event.pull_request.number }}.workers.dev`; - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.payload.pull_request.number, - body: `๐Ÿš€ Preview deployed: ${previewUrl}` + const prNumber = context.payload.pull_request.number; + const owner = context.repo.owner; + const repo = context.repo.repo; + + // Check for existing comment to avoid duplicates + const { data: comments } = await github.rest.issues.listComments({ + owner, + repo, + issue_number: prNumber }); + + const existingComment = comments.find(comment => + comment.body.includes('๐Ÿš€ Preview deployed:') + ); + + if (existingComment) { + // Update existing comment + await github.rest.issues.updateComment({ + owner, + repo, + comment_id: existingComment.id, + body: `๐Ÿš€ Preview deployed: ${previewUrl}` + }); + } else { + // Create new comment + await github.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body: `๐Ÿš€ Preview deployed: ${previewUrl}` + }); + } From 1b46f6b0b0d2eeb7f94c703a0f6113470d667fb8 Mon Sep 17 00:00:00 2001 From: Nooc Date: Mon, 9 Mar 2026 21:51:14 +0800 Subject: [PATCH 7/8] feat: get actual URL from Cloudflare API and add cleanup job --- .github/workflows/deploy.yml | 95 +++++++++++++++++++++++++++++++++--- 1 file changed, 87 insertions(+), 8 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 0d06825..ddc24fd 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -9,6 +9,7 @@ on: - opened - synchronize - reopened + - closed jobs: deploy: @@ -50,11 +51,39 @@ jobs: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - # Deploy to preview subdomain (PR only) + # Deploy to preview environment (PR only) - name: Deploy to Cloudflare (Preview) if: github.event_name == 'pull_request' run: | - wrangler deploy --name sparkmemos-pr-${{ github.event.pull_request.number }} + wrangler deploy --env pr-${{ github.event.pull_request.number }} --legacy-env + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + + # Get actual domain from Cloudflare API + - name: Get deployment URL + if: github.event_name == 'pull_request' + id: get-url + run: | + PR_NUM=${{ github.event.pull_request.number }} + ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + WORKER_NAME="sparkmemos" + + ACCOUNT_RESPONSE=$(curl -s -X GET \ + "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}" \ + -H "Authorization: Bearer ${{ secrets.CLOUDFLARE_API_TOKEN }}" \ + -H "Content-Type: application/json") + + ACCOUNT_SUBDOMAIN=$(echo $ACCOUNT_RESPONSE | jq -r '.result.meta.workers_subdomain // empty') + + if [ -z "$ACCOUNT_SUBDOMAIN" ]; then + ACCOUNT_SUBDOMAIN=$ACCOUNT_ID + fi + + PREVIEW_URL="https://${WORKER_NAME}-pr-${PR_NUM}.${ACCOUNT_SUBDOMAIN}.workers.dev" + + echo "Preview URL: $PREVIEW_URL" + echo "preview_url=${PREVIEW_URL}" >> $GITHUB_OUTPUT env: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} @@ -65,12 +94,11 @@ jobs: uses: actions/github-script@v7 with: script: | - const previewUrl = `https://sparkmemos-pr-${{ github.event.pull_request.number }}.workers.dev`; + const previewUrl = process.env.PREVIEW_URL; const prNumber = context.payload.pull_request.number; const owner = context.repo.owner; const repo = context.repo.repo; - // Check for existing comment to avoid duplicates const { data: comments } = await github.rest.issues.listComments({ owner, repo, @@ -81,20 +109,71 @@ jobs: comment.body.includes('๐Ÿš€ Preview deployed:') ); + const commentBody = `๐Ÿš€ Preview deployed: ${previewUrl}`; + if (existingComment) { - // Update existing comment await github.rest.issues.updateComment({ owner, repo, comment_id: existingComment.id, - body: `๐Ÿš€ Preview deployed: ${previewUrl}` + body: commentBody }); } else { - // Create new comment await github.rest.issues.createComment({ owner, repo, issue_number: prNumber, - body: `๐Ÿš€ Preview deployed: ${previewUrl}` + body: commentBody }); } + env: + PREVIEW_URL: ${{ steps.get-url.outputs.preview_url }} + + cleanup: + runs-on: ubuntu-latest + permissions: + contents: read + deployments: write + issues: write + pull-requests: write + + if: github.event_name == 'pull_request' && github.event.action == 'closed' + + steps: + - name: Install Wrangler + run: npm install -g wrangler + + - name: Cleanup preview environment + run: | + PR_NUM=${{ github.event.pull_request.number }} + ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + WORKER_NAME="sparkmemos" + + echo "Cleaning up preview environment for PR #${PR_NUM}" + + RESPONSE=$(curl -s -X DELETE \ + "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/workers/scripts/${WORKER_NAME}/environments/pr-${PR_NUM}" \ + -H "Authorization: Bearer ${{ secrets.CLOUDFLARE_API_TOKEN }}" \ + -H "Content-Type: application/json") + + echo "API Cleanup response: $RESPONSE" + + echo "Cleanup completed for PR #${PR_NUM}" + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + + - name: Add cleanup comment + uses: actions/github-script@v7 + with: + script: | + const prNumber = context.payload.pull_request.number; + const owner = context.repo.owner; + const repo = context.repo.repo; + + await github.rest.issues.createComment({ + owner, + repo, + issue_number: prNumber, + body: `๐Ÿงน Preview environment cleaned up (PR #${prNumber} closed/merged)` + }); From d639d6463ace533bed407306fc46baf0685ddab4 Mon Sep 17 00:00:00 2001 From: Nooc Date: Mon, 9 Mar 2026 22:03:26 +0800 Subject: [PATCH 8/8] fix: use workers/subdomain API --- .github/workflows/deploy.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index ddc24fd..569d871 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -69,12 +69,12 @@ jobs: ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }} WORKER_NAME="sparkmemos" - ACCOUNT_RESPONSE=$(curl -s -X GET \ - "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}" \ + SUBDOMAIN_RESPONSE=$(curl -s -X GET \ + "https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/workers/subdomain" \ -H "Authorization: Bearer ${{ secrets.CLOUDFLARE_API_TOKEN }}" \ -H "Content-Type: application/json") - ACCOUNT_SUBDOMAIN=$(echo $ACCOUNT_RESPONSE | jq -r '.result.meta.workers_subdomain // empty') + ACCOUNT_SUBDOMAIN=$(echo $SUBDOMAIN_RESPONSE | jq -r '.result.subdomain // empty') if [ -z "$ACCOUNT_SUBDOMAIN" ]; then ACCOUNT_SUBDOMAIN=$ACCOUNT_ID