From 3b590acc792544e4574a1eae939cbd7398727d46 Mon Sep 17 00:00:00 2001 From: weiyf Date: Wed, 26 Aug 2026 16:52:18 +0800 Subject: [PATCH] fix(watch): normalize SSH repo identity paths --- gitnexus/src/core/auto-sync/runner.ts | 4 +-- gitnexus/test/unit/auto-sync-runner.test.ts | 36 +++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/gitnexus/src/core/auto-sync/runner.ts b/gitnexus/src/core/auto-sync/runner.ts index f0b148a46..b5c09756f 100644 --- a/gitnexus/src/core/auto-sync/runner.ts +++ b/gitnexus/src/core/auto-sync/runner.ts @@ -223,7 +223,7 @@ export async function runAutoSyncOnce( kind: 'failed' as const, project: item.project, remoteUrl: item.remoteUrl, - targetDir: '', + targetDir: item.targetDir ?? '', status: 'sync_failed' as const, lastSyncTime, }; @@ -372,7 +372,7 @@ export async function addRepoToGroup( export function getAutoSyncRepoIdentity(remoteUrl: string): string { validateAutoSyncRemoteUrl(remoteUrl); const [, host, remotePath] = /^git@([^:\s/]+):([^\s]+)$/.exec(remoteUrl.trim())!; - return `${host.toLowerCase()}/${remotePath.replace(/\.git$/, '')}`; + return `${host.toLowerCase()}/${remotePath.replace(/\.git$/i, '')}`; } export async function syncGroupByName(groupName: string): Promise { diff --git a/gitnexus/test/unit/auto-sync-runner.test.ts b/gitnexus/test/unit/auto-sync-runner.test.ts index 2bffaed9b..b5a1e4d50 100644 --- a/gitnexus/test/unit/auto-sync-runner.test.ts +++ b/gitnexus/test/unit/auto-sync-runner.test.ts @@ -5,6 +5,7 @@ import { describe, expect, it, vi } from 'vitest'; import { addRepoToGroup, + getAutoSyncRepoIdentity, getConfiguredRepoPath, getAutoSyncWatchPaths, readAutoSyncWatchStatus, @@ -278,6 +279,12 @@ describe('auto-sync runner', () => { ); }); + it('normalizes the .git suffix case in auto-sync repository identities', () => { + expect(getAutoSyncRepoIdentity('git@GitHub.com:team/service.GIT')).toBe( + 'github.com/team/service', + ); + }); + it('skips analysis when commit id has not changed', async () => { const deps: Partial = withCloneRoot({ cloneOrPull: vi.fn(async () => '/tmp/repos/gitee.com/qts_server/qts_account'), @@ -619,6 +626,35 @@ describe('auto-sync runner', () => { ); }); + it('records the resolved target directory when a post-sync operation fails', async () => { + const deps: Partial = withCloneRoot({ + cloneOrPull: vi.fn(async (_url, targetDir) => targetDir), + getCurrentBranch: vi.fn(() => 'master'), + getCurrentCommit: vi.fn(() => { + throw new Error('git log failed'); + }), + loadState: vi.fn(async () => ({})), + saveState: vi.fn(async () => {}), + writeCommitInfo: vi.fn(async () => {}), + getAvailableMemoryGB: vi.fn(() => 8), + }); + + await expect( + runAutoSyncOnce(config, { + deps, + logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() }, + }), + ).resolves.toEqual({ synced: 0, analyzed: 0, skippedAnalysis: 0, failed: 1 }); + + expect(deps.writeCommitInfo).toHaveBeenCalledWith([ + expect.objectContaining({ + remoteUrl: 'git@gitee.com:qts_server/qts_account.git', + localPath: '/tmp/repos/gitee.com/qts_server/qts_account', + status: 'sync_failed', + }), + ]); + }); + it('isolates clone-root resolution failures to the affected project', async () => { const isolatedConfig: AutoSyncConfig = { ...config,