Skip to content

Commit 6af10f3

Browse files
committed
Add Github Actions for deployment
1 parent 174f4d4 commit 6af10f3

File tree

4 files changed

+341
-5
lines changed

4 files changed

+341
-5
lines changed

.github/actions/check/action.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: "Run Code Quality Checks"
2+
description: "Install dependencies and run formatting, linting, type checking, and tests"
3+
4+
runs:
5+
using: "composite"
6+
steps:
7+
- name: Setup Bun
8+
uses: oven-sh/setup-bun@v2
9+
with:
10+
bun-version: latest
11+
12+
- name: Install dependencies
13+
shell: bash
14+
run: bun install --frozen-lockfile --prefer-offline
15+
16+
- name: Run checks
17+
shell: bash
18+
run: bun run check
Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Check
1+
name: Code Quality Checks
22

33
on:
44
push:
@@ -13,6 +13,4 @@ jobs:
1313
runs-on: ubuntu-latest
1414
steps:
1515
- uses: actions/checkout@v5
16-
- uses: oven-sh/setup-bun@v2
17-
- run: bun install --frozen-lockfile --prefer-offline
18-
- run: bun run check
16+
- uses: ./.github/actions/check

.github/workflows/deploy.yml

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
name: Deploy to Cloudflare Workers
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened, closed]
6+
push:
7+
branches: [main]
8+
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
17+
18+
# Deploy preview environment on PRs
19+
preview:
20+
if: github.event_name == 'pull_request' && github.event.action != 'closed'
21+
needs: check
22+
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 }}
29+
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+
37+
- name: Install dependencies
38+
run: bun install --frozen-lockfile
39+
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 }}
56+
57+
- name: Build application
58+
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
126+
127+
- name: Delete preview database
128+
uses: cloudflare/wrangler-action@v3
129+
continue-on-error: true
130+
with:
131+
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
132+
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
166+
167+
- name: Run database migrations
168+
uses: cloudflare/wrangler-action@v3
169+
with:
170+
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
171+
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
172+
command: d1 migrations apply DB --remote
173+
174+
- name: Build application
175+
run: bun run build
176+
env:
177+
BETTER_AUTH_URL: ${{ vars.BETTER_AUTH_URL }}
178+
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 }}
181+
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

README.md

Lines changed: 134 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
## Getting Started
2020

21-
To get started, simply clone the repository and run `bun install`:
21+
To get started, simply clone the repository and run `bun run setup`:
2222

