Spaces:
Running
Running
| #!/usr/bin/env python3 | |
| """Fail-fast, pre-upload release gate for the public HF Space.""" | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import re | |
| import subprocess | |
| import sys | |
| import urllib.request | |
| from pathlib import Path | |
| ROOT = Path(__file__).resolve().parents[1] | |
| LATEST_MANIFEST_URL = "https://huggingface.co/buckets/mzx/dilutionrisk-public/resolve/manifests/v1/latest.json" | |
| REVISION = re.compile(r"^[0-9a-f]{40}$") | |
| SEMVER = re.compile(r"^\d+\.\d+\.\d+$") | |
| def command(arguments: list[str], *, capture: bool = True) -> str: | |
| result = subprocess.run( | |
| arguments, | |
| cwd=ROOT, | |
| check=True, | |
| text=True, | |
| capture_output=capture, | |
| ) | |
| return (result.stdout or "") + (result.stderr or "") | |
| def read_json(path: Path) -> dict: | |
| return json.loads(path.read_text()) | |
| def fetch_latest_manifest() -> dict: | |
| request = urllib.request.Request( | |
| LATEST_MANIFEST_URL, | |
| headers={"User-Agent": "dilutionrisk-release-gate/1"}, | |
| ) | |
| with urllib.request.urlopen(request, timeout=30) as response: | |
| return json.load(response) | |
| def validate_release_files(root: Path, latest_manifest: dict) -> dict: | |
| release = read_json(root / "release.json") | |
| baseline = read_json(root / "LOAD_BASELINE.json") | |
| readme = (root / "README.md").read_text() | |
| requirements = (root / "requirements.txt").read_text() | |
| if not SEMVER.fullmatch(release.get("service_version", "")): | |
| raise ValueError("release service_version must be semantic x.y.z") | |
| revision = release.get("dataset_revision", "") | |
| if not REVISION.fullmatch(revision): | |
| raise ValueError("release Dataset revision must be a 40-character SHA") | |
| if release.get("dataset_id") != "mzx/dilutionrisk-data": | |
| raise ValueError("release Dataset must stay in the mzx namespace") | |
| if latest_manifest.get("dataset_revision") != revision: | |
| raise ValueError("release Dataset revision does not match the public latest manifest") | |
| if baseline.get("dataset_revision") != revision: | |
| raise ValueError("stored load baseline does not match the release Dataset revision") | |
| hosted = baseline.get("hosted_cpu_basic", {}) | |
| if hosted.get("rest", {}).get("successful") != hosted.get("rest", {}).get("concurrent_requests"): | |
| raise ValueError("stored hosted REST baseline is missing or contains failures") | |
| if hosted.get("mcp", {}).get("successful") != hosted.get("mcp", {}).get("concurrent_sessions"): | |
| raise ValueError("stored hosted MCP baseline is missing or contains failures") | |
| for required in ("sdk_version: 6.20.0", "python_version: '3.13'", "mzx/dilutionrisk-mcp"): | |
| if required not in readme: | |
| raise ValueError(f"README is missing pinned release marker: {required}") | |
| for required in ("gradio==6.20.0", "duckdb==1.4.5", "huggingface-hub==1.8.0"): | |
| if required not in requirements: | |
| raise ValueError(f"requirements lock is missing {required}") | |
| return { | |
| "service_version": release["service_version"], | |
| "dataset_id": release["dataset_id"], | |
| "dataset_revision": revision, | |
| "manifest_published_at": latest_manifest.get("published_at"), | |
| "source_watermark": latest_manifest.get("source_watermark"), | |
| "baseline_service_version": baseline.get("service_version"), | |
| "baseline_build_sha": hosted.get("build_sha"), | |
| } | |
| def run_gate(*, allow_dirty: bool = False, skip_network: bool = False) -> dict: | |
| command(["git", "diff", "--check"]) | |
| status = command(["git", "status", "--porcelain", "--untracked-files=all"]).strip() | |
| if status and not allow_dirty: | |
| raise RuntimeError("release candidate tree is not clean; commit intentional changes first") | |
| test_output = command( | |
| [sys.executable, "-m", "unittest", "discover", "-s", "tests", "-v"] | |
| ) | |
| print(test_output, end="") | |
| match = re.search(r"Ran (\d+) tests", test_output) | |
| if not match: | |
| raise RuntimeError("could not confirm unit-test count") | |
| manifest = ( | |
| {"dataset_revision": read_json(ROOT / "release.json")["dataset_revision"]} | |
| if skip_network | |
| else fetch_latest_manifest() | |
| ) | |
| release = validate_release_files(ROOT, manifest) | |
| return { | |
| "gate": "passed", | |
| "tests_passed": int(match.group(1)), | |
| "git_commit": command(["git", "rev-parse", "HEAD"]).strip(), | |
| "git_tree": command(["git", "rev-parse", "HEAD^{tree}"]).strip(), | |
| **release, | |
| } | |
| def main() -> int: | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--allow-dirty", action="store_true") | |
| parser.add_argument("--skip-network", action="store_true") | |
| options = parser.parse_args() | |
| report = run_gate( | |
| allow_dirty=options.allow_dirty, | |
| skip_network=options.skip_network, | |
| ) | |
| print(json.dumps(report, indent=2, sort_keys=True)) | |
| return 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |