66 lines
3.5 KiB
Python
Executable File
66 lines
3.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Compiler-independent source-size and test-isolation contracts for non-Rust modules."""
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
import os
|
|
import re
|
|
import shutil
|
|
import subprocess
|
|
import tempfile
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
MAX_LINES = 500
|
|
|
|
|
|
def lines(path: Path) -> int:
|
|
return len(path.read_text(encoding="utf-8").splitlines())
|
|
|
|
# Browser implementation modules are bounded. Test harnesses under scripts/ are checked separately.
|
|
for path in sorted((ROOT / "src/admin/web").rglob("*.js")):
|
|
assert lines(path) <= MAX_LINES, f"{path.relative_to(ROOT)} has {lines(path)} lines (max {MAX_LINES})"
|
|
|
|
# Docker Agent implementation and Go tests are separate files and all remain bounded.
|
|
for path in sorted((ROOT / "docker-agent").glob("*.go")):
|
|
assert lines(path) <= MAX_LINES, f"{path.relative_to(ROOT)} has {lines(path)} lines (max {MAX_LINES})"
|
|
if not path.name.endswith("_test.go"):
|
|
text = path.read_text(encoding="utf-8")
|
|
assert not re.search(r"(?m)^func\s+Test[A-Z]", text), f"Go test remains in implementation file: {path.relative_to(ROOT)}"
|
|
|
|
# Operational Python entry points are split as product modules; large QA harnesses are intentionally exempt.
|
|
for pattern in ("deploy*.py", "migrate_npm*.py"):
|
|
for path in sorted((ROOT / "scripts").glob(pattern)):
|
|
assert lines(path) <= MAX_LINES, f"{path.relative_to(ROOT)} has {lines(path)} lines (max {MAX_LINES})"
|
|
|
|
for old in (ROOT / "src/admin/web/app.js", ROOT / "src/admin/web/vhosts.js"):
|
|
assert not old.exists(), f"oversized browser monolith returned: {old.relative_to(ROOT)}"
|
|
for required in (
|
|
"src/admin/web/app/core.js", "src/admin/web/app/preferences.js", "src/admin/web/app/config-history.js", "src/admin/web/app/runtime.js", "src/admin/web/app/settings.js",
|
|
"src/admin/web/vhosts/core.js", "src/admin/web/vhosts/editor.js", "src/admin/web/vhosts/render.js",
|
|
"docker-agent/model.go", "docker-agent/docker.go", "docker-agent/network.go",
|
|
"docker-agent/certificate.go", "docker-agent/server.go",
|
|
"scripts/deploy_core.py", "scripts/deploy_runtime.py",
|
|
"scripts/migrate_npm_core.py", "scripts/migrate_npm_api.py",
|
|
):
|
|
assert (ROOT / required).is_file(), f"missing split source module: {required}"
|
|
|
|
|
|
# When Node is available, parse every standalone browser module and both assembled public bundles.
|
|
node = shutil.which("node")
|
|
if node:
|
|
env = dict(os.environ, TERM=os.environ.get("TERM", "xterm"))
|
|
standalone = list((ROOT / "src/admin/web").rglob("*.js"))
|
|
for path in sorted(standalone):
|
|
subprocess.run([node, "--check", str(path)], check=True, env=env, stdout=subprocess.DEVNULL)
|
|
from web_assets import read_app_js, read_vhosts_js
|
|
with tempfile.TemporaryDirectory(prefix="rustproxy-js-contract-") as directory:
|
|
temporary = Path(directory)
|
|
for name, content in (("app.js", read_app_js(ROOT)), ("vhosts.js", read_vhosts_js(ROOT))):
|
|
target = temporary / name
|
|
target.write_text(content, encoding="utf-8")
|
|
subprocess.run([node, "--check", str(target)], check=True, env=env, stdout=subprocess.DEVNULL)
|
|
# The public vhosts asset wraps three individually valid source modules in one private IIFE.
|
|
# Every source part is parsed above; this additional check keeps the assembled browser asset valid.
|
|
|
|
print(f"PASS: browser, Docker Agent and operational Python implementation modules are <= {MAX_LINES} lines, tests are isolated, and browser source boundaries parse cleanly.")
|