mirror of
https://github.com/sinanyuntu/trade-message-center.git
synced 2026-09-17 13:22:11 +08:00
97 lines
3.3 KiB
JavaScript
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 });
|
|
}
|
|
});
|