Unified · Split
| @@ -201,7 +201,16 @@ jobs: · 200 unmodified lines | ||
| 201 | 201 | # durations plus a conservative weight for new tests. Extra shards |
| 202 | 202 | # keep each hermetic stack below the PGlite lifetime failure window. |
| 203 | 203 | - { target: cloud, shard-index: 1, shard-name: 1of16 } |
| 204 | − - { target: cloud, shard-index: 2, shard-name: 2of16 } | |
| 204 | + # This shard owns the intentional 65-second human-delay approval | |
| 205 | + # scenario. Extra CPU cannot shorten that assertion, but it does keep | |
| 206 | + # dependency linking and the cloud stack's startup outside the | |
| 207 | + # remaining two-minute wall-clock budget. | |
| 208 | + - { | |
| 209 | + target: cloud, | |
| 210 | + shard-index: 2, | |
| 211 | + shard-name: 2of16, | |
| 212 | + runner: blacksmith-8vcpu-ubuntu-2404, | |
| 213 | + } | |
| 205 | 214 | - { target: cloud, shard-index: 3, shard-name: 3of16 } |
| 206 | 215 | - { target: cloud, shard-index: 4, shard-name: 4of16 } |
| 207 | 216 | - { target: cloud, shard-index: 5, shard-name: 5of16 } |
| @@ -231,7 +240,7 @@ jobs: · 23 unmodified lines | ||
| 231 | 240 | # lane from the two-minute critical path. |
| 232 | 241 | - { target: local, shard-index: 1, shard-name: 1of2 } |
| 233 | 242 | - { target: local, shard-index: 2, shard-name: 2of2 } |
| 234 | − runs-on: blacksmith-4vcpu-ubuntu-2404 | |
| 243 | + runs-on: ${{ matrix.runner || 'blacksmith-4vcpu-ubuntu-2404' }} | |
| 235 | 244 | timeout-minutes: 30 |
| 236 | 245 | steps: |
| 237 | 246 | - uses: actions/checkout@v4 |
| @@ -43,7 +43,7 @@ export const OBSERVED_TEST_DURATIONS_MS: Readonly< · 42 unmodified lines | ||
| 43 | 43 | "scenarios/connect-handoff-session.test.ts": 10_296, |
| 44 | 44 | "scenarios/connect-handoff.test.ts": 7_519, |
| 45 | 45 | "scenarios/connection-remove-confirm.test.ts": 5_197, |
| 46 | − "scenarios/google-health-checks.test.ts": 20_737, | |
| 46 | + "scenarios/google-health-checks.test.ts": 39_421, | |
| 47 | 47 | "scenarios/google-photos-preset-ui.test.ts": 5_696, |
| 48 | 48 | "scenarios/graphql-introspection-health.test.ts": 12_617, |
| 49 | 49 | "scenarios/health-checks-ui.test.ts": 71_165, |
| @@ -113,17 +113,27 @@ describe("CI shard planning", () => { · 112 unmodified lines | ||
| 113 | 113 | ); |
| 114 | 114 | |
| 115 | 115 | for (const target of CI_TARGETS) { |
| 116 | − const entries = workflow | |
| 117 | − .split("\n") | |
| 118 | − .filter((line) => line.includes(`{ target: ${target}, shard-index:`)); | |
| 119 | − const indexes = entries.map((line) => { | |
| 120 | − const match = /shard-index: (\d+)/.exec(line); | |
| 121 | − return match?.[1]; | |
| 122 | − }); | |
| 116 | + const entries = workflow.matchAll( | |
| 117 | + new RegExp(`-\\s*\\{[^}]*target:\\s*${target},[^}]*shard-index:\\s*(\\d+)`, "g"), | |
| 118 | + ); | |
| 119 | + const indexes = [...entries].map((entry) => entry[1]); | |
| 123 | 120 | |
| 124 | 121 | expect(indexes).toEqual( |
| 125 | 122 | Array.from({ length: CI_SHARD_COUNTS[target] }, (_, index) => String(index + 1)), |
| 126 | 123 | ); |
| 127 | 124 | } |
| 125 | + | |
| 126 | + const cloudPlan = await planTargetShards( | |
| 127 | + "cloud", | |
| 128 | + fileURLToPath(new URL("..", import.meta.url)), | |
| 129 | + ); | |
| 130 | + const approvalShard = cloudPlan.find((shard) => | |
| 131 | + shard.files.includes("scenarios/artifact-approval.test.ts"), | |
| 132 | + ); | |
| 133 | + expect(approvalShard?.files).toEqual(["scenarios/artifact-approval.test.ts"]); | |
| 134 | + const acceleratedEntry = new RegExp( | |
| 135 | + `-\\s*\\{[^}]*target:\\s*cloud,[^}]*shard-index:\\s*${approvalShard?.index},[^}]*runner:\\s*blacksmith-8vcpu-ubuntu-2404`, | |
| 136 | + ); | |
| 137 | + expect(workflow).toMatch(acceleratedEntry); | |
| 128 | 138 | }); |
| 129 | 139 | }); |
| @@ -60,9 +60,10 @@ const testDirectories: Readonly<Record<CiTarget, readonly string[]>> = { · 59 unmodified lines | ||
| 60 | 60 | local: ["local"], |
| 61 | 61 | }; |
| 62 | 62 | |
| 63 | −// A file this long already consumes most of the two-minute budget after the | |
| 64 | −// target stack boots. Keep it alone instead of balancing unrelated work onto it. | |
| 65 | −const ISOLATED_TEST_DURATION_MS = 45_000; | |
| 63 | +// A file this long already consumes most of the two-minute budget after | |
| 64 | +// dependency linking, target startup, and Vitest global setup. Keep it alone | |
| 65 | +// instead of balancing unrelated work onto it. | |
| 66 | +const ISOLATED_TEST_DURATION_MS = 35_000; | |
| 66 | 67 | |
| 67 | 68 | const comparePaths = (left: string, right: string): number => |
| 68 | 69 | left < right ? -1 : left > right ? 1 : 0; |