mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 09:41:04 +01:00
Merge current master and preserve Pi instruction-copy imports
This commit is contained in:
commit
2c88adc683
45 files changed
+6154
-4543
No files matched your search
@@ -244,10 +244,10 @@ 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", "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"]) {
|
||||
assert.match(verifyWorkflow, new RegExp(`group: ${group}`));
|
||||
}
|
||||
for (const [group, count] of [["general-server-without-chat", 10], ["general-chat", 3]]) {
|
||||
for (const [group, count] of [["general-server-without-chat-or-native-runner", 10], ["general-chat", 3]]) {
|
||||
const rows = [...verifyWorkflow.matchAll(new RegExp(`group: ${group}\\n\\s+group_label: [^\\n]+\\n\\s+shard_index: (\\d+)\\n\\s+shard_count: (\\d+)`, "g"))];
|
||||
assert.deepEqual(rows.map((row) => [Number(row[1]), Number(row[2])]),
|
||||
Array.from({ length: count }, (_, index) => [index, count]));
|
||||
@@ -271,6 +271,30 @@ test("release verify workflow covers the same split test surface as stable PR ve
|
||||
assert.match(verifyWorkflow, /pnpm test:run:serialized -- --shard-index/);
|
||||
});
|
||||
|
||||
test("release verification builds native test binaries in a required Rust-cached lane", () => {
|
||||
const workflow = readWorkflow("release-verify.yml");
|
||||
const runnerJob = workflow.match(/ verify_paperclip_runner:\n[\s\S]*?(?=\n [A-Za-z0-9_-]+:|$)/)?.[0] ?? "";
|
||||
assert.equal((runnerJob.match(/- lane: server-integration/g) ?? []).length, 1);
|
||||
assert.doesNotMatch(runnerJob, /continue-on-error/);
|
||||
assert.match(runnerJob, /timeout-minutes: 20/);
|
||||
assert.match(runnerJob, /shared-key: release-runner-v2/);
|
||||
assert.match(runnerJob, /cache-workspace-crates: false/);
|
||||
assert.match(runnerJob, /cache-bin: false/);
|
||||
assert.match(runnerJob, /save-if: \$\{\{ matrix\.lane == 'rust'/);
|
||||
assert.match(runnerJob, /Build native server test binaries\n\s+if: \$\{\{ matrix\.lane == 'server-integration' \}\}\n\s+timeout-minutes: 10/);
|
||||
assert.match(runnerJob, /pnpm build:rust\n\s+cargo build --release --manifest-path runner\/Cargo\.toml --locked -p paperclip-runner-core --bin paperclip-runnerd --bin fake-codex-app-server/);
|
||||
assert.match(runnerJob, /Run native server integration suites\n\s+if: \$\{\{ matrix\.lane == 'server-integration' \}\}\n\s+run: pnpm test:run:general -- --group general-server-native-runner/);
|
||||
assert.ok(runnerJob.indexOf("Cache Runner Rust dependencies") < runnerJob.indexOf("Build native server test binaries"));
|
||||
assert.ok(runnerJob.indexOf("Build native server test binaries") < runnerJob.indexOf("Run native server integration suites"));
|
||||
|
||||
// The reusable workflow result includes every matrix child. Its caller must
|
||||
// await that result without an override that can certify a failed native lane.
|
||||
const cloud = readWorkflow("cloud-readiness.yml");
|
||||
assert.match(cloud, /verify:[\s\S]*?uses: \.\/\.github\/workflows\/release-verify\.yml/);
|
||||
assert.match(cloud, /source_verified:[\s\S]*?needs: \[verify\]/);
|
||||
assert.doesNotMatch(cloud, /continue-on-error|always\(\)/);
|
||||
});
|
||||
|
||||
test("Runner eval workflows pin actions and gate paid live execution", () => {
|
||||
const actionPinWorkflows = [
|
||||
readWorkflow("release-verify.yml"),
|
||||
|
||||
@@ -319,9 +319,8 @@ test("12 PR without-chat shards plus the dedicated chat and native-runner lanes
|
||||
assert.ok(defaultRun.generalServerSuiteCount === full.generalServerSuiteCount);
|
||||
});
|
||||
|
||||
// Mirrors release-verify.yml (10 shards, called by the Release and Cloud
|
||||
// readiness workflows) and local runs: no Rust-cached vitest lane exists
|
||||
// there, so the native-runner suite must stay in the server shards.
|
||||
// The legacy group and local default must remain complete when a caller has
|
||||
// not selected a separate native lane.
|
||||
for (const [caller, envOverrides] of [["Release", { GITHUB_WORKFLOW: "Release" }], ["no ambient workflow", {}]]) {
|
||||
test(`10 without-chat shards under ${caller} keep the native-runner suite and cover the server group with chat alone`, () => {
|
||||
const full = dryRunJson(["--mode", "general", "--group", "general-server", "--shard-index", "0", "--shard-count", "1"], envOverrides);
|
||||
@@ -339,6 +338,23 @@ for (const [caller, envOverrides] of [["Release", { GITHUB_WORKFLOW: "Release" }
|
||||
});
|
||||
}
|
||||
|
||||
// Release verification selects its dedicated lane explicitly. Do not infer it
|
||||
// from the caller name: previews and future workflow callers need the same cover.
|
||||
for (const caller of ["Release", "Cloud readiness", "another caller"]) {
|
||||
test(`release server, chat, and native lanes cover every server suite once under ${caller}`, () => {
|
||||
const env = { GITHUB_WORKFLOW: caller };
|
||||
const full = dryRunJson(["--mode", "general", "--group", "general-server", "--shard-index", "0", "--shard-count", "1"], env);
|
||||
const files = Array.from({ length: 10 }, (_, index) => dryRunJson([
|
||||
"--mode", "general", "--group", "general-server-without-chat-or-native-runner",
|
||||
"--shard-index", String(index), "--shard-count", "10",
|
||||
], env)).flatMap((shard) => shard.selectedGeneralServerSuites);
|
||||
const native = dryRunJson(["--mode", "general", "--group", "general-server-native-runner"], env);
|
||||
const combined = [...files, chatSuitePath, ...native.selectedGeneralServerSuites];
|
||||
assert.equal(new Set(combined).size, combined.length, "lanes must not overlap");
|
||||
assert.deepEqual(combined.sort(), full.selectedGeneralServerSuites.sort());
|
||||
});
|
||||
}
|
||||
|
||||
test("the native-runner lane runs exactly the cargo-dependent suites", () => {
|
||||
const lane = dryRunJson(["--mode", "general", "--group", "general-server-native-runner"]);
|
||||
assert.deepEqual(lane.selectedGeneralServerSuites, [
|
||||
|
||||
@@ -76,6 +76,7 @@ const generalModeName = "general";
|
||||
const allModeName = "all";
|
||||
const generalServerGroupName = "general-server";
|
||||
const generalServerWithoutChatGroupName = "general-server-without-chat";
|
||||
const generalServerWithoutChatOrNativeRunnerGroupName = "general-server-without-chat-or-native-runner";
|
||||
const generalChatGroupName = "general-chat";
|
||||
const generalServerNativeRunnerGroupName = "general-server-native-runner";
|
||||
const chatSuite = "server/src/__tests__/chat-channels.integration.test.ts";
|
||||
@@ -92,10 +93,9 @@ const nativeRunnerSuites = [
|
||||
// In the PR workflow (pr.yml, the caller of pr-trusted.yml — reusable
|
||||
// workflows inherit the caller's GITHUB_WORKFLOW), the last Verify Paperclip
|
||||
// Runner vitest shard runs the native-runner group instead, because those
|
||||
// lanes restore the shared release-runner-v1 Rust cache (see
|
||||
// lanes restore the shared release-runner-v2 Rust cache (see
|
||||
// packages/paperclip-runner/scripts/run-pr-vitest-lane.mjs). Every other
|
||||
// caller — local runs, release-verify.yml under the Release and Cloud
|
||||
// readiness workflows — keeps the suite in the server shards, so a renamed or
|
||||
// caller of the same group keeps the suite in the server shards, so a renamed or
|
||||
// unknown workflow degrades to today's slower-but-covered behavior rather
|
||||
// than dropping the suite.
|
||||
const prWorkflowName = "PR";
|
||||
@@ -103,6 +103,18 @@ const nativeRunnerSuiteRunsInRustCachedLane = process.env.GITHUB_WORKFLOW === pr
|
||||
const withoutChatExcludedSuites = nativeRunnerSuiteRunsInRustCachedLane
|
||||
? [chatSuite, ...nativeRunnerSuites]
|
||||
: [chatSuite];
|
||||
// Release verification selects this explicit group and runs the omitted suites
|
||||
// in its cached Runner job. Local callers keep the complete default group.
|
||||
const generalServerGroups = [
|
||||
generalServerGroupName,
|
||||
generalServerWithoutChatGroupName,
|
||||
generalServerWithoutChatOrNativeRunnerGroupName,
|
||||
];
|
||||
function excludedServerSuites(groupName) {
|
||||
if (groupName === generalServerWithoutChatOrNativeRunnerGroupName) return [chatSuite, ...nativeRunnerSuites];
|
||||
if (groupName === generalServerWithoutChatGroupName) return withoutChatExcludedSuites;
|
||||
return [];
|
||||
}
|
||||
const generalWorkspacesAGroupName = "general-workspaces-a";
|
||||
const generalWorkspacesBGroupName = "general-workspaces-b";
|
||||
const generalWorkspacesAProjects = ["@paperclipai/ui", "paperclipai"];
|
||||
@@ -111,6 +123,7 @@ const generalGroupNames = [generalServerGroupName, generalWorkspacesAGroupName,
|
||||
const allowedGeneralGroupNames = [
|
||||
...generalGroupNames,
|
||||
generalServerWithoutChatGroupName,
|
||||
generalServerWithoutChatOrNativeRunnerGroupName,
|
||||
generalChatGroupName,
|
||||
generalServerNativeRunnerGroupName,
|
||||
];
|
||||
@@ -290,7 +303,7 @@ function parseCliOptions(argv) {
|
||||
const shardAllowed =
|
||||
mode === serializedModeName ||
|
||||
(mode === generalModeName &&
|
||||
([generalServerGroupName, generalServerWithoutChatGroupName, generalChatGroupName, generalWorkspacesAGroupName].includes(group)));
|
||||
([...generalServerGroups, generalChatGroupName, generalWorkspacesAGroupName].includes(group)));
|
||||
if (!shardAllowed && shardIndex !== null) {
|
||||
fail(
|
||||
"--shard-index/--shard-count are only valid with serialized mode or a shardable general server/chat/workspaces-a group.",
|
||||
@@ -448,14 +461,9 @@ function runGeneralGroup(routeTests, groupName, shardIndex = null, shardCount =
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (groupName === generalServerGroupName || groupName === generalServerWithoutChatGroupName) {
|
||||
// In the PR workflow the without-chat group also leaves the native-runner
|
||||
// suite to the Rust-cached vitest lane; the full general-server group
|
||||
// (local runs) keeps both.
|
||||
const withoutChat = groupName === generalServerWithoutChatGroupName;
|
||||
const files = withoutChat
|
||||
? generalServerTestFiles.filter((file) => !withoutChatExcludedSuites.includes(file))
|
||||
: generalServerTestFiles;
|
||||
if (generalServerGroups.includes(groupName)) {
|
||||
const excludedSuites = excludedServerSuites(groupName);
|
||||
const files = generalServerTestFiles.filter((file) => !excludedSuites.includes(file));
|
||||
if (shardCount !== null && shardCount > 1) {
|
||||
const shardFiles = selectGeneralServerShard(
|
||||
files,
|
||||
@@ -483,10 +491,8 @@ function runGeneralGroup(routeTests, groupName, shardIndex = null, shardCount =
|
||||
}
|
||||
|
||||
const excludeRouteArgs = routeTests.flatMap((file) => ["--exclude", file.serverPath]);
|
||||
if (withoutChat) {
|
||||
for (const suite of withoutChatExcludedSuites) {
|
||||
excludeRouteArgs.push("--exclude", suite.replace(/^server\//, ""));
|
||||
}
|
||||
for (const suite of excludedSuites) {
|
||||
excludeRouteArgs.push("--exclude", suite.replace(/^server\//, ""));
|
||||
}
|
||||
runVitest(
|
||||
[
|
||||
@@ -584,12 +590,10 @@ if (options.dryRun) {
|
||||
options.mode === generalModeName && options.group === generalServerNativeRunnerGroupName
|
||||
? nativeRunnerSuites
|
||||
: options.mode === generalModeName &&
|
||||
[generalServerGroupName, generalServerWithoutChatGroupName].includes(options.group) &&
|
||||
generalServerGroups.includes(options.group) &&
|
||||
options.shardCount !== null
|
||||
? selectGeneralServerShard(
|
||||
options.group === generalServerWithoutChatGroupName
|
||||
? generalServerTestFiles.filter((file) => !withoutChatExcludedSuites.includes(file))
|
||||
: generalServerTestFiles,
|
||||
generalServerTestFiles.filter((file) => !excludedServerSuites(options.group).includes(file)),
|
||||
options.shardIndex,
|
||||
options.shardCount,
|
||||
generalServerShardDurations,
|
||||
|
||||
Reference in new issue
Block a user