squid-main-space / scripts /preflight.py
Zin299's picture
Deploy v3.8.0 P0 finish and runtime regression guards
bab19d3
Raw
History Blame
3.54 kB
#!/usr/bin/env python3
from __future__ import annotations
import re
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
errors: list[str] = []
warnings: list[str] = []
def fail(msg: str) -> None:
errors.append(msg)
def warn(msg: str) -> None:
warnings.append(msg)
version_file = ROOT / "VERSION"
version = version_file.read_text(encoding="utf-8").strip() if version_file.exists() else ""
if not re.fullmatch(r"\d+\.\d+\.\d+", version):
fail("VERSION missing or not semantic x.y.z")
readme = (ROOT / "README.md").read_text(encoding="utf-8") if (ROOT / "README.md").exists() else ""
if not readme.startswith("---\n"):
fail("README.md must start with Hugging Face YAML front matter")
else:
end = readme.find("\n---", 4)
if end < 0:
fail("README.md YAML front matter is not closed")
else:
meta = readme[4:end]
for required in ("title:", "sdk: docker", "app_port: 7860"):
if required not in meta:
fail(f"README.md metadata missing: {required}")
app_html = ROOT / "app.html"
if not app_html.exists():
fail("root app.html is missing")
else:
html = app_html.read_text(encoding="utf-8")
if '__APP_VERSION__' not in html:
fail("app.html must use __APP_VERSION__ placeholder")
if 'data-view="projectPackage"' not in html:
fail("project data package sidebar entry is missing")
ui = ROOT / "ui_server.py"
if not ui.exists():
fail("ui_server.py is missing")
else:
text = ui.read_text(encoding="utf-8")
if 'with_name("VERSION")' not in text:
fail("ui_server.py must load VERSION as the single version source")
if 'with_name("app.html")' not in text:
fail("ui_server.py must serve root app.html")
if 'templates/app.html' in text:
fail("ui_server.py still references templates/app.html")
if (ROOT / "templates" / "app.html").exists():
fail("duplicate templates/app.html must not be shipped")
for forbidden in (".pytest_cache", "__pycache__"):
matches = [p for p in ROOT.rglob(forbidden) if p.is_dir()]
if matches:
fail(f"forbidden cache directory present: {matches[0].relative_to(ROOT)}")
if list(ROOT.rglob("*.pyc")):
fail("compiled .pyc files must not be shipped")
for required in (
ROOT / "static" / "css" / "app.css",
ROOT / "static" / "js" / "app.js",
ROOT / "views" / "admin.py",
ROOT / "services" / "project_planner.py",
ROOT / "routes" / "data_health.py",
):
if not required.exists():
fail(f"P0 architecture file missing: {required.relative_to(ROOT)}")
for name in ("Dockerfile", "start.sh", "requirements.txt"):
if not (ROOT / name).exists():
fail(f"deployment file missing: {name}")
if version and f"Current UI release: **v{version}**" not in readme:
warn("README current release line is not synchronized with VERSION")
for msg in warnings:
print(f"[preflight] WARNING: {msg}")
if errors:
for msg in errors:
print(f"[preflight] ERROR: {msg}", file=sys.stderr)
sys.exit(1)
import shutil as _shutil, subprocess as _subprocess
node_bin=_shutil.which("node")
frontend_smoke=ROOT/"scripts"/"frontend_runtime_smoke.js"
if node_bin and frontend_smoke.exists():
proc=_subprocess.run([node_bin,str(frontend_smoke)],cwd=ROOT,capture_output=True,text=True)
if proc.returncode!=0:
error("frontend runtime smoke failed: "+(proc.stderr.strip() or proc.stdout.strip())[:500])
print(f"[preflight] OK: v{version}; single template; clean deployment tree")