fix(FN-3842): harden squash-restore fallback outcomes
This commit is contained in:
@@ -7669,4 +7669,42 @@ describe("commitOrAmendMergeWithFixes", () => {
|
||||
expect(result).toEqual({ ok: true, reason: "branch-already-merged" });
|
||||
expect(mockedExecSync.mock.calls.some((call) => String(call[0]) === "git merge-base --is-ancestor def456 abc123")).toBe(true);
|
||||
});
|
||||
|
||||
it("treats squash-restore 'Already up to date' with no staged changes as already-merged success", async () => {
|
||||
mockedExecSync.mockImplementation((cmd: any) => {
|
||||
const cmdStr = String(cmd);
|
||||
if (cmdStr.includes("git diff --cached --name-only")) return "" as any;
|
||||
if (cmdStr === "git diff --name-only") return "" as any;
|
||||
if (cmdStr.includes("git status -z --porcelain")) return "" as any;
|
||||
if (cmdStr === "git rev-parse HEAD") return "abc123" as any;
|
||||
if (cmdStr === "git rev-parse fusion/fn-9999") return "def456" as any;
|
||||
if (cmdStr === "git merge-base def456 abc123") return "zzz999" as any;
|
||||
if (cmdStr === "git diff --stat abc123..fusion/fn-9999") return "" as any;
|
||||
if (cmdStr === "git ls-files --others --exclude-standard") return "" as any;
|
||||
if (cmdStr.includes("git log -1 --pretty=%B HEAD")) return "commit message without trailer" as any;
|
||||
if (cmdStr === "git merge-base --is-ancestor def456 abc123") throw new Error("not ancestor");
|
||||
if (cmdStr === "git reset --hard abc123") return "" as any;
|
||||
if (cmdStr === "git clean -fd") return "" as any;
|
||||
if (cmdStr === "git merge --squash fusion/fn-9999") return "Already up to date." as any;
|
||||
return "" as any;
|
||||
});
|
||||
|
||||
const result = await commitOrAmendMergeWithFixes(
|
||||
"/tmp/root",
|
||||
"FN-9999",
|
||||
"fusion/fn-9999",
|
||||
"",
|
||||
true,
|
||||
"abc123",
|
||||
"",
|
||||
undefined,
|
||||
DEFAULT_SETTINGS,
|
||||
undefined,
|
||||
null,
|
||||
null,
|
||||
new Set(),
|
||||
);
|
||||
|
||||
expect(result).toEqual({ ok: true, reason: "branch-already-merged" });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2763,6 +2763,7 @@ export async function commitOrAmendMergeWithFixes(
|
||||
// No commit and no staged content can still be recoverable when the
|
||||
// in-merge fix path cleared the previous squash index state. Rebuild the
|
||||
// squash from branch -> preAttemptHeadSha and continue normally.
|
||||
let squashRestoreReportedUpToDate = false;
|
||||
try {
|
||||
await execAsync(`git reset --hard ${preAttemptHeadSha}`, {
|
||||
cwd: rootDir,
|
||||
@@ -2772,13 +2773,22 @@ export async function commitOrAmendMergeWithFixes(
|
||||
cwd: rootDir,
|
||||
encoding: "utf-8",
|
||||
});
|
||||
await execAsync(`git merge --squash ${branch}`, {
|
||||
const { stdout: squashRestoreOut, stderr: squashRestoreErr } = await execAsync(`git merge --squash ${branch}`, {
|
||||
cwd: rootDir,
|
||||
encoding: "utf-8",
|
||||
});
|
||||
const squashRestoreText = `${squashRestoreOut || ""}\n${squashRestoreErr || ""}`;
|
||||
squashRestoreReportedUpToDate = /already up to date/i.test(squashRestoreText);
|
||||
} catch (err: unknown) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
mergerLog.warn(`${taskId}: failed to restore squash state before finalize: ${msg}`);
|
||||
const stderr = typeof err === "object" && err !== null && "stderr" in err ? String((err as { stderr?: unknown }).stderr ?? "") : "";
|
||||
const stdout = typeof err === "object" && err !== null && "stdout" in err ? String((err as { stdout?: unknown }).stdout ?? "") : "";
|
||||
const combined = `${stdout}\n${stderr}\n${msg}`;
|
||||
if (/conflict|CONFLICT/i.test(combined)) {
|
||||
resetMergeWithWarn(rootDir, taskId, "squash-restore conflict");
|
||||
throw new Error(`${taskId}: squash-restore fallback hit merge conflicts while finalizing verification-fix merge`);
|
||||
}
|
||||
mergerLog.warn(`${taskId}: failed to restore squash state before finalize: ${msg}; stderr=${stderr.trim() || "<empty>"}`);
|
||||
}
|
||||
|
||||
const { stdout: restoredStagedOut } = await execAsync("git diff --cached --name-only", {
|
||||
@@ -2786,6 +2796,10 @@ export async function commitOrAmendMergeWithFixes(
|
||||
encoding: "utf-8",
|
||||
});
|
||||
if (restoredStagedOut.trim().length === 0) {
|
||||
if (squashRestoreReportedUpToDate) {
|
||||
mergerLog.log(`${taskId}: squash-restore reported already up to date; treating as branch-already-merged`);
|
||||
return { ok: true, reason: "branch-already-merged" };
|
||||
}
|
||||
mergerLog.warn(
|
||||
`${taskId}: refusing to record merge — no commit was created and no changes are staged after squash-restore.`,
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user