mirror of
https://github.com/safishamsi/graphify.git
synced 2026-09-21 21:16:31 +00:00
test(watch): pin update-with-nested-gitignore (#1880); changelog for #1873/#1880
#1880 is the update-layer symptom of the #1873/#1887 nested-ignore
subtree-scoping regression (fixed in fb4d452, @Alwyn93): a nested broad
`.gitignore` zeroed update's re-scan, so it built 0 nodes and the
shrink-guard refused to overwrite. Adds a _rebuild_code regression test
asserting update sees the real files (and still scopes the nested ignore
correctly) so this can't recur at the update layer. Records both
regressions in the unreleased 0.9.16 changelog.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
fb4d45226e
commit
40eae3cea2
@@ -4,6 +4,10 @@ Full release notes with details on each version: [GitHub Releases](https://githu
|
||||
|
||||
## 0.9.16 (unreleased)
|
||||
|
||||
- Fix (regression from 0.9.15): a nested `.gitignore`/`.graphifyignore` no longer applies its patterns outside its own directory (#1873 / #1887 / #1885, thanks @Alwyn93). When 0.9.15 started reading nested ignore files, a non-anchored pattern was still matched against the path relative to the scan root, so a nested bare `*` (a common "ignore this scratch dir" idiom, e.g. what the hypothesis library writes into `.hypothesis/`) matched every file and `detect()` returned zero files, silently producing an empty graph. Patterns are now matched relative to the directory whose ignore file defined them and only apply within that subtree; the anchor directory itself is exempt.
|
||||
|
||||
- Fix (regression from 0.9.15): `graphify update` no longer emits 0 nodes and refuses to overwrite an existing `graph.json` when the source tree contains a nested broad `.gitignore` (#1880). This was the update-layer symptom of the scoping bug above: the zeroed re-scan produced an empty rebuild, which the shrink-guard then correctly refused. With subtree scoping fixed the rebuild sees the real files again; the shrink-guard is unchanged.
|
||||
|
||||
- Fix: `detect_incremental` re-extracts a legacy-manifest file when its mtime moves backwards, not just forwards (#1859 / #1862, thanks @thejesh23). The legacy float-schema branch used a strict `current_mtime > stored`, so a file restored to an older timestamp (a `git checkout` of an older commit, a tarball restore, `rsync --times`) was treated as unchanged and never re-extracted, leaving the graph reflecting newer content than the corpus on disk. It now compares with `!=`, matching the dict-schema branch; with no stored hash to verify, any mtime delta forces a re-extract, and the next save promotes the entry to the hash-verified dict schema.
|
||||
|
||||
- Fix: the dedup summary line reports the fuzzy-merge count even when there were no exact merges (#1857 / #1860, thanks @thejesh23). The fuzzy branch was nested inside `if exact_merges`, so a doc- or semantic-heavy run that merged only via the cross-file fuzzy pass printed a bare `Deduplicated N node(s).` with no breakdown. Both counts are now reported whenever non-zero.
|
||||
|
||||
@@ -188,6 +188,37 @@ def test_rebuild_code_writes_community_name(tmp_path):
|
||||
)
|
||||
|
||||
|
||||
def test_update_rebuilds_with_nested_star_gitignore(tmp_path):
|
||||
"""#1880: `graphify update` must not emit 0 nodes (and then refuse to
|
||||
overwrite) just because the source tree has a nested `.gitignore` with a
|
||||
broad pattern. This was the 0.9.15 symptom of the #1847/#1873 subtree-scoping
|
||||
bug: a nested bare `*` zeroed the re-scan, update built 0 nodes, and the
|
||||
shrink-guard refused. With scoping fixed the rebuild sees the real files."""
|
||||
import json
|
||||
from graphify.watch import _rebuild_code
|
||||
|
||||
corpus = tmp_path / "corpus"
|
||||
(corpus / "src").mkdir(parents=True)
|
||||
(corpus / "src" / "a.py").write_text(
|
||||
"from src.b import Base\nclass App(Base):\n def run(self): return 1\n", encoding="utf-8"
|
||||
)
|
||||
(corpus / "src" / "b.py").write_text("class Base: pass\n", encoding="utf-8")
|
||||
(corpus / "main.py").write_text("def top(): return 2\n", encoding="utf-8")
|
||||
# a common scratch-dir idiom deeper in the tree: ignore everything HERE only
|
||||
(corpus / "scratch").mkdir()
|
||||
(corpus / "scratch" / ".gitignore").write_text("*\n", encoding="utf-8")
|
||||
(corpus / "scratch" / "junk.py").write_text("x = 1\n", encoding="utf-8")
|
||||
|
||||
assert _rebuild_code(corpus, acquire_lock=False) is True
|
||||
|
||||
graph = json.loads((corpus / "graphify-out" / "graph.json").read_text(encoding="utf-8"))
|
||||
sources = {n.get("source_file", "") for n in graph["nodes"]}
|
||||
assert graph["nodes"], "update produced 0 nodes on a tree with a nested '*' gitignore (#1880)"
|
||||
assert any("src/a.py" in s for s in sources) and any("main.py" in s for s in sources)
|
||||
# the nested-ignored scratch file stays out (scoped correctly, not tree-wide)
|
||||
assert not any("scratch/junk.py" in s for s in sources)
|
||||
|
||||
|
||||
def test_graphify_root_preserves_absolute_when_user_supplied(tmp_path):
|
||||
"""When the caller supplies an absolute path, ``.graphify_root`` stores
|
||||
that absolute form verbatim — preserving explicit-absolute intent."""
|
||||
|
||||
Reference in New Issue
Block a user