diff --git a/.github/workflows/preview-cloudflare.yml b/.github/workflows/preview-cloudflare.yml new file mode 100644 index 0000000..7ea3250 --- /dev/null +++ b/.github/workflows/preview-cloudflare.yml @@ -0,0 +1,88 @@ +name: Preview (Cloudflare) + +on: + pull_request: + types: [opened, synchronize, reopened] + +permissions: + contents: read + pull-requests: write + +concurrency: + group: preview-cloudflare-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + preview: + runs-on: ubuntu-latest + # Forked-repo PRs don't get repo secrets; skip rather than fail noisily. + if: github.event.pull_request.head.repo.full_name == github.repository + + steps: + - name: Check out code + uses: actions/checkout@v5 + + - name: Set up Node.js + uses: actions/setup-node@v5 + with: + node-version: "24" + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Compute preview alias + id: alias + run: | + alias=$(echo "${{ github.head_ref }}" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9-]+/-/g; s/^-+|-+$//g') + echo "value=$alias" >> "$GITHUB_OUTPUT" + + - name: Upload preview version + id: upload + run: | + npx wrangler versions upload \ + --config platforms/cloudflare/wrangler.toml \ + --preview-alias "${{ steps.alias.outputs.value }}" \ + --var APP_VERSION:pr-${{ github.event.pull_request.number }}-$(git rev-parse --short HEAD) \ + --message "PR #${{ github.event.pull_request.number }}" \ + | tee wrangler-upload.log + url=$(grep -oE 'https://[^[:space:]]*workers\.dev[^[:space:]]*' wrangler-upload.log | head -1) + if [ -z "$url" ]; then + echo "::error::Could not find a preview URL in wrangler output." + exit 1 + fi + echo "url=$url" >> "$GITHUB_OUTPUT" + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + + - name: Comment preview URL on PR + uses: actions/github-script@v8 + with: + script: | + const marker = ""; + const url = "${{ steps.upload.outputs.url }}"; + const body = `${marker}\nšŸ”Ž **Cloudflare preview:** ${url}\n\nUploaded from \`${{ github.sha }}\`. This is a Worker *version* preview — it shares the production D1 database, so it reads/writes real data; it does not receive cron-triggered refreshes.`; + + const { data: comments } = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.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.issue.number, + body, + }); + } diff --git a/platforms/cloudflare/wrangler.toml b/platforms/cloudflare/wrangler.toml index 33dda75..a8951c7 100644 --- a/platforms/cloudflare/wrangler.toml +++ b/platforms/cloudflare/wrangler.toml @@ -2,6 +2,11 @@ name = "feedreader" main = "src/index.ts" compatibility_date = "2025-01-01" +# Explicit (not relying on the workers.dev-matching default) so PR preview +# deploys (.github/workflows/preview-cloudflare.yml, `wrangler versions +# upload --preview-alias`) always get a reachable *.workers.dev URL. +preview_urls = true + [observability] enabled = true