@odvi/create-dtt-framework 0.1.3 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +16 -13
- package/dist/commands/create.js.map +1 -1
- package/package.json +3 -2
- package/template/.env.example +106 -0
- package/template/components.json +22 -0
- package/template/docs/framework/01-overview.md +289 -0
- package/template/docs/framework/02-techstack.md +503 -0
- package/template/docs/framework/api-layer.md +681 -0
- package/template/docs/framework/clerk-authentication.md +649 -0
- package/template/docs/framework/cli-installation.md +564 -0
- package/template/docs/framework/deployment/ci-cd.md +907 -0
- package/template/docs/framework/deployment/digitalocean.md +991 -0
- package/template/docs/framework/deployment/domain-setup.md +972 -0
- package/template/docs/framework/deployment/environment-variables.md +862 -0
- package/template/docs/framework/deployment/monitoring.md +927 -0
- package/template/docs/framework/deployment/production-checklist.md +649 -0
- package/template/docs/framework/deployment/vercel.md +791 -0
- package/template/docs/framework/environment-variables.md +646 -0
- package/template/docs/framework/health-check-system.md +583 -0
- package/template/docs/framework/implementation.md +559 -0
- package/template/docs/framework/snowflake-integration.md +594 -0
- package/template/docs/framework/state-management.md +615 -0
- package/template/docs/framework/supabase-integration.md +582 -0
- package/template/docs/framework/testing-guide.md +544 -0
- package/template/docs/framework/what-did-i-miss.md +526 -0
- package/template/drizzle.config.ts +11 -0
- package/template/next.config.js +21 -0
- package/template/postcss.config.js +5 -0
- package/template/prettier.config.js +4 -0
- package/template/public/favicon.ico +0 -0
- package/template/src/app/(auth)/layout.tsx +4 -0
- package/template/src/app/(auth)/sign-in/[[...sign-in]]/page.tsx +10 -0
- package/template/src/app/(auth)/sign-up/[[...sign-up]]/page.tsx +10 -0
- package/template/src/app/(dashboard)/dashboard/page.tsx +8 -0
- package/template/src/app/(dashboard)/health/page.tsx +16 -0
- package/template/src/app/(dashboard)/layout.tsx +17 -0
- package/template/src/app/api/[[...route]]/route.ts +11 -0
- package/template/src/app/api/debug-files/route.ts +33 -0
- package/template/src/app/api/webhooks/clerk/route.ts +112 -0
- package/template/src/app/layout.tsx +28 -0
- package/template/src/app/page.tsx +12 -0
- package/template/src/app/providers.tsx +20 -0
- package/template/src/components/layouts/navbar.tsx +14 -0
- package/template/src/components/shared/loading-spinner.tsx +6 -0
- package/template/src/components/ui/badge.tsx +46 -0
- package/template/src/components/ui/button.tsx +62 -0
- package/template/src/components/ui/card.tsx +92 -0
- package/template/src/components/ui/collapsible.tsx +33 -0
- package/template/src/components/ui/scroll-area.tsx +58 -0
- package/template/src/components/ui/sheet.tsx +139 -0
- package/template/src/config/__tests__/env.test.ts +164 -0
- package/template/src/config/__tests__/site.test.ts +46 -0
- package/template/src/config/env.ts +36 -0
- package/template/src/config/site.ts +10 -0
- package/template/src/env.js +44 -0
- package/template/src/features/__tests__/health-check-config.test.ts +142 -0
- package/template/src/features/__tests__/health-check-types.test.ts +201 -0
- package/template/src/features/documentation/components/doc-sidebar.tsx +109 -0
- package/template/src/features/documentation/components/doc-viewer.tsx +70 -0
- package/template/src/features/documentation/index.tsx +92 -0
- package/template/src/features/documentation/utils/doc-loader.ts +177 -0
- package/template/src/features/health-check/components/health-dashboard.tsx +374 -0
- package/template/src/features/health-check/config.ts +71 -0
- package/template/src/features/health-check/index.ts +4 -0
- package/template/src/features/health-check/stores/health-store.ts +14 -0
- package/template/src/features/health-check/types.ts +18 -0
- package/template/src/hooks/__tests__/use-debounce.test.tsx +28 -0
- package/template/src/hooks/queries/use-health-checks.ts +16 -0
- package/template/src/hooks/utils/use-debounce.ts +20 -0
- package/template/src/lib/__tests__/utils.test.ts +52 -0
- package/template/src/lib/__tests__/validators.test.ts +114 -0
- package/template/src/lib/nextbank/client.ts +67 -0
- package/template/src/lib/snowflake/client.ts +102 -0
- package/template/src/lib/supabase/admin.ts +7 -0
- package/template/src/lib/supabase/client.ts +7 -0
- package/template/src/lib/supabase/server.ts +23 -0
- package/template/src/lib/utils.ts +6 -0
- package/template/src/lib/validators.ts +9 -0
- package/template/src/middleware.ts +22 -0
- package/template/src/server/api/index.ts +22 -0
- package/template/src/server/api/middleware/auth.ts +19 -0
- package/template/src/server/api/middleware/logger.ts +4 -0
- package/template/src/server/api/routes/health/clerk.ts +214 -0
- package/template/src/server/api/routes/health/database.ts +141 -0
- package/template/src/server/api/routes/health/edge-functions.ts +107 -0
- package/template/src/server/api/routes/health/framework.ts +48 -0
- package/template/src/server/api/routes/health/index.ts +102 -0
- package/template/src/server/api/routes/health/nextbank.ts +46 -0
- package/template/src/server/api/routes/health/snowflake.ts +83 -0
- package/template/src/server/api/routes/health/storage.ts +177 -0
- package/template/src/server/api/routes/users.ts +79 -0
- package/template/src/server/db/index.ts +17 -0
- package/template/src/server/db/queries/users.ts +8 -0
- package/template/src/server/db/schema/__tests__/health-checks.test.ts +31 -0
- package/template/src/server/db/schema/__tests__/users.test.ts +46 -0
- package/template/src/server/db/schema/health-checks.ts +11 -0
- package/template/src/server/db/schema/index.ts +2 -0
- package/template/src/server/db/schema/users.ts +16 -0
- package/template/src/server/db/schema.ts +1 -0
- package/template/src/stores/__tests__/ui-store.test.ts +87 -0
- package/template/src/stores/ui-store.ts +14 -0
- package/template/src/styles/globals.css +129 -0
- package/template/src/test/mocks/clerk.ts +35 -0
- package/template/src/test/mocks/snowflake.ts +28 -0
- package/template/src/test/mocks/supabase.ts +37 -0
- package/template/src/test/setup.ts +69 -0
- package/template/src/test/utils/test-helpers.ts +158 -0
- package/template/src/types/index.ts +14 -0
- package/template/tsconfig.json +43 -0
- package/template/vitest.config.ts +44 -0
|
@@ -0,0 +1,907 @@
|
|
|
1
|
+
# DTT Framework - CI/CD Setup Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This guide provides comprehensive instructions for setting up Continuous Integration and Continuous Deployment (CI/CD) for the DTT Framework using GitHub Actions. It covers automated testing, deployment, preview deployments, and branch protection rules.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
1. [GitHub Actions Setup](#github-actions-setup)
|
|
12
|
+
2. [Automated Testing](#automated-testing)
|
|
13
|
+
3. [Automated Deployment](#automated-deployment)
|
|
14
|
+
4. [Preview Deployments](#preview-deployments)
|
|
15
|
+
5. [Branch Protection Rules](#branch-protection-rules)
|
|
16
|
+
6. [Advanced CI/CD Patterns](#advanced-cicd-patterns)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## GitHub Actions Setup
|
|
21
|
+
|
|
22
|
+
### Prerequisites
|
|
23
|
+
|
|
24
|
+
Before setting up CI/CD, ensure you have:
|
|
25
|
+
|
|
26
|
+
- **GitHub Repository**: Your code should be hosted on GitHub
|
|
27
|
+
- **Vercel Account**: For Vercel deployments
|
|
28
|
+
- **Vercel Token**: For authentication
|
|
29
|
+
- **Environment Variables**: Configured in GitHub Secrets
|
|
30
|
+
|
|
31
|
+
### Step 1: Create GitHub Workflows Directory
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Create workflows directory
|
|
35
|
+
mkdir -p .github/workflows
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Step 2: Get Vercel Credentials
|
|
39
|
+
|
|
40
|
+
#### Get Vercel Token
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Install Vercel CLI
|
|
44
|
+
pnpm add -g vercel
|
|
45
|
+
|
|
46
|
+
# Login to Vercel
|
|
47
|
+
vercel login
|
|
48
|
+
|
|
49
|
+
# Get your token
|
|
50
|
+
vercel token create
|
|
51
|
+
# Copy the token and save it
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
#### Get Project IDs
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Link your project
|
|
58
|
+
vercel link
|
|
59
|
+
|
|
60
|
+
# Get project ID
|
|
61
|
+
cat .vercel/project.json
|
|
62
|
+
# Copy the "projectId" and "orgId"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Step 3: Configure GitHub Secrets
|
|
66
|
+
|
|
67
|
+
1. Go to **Repository** → **Settings** → **Secrets and variables** → **Actions**
|
|
68
|
+
2. Add the following secrets:
|
|
69
|
+
|
|
70
|
+
| Secret Name | Description | Example |
|
|
71
|
+
|-------------|-------------|---------|
|
|
72
|
+
| `VERCEL_TOKEN` | Vercel authentication token | `xxx` |
|
|
73
|
+
| `VERCEL_ORG_ID` | Vercel organization ID | `team_xxx` |
|
|
74
|
+
| `VERCEL_PROJECT_ID` | Vercel project ID | `prj_xxx` |
|
|
75
|
+
| `DATABASE_URL` | Database connection string | `postgresql://...` |
|
|
76
|
+
| `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` | Clerk publishable key | `pk_live_xxx` |
|
|
77
|
+
| `CLERK_SECRET_KEY` | Clerk secret key | `sk_live_xxx` |
|
|
78
|
+
| `CLERK_WEBHOOK_SECRET` | Clerk webhook secret | `whsec_xxx` |
|
|
79
|
+
| `NEXT_PUBLIC_SUPABASE_URL` | Supabase URL | `https://xxx.supabase.co` |
|
|
80
|
+
| `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Supabase anon key | `eyJxxx` |
|
|
81
|
+
| `SUPABASE_SERVICE_ROLE_KEY` | Supabase service role key | `eyJxxx` |
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Automated Testing
|
|
86
|
+
|
|
87
|
+
### Step 1: Create Test Workflow
|
|
88
|
+
|
|
89
|
+
Create `.github/workflows/test.yml`:
|
|
90
|
+
|
|
91
|
+
```yaml
|
|
92
|
+
name: Test
|
|
93
|
+
|
|
94
|
+
on:
|
|
95
|
+
push:
|
|
96
|
+
branches: [main, develop]
|
|
97
|
+
pull_request:
|
|
98
|
+
branches: [main, develop]
|
|
99
|
+
|
|
100
|
+
jobs:
|
|
101
|
+
test:
|
|
102
|
+
runs-on: ubuntu-latest
|
|
103
|
+
|
|
104
|
+
steps:
|
|
105
|
+
- name: Checkout code
|
|
106
|
+
uses: actions/checkout@v4
|
|
107
|
+
|
|
108
|
+
- name: Setup Node.js
|
|
109
|
+
uses: actions/setup-node@v4
|
|
110
|
+
with:
|
|
111
|
+
node-version: '20'
|
|
112
|
+
cache: 'pnpm'
|
|
113
|
+
|
|
114
|
+
- name: Install pnpm
|
|
115
|
+
uses: pnpm/action-setup@v2
|
|
116
|
+
with:
|
|
117
|
+
version: 10
|
|
118
|
+
|
|
119
|
+
- name: Install dependencies
|
|
120
|
+
run: pnpm install --frozen-lockfile
|
|
121
|
+
|
|
122
|
+
- name: Run linting
|
|
123
|
+
run: pnpm lint
|
|
124
|
+
|
|
125
|
+
- name: Run type checking
|
|
126
|
+
run: pnpm type-check
|
|
127
|
+
|
|
128
|
+
- name: Run unit tests
|
|
129
|
+
run: pnpm test:unit
|
|
130
|
+
|
|
131
|
+
- name: Run integration tests
|
|
132
|
+
run: pnpm test:integration
|
|
133
|
+
env:
|
|
134
|
+
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
135
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }}
|
|
136
|
+
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
|
|
137
|
+
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
|
|
138
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
|
|
139
|
+
SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}
|
|
140
|
+
|
|
141
|
+
- name: Upload coverage reports
|
|
142
|
+
uses: codecov/codecov-action@v4
|
|
143
|
+
with:
|
|
144
|
+
file: ./coverage/lcov.info
|
|
145
|
+
flags: unittests
|
|
146
|
+
name: codecov-umbrella
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Step 2: Configure Test Scripts
|
|
150
|
+
|
|
151
|
+
Add test scripts to `package.json`:
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"scripts": {
|
|
156
|
+
"lint": "eslint . --ext .ts,.tsx",
|
|
157
|
+
"type-check": "tsc --noEmit",
|
|
158
|
+
"test": "vitest",
|
|
159
|
+
"test:unit": "vitest run --coverage",
|
|
160
|
+
"test:integration": "vitest run --config vitest.integration.config.ts",
|
|
161
|
+
"test:watch": "vitest"
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Step 3: Test Workflow Features
|
|
167
|
+
|
|
168
|
+
| Feature | Description |
|
|
169
|
+
|---------|-------------|
|
|
170
|
+
| **Triggered on push** | Runs on every push to main/develop |
|
|
171
|
+
| **Triggered on PR** | Runs on every pull request |
|
|
172
|
+
| **Linting** | Checks code style |
|
|
173
|
+
| **Type checking** | Verifies TypeScript types |
|
|
174
|
+
| **Unit tests** | Runs unit tests |
|
|
175
|
+
| **Integration tests** | Runs integration tests |
|
|
176
|
+
| **Coverage upload** | Uploads coverage to Codecov |
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Automated Deployment
|
|
181
|
+
|
|
182
|
+
### Step 1: Create Production Deployment Workflow
|
|
183
|
+
|
|
184
|
+
Create `.github/workflows/deploy-production.yml`:
|
|
185
|
+
|
|
186
|
+
```yaml
|
|
187
|
+
name: Deploy to Production
|
|
188
|
+
|
|
189
|
+
on:
|
|
190
|
+
push:
|
|
191
|
+
branches: [main]
|
|
192
|
+
workflow_dispatch:
|
|
193
|
+
|
|
194
|
+
jobs:
|
|
195
|
+
deploy:
|
|
196
|
+
runs-on: ubuntu-latest
|
|
197
|
+
|
|
198
|
+
steps:
|
|
199
|
+
- name: Checkout code
|
|
200
|
+
uses: actions/checkout@v4
|
|
201
|
+
|
|
202
|
+
- name: Setup Node.js
|
|
203
|
+
uses: actions/setup-node@v4
|
|
204
|
+
with:
|
|
205
|
+
node-version: '20'
|
|
206
|
+
cache: 'pnpm'
|
|
207
|
+
|
|
208
|
+
- name: Install pnpm
|
|
209
|
+
uses: pnpm/action-setup@v2
|
|
210
|
+
with:
|
|
211
|
+
version: 10
|
|
212
|
+
|
|
213
|
+
- name: Install dependencies
|
|
214
|
+
run: pnpm install --frozen-lockfile
|
|
215
|
+
|
|
216
|
+
- name: Run tests
|
|
217
|
+
run: pnpm test
|
|
218
|
+
env:
|
|
219
|
+
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
220
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }}
|
|
221
|
+
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
|
|
222
|
+
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
|
|
223
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
|
|
224
|
+
SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}
|
|
225
|
+
|
|
226
|
+
- name: Build application
|
|
227
|
+
run: pnpm build
|
|
228
|
+
env:
|
|
229
|
+
NEXT_PUBLIC_APP_URL: ${{ secrets.NEXT_PUBLIC_APP_URL }}
|
|
230
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }}
|
|
231
|
+
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
|
|
232
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
|
|
233
|
+
|
|
234
|
+
- name: Deploy to Vercel Production
|
|
235
|
+
uses: amondnet/vercel-action@v25
|
|
236
|
+
with:
|
|
237
|
+
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
|
238
|
+
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
|
|
239
|
+
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
|
|
240
|
+
vercel-args: '--prod'
|
|
241
|
+
working-directory: ./
|
|
242
|
+
|
|
243
|
+
- name: Run database migrations
|
|
244
|
+
run: pnpm db:push
|
|
245
|
+
env:
|
|
246
|
+
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
247
|
+
|
|
248
|
+
- name: Notify deployment status
|
|
249
|
+
if: always()
|
|
250
|
+
uses: 8398a7/action-slack@v3
|
|
251
|
+
with:
|
|
252
|
+
status: ${{ job.status }}
|
|
253
|
+
text: 'Production deployment ${{ job.status }}'
|
|
254
|
+
webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Step 2: Create Staging Deployment Workflow
|
|
258
|
+
|
|
259
|
+
Create `.github/workflows/deploy-staging.yml`:
|
|
260
|
+
|
|
261
|
+
```yaml
|
|
262
|
+
name: Deploy to Staging
|
|
263
|
+
|
|
264
|
+
on:
|
|
265
|
+
push:
|
|
266
|
+
branches: [develop]
|
|
267
|
+
workflow_dispatch:
|
|
268
|
+
|
|
269
|
+
jobs:
|
|
270
|
+
deploy:
|
|
271
|
+
runs-on: ubuntu-latest
|
|
272
|
+
|
|
273
|
+
steps:
|
|
274
|
+
- name: Checkout code
|
|
275
|
+
uses: actions/checkout@v4
|
|
276
|
+
|
|
277
|
+
- name: Setup Node.js
|
|
278
|
+
uses: actions/setup-node@v4
|
|
279
|
+
with:
|
|
280
|
+
node-version: '20'
|
|
281
|
+
cache: 'pnpm'
|
|
282
|
+
|
|
283
|
+
- name: Install pnpm
|
|
284
|
+
uses: pnpm/action-setup@v2
|
|
285
|
+
with:
|
|
286
|
+
version: 10
|
|
287
|
+
|
|
288
|
+
- name: Install dependencies
|
|
289
|
+
run: pnpm install --frozen-lockfile
|
|
290
|
+
|
|
291
|
+
- name: Run tests
|
|
292
|
+
run: pnpm test
|
|
293
|
+
env:
|
|
294
|
+
DATABASE_URL: ${{ secrets.STAGING_DATABASE_URL }}
|
|
295
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.STAGING_CLERK_PUBLISHABLE_KEY }}
|
|
296
|
+
CLERK_SECRET_KEY: ${{ secrets.STAGING_CLERK_SECRET_KEY }}
|
|
297
|
+
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.STAGING_SUPABASE_URL }}
|
|
298
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.STAGING_SUPABASE_ANON_KEY }}
|
|
299
|
+
SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.STAGING_SUPABASE_SERVICE_ROLE_KEY }}
|
|
300
|
+
|
|
301
|
+
- name: Build application
|
|
302
|
+
run: pnpm build
|
|
303
|
+
env:
|
|
304
|
+
NEXT_PUBLIC_APP_URL: ${{ secrets.STAGING_APP_URL }}
|
|
305
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.STAGING_CLERK_PUBLISHABLE_KEY }}
|
|
306
|
+
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.STAGING_SUPABASE_URL }}
|
|
307
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.STAGING_SUPABASE_ANON_KEY }}
|
|
308
|
+
|
|
309
|
+
- name: Deploy to Vercel Staging
|
|
310
|
+
uses: amondnet/vercel-action@v25
|
|
311
|
+
with:
|
|
312
|
+
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
|
313
|
+
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
|
|
314
|
+
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
|
|
315
|
+
vercel-args: '--scope=your-team'
|
|
316
|
+
working-directory: ./
|
|
317
|
+
|
|
318
|
+
- name: Run database migrations
|
|
319
|
+
run: pnpm db:push
|
|
320
|
+
env:
|
|
321
|
+
DATABASE_URL: ${{ secrets.STAGING_DATABASE_URL }}
|
|
322
|
+
|
|
323
|
+
- name: Run smoke tests
|
|
324
|
+
run: pnpm test:smoke
|
|
325
|
+
env:
|
|
326
|
+
STAGING_URL: ${{ secrets.STAGING_APP_URL }}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Step 3: Deployment Workflow Features
|
|
330
|
+
|
|
331
|
+
| Feature | Production | Staging |
|
|
332
|
+
|---------|------------|---------|
|
|
333
|
+
| **Trigger** | Push to main | Push to develop |
|
|
334
|
+
| **Manual trigger** | Yes | Yes |
|
|
335
|
+
| **Run tests** | Yes | Yes |
|
|
336
|
+
| **Build** | Yes | Yes |
|
|
337
|
+
| **Deploy** | Vercel --prod | Vercel preview |
|
|
338
|
+
| **Migrations** | Yes | Yes |
|
|
339
|
+
| **Smoke tests** | Optional | Yes |
|
|
340
|
+
| **Notifications** | Yes | Optional |
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## Preview Deployments
|
|
345
|
+
|
|
346
|
+
### Step 1: Create Preview Deployment Workflow
|
|
347
|
+
|
|
348
|
+
Create `.github/workflows/deploy-preview.yml`:
|
|
349
|
+
|
|
350
|
+
```yaml
|
|
351
|
+
name: Deploy Preview
|
|
352
|
+
|
|
353
|
+
on:
|
|
354
|
+
pull_request:
|
|
355
|
+
types: [opened, synchronize, reopened]
|
|
356
|
+
|
|
357
|
+
jobs:
|
|
358
|
+
deploy-preview:
|
|
359
|
+
runs-on: ubuntu-latest
|
|
360
|
+
|
|
361
|
+
steps:
|
|
362
|
+
- name: Checkout code
|
|
363
|
+
uses: actions/checkout@v4
|
|
364
|
+
|
|
365
|
+
- name: Setup Node.js
|
|
366
|
+
uses: actions/setup-node@v4
|
|
367
|
+
with:
|
|
368
|
+
node-version: '20'
|
|
369
|
+
cache: 'pnpm'
|
|
370
|
+
|
|
371
|
+
- name: Install pnpm
|
|
372
|
+
uses: pnpm/action-setup@v2
|
|
373
|
+
with:
|
|
374
|
+
version: 10
|
|
375
|
+
|
|
376
|
+
- name: Install dependencies
|
|
377
|
+
run: pnpm install --frozen-lockfile
|
|
378
|
+
|
|
379
|
+
- name: Run tests
|
|
380
|
+
run: pnpm test
|
|
381
|
+
env:
|
|
382
|
+
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
|
383
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }}
|
|
384
|
+
CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }}
|
|
385
|
+
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
|
|
386
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
|
|
387
|
+
SUPABASE_SERVICE_ROLE_KEY: ${{ secrets.SUPABASE_SERVICE_ROLE_KEY }}
|
|
388
|
+
|
|
389
|
+
- name: Build application
|
|
390
|
+
run: pnpm build
|
|
391
|
+
env:
|
|
392
|
+
NEXT_PUBLIC_APP_URL: https://preview-${{ github.event.number }}.your-app.com
|
|
393
|
+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }}
|
|
394
|
+
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
|
|
395
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
|
|
396
|
+
|
|
397
|
+
- name: Deploy to Vercel Preview
|
|
398
|
+
id: vercel
|
|
399
|
+
uses: amondnet/vercel-action@v25
|
|
400
|
+
with:
|
|
401
|
+
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
|
402
|
+
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
|
|
403
|
+
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
|
|
404
|
+
vercel-args: '--scope=your-team'
|
|
405
|
+
working-directory: ./
|
|
406
|
+
|
|
407
|
+
- name: Comment PR with preview URL
|
|
408
|
+
uses: actions/github-script@v7
|
|
409
|
+
with:
|
|
410
|
+
script: |
|
|
411
|
+
github.rest.issues.createComment({
|
|
412
|
+
issue_number: context.issue.number,
|
|
413
|
+
owner: context.repo.owner,
|
|
414
|
+
repo: context.repo.repo,
|
|
415
|
+
body: `🚀 Preview deployment ready!\n\nURL: ${{ steps.vercel.outputs.preview-url }}`
|
|
416
|
+
})
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### Step 2: Configure Preview Deployments in Vercel
|
|
420
|
+
|
|
421
|
+
1. Go to **Settings** → **Git**
|
|
422
|
+
2. Enable **"Preview Deployments"**
|
|
423
|
+
3. Configure preview branch settings:
|
|
424
|
+
- **Branch**: `*` (all branches)
|
|
425
|
+
- **Environment**: Preview
|
|
426
|
+
- **Automatic**: Yes
|
|
427
|
+
|
|
428
|
+
### Step 3: Preview Deployment Features
|
|
429
|
+
|
|
430
|
+
| Feature | Description |
|
|
431
|
+
|---------|-------------|
|
|
432
|
+
| **Auto-created** | Created for every PR |
|
|
433
|
+
| **Unique URL** | Each PR gets unique URL |
|
|
434
|
+
| **Auto-comment** | URL posted to PR |
|
|
435
|
+
| **Auto-deleted** | Deleted when PR closes |
|
|
436
|
+
| **Environment** | Uses preview environment variables |
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
## Branch Protection Rules
|
|
441
|
+
|
|
442
|
+
### Step 1: Configure Branch Protection
|
|
443
|
+
|
|
444
|
+
1. Go to **Repository** → **Settings** → **Branches**
|
|
445
|
+
2. Click **"Add rule"**
|
|
446
|
+
3. Enter branch name pattern: `main`
|
|
447
|
+
4. Configure protection rules:
|
|
448
|
+
|
|
449
|
+
### Required Branch Protection Settings
|
|
450
|
+
|
|
451
|
+
| Setting | Value | Description |
|
|
452
|
+
|---------|-------|-------------|
|
|
453
|
+
| **Require pull request** | ✅ Yes | Require PR before merging |
|
|
454
|
+
| **Require approvals** | ✅ Yes | Minimum 1 approval |
|
|
455
|
+
| **Dismiss stale approvals** | ✅ Yes | Re-approve on new commits |
|
|
456
|
+
| **Require status checks** | ✅ Yes | Require CI to pass |
|
|
457
|
+
| **Require branches to be up to date** | ✅ Yes | Must be up to date with main |
|
|
458
|
+
| **Do not allow bypassing** | ✅ Yes | Enforce rules for all users |
|
|
459
|
+
| **Require signed commits** | Optional | Require GPG signatures |
|
|
460
|
+
| **Include administrators** | ✅ Yes | Apply rules to admins |
|
|
461
|
+
| **Allow force pushes** | ❌ No | Prevent force pushes |
|
|
462
|
+
| **Allow deletions** | ❌ No | Prevent branch deletion |
|
|
463
|
+
|
|
464
|
+
### Step 2: Configure Required Status Checks
|
|
465
|
+
|
|
466
|
+
Add the following required checks:
|
|
467
|
+
|
|
468
|
+
| Check Name | Description |
|
|
469
|
+
|-------------|-------------|
|
|
470
|
+
| `Test` | Unit and integration tests |
|
|
471
|
+
| `Lint` | Code linting |
|
|
472
|
+
| `Type Check` | TypeScript type checking |
|
|
473
|
+
| `Build` | Application build |
|
|
474
|
+
|
|
475
|
+
### Step 3: Configure Branch Protection via API
|
|
476
|
+
|
|
477
|
+
Use GitHub CLI to configure branch protection:
|
|
478
|
+
|
|
479
|
+
```bash
|
|
480
|
+
# Install GitHub CLI
|
|
481
|
+
# https://cli.github.com/
|
|
482
|
+
|
|
483
|
+
# Authenticate
|
|
484
|
+
gh auth login
|
|
485
|
+
|
|
486
|
+
# Configure branch protection
|
|
487
|
+
gh api repos/:owner/:repo/branches/main/protection \
|
|
488
|
+
--method PUT \
|
|
489
|
+
-H "Accept: application/vnd.github+json" \
|
|
490
|
+
-f required_status_checks='{
|
|
491
|
+
"strict": true,
|
|
492
|
+
"contexts": ["Test", "Lint", "Type Check", "Build"]
|
|
493
|
+
}' \
|
|
494
|
+
-f enforce_admins=true \
|
|
495
|
+
-f required_pull_request_reviews='{
|
|
496
|
+
"required_approving_review_count": 1,
|
|
497
|
+
"dismiss_stale_reviews": true,
|
|
498
|
+
"require_code_owner_reviews": false
|
|
499
|
+
}' \
|
|
500
|
+
-f restrictions=null \
|
|
501
|
+
-f allow_force_pushes=false \
|
|
502
|
+
-f allow_deletions=false
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Step 4: Branch Protection Best Practices
|
|
506
|
+
|
|
507
|
+
| Practice | Description |
|
|
508
|
+
|-----------|-------------|
|
|
509
|
+
| **Require PRs** | All changes go through PRs |
|
|
510
|
+
| **Require approvals** | At least one review required |
|
|
511
|
+
| **Require CI** | All checks must pass |
|
|
512
|
+
| **Keep up to date** | PRs must be up to date |
|
|
513
|
+
| **No force pushes** | Prevent history rewrites |
|
|
514
|
+
| **No deletions** | Prevent accidental deletion |
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
## Advanced CI/CD Patterns
|
|
519
|
+
|
|
520
|
+
### Pattern 1: Monorepo Support
|
|
521
|
+
|
|
522
|
+
For monorepo setups using Turborepo:
|
|
523
|
+
|
|
524
|
+
```yaml
|
|
525
|
+
name: Monorepo CI
|
|
526
|
+
|
|
527
|
+
on:
|
|
528
|
+
push:
|
|
529
|
+
branches: [main]
|
|
530
|
+
pull_request:
|
|
531
|
+
|
|
532
|
+
jobs:
|
|
533
|
+
ci:
|
|
534
|
+
runs-on: ubuntu-latest
|
|
535
|
+
steps:
|
|
536
|
+
- uses: actions/checkout@v4
|
|
537
|
+
|
|
538
|
+
- name: Setup Node.js
|
|
539
|
+
uses: actions/setup-node@v4
|
|
540
|
+
with:
|
|
541
|
+
node-version: '20'
|
|
542
|
+
|
|
543
|
+
- name: Install pnpm
|
|
544
|
+
uses: pnpm/action-setup@v2
|
|
545
|
+
with:
|
|
546
|
+
version: 10
|
|
547
|
+
|
|
548
|
+
- name: Install Turborepo
|
|
549
|
+
run: pnpm add -g turbo
|
|
550
|
+
|
|
551
|
+
- name: Install dependencies
|
|
552
|
+
run: pnpm install
|
|
553
|
+
|
|
554
|
+
- name: Run affected tests
|
|
555
|
+
run: turbo test --filter=[HEAD~1]
|
|
556
|
+
|
|
557
|
+
- name: Run affected builds
|
|
558
|
+
run: turbo build --filter=[HEAD~1]
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### Pattern 2: Multi-Environment Deployment
|
|
562
|
+
|
|
563
|
+
Deploy to multiple environments:
|
|
564
|
+
|
|
565
|
+
```yaml
|
|
566
|
+
name: Multi-Environment Deploy
|
|
567
|
+
|
|
568
|
+
on:
|
|
569
|
+
push:
|
|
570
|
+
branches: [main, develop, staging]
|
|
571
|
+
|
|
572
|
+
jobs:
|
|
573
|
+
deploy:
|
|
574
|
+
runs-on: ubuntu-latest
|
|
575
|
+
steps:
|
|
576
|
+
- uses: actions/checkout@v4
|
|
577
|
+
|
|
578
|
+
- name: Setup Node.js
|
|
579
|
+
uses: actions/setup-node@v4
|
|
580
|
+
with:
|
|
581
|
+
node-version: '20'
|
|
582
|
+
|
|
583
|
+
- name: Install pnpm
|
|
584
|
+
uses: pnpm/action-setup@v2
|
|
585
|
+
with:
|
|
586
|
+
version: 10
|
|
587
|
+
|
|
588
|
+
- name: Install dependencies
|
|
589
|
+
run: pnpm install
|
|
590
|
+
|
|
591
|
+
- name: Build
|
|
592
|
+
run: pnpm build
|
|
593
|
+
|
|
594
|
+
- name: Deploy to Production
|
|
595
|
+
if: github.ref == 'refs/heads/main'
|
|
596
|
+
uses: amondnet/vercel-action@v25
|
|
597
|
+
with:
|
|
598
|
+
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
|
599
|
+
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
|
|
600
|
+
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
|
|
601
|
+
vercel-args: '--prod'
|
|
602
|
+
|
|
603
|
+
- name: Deploy to Staging
|
|
604
|
+
if: github.ref == 'refs/heads/staging'
|
|
605
|
+
uses: amondnet/vercel-action@v25
|
|
606
|
+
with:
|
|
607
|
+
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
|
608
|
+
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
|
|
609
|
+
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
|
|
610
|
+
|
|
611
|
+
- name: Deploy to Development
|
|
612
|
+
if: github.ref == 'refs/heads/develop'
|
|
613
|
+
uses: amondnet/vercel-action@v25
|
|
614
|
+
with:
|
|
615
|
+
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
|
616
|
+
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
|
|
617
|
+
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
### Pattern 3: Database Migration Workflow
|
|
621
|
+
|
|
622
|
+
Separate workflow for database migrations:
|
|
623
|
+
|
|
624
|
+
```yaml
|
|
625
|
+
name: Database Migrations
|
|
626
|
+
|
|
627
|
+
on:
|
|
628
|
+
workflow_dispatch:
|
|
629
|
+
inputs:
|
|
630
|
+
environment:
|
|
631
|
+
description: 'Environment to migrate'
|
|
632
|
+
required: true
|
|
633
|
+
default: 'production'
|
|
634
|
+
type: choice
|
|
635
|
+
options:
|
|
636
|
+
- production
|
|
637
|
+
- staging
|
|
638
|
+
- development
|
|
639
|
+
|
|
640
|
+
jobs:
|
|
641
|
+
migrate:
|
|
642
|
+
runs-on: ubuntu-latest
|
|
643
|
+
steps:
|
|
644
|
+
- uses: actions/checkout@v4
|
|
645
|
+
|
|
646
|
+
- name: Setup Node.js
|
|
647
|
+
uses: actions/setup-node@v4
|
|
648
|
+
with:
|
|
649
|
+
node-version: '20'
|
|
650
|
+
|
|
651
|
+
- name: Install pnpm
|
|
652
|
+
uses: pnpm/action-setup@v2
|
|
653
|
+
with:
|
|
654
|
+
version: 10
|
|
655
|
+
|
|
656
|
+
- name: Install dependencies
|
|
657
|
+
run: pnpm install
|
|
658
|
+
|
|
659
|
+
- name: Run migrations
|
|
660
|
+
run: pnpm db:push
|
|
661
|
+
env:
|
|
662
|
+
DATABASE_URL: ${{ secrets[format('{0}_DATABASE_URL', github.event.inputs.environment)] }}
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
### Pattern 4: Rollback Workflow
|
|
666
|
+
|
|
667
|
+
Automated rollback workflow:
|
|
668
|
+
|
|
669
|
+
```yaml
|
|
670
|
+
name: Rollback Deployment
|
|
671
|
+
|
|
672
|
+
on:
|
|
673
|
+
workflow_dispatch:
|
|
674
|
+
inputs:
|
|
675
|
+
commit_sha:
|
|
676
|
+
description: 'Commit SHA to rollback to'
|
|
677
|
+
required: true
|
|
678
|
+
environment:
|
|
679
|
+
description: 'Environment to rollback'
|
|
680
|
+
required: true
|
|
681
|
+
default: 'production'
|
|
682
|
+
type: choice
|
|
683
|
+
options:
|
|
684
|
+
- production
|
|
685
|
+
- staging
|
|
686
|
+
|
|
687
|
+
jobs:
|
|
688
|
+
rollback:
|
|
689
|
+
runs-on: ubuntu-latest
|
|
690
|
+
steps:
|
|
691
|
+
- uses: actions/checkout@v4
|
|
692
|
+
with:
|
|
693
|
+
ref: ${{ github.event.inputs.commit_sha }}
|
|
694
|
+
|
|
695
|
+
- name: Setup Node.js
|
|
696
|
+
uses: actions/setup-node@v4
|
|
697
|
+
with:
|
|
698
|
+
node-version: '20'
|
|
699
|
+
|
|
700
|
+
- name: Install pnpm
|
|
701
|
+
uses: pnpm/action-setup@v2
|
|
702
|
+
with:
|
|
703
|
+
version: 10
|
|
704
|
+
|
|
705
|
+
- name: Install dependencies
|
|
706
|
+
run: pnpm install
|
|
707
|
+
|
|
708
|
+
- name: Build
|
|
709
|
+
run: pnpm build
|
|
710
|
+
|
|
711
|
+
- name: Deploy rollback
|
|
712
|
+
uses: amondnet/vercel-action@v25
|
|
713
|
+
with:
|
|
714
|
+
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
|
715
|
+
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
|
|
716
|
+
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
|
|
717
|
+
vercel-args: '--prod'
|
|
718
|
+
|
|
719
|
+
- name: Notify rollback
|
|
720
|
+
uses: 8398a7/action-slack@v3
|
|
721
|
+
with:
|
|
722
|
+
status: 'success'
|
|
723
|
+
text: 'Rollback to ${{ github.event.inputs.commit_sha }} completed'
|
|
724
|
+
webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
### Pattern 5: Scheduled Maintenance Workflow
|
|
728
|
+
|
|
729
|
+
Scheduled health checks and maintenance:
|
|
730
|
+
|
|
731
|
+
```yaml
|
|
732
|
+
name: Scheduled Maintenance
|
|
733
|
+
|
|
734
|
+
on:
|
|
735
|
+
schedule:
|
|
736
|
+
- cron: '0 2 * * *' # Daily at 2 AM UTC
|
|
737
|
+
workflow_dispatch:
|
|
738
|
+
|
|
739
|
+
jobs:
|
|
740
|
+
health-check:
|
|
741
|
+
runs-on: ubuntu-latest
|
|
742
|
+
steps:
|
|
743
|
+
- name: Check production health
|
|
744
|
+
run: |
|
|
745
|
+
response=$(curl -s -o /dev/null -w "%{http_code}" https://your-app.com/api/health)
|
|
746
|
+
if [ $response -ne 200 ]; then
|
|
747
|
+
echo "Health check failed!"
|
|
748
|
+
exit 1
|
|
749
|
+
fi
|
|
750
|
+
|
|
751
|
+
- name: Check database connection
|
|
752
|
+
run: |
|
|
753
|
+
psql ${{ secrets.DATABASE_URL }} -c "SELECT 1"
|
|
754
|
+
|
|
755
|
+
- name: Run database backups
|
|
756
|
+
run: |
|
|
757
|
+
pg_dump ${{ secrets.DATABASE_URL }} > backup_$(date +%Y%m%d).sql
|
|
758
|
+
|
|
759
|
+
- name: Notify maintenance status
|
|
760
|
+
if: always()
|
|
761
|
+
uses: 8398a7/action-slack@v3
|
|
762
|
+
with:
|
|
763
|
+
status: ${{ job.status }}
|
|
764
|
+
text: 'Scheduled maintenance ${{ job.status }}'
|
|
765
|
+
webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
---
|
|
769
|
+
|
|
770
|
+
## CI/CD Best Practices
|
|
771
|
+
|
|
772
|
+
### 1. Use Caching
|
|
773
|
+
|
|
774
|
+
Cache dependencies to speed up builds:
|
|
775
|
+
|
|
776
|
+
```yaml
|
|
777
|
+
- name: Setup Node.js
|
|
778
|
+
uses: actions/setup-node@v4
|
|
779
|
+
with:
|
|
780
|
+
node-version: '20'
|
|
781
|
+
cache: 'pnpm'
|
|
782
|
+
```
|
|
783
|
+
|
|
784
|
+
### 2. Parallel Jobs
|
|
785
|
+
|
|
786
|
+
Run tests in parallel:
|
|
787
|
+
|
|
788
|
+
```yaml
|
|
789
|
+
jobs:
|
|
790
|
+
test:
|
|
791
|
+
runs-on: ubuntu-latest
|
|
792
|
+
strategy:
|
|
793
|
+
matrix:
|
|
794
|
+
node-version: [18, 20]
|
|
795
|
+
steps:
|
|
796
|
+
- uses: actions/checkout@v4
|
|
797
|
+
- name: Setup Node.js
|
|
798
|
+
uses: actions/setup-node@v4
|
|
799
|
+
with:
|
|
800
|
+
node-version: ${{ matrix.node-version }}
|
|
801
|
+
```
|
|
802
|
+
|
|
803
|
+
### 3. Conditional Deployments
|
|
804
|
+
|
|
805
|
+
Only deploy on specific conditions:
|
|
806
|
+
|
|
807
|
+
```yaml
|
|
808
|
+
- name: Deploy
|
|
809
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
810
|
+
uses: amondnet/vercel-action@v25
|
|
811
|
+
```
|
|
812
|
+
|
|
813
|
+
### 4. Artifact Upload
|
|
814
|
+
|
|
815
|
+
Upload build artifacts:
|
|
816
|
+
|
|
817
|
+
```yaml
|
|
818
|
+
- name: Upload build artifacts
|
|
819
|
+
uses: actions/upload-artifact@v4
|
|
820
|
+
with:
|
|
821
|
+
name: build
|
|
822
|
+
path: .next/
|
|
823
|
+
```
|
|
824
|
+
|
|
825
|
+
### 5. Notification Integration
|
|
826
|
+
|
|
827
|
+
Integrate with Slack, Discord, etc.:
|
|
828
|
+
|
|
829
|
+
```yaml
|
|
830
|
+
- name: Notify Slack
|
|
831
|
+
uses: 8398a7/action-slack@v3
|
|
832
|
+
with:
|
|
833
|
+
status: ${{ job.status }}
|
|
834
|
+
text: 'Deployment ${{ job.status }}'
|
|
835
|
+
webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }}
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
---
|
|
839
|
+
|
|
840
|
+
## Troubleshooting
|
|
841
|
+
|
|
842
|
+
### Issue: Workflow Fails on Environment Variables
|
|
843
|
+
|
|
844
|
+
**Symptoms:**
|
|
845
|
+
- Workflow fails during build
|
|
846
|
+
- Environment variable errors
|
|
847
|
+
|
|
848
|
+
**Solutions:**
|
|
849
|
+
|
|
850
|
+
```bash
|
|
851
|
+
# Verify secrets are set
|
|
852
|
+
gh secret list
|
|
853
|
+
|
|
854
|
+
# Check secret names match exactly
|
|
855
|
+
# Case-sensitive names
|
|
856
|
+
|
|
857
|
+
# Verify secrets are accessible
|
|
858
|
+
# Check repository permissions
|
|
859
|
+
```
|
|
860
|
+
|
|
861
|
+
### Issue: Deployment Fails Due to Tests
|
|
862
|
+
|
|
863
|
+
**Symptoms:**
|
|
864
|
+
- Tests fail in CI but pass locally
|
|
865
|
+
- Flaky tests
|
|
866
|
+
|
|
867
|
+
**Solutions:**
|
|
868
|
+
|
|
869
|
+
```yaml
|
|
870
|
+
# Add retry logic
|
|
871
|
+
- name: Run tests
|
|
872
|
+
run: pnpm test
|
|
873
|
+
continue-on-error: false
|
|
874
|
+
|
|
875
|
+
# Use test retries
|
|
876
|
+
# Configure in vitest.config.ts
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
### Issue: Preview Deployments Not Created
|
|
880
|
+
|
|
881
|
+
**Symptoms:**
|
|
882
|
+
- PRs don't create preview deployments
|
|
883
|
+
- No preview URL in PR comments
|
|
884
|
+
|
|
885
|
+
**Solutions:**
|
|
886
|
+
|
|
887
|
+
```bash
|
|
888
|
+
# Check Vercel Git integration
|
|
889
|
+
# Settings → Git → Preview Deployments
|
|
890
|
+
|
|
891
|
+
# Verify Vercel credentials
|
|
892
|
+
# Check VERCEL_TOKEN, VERCEL_ORG_ID, VERCEL_PROJECT_ID
|
|
893
|
+
|
|
894
|
+
# Check workflow permissions
|
|
895
|
+
# Repository → Settings → Actions → General → Workflow permissions
|
|
896
|
+
```
|
|
897
|
+
|
|
898
|
+
---
|
|
899
|
+
|
|
900
|
+
## Related Documentation
|
|
901
|
+
|
|
902
|
+
- [Vercel Deployment](./vercel.md) - Vercel deployment guide
|
|
903
|
+
- [DigitalOcean Deployment](./digitalocean.md) - DigitalOcean deployment guide
|
|
904
|
+
- [Environment Variables](./environment-variables.md) - Complete variable reference
|
|
905
|
+
- [Production Checklist](./production-checklist.md) - Pre-deployment checklist
|
|
906
|
+
- [Monitoring](./monitoring.md) - Monitoring and alerting setup
|
|
907
|
+
- [Testing Guide](../testing-guide.md) - Testing patterns and practices
|