from pathlib import Path import json import os import shutil import subprocess import sys from typing import Dict, List, Tuple ROOT = Path(__file__).resolve().parents[1] DEFAULT_CHECKS = [ ("unit_tests", [sys.executable, "-m", "unittest", "discover", "-s", "tests/unit", "-p", "test_*.py"]), ("training_case_package", [sys.executable, "scripts/run_training_case_package.py"]), ("migration_static_checks", [sys.executable, "scripts/run_migration_static_checks.py"]), ("script_static_checks", [sys.executable, "scripts/run_script_static_checks.py"]), ("trading_delivery_readiness", [sys.executable, "scripts/check_trading_delivery_readiness.py"]), ("dashboard_js_syntax", ["node", "--check", "src/web/app.js"]), ("training_console_js_syntax", ["node", "--check", "src/web/training.js"]), ] def build_check_commands(env=None) -> List[Tuple[str, List[str]]]: env = os.environ if env is None else env commands = list(DEFAULT_CHECKS) replay_file = env.get("OFFLINE_REPLAY_FILE") if replay_file: commands.append(("replay_file", [sys.executable, "scripts/run_replay_file.py", replay_file])) return commands def run_checks(commands=None, runner=subprocess.run, cwd=ROOT, node_available=None, env=None) -> int: commands = commands or build_check_commands(env=env) if node_available is None: node_available = shutil.which("node") is not None env = os.environ if env is None else env subprocess_env = dict(os.environ) subprocess_env.update(env) json_output = _get_bool(env, "OFFLINE_CHECKS_OUTPUT_JSON", False) results = [] for name, command in commands: if command[0] == "node" and not node_available: results.append({"name": name, "status": "skipped", "exit_code": 0, "reason": "node_not_available"}) if not json_output: print(f"Offline check skipped: {name} (node not available)") continue if not json_output: print(f"Offline check started: {name}") result = runner(command, cwd=cwd, capture_output=True, text=True, check=False, env=subprocess_env) results.append( { "name": name, "status": "passed" if result.returncode == 0 else "failed", "exit_code": result.returncode, "stdout": result.stdout, "stderr": result.stderr, } ) if result.stdout and not json_output: print(result.stdout.rstrip()) if result.stderr and not json_output: print(result.stderr.rstrip()) if result.returncode != 0: if json_output: _print_json_summary(results) else: print(f"Offline check failed: {name} exit_code={result.returncode}") return result.returncode if not json_output: print(f"Offline check passed: {name}") if json_output: _print_json_summary(results) return 0 def main() -> int: return run_checks() def _get_bool(env, key: str, default: bool) -> bool: value = env.get(key) if value is None or value == "": return default return str(value).strip().lower() in {"1", "true", "yes", "on"} def _print_json_summary(results: List[Dict[str, object]]) -> None: print( json.dumps( { "passed": all(item["status"] in {"passed", "skipped"} for item in results), "checks": results, }, ensure_ascii=False, sort_keys=True, ) ) if __name__ == "__main__": raise SystemExit(main())