Repository navigation
ci(deploy): add workflow_dispatch to production deploy #72
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: PR preview | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened, closed] | |
| concurrency: | |
| group: preview-${{ github.event.pull_request.number }} | |
| cancel-in-progress: false | |
| permissions: | |
| contents: read | |
| jobs: | |
| preview: | |
| if: github.event.action != 'closed' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| permissions: | |
| contents: read | |
| pull-requests: write # only this job comments on the PR | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: oven-sh/setup-bun@v2 | |
| with: { bun-version: "1.3.14" } | |
| - run: bun install --frozen-lockfile | |
| - run: bun run lint | |
| - run: bun run fmt:check | |
| - run: bun run typecheck | |
| - run: bun run test | |
| - name: Cache GTFS feed # fallback so a data.pid.cz outage can't block a preview | |
| uses: actions/cache@v5 | |
| with: | |
| path: .cache | |
| key: gtfs-${{ github.run_id }} | |
| restore-keys: gtfs- | |
| - run: bun run build:index | |
| - run: bun run build:web | |
| - run: bun run verify:pwa | |
| - name: Require CF_WORKERS_SUBDOMAIN | |
| env: { CF_WORKERS_SUBDOMAIN: "${{ vars.CF_WORKERS_SUBDOMAIN }}" } | |
| run: | | |
| if [ -z "$CF_WORKERS_SUBDOMAIN" ]; then | |
| echo "::error::CF_WORKERS_SUBDOMAIN repo variable is not set." | |
| exit 1 | |
| fi | |
| - name: Deploy preview | |
| run: bunx alchemy deploy --stage "pr-${{ github.event.pull_request.number }}" --yes | |
| env: | |
| TABLO_STAGE: pr-${{ github.event.pull_request.number }} # worker names itself tablo-pr-<N> | |
| TABLO_COMMIT: ${{ github.event.pull_request.head.sha }} # served by /api/health; asserted below | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| GOLEMIO_API_TOKEN: ${{ secrets.GOLEMIO_API_TOKEN }} | |
| - name: Smoke test (/api/health serves this commit) | |
| env: | |
| URL: https://tablo-pr-${{ github.event.pull_request.number }}.${{ vars.CF_WORKERS_SUBDOMAIN }}.workers.dev | |
| EXPECTED: ${{ github.event.pull_request.head.sha }} | |
| run: | | |
| # Assert the deployed build, not just a 200 — a previous build's | |
| # health endpoint also answers 200. | |
| for i in $(seq 1 12); do | |
| body=$(curl -sS "$URL/api/health" || echo "") | |
| echo "attempt $i: $URL/api/health -> $body" | |
| if echo "$body" | grep -q "\"version\":\"$EXPECTED\""; then exit 0; fi | |
| sleep 6 | |
| done | |
| echo "::error::preview health check failed: $URL/api/health never served version $EXPECTED" | |
| exit 1 | |
| - name: Comment preview URL | |
| uses: actions/github-script@v8 | |
| env: | |
| # Primary: the custom-domain hostname attached by the worker | |
| # (workerDomain → preview-<N>.tablo.run). The workers.dev URL stays | |
| # live via `url: true` and is shown as a fallback. | |
| PREVIEW_URL: https://preview-${{ github.event.pull_request.number }}.tablo.run | |
| WORKERS_DEV_URL: https://tablo-pr-${{ github.event.pull_request.number }}.${{ vars.CF_WORKERS_SUBDOMAIN }}.workers.dev | |
| with: | |
| script: | | |
| const marker = '<!-- tablo-preview -->'; | |
| const body = `${marker}\n🚀 **Preview deployed:** ${process.env.PREVIEW_URL}\n<sub>fallback: ${process.env.WORKERS_DEV_URL}</sub>`; | |
| 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 && c.body.includes(marker)); | |
| const api = existing ? 'updateComment' : 'createComment'; | |
| await github.rest.issues[api]({ | |
| owner: context.repo.owner, repo: context.repo.repo, | |
| ...(existing ? { comment_id: existing.id } : { issue_number: context.issue.number }), | |
| body, | |
| }); | |
| cleanup: | |
| if: github.event.action == 'closed' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: oven-sh/setup-bun@v2 | |
| with: { bun-version: "1.3.14" } | |
| - run: bun install --frozen-lockfile | |
| - name: Destroy preview # no-op if this PR never deployed one | |
| run: bunx alchemy destroy --stage "pr-${{ github.event.pull_request.number }}" --yes | |
| env: | |
| TABLO_STAGE: pr-${{ github.event.pull_request.number }} | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| GOLEMIO_API_TOKEN: ${{ secrets.GOLEMIO_API_TOKEN }} |