mirror of
https://github.com/yamadashy/repomix.git
synced 2026-02-03 11:33:39 +01:00
Added override configuration to disable Biome's organizeImports feature specifically for src/index.ts to allow manual import order management while keeping automatic import organization enabled for other files.
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'],
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
});
|