"""工具链事件模板引擎(Toolchain Event Hub) 加载 templates/toolchain/ 下的 Markdown 模板,提供 {variable} 占位符渲染。 """ from __future__ import annotations import logging from collections import defaultdict from pathlib import Path from typing import Dict logger = logging.getLogger(__name__) TEMPLATES_DIR = Path(__file__).parent.parent.parent / "templates" / "toolchain" # 模板文件名映射 _TEMPLATE_MAP: Dict[str, str] = { "review_request": "review_request.md", "review_result": "review_result.md", "issue_assigned": "issue_assigned.md", "ci_failure": "ci_failure.md", "deploy_failure": "deploy_failure.md", "review_updated": "review_updated.md", "review_comment": "review_comment.md", "review_merged": "review_merged.md", } # 模板缓存 _template_cache: Dict[str, str] = {} def _load_template(name: str) -> str: """加载并缓存模板文件内容。 Args: name: 模板名称(不含 .md 后缀) Returns: 模板文本内容 Raises: FileNotFoundError: 模板文件不存在 """ if name in _template_cache: return _template_cache[name] filename = _TEMPLATE_MAP.get(name) if not filename: raise ValueError(f"Unknown template: {name}") path = TEMPLATES_DIR / filename if not path.exists(): raise FileNotFoundError(f"Template not found: {path}") content = path.read_text(encoding="utf-8") _template_cache[name] = content logger.debug("Loaded template: %s (%d bytes)", name, len(content)) return content def _escape_braces(value: str) -> str: """转义花括号防止 format_map 报错""" return str(value).replace("{", "{{").replace("}", "}}") def render_template(name: str, variables: Dict[str, str]) -> str: """渲染模板,将 {variable} 占位符替换为实际值。 使用 defaultdict(str) 确保未提供的变量替换为空字符串而非报错。 Args: name: 模板名称 variables: 变量字典 Returns: 渲染后的文本 """ template_text = _load_template(name) # 先对所有变量值转义花括号,防止 format_map 报错 escaped_vars = {k: _escape_braces(v) for k, v in variables.items()} safe_vars: Dict[str, str] = defaultdict(str, escaped_vars) return template_text.format_map(safe_vars) def clear_cache() -> None: """清空模板缓存(用于测试或热更新)""" _template_cache.clear()