mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-13 04:02:28 +02:00
ci: run the db project as its own workspaces-c lane
workspaces-b became the slowest PR check (499-593s) once the server shards were rebalanced. The @paperclipai/db project alone was 168-250s of its 436-513s of vitest time (PR runs 38084171761, 38083084276 and 38083020834, 2026-10-10). Vitest's native --shard would not level it: the project is already file-parallel and client.test.ts is 117-189s of its wall time, so a hash-ordered slice can put both slow suites on one runner. The db project now runs as general-workspaces-c in both pr-trusted.yml and release-verify.yml; workspaces-b keeps the other sixteen projects at ~265-275s of vitest time. Local `all` mode still covers every project, and the guard tests assert that the three workspace lanes cover the root Vitest project list exactly once and that both workflows carry the new lane. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
9ba5569030
commit
88433c1be7
5 files changed
+65
-9
No files matched your search
@@ -585,8 +585,16 @@ jobs:
|
||||
group_label: workspaces-a (2/2)
|
||||
shard_index: 1
|
||||
shard_count: 2
|
||||
# workspaces-b became the slowest check (499-593s) once the server
|
||||
# shards were rebalanced: the db project alone was 168-250s of its
|
||||
# 436-513s of vitest time (PR runs 38084171761, 38083084276 and
|
||||
# 38083020834, 2026-10-10). The db project now runs as its own
|
||||
# workspaces-c lane; the rest of workspaces-b is ~265-275s of
|
||||
# vitest time, so both jobs land near 300-350s with setup.
|
||||
- group: general-workspaces-b
|
||||
group_label: workspaces-b
|
||||
- group: general-workspaces-c
|
||||
group_label: workspaces-c
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
|
||||
@@ -174,6 +174,9 @@ jobs:
|
||||
shard_count: 2
|
||||
- group: general-workspaces-b
|
||||
group_label: workspaces-b
|
||||
# Keep parity with pr.yml: the db project runs as its own lane.
|
||||
- group: general-workspaces-c
|
||||
group_label: workspaces-c
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
|
||||
@@ -503,7 +503,7 @@ test("release verify workflow covers the same split test surface as stable PR ve
|
||||
assert.match(buildJob, /persist-credentials: false/);
|
||||
assert.doesNotMatch(buildJob, /cache: pnpm/);
|
||||
|
||||
for (const group of ["general-server-without-chat-or-native-runner", "general-chat", "general-workspaces-a", "general-workspaces-b"]) {
|
||||
for (const group of ["general-server-without-chat-or-native-runner", "general-chat", "general-workspaces-a", "general-workspaces-b", "general-workspaces-c"]) {
|
||||
assert.match(verifyWorkflow, new RegExp(`group: ${group}`));
|
||||
}
|
||||
for (const [group, count] of [["general-server-without-chat-or-native-runner", 10], ["general-chat", 3]]) {
|
||||
|
||||
@@ -107,10 +107,12 @@ test("general shards retain scripts and route-named suites outside the serialize
|
||||
]) assert.ok(general.selectedGeneralServerSuites.includes(file), `missing configured server suite: ${file}`);
|
||||
});
|
||||
|
||||
test("shard flags are rejected for the workspaces-b group", () => {
|
||||
const result = dryRun(["--mode", "general", "--group", "general-workspaces-b", "--shard-index", "0", "--shard-count", "3"]);
|
||||
assert.notEqual(result.status, 0, "workspaces-b must not accept shard flags");
|
||||
});
|
||||
for (const group of ["general-workspaces-b", "general-workspaces-c"]) {
|
||||
test(`shard flags are rejected for the ${group} group`, () => {
|
||||
const result = dryRun(["--mode", "general", "--group", group, "--shard-index", "0", "--shard-count", "3"]);
|
||||
assert.notEqual(result.status, 0, `${group} must not accept shard flags`);
|
||||
});
|
||||
}
|
||||
|
||||
test("workspace lanes cover every non-server project in the root Vitest configuration", () => {
|
||||
const config = readFileSync(path.join(repoRoot, "vitest.config.ts"), "utf8");
|
||||
@@ -118,11 +120,29 @@ test("workspace lanes cover every non-server project in the root Vitest configur
|
||||
assert.ok(roots.includes("server"), "expected the explicit root Vitest project list");
|
||||
const expected = roots.filter(root => root !== "server")
|
||||
.map(root => JSON.parse(readFileSync(path.join(repoRoot, root, "package.json"), "utf8")).name).sort();
|
||||
const actual = ["general-workspaces-a", "general-workspaces-b"]
|
||||
const actual = ["general-workspaces-a", "general-workspaces-b", "general-workspaces-c"]
|
||||
.flatMap(group => dryRunJson(["--mode", "general", "--group", group]).workspaceProjects).sort();
|
||||
assert.deepEqual(actual, expected, "no configured project may be silently omitted or run twice");
|
||||
});
|
||||
|
||||
test("workspaces-c runs the db project alone and workspaces-b no longer carries it", () => {
|
||||
// The db project was 168-250s of the 436-513s workspaces-b vitest time
|
||||
// (PR runs 38084171761, 38083084276 and 38083020834, 2026-10-10), so it
|
||||
// runs in its own lane. The PR and release matrices both carry that lane.
|
||||
const workspacesC = dryRunJson(["--mode", "general", "--group", "general-workspaces-c"]);
|
||||
assert.deepEqual(workspacesC.workspaceProjects, ["@paperclipai/db"]);
|
||||
assert.equal(workspacesC.workspacesVitestShard, null);
|
||||
const workspacesB = dryRunJson(["--mode", "general", "--group", "general-workspaces-b"]);
|
||||
assert.ok(!workspacesB.workspaceProjects.includes("@paperclipai/db"), "db must not run twice");
|
||||
assert.ok(workspacesB.workspaceProjects.length > 0, "workspaces-b must still run its other projects");
|
||||
for (const workflow of ["pr-trusted.yml", "release-verify.yml"]) {
|
||||
const text = readFileSync(path.join(repoRoot, ".github", "workflows", workflow), "utf8");
|
||||
for (const group of ["general-workspaces-b", "general-workspaces-c"]) {
|
||||
assert.match(text, new RegExp(`- group: ${group}\\n\\s+group_label: [^\\n]+\\n(?!\\s+shard_)`), `${workflow} must run ${group} unsharded`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("workspaces-a shards map to Vitest native --shard slices over a stable project list", () => {
|
||||
const shards = [0, 1].map((index) =>
|
||||
dryRunJson([
|
||||
|
||||
@@ -117,9 +117,27 @@ function excludedServerSuites(groupName) {
|
||||
}
|
||||
const generalWorkspacesAGroupName = "general-workspaces-a";
|
||||
const generalWorkspacesBGroupName = "general-workspaces-b";
|
||||
const generalWorkspacesCGroupName = "general-workspaces-c";
|
||||
const generalWorkspacesAProjects = ["@paperclipai/ui", "paperclipai"];
|
||||
const generalWorkspacesBProjects = nonServerProjects.filter((project) => !generalWorkspacesAProjects.includes(project));
|
||||
const generalGroupNames = [generalServerGroupName, generalWorkspacesAGroupName, generalWorkspacesBGroupName];
|
||||
// The db project runs in its own lane. Its vitest invocation took 168-250s
|
||||
// of a 436-513s workspaces-b job (PR runs 38084171761, 38083084276 and
|
||||
// 38083020834, 2026-10-10), which made workspaces-b the slowest check once
|
||||
// the server shards were rebalanced. Vitest's native --shard would not help
|
||||
// here: the project is already file-parallel and client.test.ts alone is
|
||||
// 117-189s of its wall time, so a hash-ordered slice can land both of its
|
||||
// slow suites on one runner. Splitting by project is deterministic and
|
||||
// leaves the remaining projects at ~265-275s of vitest time, roughly level
|
||||
// with this lane.
|
||||
const generalWorkspacesCProjects = ["@paperclipai/db"];
|
||||
const generalWorkspacesBProjects = nonServerProjects.filter(
|
||||
(project) => !generalWorkspacesAProjects.includes(project) && !generalWorkspacesCProjects.includes(project),
|
||||
);
|
||||
const generalGroupNames = [
|
||||
generalServerGroupName,
|
||||
generalWorkspacesAGroupName,
|
||||
generalWorkspacesBGroupName,
|
||||
generalWorkspacesCGroupName,
|
||||
];
|
||||
const allowedGeneralGroupNames = [
|
||||
...generalGroupNames,
|
||||
generalServerWithoutChatGroupName,
|
||||
@@ -520,6 +538,11 @@ function runGeneralGroup(routeTests, groupName, shardIndex = null, shardCount =
|
||||
return;
|
||||
}
|
||||
|
||||
if (groupName === generalWorkspacesCGroupName) {
|
||||
runProjectGroup(generalWorkspacesCProjects, groupName);
|
||||
return;
|
||||
}
|
||||
|
||||
fail(`Unknown group "${groupName}".`);
|
||||
}
|
||||
|
||||
@@ -604,7 +627,9 @@ if (options.dryRun) {
|
||||
? generalWorkspacesAProjects
|
||||
: options.group === generalWorkspacesBGroupName
|
||||
? generalWorkspacesBProjects
|
||||
: null,
|
||||
: options.group === generalWorkspacesCGroupName
|
||||
? generalWorkspacesCProjects
|
||||
: null,
|
||||
workspacesVitestShard:
|
||||
options.group === generalWorkspacesAGroupName &&
|
||||
options.shardCount !== null &&
|
||||
|
||||
Reference in new issue
Block a user