mirror of
https://github.com/sinanyuntu/trade-message-center.git
synced 2026-09-17 13:22:11 +08:00
203 lines
7.6 KiB
JavaScript
203 lines
7.6 KiB
JavaScript
// 验证发布命令的版本和 Git 门禁。
|
|
|
|
import assert from "node:assert/strict";
|
|
import { mkdtempSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import test from "node:test";
|
|
|
|
import { prepareRelease, publishRelease } from "./release.mjs";
|
|
|
|
const createWorkspace = (version = "0.8.16") => {
|
|
const rootDir = mkdtempSync(join(tmpdir(), "tmc-release-"));
|
|
mkdirSync(join(rootDir, "apps"));
|
|
mkdirSync(join(rootDir, "packages"));
|
|
writeFileSync(
|
|
join(rootDir, "package.json"),
|
|
`${JSON.stringify({ name: "fixture", version }, null, 4)}\n`,
|
|
);
|
|
for (const [directory, name] of [
|
|
["apps", "extension"],
|
|
["apps", "server"],
|
|
["packages", "contract"],
|
|
]) {
|
|
const packageDir = join(rootDir, directory, name);
|
|
mkdirSync(packageDir);
|
|
writeFileSync(
|
|
join(packageDir, "package.json"),
|
|
`${JSON.stringify({ name, version }, null, 4)}\n`,
|
|
);
|
|
}
|
|
return rootDir;
|
|
};
|
|
|
|
const commandKey = (command, arguments_) => [command, ...arguments_].join(" ");
|
|
|
|
const createRunner = (responses) => {
|
|
const calls = [];
|
|
const execute = (command, arguments_) => {
|
|
calls.push({ command, arguments_ });
|
|
const key = commandKey(command, arguments_);
|
|
const response = responses.get(key);
|
|
if (response instanceof Error) throw response;
|
|
if (Array.isArray(response)) return response.shift() ?? "";
|
|
return response ?? "";
|
|
};
|
|
return { calls, execute };
|
|
};
|
|
|
|
const expectedFiles = [
|
|
"package.json",
|
|
"apps/extension/package.json",
|
|
"apps/server/package.json",
|
|
"packages/contract/package.json",
|
|
];
|
|
|
|
test("prepares a patch release using only root-derived version mirrors", () => {
|
|
const rootDir = createWorkspace();
|
|
const { calls, execute } = createRunner(
|
|
new Map([
|
|
[commandKey("git", ["status", "--porcelain"]), ""],
|
|
[commandKey("git", ["branch", "--show-current"]), "release/0.8.17\n"],
|
|
[commandKey("git", ["rev-parse", "origin/main"]), "main-sha\n"],
|
|
[commandKey("git", ["merge-base", "origin/main", "HEAD"]), "main-sha\n"],
|
|
[commandKey("git", ["diff", "--name-only"]), `${expectedFiles.join("\n")}\n`],
|
|
[commandKey("git", ["ls-files", "--others", "--exclude-standard"]), ""],
|
|
[commandKey("git", ["--no-pager", "diff", "--check"]), ""],
|
|
[
|
|
commandKey("git", ["diff", "--cached", "--name-only"]),
|
|
`${expectedFiles.join("\n")}\n`,
|
|
],
|
|
]),
|
|
);
|
|
|
|
assert.equal(prepareRelease({ rootDir, execute }), "0.8.17");
|
|
assert.equal(JSON.parse(readFileSync(join(rootDir, "package.json"), "utf8")).version, "0.8.17");
|
|
for (const packagePath of expectedFiles.slice(1)) {
|
|
assert.equal(
|
|
JSON.parse(readFileSync(join(rootDir, packagePath), "utf8")).version,
|
|
"0.8.17",
|
|
);
|
|
}
|
|
assert.deepEqual(
|
|
calls.filter(({ command }) => command === "pnpm").map(({ arguments_ }) => arguments_),
|
|
[
|
|
["format:check"],
|
|
["--filter", "@trade-message-center/server", "db:check"],
|
|
["typecheck"],
|
|
["test"],
|
|
["build"],
|
|
],
|
|
);
|
|
assert.ok(
|
|
calls.some(
|
|
({ command, arguments_ }) =>
|
|
commandKey(command, arguments_) ===
|
|
commandKey("git", ["--no-pager", "diff", "--check"]),
|
|
),
|
|
);
|
|
assert.ok(
|
|
calls.some(
|
|
({ command, arguments_ }) =>
|
|
command === "git" &&
|
|
commandKey(command, arguments_) ===
|
|
commandKey("git", ["commit", "-m", "chore: release 0.8.17"]),
|
|
),
|
|
);
|
|
assert.ok(
|
|
calls.some(
|
|
({ command, arguments_ }) =>
|
|
command === "git" &&
|
|
commandKey(command, arguments_) ===
|
|
commandKey("git", ["push", "--set-upstream", "origin", "release/0.8.17"]),
|
|
),
|
|
);
|
|
});
|
|
|
|
test("prepares a release directly on main", () => {
|
|
const rootDir = createWorkspace();
|
|
const { calls, execute } = createRunner(
|
|
new Map([
|
|
[commandKey("git", ["status", "--porcelain"]), ""],
|
|
[commandKey("git", ["branch", "--show-current"]), "main\n"],
|
|
[commandKey("git", ["rev-parse", "origin/main"]), "main-sha\n"],
|
|
[commandKey("git", ["merge-base", "origin/main", "HEAD"]), "main-sha\n"],
|
|
[commandKey("git", ["diff", "--name-only"]), `${expectedFiles.join("\n")}\n`],
|
|
[commandKey("git", ["ls-files", "--others", "--exclude-standard"]), ""],
|
|
[commandKey("git", ["--no-pager", "diff", "--check"]), ""],
|
|
[
|
|
commandKey("git", ["diff", "--cached", "--name-only"]),
|
|
`${expectedFiles.join("\n")}\n`,
|
|
],
|
|
]),
|
|
);
|
|
|
|
assert.equal(prepareRelease({ rootDir, execute }), "0.8.17");
|
|
assert.ok(
|
|
calls.some(
|
|
({ command, arguments_ }) =>
|
|
commandKey(command, arguments_) ===
|
|
commandKey("git", ["push", "--set-upstream", "origin", "main"]),
|
|
),
|
|
);
|
|
});
|
|
|
|
test("restores all version files when staging fails before the release commit", () => {
|
|
const rootDir = createWorkspace();
|
|
const { calls, execute } = createRunner(
|
|
new Map([
|
|
[commandKey("git", ["status", "--porcelain"]), ""],
|
|
[commandKey("git", ["branch", "--show-current"]), "release/0.8.17\n"],
|
|
[commandKey("git", ["rev-parse", "origin/main"]), "main-sha\n"],
|
|
[commandKey("git", ["merge-base", "origin/main", "HEAD"]), "main-sha\n"],
|
|
[commandKey("git", ["diff", "--name-only"]), `${expectedFiles.join("\n")}\n`],
|
|
[commandKey("git", ["ls-files", "--others", "--exclude-standard"]), ""],
|
|
[commandKey("git", ["--no-pager", "diff", "--check"]), ""],
|
|
[commandKey("git", ["add", "--", ...expectedFiles]), new Error("index lock denied")],
|
|
]),
|
|
);
|
|
|
|
assert.throws(() => prepareRelease({ rootDir, execute }), /restored the root/u);
|
|
for (const filePath of expectedFiles) {
|
|
const version = JSON.parse(readFileSync(join(rootDir, filePath), "utf8")).version;
|
|
assert.equal(version, "0.8.16");
|
|
}
|
|
assert.ok(
|
|
calls.some(
|
|
({ command, arguments_ }) =>
|
|
commandKey(command, arguments_) ===
|
|
commandKey("git", ["add", "--", ...expectedFiles]),
|
|
),
|
|
);
|
|
});
|
|
|
|
test("publishes only the exact origin main commit with a new tag", () => {
|
|
const rootDir = createWorkspace();
|
|
const { calls, execute } = createRunner(
|
|
new Map([
|
|
[commandKey("git", ["status", "--porcelain"]), ""],
|
|
[commandKey("git", ["branch", "--show-current"]), "main\n"],
|
|
[commandKey("git", ["rev-parse", "HEAD"]), "main-sha\n"],
|
|
[commandKey("git", ["rev-parse", "origin/main"]), "main-sha\n"],
|
|
[commandKey("git", ["tag", "--list", "v0.8.16"]), ""],
|
|
[commandKey("git", ["ls-remote", "--tags", "origin", "refs/tags/v0.8.16"]), ""],
|
|
]),
|
|
);
|
|
|
|
assert.equal(publishRelease({ rootDir, execute }), "v0.8.16");
|
|
assert.ok(
|
|
calls.some(
|
|
({ command, arguments_ }) =>
|
|
commandKey(command, arguments_) ===
|
|
commandKey("git", ["tag", "--annotate", "v0.8.16", "--message", "Release v0.8.16"]),
|
|
),
|
|
);
|
|
assert.ok(
|
|
calls.some(
|
|
({ command, arguments_ }) =>
|
|
commandKey(command, arguments_) ===
|
|
commandKey("git", ["push", "origin", "v0.8.16"]),
|
|
),
|
|
);
|
|
});
|