90 lines
2.8 KiB
Python
90 lines
2.8 KiB
Python
# -*- coding: utf-8 -*-
|
|||
|
|
"""M2 实施基线文档一致性校验(issue #1 辅助脚本)。
|
||
|
|
|
||
|
|
校验项:
|
||
|
|
1. 必备章节齐全(目标/现状盘点/改造清单/里程碑与风险/验收对照/关联);
|
||
|
|
2. 引用的配置资产路径在仓库中存在(防文档指向缺失文件);
|
||
|
|
3. 关键验收关键词存在(配置驱动/模板配置台/缓冲/RISK 风险标注)。
|
||
|
|
"""
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import os
|
||
|
|
import re
|
||
|
|
import sys
|
||
|
|
|
||
|
|
REPO_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||
|
|
DOC = os.path.join(REPO_ROOT, "docs", "M2内核平台化改造_实施基线.md")
|
||
|
|
|
||
|
|
REQUIRED_SECTIONS = [
|
||
|
|
"目标与范围",
|
||
|
|
"现状盘点",
|
||
|
|
"改造清单",
|
||
|
|
"里程碑与风险",
|
||
|
|
"验收对照",
|
||
|
|
"关联",
|
||
|
|
]
|
||
|
|
|
||
|
|
KEYWORDS = ["配置驱动", "Template Console", "模板配置台", "预留 2 周缓冲", "iAOP-Core 可用"]
|
||
|
|
|
||
|
|
# 文档中应引用的内核配置资产(以仓库内路径出现,支持 {a,b} 集合写法)
|
||
|
|
EXPECTED_ASSETS = [
|
||
|
|
"core/edge-gateway/config/gateway.example.yaml",
|
||
|
|
"core/data-bus/config/{kafka,postgres,retention,minio}.template.yaml",
|
||
|
|
"core/llm-gateway/config/{router,prompts}.template.yaml",
|
||
|
|
"core/rag-kb/config/kb.template.yaml",
|
||
|
|
"core/inference-backend/config/backends.template.yaml",
|
||
|
|
"deploy/k8s/helm/iaop",
|
||
|
|
"templates/resin/dashboard/cockpit.resin.yaml",
|
||
|
|
]
|
||
|
|
|
||
|
|
|
||
|
|
def expand_braces(path: str) -> list:
|
||
|
|
"""展开 {a,b} 集合写法:a/{b,c}.yaml -> [a/b.yaml, a/c.yaml]。"""
|
||
|
|
m = re.search(r"\{(.+?)\}", path)
|
||
|
|
if not m:
|
||
|
|
return [path]
|
||
|
|
parts = m.group(1).split(",")
|
||
|
|
prefix, suffix = path.split(m.group(0), 1)
|
||
|
|
return [prefix + p + suffix for p in parts]
|
||
|
|
|
||
|
|
|
||
|
|
def main() -> int:
|
||
|
|
with open(DOC, encoding="utf-8") as f:
|
||
|
|
text = f.read()
|
||
|
|
|
||
|
|
errors = []
|
||
|
|
|
||
|
|
# 1. 必备章节
|
||
|
|
for sec in REQUIRED_SECTIONS:
|
||
|
|
if sec not in text:
|
||
|
|
errors.append("缺少必备章节: %s" % sec)
|
||
|
|
|
||
|
|
# 2. 配置资产引用存在(支持 {a,b} 集合写法:原始形式或展开后任一命中)
|
||
|
|
for asset in EXPECTED_ASSETS:
|
||
|
|
candidates = expand_braces(asset)
|
||
|
|
if asset in text or any(a in text for a in candidates):
|
||
|
|
for a in candidates:
|
||
|
|
if not os.path.exists(os.path.join(REPO_ROOT, a)):
|
||
|
|
errors.append("引用资产不存在: %s" % a)
|
||
|
|
else:
|
||
|
|
errors.append("未引用核心资产: %s" % asset)
|
||
|
|
|
||
|
|
# 3. 验收关键词
|
||
|
|
for kw in KEYWORDS:
|
||
|
|
if kw not in text:
|
||
|
|
errors.append("缺少验收关键词: %s" % kw)
|
||
|
|
|
||
|
|
if errors:
|
||
|
|
print("FAIL")
|
||
|
|
for e in errors:
|
||
|
|
print(" - %s" % e)
|
||
|
|
return 1
|
||
|
|
|
||
|
|
print("PASS — 章节 %d 项、资产引用 %d 项、关键词 %d 项全部通过" %
|
||
|
|
(len(REQUIRED_SECTIONS), len(EXPECTED_ASSETS), len(KEYWORDS)))
|
||
|
|
return 0
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
sys.exit(main())
|