fix: initialisation of git

This commit is contained in:
2026-02-16 11:23:10 +01:00
parent 0230010515
commit 4695570c34
6 changed files with 109 additions and 0 deletions

View File

@@ -66,6 +66,19 @@ export interface GitIgnoreEnsureResult {
addedEntries: string[]; addedEntries: string[];
} }
export interface GitLfsPruneOptions {
dryRun?: boolean;
verifyRemote?: boolean;
}
export interface GitLfsPruneResult {
success: boolean;
dryRun: boolean;
verifyRemote: boolean;
output?: string;
error?: string;
}
let gitEngineInstance: GitEngine | null = null; let gitEngineInstance: GitEngine | null = null;
export function getGitEngine(): GitEngine { export function getGitEngine(): GitEngine {
@@ -250,6 +263,38 @@ export class GitEngine {
}; };
} }
async pruneLfsCache(projectPath: string, options: GitLfsPruneOptions = {}): Promise<GitLfsPruneResult> {
const git = simpleGit(projectPath);
const verifyRemote = options.verifyRemote ?? true;
const dryRun = options.dryRun ?? false;
const args = ['lfs', 'prune'];
if (verifyRemote) {
args.push('--verify-remote');
}
if (dryRun) {
args.push('--dry-run');
}
try {
const output = await git.raw(args);
return {
success: true,
dryRun,
verifyRemote,
output,
};
} catch (error) {
const message = error instanceof Error ? error.message : 'Failed to prune Git LFS cache.';
return {
success: false,
dryRun,
verifyRemote,
error: message,
};
}
}
async initializeRepo( async initializeRepo(
projectPath: string, projectPath: string,
remoteUrl?: string, remoteUrl?: string,

View File

@@ -60,6 +60,11 @@ export function registerIpcHandlers(): void {
return engine.ensureGitignore(projectPath); return engine.ensureGitignore(projectPath);
}); });
safeHandle('git:pruneLfs', async (_, projectPath: string, options?: { dryRun?: boolean; verifyRemote?: boolean }) => {
const engine = getGitEngine();
return engine.pruneLfsCache(projectPath, options);
});
// ============ Project Handlers ============ // ============ Project Handlers ============
safeHandle('projects:create', async (_, data: { name: string; description?: string; slug?: string; dataPath?: string }) => { safeHandle('projects:create', async (_, data: { name: string; description?: string; slug?: string; dataPath?: string }) => {

View File

@@ -11,6 +11,7 @@ export const electronAPI: ElectronAPI = {
getRepoState: (projectPath: string) => ipcRenderer.invoke('git:getRepoState', projectPath), getRepoState: (projectPath: string) => ipcRenderer.invoke('git:getRepoState', projectPath),
getStatus: (projectPath: string) => ipcRenderer.invoke('git:status', projectPath), getStatus: (projectPath: string) => ipcRenderer.invoke('git:status', projectPath),
ensureGitignore: (projectPath: string) => ipcRenderer.invoke('git:ensureGitignore', projectPath), ensureGitignore: (projectPath: string) => ipcRenderer.invoke('git:ensureGitignore', projectPath),
pruneLfs: (projectPath: string, options?: { dryRun?: boolean; verifyRemote?: boolean }) => ipcRenderer.invoke('git:pruneLfs', projectPath, options),
init: (projectPath: string, remoteUrl?: string) => { init: (projectPath: string, remoteUrl?: string) => {
if (remoteUrl) { if (remoteUrl) {
return ipcRenderer.invoke('git:init', projectPath, remoteUrl); return ipcRenderer.invoke('git:init', projectPath, remoteUrl);

View File

@@ -266,6 +266,14 @@ export interface GitIgnoreEnsureResult {
addedEntries: string[]; addedEntries: string[];
} }
export interface GitLfsPruneResult {
success: boolean;
dryRun: boolean;
verifyRemote: boolean;
output?: string;
error?: string;
}
// Post-Media Link types // Post-Media Link types
export interface MediaLinkData { export interface MediaLinkData {
id: string; id: string;
@@ -341,6 +349,7 @@ export interface ElectronAPI {
getRepoState: (projectPath: string) => Promise<GitRepoState>; getRepoState: (projectPath: string) => Promise<GitRepoState>;
getStatus: (projectPath: string) => Promise<GitStatusDto>; getStatus: (projectPath: string) => Promise<GitStatusDto>;
ensureGitignore: (projectPath: string) => Promise<GitIgnoreEnsureResult>; ensureGitignore: (projectPath: string) => Promise<GitIgnoreEnsureResult>;
pruneLfs: (projectPath: string, options?: { dryRun?: boolean; verifyRemote?: boolean }) => Promise<GitLfsPruneResult>;
init: (projectPath: string, remoteUrl?: string) => Promise<GitInitResult>; init: (projectPath: string, remoteUrl?: string) => Promise<GitInitResult>;
onInitProgress: (callback: (progress: GitInitProgress) => void) => () => void; onInitProgress: (callback: (progress: GitInitProgress) => void) => () => void;
}; };

View File

@@ -350,4 +350,36 @@ describe('GitEngine', () => {
expect(result.error).toContain('install Git LFS'); expect(result.error).toContain('install Git LFS');
}); });
}); });
describe('pruneLfsCache', () => {
it('should run git lfs prune with verify-remote by default', async () => {
mockRaw.mockResolvedValue('prune complete');
const result = await gitEngine.pruneLfsCache('/tmp/project');
expect(mockRaw).toHaveBeenCalledWith(['lfs', 'prune', '--verify-remote']);
expect(result.success).toBe(true);
expect(result.dryRun).toBe(false);
expect(result.verifyRemote).toBe(true);
});
it('should run git lfs prune in dry-run mode when requested', async () => {
mockRaw.mockResolvedValue('would prune');
const result = await gitEngine.pruneLfsCache('/tmp/project', { dryRun: true });
expect(mockRaw).toHaveBeenCalledWith(['lfs', 'prune', '--verify-remote', '--dry-run']);
expect(result.success).toBe(true);
expect(result.dryRun).toBe(true);
});
it('should return error result when git lfs prune fails', async () => {
mockRaw.mockRejectedValue(new Error('prune failed'));
const result = await gitEngine.pruneLfsCache('/tmp/project');
expect(result.success).toBe(false);
expect(result.error).toContain('prune failed');
});
});
}); });

View File

@@ -146,6 +146,7 @@ const mockGitEngine = {
getStatus: vi.fn(), getStatus: vi.fn(),
initializeRepo: vi.fn(), initializeRepo: vi.fn(),
ensureGitignore: vi.fn(), ensureGitignore: vi.fn(),
pruneLfsCache: vi.fn(),
}; };
const mockTaskManager = { const mockTaskManager = {
@@ -379,6 +380,22 @@ describe('IPC Handlers', () => {
}); });
}); });
}); });
describe('git:pruneLfs', () => {
it('should pass project path and options to GitEngine.pruneLfsCache', async () => {
mockGitEngine.pruneLfsCache.mockResolvedValue({
success: true,
dryRun: true,
verifyRemote: true,
output: 'would prune',
});
const result = await invokeHandler('git:pruneLfs', '/repo', { dryRun: true, verifyRemote: true });
expect(mockGitEngine.pruneLfsCache).toHaveBeenCalledWith('/repo', { dryRun: true, verifyRemote: true });
expect(result.success).toBe(true);
});
});
}); });
// ============ Project Handlers ============ // ============ Project Handlers ============