feat(FN-4990): complete Step 2 — recompute currentStep after lost work reset
Fusion-Task-Id: FN-4990 Fusion-Task-Lineage: 167a6011-d246-45bd-ad7a-1f2fe8b99323
This commit is contained in:
committed by
gsxdsm
parent
f9f8ca04b9
commit
7bcffa5a58
@@ -0,0 +1,62 @@
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
import "./executor-test-helpers.js";
|
||||
import { TaskExecutor } from "../executor.js";
|
||||
import type { Task } from "@fusion/core";
|
||||
import { createMockStore, mockedExecSync, resetExecutorMocks } from "./executor-test-helpers.js";
|
||||
|
||||
describe("TaskExecutor.resetStepsIfWorkLost", () => {
|
||||
beforeEach(() => {
|
||||
resetExecutorMocks();
|
||||
});
|
||||
|
||||
it("resets completed steps and recomputes currentStep when branch has no unique commits", async () => {
|
||||
const store = createMockStore();
|
||||
const task: Task = {
|
||||
id: "FN-4990",
|
||||
title: "Reset steps",
|
||||
description: "desc",
|
||||
column: "in-progress",
|
||||
dependencies: [],
|
||||
steps: [
|
||||
{ name: "Step 1", status: "done" },
|
||||
{ name: "Step 2", status: "done" },
|
||||
{ name: "Step 3", status: "done" },
|
||||
{ name: "Step 4", status: "pending" },
|
||||
{ name: "Step 5", status: "pending" },
|
||||
],
|
||||
currentStep: 3,
|
||||
log: [],
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString(),
|
||||
branch: "fusion/fn-4990",
|
||||
};
|
||||
|
||||
store.getTask.mockImplementation(async () => task);
|
||||
store.updateStep.mockImplementation(async (_taskId: string, stepIndex: number, status: Task["steps"][number]["status"]) => {
|
||||
task.steps[stepIndex].status = status;
|
||||
return task;
|
||||
});
|
||||
store.updateTask.mockImplementation(async (_taskId: string, updates: Partial<Task>) => {
|
||||
Object.assign(task, updates);
|
||||
return task;
|
||||
});
|
||||
|
||||
mockedExecSync.mockImplementation((cmd: string) => {
|
||||
if (cmd.includes("git merge-base")) return "abc123\n";
|
||||
if (cmd.includes("git rev-parse")) return "abc123\n";
|
||||
return "";
|
||||
});
|
||||
|
||||
const executor = new TaskExecutor(store as any, "/tmp/test");
|
||||
await (executor as any).resetStepsIfWorkLost(task);
|
||||
|
||||
expect(task.steps[0].status).toBe("pending");
|
||||
expect(task.steps[1].status).toBe("pending");
|
||||
expect(task.steps[2].status).toBe("pending");
|
||||
expect(task.currentStep).toBe(0);
|
||||
expect(store.logEntry).toHaveBeenCalledWith(
|
||||
task.id,
|
||||
expect.stringContaining("currentStep"),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -9417,6 +9417,23 @@ Backward compat fallback: if JSON is unavailable, you may still begin output wit
|
||||
}
|
||||
}
|
||||
|
||||
const refreshedTask = await this.store.getTask(task.id);
|
||||
const prevCurrentStep = refreshedTask.currentStep;
|
||||
if (refreshedTask.steps.length > 0) {
|
||||
const firstPendingStep = refreshedTask.steps.findIndex((s) => s.status === "pending");
|
||||
const newCurrentStep = firstPendingStep >= 0 ? firstPendingStep : 0;
|
||||
if (newCurrentStep !== prevCurrentStep) {
|
||||
await this.store.updateTask(task.id, { currentStep: newCurrentStep });
|
||||
executorLog.log(
|
||||
`${task.id}: reset currentStep to ${newCurrentStep} after lost-work reset (was ${prevCurrentStep})`,
|
||||
);
|
||||
await this.store.logEntry(
|
||||
task.id,
|
||||
`Reset currentStep to ${newCurrentStep} after lost-work step reset (was ${prevCurrentStep})`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
await this.store.logEntry(
|
||||
task.id,
|
||||
`Reset ${completedSteps.length} step(s) to pending — branch had no commits (uncommitted work lost with worktree)`,
|
||||
|
||||
Reference in New Issue
Block a user