Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub(crate) const DEFAULT_IGNORE_DIRS: &[&str] = &[
"venv",
"env",
".env",
"target",
];

/// All supported file extensions (mirrors the JS `EXTENSIONS` set).
Expand Down Expand Up @@ -473,6 +474,24 @@ mod tests {
let _ = fs::remove_dir_all(&tmp);
}

#[test]
fn collect_skips_target_dir() {
let tmp = std::env::temp_dir().join("codegraph_collect_target_test");
let _ = fs::remove_dir_all(&tmp);
let build_out = tmp.join("target").join("debug");
fs::create_dir_all(&build_out).unwrap();
fs::write(build_out.join("build.rs"), "").unwrap();
let src = tmp.join("src");
fs::create_dir_all(&src).unwrap();
fs::write(src.join("app.rs"), "").unwrap();

let result = collect_files(tmp.to_str().unwrap(), &[], &[], &[]);
assert_eq!(result.files.len(), 1);
assert!(result.files[0].contains("app.rs"));

let _ = fs::remove_dir_all(&tmp);
}

#[test]
fn collect_honors_exclude_globs() {
let tmp = std::env::temp_dir().join("codegraph_collect_exclude_test");
Expand Down
1 change: 1 addition & 0 deletions src/shared/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const IGNORE_DIRS: ArrayCompatSet<string> = withArrayCompat(
'venv',
'env',
'.env',
'target',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Incremental collection retains target files

When an existing graph contains files under target/ and the next build uses incremental collection, the fast path reconstructs its file set without applying this new default ignore, causing generated Rust files to remain in the graph until a full rebuild invalidates them.

Knowledge Base Used:

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed — this is real, but it's a general characteristic of the incremental fast path (tryFastCollect/try_fast_collect), not something specific to target: neither engine's fast path re-applies IGNORE_DIRS/DEFAULT_IGNORE_DIRS at all, so any file already in file_hashes from a prior build survives incremental rebuilds regardless of which ignore-dir entry would now exclude it. Fixing that means changing the fast path for every ignore-dir entry, which is out of scope for this PR. Filed as #2512 to track separately. Existing graphs self-heal via the documented --no-incremental full rebuild in the meantime.

]),
);

Expand Down
10 changes: 10 additions & 0 deletions tests/unit/builder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,15 @@ beforeAll(() => {
// secret.js (hidden dir, ignored)
// vendor/
// third.js (in IGNORE_DIRS)
// target/
// debug/build.rs (Rust build output, in IGNORE_DIRS)
fs.mkdirSync(path.join(tmpDir, 'src'), { recursive: true });
fs.mkdirSync(path.join(tmpDir, 'lib'), { recursive: true });
fs.mkdirSync(path.join(tmpDir, 'node_modules', 'pkg'), { recursive: true });
fs.mkdirSync(path.join(tmpDir, '.git'), { recursive: true });
fs.mkdirSync(path.join(tmpDir, '.hidden'), { recursive: true });
fs.mkdirSync(path.join(tmpDir, 'vendor'), { recursive: true });
fs.mkdirSync(path.join(tmpDir, 'target', 'debug'), { recursive: true });

fs.writeFileSync(path.join(tmpDir, 'src', 'app.js'), 'export default {}');
fs.writeFileSync(path.join(tmpDir, 'src', 'utils.ts'), 'export const x = 1;');
Expand All @@ -48,6 +51,7 @@ beforeAll(() => {
fs.writeFileSync(path.join(tmpDir, '.git', 'config'), '[core]');
fs.writeFileSync(path.join(tmpDir, '.hidden', 'secret.js'), 'export const s = 1;');
fs.writeFileSync(path.join(tmpDir, 'vendor', 'third.js'), 'export const t = 1;');
fs.writeFileSync(path.join(tmpDir, 'target', 'debug', 'build.rs'), 'fn main() {}');
});

afterAll(() => {
Expand Down Expand Up @@ -97,6 +101,12 @@ describe('collectFiles', () => {
expect(inVendor).toHaveLength(0);
});

it('skips target directory (Rust build output)', () => {
const files = collectFiles(tmpDir);
const inTarget = files.filter((f) => f.includes('target'));
expect(inTarget).toHaveLength(0);
});

it('respects config.ignoreDirs', () => {
const files = collectFiles(tmpDir, [], { ignoreDirs: ['lib'] });
const basenames = files.map((f) => path.basename(f));
Expand Down
15 changes: 14 additions & 1 deletion tests/unit/constants.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,16 @@ describe('EXTENSIONS', () => {

describe('IGNORE_DIRS', () => {
it('contains expected directory names', () => {
const expected = ['node_modules', '.git', 'dist', 'build', 'coverage', '__pycache__', 'vendor'];
const expected = [
'node_modules',
'.git',
'dist',
'build',
'coverage',
'__pycache__',
'vendor',
'target',
];
for (const dir of expected) {
expect(IGNORE_DIRS.has(dir)).toBe(true);
}
Expand Down Expand Up @@ -93,6 +102,10 @@ describe('shouldIgnore', () => {
expect(shouldIgnore('.git')).toBe(true);
});

it('returns true for target (Rust build output)', () => {
expect(shouldIgnore('target')).toBe(true);
});

it('returns true for hidden directories (dot prefix)', () => {
expect(shouldIgnore('.hidden')).toBe(true);
expect(shouldIgnore('.cache')).toBe(true);
Expand Down
Loading