Skip to content

Commit 76713a5

Browse files
committed
Improve preview-environment deployments
- Per PR preview URL - Better documentation for previews, github apps, enter
1 parent 6af10f3 commit 76713a5

File tree

15 files changed

+7299
-8542
lines changed

15 files changed

+7299
-8542
lines changed

.env.example

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
BETTER_AUTH_SECRET=""
22
BETTER_AUTH_URL="http://localhost:3000"
3-
GITHUB_CLIENT_ID=""
4-
GITHUB_CLIENT_SECRET=""
3+
OAUTH_GITHUB_CLIENT_ID=""
4+
OAUTH_GITHUB_CLIENT_SECRET=""
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
name: "Run Code Quality Checks"
2-
description: "Install dependencies and run formatting, linting, type checking, and tests"
1+
name: "Setup Bun and Dependencies"
2+
description: "Setup Bun and install dependencies"
33

44
runs:
55
using: "composite"
@@ -12,7 +12,3 @@ runs:
1212
- name: Install dependencies
1313
shell: bash
1414
run: bun install --frozen-lockfile --prefer-offline
15-
16-
- name: Run checks
17-
shell: bash
18-
run: bun run check

.github/workflows/check.yml

Lines changed: 0 additions & 16 deletions
This file was deleted.

.github/workflows/deploy.yml

Lines changed: 57 additions & 161 deletions
Original file line numberDiff line numberDiff line change
@@ -1,187 +1,83 @@
1-
name: Deploy to Cloudflare Workers
1+
name: Production Deploy
2+
3+
# Requires repository secrets:
4+
# - CLOUDFLARE_ACCOUNT_ID: Cloudflare account ID for the worker.
5+
# - CLOUDFLARE_API_TOKEN: Token with Workers Scripts Edit permissions.
6+
#
7+
# Requires production environment variables:
8+
# - BETTER_AUTH_URL: Production domain URL (e.g., https://startkit.dev)
9+
# - OAUTH_GITHUB_CLIENT_ID: GitHub OAuth app client ID
10+
#
11+
# Requires production environment secrets:
12+
# - BETTER_AUTH_SECRET: Better Auth secret key
13+
# - OAUTH_GITHUB_CLIENT_SECRET: GitHub OAuth app client secret
214

315
on:
4-
pull_request:
5-
types: [opened, synchronize, reopened, closed]
616
push:
7-
branches: [main]
17+
branches:
18+
- main
19+
workflow_dispatch:
820

9-
jobs:
10-
# Check code quality on PRs and main pushes
11-
check:
12-
if: github.event.action != 'closed'
13-
runs-on: ubuntu-latest
14-
steps:
15-
- uses: actions/checkout@v5
16-
- uses: ./.github/actions/check
21+
permissions:
22+
contents: read
23+
deployments: write
24+
25+
# Prevent multiple production deployments from running simultaneously
26+
# Ensures deployments complete in order without race conditions
27+
concurrency:
28+
group: production-deploy
29+
cancel-in-progress: false
1730

18-
# Deploy preview environment on PRs
19-
preview:
20-
if: github.event_name == 'pull_request' && github.event.action != 'closed'
21-
needs: check
31+
jobs:
32+
deploy:
2233
runs-on: ubuntu-latest
23-
environment:
24-
name: preview
25-
url: https://startkit-preview-pr-${{ github.event.number }}.startkit-dev.workers.dev
26-
outputs:
27-
preview-url: ${{ steps.deploy.outputs.deployment-url }}
28-
db-name: ${{ steps.setup-db.outputs.db-name }}
34+
environment: production
2935
steps:
30-
- uses: actions/checkout@v4
31-
32-
- name: Setup Bun
33-
uses: oven-sh/setup-bun@v2
34-
with:
35-
bun-version: latest
36+
- name: Checkout
37+
uses: actions/checkout@v5
3638

