88 lines
2.5 KiB
Python
88 lines
2.5 KiB
Python
"""检查 DevHarness 必需文件和任务归档的基本结构。"""
|
||||
|
|
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
import argparse
|
|||
|
|
import re
|
|||
|
|
from pathlib import Path
|
|||
|
|
|
|||
|
|
|
|||
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|||
|
|
REQUIRED_FILES = (
|
|||
|
|
"AGENTS.md",
|
|||
|
|
"README.md",
|
|||
|
|
"docs/00-project-profile.md",
|
|||
|
|
"docs/01-workflow.md",
|
|||
|
|
"docs/templates/task-archive.md",
|
|||
|
|
".gitea/issue_template/epic.md",
|
|||
|
|
".gitea/issue_template/mvp.md",
|
|||
|
|
".gitea/issue_template/task.md",
|
|||
|
|
)
|
|||
|
|
ARCHIVE_HEADINGS = (
|
|||
|
|
"## 背景与目标",
|
|||
|
|
"## 最终方案",
|
|||
|
|
"## 修改文件",
|
|||
|
|
"## 验收结果",
|
|||
|
|
"## 测试",
|
|||
|
|
"## 相关提交",
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def check_required_files(errors: list[str]) -> None:
|
|||
|
|
for relative_path in REQUIRED_FILES:
|
|||
|
|
if not (ROOT / relative_path).is_file():
|
|||
|
|
errors.append(f"缺少必需文件:{relative_path}")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def check_project_profile(errors: list[str], warnings: list[str], strict: bool) -> None:
|
|||
|
|
profile = ROOT / "docs" / "00-project-profile.md"
|
|||
|
|
if not profile.is_file():
|
|||
|
|
return
|
|||
|
|
if "<填写" in profile.read_text(encoding="utf-8"):
|
|||
|
|
message = "项目档案仍有未填写内容"
|
|||
|
|
(errors if strict else warnings).append(message)
|
|||
|
|
|
|||
|
|
|
|||
|
|
def check_archives(errors: list[str]) -> None:
|
|||
|
|
task_dir = ROOT / "docs" / "task"
|
|||
|
|
for path in task_dir.glob("*.md"):
|
|||
|
|
if not re.match(r"^\d+-.+\.md$", path.name):
|
|||
|
|
errors.append(f"归档文件名不符合 <编号>-<标题>.md:{path.name}")
|
|||
|
|
content = path.read_text(encoding="utf-8")
|
|||
|
|
for heading in ARCHIVE_HEADINGS:
|
|||
|
|
if heading not in content:
|
|||
|
|
errors.append(f"{path.name} 缺少章节:{heading}")
|
|||
|
|
if "**未验证部分**:" not in content:
|
|||
|
|
errors.append(f"{path.name} 没有记录未验证部分")
|
|||
|
|
|
|||
|
|
|
|||
|
|
def main() -> int:
|
|||
|
|
parser = argparse.ArgumentParser(description="检查 DevHarness 项目结构")
|
|||
|
|
parser.add_argument(
|
|||
|
|
"--strict",
|
|||
|
|
action="store_true",
|
|||
|
|
help="项目档案有占位内容时返回失败",
|
|||
|
|
)
|
|||
|
|
args = parser.parse_args()
|
|||
|
|
|
|||
|
|
errors: list[str] = []
|
|||
|
|
warnings: list[str] = []
|
|||
|
|
check_required_files(errors)
|
|||
|
|
check_project_profile(errors, warnings, args.strict)
|
|||
|
|
check_archives(errors)
|
|||
|
|
|
|||
|
|
for warning in warnings:
|
|||
|
|
print(f"警告:{warning}")
|
|||
|
|
for error in errors:
|
|||
|
|
print(f"错误:{error}")
|
|||
|
|
|
|||
|
|
if errors:
|
|||
|
|
print(f"检查失败:{len(errors)} 个问题")
|
|||
|
|
return 1
|
|||
|
|
print("DevHarness 检查通过")
|
|||
|
|
return 0
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
raise SystemExit(main())
|