mirror of
https://github.com/safishamsi/graphify.git
synced 2026-10-14 07:59:40 +00:00
Read existing CLI build-config options in fresh and incremental skill
scan fragments, keeping corpus boundaries consistent without changing
standalone detection API defaults. Regenerate all host artifacts and
snapshots. Add rendered-snippet regressions and explicit-override tests.
Fixes #4240.
AI-Assisted-By: AI coding assistant
(cherry picked from commit 3f68952d80)
77 lines
3.7 KiB
Python
77 lines
3.7 KiB
Python
"""Skill scans must preserve the CLI's persisted corpus boundaries (#4240)."""
|
|
from __future__ import annotations
|
|
import json
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
import pytest
|
|
from graphify import paths
|
|
from tools.skillgen import gen
|
|
from graphify.detect import detect, save_manifest
|
|
from graphify.watch import _write_build_config, _read_build_excludes, _read_build_gitignore
|
|
|
|
|
|
def _scan_blocks():
|
|
found = []
|
|
for art in gen.render_all(gen.load_platforms()):
|
|
for block in re.findall(r'```bash\n(.*?)```', art.content, re.S):
|
|
if "result = detect(Path('INPUT_PATH')" not in block and "result = detect_incremental(Path('INPUT_PATH')" not in block:
|
|
continue
|
|
m = re.search(r' -c "\n(.*)\n"', block, re.S)
|
|
if m:
|
|
found.append((art.path, m.group(1).replace('\\"', '"')))
|
|
assert len(found) == 31
|
|
return found
|
|
|
|
|
|
@pytest.mark.parametrize('art,source', _scan_blocks(), ids=lambda value: value.split('\n', 1)[0])
|
|
def test_skill_scan_honors_persisted_options(tmp_path, monkeypatch, art, source):
|
|
monkeypatch.delenv('GRAPHIFY_OUT', raising=False)
|
|
monkeypatch.setattr(paths, 'GRAPHIFY_OUT', 'graphify-out')
|
|
corpus = tmp_path / 'corpus'
|
|
corpus.mkdir()
|
|
subprocess.run(['git', 'init', '-q', str(corpus)], check=True)
|
|
(corpus / '.gitignore').write_text('notes/\n', encoding='utf-8')
|
|
(corpus / 'notes').mkdir()
|
|
(corpus / 'docs').mkdir()
|
|
for name in ('notes/a.md', 'docs/b.md', 'docs/skip.md'):
|
|
(corpus / name).write_text('# sample\n', encoding='utf-8')
|
|
out = tmp_path / 'graphify-out'
|
|
_write_build_config(out, excludes=['docs/skip.md'], gitignore=False)
|
|
# Match the skill's documented CWD-relative output/manifest layout, with
|
|
# INPUT_PATH pointing to a distinct corpus rather than the output parent.
|
|
if 'detect_incremental' in source:
|
|
files = detect(corpus, gitignore=False, extra_excludes=['docs/skip.md'])['files']
|
|
save_manifest(files, str(out / 'manifest.json'), root=corpus)
|
|
# Only exercise the scan contract, not subsequent sidecar/report steps.
|
|
src = source.split('result = ', 1)[0] + 'result = ' + source.split('result = ', 1)[1].split('\n', 1)[0]
|
|
src += '\nprint(json.dumps(result))\n'
|
|
src = src.replace('INPUT_PATH', corpus.as_posix())
|
|
result = subprocess.run([sys.executable, '-c', src], cwd=tmp_path, check=True, capture_output=True, text=True)
|
|
data = json.loads(result.stdout)
|
|
actual = {Path(f).relative_to(corpus).as_posix() for files in data['files'].values() for f in files}
|
|
assert actual == {'notes/a.md', 'docs/b.md'}, art
|
|
if 'detect_incremental' in source:
|
|
assert data['excluded_files'] == [], art
|
|
|
|
|
|
@pytest.mark.parametrize('contents', [None, '{', '[]', '{"gitignore": "false", "excludes": 12}'])
|
|
def test_absent_or_malformed_build_options_use_defaults(tmp_path, contents):
|
|
if contents is not None:
|
|
(tmp_path / '.graphify_build.json').write_text(contents, encoding='utf-8')
|
|
assert _read_build_gitignore(tmp_path) is True
|
|
assert _read_build_excludes(tmp_path) == []
|
|
|
|
|
|
def test_detection_api_explicit_options_are_not_overridden(tmp_path):
|
|
subprocess.run(['git', 'init', '-q', str(tmp_path)], check=True)
|
|
(tmp_path / '.gitignore').write_text('notes/\n', encoding='utf-8')
|
|
(tmp_path / 'notes').mkdir()
|
|
for name in ('notes/a.md', 'keep.md'):
|
|
(tmp_path / name).write_text('# sample\n', encoding='utf-8')
|
|
_write_build_config(tmp_path / 'graphify-out', excludes=['keep.md'], gitignore=False)
|
|
data = detect(tmp_path, gitignore=True, extra_excludes=[])
|
|
actual = {Path(f).name for files in data['files'].values() for f in files}
|
|
assert actual == {'keep.md'}
|