3739
- name: Install dependencies
38-
run: bun install --frozen-lockfile
40+
uses: ./.github/actions/setup
3941

40-
- name: Setup preview database and run migrations
41-
id: setup-db
42-
run: |
43-
DB_NAME="startkit-preview-pr-${{ github.event.number }}"
44-
echo "db-name=$DB_NAME" >> $GITHUB_OUTPUT
45-
46-
# Create preview database and capture the database ID
47-
bunx wrangler d1 create "$DB_NAME" --output json > db-output.json
48-
DB_ID=$(cat db-output.json | jq -r '.result.uuid')
49-
echo "DB_ID=$DB_ID" >> $GITHUB_ENV
50-
51-
# Run migrations on preview database
52-
bunx wrangler d1 migrations apply "$DB_NAME" --remote
53-
env:
54-
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
55-
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
42+
- name: Run code quality checks
43+
run: bun run check
5644

57-
- name: Build application
45+
- name: Build project
5846
run: bun run build
59-
env:
60-
BETTER_AUTH_URL: ${{ vars.BETTER_AUTH_URL || format('https://startkit-preview-pr-{0}.startkit-dev.workers.dev', github.event.number) }}
61-
BETTER_AUTH_SECRET: ${{ secrets.BETTER_AUTH_SECRET }}
62-
GITHUB_CLIENT_ID: ${{ secrets.OAUTH_GITHUB_CLIENT_ID }}
63-
GITHUB_CLIENT_SECRET: ${{ secrets.OAUTH_GITHUB_CLIENT_SECRET }}
64-
65-
- name: Create temporary wrangler config for preview
66-
run: |
67-
cat > wrangler.preview.jsonc << EOF
68-
{
69-
"name": "startkit-preview-pr-${{ github.event.number }}",
70-
"main": "@tanstack/react-start/server-entry",
71-
"compatibility_date": "2025-09-24",
72-
"compatibility_flags": ["nodejs_compat"],
73-
"observability": {
74-
"enabled": true
75-
},
76-
"vars": {
77-
"BETTER_AUTH_URL": "${{ vars.BETTER_AUTH_URL || format('https://startkit-preview-pr-{0}.startkit-dev.workers.dev', github.event.number) }}",
78-
"GITHUB_CLIENT_ID": "${{ secrets.OAUTH_GITHUB_CLIENT_ID }}"
79-
},
80-
"d1_databases": [
81-
{
82-
"binding": "DB",
83-
"database_name": "startkit-preview-pr-${{ github.event.number }}",
84-
"database_id": "${{ env.DB_ID }}"
85-
}
86-
]
87-
}
88-
EOF
89-
90-
- name: Deploy to Cloudflare Workers
91-
id: deploy
92-
uses: cloudflare/wrangler-action@v3
93-
with:
94-
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
95-
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
96-
command: deploy --config wrangler.preview.jsonc
97-
98-
- name: Comment PR
99-
uses: actions/github-script@v7
100-
with:
101-
script: |
102-
github.rest.issues.createComment({
103-
issue_number: context.issue.number,
104-
owner: context.repo.owner,
105-
repo: context.repo.repo,
106-
body: `🚀 **Preview deployment is ready!**
107-
108-
**Preview URL:** ${{ steps.deploy.outputs.deployment-url }}
109-
**Database:** startkit-preview-pr-${{ github.event.number }}
110-
111-
This preview will be automatically deleted when the PR is closed.`
112-
})
113-
114-
# Clean up preview environment when PR is closed
115-
cleanup:
116-
if: github.event_name == 'pull_request' && github.event.action == 'closed'
117-
runs-on: ubuntu-latest
118-
steps:
119-
- name: Delete preview deployment
120-
uses: cloudflare/wrangler-action@v3
121-
continue-on-error: true
122-
with:
123-
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
124-
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
125-
command: delete startkit-preview-pr-${{ github.event.number }} --force
12647

