diff --git a/CHANGELOG.md b/CHANGELOG.md index c9f15c8331..40beb591d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -233,6 +233,7 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). #### Symbols, tests and the viewer +- Java packages named `build` under standard main and test source roots are now indexed without pulling Gradle or Maven build output into the graph. (#1642) - Kotlin functions and methods now carry their signature — `(params): ReturnType` — in `codegraph_explore`, `node` and the viewer, instead of no signature at all. Re-index Kotlin projects after upgrading. (#1495) - `codegraph affected` now finds Go, Python and JVM test files that previously went unreported, while preserving custom `--filter` behavior (thanks @danusha2345; #1507, #1688). diff --git a/__tests__/extraction.test.ts b/__tests__/extraction.test.ts index 16e0fc2449..8fd91d7dd7 100644 --- a/__tests__/extraction.test.ts +++ b/__tests__/extraction.test.ts @@ -8188,6 +8188,39 @@ describe('Nested non-submodule git repos', () => { expect(ig.ignores('src/app.ts')).toBe(false); }); + it('keeps Java packages named build while excluding build output (#1642)', () => { + const sourceFile = 'module/src/main/java/com/acme/build/RealtimePlusService.java'; + const testFile = 'module/src/test/java/com/acme/build/RealtimePlusServiceTest.java'; + const outputFile = 'module/build/generated/Generated.java'; + + for (const rel of [sourceFile, testFile, outputFile]) { + const abs = path.join(tempDir, rel); + fs.mkdirSync(path.dirname(abs), { recursive: true }); + fs.writeFileSync(abs, 'class Example {}\n'); + } + + const scope = buildScopeIgnore(tempDir); + expect(scope.ignores(sourceFile)).toBe(false); + expect(scope.ignores(testFile)).toBe(false); + expect(scope.ignores(outputFile)).toBe(true); + + const files = scanDirectory(tempDir); + expect(files).toContain(sourceFile); + expect(files).toContain(testFile); + expect(files).not.toContain(outputFile); + }); + + it('lets an explicit .gitignore exclude a Java package named build (#1642)', () => { + const sourceFile = 'src/main/java/com/acme/build/Hidden.java'; + const abs = path.join(tempDir, sourceFile); + fs.mkdirSync(path.dirname(abs), { recursive: true }); + fs.writeFileSync(abs, 'class Hidden {}\n'); + fs.writeFileSync(path.join(tempDir, '.gitignore'), 'src/main/java/**/build/\n'); + + expect(buildScopeIgnore(tempDir).ignores(sourceFile)).toBe(true); + expect(scanDirectory(tempDir)).not.toContain(sourceFile); + }); + it('buildDefaultIgnore honors .git/info/exclude (#1728)', async () => { const { execFileSync } = await import('child_process'); const git = (cwd: string, ...args: string[]) => diff --git a/src/extraction/index.ts b/src/extraction/index.ts index 8095ee5b58..94d22308d0 100644 --- a/src/extraction/index.ts +++ b/src/extraction/index.ts @@ -237,6 +237,12 @@ const DEFAULT_IGNORE_PATTERNS: string[] = [ 'bazel-*/', // Bazel output symlink trees // Android resource dirs at any depth, with their qualifier variants (#1047). ...ANDROID_RES_TYPES.map((t) => `**/res/${t}*/`), + // `build` is also a legal Java package segment. Keep it under conventional + // Java source roots while continuing to exclude module/build output (#1642). + '!**/src/main/java/**/build/', + '!**/src/main/java/**/build/**', + '!**/src/test/java/**/build/', + '!**/src/test/java/**/build/**', ]; /** True if `buf` decodes as strict UTF-8 (no invalid byte sequences). */