feat(FN-5154): complete Step 1 — restrict done rebase diff ranges
Fusion-Task-Id: FN-5154 Fusion-Task-Lineage: 1ca8d162-343b-4d55-bcba-c34efa331ac4
This commit is contained in:
committed by
gsxdsm
parent
4e3a4731aa
commit
d849539198
@@ -4,6 +4,7 @@ import type { RunAuditEvent, RunAuditEventFilter } from "@fusion/core";
|
|||||||
import { ApiError, notFound, rethrowAsApiError } from "../api-error.js";
|
import { ApiError, notFound, rethrowAsApiError } from "../api-error.js";
|
||||||
import { resolveDiffBase, runGitCommand } from "./resolve-diff-base.js";
|
import { resolveDiffBase, runGitCommand } from "./resolve-diff-base.js";
|
||||||
import { countPatchLines } from "./diff-counts.js";
|
import { countPatchLines } from "./diff-counts.js";
|
||||||
|
import { filterFilesToOwnTaskCommits } from "./attribute-done-range-files.js";
|
||||||
import type { ProjectContext } from "./types.js";
|
import type { ProjectContext } from "./types.js";
|
||||||
|
|
||||||
export interface SessionDiffRouteDeps {
|
export interface SessionDiffRouteDeps {
|
||||||
@@ -244,6 +245,9 @@ type DoneTaskAggregationTask = {
|
|||||||
filesChanged?: number;
|
filesChanged?: number;
|
||||||
insertions?: number;
|
insertions?: number;
|
||||||
deletions?: number;
|
deletions?: number;
|
||||||
|
landedFiles?: string[];
|
||||||
|
landedFilesAttributionRestricted?: boolean;
|
||||||
|
noOpVerifiedShortCircuit?: boolean;
|
||||||
} | null;
|
} | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -493,6 +497,48 @@ async function collectDoneTaskFiles(task: DoneTaskAggregationTask, scopedStore:
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function restrictRebaseRangeFiles(
|
||||||
|
task: DoneTaskAggregationTask,
|
||||||
|
rebaseRangeFiles: AggregatedDoneTaskFile[],
|
||||||
|
deps: {
|
||||||
|
rootDir: string;
|
||||||
|
rebaseBaseShaForAggregation: string;
|
||||||
|
runGit: (args: string[]) => Promise<string>;
|
||||||
|
},
|
||||||
|
): Promise<AggregatedDoneTaskFile[]> {
|
||||||
|
const landed = task.mergeDetails?.landedFiles;
|
||||||
|
const restricted =
|
||||||
|
task.mergeDetails?.landedFilesAttributionRestricted === true ||
|
||||||
|
task.mergeDetails?.noOpVerifiedShortCircuit === true;
|
||||||
|
const landedSet = new Set(landed ?? []);
|
||||||
|
|
||||||
|
if (restricted) {
|
||||||
|
// FN-5154 + FN-5103: restricted landedFiles are authoritative; empty landed
|
||||||
|
// (including no-op short-circuit) must never widen to rebase-range files.
|
||||||
|
return rebaseRangeFiles.filter((file) => landedSet.has(file.path));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(landed) && landed.length > 0) {
|
||||||
|
return rebaseRangeFiles.filter((file) => landedSet.has(file.path));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const attribution = await filterFilesToOwnTaskCommits({
|
||||||
|
worktreePath: deps.rootDir,
|
||||||
|
baseRef: deps.rebaseBaseShaForAggregation,
|
||||||
|
taskId: task.id,
|
||||||
|
runGit: deps.runGit,
|
||||||
|
});
|
||||||
|
const ownSet = new Set(attribution.files);
|
||||||
|
return rebaseRangeFiles.filter((file) => ownSet.has(file.path));
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(
|
||||||
|
`[diff] FN-5154 attribution failed for ${task.id}: ${(err as Error).message}; falling back to unrestricted range`,
|
||||||
|
);
|
||||||
|
return rebaseRangeFiles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers task session-file and diff routes.
|
* Registers task session-file and diff routes.
|
||||||
*
|
*
|
||||||
@@ -640,16 +686,21 @@ export function registerSessionDiffRoutes(router: Router, deps: SessionDiffRoute
|
|||||||
if (rebaseDiffSpec) {
|
if (rebaseDiffSpec) {
|
||||||
const rebaseRangeFiles = await collectDoneRangeFiles(rebaseDiffSpec.range, scopedStore.getRootDir()).catch(() => []);
|
const rebaseRangeFiles = await collectDoneRangeFiles(rebaseDiffSpec.range, scopedStore.getRootDir()).catch(() => []);
|
||||||
if (rebaseRangeFiles.length > 0) {
|
if (rebaseRangeFiles.length > 0) {
|
||||||
const files = rebaseRangeFiles.map((file) => ({
|
const filtered = await restrictRebaseRangeFiles(task, rebaseRangeFiles, {
|
||||||
|
rootDir: scopedStore.getRootDir(),
|
||||||
|
rebaseBaseShaForAggregation,
|
||||||
|
runGit: (args: string[]) => runGitCommand(args, scopedStore.getRootDir(), 10000),
|
||||||
|
});
|
||||||
|
const files = filtered.map((file) => ({
|
||||||
...file,
|
...file,
|
||||||
status: file.status === "renamed" ? "modified" : file.status,
|
status: file.status === "renamed" ? "modified" : file.status,
|
||||||
}));
|
}));
|
||||||
res.json({
|
res.json({
|
||||||
files,
|
files,
|
||||||
stats: {
|
stats: {
|
||||||
filesChanged: files.length,
|
filesChanged: filtered.length,
|
||||||
additions: files.reduce((sum, file) => sum + file.additions, 0),
|
additions: filtered.reduce((sum, file) => sum + file.additions, 0),
|
||||||
deletions: files.reduce((sum, file) => sum + file.deletions, 0),
|
deletions: filtered.reduce((sum, file) => sum + file.deletions, 0),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -896,7 +947,12 @@ export function registerSessionDiffRoutes(router: Router, deps: SessionDiffRoute
|
|||||||
if (rebaseDiffSpec) {
|
if (rebaseDiffSpec) {
|
||||||
const rebaseRangeFiles = await collectDoneRangeFiles(rebaseDiffSpec.range, scopedStore.getRootDir()).catch(() => []);
|
const rebaseRangeFiles = await collectDoneRangeFiles(rebaseDiffSpec.range, scopedStore.getRootDir()).catch(() => []);
|
||||||
if (rebaseRangeFiles.length > 0) {
|
if (rebaseRangeFiles.length > 0) {
|
||||||
res.json(rebaseRangeFiles.map((file) => ({ path: file.path, status: file.status, diff: file.patch })));
|
const filtered = await restrictRebaseRangeFiles(task, rebaseRangeFiles, {
|
||||||
|
rootDir: scopedStore.getRootDir(),
|
||||||
|
rebaseBaseShaForAggregation,
|
||||||
|
runGit: (args: string[]) => runGitCommand(args, scopedStore.getRootDir(), 10000),
|
||||||
|
});
|
||||||
|
res.json(filtered.map((file) => ({ path: file.path, status: file.status, diff: file.patch })));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user