Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from __future__ import annotations

import argparse
import os
import subprocess
import sys
import tempfile
Expand Down Expand Up @@ -105,6 +106,38 @@ def generate_in_scope_files(repository: Path, scope: str, output: Path) -> int:
return write_inventory(output, rows)


def committed_changed_paths(repository: Path, base: str, head: str) -> list[tuple[Path, str]]:
result = subprocess.run(
[
"git",
"-C",
str(repository),
"diff",
"--raw",
"-z",
"--diff-filter=ACMRD",
f"{base}..{head}",
],
capture_output=True,
check=True,
)
fields = result.stdout.split(b"\0")
changed: list[tuple[Path, str]] = []
index = 0
while index < len(fields) - 1:
metadata = fields[index].split()
status = chr(metadata[-1][0])
index += 1
if status in {"C", "R"}:
index += 1
path = os.fsdecode(fields[index])
index += 1
selected_mode = metadata[0].removeprefix(b":") if status == "D" else metadata[1]
if selected_mode != b"120000":
changed.append((repository / path, status))
return changed


def generate_diff_in_scope_files(
repository: Path,
base: str,
Expand All @@ -125,7 +158,11 @@ def generate_diff_in_scope_files(

rows: list[bytes] = []
try:
changed = git_changed_paths(repository, base, head, mode)
changed = (
committed_changed_paths(repository, base, head)
if mode == "revisions"
else git_changed_paths(repository, base, head, mode)
)
eligible = [
(path, status)
for path, status in changed
Expand Down
61 changes: 61 additions & 0 deletions sdk/typescript/tests-ts/compact-diff-scan.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,67 @@ describe("compact diff scan", () => {
]);
});

test("omits committed symlinks from the revision inventory", () => {
const { root, repository } = createRepository();
writeSource(repository, "src/handler.py", "value = 1\n");
writeSource(repository, "src/deleted-link.py", "handler.py");
git(repository, "add", ".");
const deletedLink = git(repository, "hash-object", "src/deleted-link.py");
git(
repository,
"update-index",
"--cacheinfo",
`120000,${deletedLink},src/deleted-link.py`,
);
git(repository, "commit", "-qm", "base");
const base = git(repository, "rev-parse", "HEAD");

rmSync(join(repository, "src", "deleted-link.py"));
writeSource(repository, "src/handler.py", "value = 2\n");
writeSource(repository, "src/丁.py", "value = 3\n");
writeSource(repository, "src/added-link.py", "handler.py");
git(repository, "add", ".");
const addedLink = git(repository, "hash-object", "src/added-link.py");
git(
repository,
"update-index",
"--cacheinfo",
`120000,${addedLink},src/added-link.py`,
);
git(repository, "commit", "-qm", "selected changes");
const head = git(repository, "rev-parse", "HEAD");
const output = join(root, "in-scope.txt");

const executable = Bun.which("python3") ?? Bun.which("python");
expect(executable).not.toBeNull();
const result = spawnSync(
executable!,
[
"-B",
"-c",
"import locale, runpy, sys; locale.setlocale(locale.LC_CTYPE, 'C'); runpy.run_path(sys.argv.pop(1), run_name='__main__')",
join(PLUGIN_ROOT, "scripts", "generate_in_scope_files.py"),
"--repo",
repository,
"--scope",
".",
"--diff-base",
base,
"--diff-head",
head,
"--out",
output,
],
{ encoding: "utf8", env: { ...process.env, PYTHONUTF8: "0" } },
);

expect(result.status, result.stderr).toBe(0);
expect(readFileSync(output, "utf8").split("\n").filter(Boolean)).toEqual([
"src/handler.py",
"src/丁.py",
]);
});

test("keeps staged, unstaged, and untracked working-tree inputs aligned", () => {
const { root, repository } = createRepository();
writeSource(repository, "src/handler.py", "value = 1\n");
Expand Down
Loading