Files
tutti/tools/scripts/publish-packages.test.mjs
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

243 lines
6.8 KiB
JavaScript

import assert from "node:assert/strict";
import test from "node:test";
import {
createPublishedVersionViewArguments,
createPublishArguments,
createReleaseGitEnvironment,
formatPackageGoModuleReleaseTag,
isPublishedVersionListed,
normalizePublishedPackageVersions,
publishPackageGroup,
publishPackageWithRetry,
resolvePackagePublishConcurrency,
resolveReleaseTagNames,
runWithConcurrency
} from "./publish-packages.mjs";
test("createPublishArguments omits provenance by default", () => {
assert.deepEqual(createPublishArguments({ withProvenance: false }), [
"publish",
"--access",
"public",
"--tag",
"latest",
"--no-git-checks"
]);
});
test("createPublishArguments enables provenance when requested", () => {
assert.deepEqual(createPublishArguments({ withProvenance: true }), [
"publish",
"--access",
"public",
"--tag",
"latest",
"--no-git-checks",
"--provenance"
]);
});
test("createPublishedVersionViewArguments queries only the exact immutable version", () => {
assert.deepEqual(
createPublishedVersionViewArguments("@tutti-os/example", "0.0.25"),
["view", "@tutti-os/example@0.0.25", "version", "--json"]
);
});
test("createReleaseGitEnvironment disables husky hooks for CI release pushes", () => {
assert.equal(createReleaseGitEnvironment().HUSKY, "0");
});
test("formatPackageGoModuleReleaseTag uses Go submodule tag shape", () => {
assert.equal(
formatPackageGoModuleReleaseTag("packages/workbench/service", "0.0.25"),
"packages/workbench/service/v0.0.25"
);
});
test("formatPackageGoModuleReleaseTag rejects non-package directories", () => {
assert.throws(
() => formatPackageGoModuleReleaseTag("services/tuttid", "0.0.25"),
/must be under packages/
);
});
test("resolveReleaseTagNames includes package Go module tags", async () => {
const tagNames = await resolveReleaseTagNames("0.0.25");
assert.equal(tagNames[0], "packages-v0.0.25");
assert.equal(
[
"packages/agent/activity-replication/v0.0.25",
"packages/agent/store-sqlite/canonical/v0.0.25",
"packages/appcli/core/v0.0.25",
"packages/device-link/v0.0.25",
"packages/workbench/service/v0.0.25",
"packages/workspace/files/v0.0.25",
"packages/workspace/issues/v0.0.25"
].every((tagName) => tagNames.includes(tagName)),
true
);
});
test("normalizePublishedPackageVersions accepts npm string and array outputs", () => {
assert.deepEqual(normalizePublishedPackageVersions("0.0.1"), ["0.0.1"]);
assert.deepEqual(normalizePublishedPackageVersions(["0.0.1", "0.0.2"]), [
"0.0.1",
"0.0.2"
]);
});
test("isPublishedVersionListed detects already published versions", () => {
assert.equal(isPublishedVersionListed(["0.0.1", "0.0.2"], "0.0.1"), true);
assert.equal(isPublishedVersionListed(["0.0.1", "0.0.2"], "0.0.3"), false);
});
test("resolvePackagePublishConcurrency defaults to four bounded workers", () => {
assert.equal(resolvePackagePublishConcurrency(undefined), 4);
assert.equal(resolvePackagePublishConcurrency("1"), 1);
assert.equal(resolvePackagePublishConcurrency("8"), 8);
assert.throws(
() => resolvePackagePublishConcurrency("0"),
/integer from 1 to 8/
);
assert.throws(
() => resolvePackagePublishConcurrency("9"),
/integer from 1 to 8/
);
assert.throws(
() => resolvePackagePublishConcurrency("4.5"),
/integer from 1 to 8/
);
});
test("publishPackageGroup bounds concurrent publishes and skips existing versions", async () => {
const packages = ["a", "b", "c", "existing"].map((name) => ({
name: `@tutti-os/${name}`
}));
const published = [];
let activePublishes = 0;
let maximumActivePublishes = 0;
let releaseFirstWave;
const firstWave = new Promise((resolve) => {
releaseFirstWave = resolve;
});
await publishPackageGroup({
concurrency: 2,
isPublished: async (name) => name === "@tutti-os/existing",
packages,
publish: async (packageConfig) => {
activePublishes += 1;
maximumActivePublishes = Math.max(
maximumActivePublishes,
activePublishes
);
if (maximumActivePublishes === 2) {
releaseFirstWave();
}
await firstWave;
published.push(packageConfig.name);
activePublishes -= 1;
},
releaseVersion: "0.0.1"
});
assert.equal(maximumActivePublishes, 2);
assert.deepEqual(published.sort(), [
"@tutti-os/a",
"@tutti-os/b",
"@tutti-os/c"
]);
});
test("runWithConcurrency stops admitting work after failure and drains in-flight tasks", async () => {
const expected = new Error("publish failed");
const started = [];
let inFlightFinished = false;
let markSecondStarted;
let markFailureTriggered;
const secondStarted = new Promise((resolve) => {
markSecondStarted = resolve;
});
const failureTriggered = new Promise((resolve) => {
markFailureTriggered = resolve;
});
await assert.rejects(
runWithConcurrency([0, 1, 2, 3], 2, async (item) => {
started.push(item);
if (item === 0) {
await secondStarted;
markFailureTriggered();
throw expected;
}
if (item === 1) {
markSecondStarted();
await failureTriggered;
await new Promise((resolve) => setImmediate(resolve));
inFlightFinished = true;
}
}),
expected
);
assert.deepEqual(started, [0, 1]);
assert.equal(inFlightFinished, true);
});
test("publishPackageWithRetry retries a failed unpublished version", async () => {
let attempts = 0;
const waits = [];
await publishPackageWithRetry({
packageName: "@tutti-os/example",
version: "0.0.1",
async publish() {
attempts += 1;
if (attempts === 1) {
throw new Error("transparency log conflict");
}
},
isPublished: async () => false,
wait: async (attempt) => waits.push(attempt)
});
assert.equal(attempts, 2);
assert.deepEqual(waits, [1]);
});
test("publishPackageWithRetry accepts a version visible after an error", async () => {
let attempts = 0;
await publishPackageWithRetry({
packageName: "@tutti-os/example",
version: "0.0.1",
publish() {
attempts += 1;
throw new Error("registry response was lost");
},
isPublished: () => true,
wait: async () => assert.fail("published version must not be retried")
});
assert.equal(attempts, 1);
});
test("publishPackageWithRetry preserves the final publish error", async () => {
const expected = new Error("permanent publish failure");
let attempts = 0;
await assert.rejects(
publishPackageWithRetry({
packageName: "@tutti-os/example",
version: "0.0.1",
maxAttempts: 2,
publish() {
attempts += 1;
throw expected;
},
isPublished: () => false,
wait: async () => {}
}),
expected
);
assert.equal(attempts, 2);
});