fix: distinguish remote project paths by SSH connection (#5279)
Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
parent
011ea0db34
commit
ebeb12fedc
|
|
@ -89,7 +89,7 @@ vi.mock('./filesystem-auth', () => ({
|
|||
|
||||
vi.mock('../providers/ssh-git-dispatch', () => ({
|
||||
getSshGitProvider: vi.fn().mockImplementation((id: string) => {
|
||||
if (id === 'conn-1') {
|
||||
if (id === 'conn-1' || id === 'conn-2') {
|
||||
return mockGitProvider
|
||||
}
|
||||
return undefined
|
||||
|
|
@ -98,7 +98,7 @@ vi.mock('../providers/ssh-git-dispatch', () => ({
|
|||
|
||||
vi.mock('../providers/ssh-filesystem-dispatch', () => ({
|
||||
getSshFilesystemProvider: vi.fn().mockImplementation((id: string) => {
|
||||
if (id === 'conn-1') {
|
||||
if (id === 'conn-1' || id === 'conn-2') {
|
||||
return mockFilesystemProvider
|
||||
}
|
||||
return undefined
|
||||
|
|
@ -107,7 +107,7 @@ vi.mock('../providers/ssh-filesystem-dispatch', () => ({
|
|||
|
||||
vi.mock('./ssh', () => ({
|
||||
getActiveMultiplexer: vi.fn().mockImplementation((id: string) => {
|
||||
if (id === 'conn-1') {
|
||||
if (id === 'conn-1' || id === 'conn-2') {
|
||||
return mockMultiplexer
|
||||
}
|
||||
return undefined
|
||||
|
|
@ -886,6 +886,59 @@ describe('repos:addRemote', () => {
|
|||
expect(mockStore.addRepo).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('allows the same resolved remote path on a different SSH connection', async () => {
|
||||
const existing = {
|
||||
id: 'machine-1-project',
|
||||
path: '/home/user/project',
|
||||
connectionId: 'conn-1',
|
||||
displayName: 'project',
|
||||
badgeColor: '#fff',
|
||||
addedAt: 1000,
|
||||
kind: 'git'
|
||||
}
|
||||
mockStore.getRepos.mockReturnValue([existing])
|
||||
|
||||
const result = await handlers.get('repos:addRemote')!(null, {
|
||||
connectionId: 'conn-2',
|
||||
remotePath: '/home/user/project'
|
||||
})
|
||||
|
||||
expect(mockStore.addRepo).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
path: '/home/user/project',
|
||||
connectionId: 'conn-2'
|
||||
})
|
||||
)
|
||||
expect(result).toHaveProperty('repo.connectionId', 'conn-2')
|
||||
expect(result).toHaveProperty('repo.id')
|
||||
expect(result).not.toEqual({ repo: existing })
|
||||
})
|
||||
|
||||
it('dedupes remote projects after git root resolution on the same SSH connection', async () => {
|
||||
const existing = {
|
||||
id: 'existing-id',
|
||||
path: '/home/user/project',
|
||||
connectionId: 'conn-1',
|
||||
displayName: 'project',
|
||||
badgeColor: '#fff',
|
||||
addedAt: 1000,
|
||||
kind: 'git'
|
||||
}
|
||||
mockStore.getRepos.mockReturnValue([existing])
|
||||
mockGitProvider.isGitRepoAsync.mockResolvedValueOnce({
|
||||
isRepo: true,
|
||||
rootPath: '/home/user/project'
|
||||
})
|
||||
|
||||
const result = await handlers.get('repos:addRemote')!(null, {
|
||||
connectionId: 'conn-1',
|
||||
remotePath: '/home/user/project/src'
|
||||
})
|
||||
|
||||
expect(result).toEqual({ repo: existing })
|
||||
expect(mockStore.addRepo).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('throws when SSH connection is not found', async () => {
|
||||
const result = await handlers.get('repos:addRemote')!(null, {
|
||||
connectionId: 'unknown-conn',
|
||||
|
|
|
|||
|
|
@ -937,6 +937,16 @@ export function registerRepoHandlers(mainWindow: BrowserWindow, store: Store): v
|
|||
return { error: `SSH connection "${args.connectionId}" not found or not connected` }
|
||||
}
|
||||
|
||||
const findExistingRemoteRepo = (path: string): Repo | undefined =>
|
||||
store
|
||||
.getRepos()
|
||||
.find(
|
||||
(repo) =>
|
||||
repo.connectionId === args.connectionId &&
|
||||
normalizeRuntimePathForComparison(repo.path) ===
|
||||
normalizeRuntimePathForComparison(path)
|
||||
)
|
||||
|
||||
let repoKind: 'git' | 'folder' = args.kind ?? 'git'
|
||||
let resolvedPath = args.remotePath
|
||||
|
||||
|
|
@ -959,9 +969,7 @@ export function registerRepoHandlers(mainWindow: BrowserWindow, store: Store): v
|
|||
|
||||
// Why: check for duplicates after tilde resolution so that adding `~/`
|
||||
// when `/home/ubuntu` is already stored correctly detects the duplicate.
|
||||
const existing = store
|
||||
.getRepos()
|
||||
.find((r) => r.connectionId === args.connectionId && r.path === resolvedPath)
|
||||
const existing = findExistingRemoteRepo(resolvedPath)
|
||||
if (existing) {
|
||||
// Why: duplicate hit is suppressed by `emitRepoAdded` anyway, and for
|
||||
// remote adds git-ness isn't resolved until the isGitRepoAsync check
|
||||
|
|
@ -982,6 +990,13 @@ export function registerRepoHandlers(mainWindow: BrowserWindow, store: Store): v
|
|||
if (check.rootPath) {
|
||||
resolvedPath = check.rootPath
|
||||
}
|
||||
const existingAfterRootResolution = findExistingRemoteRepo(resolvedPath)
|
||||
if (existingAfterRootResolution) {
|
||||
// Why: users may browse inside a repo; store identity is the Git root,
|
||||
// but different SSH targets can legitimately share that same path.
|
||||
emitRepoAdded('folder_picker', true, true)
|
||||
return { repo: existingAfterRootResolution }
|
||||
}
|
||||
} else {
|
||||
return { error: `Not a valid git repository: ${args.remotePath}` }
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue