From ac24da3cc5e78685753f9c24e23b3ac697ff2716 Mon Sep 17 00:00:00 2001 From: hanna-skryl Date: Tue, 17 Mar 2026 18:05:47 -0400 Subject: [PATCH] fix(utils): pass revparse args as array --- packages/utils/src/lib/git/git.int.test.ts | 39 +++++++++++++------- packages/utils/src/lib/git/git.ts | 2 +- testing/test-utils/src/lib/utils/git.ts | 41 +++++++++++++++++++--- 3 files changed, 65 insertions(+), 17 deletions(-) diff --git a/packages/utils/src/lib/git/git.int.test.ts b/packages/utils/src/lib/git/git.int.test.ts index 151cffdd07..f3a90436d3 100644 --- a/packages/utils/src/lib/git/git.int.test.ts +++ b/packages/utils/src/lib/git/git.int.test.ts @@ -1,9 +1,13 @@ -import { mkdir, rm, stat, writeFile } from 'node:fs/promises'; +import { rm, stat, writeFile } from 'node:fs/promises'; import path from 'node:path'; import { type SimpleGit, simpleGit } from 'simple-git'; -import { initGitRepo, teardownTestFolder } from '@code-pushup/test-utils'; +import { + initGitRepoWithRemote, + teardownTestFolder, +} from '@code-pushup/test-utils'; import { toUnixPath } from '../transform.js'; import { + getGitDefaultBranch, getGitRoot, guardAgainstLocalChanges, safeCheckout, @@ -12,11 +16,14 @@ import { describe('git utils in a git repo', () => { const baseDir = path.join(process.cwd(), 'tmp', 'git-tests'); + const repoDir = path.join(baseDir, 'repo'); let emptyGit: SimpleGit; beforeAll(async () => { - await mkdir(baseDir, { recursive: true }); - emptyGit = await initGitRepo(simpleGit, { baseDir, baseBranch: 'master' }); + emptyGit = await initGitRepoWithRemote(simpleGit, { + baseDir, + baseBranch: 'master', + }); }); afterAll(async () => { @@ -25,13 +32,15 @@ describe('git utils in a git repo', () => { describe('without a branch and commits', () => { it('getGitRoot should return git root in a set up repo', async () => { - await expect(getGitRoot(emptyGit)).resolves.toMatch(/tmp\/git-tests$/); + await expect(getGitRoot(emptyGit)).resolves.toMatch( + /tmp\/git-tests\/repo$/, + ); }); }); describe('with a branch and commits clean', () => { beforeAll(async () => { - await writeFile(path.join(baseDir, 'README.md'), '# hello-world\n'); + await writeFile(path.join(repoDir, 'README.md'), '# hello-world\n'); await emptyGit.add('README.md'); await emptyGit.commit('Create README'); @@ -45,24 +54,24 @@ describe('git utils in a git repo', () => { }); it('should find Git root', async () => { - await expect(getGitRoot(emptyGit)).resolves.toBe(toUnixPath(baseDir)); + await expect(getGitRoot(emptyGit)).resolves.toBe(toUnixPath(repoDir)); }); it('should convert absolute path to relative Git path', async () => { await expect( - toGitPath(path.join(baseDir, 'src', 'utils.ts'), emptyGit), + toGitPath(path.join(repoDir, 'src', 'utils.ts'), emptyGit), ).resolves.toBe('src/utils.ts'); }); it('should convert relative Windows path to relative Git path', async () => { await expect( toGitPath(String.raw`Backend\API\Startup.cs`, emptyGit), - ).resolves.toBe('../../Backend/API/Startup.cs'); + ).resolves.toBe('../../../Backend/API/Startup.cs'); }); it('should keep relative Unix path as is (already a Git path)', async () => { await expect(toGitPath('Backend/API/Startup.cs', emptyGit)).resolves.toBe( - '../../Backend/API/Startup.cs', + '../../../Backend/API/Startup.cs', ); }); @@ -89,10 +98,10 @@ describe('git utils in a git repo', () => { }); describe('with a branch and commits dirty', () => { - const newFilePath = path.join(baseDir, 'new-file.md'); + const newFilePath = path.join(repoDir, 'new-file.md'); beforeAll(async () => { - await writeFile(path.join(baseDir, 'README.md'), '# hello-world\n'); + await writeFile(path.join(repoDir, 'README.md'), '# hello-world\n'); await emptyGit.add('README.md'); await emptyGit.commit('Create README'); @@ -179,4 +188,10 @@ describe('git utils in a git repo', () => { ); }); }); + + describe('getGitDefaultBranch', () => { + it('should resolve the default branch name from origin/HEAD', async () => { + await expect(getGitDefaultBranch(emptyGit)).resolves.toBe('master'); + }); + }); }); diff --git a/packages/utils/src/lib/git/git.ts b/packages/utils/src/lib/git/git.ts index 5176284771..7bba14ae7a 100644 --- a/packages/utils/src/lib/git/git.ts +++ b/packages/utils/src/lib/git/git.ts @@ -10,7 +10,7 @@ export function getGitRoot(git = simpleGit()): Promise { export async function getGitDefaultBranch(git = simpleGit()): Promise { try { - const head = await git.revparse('--abbrev-ref origin/HEAD'); + const head = await git.revparse(['--abbrev-ref', 'origin/HEAD']); return head.replace(/^origin\//, ''); } catch (error) { logger.warn( diff --git a/testing/test-utils/src/lib/utils/git.ts b/testing/test-utils/src/lib/utils/git.ts index e89ac750a2..bc2aeb0d97 100644 --- a/testing/test-utils/src/lib/utils/git.ts +++ b/testing/test-utils/src/lib/utils/git.ts @@ -18,17 +18,50 @@ export async function initGitRepo( baseBranch?: string; }, ): Promise { - const { baseDir, config, baseBranch } = opt; - const { email = 'john.doe@example.com', name = 'John Doe' } = config ?? {}; + const { baseDir, baseBranch } = opt; await mkdir(baseDir, { recursive: true }); const git = simpleGit(baseDir); await git.init(); + await git.branch(['-M', baseBranch ?? 'main']); + await configureGitUser(git, opt.config); + return git; +} + +/** Like {@link initGitRepo}, but with a simulated remote origin. Working directory is `/repo`. */ +export async function initGitRepoWithRemote( + simpleGit: SimpleGitFactory, + opt: { + baseDir: string; + config?: GitConfig; + baseBranch?: string; + }, +): Promise { + const { baseDir, baseBranch = 'main' } = opt; + const originDir = path.join(baseDir, 'origin.git'); + const repoDir = path.join(baseDir, 'repo'); + + await mkdir(originDir, { recursive: true }); + await simpleGit(originDir).init(true, ['--initial-branch', baseBranch]); + await simpleGit(baseDir).clone(originDir, repoDir); + + const git = simpleGit(repoDir); + await configureGitUser(git, opt.config); + await commitFile(git, { baseDir: repoDir }); + await git.push('origin', baseBranch); + await git.remote(['set-head', 'origin', baseBranch]); + + return git; +} + +async function configureGitUser( + git: SimpleGit, + config?: GitConfig, +): Promise { + const { email = 'john.doe@example.com', name = 'John Doe' } = config ?? {}; await git.addConfig('user.name', name); await git.addConfig('user.email', email); await git.addConfig('commit.gpgSign', 'false'); await git.addConfig('tag.gpgSign', 'false'); - await git.branch(['-M', baseBranch ?? 'main']); - return git; } export async function commitFile(