test(FN-4672): complete Step 2 — cover rebase shortstat repair
Fusion-Task-Id: FN-4672 Fusion-Task-Lineage: e05a4a1d-1750-498d-a229-df581fd528e3
This commit is contained in:
@@ -81,7 +81,7 @@ describeIfGit("SelfHealingManager recoverDoneTaskMergeMetadata stale stats", ()
|
||||
for (const repo of repos.splice(0)) rmSync(repo, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
function setupRepo() {
|
||||
function setupSquashRepo() {
|
||||
const repo = mkdtempSync(path.join(os.tmpdir(), "fn-4526-"));
|
||||
repos.push(repo);
|
||||
git(repo, "git init -b main");
|
||||
@@ -96,8 +96,44 @@ describeIfGit("SelfHealingManager recoverDoneTaskMergeMetadata stale stats", ()
|
||||
return { repo, sha: git(repo, "git rev-parse HEAD") };
|
||||
}
|
||||
|
||||
function setupRebaseMergeRepo() {
|
||||
const repo = mkdtempSync(path.join(os.tmpdir(), "fn-4672-"));
|
||||
repos.push(repo);
|
||||
git(repo, "git init -b main");
|
||||
git(repo, 'git config user.email "test@example.com"');
|
||||
git(repo, 'git config user.name "Test"');
|
||||
|
||||
writeFileSync(path.join(repo, "a.ts"), "const a = 1;\n", "utf-8");
|
||||
writeFileSync(path.join(repo, "b.ts"), "const b = 1;\n", "utf-8");
|
||||
writeFileSync(path.join(repo, "c.ts"), "const c = 1;\n", "utf-8");
|
||||
writeFileSync(path.join(repo, "d.ts"), "const d = 1;\n", "utf-8");
|
||||
git(repo, "git add a.ts b.ts c.ts d.ts && git commit -m 'init'");
|
||||
|
||||
git(repo, "git checkout -b feature/fn-4672");
|
||||
writeFileSync(path.join(repo, "a.ts"), "const a = 2;\nconst a2 = 3;\n", "utf-8");
|
||||
writeFileSync(path.join(repo, "b.ts"), "const b = 2;\n", "utf-8");
|
||||
git(repo, "git add a.ts b.ts && git commit -m 'feature-1'");
|
||||
|
||||
writeFileSync(path.join(repo, "c.ts"), "const c = 2;\nconst c2 = 3;\n", "utf-8");
|
||||
writeFileSync(path.join(repo, "d.ts"), "const d = 1;\n", "utf-8");
|
||||
git(repo, "git add c.ts d.ts && git commit -m 'feature-2' -m 'Fusion-Task-Id: FN-4672-REBASE'");
|
||||
|
||||
const rebaseBaseSha = git(repo, "git merge-base main HEAD");
|
||||
|
||||
git(repo, "git checkout main");
|
||||
git(repo, "git cherry-pick feature/fn-4672~1");
|
||||
git(repo, "git cherry-pick feature/fn-4672");
|
||||
|
||||
const sha = git(repo, "git rev-parse HEAD");
|
||||
const rangeStats = parseShortstat(git(repo, `git diff --shortstat ${rebaseBaseSha}..${sha}`));
|
||||
const tipStats = parseShortstat(git(repo, `git show --shortstat --format= ${sha}`));
|
||||
const landedFiles = parseNameOnly(git(repo, `git diff --name-only ${rebaseBaseSha}..${sha}`));
|
||||
|
||||
return { repo, sha, rebaseBaseSha, rangeStats, tipStats, landedFiles };
|
||||
}
|
||||
|
||||
it("repairs stale confirmed stats from live shortstat without changing SHA", async () => {
|
||||
const { repo, sha } = setupRepo();
|
||||
const { repo, sha } = setupSquashRepo();
|
||||
const expected = parseShortstat(git(repo, `git show --shortstat --format= ${sha}`));
|
||||
const task = makeTask("FN-4526-STATS", repo, sha, { filesChanged: 99, insertions: 999, deletions: 999, landedFiles: ["a.ts", "b.ts", "c.ts"] });
|
||||
const tasks = new Map([[task.id, task]]);
|
||||
@@ -114,8 +150,58 @@ describeIfGit("SelfHealingManager recoverDoneTaskMergeMetadata stale stats", ()
|
||||
expect((store.logEntry as any).mock.calls.some((call: any[]) => String(call[1]).includes("stale mergeDetails repaired"))).toBe(true);
|
||||
});
|
||||
|
||||
it("FN-4672: uses rebase range shortstat when rebaseBaseSha is present", async () => {
|
||||
const { repo, sha, rebaseBaseSha, rangeStats, tipStats, landedFiles } = setupRebaseMergeRepo();
|
||||
expect(rangeStats).not.toEqual(tipStats);
|
||||
const task = makeTask("FN-4672-REBASE", repo, sha, {
|
||||
filesChanged: 99,
|
||||
insertions: 999,
|
||||
deletions: 999,
|
||||
landedFiles: ["wrong.ts"],
|
||||
rebaseBaseSha,
|
||||
});
|
||||
const tasks = new Map([[task.id, task]]);
|
||||
const store = createStore(tasks);
|
||||
const manager = new SelfHealingManager(store, { rootDir: repo, getExecutingTaskIds: () => new Set() });
|
||||
|
||||
await manager.recoverDoneTaskMergeMetadata();
|
||||
|
||||
const repaired = tasks.get(task.id)!;
|
||||
expect(repaired.mergeDetails?.commitSha).toBe(sha);
|
||||
expect(repaired.mergeDetails?.filesChanged).toBe(rangeStats.filesChanged);
|
||||
expect(repaired.mergeDetails?.insertions).toBe(rangeStats.insertions);
|
||||
expect(repaired.mergeDetails?.deletions).toBe(rangeStats.deletions);
|
||||
expect(repaired.mergeDetails?.filesChanged).not.toBe(tipStats.filesChanged);
|
||||
expect(repaired.mergeDetails?.insertions).not.toBe(tipStats.insertions);
|
||||
expect(repaired.mergeDetails?.deletions).not.toBe(tipStats.deletions);
|
||||
expect(repaired.mergeDetails?.landedFiles).toEqual(landedFiles);
|
||||
});
|
||||
|
||||
it("FN-4655 regression: does not overwrite correct rebase-range stats with tip-only shortstat", async () => {
|
||||
const { repo, sha, rebaseBaseSha, rangeStats, tipStats, landedFiles } = setupRebaseMergeRepo();
|
||||
expect(rangeStats).not.toEqual(tipStats);
|
||||
const task = makeTask("FN-4672-REGRESSION", repo, sha, {
|
||||
filesChanged: rangeStats.filesChanged,
|
||||
insertions: rangeStats.insertions,
|
||||
deletions: rangeStats.deletions,
|
||||
landedFiles,
|
||||
rebaseBaseSha,
|
||||
});
|
||||
const tasks = new Map([[task.id, task]]);
|
||||
const store = createStore(tasks);
|
||||
const manager = new SelfHealingManager(store, { rootDir: repo, getExecutingTaskIds: () => new Set() });
|
||||
|
||||
await manager.recoverDoneTaskMergeMetadata();
|
||||
|
||||
expect((store.updateTask as any).mock.calls).toHaveLength(0);
|
||||
const unchanged = tasks.get(task.id)!;
|
||||
expect(unchanged.mergeDetails?.filesChanged).toBe(rangeStats.filesChanged);
|
||||
expect(unchanged.mergeDetails?.insertions).toBe(rangeStats.insertions);
|
||||
expect(unchanged.mergeDetails?.deletions).toBe(rangeStats.deletions);
|
||||
});
|
||||
|
||||
it("FN-4646: repairs stale landed file snapshot and modifiedFiles from live commit", async () => {
|
||||
const { repo, sha } = setupRepo();
|
||||
const { repo, sha } = setupSquashRepo();
|
||||
const expected = parseShortstat(git(repo, `git show --shortstat --format= ${sha}`));
|
||||
const expectedFiles = parseNameOnly(git(repo, `git show --name-only --format= ${sha}`));
|
||||
const task = makeTask("FN-4526-STATS", repo, sha, {
|
||||
@@ -138,8 +224,8 @@ describeIfGit("SelfHealingManager recoverDoneTaskMergeMetadata stale stats", ()
|
||||
expect((store.logEntry as any).mock.calls.some((call: any[]) => String(call[1]).includes("files 5 → 2"))).toBe(true);
|
||||
});
|
||||
|
||||
it("does not rewrite when stats are already correct", async () => {
|
||||
const { repo, sha } = setupRepo();
|
||||
it("does not rewrite when squash stats are already correct", async () => {
|
||||
const { repo, sha } = setupSquashRepo();
|
||||
const expected = parseShortstat(git(repo, `git show --shortstat --format= ${sha}`));
|
||||
const task = makeTask("FN-4526-STATS", repo, sha, { ...expected, landedFiles: parseNameOnly(git(repo, `git show --name-only --format= ${sha}`)) });
|
||||
const tasks = new Map([[task.id, task]]);
|
||||
@@ -150,22 +236,4 @@ describeIfGit("SelfHealingManager recoverDoneTaskMergeMetadata stale stats", ()
|
||||
|
||||
expect((store.updateTask as any).mock.calls).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("repairs stale stats in unconfirmed branch when SHA matches landed commit", async () => {
|
||||
const { repo, sha } = setupRepo();
|
||||
const expected = parseShortstat(git(repo, `git show --shortstat --format= ${sha}`));
|
||||
const task = makeTask("FN-4526-STATS", repo, sha, { filesChanged: 777, insertions: 888, deletions: 999, mergeConfirmed: false });
|
||||
const tasks = new Map([[task.id, task]]);
|
||||
const store = createStore(tasks);
|
||||
const manager = new SelfHealingManager(store, { rootDir: repo, getExecutingTaskIds: () => new Set() });
|
||||
|
||||
await manager.recoverDoneTaskMergeMetadata();
|
||||
|
||||
const repaired = tasks.get(task.id)!;
|
||||
expect(repaired.mergeDetails?.commitSha).toBe(sha);
|
||||
expect(repaired.mergeDetails?.filesChanged).toBe(expected.filesChanged);
|
||||
expect(repaired.mergeDetails?.insertions).toBe(expected.insertions);
|
||||
expect(repaired.mergeDetails?.deletions).toBe(expected.deletions);
|
||||
expect(repaired.mergeDetails?.mergeConfirmed).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user