diff --git a/.github/workflows/worker-preview.yml b/.github/workflows/worker-preview.yml new file mode 100644 index 000000000..9def1905d --- /dev/null +++ b/.github/workflows/worker-preview.yml @@ -0,0 +1,79 @@ +name: Worker Preview + +on: + pull_request: + types: [opened, synchronize, reopened, closed] + +permissions: + contents: read + pull-requests: write + +jobs: + preview: + if: github.event.action != 'closed' && github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + - run: pnpm install --frozen-lockfile --prefer-offline + - run: cp wrangler.example.jsonc wrangler.jsonc + - name: Configure preview auth URL + env: + PREVIEW_NAME: pr-${{ github.event.pull_request.number }} + run: | + preview_url="https://${PREVIEW_NAME}-splitpro.andrepascoa.workers.dev" + sed -i "s|https://replace-with-this-preview-url|${preview_url}|g" wrangler.jsonc + - run: SKIP_ENV_VALIDATION=1 pnpm build + - name: Apply preview database migrations + run: pnpm exec wrangler d1 migrations apply DB --remote --preview --config wrangler.jsonc + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CF_PREVIEW_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: 4c52a530606031af4f6ca06e32ca1ec5 + - name: Deploy Worker Preview + id: preview + run: | + output="$(pnpm exec wrangler preview --name "pr-${{ github.event.pull_request.number }}" --json)" + printf '%s\n' "$output" + url="$(printf '%s' "$output" | node -e 'let output = ""; process.stdin.on("data", chunk => output += chunk); process.stdin.on("end", () => { const match = output.match(/"preview":\s*\{[\s\S]*?"urls":\s*\[\s*"([^"]+)"/); if (!match) process.exit(1); process.stdout.write(match[1]); });')" + echo "url=$url" >> "$GITHUB_OUTPUT" + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CF_PREVIEW_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: 4c52a530606031af4f6ca06e32ca1ec5 + - name: Add or update preview comment + uses: actions/github-script@v7 + env: + PREVIEW_URL: ${{ steps.preview.outputs.url }} + with: + script: | + const marker = ''; + const body = `${marker}\nšŸš€ Worker preview: ${process.env.PREVIEW_URL}`; + const { owner, repo } = context.repo; + const issue_number = context.issue.number; + const comments = await github.paginate(github.rest.issues.listComments, { owner, repo, issue_number }); + const existing = comments.find((comment) => comment.body?.includes(marker)); + if (existing) { + await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body }); + } else { + await github.rest.issues.createComment({ owner, repo, issue_number, body }); + } + + cleanup: + if: github.event.action == 'closed' && github.event.pull_request.head.repo.full_name == github.repository + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + - run: pnpm install --frozen-lockfile --prefer-offline + - run: cp wrangler.example.jsonc wrangler.jsonc + - run: pnpm exec wrangler preview delete --name "pr-${{ github.event.pull_request.number }}" --skip-confirmation + env: + CLOUDFLARE_API_TOKEN: ${{ secrets.CF_PREVIEW_TOKEN }} + CLOUDFLARE_ACCOUNT_ID: 4c52a530606031af4f6ca06e32ca1ec5 diff --git a/README.md b/README.md index 53df55798..47cf417ef 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,29 @@ setting belongs only in `previews.vars`, not production `vars`. - `drizzle-kit` and `wrangler d1 migrations` own the schema. `migrations/0001_balance_view_and_triggers.sql` is hand-written (the `BalanceView` view and a trigger). Back it up before regenerating migrations. +## Backups + +- **Time Travel:** D1 keeps point-in-time history for 30 days on the Workers Paid plan. + Restore with `npx wrangler d1 time-travel restore splitpro --timestamp=`. +- **Daily backup to R2:** the `splitpro-backup` Workflow (03:00 UTC) exports D1 through the REST API + to `d1/splitpro--