test(ci): add plugin prerelease suite to CI (#73741)

* test(ci): route plugin prerelease coverage to plugin shard

* test(ci): add plugin prerelease suite to CI

* fix(ci): preserve pnpm path in plugin prerelease shard

* fix(ci): avoid inheriting secrets for plugin prerelease suite
This commit is contained in:
Vincent Koc
2026-04-28 14:52:03 -07:00
committed by GitHub
parent 69fb7455c6
commit e7947948b6
8 changed files with 498 additions and 2 deletions

View File

@@ -0,0 +1,122 @@
import { BUNDLED_PLUGIN_INSTALL_UNINSTALL_SHARDS } from "./docker-e2e-scenarios.mjs";
export const PLUGIN_PRERELEASE_REQUIRED_SURFACES = Object.freeze([
"package-artifact",
"bundled-lifecycle",
"external-plugins",
"update-no-op",
"channel-runtime-deps",
"doctor-fix",
"config-round-trip",
"gateway-bootstrap",
"sdk-compatibility",
"status-diagnostics",
"live-ish-availability",
]);
const pluginPrereleaseDockerLanes = Object.freeze([
{
lane: "npm-onboard-channel-agent",
surfaces: ["package-artifact", "gateway-bootstrap", "status-diagnostics"],
},
{
lane: "doctor-switch",
surfaces: ["package-artifact", "doctor-fix"],
},
{
lane: "update-channel-switch",
surfaces: ["package-artifact", "channel-runtime-deps", "update-no-op"],
},
{
lane: "bundled-channel-deps-compat",
surfaces: ["package-artifact", "channel-runtime-deps", "gateway-bootstrap"],
},
{
lane: "plugins-offline",
surfaces: ["external-plugins", "sdk-compatibility", "status-diagnostics"],
},
{
lane: "plugins",
surfaces: ["external-plugins", "sdk-compatibility", "status-diagnostics"],
},
{
lane: "plugin-update",
surfaces: ["package-artifact", "update-no-op"],
},
{
lane: "config-reload",
surfaces: ["config-round-trip", "gateway-bootstrap"],
},
{
lane: "gateway-network",
surfaces: ["gateway-bootstrap", "status-diagnostics"],
},
{
lane: "mcp-channels",
surfaces: ["gateway-bootstrap", "status-diagnostics"],
},
{
lane: "cron-mcp-cleanup",
surfaces: ["gateway-bootstrap", "status-diagnostics"],
},
...Array.from({ length: BUNDLED_PLUGIN_INSTALL_UNINSTALL_SHARDS }, (_, index) => ({
lane: `bundled-plugin-install-uninstall-${index}`,
surfaces: ["bundled-lifecycle", "package-artifact", "status-diagnostics"],
})),
]);
const staticChecks = Object.freeze([
{
check: "test:extensions:package-boundary:compile",
checkName: "checks-plugin-prerelease-package-boundary-compile",
command: "pnpm run test:extensions:package-boundary:compile",
surfaces: ["package-artifact", "sdk-compatibility"],
},
{
check: "test:extensions:package-boundary:canary",
checkName: "checks-plugin-prerelease-package-boundary-canary",
command: "pnpm run test:extensions:package-boundary:canary",
surfaces: ["package-artifact", "sdk-compatibility"],
},
{
check: "live-ish-availability",
checkName: "checks-plugin-prerelease-live-ish-availability",
command: "node scripts/plugin-prerelease-liveish-matrix.mjs",
surfaces: ["live-ish-availability"],
},
]);
function coveredSurfaces(entries) {
return [
...new Set(
entries
.flatMap((entry) => entry.surfaces)
.filter((surface) => typeof surface === "string" && surface.length > 0),
),
].toSorted((a, b) => a.localeCompare(b));
}
export function createPluginPrereleaseTestPlan() {
const dockerLanes = pluginPrereleaseDockerLanes.map((entry) => entry.lane);
const allEntries = [...pluginPrereleaseDockerLanes, ...staticChecks];
return {
dockerLanes,
staticChecks: staticChecks.map((entry) => ({
check: entry.check,
checkName: entry.checkName,
command: entry.command,
surfaces: entry.surfaces.slice(),
})),
surfaces: coveredSurfaces(allEntries),
};
}
export function assertPluginPrereleaseTestPlanComplete(plan = createPluginPrereleaseTestPlan()) {
const missing = PLUGIN_PRERELEASE_REQUIRED_SURFACES.filter(
(surface) => !plan.surfaces.includes(surface),
);
if (missing.length > 0) {
throw new Error(`Plugin prerelease test plan is missing surfaces: ${missing.join(", ")}`);
}
return plan;
}

View File

@@ -0,0 +1,54 @@
const LIVEISH_INPUTS = Object.freeze([
{
probe: "provider-openai",
env: ["OPENAI_API_KEY", "OPENAI_BASE_URL"],
},
{
probe: "provider-anthropic",
env: ["ANTHROPIC_API_KEY", "ANTHROPIC_API_TOKEN"],
},
{
probe: "provider-mistral",
env: ["MISTRAL_API_KEY"],
},
{
probe: "provider-openrouter",
env: ["OPENROUTER_API_KEY"],
},
{
probe: "channel-telegram",
env: ["TELEGRAM_BOT_TOKEN", "OPENCLAW_TELEGRAM_BOT_TOKEN"],
},
{
probe: "channel-discord",
env: ["DISCORD_TOKEN", "OPENCLAW_DISCORD_TOKEN"],
},
{
probe: "channel-slack",
env: ["SLACK_BOT_TOKEN", "OPENCLAW_SLACK_BOT_TOKEN"],
},
{
probe: "channel-whatsapp",
env: ["WHATSAPP_ACCESS_TOKEN", "OPENCLAW_WHATSAPP_ACCESS_TOKEN"],
},
]);
function hasValue(name) {
return typeof process.env[name] === "string" && process.env[name].trim().length > 0;
}
const rows = LIVEISH_INPUTS.map((entry) => ({
available: entry.env.some(hasValue),
env: entry.env,
probe: entry.probe,
}));
console.log("Plugin prerelease live-ish availability matrix:");
for (const row of rows) {
const status = row.available ? "present" : "missing";
console.log(`- ${row.probe}: ${status} (${row.env.join(", ")})`);
}
if (!rows.some((row) => row.available)) {
console.log("No live-ish credentials present; skipping external probes by design.");
}

View File

@@ -247,7 +247,15 @@ const TOOLING_SOURCE_TEST_TARGETS = new Map([
["scripts/lib/extension-test-plan.mjs", ["test/scripts/test-extension.test.ts"]],
["scripts/lib/vitest-batch-runner.mjs", ["test/scripts/test-extension.test.ts"]],
["scripts/lib/ci-node-test-plan.mjs", ["test/scripts/ci-node-test-plan.test.ts"]],
[
"scripts/lib/plugin-prerelease-test-plan.mjs",
["test/scripts/plugin-prerelease-test-plan.test.ts"],
],
["scripts/lib/vitest-shard-timings.mjs", ["test/scripts/vitest-shard-timings.test.ts"]],
[
"scripts/plugin-prerelease-liveish-matrix.mjs",
["test/scripts/plugin-prerelease-test-plan.test.ts"],
],
["scripts/test-projects.mjs", ["test/scripts/test-projects.test.ts"]],
["scripts/test-projects.test-support.d.mts", ["test/scripts/test-projects.test.ts"]],
["scripts/test-projects.test-support.mjs", ["test/scripts/test-projects.test.ts"]],
@@ -258,6 +266,10 @@ const TOOLING_TEST_TARGETS = new Map([
["test/scripts/changed-lanes.test.ts", ["test/scripts/changed-lanes.test.ts"]],
["test/scripts/live-docker-stage.test.ts", ["test/scripts/live-docker-stage.test.ts"]],
["test/scripts/openclaw-test-state.test.ts", ["test/scripts/openclaw-test-state.test.ts"]],
[
"test/scripts/plugin-prerelease-test-plan.test.ts",
["test/scripts/plugin-prerelease-test-plan.test.ts"],
],
["test/scripts/test-projects.test.ts", ["test/scripts/test-projects.test.ts"]],
["test/scripts/testbox-sync-sanity.test.ts", ["test/scripts/testbox-sync-sanity.test.ts"]],
[