Files
Agentic-AI-Template/Document/scripts/validate_workspace.py
T
2026-04-24 08:34:53 +09:00

153 lines
3.9 KiB
Python

#!/usr/bin/env python3
"""Run repository validation commands for the Report Harness template."""
from __future__ import annotations
import json
import os
import subprocess
import sys
from pathlib import Path
DEFAULT_NPM_ORDER = ("lint", "build", "test")
REQUIRED_DOCS = (
"PRD.md",
"ARCHITECTURE.md",
"ADR.md",
"UI_GUIDE.md",
"RESEARCH_LOG.md",
"REPORT_DRAFT.md",
"FEEDBACK.md",
)
REQUIRED_SECTIONS = {
"PRD.md": (
"## 보고서 주제",
"## 용도",
"## 핵심 키워드",
"## 방향성",
),
"RESEARCH_LOG.md": (
"## 출처 목록",
"## 검증 필요",
),
"REPORT_DRAFT.md": (
"## Executive Summary",
"## 참고 출처",
"## 사용자 피드백 질문",
),
"FEEDBACK.md": (
"## 다음 반복에서 확인할 사항",
),
}
def load_env_commands() -> list[str]:
raw = os.environ.get("HARNESS_VALIDATION_COMMANDS", "")
return [line.strip() for line in raw.splitlines() if line.strip()]
def load_npm_commands(root: Path) -> list[str]:
package_json = root / "package.json"
if not package_json.exists():
return []
try:
payload = json.loads(package_json.read_text(encoding="utf-8"))
except json.JSONDecodeError:
return []
scripts = payload.get("scripts", {})
if not isinstance(scripts, dict):
return []
commands = []
for name in DEFAULT_NPM_ORDER:
value = scripts.get(name)
if isinstance(value, str) and value.strip():
commands.append(f"npm run {name}")
return commands
def discover_commands(root: Path) -> list[str]:
env_commands = load_env_commands()
if env_commands:
return env_commands
return load_npm_commands(root)
def validate_report_docs(root: Path) -> list[str]:
errors: list[str] = []
docs_dir = root / "docs"
if not docs_dir.is_dir():
return ["Missing docs/ directory."]
for filename in REQUIRED_DOCS:
path = docs_dir / filename
if not path.exists():
errors.append(f"Missing docs/{filename}.")
continue
text = path.read_text(encoding="utf-8")
if not text.strip():
errors.append(f"docs/{filename} is empty.")
continue
for heading in REQUIRED_SECTIONS.get(filename, ()):
if heading not in text:
errors.append(f"docs/{filename} missing section: {heading}")
return errors
def run_command(command: str, root: Path) -> subprocess.CompletedProcess:
return subprocess.run(
command,
cwd=root,
shell=True,
capture_output=True,
text=True,
)
def emit_stream(prefix: str, content: str, *, stream) -> None:
text = content.strip()
if not text:
return
print(prefix, file=stream)
print(text, file=stream)
def main() -> int:
root = Path(__file__).resolve().parent.parent
doc_errors = validate_report_docs(root)
if doc_errors:
print("Report template validation failed:", file=sys.stderr)
for error in doc_errors:
print(f"- {error}", file=sys.stderr)
return 1
commands = discover_commands(root)
if not commands:
print("Report template validation succeeded.")
print("No extra validation commands configured.")
print("Set HARNESS_VALIDATION_COMMANDS or add npm scripts for lint/build/test if needed.")
return 0
for command in commands:
print(f"$ {command}")
result = run_command(command, root)
emit_stream("[stdout]", result.stdout, stream=sys.stdout)
emit_stream("[stderr]", result.stderr, stream=sys.stderr)
if result.returncode != 0:
print(f"Validation failed: {command}", file=sys.stderr)
return result.returncode
print("Validation succeeded.")
return 0
if __name__ == "__main__":
raise SystemExit(main())