Files
trade-message-center/scripts/pre-push-main-protection.test.mjs

97 lines
3.3 KiB
JavaScript

// 验证 pre-push 对远端 main 的非快进更新进行保护。
import assert from "node:assert/strict";
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
import { spawnSync } from "node:child_process";
import test from "node:test";
const repositoryRoot = fileURLToPath(new URL("../", import.meta.url));
const hookPath = join(repositoryRoot, ".husky", "pre-push");
const zeroObjectId = "0".repeat(40);
const runGit = (cwd, arguments_) => {
const result = spawnSync("git", arguments_, {
cwd,
encoding: "utf8",
});
assert.equal(result.status, 0, result.stderr);
return result.stdout.trim();
};
const createRepository = () => {
const repository = mkdtempSync(join(tmpdir(), "tmc-pre-push-"));
runGit(repository, ["init", "--quiet"]);
runGit(repository, ["config", "user.email", "test@example.com"]);
runGit(repository, ["config", "user.name", "Pre-push test"]);
const commit = (fileName, content, message) => {
writeFileSync(join(repository, fileName), content);
runGit(repository, ["add", fileName]);
runGit(repository, ["commit", "--quiet", "-m", message]);
return runGit(repository, ["rev-parse", "HEAD"]);
};
const base = commit("base.txt", "base\n", "base");
const main = commit("main.txt", "main\n", "main");
runGit(repository, ["switch", "--detach", base]);
const divergent = commit("divergent.txt", "divergent\n", "divergent");
return { base, divergent, main, repository };
};
const runHook = (repository, localObjectId, remoteRef, remoteObjectId) =>
spawnSync("sh", [hookPath], {
cwd: repository,
encoding: "utf8",
input: `refs/heads/local ${localObjectId} ${remoteRef} ${remoteObjectId}\n`,
});
test("allows a fast-forward update to remote main", () => {
const { base, main, repository } = createRepository();
try {
const result = runHook(repository, main, "refs/heads/main", base);
assert.equal(result.status, 0, result.stderr);
} finally {
rmSync(repository, { force: true, recursive: true });
}
});
test("rejects a non-fast-forward update to remote main", () => {
const { divergent, main, repository } = createRepository();
try {
const result = runHook(repository, divergent, "refs/heads/main", main);
assert.notEqual(result.status, 0);
assert.match(result.stderr, /只允许快进更新/u);
} finally {
rmSync(repository, { force: true, recursive: true });
}
});
test("does not restrict non-fast-forward updates to other remote branches", () => {
const { divergent, main, repository } = createRepository();
try {
const result = runHook(repository, divergent, "refs/heads/release", main);
assert.equal(result.status, 0, result.stderr);
} finally {
rmSync(repository, { force: true, recursive: true });
}
});
test("rejects deleting remote main", () => {
const { main, repository } = createRepository();
try {
const result = runHook(repository, zeroObjectId, "refs/heads/main", main);
assert.notEqual(result.status, 0);
assert.match(result.stderr, /禁止删除远端 main/u);
} finally {
rmSync(repository, { force: true, recursive: true });
}
});