mirror of
https://github.com/codestable/CodeStable.git
synced 2026-09-19 09:03:09 +08:00
30fecaae5e
收敛 CodeStable 主入口、runtime preflight、goal driver 与 skill 工程化评测闭环。 - 根 cs 对行动请求同轮直转,咨询与介绍保持非执行 - feature/issue/refactor/epic/docs 按仓库事实恢复,旧 stage skill 保留兼容薄壳 - repo-local runtime 支持版本检测、安全自动同步和显式 refresh-runtime - 完成 Codex/Claude marketplace 1.0.2、升级文档和回归/评测证据 验证:215 tests passed;package/runtime/diff checks passed;独立 review 与 QA 无 unresolved blocking/important findings。
88 lines
3.4 KiB
Python
88 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Run checklist dod.commands and report real exit codes."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
if os.environ.get("PYTHONDONTWRITEBYTECODE") != "1":
|
|
os.environ["PYTHONDONTWRITEBYTECODE"] = "1"
|
|
os.execvpe(sys.executable, [sys.executable, *sys.argv], os.environ)
|
|
sys.dont_write_bytecode = True
|
|
|
|
from codestable_gate_common import gate_result, load_yaml, main_exit, parse_args, repo_root, run_command
|
|
|
|
|
|
def clear_previous_json_out(json_out: str | None) -> None:
|
|
if not json_out:
|
|
return
|
|
path = Path(json_out)
|
|
if (path.exists() or path.is_symlink()) and not (path.is_dir() and not path.is_symlink()):
|
|
path.unlink()
|
|
|
|
|
|
def collect_commands(checklist: dict[str, Any]) -> list[dict[str, Any]]:
|
|
# Authoritative schema: top-level `dod.commands` (cs-feat-design reference §"DoD
|
|
# Contract" — `dod` is a top-level checklist key alongside `steps`/`checks`).
|
|
# If present, it is the single source — do NOT also pull step-level commands,
|
|
# or a checklist carrying both would execute each command twice.
|
|
top_commands = (checklist.get("dod") or {}).get("commands") or []
|
|
if top_commands:
|
|
return list(top_commands)
|
|
# Backward-compat: no top-level dod → fall back to step-level `dod.commands`.
|
|
commands: list[dict[str, Any]] = []
|
|
for step in checklist.get("steps", []) or []:
|
|
dod = step.get("dod") or {}
|
|
for command in dod.get("commands", []) or []:
|
|
commands.append(command)
|
|
return commands
|
|
|
|
|
|
def main() -> None:
|
|
parser = parse_args("Run explicit checklist dod.commands using real subprocess exit codes.")
|
|
parser.add_argument("--checklist", required=True, help="Path to checklist YAML")
|
|
parser.add_argument("--only", action="append", default=[], help="Run only this command id; repeatable")
|
|
parser.add_argument("--stage", default="implementation.before_review")
|
|
args = parser.parse_args()
|
|
clear_previous_json_out(args.json_out)
|
|
|
|
checklist_path = Path(args.checklist)
|
|
if not checklist_path.exists():
|
|
result = gate_result("dod-runner", args.stage, "blocked", [f"checklist not found: {checklist_path}"])
|
|
main_exit(result, args.json_out)
|
|
|
|
checklist = load_yaml(checklist_path)
|
|
commands = collect_commands(checklist)
|
|
if args.only:
|
|
requested = set(args.only)
|
|
commands = [command for command in commands if command.get("id") in requested]
|
|
if not commands:
|
|
result = gate_result("dod-runner", args.stage, "skipped", warnings=["no matching dod.commands found"])
|
|
main_exit(result, args.json_out)
|
|
|
|
root = repo_root()
|
|
evidence = []
|
|
blocking = []
|
|
warnings = []
|
|
for command in commands:
|
|
run = run_command(str(command.get("command", "")), root)
|
|
run["id"] = command.get("id")
|
|
run["core"] = bool(command.get("core"))
|
|
run["failure_handling"] = command.get("failure_handling")
|
|
evidence.append(run)
|
|
if run["exit_code"] != 0 and run["core"]:
|
|
blocking.append(f"{command.get('id')}: command failed with exit {run['exit_code']}")
|
|
elif run["exit_code"] != 0:
|
|
warnings.append(f"{command.get('id')}: non-core command failed with exit {run['exit_code']}")
|
|
|
|
status = "failed" if blocking else "passed"
|
|
result = gate_result("dod-runner", args.stage, status, blocking, warnings, evidence)
|
|
main_exit(result, args.json_out)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|