719032b19f
Update Schema / Update configuration json schema (push) Has been cancelled
Memory Benchmark / Memory Test (Full Analysis) (push) Has been cancelled
CI Quality / Lint GitHub Actions (actionlint) (push) Has been cancelled
CI Quality / Lint GitHub Actions (zizmor) (push) Has been cancelled
CI Quality / Check typos (push) Has been cancelled
CI / Test coverage (push) Has been cancelled
CI / Test (22.x, windows-latest) (push) Has been cancelled
CI / Test (24.x, macos-latest) (push) Has been cancelled
CI / Test (24.x, ubuntu-latest) (push) Has been cancelled
CI / Test (24.x, windows-latest) (push) Has been cancelled
CI / Test (26.x, macos-latest) (push) Has been cancelled
CI / Test (26.x, ubuntu-latest) (push) Has been cancelled
CI / Test (26.x, windows-latest) (push) Has been cancelled
CI / Test with Bun (latest, macos-latest) (push) Has been cancelled
CI / Test with Bun (latest, ubuntu-latest) (push) Has been cancelled
CI / Test with Bun (latest, windows-latest) (push) Has been cancelled
CI / Build and run (22.x, macos-latest) (push) Has been cancelled
CI / Build and run (22.x, ubuntu-latest) (push) Has been cancelled
CI / Build and run (22.x, windows-latest) (push) Has been cancelled
autofix.ci / autofix (push) Has been cancelled
CI Browser Extension / Lint Browser Extension (push) Has been cancelled
CI Browser Extension / Test Browser Extension (push) Has been cancelled
Memory Benchmark / Memory Test (push) Has been cancelled
CI Website / Lint Website Client (push) Has been cancelled
CI Website / Lint Website Server (push) Has been cancelled
CI Website / Test Website Server (push) Has been cancelled
CI Website / Bundle Website Server (push) Has been cancelled
CI / Lint Biome (push) Has been cancelled
CI / Lint oxlint (push) Has been cancelled
CI / Lint TypeScript (push) Has been cancelled
CI / Lint Secretlint (push) Has been cancelled
CI / Test (22.x, macos-latest) (push) Has been cancelled
CI / Test (22.x, ubuntu-latest) (push) Has been cancelled
CI / Build and run (24.x, macos-latest) (push) Has been cancelled
CI / Build and run (24.x, ubuntu-latest) (push) Has been cancelled
CI / Build and run (24.x, windows-latest) (push) Has been cancelled
CI / Build and run (26.x, macos-latest) (push) Has been cancelled
CI / Build and run (26.x, ubuntu-latest) (push) Has been cancelled
CI / Build and run (26.x, windows-latest) (push) Has been cancelled
CI / Build and run with Bun (latest, macos-latest) (push) Has been cancelled
CI / Build and run with Bun (latest, ubuntu-latest) (push) Has been cancelled
CI / Build and run with Bun (latest, windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Docker / build (linux/amd64, ubuntu-latest) (push) Has been cancelled
Docker / build (linux/arm/v7, ubuntu-24.04-arm) (push) Has been cancelled
Docker / build (linux/arm64, ubuntu-24.04-arm) (push) Has been cancelled
Docker / merge (push) Has been cancelled
Pack repository with Repomix / pack-repo (push) Has been cancelled
Performance Benchmark History / Benchmark (macos-latest) (push) Has been cancelled
Performance Benchmark History / Benchmark (ubuntu-latest) (push) Has been cancelled
Performance Benchmark History / Benchmark (windows-latest) (push) Has been cancelled
Performance Benchmark History / Store Results (push) Has been cancelled
Test Repomix Action / Test Node.js 22 (push) Has been cancelled
Test Repomix Action / Test Node.js 24 (push) Has been cancelled
Test Repomix Action / Test Node.js 26 (push) Has been cancelled
299 lines
9.0 KiB
TypeScript
299 lines
9.0 KiB
TypeScript
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
import type { RepomixConfigMerged } from '../../../src/config/configSchema.js';
|
|
import {
|
|
GIT_LOG_FORMAT_SEPARATOR,
|
|
GIT_LOG_RECORD_SEPARATOR,
|
|
getGitLog,
|
|
getGitLogs,
|
|
} from '../../../src/core/git/gitLogHandle.js';
|
|
import { RepomixError } from '../../../src/shared/errorHandle.js';
|
|
import { logger } from '../../../src/shared/logger.js';
|
|
|
|
vi.mock('../../../src/shared/logger');
|
|
|
|
describe('gitLogHandle', () => {
|
|
beforeEach(() => {
|
|
vi.resetAllMocks();
|
|
});
|
|
|
|
describe('getGitLog', () => {
|
|
test('should return git log content when directory is a git repository', async () => {
|
|
const mockExecGitLog = vi.fn().mockResolvedValue('mock log content');
|
|
const mockIsGitRepository = vi.fn().mockResolvedValue(true);
|
|
|
|
const result = await getGitLog('/test/dir', 10, {
|
|
execGitLog: mockExecGitLog,
|
|
isGitRepository: mockIsGitRepository,
|
|
});
|
|
|
|
expect(result).toBe('mock log content');
|
|
expect(mockIsGitRepository).toHaveBeenCalledWith('/test/dir');
|
|
expect(mockExecGitLog).toHaveBeenCalledWith('/test/dir', 10, GIT_LOG_FORMAT_SEPARATOR);
|
|
});
|
|
|
|
test('should return empty string when directory is not a git repository', async () => {
|
|
const mockExecGitLog = vi.fn();
|
|
const mockIsGitRepository = vi.fn().mockResolvedValue(false);
|
|
|
|
const result = await getGitLog('/test/dir', 10, {
|
|
execGitLog: mockExecGitLog,
|
|
isGitRepository: mockIsGitRepository,
|
|
});
|
|
|
|
expect(result).toBe('');
|
|
expect(mockIsGitRepository).toHaveBeenCalledWith('/test/dir');
|
|
expect(mockExecGitLog).not.toHaveBeenCalled();
|
|
expect(logger.trace).toHaveBeenCalledWith('Directory /test/dir is not a git repository');
|
|
});
|
|
|
|
test('should throw error when git log command fails', async () => {
|
|
const mockError = new Error('git command failed');
|
|
const mockExecGitLog = vi.fn().mockRejectedValue(mockError);
|
|
const mockIsGitRepository = vi.fn().mockResolvedValue(true);
|
|
|
|
await expect(
|
|
getGitLog('/test/dir', 10, {
|
|
execGitLog: mockExecGitLog,
|
|
isGitRepository: mockIsGitRepository,
|
|
}),
|
|
).rejects.toThrow('git command failed');
|
|
|
|
expect(logger.trace).toHaveBeenCalledWith('Failed to get git log:', 'git command failed');
|
|
});
|
|
});
|
|
|
|
describe('getGitLogs', () => {
|
|
test('should return git logs when includeLogs is enabled', async () => {
|
|
const mockLogContent = `${GIT_LOG_RECORD_SEPARATOR}2024-01-01 10:00:00 +0900|Initial commit
|
|
file1.txt
|
|
file2.txt
|
|
${GIT_LOG_RECORD_SEPARATOR}2024-01-02 11:00:00 +0900|Add feature
|
|
src/feature.ts`;
|
|
|
|
const mockGetGitLog = vi.fn().mockResolvedValue(mockLogContent);
|
|
const config: RepomixConfigMerged = {
|
|
cwd: '/project',
|
|
output: {
|
|
git: {
|
|
includeLogs: true,
|
|
includeLogsCount: 25,
|
|
},
|
|
},
|
|
} as RepomixConfigMerged;
|
|
|
|
const result = await getGitLogs(['/project/src'], config, {
|
|
getGitLog: mockGetGitLog,
|
|
});
|
|
|
|
expect(result).toEqual({
|
|
logContent: mockLogContent,
|
|
commits: [
|
|
{
|
|
date: '2024-01-01 10:00:00 +0900',
|
|
message: 'Initial commit',
|
|
files: ['file1.txt', 'file2.txt'],
|
|
},
|
|
{
|
|
date: '2024-01-02 11:00:00 +0900',
|
|
message: 'Add feature',
|
|
files: ['src/feature.ts'],
|
|
},
|
|
],
|
|
});
|
|
expect(mockGetGitLog).toHaveBeenCalledWith('/project/src', 25);
|
|
});
|
|
|
|
test('should return undefined when includeLogs is disabled', async () => {
|
|
const config: RepomixConfigMerged = {
|
|
cwd: '/project',
|
|
output: {
|
|
git: {
|
|
includeLogs: false,
|
|
},
|
|
},
|
|
} as RepomixConfigMerged;
|
|
|
|
const result = await getGitLogs(['/project/src'], config);
|
|
|
|
expect(result).toBeUndefined();
|
|
});
|
|
|
|
test('should use default commit count when includeLogsCount is not specified', async () => {
|
|
const mockGetGitLog = vi.fn().mockResolvedValue(`${GIT_LOG_RECORD_SEPARATOR}2024-01-01 10:00:00 +0900|Test commit
|
|
test.txt`);
|
|
const config: RepomixConfigMerged = {
|
|
cwd: '/project',
|
|
output: {
|
|
git: {
|
|
includeLogs: true,
|
|
},
|
|
},
|
|
} as RepomixConfigMerged;
|
|
|
|
await getGitLogs(['/project/src'], config, {
|
|
getGitLog: mockGetGitLog,
|
|
});
|
|
|
|
expect(mockGetGitLog).toHaveBeenCalledWith('/project/src', 50);
|
|
});
|
|
|
|
test('should use first directory as git root', async () => {
|
|
const mockGetGitLog = vi.fn().mockResolvedValue('');
|
|
const config: RepomixConfigMerged = {
|
|
cwd: '/fallback',
|
|
output: {
|
|
git: {
|
|
includeLogs: true,
|
|
},
|
|
},
|
|
} as RepomixConfigMerged;
|
|
|
|
await getGitLogs(['/first/dir', '/second/dir'], config, {
|
|
getGitLog: mockGetGitLog,
|
|
});
|
|
|
|
expect(mockGetGitLog).toHaveBeenCalledWith('/first/dir', 50);
|
|
});
|
|
|
|
test('should fallback to config.cwd when no directories provided', async () => {
|
|
const mockGetGitLog = vi.fn().mockResolvedValue('');
|
|
const config: RepomixConfigMerged = {
|
|
cwd: '/fallback',
|
|
output: {
|
|
git: {
|
|
includeLogs: true,
|
|
},
|
|
},
|
|
} as RepomixConfigMerged;
|
|
|
|
await getGitLogs([], config, {
|
|
getGitLog: mockGetGitLog,
|
|
});
|
|
|
|
expect(mockGetGitLog).toHaveBeenCalledWith('/fallback', 50);
|
|
});
|
|
|
|
test('should throw RepomixError when getGitLog fails', async () => {
|
|
const mockError = new Error('git failed');
|
|
const mockGetGitLog = vi.fn().mockRejectedValue(mockError);
|
|
const config: RepomixConfigMerged = {
|
|
cwd: '/project',
|
|
output: {
|
|
git: {
|
|
includeLogs: true,
|
|
},
|
|
},
|
|
} as RepomixConfigMerged;
|
|
|
|
await expect(
|
|
getGitLogs(['/project'], config, {
|
|
getGitLog: mockGetGitLog,
|
|
}),
|
|
).rejects.toThrow(RepomixError);
|
|
await expect(
|
|
getGitLogs(['/project'], config, {
|
|
getGitLog: mockGetGitLog,
|
|
}),
|
|
).rejects.toThrow('Failed to get git logs: git failed');
|
|
});
|
|
|
|
test('should handle empty git log output', async () => {
|
|
const mockGetGitLog = vi.fn().mockResolvedValue('');
|
|
const config: RepomixConfigMerged = {
|
|
cwd: '/project',
|
|
output: {
|
|
git: {
|
|
includeLogs: true,
|
|
},
|
|
},
|
|
} as RepomixConfigMerged;
|
|
|
|
const result = await getGitLogs(['/project'], config, {
|
|
getGitLog: mockGetGitLog,
|
|
});
|
|
|
|
expect(result).toEqual({
|
|
logContent: '',
|
|
commits: [],
|
|
});
|
|
});
|
|
|
|
test('should parse git log correctly with malformed separator content', async () => {
|
|
// Test behavior when log content doesn't match expected separator
|
|
const malformedLogContent = 'random content without separator';
|
|
|
|
const mockGetGitLog = vi.fn().mockResolvedValue(malformedLogContent);
|
|
const config: RepomixConfigMerged = {
|
|
cwd: '/project',
|
|
output: {
|
|
git: {
|
|
includeLogs: true,
|
|
},
|
|
},
|
|
} as RepomixConfigMerged;
|
|
|
|
const result = await getGitLogs(['/project'], config, {
|
|
getGitLog: mockGetGitLog,
|
|
});
|
|
|
|
// Should return empty commits array when content cannot be parsed properly
|
|
expect(result?.commits).toEqual([]);
|
|
expect(result?.logContent).toBe(malformedLogContent);
|
|
});
|
|
|
|
test('should handle Windows line endings (CRLF) correctly', async () => {
|
|
// Test with Windows-style line endings (\r\n)
|
|
const mockLogContent = `${GIT_LOG_RECORD_SEPARATOR}2024-01-01 10:00:00 +0900|Windows commit\r\nfile1.txt\r\nfile2.txt`;
|
|
|
|
const mockGetGitLog = vi.fn().mockResolvedValue(mockLogContent);
|
|
const config: RepomixConfigMerged = {
|
|
cwd: '/project',
|
|
output: {
|
|
git: {
|
|
includeLogs: true,
|
|
},
|
|
},
|
|
} as RepomixConfigMerged;
|
|
|
|
const result = await getGitLogs(['/project'], config, {
|
|
getGitLog: mockGetGitLog,
|
|
});
|
|
|
|
expect(result?.commits).toEqual([
|
|
{
|
|
date: '2024-01-01 10:00:00 +0900',
|
|
message: 'Windows commit',
|
|
files: ['file1.txt', 'file2.txt'],
|
|
},
|
|
]);
|
|
});
|
|
|
|
test('should handle mixed line endings correctly', async () => {
|
|
// Test with mixed Unix (\n) and Windows (\r\n) line endings
|
|
const mockLogContent = `${GIT_LOG_RECORD_SEPARATOR}2024-01-01 10:00:00 +0900|Mixed line endings\nfile1.txt\r\nfile2.txt`;
|
|
|
|
const mockGetGitLog = vi.fn().mockResolvedValue(mockLogContent);
|
|
const config: RepomixConfigMerged = {
|
|
cwd: '/project',
|
|
output: {
|
|
git: {
|
|
includeLogs: true,
|
|
},
|
|
},
|
|
} as RepomixConfigMerged;
|
|
|
|
const result = await getGitLogs(['/project'], config, {
|
|
getGitLog: mockGetGitLog,
|
|
});
|
|
|
|
expect(result?.commits).toEqual([
|
|
{
|
|
date: '2024-01-01 10:00:00 +0900',
|
|
message: 'Mixed line endings',
|
|
files: ['file1.txt', 'file2.txt'],
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
});
|