g1t/.g1t/workflows/deploy.yml

180 lines6,893 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Deploys as code: a manifest of every Worker, a deploy tool that ships only what changed in parallel stages, and a g1t Actions workflow1# Deploys g1t.sh from main, with g1t's own Actions. What it does is
2# scripts/deploy.mjs, the same tool a person runs; docs/DEPLOYING.md is the
3# guide.
4#
5# check the deploy manifest is consistent, and the tool's tests pass
6# plan what changed since each Worker's live commit, and pending migrations
7# migrate pending D1 migrations, before any code
8# core, edge, front the units of each stage, in jobs that share a build;
9# a stage starts only when the one before it succeeded
10#
11# Needs the repository secret CLOUDFLARE_API_TOKEN (a Production row) and
12# the variable CLOUDFLARE_ACCOUNT_ID, and api.cloudflare.com among the
13# project's allowed domains (Settings, Guardrails). See docs/DEPLOYING.md.
14name: Deploy
15
16on:
17 push:
18 branches: [main]
19 workflow_dispatch:
20 inputs:
21 units:
22 description: "Units to deploy whether or not they changed, comma separated (empty: what changed)"
23 type: string
24 default: ""
25 all:
26 description: "Deploy every unit"
27 type: boolean
28 default: false
29 dry_run:
30 description: "Plan only: deploy nothing"
31 type: boolean
32 default: false
33
34# One deploy at a time, and never one cut off halfway: the next waits.
35concurrency:
36 group: deploy-production
37 cancel-in-progress: false
38
39env:
40 CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
41 CARGO_TERM_COLOR: never
42 WRANGLER_SEND_METRICS: "false"
43
44jobs:
45 check:
46 name: Check
47 runs-on: ubuntu-latest
48 timeout-minutes: 20
49 steps:
50 - uses: actions/checkout@v5
51 - name: Install Wrangler
52 run: npm ci --workspaces=false --no-audit --no-fund
53 - name: The manifest matches every wrangler.jsonc
54 run: node scripts/deploy.mjs manifest --check
55 - name: The deploy tool's tests
56 run: npm run test:deploy
57
58 plan:
59 name: Plan
60 needs: check
61 runs-on: ubuntu-latest
62 environment: production
63 timeout-minutes: 15
64 outputs:
65 migrate: ${{ steps.plan.outputs.migrate }}
66 migrate_units: ${{ steps.plan.outputs.migrate_units }}
67 has_core: ${{ steps.plan.outputs.has_core }}
68 core: ${{ steps.plan.outputs.core }}
69 has_edge: ${{ steps.plan.outputs.has_edge }}
70 edge: ${{ steps.plan.outputs.edge }}
71 has_front: ${{ steps.plan.outputs.has_front }}
72 front: ${{ steps.plan.outputs.front }}
73 steps:
74 - uses: actions/checkout@v5
75 with:
76 # Each Worker's live commit is compared with this one.
77 fetch-depth: 0
78 - name: Install Wrangler
79 run: npm ci --workspaces=false --no-audit --no-fund
80 - name: Plan
81 id: plan
82 env:
83 CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
84 UNITS: ${{ inputs.units }}
85 ALL: ${{ inputs.all }}
86 run: |
87 args=()
88 if [ -n "$UNITS" ]; then args+=(--only "$UNITS" --force); fi
89 if [ "$ALL" = "true" ]; then args+=(--all); fi
90 node scripts/deploy.mjs plan "${args[@]}" --github-output
91
92 migrate:
93 name: Migrations
94 needs: plan
95 if: ${{ needs.plan.outputs.migrate == 'true' && inputs.dry_run != true }}
96 runs-on: ubuntu-latest
97 environment: production
98 timeout-minutes: 20
99 steps:
100 - uses: actions/checkout@v5
101 - name: Install Wrangler
102 run: npm ci --workspaces=false --no-audit --no-fund
103 - name: Apply pending migrations
104 env:
105 CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
106 run: node scripts/deploy.mjs migrate --only "${{ needs.plan.outputs.migrate_units }}"
107
108 core:
109 name: core (${{ matrix.group }})
110 needs: [plan, migrate]
111 if: ${{ !cancelled() && needs.plan.result == 'success' && (needs.migrate.result == 'success' || needs.migrate.result == 'skipped') && needs.plan.outputs.has_core == 'true' && inputs.dry_run != true }}
112 runs-on: ubuntu-latest
113 environment: production
114 timeout-minutes: 60
115 strategy:
116 # A deploy cut off halfway is worse than one that finishes: the other
117 # jobs of a stage run on when one fails, and the next stage does not.
118 fail-fast: false
119 max-parallel: 4
120 matrix: ${{ fromJSON(needs.plan.outputs.core) }}
121 steps: &deploy
122 - uses: actions/checkout@v5
123 with:
124 fetch-depth: 0
125 # Rust workers: the wasm target, and worker-build kept between runs
126 # (its version is pinned in scripts/build-rust-worker.mjs).
127 - name: Rust for Workers
128 if: ${{ matrix.rust }}
129 run: rustup target add wasm32-unknown-unknown
130 - name: Cache worker-build
131 if: ${{ matrix.rust }}
132 uses: actions/cache@v4
133 with:
134 path: ~/.cargo/bin/worker-build
135 key: worker-build-${{ runner.os }}-${{ hashFiles('scripts/build-rust-worker.mjs') }}
136 - name: Cache worker-build's tools (wasm-bindgen, esbuild)
137 if: ${{ matrix.rust }}
138 uses: actions/cache@v4
139 with:
140 path: ~/.cache/worker-build
141 key: worker-build-tools-${{ runner.os }}-${{ hashFiles('scripts/build-rust-worker.mjs') }}
142 - name: Cache crates
143 if: ${{ matrix.rust }}
144 uses: actions/cache@v4
145 with:
146 path: ~/.cargo/registry/cache
147 key: cargo-crates-${{ runner.os }}-${{ hashFiles('Cargo.lock') }}
148 restore-keys: cargo-crates-${{ runner.os }}-
149 - name: Install
150 run: node scripts/deploy.mjs install --only "${{ matrix.units }}"
151 - name: Deploy ${{ matrix.units }}
152 env:
153 CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
154 run: node scripts/deploy.mjs deploy --only "${{ matrix.units }}" --force --no-migrations --concurrency 2
155
156 edge:
157 name: edge (${{ matrix.group }})
158 needs: [plan, migrate, core]
159 if: ${{ !cancelled() && needs.plan.result == 'success' && (needs.migrate.result == 'success' || needs.migrate.result == 'skipped') && (needs.core.result == 'success' || needs.core.result == 'skipped') && needs.plan.outputs.has_edge == 'true' && inputs.dry_run != true }}
160 runs-on: ubuntu-latest
161 environment: production
162 timeout-minutes: 60
163 strategy:
164 fail-fast: false
165 max-parallel: 4
166 matrix: ${{ fromJSON(needs.plan.outputs.edge) }}
167 steps: *deploy
168
169 front:
170 name: front (${{ matrix.group }})
171 needs: [plan, migrate, core, edge]
172 if: ${{ !cancelled() && needs.plan.result == 'success' && (needs.migrate.result == 'success' || needs.migrate.result == 'skipped') && (needs.core.result == 'success' || needs.core.result == 'skipped') && (needs.edge.result == 'success' || needs.edge.result == 'skipped') && needs.plan.outputs.has_front == 'true' && inputs.dry_run != true }}
173 runs-on: ubuntu-latest
174 environment: production
175 timeout-minutes: 60
176 strategy:
177 fail-fast: false
178 max-parallel: 4
179 matrix: ${{ fromJSON(needs.plan.outputs.front) }}
180 steps: *deploy