Spaces:
Sleeping
Sleeping
File size: 4,993 Bytes
31226fd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | """Validate documentation links and canonical baseline claims."""
from __future__ import annotations
import argparse
import json
import re
import subprocess
import sys
from pathlib import Path
from urllib.parse import unquote
REPO_ROOT = Path(__file__).resolve().parents[1]
DOCS_ROOT = REPO_ROOT / "docs"
ROADMAP_DOCS = (
DOCS_ROOT / "08-roadmap" / "TODO.md",
DOCS_ROOT / "08-roadmap" / "ROADMAP.md",
)
MARKDOWN_LINK = re.compile(r"(?<!!)\[[^\]]+\]\(([^)]+)\)")
BASELINE_PATTERN = re.compile(
r"\*\*Baseline:\*\*\s+`?(?:brain5d-core|mhrn-core)\s+([^`\s]+)`?"
)
COLLECTED_PATTERN = re.compile(r"(\d+)\s+tests collected")
def markdown_files() -> tuple[Path, ...]:
"""Return tracked documentation files in stable order."""
return tuple(sorted(DOCS_ROOT.rglob("*.md")))
def check_markdown_links(files: tuple[Path, ...], root: Path = REPO_ROOT) -> list[str]:
"""Return one error for every missing local Markdown link target."""
root = root.resolve()
errors: list[str] = []
for source in files:
source = source.resolve()
text = source.read_text(encoding="utf-8")
for match in MARKDOWN_LINK.finditer(text):
target = match.group(1).strip().strip("<>")
target = target.split("#", 1)[0].strip()
if not target or target.startswith(
("http://", "https://", "mailto:", "data:")
):
continue
candidate = (source.parent / unquote(target)).resolve()
try:
candidate.relative_to(root)
except ValueError:
errors.append(f"{source}: link escapes repository: {target}")
continue
if not candidate.exists():
errors.append(f"{source}: missing link target: {target}")
return errors
def check_baseline_version() -> list[str]:
"""Ensure the canonical roadmap baseline matches ``pyproject.toml``."""
pyproject = (REPO_ROOT / "pyproject.toml").read_text(encoding="utf-8")
version_match = re.search(r'^version\s*=\s*"([^"]+)"', pyproject, re.MULTILINE)
if version_match is None:
return ["pyproject.toml: canonical project version is missing"]
expected = version_match.group(1)
errors: list[str] = []
for path in ROADMAP_DOCS:
text = path.read_text(encoding="utf-8")
match = BASELINE_PATTERN.search(text)
if match is None:
errors.append(f"{path.relative_to(REPO_ROOT)}: baseline claim is missing")
elif match.group(1) != expected:
errors.append(
f"{path.relative_to(REPO_ROOT)}: baseline {match.group(1)} "
f"does not match {expected}"
)
return errors
def check_collected_test_count() -> list[str]:
"""Reject test-collection regressions relative to the canonical baseline.
``tests/test_baseline.json`` records a verified historical run. Adding new
tests must not make documentation consistency fail merely because that
immutable snapshot is older than the current tree. A lower current count,
however, remains a regression and fails the gate.
"""
result = subprocess.run(
[sys.executable, "-m", "pytest", "--collect-only", "-q"],
cwd=REPO_ROOT,
capture_output=True,
text=True,
check=False,
)
output = f"{result.stdout}\n{result.stderr}"
actual_match = COLLECTED_PATTERN.search(output)
if actual_match is None:
return ["pytest collection did not report a collected test count"]
if result.returncode != 0:
return ["pytest collection failed; a partial count is not a valid baseline"]
baseline_path = REPO_ROOT / "tests" / "test_baseline.json"
try:
baseline = json.loads(baseline_path.read_text(encoding="utf-8"))
declared = int(baseline["full_collection"]["collected"])
except (OSError, ValueError, KeyError, TypeError):
return ["tests/test_baseline.json: canonical collected-test snapshot missing"]
actual = int(actual_match.group(1))
if actual < declared:
return [
"tests/test_baseline.json: test collection regressed "
f"from baseline {declared} to {actual}"
]
return []
def main() -> int:
"""Run documentation checks and return a shell-friendly status code."""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
"--check-tests",
action="store_true",
help="also ensure pytest collection has not regressed below the baseline",
)
args = parser.parse_args()
errors = check_markdown_links(markdown_files())
errors.extend(check_baseline_version())
if args.check_tests:
errors.extend(check_collected_test_count())
if errors:
for error in errors:
print(f"ERROR: {error}")
return 1
print("Documentation consistency checks passed.")
return 0
if __name__ == "__main__":
raise SystemExit(main())
|