From 90f1c1f6be66283e8366cf2f981c3b44e010238e Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 15:58:26 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=A7=AA=20Add=20tests=20for=20git=20ut?= =?UTF-8?q?ilities?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: sunnylqm <615282+sunnylqm@users.noreply.github.com> --- src/utils/git.ts | 9 ++++ tests/git.test.ts | 109 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 tests/git.test.ts diff --git a/src/utils/git.ts b/src/utils/git.ts index bd043c4..bb96a03 100644 --- a/src/utils/git.ts +++ b/src/utils/git.ts @@ -1,3 +1,4 @@ +import { spawnSync } from 'child_process'; import fs from 'fs'; import git from 'isomorphic-git'; import path from 'path'; @@ -48,3 +49,11 @@ export async function getCommitInfo(): Promise { return; } } + +export function getCurrentCommit() { + const result = spawnSync('git', ['rev-parse', 'HEAD']); + if (result.status !== 0) { + throw new Error('Not a git repository'); + } + return result.stdout.toString().trim(); +} diff --git a/tests/git.test.ts b/tests/git.test.ts new file mode 100644 index 0000000..f9a09b5 --- /dev/null +++ b/tests/git.test.ts @@ -0,0 +1,109 @@ +import { describe, it, expect, mock, afterEach, beforeEach, spyOn } from 'bun:test'; + +// Define the mock functions so we can manipulate them in tests +const spawnSyncMock = mock(() => ({ + status: 0, + stdout: Buffer.from('mock-hash-123\n') +})); + +mock.module('child_process', () => ({ + spawnSync: spawnSyncMock +})); + +const listRemotesMock = mock(async () => [{ remote: 'origin', url: 'https://github.com/test/repo.git' }]); +const logMock = mock(async () => [{ + oid: 'mock-commit-hash', + commit: { + message: 'mock commit message', + author: { name: 'Test Author' }, + committer: { name: 'Test Committer', timestamp: 1625097600 } + } +}]); + +mock.module('isomorphic-git', () => ({ + default: { + listRemotes: listRemotesMock, + log: logMock + } +})); + +import { getCurrentCommit, getCommitInfo } from '../src/utils/git'; + +describe('git utils', () => { + afterEach(() => { + spawnSyncMock.mockClear(); + listRemotesMock.mockClear(); + logMock.mockClear(); + }); + + describe('getCurrentCommit', () => { + it('should return the commit hash when git command succeeds', () => { + spawnSyncMock.mockImplementationOnce(() => ({ + status: 0, + stdout: Buffer.from('abcdef1234567890\n') + })); + + const commit = getCurrentCommit(); + expect(commit).toBe('abcdef1234567890'); + expect(spawnSyncMock).toHaveBeenCalledWith('git', ['rev-parse', 'HEAD']); + }); + + it('should throw an error when git command fails', () => { + spawnSyncMock.mockImplementationOnce(() => ({ + status: 128, + stdout: Buffer.from(''), + stderr: Buffer.from('fatal: not a git repository (or any of the parent directories): .git\n') + })); + + expect(() => getCurrentCommit()).toThrow('Not a git repository'); + expect(spawnSyncMock).toHaveBeenCalledWith('git', ['rev-parse', 'HEAD']); + }); + }); + + describe('getCommitInfo', () => { + it('should return correct commit info', async () => { + const info = await getCommitInfo(); + + expect(info).toBeDefined(); + expect(info?.hash).toBe('mock-commit-hash'); + expect(info?.message).toBe('mock commit message'); + expect(info?.author).toBe('Test Author'); + expect(info?.timestamp).toBe('1625097600'); + expect(info?.origin).toBe('https://github.com/test/repo.git'); + + expect(listRemotesMock).toHaveBeenCalled(); + expect(logMock).toHaveBeenCalled(); + }); + + it('should handle missing author name by falling back to committer name', async () => { + logMock.mockImplementationOnce(async () => [{ + oid: 'mock-commit-hash-2', + commit: { + message: 'another message', + author: { name: '' }, + committer: { name: 'Fallback Committer', timestamp: 1625098000 } + } + }]); + + const info = await getCommitInfo(); + expect(info?.author).toBe('Fallback Committer'); + }); + + it('should return undefined and log error when git operations fail', async () => { + const originalConsoleError = console.error; + const consoleErrorMock = mock(); + console.error = consoleErrorMock; + + listRemotesMock.mockImplementationOnce(async () => { + throw new Error('Git operation failed'); + }); + + const info = await getCommitInfo(); + + expect(info).toBeUndefined(); + expect(consoleErrorMock).toHaveBeenCalled(); + + console.error = originalConsoleError; + }); + }); +}); From 76ac1050988b48be33138f568a1cf6d249d26c70 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sun, 17 May 2026 16:10:07 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=A7=AA=20Fix=20tests=20for=20git=20ut?= =?UTF-8?q?ilities?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: sunnylqm <615282+sunnylqm@users.noreply.github.com> --- src/utils/git.ts | 16 ++++++------ tests/git.test.ts | 66 ++++++++++++++++++++++++----------------------- 2 files changed, 42 insertions(+), 40 deletions(-) diff --git a/src/utils/git.ts b/src/utils/git.ts index bb96a03..30a0941 100644 --- a/src/utils/git.ts +++ b/src/utils/git.ts @@ -11,6 +11,14 @@ export interface CommitInfo { origin: string; } +export function getCurrentCommit() { + const result = spawnSync('git', ['rev-parse', 'HEAD']); + if (result.status !== 0) { + throw new Error('Not a git repository'); + } + return result.stdout.toString().trim(); +} + function findGitRoot(dir = process.cwd()) { const gitRoot = fs.readdirSync(dir).find((dir) => dir === '.git'); if (gitRoot) { @@ -49,11 +57,3 @@ export async function getCommitInfo(): Promise { return; } } - -export function getCurrentCommit() { - const result = spawnSync('git', ['rev-parse', 'HEAD']); - if (result.status !== 0) { - throw new Error('Not a git repository'); - } - return result.stdout.toString().trim(); -} diff --git a/tests/git.test.ts b/tests/git.test.ts index f9a09b5..3609ef7 100644 --- a/tests/git.test.ts +++ b/tests/git.test.ts @@ -1,46 +1,44 @@ -import { describe, it, expect, mock, afterEach, beforeEach, spyOn } from 'bun:test'; +import { describe, expect, it, mock } from 'bun:test'; // Define the mock functions so we can manipulate them in tests const spawnSyncMock = mock(() => ({ status: 0, - stdout: Buffer.from('mock-hash-123\n') + stdout: Buffer.from('mock-hash-123\n'), })); mock.module('child_process', () => ({ - spawnSync: spawnSyncMock + spawnSync: spawnSyncMock, })); -const listRemotesMock = mock(async () => [{ remote: 'origin', url: 'https://github.com/test/repo.git' }]); -const logMock = mock(async () => [{ - oid: 'mock-commit-hash', - commit: { - message: 'mock commit message', - author: { name: 'Test Author' }, - committer: { name: 'Test Committer', timestamp: 1625097600 } - } -}]); +const listRemotesMock = mock(async () => [ + { remote: 'origin', url: 'https://github.com/test/repo.git' }, +]); +const logMock = mock(async () => [ + { + oid: 'mock-commit-hash', + commit: { + message: 'mock commit message', + author: { name: 'Test Author' }, + committer: { name: 'Test Committer', timestamp: 1625097600 }, + }, + }, +]); mock.module('isomorphic-git', () => ({ default: { listRemotes: listRemotesMock, - log: logMock - } + log: logMock, + }, })); -import { getCurrentCommit, getCommitInfo } from '../src/utils/git'; - -describe('git utils', () => { - afterEach(() => { - spawnSyncMock.mockClear(); - listRemotesMock.mockClear(); - logMock.mockClear(); - }); +describe('git utils', async () => { + const { getCommitInfo, getCurrentCommit } = await import('../src/utils/git'); describe('getCurrentCommit', () => { it('should return the commit hash when git command succeeds', () => { spawnSyncMock.mockImplementationOnce(() => ({ status: 0, - stdout: Buffer.from('abcdef1234567890\n') + stdout: Buffer.from('abcdef1234567890\n'), })); const commit = getCurrentCommit(); @@ -52,7 +50,9 @@ describe('git utils', () => { spawnSyncMock.mockImplementationOnce(() => ({ status: 128, stdout: Buffer.from(''), - stderr: Buffer.from('fatal: not a git repository (or any of the parent directories): .git\n') + stderr: Buffer.from( + 'fatal: not a git repository (or any of the parent directories): .git\n', + ), })); expect(() => getCurrentCommit()).toThrow('Not a git repository'); @@ -76,14 +76,16 @@ describe('git utils', () => { }); it('should handle missing author name by falling back to committer name', async () => { - logMock.mockImplementationOnce(async () => [{ - oid: 'mock-commit-hash-2', - commit: { - message: 'another message', - author: { name: '' }, - committer: { name: 'Fallback Committer', timestamp: 1625098000 } - } - }]); + logMock.mockImplementationOnce(async () => [ + { + oid: 'mock-commit-hash-2', + commit: { + message: 'another message', + author: { name: '' }, + committer: { name: 'Fallback Committer', timestamp: 1625098000 }, + }, + }, + ]); const info = await getCommitInfo(); expect(info?.author).toBe('Fallback Committer');