| 250 | /// `bucket` key, which contains the CLI flags we must pass to `cargo` to run |
| 251 | /// tests for just this config's subset of crates. |
| 252 | async function shard(configs) { |
| 253 | const members = await getWorkspaceMembers(); |
| 254 | |
| 255 | // Divide the workspace crates into N disjoint subsets. Crates that are |
| 256 | // particularly expensive to compile and test form their own singleton subset. |
| 257 | // A bucket is either a Set of crate names (used as-is for `cargo test |
| 258 | // --workspace --exclude ...`) or an object `{ crate, sub }` describing a |
| 259 | // single-crate bucket that should be further split by `--test` filter. |
| 260 | const singleBucketCrateNames = new Set(SINGLE_CRATE_BUCKETS.map(singleBucketCrateName)); |
| 261 | const buckets = Array.from({ length: GENERIC_BUCKETS }, _ => new Set()); |
| 262 | let i = 0; |
| 263 | for (const crate of members) { |
| 264 | if (singleBucketCrateNames.has(crate)) continue; |
| 265 | buckets[i].add(crate); |
| 266 | i = (i + 1) % GENERIC_BUCKETS; |
| 267 | } |
| 268 | for (const entry of SINGLE_CRATE_BUCKETS) { |
| 269 | if (typeof entry === "string") { |
| 270 | buckets.push(new Set([entry])); |
| 271 | } else { |
| 272 | // A crate with sub-buckets: push one bucket per `sub` entry, retaining |
| 273 | // the crate name and extra-args for naming and bucket-arg expansion. |
| 274 | for (const sub of entry.sub) { |
| 275 | buckets.push({ crate: entry.crate, name: sub.name, args: sub.args }); |
| 276 | } |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | // For each config, expand it into N configs, one for each disjoint set we |
| 281 | // created above. |
| 282 | const sharded = []; |
| 283 | for (const config of configs) { |
| 284 | // If `crates` is specified, don't shard against the generic buckets. |
| 285 | // A string value produces a single job for that crate; an array value |
| 286 | // produces one job per crate with the crate name appended to `name`. |
| 287 | if (config.crates) { |
| 288 | const cratesList = Array.isArray(config.crates) ? config.crates : [config.crates]; |
| 289 | const useSuffix = Array.isArray(config.crates); |
| 290 | for (const crate of cratesList) { |
| 291 | sharded.push(Object.assign( |
| 292 | {}, |
| 293 | config, |
| 294 | { |
| 295 | name: useSuffix ? `${config.name} (${crate})` : config.name, |
| 296 | bucket: members |
| 297 | .map(c => c === crate ? `--package ${c}` : `--exclude ${c}`) |
| 298 | .join(" "), |
| 299 | } |
| 300 | )); |
| 301 | } |
| 302 | continue; |
| 303 | } |
| 304 | |
| 305 | let nbucket = 1; |
| 306 | for (const bucket of buckets) { |
| 307 | let bucket_name; |
| 308 | let bucket_args; |
| 309 | if (bucket instanceof Set) { |