feat(FN-4622): complete Step 1 — native backend sync contract

Fusion-Task-Id: FN-4622
Fusion-Task-Lineage: 10ab809f-32ef-4a1e-921e-4f8ae4161323
This commit is contained in:
Fusion (runfusion.ai)
2026-05-15 18:33:35 -07:00
committed by gsxdsm
parent 43ae0ee074
commit f3c557b216
2 changed files with 41 additions and 6 deletions

View File

@@ -74,6 +74,28 @@ describe("NativeWorktreeBackend", () => {
);
});
it("syncs by fetching then rebasing", async () => {
execMock.mockResolvedValue({ stdout: "", stderr: "" });
const result = await new NativeWorktreeBackend().sync({
rootDir: "/repo",
worktreePath: "/repo/.worktrees/fn-1",
branch: "main",
});
expect(result).toEqual({ skipped: false });
expect(execMock).toHaveBeenNthCalledWith(
1,
"git fetch --all --prune",
expect.objectContaining({ cwd: "/repo/.worktrees/fn-1", timeout: 120000, maxBuffer: 10485760 }),
);
expect(execMock).toHaveBeenNthCalledWith(
2,
'git rebase "origin/main"',
expect.objectContaining({ cwd: "/repo/.worktrees/fn-1", timeout: 120000, maxBuffer: 10485760 }),
);
});
it("prunes worktrees with expected command", async () => {
execMock.mockResolvedValue({ stdout: "", stderr: "" });

View File

@@ -48,7 +48,7 @@ export interface WorktreeBackend {
readonly kind: WorktreeBackendKind;
create(input: WorktreeCreateInput): Promise<WorktreeCreateResult>;
remove(input: WorktreeRemoveInput): Promise<void>;
sync(input: WorktreeSyncInput): Promise<{ skipped: true }>;
sync(input: WorktreeSyncInput): Promise<{ skipped: boolean }>;
prune(input: WorktreePruneInput): Promise<void>;
}
@@ -165,9 +165,22 @@ export class NativeWorktreeBackend implements WorktreeBackend {
});
}
async sync(_input: WorktreeSyncInput): Promise<{ skipped: true }> {
// Sync-with-trunk semantics are specific to the worktrunk backend.
return { skipped: true as const };
async sync(input: WorktreeSyncInput): Promise<{ skipped: boolean }> {
await execAsync("git fetch --all --prune", {
cwd: input.worktreePath,
encoding: "utf-8",
timeout: NATIVE_TIMEOUT_MS,
maxBuffer: MAX_BUFFER,
});
await execAsync(`git rebase ${quoteShellArg(`origin/${input.branch}`)}`, {
cwd: input.worktreePath,
encoding: "utf-8",
timeout: NATIVE_TIMEOUT_MS,
maxBuffer: MAX_BUFFER,
});
return { skipped: false };
}
async prune(input: WorktreePruneInput): Promise<void> {
@@ -246,9 +259,9 @@ export class WorktrunkWorktreeBackend implements WorktreeBackend {
await this.runPlaceholder("remove", input.rootDir);
}
async sync(input: WorktreeSyncInput): Promise<{ skipped: true }> {
async sync(input: WorktreeSyncInput): Promise<{ skipped: boolean }> {
await this.runPlaceholder("sync", input.rootDir);
return { skipped: true as const };
return { skipped: true };
}
async prune(input: WorktreePruneInput): Promise<void> {