The timeout constant made the first it() line exceed the line width, so `biome check .` failed with a format error. Reformat and confirm the three publication tests still pass.
118 lines
4.0 KiB
TypeScript
118 lines
4.0 KiB
TypeScript
// @ts-nocheck
|
|
import { execFileSync } from "node:child_process";
|
|
import { mkdir, mkdtemp, readFile, writeFile } from "node:fs/promises";
|
|
import os from "node:os";
|
|
import path from "node:path";
|
|
import { describe, expect, it } from "vitest";
|
|
import { digestFile } from "@/features/catalog/releases/files";
|
|
import {
|
|
CATALOG_RELEASE_MANIFEST_PATH,
|
|
createReleaseManifest,
|
|
} from "@/features/catalog/releases/manifest";
|
|
import { publishCatalogFiles } from "./catalog-git-core";
|
|
|
|
async function fixture() {
|
|
const root = await mkdtemp(
|
|
path.join(os.tmpdir(), "catalog-release-publish-"),
|
|
);
|
|
const remote = path.join(root, "remote.git");
|
|
const checkout = path.join(root, "checkout");
|
|
const git = (...args: string[]) =>
|
|
execFileSync("git", args, {
|
|
cwd: checkout,
|
|
encoding: "utf8",
|
|
stdio: ["ignore", "pipe", "pipe"],
|
|
}).trim();
|
|
execFileSync("git", ["init", "--bare", remote], { stdio: "ignore" });
|
|
await mkdir(checkout);
|
|
git("init", "-b", "catalog");
|
|
git("config", "core.autocrlf", "false");
|
|
git("config", "user.name", "Test");
|
|
git("config", "user.email", "[email protected]");
|
|
await writeFile(path.join(checkout, "README.md"), "fixture\n");
|
|
git("add", ".");
|
|
git("commit", "-m", "Initialize");
|
|
git("remote", "add", "origin", remote);
|
|
git("push", "-u", "origin", "catalog");
|
|
const source = path.join(root, "asset");
|
|
await writeFile(source, "asset\r\n");
|
|
const { bytes, sha256 } = await digestFile(source);
|
|
const manifest = createReleaseManifest([
|
|
{ path: "Gamedata/icons/chair.png", bytes, sha256 },
|
|
]);
|
|
const manifestSource = path.join(root, "manifest.json");
|
|
await writeFile(manifestSource, JSON.stringify(manifest));
|
|
const options = {
|
|
checkout,
|
|
remote,
|
|
branch: "catalog",
|
|
files: [
|
|
{ source, target: "Gamedata/icons/chair.png" },
|
|
{ source: manifestSource, target: CATALOG_RELEASE_MANIFEST_PATH },
|
|
],
|
|
};
|
|
return { options, git, manifestSource, source };
|
|
}
|
|
|
|
// Each test drives real `git` processes against a local bare remote: init,
|
|
// pull --rebase, ls-files --stage, push and rev-parse. That is deliberately
|
|
// real work, so the cost is process spawns competing with every other Vitest
|
|
// worker for CPU. On CI these land at 23-30s each, which is why the default
|
|
// 10s and even a hand-picked 30s are too tight; the first case measures two
|
|
// publications to prove identical data does not create a second commit.
|
|
// Keep the override well clear of a genuine hang.
|
|
const GIT_PUBLICATION_TIMEOUT = 120_000;
|
|
|
|
describe("catalog release Git publication", () => {
|
|
it(
|
|
"publishes exact files and does not create another commit for identical data",
|
|
async () => {
|
|
const { options, git } = await fixture();
|
|
const first = await publishCatalogFiles(options);
|
|
expect(await publishCatalogFiles(options)).toBe(first);
|
|
expect(git("rev-list", "--count", "HEAD")).toBe("2");
|
|
expect(
|
|
await readFile(
|
|
path.join(options.checkout, "Gamedata/icons/chair.png"),
|
|
"utf8",
|
|
),
|
|
).toBe("asset\r\n");
|
|
},
|
|
GIT_PUBLICATION_TIMEOUT,
|
|
);
|
|
it(
|
|
"rejects a snapshot changed after manifest creation and restores a clean checkout",
|
|
async () => {
|
|
const { options, source, git } = await fixture();
|
|
const head = git("rev-parse", "HEAD");
|
|
await writeFile(source, "tampered");
|
|
await expect(publishCatalogFiles(options)).rejects.toThrow(
|
|
"bytes mismatch",
|
|
);
|
|
expect(git("rev-parse", "HEAD")).toBe(head);
|
|
expect(git("status", "--porcelain")).toBe("");
|
|
},
|
|
GIT_PUBLICATION_TIMEOUT,
|
|
);
|
|
it(
|
|
"rejects Git newline normalization before creating a commit",
|
|
async () => {
|
|
const { options, git } = await fixture();
|
|
await writeFile(
|
|
path.join(options.checkout, ".gitattributes"),
|
|
"Gamedata/** text eol=lf\n",
|
|
);
|
|
git("add", ".gitattributes");
|
|
git("commit", "-m", "Normalize newlines");
|
|
git("push");
|
|
const head = git("rev-parse", "HEAD");
|
|
await expect(publishCatalogFiles(options)).rejects.toThrow(
|
|
"Staged catalog bytes mismatch",
|
|
);
|
|
expect(git("rev-parse", "HEAD")).toBe(head);
|
|
expect(git("status", "--porcelain")).toBe("");
|
|
},
|
|
GIT_PUBLICATION_TIMEOUT,
|
|
);
|
|
});
|