shopstack / scripts /repo_truth.py
pranaysuyash's picture
Sync ShopStack HEAD 6f8adfc
d999bba verified
Raw
History Blame Contribute Delete
4.63 kB
#!/usr/bin/env python3
"""Generate canonical repo truth numbers from the live codebase.
Outputs:
- DB table count
- DB view count
- DB trigger count
- DB index count
- Module count from module_registry
- Tab count from TAB_ORDER
- Service module count
- Test count from pytest collection
Usage:
python3 scripts/repo_truth.py
python3 scripts/repo_truth.py --format json
This script exists per motto_v3 §0.3 (documentation continuity) and
the 2026-06-14 audit recommendation. Run it to keep README.md and
docs/ in sync with the actual code state.
"""
from __future__ import annotations
import json
import re
import subprocess
import sys
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[1]
def count_db_tables() -> int:
"""Count CREATE TABLE IF NOT EXISTS statements in database.py."""
db_file = REPO_ROOT / "shopstack" / "persistence" / "database.py"
content = db_file.read_text(encoding="utf-8")
return len(re.findall(r"CREATE TABLE\s+IF NOT EXISTS\s+\w+", content))
def count_db_views() -> int:
"""Count CREATE VIEW statements in database.py."""
db_file = REPO_ROOT / "shopstack" / "persistence" / "database.py"
content = db_file.read_text(encoding="utf-8")
return len(re.findall(r"CREATE VIEW\s+IF NOT EXISTS\s+\w+", content))
def count_db_triggers() -> int:
"""Count CREATE TRIGGER statements in database.py."""
db_file = REPO_ROOT / "shopstack" / "persistence" / "database.py"
content = db_file.read_text(encoding="utf-8")
return len(re.findall(r"CREATE TRIGGER\s+IF NOT EXISTS\s+\w+", content))
def count_db_indexes() -> int:
"""Count CREATE INDEX statements in database.py."""
db_file = REPO_ROOT / "shopstack" / "persistence" / "database.py"
content = db_file.read_text(encoding="utf-8")
return len(re.findall(r"CREATE INDEX\s+IF NOT EXISTS\s+\w+", content))
def list_table_names() -> list[str]:
"""List all DB table names."""
db_file = REPO_ROOT / "shopstack" / "persistence" / "database.py"
content = db_file.read_text(encoding="utf-8")
return sorted(re.findall(r"CREATE TABLE\s+IF NOT EXISTS\s+(\w+)", content))
def count_modules() -> int:
"""Count registered modules in module_registry."""
try:
from shopstack.module_registry import get_all
return len(get_all())
except Exception:
return -1
def count_tabs() -> int:
"""Count tabs in TAB_ORDER."""
try:
from shopstack.module_registry import TAB_ORDER
return len(TAB_ORDER)
except Exception:
return -1
def count_test_files() -> int:
"""Count test files in tests/."""
tests_dir = REPO_ROOT / "tests"
return sum(1 for p in tests_dir.glob("test_*.py") if p.is_file())
def collect_pytest_output() -> dict[str, int | str]:
"""Run pytest --collect-only and parse the summary line."""
try:
result = subprocess.run(
["python3", "-m", "pytest", "--collect-only", "-q"],
cwd=REPO_ROOT,
capture_output=True,
text=True,
timeout=120,
)
output = result.stdout + result.stderr
# Look for "N tests collected" or similar
m = re.search(r"(\d+)\s+tests?\s+collected", output)
if m:
return {"tests_collected": int(m.group(1))}
except Exception as e:
return {"error": str(e)}
return {}
def main() -> int:
tables = list_table_names()
truth = {
"database": {
"tables": count_db_tables(),
"views": count_db_views(),
"triggers": count_db_triggers(),
"indexes": count_db_indexes(),
"table_names": tables,
},
"modules": {
"registered": count_modules(),
"tabs": count_tabs(),
},
"tests": {
"files": count_test_files(),
**collect_pytest_output(),
},
}
if "--format" in sys.argv and "json" in sys.argv:
print(json.dumps(truth, indent=2))
else:
print(f"DB tables: {truth['database']['tables']}")
print(f"DB views: {truth['database']['views']}")
print(f"DB triggers: {truth['database']['triggers']}")
print(f"DB indexes: {truth['database']['indexes']}")
print(f"Modules: {truth['modules']['registered']}")
print(f"Tabs: {truth['modules']['tabs']}")
print(f"Test files: {truth['tests']['files']}")
if "tests_collected" in truth["tests"]:
print(f"Tests collected: {truth['tests']['tests_collected']}")
return 0
if __name__ == "__main__":
sys.exit(main())