Repository navigation
168 lines (149 loc) · 6.28 KB
/
Copy pathdeploy.yml
File metadata and controls
168 lines (149 loc) · 6.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
name: Deploy to Cloudflare
# Triggered on push to main OR manually from the GitHub UI.
# After forking the repo, add these two secrets under Settings → Secrets and variables → Actions:
# CLOUDFLARE_API_TOKEN (with "Edit Cloudflare Workers" template permissions + D1 + R2 read/write)
# CLOUDFLARE_ACCOUNT_ID
# Optionally add APP_PASSWORD as a repository secret, or pass it when running
# workflow_dispatch, for the initial admin seed.
on:
push:
branches: [main]
workflow_dispatch:
inputs:
app_password:
description: 'Optional APP_PASSWORD seed (will be set as Worker secret after deploy)'
required: false
type: string
concurrency:
group: deploy
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: package-lock.json
- name: Install dependencies
run: npm ci --legacy-peer-deps
- name: Build platform
working-directory: platform
run: npm run build
- name: Check Cloudflare deploy credentials
id: cloudflare
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
run: |
if [ -z "$CLOUDFLARE_API_TOKEN" ] || [ -z "$CLOUDFLARE_ACCOUNT_ID" ]; then
echo "deploy=false" >> "$GITHUB_OUTPUT"
echo "::warning::Cloudflare deploy skipped. Add CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID in GitHub repository secrets to enable deployment."
else
echo "deploy=true" >> "$GITHUB_OUTPUT"
fi
- name: Validate Cloudflare account access
if: steps.cloudflare.outputs.deploy == 'true'
working-directory: backend
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
run: npx wrangler whoami --account "$CLOUDFLARE_ACCOUNT_ID"
- name: Ensure D1 database exists
if: steps.cloudflare.outputs.deploy == 'true'
working-directory: backend
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
run: |
set -euo pipefail
get_db_id() {
DB_JSON="$(npx wrangler d1 list --json)"
DB_JSON="$DB_JSON" node -e "
const rows = JSON.parse(process.env.DB_JSON || '[]');
const hit = rows.find((r) => r.name === 'dyeink');
if (hit?.uuid) {
console.log(hit.uuid);
}
"
}
DB_ID="$(get_db_id)"
if [ -z "$DB_ID" ]; then
npx wrangler d1 create dyeink
for attempt in 1 2 3 4 5; do
DB_ID="$(get_db_id)"
if [ -n "$DB_ID" ]; then
break
fi
echo "Waiting for D1 database dyeink to appear in account list... attempt $attempt"
sleep 2
done
fi
if [ -z "$DB_ID" ]; then
echo "::error::D1 database \"dyeink\" was not found after create/list."
exit 1
fi
echo "DB_ID=$DB_ID"
export DB_ID
node -e 'const fs = require("fs"); const p = "wrangler.toml"; const id = process.env.DB_ID; let s = fs.readFileSync(p, "utf8"); if (/database_id\s*=/.test(s)) { s = s.replace(/database_id\s*=\s*"[^"]*"/, `database_id = "${id}"`); } else { s = s.replace(/database_name\s*=\s*"dyeink"\n/, `database_name = "dyeink"\ndatabase_id = "${id}"\n`); } fs.writeFileSync(p, s);'
- name: Ensure R2 bucket exists
if: steps.cloudflare.outputs.deploy == 'true'
working-directory: backend
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
run: |
set -euo pipefail
if npx wrangler r2 bucket info dyeink-images >/dev/null 2>&1; then
echo "R2 bucket dyeink-images already exists."
else
npx wrangler r2 bucket create dyeink-images
for attempt in 1 2 3 4 5; do
if npx wrangler r2 bucket info dyeink-images >/dev/null 2>&1; then
echo "R2 bucket dyeink-images is ready."
exit 0
fi
echo "Waiting for R2 bucket dyeink-images to become available... attempt $attempt"
sleep 2
done
echo "::error::R2 bucket dyeink-images was not available after creation."
exit 1
fi
- name: Apply D1 migrations
if: steps.cloudflare.outputs.deploy == 'true'
working-directory: backend
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
run: npx wrangler d1 migrations apply dyeink --remote
- name: Deploy Worker
if: steps.cloudflare.outputs.deploy == 'true'
working-directory: backend
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
run: npx wrangler deploy
- name: Seed APP_PASSWORD (if provided)
if: steps.cloudflare.outputs.deploy == 'true'
working-directory: backend
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
APP_PASSWORD_INPUT: ${{ inputs.app_password }}
APP_PASSWORD_SECRET: ${{ secrets.APP_PASSWORD }}
run: |
set -euo pipefail
APP_PASSWORD="${APP_PASSWORD_INPUT:-$APP_PASSWORD_SECRET}"
if [ -z "$APP_PASSWORD" ]; then
echo "APP_PASSWORD was not provided; skipping secret seed."
exit 0
fi
printf '%s' "$APP_PASSWORD" | npx wrangler secret put APP_PASSWORD
- name: Deployment skipped
if: steps.cloudflare.outputs.deploy != 'true'
run: |
echo "Build completed. Cloudflare deployment was skipped because required repository secrets are missing."