127-
- name: Delete preview database
48+
- name: Run database migrations
12849
uses: cloudflare/wrangler-action@v3
129-
continue-on-error: true
13050
with:
13151
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
13252
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
133-
command: d1 delete startkit-preview-pr-${{ github.event.number }} --force
134-
135-
- name: Comment PR
136-
uses: actions/github-script@v7
137-
with:
138-
script: |
139-
github.rest.issues.createComment({
140-
issue_number: context.issue.number,
141-
owner: context.repo.owner,
142-
repo: context.repo.repo,
143-
body: `🧹 **Preview environment cleaned up**
144-
145-
The preview deployment and database for this PR have been deleted.`
146-
})
147-
148-
# Deploy to production on main branch
149-
production:
150-
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
151-
needs: check
152-
runs-on: ubuntu-latest
153-
environment:
154-
name: production
155-
url: ${{ vars.BETTER_AUTH_URL }}
156-
steps:
157-
- uses: actions/checkout@v4
158-
159-
- name: Setup Bun
160-
uses: oven-sh/setup-bun@v2
161-
with:
162-
bun-version: latest
163-
164-
- name: Install dependencies
165-
run: bun install --frozen-lockfile
53+
command: d1 migrations apply DB --remote
54+
packageManager: bun
16655

167-
- name: Run database migrations
56+
- name: Deploy Worker
16857
uses: cloudflare/wrangler-action@v3
16958
with:
17059
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
17160
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
172-
command: d1 migrations apply DB --remote
173-
174-
- name: Build application
175-
run: bun run build
61+
command: deploy
62+
packageManager: bun
63+
secrets: |
64+
BETTER_AUTH_SECRET
65+
OAUTH_GITHUB_CLIENT_SECRET
17666
env:
17767
BETTER_AUTH_URL: ${{ vars.BETTER_AUTH_URL }}
17868
BETTER_AUTH_SECRET: ${{ secrets.BETTER_AUTH_SECRET }}
179-
GITHUB_CLIENT_ID: ${{ secrets.OAUTH_GITHUB_CLIENT_ID }}
180-
GITHUB_CLIENT_SECRET: ${{ secrets.OAUTH_GITHUB_CLIENT_SECRET }}
69+
OAUTH_GITHUB_CLIENT_ID: ${{ vars.OAUTH_GITHUB_CLIENT_ID }}
70+
OAUTH_GITHUB_CLIENT_SECRET: ${{ secrets.OAUTH_GITHUB_CLIENT_SECRET }}
18171

182-
- name: Deploy to production
183-
uses: cloudflare/wrangler-action@v3
184-
with:
185-
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
186-
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
187-
command: deploy
72+
- name: Summarize deployment
73+
if: success()
74+
run: |
75+
{
76+
echo "### Deployed"
77+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
78+
echo "Triggered manually via workflow_dispatch"
79+
else
80+
echo "Triggered by push to main"
81+
fi
82+
echo "Commit: ${{ github.sha }}"
83+
} >>"$GITHUB_STEP_SUMMARY"

