fix: compare linked repo status by path

This commit is contained in:
Alex Lucero 2026-05-31 08:49:20 +02:00
parent e096b662ab
commit b8593cf8fd
2 changed files with 64 additions and 2 deletions

View file

@ -77,8 +77,11 @@ export function summarizeLinkedRepoChanges(
const beforeByPath = new Map(before.linkedDirs.map((dir) => [dir.path, dir]));
const linkedDirs: LinkedRepoChangeDirectorySummary[] = after.linkedDirs.map((dir) => {
const baseline = beforeByPath.get(dir.path);
const baselineLines = new Set(baseline?.statusLines ?? []);
const newStatusLineCount = dir.statusLines.filter((line) => !baselineLines.has(line)).length;
const baselinePaths = new Set((baseline?.statusLines ?? []).flatMap(statusLinePaths));
const newStatusLineCount = dir.statusLines.filter((line) => {
const paths = statusLinePaths(line);
return paths.length === 0 || paths.every((path) => !baselinePaths.has(path));
}).length;
const preexistingChangeCount = Math.min(
dir.statusLineCount,
Math.max(0, dir.statusLineCount - newStatusLineCount),
@ -184,6 +187,17 @@ function splitLines(value: string): string[] {
.filter((line) => line.trim().length > 0);
}
function statusLinePaths(line: string): string[] {
const value = line.length > 3 ? line.slice(3).trim() : line.trim();
if (!value) return [];
const renameSeparator = ' -> ';
if (!value.includes(renameSeparator)) return [value];
return value
.split(renameSeparator)
.map((part) => part.trim())
.filter(Boolean);
}
function errorMessage(err: unknown): string {
if (!err) return 'Unknown git error.';
if (err instanceof Error && err.message.trim()) return err.message.trim();

View file

@ -90,6 +90,54 @@ describe('linked repo change summaries', () => {
});
});
it('treats status-only transitions on the same path as pre-existing changes', () => {
const before: LinkedRepoSnapshot = {
generatedAt: 1,
linkedDirs: [
{
path: '/repo',
status: 'changed',
branch: 'main',
headSha: 'abc1234',
statusLines: [' M src/app.ts'],
statusLineCount: 1,
untrackedFileCount: 0,
diffStat: 'src/app.ts | 2 ++',
error: null,
},
],
};
const after: LinkedRepoSnapshot = {
generatedAt: 2,
linkedDirs: [
{
path: '/repo',
status: 'changed',
branch: 'main',
headSha: 'abc1234',
statusLines: ['M src/app.ts'],
statusLineCount: 1,
untrackedFileCount: 0,
diffStat: 'src/app.ts | 2 ++',
error: null,
},
],
};
const summary = summarizeLinkedRepoChanges(before, after);
expect(summary).toMatchObject({
changedFileCount: 1,
newStatusLineCount: 0,
preexistingChangeCount: 1,
});
expect(summary.linkedDirs[0]).toMatchObject({
changedFileCount: 1,
newStatusLineCount: 0,
preexistingChangeCount: 1,
});
});
it('reports a linked dir as not_git when git cannot read it as a repository', async () => {
const runGit: RunGit = async () => {
throw new Error('fatal: not a git repository');