日常更新

This commit is contained in:
2026-03-29 09:08:01 +08:00
parent 31709425e2
commit befdefd222
224 changed files with 7240 additions and 3297 deletions

View File

@@ -0,0 +1,152 @@
#!/usr/bin/env python3
"""为执行域 doc_id 生成最小闭环骨架docs + ansible/files + verify playbook。
符合 Epic 1 Story 1.3:默认通过 verify_common noop 任务链接入集群基线断言。
"""
from __future__ import annotations
import argparse
import re
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent.parent
DOCS_DIR = ROOT / "docs"
FILES_BASE = ROOT / "ansible" / "files"
VERIFY_DIR = ROOT / "ansible" / "playbooks" / "verify"
EXEC_ID_RE = re.compile(r"^(0[1-9]|[1-9][0-9])-(0[1-9]|[1-9][0-9])$")
def doc_markdown(doc_id: str, slug: str, title: str) -> str:
return f"""# {title}
> **doc_id**`{doc_id}` · 执行域文档(参与 `verify.sh list/full`)。
## 契约与真源
- **清单真源目录**`ansible/files/{doc_id}/`(不要在本文重复粘贴大块 YAML 作为第二真源)。
- **Ansible 验证入口**`ansible/playbooks/verify/{doc_id}.yml`
- 基线断言复用 `ansible/roles/verify_common/tasks/noop-doc-verify.yml`(集群连通 + 可选 manifest dry-run
验收命令:
```bash
./ansible/bin/verify.sh run {doc_id}
```
## 正文
(编写步骤说明;引用清单时请写相对于仓库的路径,例如 `ansible/files/{doc_id}/demo.yaml`。)
"""
def files_readme(doc_id: str) -> str:
return f"""# {doc_id} 清单真源
将本篇相关的 Kubernetes YAML、Helm values 等放在此目录。
- 命名建议:小写 + 连字符,例如 `app-deploy.yaml`。
- 示例或非集群清单可使用 `*.example.yaml` 后缀noop 验证会跳过这类文件的 `kubectl dry-run`。
"""
def verify_playbook(doc_id: str, doc_filename: str) -> str:
return f"""---
- name: "{doc_id} noop verify (scaffold)"
hosts: localhost
gather_facts: false
vars:
repo_root: "{{{{ playbook_dir }}}}/../../.."
doc_id: "{doc_id}"
doc_filename: "{doc_filename}"
tasks:
- name: Include noop doc verify role tasks
ansible.builtin.include_role:
name: verify_common
tasks_from: noop-doc-verify.yml
"""
def parse_args() -> argparse.Namespace:
p = argparse.ArgumentParser(
description="生成执行域 doc_id 最小骨架docs、ansible/files/<doc_id>/、verify playbook。"
)
p.add_argument("doc_id", help="如 04-15XX-YYXX>0 且 YY>0")
p.add_argument("slug", help="文档文件名段,如 k3s-traefik-acme生成 docs/<doc_id>-<slug>.md")
p.add_argument("--title", default="", help="文档 H1 标题(默认从 slug 生成)")
p.add_argument("--dry-run", action="store_true", help="只打印将创建的路径,不写盘")
p.add_argument("--force", action="store_true", help="覆盖已存在的同名目标文件")
return p.parse_args()
def validate_slug(slug: str) -> None:
if not slug or len(slug) > 200:
print("ERR: slug 长度须在 1200 之间", file=sys.stderr)
sys.exit(2)
if slug.strip() != slug:
print("ERR: slug 首尾不应含空白", file=sys.stderr)
sys.exit(2)
if "/" in slug or "\\" in slug or slug.startswith("."):
print("ERR: slug 不允许路径分隔符或以 '.' 开头", file=sys.stderr)
sys.exit(2)
def main() -> None:
args = parse_args()
doc_id = args.doc_id.strip()
slug = args.slug.strip()
if not EXEC_ID_RE.fullmatch(doc_id):
print(f"ERR: doc_id 非法(须匹配执行域 XX-YY{doc_id!r}", file=sys.stderr)
sys.exit(2)
validate_slug(slug)
doc_filename = f"{doc_id}-{slug}.md"
title = args.title.strip() or slug.replace("-", " ").replace("_", " ")
target_doc = DOCS_DIR / doc_filename
target_pb = VERIFY_DIR / f"{doc_id}.yml"
files_dir = FILES_BASE / doc_id
target_readme = files_dir / "README.md"
# 同一 doc_id 仅允许一篇 docs/<doc_id>-*.md与 validate_matrix 一致)
siblings = sorted(DOCS_DIR.glob(f"{doc_id}-*.md"))
for p in siblings:
if p.name != doc_filename:
print(
f"ERR: doc_id={doc_id} 已存在其他文档 {p.relative_to(ROOT)}"
f"请先删除或合并,不能新增第二篇。",
file=sys.stderr,
)
sys.exit(2)
planned = [
("docs", target_doc, doc_markdown(doc_id, slug, title)),
("files README", target_readme, files_readme(doc_id)),
("verify playbook", target_pb, verify_playbook(doc_id, doc_filename)),
]
for label, path, content in planned:
if path.exists() and not args.force:
print(f"ERR: 已存在(使用 --force 覆盖):{path.relative_to(ROOT)}", file=sys.stderr)
sys.exit(2)
if args.dry_run:
print("[dry-run] 将创建:")
for label, path, _ in planned:
print(f" - {label}: {path.relative_to(ROOT)}")
return
for label, path, content in planned:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(content, encoding="utf-8")
print(f"[OK] wrote {path.relative_to(ROOT)}")
print("")
print("下一步:编辑正文与清单,然后执行:")
print(f" ./scripts/offline-check.sh")
print(f" ./ansible/bin/verify.sh run {doc_id}")
if __name__ == "__main__":
main()