Skip to content

Commit b12df6d

Browse files
committed
feat(utils): implement helpers for making paths relative to git root
1 parent 3cb9ae8 commit b12df6d

File tree

3 files changed

+91
-22
lines changed

3 files changed

+91
-22
lines changed

packages/utils/src/index.ts

+12-6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ export {
2222
readTextFile,
2323
removeDirectoryIfExists,
2424
} from './lib/file-system';
25+
export {
26+
filterAuditsBySlug,
27+
filterGroupsByAuditSlug,
28+
} from './lib/filter-by-slug';
2529
export {
2630
formatBytes,
2731
formatDuration,
@@ -33,13 +37,20 @@ export {
3337
truncateText,
3438
truncateTitle,
3539
} from './lib/formatting';
36-
export { getLatestCommit, git, validateCommitData } from './lib/git';
40+
export {
41+
formatGitPath,
42+
getGitRoot,
43+
getLatestCommit,
44+
toGitPath,
45+
validateCommitData,
46+
} from './lib/git';
3747
export { groupByStatus } from './lib/group-by-status';
3848
export {
3949
isPromiseFulfilledResult,
4050
isPromiseRejectedResult,
4151
} from './lib/guards';
4252
export { logMultipleResults } from './lib/log-results';
53+
export { link } from './lib/logging';
4354
export { ProgressBar, getProgressBar } from './lib/progress';
4455
export { TERMINAL_WIDTH } from './lib/reports/constants';
4556
export { generateMdReport } from './lib/reports/generate-md-report';
@@ -71,8 +82,3 @@ export {
7182
toUnixPath,
7283
} from './lib/transform';
7384
export { verboseUtils } from './lib/verbose-utils';
74-
export { link } from './lib/logging';
75-
export {
76-
filterAuditsBySlug,
77-
filterGroupsByAuditSlug,
78-
} from './lib/filter-by-slug';
+56-11
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,63 @@
1+
import { mkdir, rm, writeFile } from 'node:fs/promises';
2+
import { join } from 'node:path';
3+
import { type SimpleGit, simpleGit } from 'simple-git';
14
import { expect } from 'vitest';
2-
import { getLatestCommit } from './git';
5+
import { getGitRoot, getLatestCommit, toGitPath } from './git';
6+
import { toUnixPath } from './transform';
37

4-
const gitCommitDateRegex =
5-
/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{1,2} \d{2}:\d{2}:\d{2} \d{4} [+|-]\d{4}$/;
8+
describe('git utils', () => {
9+
const baseDir = join(process.cwd(), 'tmp', 'testing-git-repo');
10+
let git: SimpleGit;
11+
12+
beforeAll(async () => {
13+
await mkdir(baseDir, { recursive: true });
14+
await writeFile(join(baseDir, 'README.md'), '# hello-world\n');
15+
16+
git = simpleGit(baseDir);
17+
await git.init();
18+
19+
await git.addConfig('user.name', 'John Doe');
20+
await git.addConfig('user.email', '[email protected]');
21+
22+
await git.add('README.md');
23+
await git.commit('Create README');
24+
});
25+
26+
afterAll(async () => {
27+
await rm(baseDir, { recursive: true, force: true });
28+
});
629

7-
describe('getLatestCommit', () => {
830
it('should log latest commit', async () => {
9-
await expect(getLatestCommit()).resolves.toEqual(
10-
expect.objectContaining({
11-
hash: expect.stringMatching(/^[\da-f]{40}$/),
12-
message: expect.stringMatching(/.+/),
13-
author: expect.stringMatching(/.+/),
14-
date: expect.stringMatching(gitCommitDateRegex),
15-
}),
31+
const gitCommitDateRegex =
32+
/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{1,2} \d{2}:\d{2}:\d{2} \d{4} [+|-]\d{4}$/;
33+
34+
await expect(getLatestCommit(git)).resolves.toEqual({
35+
hash: expect.stringMatching(/^[\da-f]{40}$/),
36+
message: 'Create README',
37+
author: 'John Doe',
38+
date: expect.stringMatching(gitCommitDateRegex),
39+
});
40+
});
41+
42+
it('should find Git root', async () => {
43+
await expect(getGitRoot(git)).resolves.toBe(toUnixPath(baseDir));
44+
});
45+
46+
it('should convert absolute path to relative Git path', async () => {
47+
await expect(
48+
toGitPath(join(process.cwd(), 'src', 'utils.ts')),
49+
).resolves.toBe('src/utils.ts');
50+
});
51+
52+
it('should convert relative Windows path to relative Git path', async () => {
53+
await expect(toGitPath('Backend\\API\\Startup.cs')).resolves.toBe(
54+
'Backend/API/Startup.cs',
55+
);
56+
});
57+
58+
it('should keep relative Unix path as is (already a Git path)', async () => {
59+
await expect(toGitPath('Backend/API/Startup.cs')).resolves.toBe(
60+
'Backend/API/Startup.cs',
1661
);
1762
});
1863
});

packages/utils/src/lib/git.ts

+23-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import { isAbsolute, join, relative } from 'node:path';
12
import { simpleGit } from 'simple-git';
3+
import { toUnixPath } from './transform';
24

35
export type CommitData = {
46
hash: string;
@@ -7,19 +9,35 @@ export type CommitData = {
79
date: string;
810
};
911

10-
export const git = simpleGit();
11-
12-
export async function getLatestCommit() {
12+
export async function getLatestCommit(git = simpleGit()) {
1313
// git log -1 --pretty=format:"%H %s %an %ad" // logs hash, message, author, date
1414
const log = await git.log({
1515
maxCount: 1,
1616
format: { hash: '%H', message: '%s', author: '%an', date: '%ad' },
1717
});
18-
return log.latest;
18+
return log.latest satisfies CommitData | null;
19+
}
20+
21+
export function getGitRoot(git = simpleGit()): Promise<string> {
22+
return git.revparse('--show-toplevel');
23+
}
24+
25+
export function formatGitPath(path: string, gitRoot: string): string {
26+
const absolutePath = isAbsolute(path) ? path : join(process.cwd(), path);
27+
const relativePath = relative(gitRoot, absolutePath);
28+
return toUnixPath(relativePath);
29+
}
30+
31+
export async function toGitPath(
32+
path: string,
33+
git = simpleGit(),
34+
): Promise<string> {
35+
const gitRoot = await getGitRoot(git);
36+
return formatGitPath(path, gitRoot);
1937
}
2038

2139
export function validateCommitData(
22-
commitData?: unknown,
40+
commitData: CommitData | null,
2341
options: { throwError?: boolean } = {},
2442
): commitData is CommitData {
2543
const { throwError = false } = options;

0 commit comments

Comments
 (0)