Merge branch 'main' into auto-update-github-stars #118
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy Preview | |
| on: | |
| pull_request: | |
| push: | |
| branches-ignore: [main, develop] | |
| concurrency: | |
| group: preview-${{ github.event.pull_request.number || github.ref_name }} | |
| cancel-in-progress: true | |
| jobs: | |
| deploy: | |
| name: Deploy Preview to Cloudflare Workers | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| deployments: write | |
| steps: | |
| - 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 [[ "$ACTOR" == "dependabot[bot]" ]]; then | |
| SHOULD_DEPLOY="false" | |
| REASON="Dependabot-triggered workflows do not have access to repository secrets in this workflow." | |
| fi | |
| 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 | |
| fi | |
| if [[ "$SHOULD_DEPLOY" == "true" ]]; then | |
| if [[ -z "$CF_API_TOKEN" || -z "$CF_ACCOUNT_ID" ]]; then | |
| SHOULD_DEPLOY="false" | |
| REASON="Missing required Cloudflare secrets (CLOUDFLARE_API_TOKEN/CLOUDFLARE_ACCOUNT_ID)." | |
| fi | |
| fi | |
| { | |
| echo "should_deploy=$SHOULD_DEPLOY" | |
| echo "reason=$REASON" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Compute preview identifiers | |
| id: preview_meta | |
| run: | | |
| if [[ "${{ github.event_name }}" == "pull_request" ]]; then | |
| CF_BRANCH="pr-${{ github.event.pull_request.number }}" | |
| CONTEXT_LABEL="PR #${{ github.event.pull_request.number }}" | |
| else | |
| RAW_BRANCH="${{ github.ref_name }}" | |
| SLUG="$(echo "$RAW_BRANCH" | tr '[:upper:]' '[:lower:]' | sed -E 's#[^a-z0-9]+#-#g; s#(^-+|-+$)##g' | cut -c1-40)" | |
| if [[ -z "$SLUG" ]]; then | |
| SLUG="branch" | |
| fi | |
| CF_BRANCH="br-$SLUG" | |
| CONTEXT_LABEL="Branch $RAW_BRANCH" | |
| fi | |
| # Cloudflare Preview URLs (aliased) format: | |
| # <ALIAS>-<WORKER_NAME>.<SUBDOMAIN>.workers.dev | |
| # See: https://developers.cloudflare.com/workers/configuration/previews/ | |
| PREVIEW_ALIAS="$CF_BRANCH" | |
| WORKER_NAME="aicodingstack" | |
| PREVIEW_URL="https://${PREVIEW_ALIAS}-${WORKER_NAME}.pr-preview.workers.dev" | |
| { | |
| echo "cf_branch=$CF_BRANCH" | |
| echo "worker_name=$WORKER_NAME" | |
| echo "preview_alias=$PREVIEW_ALIAS" | |
| echo "preview_url=$PREVIEW_URL" | |
| echo "context_label=$CONTEXT_LABEL" | |
| } >> "$GITHUB_OUTPUT" | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '22' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run CI tests | |
| run: npm run test:ci | |
| - name: Build with OpenNext | |
| run: npm run build | |
| env: | |
| 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 }} | |
| - 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 | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| }); | |
| const botComment = comments.find(c => | |
| 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 | | |
| |--------|-----| | |
| | ${status} | ${urlCell} | | |
| **Commit:** \`${commitSha}\` | |
| **Updated:** ${new Date().toISOString()}${reasonBlock}`; | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: prNumber, | |
| body | |
| }); | |
| } | |
| - name: Deployment summary | |
| run: | | |
| echo "### Preview Deployment" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Context:** ${{ steps.preview_meta.outputs.context_label }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **URL:** ${{ steps.preview_meta.outputs.preview_url }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Commit:** ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Deploy:** ${{ steps.deploy_guard.outputs.should_deploy == 'true' && 'ran' || 'skipped' }}" >> $GITHUB_STEP_SUMMARY | |
| if [[ "${{ steps.deploy_guard.outputs.should_deploy }}" != "true" && -n "${{ steps.deploy_guard.outputs.reason }}" ]]; then | |
| echo "- **Skip reason:** ${{ steps.deploy_guard.outputs.reason }}" >> $GITHUB_STEP_SUMMARY | |
| fi |