mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 17:17:38 +00:00
fix(worktrees): skip Git sweeps for missing repo folders
This commit is contained in:
@@ -1,9 +1,16 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const { listWorktreeGraphMock, listWorktreesMock, listWorktreesStrictMock } = vi.hoisted(() => ({
|
||||
listWorktreeGraphMock: vi.fn(),
|
||||
listWorktreesMock: vi.fn(),
|
||||
listWorktreesStrictMock: vi.fn()
|
||||
const { listWorktreeGraphMock, listWorktreesMock, listWorktreesStrictMock, statMock } = vi.hoisted(
|
||||
() => ({
|
||||
listWorktreeGraphMock: vi.fn(),
|
||||
listWorktreesMock: vi.fn(),
|
||||
listWorktreesStrictMock: vi.fn(),
|
||||
statMock: vi.fn()
|
||||
})
|
||||
)
|
||||
|
||||
vi.mock('./local-worktree-filesystem', () => ({
|
||||
getLocalWorktreePathAccess: () => ({ statPath: statMock })
|
||||
}))
|
||||
|
||||
vi.mock('./git/worktree', () => ({
|
||||
@@ -23,11 +30,32 @@ import {
|
||||
} from './repo-worktrees'
|
||||
import { WorktreeCatalogUnavailableError } from '../shared/worktree/worktree-catalog-availability'
|
||||
|
||||
const testGitRepo = {
|
||||
id: 'repo-1',
|
||||
path: '/workspace/repo',
|
||||
displayName: 'repo',
|
||||
badgeColor: '#000',
|
||||
addedAt: 0,
|
||||
kind: 'git' as const
|
||||
}
|
||||
|
||||
describe('repo-worktrees', () => {
|
||||
beforeEach(() => {
|
||||
listWorktreeGraphMock.mockReset()
|
||||
listWorktreesMock.mockReset()
|
||||
listWorktreesStrictMock.mockReset()
|
||||
statMock.mockReset().mockResolvedValue({})
|
||||
})
|
||||
|
||||
it('skips Git on each missing-folder scan and resumes when the folder returns', async () => {
|
||||
statMock.mockRejectedValueOnce(Object.assign(new Error('missing'), { code: 'ENOENT' }))
|
||||
statMock.mockRejectedValueOnce(Object.assign(new Error('missing'), { code: 'ENOENT' }))
|
||||
expect(await listRepoWorktreesForDetectedScan(testGitRepo)).toEqual([])
|
||||
expect(await listRepoWorktreesForDetectedScan(testGitRepo)).toEqual([])
|
||||
expect(listWorktreesStrictMock).not.toHaveBeenCalled()
|
||||
listWorktreesStrictMock.mockResolvedValueOnce([])
|
||||
await listRepoWorktreesForDetectedScan(testGitRepo)
|
||||
expect(listWorktreesStrictMock).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
it('creates a stable synthetic worktree for folder repos', () => {
|
||||
@@ -100,17 +128,7 @@ describe('repo-worktrees', () => {
|
||||
])
|
||||
const signal = new AbortController().signal
|
||||
|
||||
const result = await listRepoWorktrees(
|
||||
{
|
||||
id: 'repo-1',
|
||||
path: '/workspace/repo',
|
||||
displayName: 'repo',
|
||||
badgeColor: '#000',
|
||||
addedAt: 0,
|
||||
kind: 'git'
|
||||
},
|
||||
{ signal }
|
||||
)
|
||||
const result = await listRepoWorktrees(testGitRepo, { signal })
|
||||
|
||||
expect(listWorktreesMock).toHaveBeenCalledWith('/workspace/repo', { signal })
|
||||
expect(result).toHaveLength(1)
|
||||
@@ -122,14 +140,7 @@ describe('repo-worktrees', () => {
|
||||
{ path: '/workspace/repo', head: 'abc', branch: '', isBare: false, isMainWorktree: true }
|
||||
])
|
||||
|
||||
const result = await listRepoWorktreeGraph({
|
||||
id: 'repo-1',
|
||||
path: '/workspace/repo',
|
||||
displayName: 'repo',
|
||||
badgeColor: '#000',
|
||||
addedAt: 0,
|
||||
kind: 'git'
|
||||
})
|
||||
const result = await listRepoWorktreeGraph(testGitRepo)
|
||||
|
||||
expect(listWorktreeGraphMock).toHaveBeenCalledWith('/workspace/repo')
|
||||
expect(listWorktreesMock).not.toHaveBeenCalled()
|
||||
@@ -165,17 +176,10 @@ describe('repo-worktrees', () => {
|
||||
])
|
||||
const signal = new AbortController().signal
|
||||
|
||||
const result = await listLocalRepoWorktreesStrict(
|
||||
{
|
||||
id: 'repo-1',
|
||||
path: '/workspace/repo',
|
||||
displayName: 'repo',
|
||||
badgeColor: '#000',
|
||||
addedAt: 0,
|
||||
kind: 'git'
|
||||
},
|
||||
{ signal, wslDistro: 'Ubuntu' }
|
||||
)
|
||||
const result = await listLocalRepoWorktreesStrict(testGitRepo, {
|
||||
signal,
|
||||
wslDistro: 'Ubuntu'
|
||||
})
|
||||
|
||||
expect(listWorktreesStrictMock).toHaveBeenCalledWith('/workspace/repo', {
|
||||
signal,
|
||||
|
||||
@@ -12,6 +12,8 @@ import { getRepoExecutionHostId, LOCAL_EXECUTION_HOST_ID } from '../shared/execu
|
||||
import { resolveGitRouteForHost } from './providers/execution-host-provider-dispatch'
|
||||
import { areWorktreePathsEqual } from './ipc/worktree-logic'
|
||||
import { WorktreeCatalogUnavailableError } from '../shared/worktree/worktree-catalog-availability'
|
||||
import { isDefinitiveAbsence } from '../shared/definitive-filesystem-absence'
|
||||
import { getLocalWorktreePathAccess } from './local-worktree-filesystem'
|
||||
|
||||
type LocalRepoWorktreeListOptions = {
|
||||
wslDistro?: string
|
||||
@@ -61,7 +63,18 @@ export async function listRepoWorktreesForDetectedScan(
|
||||
repo: Repo,
|
||||
options?: LocalRepoWorktreeListOptions
|
||||
): Promise<GitWorktreeInfo[]> {
|
||||
return listRoutedRepoWorktrees(repo, options, listWorktreesSharedStrictAllowingTrueEmpty)
|
||||
return listRoutedRepoWorktrees(repo, options, async (repoPath, localOptions) => {
|
||||
try {
|
||||
// The local route runs on the execution host, including the server for SSH repositories.
|
||||
await getLocalWorktreePathAccess(localOptions).statPath(repoPath)
|
||||
} catch (error) {
|
||||
if (isDefinitiveAbsence(error)) {
|
||||
return []
|
||||
}
|
||||
throw error
|
||||
}
|
||||
return listWorktreesSharedStrictAllowingTrueEmpty(repoPath, localOptions)
|
||||
})
|
||||
}
|
||||
|
||||
async function listRoutedRepoWorktrees(
|
||||
|
||||
Reference in New Issue
Block a user