FN-5671: add branch-strategy selection to new task creation
Add branch-strategy based task branch handling from modal through task creation routes. - add branch strategy dropdown + validation in New Task modal and TaskForm, including required branch-name handling for existing/custom-new modes - send structured branchSelection payload from dashboard API client and cover UI/API behavior with new tests - add server-side branch selection mode parsing, auto-new branch derivation (fusion/<task-id>-<slug>), and response updates when auto branch is generated - update engine/worktree and dashboard route tests plus dashboard guide documentation - add a changeset for @runfusion/fusion patch release Files changed: .changeset/fn-5671-branch-strategy-dropdown.md | 7 ++ docs/dashboard-guide.md | 16 +++++ packages/dashboard/app/__tests__/api-tasks.test.ts | 21 ++++++ packages/dashboard/app/api/legacy.ts | 9 +++ packages/dashboard/app/components/NewTaskModal.css | 8 +++ packages/dashboard/app/components/NewTaskModal.tsx | 41 +++++++++--- packages/dashboard/app/components/TaskForm.tsx | 30 ++++++++- .../app/components/__tests__/NewTaskModal.test.tsx | 77 +++++++++++++++++++--- .../src/__tests__/branch-selection.test.ts | 13 ++++ .../dashboard/src/__tests__/routes-tasks.test.ts | 72 ++++++++++++++++++++ packages/dashboard/src/routes/branch-selection.ts | 45 ++++++++----- .../src/routes/register-task-workflow-routes.ts | 22 +++++-- .../engine/src/__tests__/worktree-pool.test.ts | 41 ++++++++++++ packages/engine/src/worktree-pool.ts | 2 +- 14 files changed, 361 insertions(+), 43 deletions(-) Fusion-Task-Id: FN-5671 Fusion-Task-Lineage: 7f2e7b68-050d-4a2c-af0b-cb895de35576
This commit is contained in:
@@ -363,6 +363,46 @@ describe("WorktreePool", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("maps slugged fusion branches to canonical task IDs", async () => {
|
||||
mockedExistsSync.mockReturnValue(true);
|
||||
|
||||
mockedExecSync.mockImplementation((cmd: any) => {
|
||||
const cmdStr = String(cmd);
|
||||
if (cmdStr === 'git checkout -B "fusion/fn-5671-add-dropdown" main') {
|
||||
const err: any = new Error("branch conflict");
|
||||
err.stderr = Buffer.from("fatal: 'fusion/fn-5671-add-dropdown' is already used by worktree at '/other/wt'");
|
||||
throw err;
|
||||
}
|
||||
if (cmdStr === "git worktree list --porcelain") {
|
||||
return Buffer.from(["worktree /other/wt", "HEAD 1111111", "branch refs/heads/fusion/fn-5671-add-dropdown", ""].join("\n"));
|
||||
}
|
||||
if (cmdStr.includes("git rev-parse --verify 'fusion/fn-5671-add-dropdown^{commit}'")) {
|
||||
return Buffer.from("abc123def456\n");
|
||||
}
|
||||
return Buffer.from("");
|
||||
});
|
||||
|
||||
const inspectSpy = vi.spyOn(branchConflictModule, "inspectBranchConflict").mockResolvedValueOnce({
|
||||
kind: "live-foreign",
|
||||
livePath: "/other/wt",
|
||||
error: new BranchConflictError({
|
||||
branchName: "fusion/fn-5671-add-dropdown",
|
||||
conflictingWorktreePath: "/other/wt",
|
||||
existingTipSha: "abc123def456",
|
||||
strandedCommits: [],
|
||||
startPoint: "main",
|
||||
recommendedAction: "Inspect/reclaim.",
|
||||
}),
|
||||
});
|
||||
|
||||
await expect(pool.prepareForTask("/tmp/wt", "fusion/fn-5671-add-dropdown")).rejects.toBeInstanceOf(BranchConflictError);
|
||||
expect(inspectSpy).toHaveBeenCalledWith(expect.objectContaining({
|
||||
branchName: "fusion/fn-5671-add-dropdown",
|
||||
ownerTaskId: "FN-5671",
|
||||
requestingTaskId: "FN-5671",
|
||||
}));
|
||||
});
|
||||
|
||||
it("throws BranchConflictError for cross-task live-foreign conflicts", async () => {
|
||||
mockedExistsSync.mockReturnValue(true);
|
||||
|
||||
@@ -897,6 +937,7 @@ describe("cleanupOrphanedWorktrees", () => {
|
||||
expect(removeCalls[0][0]).not.toContain("active-wt");
|
||||
});
|
||||
|
||||
|
||||
it("handles git worktree remove failures gracefully (non-fatal)", async () => {
|
||||
mockedReaddirSync.mockReturnValue([
|
||||
makeDirEntry("fail-wt"),
|
||||
|
||||
@@ -252,7 +252,7 @@ export function isInsideWorktreesDir(
|
||||
* up via {@link cleanupOrphanedWorktrees}.
|
||||
*/
|
||||
function deriveTaskIdFromBranch(branchName: string): string {
|
||||
const match = branchName.match(/^fusion\/(fn-\d+)(?:-\d+)?$/i);
|
||||
const match = branchName.match(/^fusion\/(fn-\d+)(?:-\d+)?(?:-[a-z0-9._-]+)*$/i);
|
||||
return match ? match[1].toUpperCase() : branchName.toUpperCase();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user