Repository navigation
fix(affected): a --filter glob matches whole names, from any folder boundary - #3029
Merged
Merged
Conversation
…oundary `codegraph affected --filter` turned its glob into an unanchored regex by hand (`**` to `.+`, `*` to `[^/]*`, no `^` or `$`), so it matched anywhere inside a path: `tests/**/*.py` missed `tests/x.py` (`.+` needs a folder), a changed `tests/x.py.bak` counted as a test under `tests/*.py`, the changed test itself was missed under `tests/**/*.py`, `e2e/*.spec.ts` took an `xe2e/` folder, and `/tests/*.py` matched only `other/tests/...`. The filter is now a picomatch glob (an existing dependency, loaded only by this command) with `dot: true`, matched against the whole project-relative path. A pattern with no slash matches the file name at any depth. One with a slash matches from any folder boundary, an implicit leading `**/`, which keeps the help text's own `e2e/*.spec.ts` matching `apps/web/e2e/...` as the filter always did; a leading `/` or `./` anchors it at the project root, and a trailing `/` takes everything under that folder. A pattern picomatch rejects is reported as an invalid --filter instead of failing later. Validation: new CLI-level cli-affected-filter-globs tests (6): 4 fail on main's source and pass with the fix; the other 2 guard behavior kept on purpose (file-name patterns at any depth, folders outside the test conventions, dotfiles, a trailing-slash folder). The existing affected CLI suites pass. The triage fixture shows the same before and after. Reimplements PR #1273 by @Jseca666. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
colbymchenry
force-pushed
the
claude/fix-affected-filter-globs
branch
from
October 29, 2026 21:42
7dfaaaa to
a062778
Compare
inth3shadows
added a commit
to inth3shadows/codegraph
that referenced
this pull request
Oct 29, 2026
Brings a38a1ec..60b0d7a (colbymchenry#3028, colbymchenry#3032, colbymchenry#3009, colbymchenry#3029). Clean auto-merge.
bompus
added a commit
to bompus/codegraph
that referenced
this pull request
Oct 30, 2026
…er globs (#589) * fix(spring): a route links the method it annotates, including a package-private one (colbymchenry#3009) The Spring extractor found a mapping's handler with a pattern that wanted `public`, `private` or `protected` (or Kotlin's `fun`) before the name, in the next 600 characters. A package-private handler, like Spring Boot 3's `@GetMapping List<Article> list()`, matched nothing, so its route linked the next method declared with a modifier, or nothing at all, and a method-level `@RequestMapping(value = "/feed", method = GET)` on such a method made no route. A generic Kotlin `fun <T> find()` handler fell through the same way. Separately, a route bound by name alone took the wrong overload when a tall annotation stack (`@Operation`, `@ApiResponses`) above the mapping left the next overload's declaration nearer the annotation. The extractor now reads the declaration the annotation is written on: past it and every annotation stacked with it (arguments read as balanced groups, strings and text blocks included), the modifiers (none at all for a package-private method), type parameters and the return type (void, a primitive, a qualified or nested generic type, an array) to `name(`; for Kotlin, past its modifiers to `fun`, type parameters and `name(`. A field, a constructor or a class under the annotation gives no handler. The mapping annotation's own arguments are read the same balanced way. At resolution, the route's handler reference binds to the method of that name whose span (which starts at its first annotation) holds the annotation's line, the innermost such method; any other case resolves by name as before. Validation, kernel engine, main 01e0ac3 vs this commit: - realworld-java21 93e018e: Spring routes linked 4/19 -> 19/19; the 15 new edges each go to the method the mapping is written on. - spring-petclinic 500158f (17 routes), spring-petclinic-kotlin 817dba3 (18), eladmin 55fbf70 (133), mall dcaa93b (246), dolphinscheduler 21968bc (239): same targets, only the edge metadata changes (exact-match 0.7/0.9 -> framework 0.95). - Controls jsoup 0c508f1 (Java, no Spring), requests 3c7baaa (Python), cobra adbc881 (Go): dump-graph byte-identical. - Index time, median of 3 interleaved: mall 12.3 s vs 12.6 s, eladmin 3.02 s vs 3.03 s (noise on a shared machine). - New tests fail on main's java.ts (20 failing) and pass with the fix, in both engines; dropping the positional binding fails only the overload test. Reimplements PR colbymchenry#851 by @Liurchen, who found the package-private gap. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 3d19da2) * fix(affected): a --filter glob matches whole names, from any folder boundary (colbymchenry#3029) `codegraph affected --filter` turned its glob into an unanchored regex by hand (`**` to `.+`, `*` to `[^/]*`, no `^` or `$`), so it matched anywhere inside a path: `tests/**/*.py` missed `tests/x.py` (`.+` needs a folder), a changed `tests/x.py.bak` counted as a test under `tests/*.py`, the changed test itself was missed under `tests/**/*.py`, `e2e/*.spec.ts` took an `xe2e/` folder, and `/tests/*.py` matched only `other/tests/...`. The filter is now a picomatch glob (an existing dependency, loaded only by this command) with `dot: true`, matched against the whole project-relative path. A pattern with no slash matches the file name at any depth. One with a slash matches from any folder boundary, an implicit leading `**/`, which keeps the help text's own `e2e/*.spec.ts` matching `apps/web/e2e/...` as the filter always did; a leading `/` or `./` anchors it at the project root, and a trailing `/` takes everything under that folder. A pattern picomatch rejects is reported as an invalid --filter instead of failing later. Validation: new CLI-level cli-affected-filter-globs tests (6): 4 fail on main's source and pass with the fix; the other 2 guard behavior kept on purpose (file-name patterns at any depth, folders outside the test conventions, dotfiles, a trailing-slash folder). The existing affected CLI suites pass. The triage fixture shows the same before and after. Reimplements PR colbymchenry#1273 by @Jseca666. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit 60b0d7a) * docs(readme): track upstream through 60b0d7a * fix(spring): read type-use annotations inside return types (colbymchenry#3009 review) `annotatedMethodName` stopped at a type-use annotation in a qualified or array return type, so `public String @nullable [] names()` and `public java.util.@nullable List<String> names()` lost their route's handler link. Read annotations at each return-type position and add both declarations, plus a method-level `@RequestMapping`, to the Spring test. Also correct two copied [Unreleased] bullets that claimed the CLI read commands open the index read-only and report a rebuild: the fork's CLI still opens read-write, so the claims did not describe this fork. Document the affected filter's whole-name, folder-boundary, root-anchor and trailing-slash matching in the README and the site guide. * fix(spring): span consecutive type-use annotations after a qualifier `java.util.@nullable @readonly List<String>` left the second annotation unread, so the method name lookup hit `@` and the route lost its handler. Consume every consecutive annotation after the dot, cover both a `@GetMapping` and a method-level `@RequestMapping` handler, and add the missing "no slash matches the file name" rule to the README's affected filter description. --------- Co-authored-by: Colby Mchenry <me@colbymchenry.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
codegraph affected --filter <glob>matched its glob anywhere inside a path, sotests/**/*.pymissed the tests directly insidetests/, including a changed test file itself, a changedtests/x.py.bakcounted as a test undertests/*.py, ande2e/*.spec.tsmatched anxe2e/folder. The glob now has to match the whole name. A pattern with a folder in it still matches that folder at any depth, as the help text's owne2e/*.spec.tsalways did; a leading/anchors it at the project root.Root cause
The
affectedaction insrc/bin/codegraph.tsturned the glob into a regex by hand, with no anchors:^/$:tests/[^/]*\.pymatches insidetests/x.py.bakandother/tests/x.py, ande2e/...insidexe2e/....**became.+, which needs at least one character, sotests/.+/[^/]*\.pyneeds a folder belowtests/./tests/*.pybecame/tests/..., which only a nestedtests/can match.Fix
A small
affectedFilterMatcherbuilds a picomatch matcher (an existing dependency, loaded lazily, only by this command) withdot: trueandwindows: false(stored paths always use/), tested against the project-relative path:*_test.go,test_*.pye2e/*.spec.ts,tests/**/*.py**/(depth-free, as before, but only at a folder boundary)/or./:/tests/*.py/:tests/The whole name must match, and
**matches zero folders. A pattern picomatch rejects (an empty one) is reported as an invalid--filterbefore the index is opened. The--filterhelp text now says how each form matches.A choice for Colby: slash patterns stay depth-free, so
tests/*.pystill matchesother/tests/test_x.py, the waye2e/*.spec.tsin the help text has always matchedapps/web/e2e/login.spec.ts. Our triage (T8) suggested root-anchoring instead, which is picomatch's default and what #1273 does, with**/e2e/*.spec.tsdocumented for the depth-free case. I kept today's reading so that no existing filter silently starts matching fewer tests, and added the leading/for anchoring. Switching to root-anchoring later is a one-line change inaffectedFilterMatcherplus the help text.Validation
__tests__/cli-affected-filter-globs.test.ts(6 tests, through the built CLI, besidecli-affected-paths.test.ts): 4 fail with main'ssrc/bin/codegraph.tsand all pass with the fix. The other 2 pin what stays the same on purpose: file-name patterns at any depth,checks/*.py(a folder outside the test conventions), dotfiles, and a trailing-slash folder.cli-affected-pathsandcli-affected-test-conventionspass unchanged.math_utils.pyimported by tests at several depths), main's build vs this branch's:affected math_utils.py --filter 'tests/**/*.py'tests/unit/deep/…,tests/unit/…tests/test_math_utils.py,other/tests/test_math_utils.pyaffected tests/test_math_utils.py.bak --filter 'tests/*.py'.bakfileaffected tests/test_math_utils.py --filter 'tests/**/*.py'tests/test_math_utils.py--filter '/tests/*.py'other/tests/test_math_utils.pyonlytests/test_math_utils.pyonlytest_*.py,checks/*.py,tests/*.pyontests/.hidden.pyCODEGRAPH_KERNEL_EXPECT=1,--maxWorkers=2for memory headroom): 791 files (785 passed, 6 skipped), 9,424 tests: 9,339 passed, 0 failed, 85 skipped.Left out
codegraph files --patternand thecodegraph_filestool'spatternuse their own unanchored glob converter (globToRegex) and have the same substring behavior; they are a different surface and are not changed here.Reimplements #1273 by @Jseca666, who found the substring matching and the missing root-level tests; this is an independent implementation (depth-free slash patterns, root anchoring with
/, a trailing-slash folder, lazy picomatch) with new tests, credited in the CHANGELOG.🤖 Generated with Claude Code