-
Notifications
You must be signed in to change notification settings - Fork 963
Expand file tree
/
Copy pathindex.test.ts
More file actions
127 lines (102 loc) · 4.01 KB
/
index.test.ts
File metadata and controls
127 lines (102 loc) · 4.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
import { test, expect, describe } from "vitest";
import path from "node:path";
import fs from "fs-extra";
import tmp from "tmp";
import { execFile } from "node:child_process";
import { promisify } from "node:util";
import { realpathSync } from "node:fs";
import toplevel from "./index.js";
const execFileAsync = promisify(execFile);
/**
* Normalize a path for cross-platform comparison.
* On Windows, tmp paths may use short names (e.g., RUNNER~1) while git returns long names.
* This resolves symlinks and normalizes the path format.
*/
function normalizePath(p: string): string {
return realpathSync(p).replace(/\\/g, "/");
}
async function initGitRepo(cwd: string): Promise<void> {
await execFileAsync("git", ["init"], { cwd });
await execFileAsync("git", ["config", "user.email", "test@example.com"], {
cwd,
});
await execFileAsync("git", ["config", "user.name", "test"], { cwd });
await execFileAsync("git", ["config", "commit.gpgsign", "false"], { cwd });
}
describe("toplevel", () => {
test("should return git root for a regular repository", async () => {
const tmpDir = tmp.dirSync({ keep: false, unsafeCleanup: true });
const repoDir = tmpDir.name;
await initGitRepo(repoDir);
const result = await toplevel(repoDir);
expect(normalizePath(result!)).toBe(normalizePath(repoDir));
});
test("should return git root from a subdirectory", async () => {
const tmpDir = tmp.dirSync({ keep: false, unsafeCleanup: true });
const repoDir = tmpDir.name;
await initGitRepo(repoDir);
const subDir = path.join(repoDir, "sub", "dir");
await fs.mkdirp(subDir);
const result = await toplevel(subDir);
expect(normalizePath(result!)).toBe(normalizePath(repoDir));
});
test("should return undefined for a non-git directory", async () => {
const tmpDir = tmp.dirSync({ keep: false, unsafeCleanup: true });
const result = await toplevel(tmpDir.name);
expect(result).toBeUndefined();
});
test("should work with git worktrees", async () => {
const tmpDir = tmp.dirSync({ keep: false, unsafeCleanup: true });
const mainRepoDir = path.join(tmpDir.name, "main");
const worktreeDir = path.join(tmpDir.name, "worktree");
await fs.mkdirp(mainRepoDir);
await initGitRepo(mainRepoDir);
// Create an initial commit (required for worktree)
await fs.writeFile(path.join(mainRepoDir, "file.txt"), "content");
await execFileAsync("git", ["add", "."], { cwd: mainRepoDir });
await execFileAsync("git", ["commit", "-m", "initial"], {
cwd: mainRepoDir,
});
// Create a new branch for the worktree
await execFileAsync("git", ["branch", "worktree-branch"], {
cwd: mainRepoDir,
});
// Create the worktree
await execFileAsync(
"git",
["worktree", "add", worktreeDir, "worktree-branch"],
{ cwd: mainRepoDir },
);
// toplevel should return the worktree directory, not the main repo
const result = await toplevel(worktreeDir);
expect(normalizePath(result!)).toBe(normalizePath(worktreeDir));
});
test("should work from a subdirectory of a git worktree", async () => {
const tmpDir = tmp.dirSync({ keep: false, unsafeCleanup: true });
const mainRepoDir = path.join(tmpDir.name, "main");
const worktreeDir = path.join(tmpDir.name, "worktree");
await fs.mkdirp(mainRepoDir);
await initGitRepo(mainRepoDir);
// Create an initial commit
await fs.writeFile(path.join(mainRepoDir, "file.txt"), "content");
await execFileAsync("git", ["add", "."], { cwd: mainRepoDir });
await execFileAsync("git", ["commit", "-m", "initial"], {
cwd: mainRepoDir,
});
// Create a new branch and worktree
await execFileAsync("git", ["branch", "worktree-branch"], {
cwd: mainRepoDir,
});
await execFileAsync(
"git",
["worktree", "add", worktreeDir, "worktree-branch"],
{ cwd: mainRepoDir },
);
// Create a subdirectory in the worktree
const subDir = path.join(worktreeDir, "sub", "dir");
await fs.mkdirp(subDir);
// toplevel from subdirectory should return the worktree root
const result = await toplevel(subDir);
expect(normalizePath(result!)).toBe(normalizePath(worktreeDir));
});
});