2323
1. Clone the project or [use the template](https://github.com/new?template_owner=startkit-dev&template_name=startkit)
2424

@@ -106,6 +106,139 @@ Build for production:
106106
bun run build
107107
```
108108

109+
## Deployment
110+
111+
This project is configured for automatic deployment to [Cloudflare Workers](https://workers.cloudflare.com/) via GitHub Actions.
112+
113+
### GitHub Environments Setup
114+
115+
GitHub Environments provide secure secret management and deployment protection. Create these environments in your repository settings (`Settings > Environments`):
116+
117+
#### 1. **Production Environment**
118+
119+
- **Name:** `production`
120+
- **Deployment branches:** Restrict to `main` branch only
121+
- **Environment variables:**
122+
- `BETTER_AUTH_URL` - Your production domain (e.g., `https://startkit.example.com`)
123+
- `OAUTH_GITHUB_CLIENT_ID` - Github OAuth app ID for production
124+
- **Environment secrets:**
125+
- `BETTER_AUTH_SECRET` - Generate using `openssl rand -base64 32`
126+
- `OAUTH_GITHUB_CLIENT_SECRET` - GitHub OAuth app secret for production
127+
- **Protection rules (recommended):**
128+
- Require reviewers (1+ team members)
129+
- Wait timer (optional, e.g., 5 minutes)
130+
131+
#### 2. **Preview Environment**
132+
133+
- **Name:** `preview`
134+
- **Deployment branches:** No restrictions (allows any branch)
135+
- **Environment variables:**
136+
- `BETTER_AUTH_URL` - Auto-generated preview URL (optional override)
137+
- `OAUTH_GITHUB_CLIENT_ID` - Github OAuth app secret for preview
138+
- **Environment secrets:**
139+
- `BETTER_AUTH_SECRET` - Generate using `openssl rand -base64 32`
140+
- `OAUTH_GITHUB_CLIENT_SECRET` - GitHub OAuth app secret for preview (can reuse production or create separate)
141+
- **Protection rules:** None (allows automatic deployments)
142+
143+
### Required Repository Secrets
144+
145+
Configure these secrets in your repository settings (`Settings > Secrets and variables > Actions > Repository secrets`):
146+
147+
- `CLOUDFLARE_API_TOKEN` - Cloudflare API token with `Cloudflare Workers:Edit` and `Cloudflare D1:Edit` permissions
148+
- `CLOUDFLARE_ACCOUNT_ID` - Your Cloudflare account ID
149+
150+
### Environment-Specific Configuration
151+
152+
**Production:**
153+
154+
- Uses `BETTER_AUTH_URL` from production environment variable
155+
- Uses `BETTER_AUTH_SECRET` and `OAUTH_GITHUB_CLIENT_SECRET` from production environment secrets
156+
- Requires manual approval if protection rules are enabled
157+
- Deploys to your production domain
158+
159+
**Preview:**
160+
161+
- Auto-generates preview URLs: `https://startkit-preview-pr-{number}.{account}.workers.dev` (unless overridden with environment variable)
162+
- Uses `BETTER_AUTH_SECRET` and `OAUTH_GITHUB_CLIENT_SECRET` from preview environment secrets
163+
- No manual approval required
164+
- Automatically cleaned up when PR is closed
165+
166+
### GitHub OAuth App Configuration
167+
168+
**For Production:**
169+
170+
1. Create a GitHub OAuth app with your production URL as the homepage
171+
2. Set authorization callback URL to: `https://your-domain.com/api/auth/callback/github`
172+
3. Add the Client ID as `OAUTH_GITHUB_CLIENT_ID` (repository secret)
173+
4. Add the Client Secret as `OAUTH_GITHUB_CLIENT_SECRET` (production environment secret)
174+
175+
**For Preview (Two Options):**
176+
177+
**Option 1: Shared OAuth App (Simpler)**
178+
179+
- Use the same OAuth app for both production and preview
180+
- Add multiple callback URLs to your OAuth app:
181+
- `https://your-domain.com/api/auth/callback/github` (production)
182+
- `https://startkit-preview-pr-*.{account}.workers.dev/api/auth/callback/github` (preview - add as needed)
183+
- Note: You'll need to manually add preview URLs to your OAuth app settings
184+
185+
**Option 2: Separate OAuth App (Recommended for Security)**
186+
187+
- Create a separate GitHub OAuth app specifically for preview environments
188+
- Set homepage URL to your repository or a placeholder
189+
- Swap the callback URL for preview environments as needed:
190+
- `https://startkit-preview-pr-1.{account}.workers.dev/api/auth/callback/github`
191+
- `https://startkit-preview-pr-2.{account}.workers.dev/api/auth/callback/github`
192+
- (Add more as needed for active PRs)
193+
- Override `OAUTH_GITHUB_CLIENT_ID` and `OAUTH_GITHUB_CLIENT_SECRET` in preview environment
194+
195+
**⚠️ OAuth Callback URL Limitation:**
196+
GitHub OAuth apps don't support wildcard callback URLs, making it unusable in preview URLs for now. We will give instructions for setting up a `proxy`.
197+
198+
### Deployment Workflow
199+
200+
**Pull Requests:**
201+
202+
- Runs code quality checks (`bun run check`)
203+
- Creates a preview deployment with dedicated database
204+
- Posts preview URL in PR comments
205+
- Automatically cleans up preview environment when PR is closed
206+
207+
**Main Branch:**
208+
209+
- Runs code quality checks
210+
- Applies database migrations to production
211+
- Deploys to production Cloudflare Workers
212+
213+
### Initial Cloudflare Setup
214+
215+
1. **Create production database:**
216+
217+
```sh
218+
bunx wrangler d1 create "startkit-db"
219+
```
220+
221+
2. **Update `wrangler.jsonc`** with your database ID from the previous step
222+
223+
3. **Run initial migration:**
224+
```sh
225+
bun run db:migrate:prod
226+
```
227+
228+
### Manual Deployment
229+
230+
For manual deployments:
231+
232+
```sh
233+
# Deploy to production
234+
bun run build
235+
bunx wrangler deploy
236+
237+
# Deploy with database migrations
238+
bun run db:migrate:prod
239+
bunx wrangler deploy
240+
```
241+
109242
## Utilities
110243

111244
```sh

0 commit comments

Comments
 (0)