diff --git a/src/main/ipc/worktrees.test.ts b/src/main/ipc/worktrees.test.ts index 8e128912517..0fb1a657a5f 100644 --- a/src/main/ipc/worktrees.test.ts +++ b/src/main/ipc/worktrees.test.ts @@ -28,7 +28,7 @@ const { removeWorktreeMock, forceDeleteLocalBranchMock, resolveLocalGitUsernameMock, - getDefaultBaseRefMock, + getBaseRefDefaultMock, resolveDefaultBaseRefViaExecMock, getDefaultRemoteMock, getBranchConflictKindMock, @@ -77,7 +77,7 @@ const { removeWorktreeMock: vi.fn(), forceDeleteLocalBranchMock: vi.fn(), resolveLocalGitUsernameMock: vi.fn(), - getDefaultBaseRefMock: vi.fn(), + getBaseRefDefaultMock: vi.fn(), resolveDefaultBaseRefViaExecMock: vi.fn(), getDefaultRemoteMock: vi.fn(), getBranchConflictKindMock: vi.fn(), @@ -130,7 +130,7 @@ vi.mock('../git/runner', () => ({ })) vi.mock('../git/repo', () => ({ - getDefaultBaseRef: getDefaultBaseRefMock, + getBaseRefDefault: getBaseRefDefaultMock, resolveDefaultBaseRefViaExec: resolveDefaultBaseRefViaExecMock, getDefaultRemote: getDefaultRemoteMock, getBranchConflictKind: getBranchConflictKindMock @@ -299,7 +299,7 @@ describe('registerWorktreeHandlers', () => { removeWorktreeMock, forceDeleteLocalBranchMock, resolveLocalGitUsernameMock, - getDefaultBaseRefMock, + getBaseRefDefaultMock, resolveDefaultBaseRefViaExecMock, getDefaultRemoteMock, getBranchConflictKindMock, @@ -400,7 +400,7 @@ describe('registerWorktreeHandlers', () => { ]) store.getAllWorktreeLineage.mockReturnValue({}) resolveLocalGitUsernameMock.mockResolvedValue('') - getDefaultBaseRefMock.mockReturnValue('origin/main') + getBaseRefDefaultMock.mockResolvedValue('origin/main') resolveDefaultBaseRefViaExecMock.mockResolvedValue('origin/main') getDefaultRemoteMock.mockResolvedValue('origin') getBranchConflictKindMock.mockResolvedValue(null) @@ -523,6 +523,7 @@ describe('registerWorktreeHandlers', () => { await handlers['worktrees:prefetchCreateBase'](null, { repoId: 'repo-1' }) + expect(getBaseRefDefaultMock).toHaveBeenCalledWith('/workspace/repo') expect(runtimeStub.resolveRemoteTrackingBase).toHaveBeenCalledWith( '/workspace/repo', 'origin/master' diff --git a/src/main/runtime/orca-runtime.test.ts b/src/main/runtime/orca-runtime.test.ts index 2b515e230bb..3b8508c9313 100644 --- a/src/main/runtime/orca-runtime.test.ts +++ b/src/main/runtime/orca-runtime.test.ts @@ -41,7 +41,7 @@ import { runHook, shouldRunSetupForCreate } from '../hooks' -import { getBranchConflictKind, getDefaultBaseRef } from '../git/repo' +import { getBaseRefDefault, getBranchConflictKind } from '../git/repo' import type { OrchestrationDb } from './orchestration/db' import type { MessagePriority, MessageRow, MessageType } from './orchestration/types' import { @@ -516,16 +516,23 @@ vi.mock('../github/issues', async (importOriginal) => { } }) -// Why: the CLI create-worktree path calls getDefaultBaseRef to resolve a -// fallback base branch. Real resolution shells out to `git` against the -// test's fabricated repo path, which has no refs, so we stub it to a -// predictable 'origin/main'. The runtime no longer silently fabricates this -// default, so tests that want the legacy behavior must express it via the mock. +// Why: CLI worktree creation resolves a default against fabricated repo paths +// in these tests, so keep the async resolver deterministic. vi.mock('../git/repo', async (importOriginal) => { const actual = (await importOriginal()) as Record + const actualGetBaseRefDefault = actual.getBaseRefDefault as ( + path: string, + options?: { wslDistro?: string } + ) => Promise return { ...actual, - getDefaultBaseRef: vi.fn().mockReturnValue('origin/main'), + // Why: fabricated local test repos need a deterministic default, while + // WSL coverage must still exercise the real async Git-options path. + getBaseRefDefault: vi + .fn() + .mockImplementation((path: string, options?: { wslDistro?: string }) => + options?.wslDistro ? actualGetBaseRefDefault(path, options) : Promise.resolve('origin/main') + ), getBranchConflictKind: vi.fn().mockResolvedValue(null) } }) @@ -2825,7 +2832,7 @@ describe('OrcaRuntimeService', () => { suggestLocalBaseRefUpdate: true } ) - expect(getDefaultBaseRef).toHaveBeenCalled() + expect(getBaseRefDefault).toHaveBeenCalled() } finally { getReposSpy.mockRestore() gitSpy.mockRestore() @@ -5330,7 +5337,7 @@ describe('OrcaRuntimeService', () => { it('treats SSH worktree drift as unknown without local git probes', async () => { vi.mocked(listWorktrees).mockClear() - vi.mocked(getDefaultBaseRef).mockClear() + vi.mocked(getBaseRefDefault).mockClear() const remoteStore = { ...store, getRepos: () => [ @@ -5366,7 +5373,7 @@ describe('OrcaRuntimeService', () => { } expect(gitProvider.listWorktrees).toHaveBeenCalledWith('/remote/repo') - expect(getDefaultBaseRef).not.toHaveBeenCalled() + expect(getBaseRefDefault).not.toHaveBeenCalled() expect(listWorktrees).not.toHaveBeenCalled() }) diff --git a/src/main/runtime/orca-runtime.ts b/src/main/runtime/orca-runtime.ts index b7e4c1d2c30..a4dea13dd80 100644 --- a/src/main/runtime/orca-runtime.ts +++ b/src/main/runtime/orca-runtime.ts @@ -599,7 +599,6 @@ import type { } from '../../shared/github-project-types' import { getBaseRefDefault, - getDefaultBaseRef, getDefaultRemote, getBranchConflictKind, isGitRepo, @@ -14249,7 +14248,7 @@ export class OrcaRuntimeService { resolveDefaultBaseRef: () => hasLocalWorktreeGitOptions ? resolveDefaultBaseRefViaExec((argv) => gitExecFileAsync(argv, localGitExecOptions)) - : Promise.resolve(getDefaultBaseRef(repo.path)), + : getBaseRefDefault(repo.path), isBaseUsable: async (baseBranchCandidate) => { const remoteTrackingBase = await this.resolveRemoteTrackingBase( repo.path, @@ -14280,10 +14279,8 @@ export class OrcaRuntimeService { } }) if (!baseBranch) { - // Why: getDefaultBaseRef returns null when no suitable ref exists. - // Don't fabricate 'origin/main' — passing it to addWorktree would - // produce an opaque git failure. Surface a clear error so the CLI - // caller can pick an explicit --base ref. + // Why: a null default means no suitable ref exists; fail clearly instead + // of handing Git a fabricated origin/main ref. throw new Error( 'Could not resolve a default base ref for this repo. Pass an explicit --base and try again.' ) diff --git a/src/main/worktree-create-base-prefetch.ts b/src/main/worktree-create-base-prefetch.ts index 42add57be66..8653c6866eb 100644 --- a/src/main/worktree-create-base-prefetch.ts +++ b/src/main/worktree-create-base-prefetch.ts @@ -2,7 +2,7 @@ import { isFolderRepo } from '../shared/repo-kind' import type { Repo } from '../shared/types' import { hasLocalCommitObject, isFullGitObjectId } from './git/commit-object-ref' import { hasWorktreeBaseCommitRef } from './git/worktree-base-ref-probe' -import { getDefaultBaseRef } from './git/repo' +import { getBaseRefDefault } from './git/repo' import { getSshGitProvider } from './providers/ssh-git-dispatch' import { prefetchRemoteWorktreeCreateBase } from './ipc/worktree-remote' import { resolveWorktreeCreateBase } from './worktree-create-base' @@ -48,7 +48,7 @@ async function prefetchLocalWorktreeCreateBase( const resolvedBaseBranch = await resolveWorktreeCreateBase({ requestedBaseBranch: baseBranch, repoWorktreeBaseRef: repo.worktreeBaseRef, - resolveDefaultBaseRef: async () => getDefaultBaseRef(repo.path), + resolveDefaultBaseRef: () => getBaseRefDefault(repo.path), isBaseUsable: async (baseBranchCandidate) => { const remoteTrackingBase = await runtime.resolveRemoteTrackingBase( repo.path,