[aide] impl: 子计划3: aide flow 流程图集成完成 - PlantUML 校验/构建钩子增强

This commit is contained in:
2025-12-15 18:12:50 +08:00
parent 6a1b230cc9
commit 5f7c91afa1
4 changed files with 83 additions and 11 deletions

View File

@@ -5,6 +5,7 @@ from __future__ import annotations
import shutil
import subprocess
from pathlib import Path
from typing import Any
from aide.core import output
from aide.flow.errors import FlowError
@@ -20,9 +21,10 @@ def run_pre_commit_hooks(
from_phase: str | None,
to_phase: str,
action: str,
config: dict[str, Any] | None = None,
) -> None:
if from_phase == "flow-design" and action in {"next-part", "back-part"}:
_hook_plantuml(root=root)
_hook_plantuml(root=root, config=config)
if from_phase == "docs" and action in {"next-part", "back-part"}:
_hook_changelog_on_leave_docs(root=root, git=git, status=status)
@@ -32,11 +34,49 @@ def run_post_commit_hooks(*, to_phase: str, action: str) -> None:
output.info("请更新 CHANGELOG.md")
def _hook_plantuml(*, root: Path) -> None:
docs_dir = root / "docs"
discuss_dir = root / "discuss"
def _get_plantuml_command(config: dict[str, Any] | None) -> list[str] | None:
"""获取 PlantUML 命令,优先使用配置的 jar 文件。"""
if config:
jar_path = config.get("plantuml", {}).get("jar_path")
java_path = config.get("plantuml", {}).get("java_path", "java")
if jar_path:
# 尝试解析 jar 路径
jar_file = Path(jar_path)
if not jar_file.is_absolute():
# 相对路径,相对于 aide-program 目录
aide_program_dir = Path(__file__).parent.parent.parent
jar_file = aide_program_dir / jar_path
if jar_file.exists():
return [java_path, "-jar", str(jar_file)]
# 回退到系统 plantuml 命令
if shutil.which("plantuml"):
return ["plantuml"]
return None
def _hook_plantuml(*, root: Path, config: dict[str, Any] | None = None) -> None:
"""PlantUML 校验和构建钩子。"""
# 获取流程图目录
diagram_path = ".aide/diagrams"
if config:
diagram_path = config.get("flow", {}).get("diagram_path", diagram_path)
diagram_dir = root / diagram_path
# 收集所有 .puml 文件
candidates: list[Path] = []
for base in (docs_dir, discuss_dir):
# 从配置的流程图目录
if diagram_dir.exists():
candidates.extend([p for p in diagram_dir.rglob("*.puml") if p.is_file()])
candidates.extend([p for p in diagram_dir.rglob("*.plantuml") if p.is_file()])
# 也检查 docs 和 discuss 目录(向后兼容)
for base in (root / "docs", root / "discuss"):
if not base.exists():
continue
candidates.extend([p for p in base.rglob("*.puml") if p.is_file()])
@@ -45,20 +85,42 @@ def _hook_plantuml(*, root: Path) -> None:
if not candidates:
return
if shutil.which("plantuml") is None:
output.warn("未找到 plantuml已跳过 PlantUML 校验/PNG 生成")
# 获取 PlantUML 命令
plantuml_cmd = _get_plantuml_command(config)
if plantuml_cmd is None:
output.warn("未找到 PlantUMLjar 或系统命令),已跳过校验/PNG 生成")
return
# 先校验所有文件
errors: list[str] = []
for file_path in candidates:
result = subprocess.run(
["plantuml", "-tpng", str(file_path)],
plantuml_cmd + ["-checkonly", str(file_path)],
cwd=root,
text=True,
capture_output=True,
)
if result.returncode != 0:
detail = (result.stderr or "").strip() or (result.stdout or "").strip()
raise FlowError(f"PlantUML 处理失败: {file_path} {detail}".strip())
errors.append(f"{file_path.name}: {detail}")
if errors:
error_msg = "\n".join(errors)
raise FlowError(f"PlantUML 语法校验失败:\n{error_msg}")
# 校验通过,生成 PNG
for file_path in candidates:
result = subprocess.run(
plantuml_cmd + ["-tpng", str(file_path)],
cwd=root,
text=True,
capture_output=True,
)
if result.returncode != 0:
detail = (result.stderr or "").strip() or (result.stdout or "").strip()
raise FlowError(f"PlantUML PNG 生成失败: {file_path} {detail}".strip())
output.ok(f"PlantUML 处理完成: {len(candidates)} 个文件")
def _hook_changelog_on_leave_docs(*, root: Path, git: GitIntegration, status: FlowStatus | None) -> None: