Skip to content

Commit fdd447c

Browse files
committed
ci: fully automated prod deploy + snapshot build (no manual steps)
- deploy-workers.yml now auto-runs after Static Checks succeeds on main (workflow_run); workers deploy as a chain, web self-skips until its NEXT_PUBLIC vars are set so it can't block the backend cutover. - build-snapshot.yml rebuilds+republishes the cheatcode-sandbox Daytona snapshot on any infra/containers/sandbox change (builds on Daytona infra). - workflow_dispatch retained as manual fallback.
1 parent f9dd040 commit fdd447c

2 files changed

Lines changed: 89 additions & 47 deletions

File tree

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Build Sandbox Snapshot
2+
3+
# Rebuilds + republishes the Daytona sandbox snapshot whenever the sandbox image
4+
# changes. Builds on Daytona's infra (no Docker/cross-arch build needed in CI).
5+
# Keeps the `cheatcode-sandbox` snapshot name stable so the agent-worker's
6+
# DAYTONA_SANDBOX_SNAPSHOT var never has to change.
7+
on:
8+
push:
9+
branches: [main]
10+
paths:
11+
- "infra/containers/sandbox/**"
12+
workflow_dispatch: {}
13+
14+
permissions:
15+
contents: read
16+
17+
concurrency:
18+
group: daytona-snapshot
19+
cancel-in-progress: false
20+
21+
jobs:
22+
build-snapshot:
23+
runs-on: ubuntu-latest
24+
environment: production
25+
env:
26+
DAYTONA_API_KEY: ${{ secrets.DAYTONA_API_KEY }}
27+
steps:
28+
- uses: actions/checkout@v4
29+
- name: Install Daytona CLI
30+
run: |
31+
curl -sf -L https://download.daytona.io/daytona/install.sh | sudo bash
32+
daytona version
33+
- name: Build & publish snapshot
34+
run: |
35+
# Idempotent: drop the previous snapshot of this name (existing sandboxes
36+
# are unaffected — they already hold their own copy) then rebuild.
37+
daytona snapshot delete cheatcode-sandbox -y 2>/dev/null || true
38+
daytona snapshot create cheatcode-sandbox \
39+
-f infra/containers/sandbox/Dockerfile \
40+
-c infra/containers/sandbox \
41+
--cpu 2 --memory 4 --disk 10
Lines changed: 48 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,33 @@
11
name: Deploy Workers
22

3+
# Fully automated production deploy. Runs after "Static Checks" succeeds on main —
4+
# no manual step required. `workflow_dispatch` is kept only as a manual fallback.
5+
# The worker chain (agent → gateway → webhooks → preview-proxy) is the Daytona
6+
# backend; the web deploy runs independently and self-skips until its NEXT_PUBLIC
7+
# vars are configured (so a missing web var never blocks the backend cutover).
38
on:
4-
workflow_dispatch:
5-
inputs:
6-
confirm_production_deploy:
7-
description: Type "deploy Cheatcode V2 to production" to approve production deployment.
8-
required: true
9-
type: string
9+
workflow_run:
10+
workflows: ["Static Checks"]
11+
types: [completed]
12+
workflow_dispatch: {}
1013

1114
permissions:
1215
contents: read
1316

1417
concurrency:
15-
group: production-workers
18+
group: production-deploy
1619
cancel-in-progress: false
1720

1821
jobs:
19-
prepare-production:
20-
if: github.event.inputs.confirm_production_deploy == 'deploy Cheatcode V2 to production'
21-
runs-on: ubuntu-latest
22-
environment: production
23-
steps:
24-
- uses: actions/checkout@v4
25-
- uses: pnpm/action-setup@v4
26-
with:
27-
version: 10.33.2
28-
- uses: actions/setup-node@v4
29-
with:
30-
node-version: 22
31-
cache: pnpm
32-
- run: pnpm install --frozen-lockfile
33-
- run: pnpm typecheck:scripts
34-
3522
deploy-agent:
23+
# Only on a successful Static Checks run on main, or a manual dispatch.
24+
if: ${{ github.event_name == 'workflow_dispatch' || (github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.head_branch == 'main') }}
3625
runs-on: ubuntu-latest
37-
needs: prepare-production
3826
environment: production
3927
steps:
4028
- uses: actions/checkout@v4
29+
with:
30+
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
4131
- uses: pnpm/action-setup@v4
4232
with:
4333
version: 10.33.2
@@ -55,11 +45,13 @@ jobs:
5545
command: deploy
5646

5747
deploy-gateway:
58-
runs-on: ubuntu-latest
5948
needs: deploy-agent
49+
runs-on: ubuntu-latest
6050
environment: production
6151
steps:
6252
- uses: actions/checkout@v4
53+
with:
54+
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
6355
- uses: pnpm/action-setup@v4
6456
with:
6557
version: 10.33.2
@@ -76,12 +68,14 @@ jobs:
7668
workingDirectory: apps/gateway-worker
7769
command: deploy
7870

79-
deploy-web:
80-
runs-on: ubuntu-latest
71+
deploy-webhooks:
8172
needs: deploy-gateway
73+
runs-on: ubuntu-latest
8274
environment: production
8375
steps:
8476
- uses: actions/checkout@v4
77+
with:
78+
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
8579
- uses: pnpm/action-setup@v4
8680
with:
8781
version: 10.33.2
@@ -90,20 +84,22 @@ jobs:
9084
node-version: 22
9185
cache: pnpm
9286
- run: pnpm install --frozen-lockfile
93-
- run: pnpm --filter @cheatcode/web deploy
94-
env:
95-
CHEATCODE_PROD_DEPLOY_APPROVED: "true"
96-
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
97-
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
98-
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ vars.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }}
99-
NEXT_PUBLIC_POLAR_PRO_MONTHLY_PRODUCT_ID: ${{ vars.NEXT_PUBLIC_POLAR_PRO_MONTHLY_PRODUCT_ID }}
87+
- run: pnpm turbo build --filter=@cheatcode/webhooks-worker
88+
- uses: cloudflare/wrangler-action@v3
89+
with:
90+
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
91+
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
92+
workingDirectory: apps/webhooks-worker
93+
command: deploy
10094

101-
deploy-webhooks:
95+
deploy-preview-proxy:
96+
needs: deploy-webhooks
10297
runs-on: ubuntu-latest
103-
needs: deploy-web
10498
environment: production
10599
steps:
106100
- uses: actions/checkout@v4
101+
with:
102+
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
107103
- uses: pnpm/action-setup@v4
108104
with:
109105
version: 10.33.2
@@ -112,20 +108,25 @@ jobs:
112108
node-version: 22
113109
cache: pnpm
114110
- run: pnpm install --frozen-lockfile
115-
- run: pnpm turbo build --filter=@cheatcode/webhooks-worker
111+
- run: pnpm turbo build --filter=@cheatcode/preview-proxy
116112
- uses: cloudflare/wrangler-action@v3
117113
with:
118114
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
119115
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
120-
workingDirectory: apps/webhooks-worker
116+
workingDirectory: apps/preview-proxy
121117
command: deploy
122118

123-
deploy-preview-proxy:
119+
deploy-web:
120+
# Independent of the worker chain; self-skips until the NEXT_PUBLIC vars exist
121+
# so a missing web var can never block the backend cutover.
122+
needs: deploy-agent
123+
if: ${{ vars.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY != '' }}
124124
runs-on: ubuntu-latest
125-
needs: deploy-webhooks
126125
environment: production
127126
steps:
128127
- uses: actions/checkout@v4
128+
with:
129+
ref: ${{ github.event.workflow_run.head_sha || github.sha }}
129130
- uses: pnpm/action-setup@v4
130131
with:
131132
version: 10.33.2
@@ -134,10 +135,10 @@ jobs:
134135
node-version: 22
135136
cache: pnpm
136137
- run: pnpm install --frozen-lockfile
137-
- run: pnpm turbo build --filter=@cheatcode/preview-proxy
138-
- uses: cloudflare/wrangler-action@v3
139-
with:
140-
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
141-
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
142-
workingDirectory: apps/preview-proxy
143-
command: deploy
138+
- run: pnpm --filter @cheatcode/web deploy
139+
env:
140+
CHEATCODE_PROD_DEPLOY_APPROVED: "true"
141+
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
142+
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
143+
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ vars.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }}
144+
NEXT_PUBLIC_POLAR_PRO_MONTHLY_PRODUCT_ID: ${{ vars.NEXT_PUBLIC_POLAR_PRO_MONTHLY_PRODUCT_ID }}

0 commit comments

Comments
 (0)