Unified · Split
| @@ -201,7 +201,16 @@ jobs: · 200 unmodified lines | |||
| 201 | # durations plus a conservative weight for new tests. Extra shards | 201 | # durations plus a conservative weight for new tests. Extra shards |
| 202 | # keep each hermetic stack below the PGlite lifetime failure window. | 202 | # keep each hermetic stack below the PGlite lifetime failure window. |
| 203 | - { target: cloud, shard-index: 1, shard-name: 1of16 } | 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 | - { target: cloud, shard-index: 3, shard-name: 3of16 } | 214 | - { target: cloud, shard-index: 3, shard-name: 3of16 } |
| 206 | - { target: cloud, shard-index: 4, shard-name: 4of16 } | 215 | - { target: cloud, shard-index: 4, shard-name: 4of16 } |
| 207 | - { target: cloud, shard-index: 5, shard-name: 5of16 } | 216 | - { target: cloud, shard-index: 5, shard-name: 5of16 } |
| @@ -231,7 +240,7 @@ jobs: · 23 unmodified lines | |||
| 231 | # lane from the two-minute critical path. | 240 | # lane from the two-minute critical path. |
| 232 | - { target: local, shard-index: 1, shard-name: 1of2 } | 241 | - { target: local, shard-index: 1, shard-name: 1of2 } |
| 233 | - { target: local, shard-index: 2, shard-name: 2of2 } | 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 | timeout-minutes: 30 | 244 | timeout-minutes: 30 |
| 236 | steps: | 245 | steps: |
| 237 | - uses: actions/checkout@v4 | 246 | - uses: actions/checkout@v4 |
| @@ -43,7 +43,7 @@ export const OBSERVED_TEST_DURATIONS_MS: Readonly< · 42 unmodified lines | |||
| 43 | "scenarios/connect-handoff-session.test.ts": 10_296, | 43 | "scenarios/connect-handoff-session.test.ts": 10_296, |
| 44 | "scenarios/connect-handoff.test.ts": 7_519, | 44 | "scenarios/connect-handoff.test.ts": 7_519, |
| 45 | "scenarios/connection-remove-confirm.test.ts": 5_197, | 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 | "scenarios/google-photos-preset-ui.test.ts": 5_696, | 47 | "scenarios/google-photos-preset-ui.test.ts": 5_696, |
| 48 | "scenarios/graphql-introspection-health.test.ts": 12_617, | 48 | "scenarios/graphql-introspection-health.test.ts": 12_617, |
| 49 | "scenarios/health-checks-ui.test.ts": 71_165, | 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 | for (const target of CI_TARGETS) { | 115 | for (const target of CI_TARGETS) { |
| 116 | const entries = workflow | 116 | const entries = workflow.matchAll( |
| 117 | .split("\n") | 117 | new RegExp(`-\\s*\\{[^}]*target:\\s*${target},[^}]*shard-index:\\s*(\\d+)`, "g"), |
| 118 | .filter((line) => line.includes(`{ target: ${target}, shard-index:`)); | 118 | ); |
| 119 | const indexes = entries.map((line) => { | 119 | const indexes = [...entries].map((entry) => entry[1]); |
| 120 | const match = /shard-index: (\d+)/.exec(line); | ||
| 121 | return match?.[1]; | ||
| 122 | }); | ||
| 123 | 120 | ||
| 124 | expect(indexes).toEqual( | 121 | expect(indexes).toEqual( |
| 125 | Array.from({ length: CI_SHARD_COUNTS[target] }, (_, index) => String(index + 1)), | 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 | local: ["local"], | 60 | local: ["local"], |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| 63 | // A file this long already consumes most of the two-minute budget after the | 63 | // A file this long already consumes most of the two-minute budget after |
| 64 | // target stack boots. Keep it alone instead of balancing unrelated work onto it. | 64 | // dependency linking, target startup, and Vitest global setup. Keep it alone |
| 65 | const ISOLATED_TEST_DURATION_MS = 45_000; | 65 | // instead of balancing unrelated work onto it. |
| 66 | const ISOLATED_TEST_DURATION_MS = 35_000; | ||
| 66 | 67 | ||
| 67 | const comparePaths = (left: string, right: string): number => | 68 | const comparePaths = (left: string, right: string): number => |
| 68 | left < right ? -1 : left > right ? 1 : 0; | 69 | left < right ? -1 : left > right ? 1 : 0; |