"""Command line for ``python build/run.py release``.""" from __future__ import annotations import argparse import sys from pathlib import Path _BUILD_ROOT = Path(__file__).resolve().parents[1] if str(_BUILD_ROOT) not in sys.path: sys.path.insert(0, str(_BUILD_ROOT)) from common.paths import REPO_ROOT # noqa: E402 from common.verify.wheel import ( # noqa: E402 DEFAULT_RUNTIME_CONFIG, default_verification_video, verify_wheel_assets, verify_wheel_runtime, ) from common.verify.wheel_contents import inspect_wheel # noqa: E402 from release.preflight import PreflightOptions, run_preflight # noqa: E402 def _cmd_preflight(argv: list[str]) -> int: parser = argparse.ArgumentParser( prog="build/run.py release preflight", description="Gate a release locally: version, tests, wheel content, runtime.", ) parser.add_argument("--version", help="release version (default: pyproject's dynamic version)") parser.add_argument("--wheel-dir", type=Path, help="directory to inspect (default: SDK/)") parser.add_argument("--video", type=Path, help="clip for the end-to-end runtime check") parser.add_argument("--config", default=DEFAULT_RUNTIME_CONFIG, help="config name for that check") parser.add_argument("--frames", type=int, default=40, help="frames to process (default: 40)") parser.add_argument("--skip-tests", action="store_true", help="skip pytest (recorded in the report)") parser.add_argument("--longrun", action="store_true", help="include the slow long-run stability test") parser.add_argument("--allow-dirty", action="store_true", help="allow a dirty working tree") parser.add_argument( "--force", action="store_true", help="accept a version that a git tag already marks as released", ) parser.add_argument("--check-pypi", action="store_true", help="read PyPI and fail if the version exists") parser.add_argument( "--all-wheel-pythons", action="store_true", help="verify cp310/cp311/cp312 wheels, each in its own conda env", ) parser.add_argument("--offline", action="store_true", help="reuse parent-env deps instead of PyPI") parser.add_argument("--no-runtime", action="store_true", help="skip the isolated runtime check") parser.add_argument("--no-assets", action="store_true", help="skip the bundled-asset check") parser.add_argument("--keep-going", action="store_true", help="collect every failure instead of stopping") parser.add_argument("--report-dir", type=Path, help="override build/release/reports") args = parser.parse_args(argv) options = PreflightOptions( version=args.version, wheel_dir=args.wheel_dir, video=args.video, config_name=args.config, frames=args.frames, skip_tests=args.skip_tests, longrun=args.longrun, allow_dirty=args.allow_dirty, force=args.force, check_pypi=args.check_pypi, all_wheel_pythons=args.all_wheel_pythons, offline=args.offline, keep_going=args.keep_going, report_dir=args.report_dir, no_runtime=args.no_runtime, no_assets=args.no_assets, ) return run_preflight(options, repo_root=REPO_ROOT) def _cmd_audit(argv: list[str]) -> int: parser = argparse.ArgumentParser( prog="build/run.py release audit", description="Inspect one built wheel without a release context.", ) parser.add_argument("wheel", type=Path, help="path to an .whl") parser.add_argument("--expected-version", help="assert the wheel reports this version") parser.add_argument( "--strict-bundle", action="store_true", help="treat bundled-file drift from the current source tree as a failure", ) parser.add_argument("--runtime", action="store_true", help="also install and run the wheel") parser.add_argument("--assets", action="store_true", help="also assert bundled assets load") parser.add_argument("--video", type=Path, help="clip for --runtime") parser.add_argument("--config", default=DEFAULT_RUNTIME_CONFIG) parser.add_argument("--frames", type=int, default=40) parser.add_argument("--offline", action="store_true") parser.add_argument( "--python", type=Path, default=None, help="interpreter to build the verification venv from (default: the running one)", ) args = parser.parse_args(argv) wheel = args.wheel if not wheel.is_file(): print(f"[ERROR] wheel not found: {wheel}", file=sys.stderr) return 2 exit_code = 0 result = inspect_wheel( wheel, expected_version=args.expected_version, repo_root=REPO_ROOT, strict_bundle=args.strict_bundle, ) print(result.render()) if not result.ok: exit_code = 1 if args.assets or args.runtime: try: print(verify_wheel_assets(wheel, python_executable=args.python)) except Exception as exc: print(f"[FAIL] bundled assets: {type(exc).__name__}: {exc}") exit_code = 1 if args.runtime: video = args.video or default_verification_video(REPO_ROOT) if video is None: print("[FAIL] runtime: no verification clip; pass --video or set ORISYS_VERIFY_VIDEO") return 1 try: info = verify_wheel_runtime( wheel, video=video, config_name=args.config, frames=args.frames, python_executable=args.python, offline=args.offline, ) print(f"[ok ] runtime: {info}") except Exception as exc: print(f"[FAIL] runtime: {type(exc).__name__}: {exc}") exit_code = 1 return exit_code def main(argv: list[str] | None = None) -> int: argv = list(sys.argv[1:] if argv is None else argv) if not argv or argv[0] in ("-h", "--help"): print(__doc__) print("Commands: preflight | audit") return 0 command, rest = argv[0], argv[1:] if command == "preflight": return _cmd_preflight(rest) if command == "audit": return _cmd_audit(rest) print(f"Unknown release command: {command!r}", file=sys.stderr) print("Choose from: preflight, audit", file=sys.stderr) return 2 if __name__ == "__main__": raise SystemExit(main())