[moz] impl(§21): toolchain-templates.yaml + Issue 模板补全 + G1 修复 #106

Merged
pangtong-fujunshi merged 2 commits from impl/21-toolchain-templates-and-cleanup into main 2026-06-20 15:35:59 +00:00
7 changed files with 322 additions and 3 deletions
+27
View File
@@ -0,0 +1,27 @@
name: 文档任务
about: 编写或更新文档
title: "[moz] docs: "
labels:
- type/docs
body:
- type: textarea
id: description
attributes:
label: 文档目标
description: 要写什么文档,解决什么问题
validations:
required: true
- type: textarea
id: path
attributes:
label: 文档路径
description: 目标文件路径(如 docs/design/xxx.md
validations:
required: true
- type: textarea
id: outline
attributes:
label: 大纲
description: 文档结构和要点
validations:
required: true
+33
View File
@@ -0,0 +1,33 @@
name: 实现任务
about: 按设计文档实现功能
title: "[moz] impl: "
labels:
- type/feature
body:
- type: textarea
id: description
attributes:
label: 实现目标
description: 清晰描述要实现什么
validations:
required: true
- type: textarea
id: design_doc
attributes:
label: 设计文档
description: 关联的设计文档路径(如 docs/design/xxx.md
validations:
required: true
- type: textarea
id: scope
attributes:
label: 实现范围
description: 涉及哪些文件/模块
validations:
required: true
- type: textarea
id: acceptance
attributes:
label: 验收标准
validations:
required: true
+27
View File
@@ -0,0 +1,27 @@
name: 重构任务
about: 重构现有代码
title: "[moz] refactor: "
labels:
- type/refactor
body:
- type: textarea
id: description
attributes:
label: 重构目标
description: 为什么重构,期望改善什么
validations:
required: true
- type: textarea
id: scope
attributes:
label: 影响范围
description: 涉及哪些文件/模块,是否有 breaking change
validations:
required: true
- type: textarea
id: tests
attributes:
label: 测试保障
description: 重构前哪些测试必须通过
validations:
required: true
+171
View File
@@ -0,0 +1,171 @@
# toolchain-templates.yaml
# §21 §4 steps 模板化 — 按 action_type + business_type 查找
# 占位符 {issue_number}/{brief}/{title}/{pr_number} 等运行时渲染
# ---------------------------------------------------------------------------
# issue_assigned(按 Issue label 分 6 路 + infrastructure
# ---------------------------------------------------------------------------
issue_assigned:
feature:
steps:
- "理解需求(Issue body)→ 如有不明确在 Issue comment 追问"
- "git checkout main && git pull origin main"
- "git checkout -b feat/{issue_number}-{brief}"
- "编码实现 + 写 UT"
- "文档同步:如果本次改动涉及设计变更或接口变更,在同一分支更新 docs/design/ 对应文档。如无需更新,在 action report 中说明「文档无需更新」"
- "git add -A && git commit -m '[moz] feat: {title}' && git push origin feat/{issue_number}-{brief}"
- "CI 通过后创建 PRbody 含 Closes #{issue_number}"
- "等 Review"
output_template: |
[Action Report]
**分支**feat/{issue_number}-{brief}
**PR**#{pr_number}
**改动文件**{files}
**CI**{ci_status}
**文档同步**{doc_status}
impl:
steps:
- "读设计文档(Issue body 中的路径)→ 理解实现范围"
- "git checkout main && git pull origin main"
- "git checkout -b impl/{issue_number}-{brief}"
- "按设计编码实现 + 写 UT"
- "文档同步:如果本次改动涉及设计变更或接口变更,在同一分支更新 docs/design/ 对应文档。如无需更新,在 action report 中说明「文档无需更新」"
- "git add -A && git commit -m '[moz] impl: {title}' && git push origin impl/{issue_number}-{brief}"
- "CI 通过后创建 PRbody 含 Closes #{issue_number} + 设计文档路径)"
- "等 Review"
output_template: |
[Action Report]
**设计文档**{design_doc}
**分支**impl/{issue_number}-{brief}
**PR**#{pr_number}
**改动文件**{files}
**CI**{ci_status}
**文档同步**{doc_status}
bug:
steps:
- "读 Bug 描述 + 复现步骤(Issue body"
- "定位根因(读代码/日志,不要猜测)"
- "git checkout main && git pull origin main"
- "git checkout -b fix/{issue_number}-{brief}"
- "修复 + 写回归测试"
- "文档同步:如修复涉及设计/接口变更,同步更新 docs/design/ 对应文档"
- "git add -A && git commit -m '[moz] fix: {title}' && git push origin fix/{issue_number}-{brief}"
- "CI 通过后创建 PRbody 含 Closes #{issue_number} + 根因和修复方式)"
- "等 Review"
output_template: |
[Action Report]
**根因**{root_cause}
**修复方式**{fix_approach}
**分支**fix/{issue_number}-{brief}
**PR**#{pr_number}
**CI**{ci_status}
**文档同步**{doc_status}
docs:
steps:
- "读文档目标(Issue body"
- "git checkout main && git pull origin main"
- "git checkout -b docs/{issue_number}-{brief}"
- "编写文档到 docs/ 对应目录"
- "git add -A && git commit -m '[moz] docs: {title}' && git push origin docs/{issue_number}-{brief}"
- "创建 PRbody 含 Closes #{issue_number}"
- "等 Review"
output_template: |
[Action Report]
**文档路径**{doc_path}
**分支**docs/{issue_number}-{brief}
**PR**#{pr_number}
refactor:
steps:
- "读重构目标 + 影响范围(Issue body"
- "git checkout main && git pull origin main"
- "git checkout -b refactor/{issue_number}-{brief}"
- "重构 + 确保现有测试不 breakpython3 -m pytest tests/unit/ -q"
- "文档同步:如重构涉及架构变更,同步更新 docs/design/ 对应文档"
- "git add -A && git commit -m '[moz] refactor: {title}' && git push origin refactor/{issue_number}-{brief}"
- "CI 通过后创建 PRbody 含 Closes #{issue_number} + 重构内容和影响范围)"
- "等 Review"
output_template: |
[Action Report]
**重构范围**{scope}
**测试结果**{test_result} passed
**分支**refactor/{issue_number}-{brief}
**PR**#{pr_number}
**CI**{ci_status}
**文档同步**{doc_status}
test:
steps:
- "读测试目标(Issue body"
- "git checkout main && git pull origin main"
- "git checkout -b test/{issue_number}-{brief}"
- "编写测试脚本到 tests/ 对应目录"
- "运行测试验证(python3 -m pytest {test_file} -v"
- "git add -A && git commit -m '[moz] test: {title}' && git push origin test/{issue_number}-{brief}"
- "创建 PRbody 含 Closes #{issue_number}"
- "等 Review"
output_template: |
[Action Report]
**测试文件**{test_file}
**测试结果**{test_result}
**分支**test/{issue_number}-{brief}
**PR**#{pr_number}
infrastructure:
steps:
- "根据 Issue body 中的错误来源和日志片段排查问题"
- "修复基础设施问题(CI runner/网络/Gitea/磁盘等)"
- "修复后在 Issue 上 comment 说明修复方式和结果"
- "提交 action reportPOST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/commentscomment_type=action_report"
output_template: |
[Action Report]
**问题**{problem}
**根因**{root_cause}
**修复方式**{fix}
**验证**{verification}
# ---------------------------------------------------------------------------
# ci_failure
# ---------------------------------------------------------------------------
ci_failure:
steps:
- "查看完整 CI 日志(PR 页面或 Gitea Actions 页面)"
- "根据 CI 日志判断失败原因类型:\n a. 代码问题(lint/test 失败)→ 修复失败的测试 → push 到原分支 → CI 自动重跑\n b. 基础设施问题(runner 环境/Python/venv/Gitea/网络故障)→ 在该仓库创建 Issue 指派 jiangwei-infralabel 必须包含 type/infrastructure"
- "文档同步:如修复涉及设计/接口变更,同步更新 docs/design/ 对应文档"
- "提交 action reportPOST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/commentscomment_type=action_report)— 报告中说明判断的原因类型和执行的操作,以及文档是否需要更新"
output_template: |
[Action Report]
**原因类型**{cause_type}
**操作**{action}
**CI 重跑**{ci_status}
**文档同步**{doc_status}
# ---------------------------------------------------------------------------
# review_result — APPROVED
# ---------------------------------------------------------------------------
review_result_approved:
steps:
- "合并 PRGitea API: POST /repos/{repo}/pulls/{pr_number}/merge"
- "提交 action reportPOST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/commentscomment_type=action_report"
output_template: |
[Action Report]
**PR #{pr_number}**merged
# ---------------------------------------------------------------------------
# review_result — REQUEST_CHANGES
# ---------------------------------------------------------------------------
review_result_request_changes:
steps:
- "按审查意见逐条修改代码"
- "文档同步:如审查涉及设计/接口变更,同步更新 docs/design/ 对应文档"
- "push 到原分支 → CI 自动跑"
- "CI 通过后等重新 Review"
- "提交 action reportPOST http://localhost:8083/api/projects/_toolchain/tasks/<task_id>/commentscomment_type=action_report)— 报告中必须说明文档是否需要更新及处理结果"
output_template: |
[Action Report]
**修改内容**{changes}
**CI**{ci_status}
**文档同步**{doc_status}
@@ -2,7 +2,7 @@
title: "Issue-Centric Orchestration — Gitea Issue 替代黑板 DB 协作面"
created: 2026-06-19
version: v2.1 draft
status: draft
status: superseded by §21 (toolchain 部分)
changelog: v2.1 修正 M1dispatcher 直接 SQL 声明)+ M2Phase 格式)+ S1/S2TaskAdapter 残留清理)
v2.0 纳入姜维+司马懿 Review 反馈 + 庞统 Repository 模式修正
v1.1 纳入姜维 Review 反馈
+1 -1
View File
@@ -264,7 +264,7 @@ class ToolchainConstraintsSection:
'| “步骤太多了,选几个做就行” | ❌ 错!必须逐条执行,不可跳过 |',
'| “这个步骤不适用于当前情况” | ❌ 如果确实不适用,在 action report 中说明原因,但其他步骤必须执行 |',
'| “CI/部署失败不是我代码的问题,我什么也不用做” | ❌ 错!即使是基础设施问题,你也必须创建 Issue 指派 jiangwei-infrabody 含错误来源链接 + 日志 + 判断依据),并在 action report 中说明。不能只报告“不是我的问题”就完事 |',
'| "文档以后再说" | ❌ 错!文档同步和代码改动在同一 PR 中完成,action report 中必须说明文档处理情况 |',
'| 文档以后再说 | ❌ 错!文档同步和代码改动在同一 PR 中完成,action report 中必须说明文档处理情况 |',
"",
]
return "\n".join(lines)
+62 -1
View File
@@ -8,7 +8,7 @@ from __future__ import annotations
import logging
from collections import defaultdict
from pathlib import Path
from typing import Dict
from typing import Dict, List, Optional
logger = logging.getLogger(__name__)
@@ -87,3 +87,64 @@ def render_template(name: str, variables: Dict[str, str]) -> str:
def clear_cache() -> None:
"""清空模板缓存(用于测试或热更新)"""
_template_cache.clear()
_steps_cache.clear()
# ---------------------------------------------------------------------------
# §21 §4.2 YAML steps 模板加载
# ---------------------------------------------------------------------------
STEPS_YAML_PATH = Path(__file__).parent.parent.parent / "config" / "toolchain-templates.yaml"
_steps_cache: Optional[dict] = None
def _load_steps_yaml() -> dict:
"""加载并缓存 toolchain-templates.yaml。"""
global _steps_cache
if _steps_cache is not None:
return _steps_cache
try:
import yaml
with open(STEPS_YAML_PATH, encoding="utf-8") as f:
_steps_cache = yaml.safe_load(f) or {}
logger.debug("Loaded steps YAML: %d action_types", len(_steps_cache))
except FileNotFoundError:
logger.warning("Steps YAML not found: %s", STEPS_YAML_PATH)
_steps_cache = {}
except Exception as e:
logger.error("Failed to load steps YAML: %s", e)
_steps_cache = {}
return _steps_cache
def get_steps(action_type: str, business_type: str = "") -> List[str]:
"""从 YAML 模板配置获取 steps。
Args:
action_type: 动作类型issue_assigned / ci_failure / ...
business_type: 业务子类型feature/impl/bug/docs/refactor/test/infrastructure
Returns:
steps 列表找不到返回空列表
"""
templates = _load_steps_yaml()
section = templates.get(action_type, {})
if isinstance(section, dict) and business_type:
subsection = section.get(business_type, {})
return subsection.get("steps", [])
if isinstance(section, dict):
return section.get("steps", [])
return []
def get_output_template(action_type: str, business_type: str = "") -> str:
"""从 YAML 模板配置获取 output_template。"""
templates = _load_steps_yaml()
section = templates.get(action_type, {})
if isinstance(section, dict) and business_type:
subsection = section.get(business_type, {})
return subsection.get("output_template", "")
if isinstance(section, dict):
return section.get("output_template", "")
return ""