mirror of
https://github.com/proxysoul/Empryo.git
synced 2026-11-07 06:25:57 -10:00
fix: CI test failures — git default branch, clone dirs, spawn timeout
Git tests: use `git init -b main` instead of `gitInit()` to ensure consistent branch name on CI where default may be master. Use bare init with `-b main` for remote repos. Don't pre-create clone target dirs (git clone needs to create them). Shell timeout tests: replace spawn's `timeout` option (unreliable in Bun) with manual SIGKILL timer + guarded resolve to prevent hangs.
This commit is contained in:
2 files changed
+54
-16
No files matched your search
@@ -11,7 +11,6 @@ import {
|
||||
getGitStatus,
|
||||
getGitLog,
|
||||
getGitDiff,
|
||||
gitInit,
|
||||
gitCommit,
|
||||
gitAdd,
|
||||
gitStash,
|
||||
@@ -41,7 +40,7 @@ function makeTempDir(name: string): string {
|
||||
|
||||
async function initRepo(name: string): Promise<string> {
|
||||
const dir = makeTempDir(name);
|
||||
await gitInit(dir);
|
||||
await run(["init", "-b", "main"], dir);
|
||||
await run(["config", "user.email", "[email protected]"], dir);
|
||||
await run(["config", "user.name", "Test"], dir);
|
||||
return dir;
|
||||
@@ -151,6 +150,26 @@ describe("unquoteGitPath", () => {
|
||||
expect(unquoteGitPath("")).toBe("");
|
||||
});
|
||||
|
||||
it("unescapes octal byte sequences (non-ASCII filenames)", () => {
|
||||
// "café.txt" → git quotes as "caf\303\251.txt" (UTF-8 bytes for é = 0xC3 0xA9)
|
||||
expect(unquoteGitPath('"caf\\303\\251.txt"')).toBe("café.txt");
|
||||
});
|
||||
|
||||
it("unescapes multi-byte CJK octal sequences", () => {
|
||||
// "日" = UTF-8 bytes E6 97 A5 = octal 346 227 245
|
||||
expect(unquoteGitPath('"\\346\\227\\245.txt"')).toBe("日.txt");
|
||||
});
|
||||
|
||||
it("handles mixed ASCII and octal escapes", () => {
|
||||
// "src/café/naïve.ts"
|
||||
expect(unquoteGitPath('"src/caf\\303\\251/na\\303\\257ve.ts"')).toBe("src/café/naïve.ts");
|
||||
});
|
||||
|
||||
it("handles single octal digit", () => {
|
||||
// \0 = null byte (octal 0)
|
||||
expect(unquoteGitPath('"a\\0b"')).toBe("a\0b");
|
||||
});
|
||||
|
||||
it("does not strip single leading quote without trailing", () => {
|
||||
expect(unquoteGitPath('"no-close')).toBe('"no-close');
|
||||
});
|
||||
@@ -883,11 +902,10 @@ describe("buildGitContext — upstream tracking", () => {
|
||||
});
|
||||
|
||||
it("upstream arrow shown when tracking remote", async () => {
|
||||
// Create a bare repo as "remote" and clone it
|
||||
const bareDir = makeTempDir("ctx-upstream-bare");
|
||||
await run(["init", "--bare"], bareDir);
|
||||
await run(["init", "--bare", "-b", "main"], bareDir);
|
||||
|
||||
const cloneDir = makeTempDir("ctx-upstream-clone");
|
||||
const cloneDir = join(TMP, "ctx-upstream-clone");
|
||||
await run(["clone", bareDir, cloneDir], TMP);
|
||||
await run(["config", "user.email", "[email protected]"], cloneDir);
|
||||
await run(["config", "user.name", "Test"], cloneDir);
|
||||
@@ -905,9 +923,9 @@ describe("buildGitContext — upstream tracking", () => {
|
||||
|
||||
it("ahead/behind counts with remote", async () => {
|
||||
const bareDir = makeTempDir("ctx-ahead-bare");
|
||||
await run(["init", "--bare"], bareDir);
|
||||
await run(["init", "--bare", "-b", "main"], bareDir);
|
||||
|
||||
const cloneDir = makeTempDir("ctx-ahead-clone");
|
||||
const cloneDir = join(TMP, "ctx-ahead-clone");
|
||||
await run(["clone", bareDir, cloneDir], TMP);
|
||||
await run(["config", "user.email", "[email protected]"], cloneDir);
|
||||
await run(["config", "user.name", "Test"], cloneDir);
|
||||
@@ -982,6 +1000,20 @@ describe("git — special file names", () => {
|
||||
const s = await getGitStatus(dir);
|
||||
expect(s.untracked).toContain("empty.txt");
|
||||
});
|
||||
|
||||
it("non-ASCII filename unquoted correctly through getGitStatus", async () => {
|
||||
const dir = await initRepoWithCommit("special-unicode");
|
||||
writeFileSync(join(dir, "café.txt"), "latte");
|
||||
const s = await getGitStatus(dir);
|
||||
expect(s.untracked).toContain("café.txt");
|
||||
});
|
||||
|
||||
it("CJK filename unquoted correctly through getGitStatus", async () => {
|
||||
const dir = await initRepoWithCommit("special-cjk");
|
||||
writeFileSync(join(dir, "日本語.txt"), "hello");
|
||||
const s = await getGitStatus(dir);
|
||||
expect(s.untracked).toContain("日本語.txt");
|
||||
});
|
||||
});
|
||||
|
||||
// ─── Commit message edge cases ───
|
||||
|
||||
@@ -15,13 +15,19 @@ function runShell(
|
||||
const maxOutput = opts.maxOutput ?? 16_384;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
const proc = spawn("sh", ["-c", command], { timeout });
|
||||
const proc = spawn("sh", ["-c", command]);
|
||||
|
||||
const stdoutChunks: Buffer[] = [];
|
||||
const stderrChunks: Buffer[] = [];
|
||||
let stdoutLen = 0;
|
||||
let stderrLen = 0;
|
||||
let timedOut = false;
|
||||
let resolved = false;
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
timedOut = true;
|
||||
proc.kill("SIGKILL");
|
||||
}, timeout);
|
||||
|
||||
proc.stdout.on("data", (data: Buffer) => {
|
||||
if (stdoutLen < maxOutput) {
|
||||
@@ -37,20 +43,20 @@ function runShell(
|
||||
}
|
||||
});
|
||||
|
||||
proc.on("error", (err: Error & { code?: string }) => {
|
||||
if (err.code === "ERR_CHILD_PROCESS_TIMEOUT" || err.message.includes("timed out")) {
|
||||
timedOut = true;
|
||||
}
|
||||
});
|
||||
|
||||
proc.on("close", (code) => {
|
||||
const finish = (code: number | null) => {
|
||||
if (resolved) return;
|
||||
resolved = true;
|
||||
clearTimeout(timer);
|
||||
resolve({
|
||||
stdout: Buffer.concat(stdoutChunks).toString("utf-8").slice(0, maxOutput),
|
||||
stderr: Buffer.concat(stderrChunks).toString("utf-8").slice(0, maxOutput),
|
||||
code,
|
||||
timedOut,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
proc.on("error", () => finish(null));
|
||||
proc.on("close", (code) => finish(code));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user