Files
openclaw/test/scripts/release-candidate-checklist.test.ts
2026-06-03 08:19:03 +02:00

175 lines
5.1 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import {
buildPublishCommand,
githubApi,
parseArgs,
parseRunIdFromDispatchOutput,
resolveArtifactName,
} from "../../scripts/release-candidate-checklist.mjs";
describe("release candidate checklist", () => {
it("requires run ids when dispatch is disabled", () => {
expect(() => parseArgs(["--tag", "v2026.5.14-beta.3", "--skip-dispatch"])).toThrow(
"--skip-dispatch requires --full-release-run and --npm-preflight-run",
);
});
it("stops parsing options after the argument terminator", () => {
const options = parseArgs([
"--tag",
"v2026.5.14-beta.3",
"--full-release-run",
"111",
"--npm-preflight-run",
"222",
"--skip-dispatch",
"--",
"--plugin-publish-scope",
"selected",
]);
expect(options.pluginPublishScope).toBe("all-publishable");
});
it("accepts package-manager argument separators before script options", () => {
const options = parseArgs([
"--",
"--tag",
"v2026.5.14-beta.3",
"--full-release-run",
"111",
"--npm-preflight-run",
"222",
"--skip-dispatch",
"--skip-parallels",
]);
expect(options.tag).toBe("v2026.5.14-beta.3");
expect(options.skipParallels).toBe(true);
});
it("builds the gated release publish command from green evidence inputs", () => {
const options = {
...parseArgs([
"--tag",
"v2026.5.14-beta.3",
"--workflow-ref",
"release/2026.5.14",
"--full-release-run",
"111",
"--npm-preflight-run",
"222",
"--skip-dispatch",
]),
workflowRef: "release/2026.5.14",
};
expect(buildPublishCommand(options)).toContain("'full_release_validation_run_id=111'");
expect(buildPublishCommand(options)).toContain("'preflight_run_id=222'");
expect(buildPublishCommand(options)).toContain("'tag=v2026.5.14-beta.3'");
expect(buildPublishCommand(options)).toContain("'plugin_publish_scope=all-publishable'");
});
it("carries the Telegram proof run into the publish command when available", () => {
const options = {
...parseArgs([
"--tag",
"v2026.5.14-beta.3",
"--workflow-ref",
"release/2026.5.14",
"--full-release-run",
"111",
"--npm-preflight-run",
"222",
"--skip-dispatch",
]),
workflowRef: "release/2026.5.14",
npmTelegramRunId: "333",
};
expect(buildPublishCommand(options)).toContain("'npm_telegram_run_id=333'");
});
it("requires explicit plugin names for selected plugin publish scope", () => {
expect(() =>
parseArgs(["--tag", "v2026.5.14-beta.3", "--plugin-publish-scope", "selected"]),
).toThrow("--plugin-publish-scope selected requires --plugins");
});
it("rejects selected plugin publish scope for release candidates", () => {
expect(() =>
parseArgs([
"--tag",
"v2026.5.14-beta.3",
"--plugin-publish-scope",
"selected",
"--plugins",
"@openclaw/diffs",
]),
).toThrow("release candidates publish OpenClaw with --plugin-publish-scope all-publishable");
});
it("extracts a workflow run id from gh dispatch output", () => {
expect(
parseRunIdFromDispatchOutput(
"https://github.com/openclaw/openclaw/actions/runs/25922042055\n",
),
).toBe("25922042055");
});
it("falls back to a single compatible artifact from the same run", () => {
expect(
resolveArtifactName(
[{ name: "openclaw-npm-preflight-dba00", expired: false }],
"openclaw-npm-preflight-v2026.5.16-beta.2",
"openclaw-npm-preflight-",
),
).toBe("openclaw-npm-preflight-dba00");
});
it("bounds GitHub API requests with a timeout signal", async () => {
const fetchImpl = vi.fn(async (_url: string, init?: RequestInit) => {
expect(init?.signal).toBeInstanceOf(AbortSignal);
expect(init?.headers).toMatchObject({
Accept: "application/vnd.github+json",
Authorization: "Bearer test-token",
"X-GitHub-Api-Version": "2022-11-28",
});
return {
ok: true,
json: async () => ({ workflow_runs: [] }),
};
});
await expect(
githubApi("repos/openclaw/openclaw/actions/runs", {
fetchImpl,
timeoutMs: 1234,
token: "test-token",
}),
).resolves.toEqual({ workflow_runs: [] });
expect(fetchImpl).toHaveBeenCalledWith(
"https://api.github.com/repos/openclaw/openclaw/actions/runs",
expect.objectContaining({
signal: expect.any(AbortSignal),
}),
);
});
it("includes the GitHub API path when a request times out", async () => {
const fetchImpl = vi.fn(async () => {
throw new DOMException("request timed out", "TimeoutError");
});
await expect(
githubApi("repos/openclaw/openclaw/actions/runs/123/jobs", {
fetchImpl,
timeoutMs: 5,
token: "test-token",
}),
).rejects.toThrow(
"GitHub API repos/openclaw/openclaw/actions/runs/123/jobs timed out after 5ms",
);
});
});