* Cut CI toward two minutes * Bring CI under two minutes * Make approval lease test deterministic * Stabilize E2E dependency setup * Harden CI regression coverage
Showing the changes to .github (1 of 15 files). Show all
Unified · Split
| @@ -144,15 +144,18 @@ jobs: · 143 unmodified lines | ||
| 144 | 144 | |
| 145 | 145 | test: |
| 146 | 146 | name: Test |
| 147 | − runs-on: blacksmith-4vcpu-ubuntu-2404 | |
| 147 | + runs-on: blacksmith-16vcpu-ubuntu-2404 | |
| 148 | 148 | 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 | 152 | env: |
| 151 | 153 | TURBO_API: ${{ vars.TURBO_API }} |
| 152 | 154 | TURBO_TEAM: ${{ vars.TURBO_TEAM }} |
| 153 | 155 | TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} |
| 154 | 156 | TURBO_REMOTE_CACHE_SIGNATURE_KEY: ${{ secrets.TURBO_REMOTE_CACHE_SIGNATURE_KEY }} |
| 155 | − TURBO_TEST_CONCURRENCY: 4 | |
| 157 | + TURBO_TEST_CONCURRENCY: 8 | |
| 158 | + VITEST_MAX_WORKERS: 2 | |
| 156 | 159 | steps: |
| 157 | 160 | - uses: actions/checkout@v4 |
| 158 | 161 | |
| @@ -184,6 +187,8 @@ jobs: · 25 unmodified lines | ||
| 184 | 187 | # no signal. This is just a few file reads plus greps, so ~zero cost. |
| 185 | 188 | - run: bun run check:patches |
| 186 | 189 | |
| 190 | + - run: bun run --cwd e2e test:ci-shard | |
| 191 | + | |
| 187 | 192 | - run: bun run test |
| 188 | 193 | |
| 189 | 194 | e2e: |
| @@ -192,25 +197,41 @@ jobs: · 2 unmodified lines | ||
| 192 | 197 | fail-fast: false |
| 193 | 198 | matrix: |
| 194 | 199 | include: |
| 195 | − # PGlite is deliberately single-connection, and under a sustained | |
| 196 | − # multi-minute shard it can stop accepting postgres sockets. Keep | |
| 197 | − # every hermetic dev stack short: eight serial shards remove that | |
| 198 | − # lifetime-dependent failure and put cloud below the selfhost lane. | |
| 199 | − - { target: cloud, shard: 1/8, shard-name: 1of8 } | |
| 200 | − - { target: cloud, shard: 2/8, shard-name: 2of8 } | |
| 201 | − - { target: cloud, shard: 3/8, shard-name: 3of8 } | |
| 202 | − - { target: cloud, shard: 4/8, shard-name: 4of8 } | |
| 203 | − - { target: cloud, shard: 5/8, shard-name: 5of8 } | |
| 204 | − - { target: cloud, shard: 6/8, shard-name: 6of8 } | |
| 205 | − - { target: cloud, shard: 7/8, shard-name: 7of8 } | |
| 206 | − - { target: cloud, shard: 8/8, shard-name: 8of8 } | |
| 207 | − # Selfhost shards the same way: each shard is its own runner booting | |
| 208 | − # its own fresh instance (own port block + data dir), so the | |
| 209 | − # project's shared-bootstrap-admin assumption stays intact per shard | |
| 210 | − # and `fileParallelism: false` still serializes within a shard. | |
| 211 | − - { target: selfhost, shard: 1/3, shard-name: 1of3 } | |
| 212 | − - { target: selfhost, shard: 2/3, shard-name: 2of3 } | |
| 213 | − - { target: selfhost, shard: 3/3, shard-name: 3of3 } | |
| 200 | + # The planner assigns every file exactly once using recorded slow-file | |
| 201 | + # durations plus a conservative weight for new tests. The cloud DB's | |
| 202 | + # connection teardown and concurrent socket protocol have dedicated | |
| 203 | + # regression tests; these shards balance wall clock, not hide retries. | |
| 204 | + - { target: cloud, shard-index: 1, shard-name: 1of16 } | |
| 205 | + - { target: cloud, shard-index: 2, shard-name: 2of16 } | |
| 206 | + - { target: cloud, shard-index: 3, shard-name: 3of16 } | |
| 207 | + - { target: cloud, shard-index: 4, shard-name: 4of16 } | |
| 208 | + - { target: cloud, shard-index: 5, shard-name: 5of16 } | |
| 209 | + - { target: cloud, shard-index: 6, shard-name: 6of16 } | |
| 210 | + - { target: cloud, shard-index: 7, shard-name: 7of16 } | |
| 211 | + - { target: cloud, shard-index: 8, shard-name: 8of16 } | |
| 212 | + - { target: cloud, shard-index: 9, shard-name: 9of16 } | |
| 213 | + - { target: cloud, shard-index: 10, shard-name: 10of16 } | |
| 214 | + - { target: cloud, shard-index: 11, shard-name: 11of16 } | |
| 215 | + - { target: cloud, shard-index: 12, shard-name: 12of16 } | |
| 216 | + - { target: cloud, shard-index: 13, shard-name: 13of16 } | |
| 217 | + - { target: cloud, shard-index: 14, shard-name: 14of16 } | |
| 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 | 235 | runs-on: blacksmith-4vcpu-ubuntu-2404 |
| 215 | 236 | timeout-minutes: 30 |
| 216 | 237 | steps: |
| @@ -246,26 +267,29 @@ jobs: · 29 unmodified lines | ||
| 246 | 267 | |
| 247 | 268 | # Install from e2e so bunx resolves ITS pinned playwright (the version |
| 248 | 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 | 273 | - name: Install Playwright Chromium |
| 250 | − run: bunx playwright install --with-deps chromium chromium-headless-shell | |
| 274 | + run: bunx playwright install chromium chromium-headless-shell | |
| 251 | 275 | working-directory: e2e |
| 252 | 276 | |
| 253 | − # The globalsetup boots the target's own dev server (ports are claimed | |
| 254 | − # per checkout, so this is hermetic) and tears it down after the run. | |
| 277 | + # Each target either boots its own shared dev server or lets each file own | |
| 278 | + # its server. Ports and data paths are hermetic in both cases. | |
| 255 | 279 | # Do not retry scenarios: retries hide flakes and multiply slow timeout |
| 256 | 280 | # failures. The fixtures and process lifecycle are deterministic enough |
| 257 | 281 | # that the first result is the result. |
| 258 | − - name: Run cloud scenarios | |
| 282 | + - name: Run cloud shard | |
| 259 | 283 | if: matrix.target == 'cloud' |
| 260 | 284 | env: |
| 261 | 285 | MCP_SESSION_TIMEOUT_MS: "3000" |
| 262 | 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 | 288 | working-directory: e2e |
| 265 | 289 | |
| 266 | − - name: Run selfhost scenarios | |
| 267 | − if: matrix.target == 'selfhost' | |
| 268 | − run: bunx vitest run --project selfhost ${{ matrix.shard && format('--shard={0}', matrix.shard) || '' }} | |
| 290 | + - name: Run scenarios | |
| 291 | + if: matrix.target != 'cloud' | |
| 292 | + run: bun scripts/run-ci-shard.ts ${{ matrix.target }} ${{ matrix['shard-index'] }} | |
| 269 | 293 | working-directory: e2e |
| 270 | 294 | |
| 271 | 295 | # Failed runs keep their trace.zip / session.mp4 / step screenshots in |
| @@ -278,56 +302,6 @@ jobs: · 6 unmodified lines | ||
| 278 | 302 | path: e2e/runs/ |
| 279 | 303 | 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 | 305 | desktop-smoke: |
| 332 | 306 | name: Desktop smoke build |
| 333 | 307 | needs: changes |