.github/workflows/preview.yml

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
name: Preview Deploy
2+
3+
# Requires repository secrets:
4+
# - CLOUDFLARE_ACCOUNT_ID: Cloudflare account ID for the worker.
5+
# - CLOUDFLARE_API_TOKEN: Token with Workers Scripts Edit permissions.
6+
#
7+
# Requires preview environment variables:
8+
# - OAUTH_GITHUB_CLIENT_ID: GitHub OAuth app client ID
9+
#
10+
# Requires preview environment secrets:
11+
# - BETTER_AUTH_SECRET: Better Auth secret key
12+
# - OAUTH_GITHUB_CLIENT_SECRET: GitHub OAuth app client secret
13+
14+
on:
15+
pull_request:
16+
types: [opened, reopened, synchronize]
17+
18+
permissions:
19+
contents: read
20+
pull-requests: write
21+
22+
jobs:
23+
upload-preview:
24+
name: Upload Worker Preview
25+
runs-on: ubuntu-latest
26+
environment: preview
27+
env:
28+
PR_ALIAS: pr-${{ github.event.number }}
29+
WORKER_NAME: startkit-preview
30+
WORKER_SUBDOMAIN: blendist
31+
steps:
32+
- name: Checkout
33+
uses: actions/checkout@v5
34+
35+
- name: Install dependencies
36+
uses: ./.github/actions/setup
37+
38+
- name: Run code quality checks
39+
run: bun run check
40+
41+
- name: Build project
42+
run: bun run build
43+
env:
44+
CLOUDFLARE_ENV: preview
45+
46+
- name: Run database migrations
47+
uses: cloudflare/wrangler-action@v3
48+
with:
49+
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
50+
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
51+
command: d1 migrations apply DB --remote --env preview
52+
packageManager: bun
53+
54+
- name: Upload preview Worker
55+
id: wrangler
56+
uses: cloudflare/wrangler-action@v3
57+
with:
58+
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
59+
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
60+
command: versions upload --preview-alias ${{ env.PR_ALIAS }}
61+
packageManager: bun
62+
env:
63+
CLOUDFLARE_ENV: preview
64+
BETTER_AUTH_SECRET: ${{ secrets.BETTER_AUTH_SECRET }}
65+
BETTER_AUTH_URL: ${{ format('https://{0}-{1}.{2}.workers.dev', env.PR_ALIAS, env.WORKER_NAME, env.WORKER_SUBDOMAIN) }}
66+
OAUTH_GITHUB_CLIENT_ID: ${{ vars.OAUTH_GITHUB_CLIENT_ID }}
67+
OAUTH_GITHUB_CLIENT_SECRET: ${{ secrets.OAUTH_GITHUB_CLIENT_SECRET }}
68+
69+
- name: Find existing comment
70+
uses: peter-evans/find-comment@v3
71+
id: find-comment
72+
with:
73+
token: ${{ secrets.GITHUB_TOKEN }}
74+
issue-number: ${{ github.event.number }}
75+
comment-author: "github-actions[bot]"
76+
body-includes: "<!-- ${{ env.WORKER_NAME }} -->"
77+
78+
- name: Comment preview link
79+
if: success()
80+
uses: peter-evans/create-or-update-comment@v4
81+
with:
82+
token: ${{ secrets.GITHUB_TOKEN }}
83+
issue-number: ${{ github.event.number }}
84+
comment-id: ${{ steps.find-comment.outputs.comment-id }}
85+
body: |
86+
<!-- ${{ env.WORKER_NAME }} -->
87+
**Preview Deployment**
88+
89+
- Deployment URL: ${{ steps.wrangler.outputs.deployment-url }}
90+
- PR Preview URL: ${{ format('[https://{0}-{1}.{2}.workers.dev](https://{0}-{1}.{2}.workers.dev)', env.PR_ALIAS, env.WORKER_NAME, env.WORKER_SUBDOMAIN) }}
91+
edit-mode: replace

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,6 @@ dist
1818

1919
# Cloudflare
2020
.wrangler
21+
22+
# Local settings
23+
*.local.json

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ bun run typegen # Generate Cloudflare Worker types
138138
**Authentication Setup:**
139139

140140
- Better-Auth with GitHub OAuth provider
141-
- Environment variables: `BETTER_AUTH_SECRET`, `BETTER_AUTH_URL`, `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`
141+
- Environment variables: `BETTER_AUTH_SECRET`, `BETTER_AUTH_URL`, `OAUTH_GITHUB_CLIENT_ID`, `OAUTH_GITHUB_CLIENT_SECRET`
142142
- Auto-generated secret via `dotkit` during setup
143143
- API routes handle auth at `src/routes/api/auth/$.ts`
144144

0 commit comments

Comments
 (0)