feat: git log limited to last 20

This commit is contained in:
2026-02-21 19:05:11 +01:00
parent 73a8b6803f
commit e0536bb4f7
9 changed files with 237 additions and 6 deletions

View File

@@ -346,6 +346,94 @@ describe('GitEngine', () => {
},
]);
});
it('should include all remote-only commits in addition to the local history limit', async () => {
mockStatus.mockResolvedValue({ current: 'main', tracking: 'origin/main', behind: 2 });
mockLog
.mockResolvedValueOnce({
all: [
{
hash: 'loc1111',
date: '2026-02-16T12:00:00.000Z',
message: 'feat: newest local',
author_name: 'Local Dev',
},
{
hash: 'both222',
date: '2026-02-16T11:00:00.000Z',
message: 'feat: shared local',
author_name: 'Shared Dev',
},
{
hash: 'loc3333',
date: '2026-02-16T10:00:00.000Z',
message: 'feat: older local',
author_name: 'Local Dev',
},
],
})
.mockResolvedValueOnce({
all: [
{
hash: 'rem9999',
date: '2026-02-16T13:00:00.000Z',
message: 'fix: newest remote waiting',
author_name: 'Remote Dev',
},
{
hash: 'rem8888',
date: '2026-02-16T12:30:00.000Z',
message: 'fix: older remote waiting',
author_name: 'Remote Dev',
},
{
hash: 'both222',
date: '2026-02-16T11:00:00.000Z',
message: 'feat: shared local',
author_name: 'Shared Dev',
},
],
});
const result = await gitEngine.getHistory('/tmp/project', 2);
expect(mockLog).toHaveBeenNthCalledWith(1, { maxCount: 2 });
expect(mockLog).toHaveBeenNthCalledWith(2, ['origin/main', '--max-count', '4']);
expect(result).toEqual([
{
hash: 'rem9999',
shortHash: 'rem9999',
date: '2026-02-16T13:00:00.000Z',
subject: 'fix: newest remote waiting',
author: 'Remote Dev',
syncStatus: 'remote-only',
},
{
hash: 'rem8888',
shortHash: 'rem8888',
date: '2026-02-16T12:30:00.000Z',
subject: 'fix: older remote waiting',
author: 'Remote Dev',
syncStatus: 'remote-only',
},
{
hash: 'loc1111',
shortHash: 'loc1111',
date: '2026-02-16T12:00:00.000Z',
subject: 'feat: newest local',
author: 'Local Dev',
syncStatus: 'local-only',
},
{
hash: 'both222',
shortHash: 'both222',
date: '2026-02-16T11:00:00.000Z',
subject: 'feat: shared local',
author: 'Shared Dev',
syncStatus: 'both',
},
]);
});
});
describe('getFileHistory', () => {

View File

@@ -156,6 +156,101 @@ describe('GitSidebar', () => {
expect(syncedCommit).toHaveClass('git-sidebar-history-item--both');
});
it('loads 20 commits by default and requests more when load more is clicked', async () => {
(window as any).electronAPI.git.getRepoState = vi.fn().mockResolvedValue({
isRepo: true,
rootPath: '/repo/path',
currentBranch: 'main',
hasRemote: true,
});
const createEntry = (index: number, syncStatus: 'both' | 'local-only' | 'remote-only' = 'both') => ({
hash: `hash-${index}`,
shortHash: `h${index}`,
date: `2026-02-${String(28 - index).padStart(2, '0')}T10:00:00.000Z`,
subject: `commit ${index}`,
author: `Dev ${index}`,
syncStatus,
});
(window as any).electronAPI.git.getHistory = vi.fn().mockImplementation((_projectPath: string, limit: number) => {
if (limit <= 20) {
return Promise.resolve([
...Array.from({ length: 20 }, (_, index) => createEntry(index + 1)),
createEntry(101, 'remote-only'),
createEntry(102, 'remote-only'),
]);
}
return Promise.resolve([
...Array.from({ length: 25 }, (_, index) => createEntry(index + 1)),
createEntry(101, 'remote-only'),
createEntry(102, 'remote-only'),
]);
});
render(<GitSidebar />);
expect(await screen.findByText('commit 20')).toBeInTheDocument();
expect(screen.queryByText('commit 25')).not.toBeInTheDocument();
expect(screen.getByText('commit 101')).toBeInTheDocument();
expect(screen.getByText('commit 102')).toBeInTheDocument();
expect((window as any).electronAPI.git.getHistory).toHaveBeenCalledWith('/repo/path', 20);
await act(async () => {
fireEvent.click(screen.getByRole('button', { name: /load more/i }));
});
await vi.waitFor(() => {
expect((window as any).electronAPI.git.getHistory).toHaveBeenCalledWith('/repo/path', 40);
});
expect(await screen.findByText('commit 25')).toBeInTheDocument();
});
it('keeps remote-only commits visible even when local history is limited to 20', async () => {
(window as any).electronAPI.git.getRepoState = vi.fn().mockResolvedValue({
isRepo: true,
rootPath: '/repo/path',
currentBranch: 'main',
hasRemote: true,
});
const localEntries = Array.from({ length: 20 }, (_, index) => ({
hash: `local-${index}`,
shortHash: `l${index}`,
date: `2026-01-${String(28 - index).padStart(2, '0')}T10:00:00.000Z`,
subject: `local commit ${index + 1}`,
author: 'Local Dev',
syncStatus: 'both' as const,
}));
(window as any).electronAPI.git.getHistory = vi.fn().mockResolvedValue([
...localEntries,
{
hash: 'remote-1',
shortHash: 'r1',
date: '2026-02-26T10:00:00.000Z',
subject: 'remote waiting 1',
author: 'Remote Dev',
syncStatus: 'remote-only',
},
{
hash: 'remote-2',
shortHash: 'r2',
date: '2026-02-25T10:00:00.000Z',
subject: 'remote waiting 2',
author: 'Remote Dev',
syncStatus: 'remote-only',
},
]);
render(<GitSidebar />);
expect(await screen.findByText('local commit 20')).toBeInTheDocument();
expect(screen.getByText('remote waiting 1')).toBeInTheDocument();
expect(screen.getByText('remote waiting 2')).toBeInTheDocument();
});
it('renders commit status legend in version history section', async () => {
(window as any).electronAPI.git.getRepoState = vi.fn().mockResolvedValue({
isRepo: true,