Skip to content

ci(deploy): add workflow_dispatch to production deploy #72

ci(deploy): add workflow_dispatch to production deploy

ci(deploy): add workflow_dispatch to production deploy #72

Workflow file for this run

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 }}