History

Bring CI under two minutes (#1644)

* Cut CI toward two minutes * Bring CI under two minutes * Make approval lease test deterministic * Stabilize E2E dependency setup * Harden CI regression coverage

Rhys Sullivan committed 2 months ago

Commit 86acd381 parent 9ecc7cb15 files · +661 −93Browse files

Showing the changes to .github (1 of 15 files). Show all

Unified · Split

.github/workflows/ci.yml+54−80
@@ -144,15 +144,18 @@ jobs: · 143 unmodified lines
144 144
145 test:145 test:
146 name: Test146 name: Test
147 runs-on: blacksmith-4vcpu-ubuntu-2404147 runs-on: blacksmith-16vcpu-ubuntu-2404
148 timeout-minutes: 15148 timeout-minutes: 15
149 # Tuned for Blacksmith's 4 vCPU runners.149 # Run eight independent packages at once and cap each Vitest process at two
150 # workers. This uses all 16 vCPUs without every nested runner seeing the
151 # whole machine and oversubscribing it.
150 env:152 env:
151 TURBO_API: ${{ vars.TURBO_API }}153 TURBO_API: ${{ vars.TURBO_API }}
152 TURBO_TEAM: ${{ vars.TURBO_TEAM }}154 TURBO_TEAM: ${{ vars.TURBO_TEAM }}
153 TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}155 TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
154 TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}156 TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }}
155 TURBO_TEST_CONCURRENCY: 4157 TURBO_TEST_CONCURRENCY: 8
158 VITEST_MAX_WORKERS: 2
156 steps:159 steps:
157 - uses: actions/checkout@v4160 - uses: actions/checkout@v4
158 161
@@ -184,6 +187,8 @@ jobs: · 25 unmodified lines
184 # no signal. This is just a few file reads plus greps, so ~zero cost.187 # no signal. This is just a few file reads plus greps, so ~zero cost.
185 - run: bun run check:patches188 - run: bun run check:patches
186 189
190 - run: bun run --cwd e2e test:ci-shard
191
187 - run: bun run test192 - run: bun run test
188 193
189 e2e:194 e2e:
@@ -192,25 +197,41 @@ jobs: · 2 unmodified lines
192 fail-fast: false197 fail-fast: false
193 matrix:198 matrix:
194 include:199 include:
195 # PGlite is deliberately single-connection, and under a sustained200 # The planner assigns every file exactly once using recorded slow-file
196 # multi-minute shard it can stop accepting postgres sockets. Keep201 # durations plus a conservative weight for new tests. The cloud DB's
197 # every hermetic dev stack short: eight serial shards remove that202 # connection teardown and concurrent socket protocol have dedicated
198 # lifetime-dependent failure and put cloud below the selfhost lane.203 # regression tests; these shards balance wall clock, not hide retries.
199 - { target: cloud, shard: 1/8, shard-name: 1of8 }204 - { target: cloud, shard-index: 1, shard-name: 1of16 }
200 - { target: cloud, shard: 2/8, shard-name: 2of8 }205 - { target: cloud, shard-index: 2, shard-name: 2of16 }
201 - { target: cloud, shard: 3/8, shard-name: 3of8 }206 - { target: cloud, shard-index: 3, shard-name: 3of16 }
202 - { target: cloud, shard: 4/8, shard-name: 4of8 }207 - { target: cloud, shard-index: 4, shard-name: 4of16 }
203 - { target: cloud, shard: 5/8, shard-name: 5of8 }208 - { target: cloud, shard-index: 5, shard-name: 5of16 }
204 - { target: cloud, shard: 6/8, shard-name: 6of8 }209 - { target: cloud, shard-index: 6, shard-name: 6of16 }
205 - { target: cloud, shard: 7/8, shard-name: 7of8 }210 - { target: cloud, shard-index: 7, shard-name: 7of16 }
206 - { target: cloud, shard: 8/8, shard-name: 8of8 }211 - { target: cloud, shard-index: 8, shard-name: 8of16 }
207 # Selfhost shards the same way: each shard is its own runner booting212 - { target: cloud, shard-index: 9, shard-name: 9of16 }
208 # its own fresh instance (own port block + data dir), so the213 - { target: cloud, shard-index: 10, shard-name: 10of16 }
209 # project's shared-bootstrap-admin assumption stays intact per shard214 - { target: cloud, shard-index: 11, shard-name: 11of16 }
210 # and `fileParallelism: false` still serializes within a shard.215 - { target: cloud, shard-index: 12, shard-name: 12of16 }
211 - { target: selfhost, shard: 1/3, shard-name: 1of3 }216 - { target: cloud, shard-index: 13, shard-name: 13of16 }
212 - { target: selfhost, shard: 2/3, shard-name: 2of3 }217 - { target: cloud, shard-index: 14, shard-name: 14of16 }
213 - { target: selfhost, shard: 3/3, shard-name: 3of3 }218 - { target: cloud, shard-index: 15, shard-name: 15of16 }
219 - { target: cloud, shard-index: 16, shard-name: 16of16 }
220 - { target: selfhost, shard-index: 1, shard-name: 1of10 }
221 - { target: selfhost, shard-index: 2, shard-name: 2of10 }
222 - { target: selfhost, shard-index: 3, shard-name: 3of10 }
223 - { target: selfhost, shard-index: 4, shard-name: 4of10 }
224 - { target: selfhost, shard-index: 5, shard-name: 5of10 }
225 - { target: selfhost, shard-index: 6, shard-name: 6of10 }
226 - { target: selfhost, shard-index: 7, shard-name: 7of10 }
227 - { target: selfhost, shard-index: 8, shard-name: 8of10 }
228 - { target: selfhost, shard-index: 9, shard-name: 9of10 }
229 - { target: selfhost, shard-index: 10, shard-name: 10of10 }
230 # Local files own their server, browser and data directory. Separate
231 # runners preserve that isolation while removing its 69-second serial
232 # lane from the two-minute critical path.
233 - { target: local, shard-index: 1, shard-name: 1of2 }
234 - { target: local, shard-index: 2, shard-name: 2of2 }
214 runs-on: blacksmith-4vcpu-ubuntu-2404235 runs-on: blacksmith-4vcpu-ubuntu-2404
215 timeout-minutes: 30236 timeout-minutes: 30
216 steps:237 steps:
@@ -246,26 +267,29 @@ jobs: · 29 unmodified lines
246 267
247 # Install from e2e so bunx resolves ITS pinned playwright (the version268 # Install from e2e so bunx resolves ITS pinned playwright (the version
248 # the tests run against) rather than floating to the latest.269 # the tests run against) rather than floating to the latest.
270 # Blacksmith's Ubuntu image carries the official GitHub runner system
271 # dependencies. Restore the pinned browser binaries without apt-updating
272 # every matrix machine.
249 - name: Install Playwright Chromium273 - name: Install Playwright Chromium
250 run: bunx playwright install --with-deps chromium chromium-headless-shell274 run: bunx playwright install chromium chromium-headless-shell
251 working-directory: e2e275 working-directory: e2e
252 276
253 # The globalsetup boots the target's own dev server (ports are claimed277 # Each target either boots its own shared dev server or lets each file own
254 # per checkout, so this is hermetic) and tears it down after the run.278 # its server. Ports and data paths are hermetic in both cases.
255 # Do not retry scenarios: retries hide flakes and multiply slow timeout279 # Do not retry scenarios: retries hide flakes and multiply slow timeout
256 # failures. The fixtures and process lifecycle are deterministic enough280 # failures. The fixtures and process lifecycle are deterministic enough
257 # that the first result is the result.281 # that the first result is the result.
258 - name: Run cloud scenarios282 - name: Run cloud shard
259 if: matrix.target == 'cloud'283 if: matrix.target == 'cloud'
260 env:284 env:
261 MCP_SESSION_TIMEOUT_MS: "3000"285 MCP_SESSION_TIMEOUT_MS: "3000"
262 MCP_PAUSED_SESSION_IDLE_TIMEOUT_MS: "6000"286 MCP_PAUSED_SESSION_IDLE_TIMEOUT_MS: "6000"
263 run: bunx vitest run --project cloud ${{ matrix.shard && format('--shard={0}', matrix.shard) || '' }}287 run: bun scripts/run-ci-shard.ts cloud ${{ matrix['shard-index'] }}
264 working-directory: e2e288 working-directory: e2e
265 289
266 - name: Run selfhost scenarios290 - name: Run scenarios
267 if: matrix.target == 'selfhost'291 if: matrix.target != 'cloud'
268 run: bunx vitest run --project selfhost ${{ matrix.shard && format('--shard={0}', matrix.shard) || '' }}292 run: bun scripts/run-ci-shard.ts ${{ matrix.target }} ${{ matrix['shard-index'] }}
269 working-directory: e2e293 working-directory: e2e
270 294
271 # Failed runs keep their trace.zip / session.mp4 / step screenshots in295 # Failed runs keep their trace.zip / session.mp4 / step screenshots in
@@ -278,56 +302,6 @@ jobs: · 6 unmodified lines
278 path: e2e/runs/302 path: e2e/runs/
279 retention-days: 7303 retention-days: 7
280 304
281 e2e-local:
282 name: E2E (local)
283 runs-on: blacksmith-4vcpu-ubuntu-2404
284 timeout-minutes: 20
285 steps:
286 - uses: actions/checkout@v4
287
288 - uses: oven-sh/setup-bun@v2
289 with:
290 bun-version: 1.3.11
291
292 - name: Cache Bun package cache
293 uses: actions/cache@v4
294 with:
295 path: ~/.bun/install/cache
296 key: ${{ runner.os }}-bun-1.3.11-${{ hashFiles('bun.lock') }}
297 restore-keys: |
298 ${{ runner.os }}-bun-1.3.11-
299
300 # The local scenarios boot a real `executor web` (which spawns a Node
301 # sidecar) and some drive a browser, so pin Node 24 and install Chromium.
302 - uses: actions/setup-node@v4
303 with:
304 node-version: 24
305
306 - run: bun install --frozen-lockfile
307
308 - name: Cache Playwright browsers
309 uses: actions/cache@v4
310 with:
311 path: ~/.cache/ms-playwright
312 key: ${{ runner.os }}-playwright-1.60.0
313 restore-keys: |
314 ${{ runner.os }}-playwright-
315
316 # `chromium` and the new `chromium-headless-shell` ship as separate
317 # downloads; the browser-driven scenarios launch the headless shell.
318 # Install from e2e so bunx resolves ITS pinned playwright (the version the
319 # tests run against) rather than floating to the latest, which would fetch
320 # a browser build the test runtime does not look for.
321 - name: Install Playwright Chromium
322 run: bunx playwright install --with-deps chromium chromium-headless-shell
323 working-directory: e2e
324
325 # Each scenario owns its server, browser, data directory, and descendants;
326 # run the complete hermetic suite on PRs without scenario retries.
327 - name: Run local scenarios
328 run: bunx vitest run --project local
329 working-directory: e2e
330
331 desktop-smoke:305 desktop-smoke:
332 name: Desktop smoke build306 name: Desktop smoke build
333 needs: changes307 needs: changes