feat(FN-4717): complete Step 2 — add backend resolver precedence

Fusion-Task-Id: FN-4717
Fusion-Task-Lineage: a2533cd8-52c4-43a0-9daf-e0a49745306b
This commit is contained in:
Fusion (runfusion.ai)
2026-05-16 01:48:47 -07:00
committed by gsxdsm
parent e21e72884b
commit f02482f8f3
2 changed files with 59 additions and 2 deletions

View File

@@ -608,6 +608,57 @@ describe("resolveWorktreeBackend", () => {
expect(resolveWorktreeBackend({ worktrunk: { enabled: true, binaryPath: "worktrunk" } as any }).kind).toBe("worktrunk");
});
it("uses literal binaryPath over resolver when both are provided", async () => {
execMock.mockResolvedValue({ stdout: "", stderr: "" });
const resolver = vi.fn().mockResolvedValue("/resolved");
const backend = resolveWorktreeBackend(
{ worktrunk: { enabled: true, binaryPath: " /literal " } as any },
{ binaryPathResolver: resolver },
);
await (backend as WorktrunkWorktreeBackend).remove({
rootDir: "/repo",
worktreePath: "/repo/.worktrees/fn-1",
branch: "fusion/fn-1",
});
expect(resolver).not.toHaveBeenCalled();
expect(execMock).toHaveBeenCalledWith(
'"/literal" "remove" "--foreground" "fusion/fn-1"',
expect.objectContaining({ cwd: "/repo" }),
);
});
it("wires binaryPathResolver when literal is absent", async () => {
execMock.mockResolvedValue({ stdout: "", stderr: "" });
const resolver = vi.fn().mockResolvedValue("/resolved");
const backend = resolveWorktreeBackend({ worktrunk: { enabled: true } as any }, { binaryPathResolver: resolver });
await (backend as WorktrunkWorktreeBackend).remove({
rootDir: "/repo",
worktreePath: "/repo/.worktrees/fn-1",
branch: "fusion/fn-1",
});
expect(resolver).toHaveBeenCalledTimes(1);
expect(execMock).toHaveBeenCalledWith(
'"/resolved" "remove" "--foreground" "fusion/fn-1"',
expect.objectContaining({ cwd: "/repo" }),
);
});
it("preserves null behavior when literal and resolver are absent", async () => {
const backend = resolveWorktreeBackend({ worktrunk: { enabled: true } as any });
await expect(
(backend as WorktrunkWorktreeBackend).remove({
rootDir: "/repo",
worktreePath: "/repo/.worktrees/fn-1",
branch: "fusion/fn-1",
}),
).rejects.toMatchObject({ code: "worktrunk_binary_missing", operation: "remove" });
});
it("uses worktrunk when enabled without binaryPath", () => {
expect(resolveWorktreeBackend({ worktrunk: { enabled: true } as any }).kind).toBe("worktrunk");
});

View File

@@ -585,11 +585,17 @@ export async function removeWorktree(input: {
export function resolveWorktreeBackend(
settings: Partial<Settings>,
deps: { logger?: { log: (m: string) => void; warn: (m: string) => void } } = {},
deps: {
logger?: { log: (m: string) => void; warn: (m: string) => void };
binaryPathResolver?: () => Promise<string | null>;
} = {},
): WorktreeBackend {
if (settings.worktrunk?.enabled === true) {
// FN-4681 wires binaryPathResolver from worktree-acquisition; precedence is literal setting > resolver > null.
const configuredBinaryPath = settings.worktrunk.binaryPath?.trim() ?? "";
const binaryPath = configuredBinaryPath ? configuredBinaryPath : deps.binaryPathResolver ?? null;
return new WorktrunkWorktreeBackend({
binaryPath: settings.worktrunk.binaryPath ?? null,
binaryPath,
logger: deps.logger,
});
}