外观
贡献指南
本文讲怎么搭开发环境、跑测试、刷新 golden、代码风格、提 PR,以及文档维护约定。系统原理见 内部原理。
开发环境
需要 Python 3.11+。
bash
git clone https://github.com/chidakiko/dn42-control-backend.git
cd dn42-control-backend
python -m venv .venv
source .venv/bin/activate
# 一方包 + 应用 + 开发依赖(editable)
pip install \
-e packages/dn42_common \
-e packages/dn42_registry \
-e packages/dn42_schemas \
-e packages/dn42_runtime \
-e packages/dn42_templates \
-e apps/control-server \
-e apps/auth-server \
-e apps/registry-server \
-e apps/node-agent \
-e ".[dev]"九个都要装。 漏装的包在 pytest 下仍能导入——pyproject.toml 的 [tool.pytest.ini_options].pythonpath 兜了底——但纯 python -c "import ..." 与编辑器的 静态解析会失败,表现为「无法解析导入 dn42_registry」这类只在 IDE 里出现的红波浪线。 装完用这条自检(它不吃 pytest 的 pythonpath,比跑测试更能暴露漏装):
bash
python -c "import dn42_common, dn42_registry, dn42_schemas, dn42_runtime, dn42_templates; import app.main, authserver.main, registryserver.main, agent.main; print('ok')"pip list | grep -i dn42 应列出九个包。若出现指向已不存在目录的残留编辑态安装(目录改名或组件下线后常见), pip uninstall 掉即可——editable 安装不会随目录消失而失效,只会在导入时报错。
跑测试
pyproject.toml 已配 testpaths 与 pythonpath:
bash
python -m pytest # 全部(共享包 + control-server + node-agent)
python -m pytest tests/unit # 仅共享包单测
python -m pytest tests/unit/test_desired_state_schema.py -q # 指定文件
python -m compileall apps packages tests # 语法/导入检查测试分层
| 层 | 目录 | 覆盖 |
|---|---|---|
| Control Server | apps/control-server/app/tests/ | health、DB repositories、注册、Bearer/WS 鉴权、admin CRUD、token/健康 |
| Node Agent | apps/node-agent/agent/tests/ | config、naming、CLI、持久化、orchestrator、watch、planner、apply backends、convergence、collectors |
| 共享包 | tests/unit/ | 校验器、labels/naming/communities、schemas、canonical IO、templates、runtime、agent 协议、导入、lab 示例 |
| 集成 | tests/integration/ | test_three_node_control_plane.py:真实多节点闭环(provision → 注册 → WS → reconcile → 上报) |
Control Server 用 FastAPI TestClient + 临时 SQLite + WS test client;Node Agent 用 fake controller/docker/executor + tmp_path,多数单测不需 Docker。
Golden 渲染回归
tests/unit/test_golden_rendered_hkg1.py 把 build_hkg1_example_state() 的渲染产物与 examples/rendered-hkg1/ 逐字节对比,保护模板输出不被意外改变。只有在 schema 默认值、模板或 runtime 输出有意改变时才刷新:
bash
python -c "from pathlib import Path; from dn42_schemas.testing import build_hkg1_example_state; from dn42_templates import render_desired_state; from dn42_runtime import write_rendered_files; write_rendered_files(render_desired_state(build_hkg1_example_state()), Path('examples/rendered-hkg1'))"
python -m pytest tests/unit/test_golden_rendered_hkg1.py -q访问 Docker 的命令
多数单测不需 Docker。下面会连 Docker Engine(没起 Docker 时可能因连不上 socket/named pipe 失败):
bash
python -m agent.main --plan-only --state-dir .agent-state
python -m agent.main --once --state-dir .agent-state --desired-state state.json代码风格
ruff(行宽 100):ruff check ./ruff format .。- 公共 API 写 docstring;面向用户的文档放
docs/。
提交 PR
- 从
main切分支。 - 提交信息用约定式前缀(
feat:/fix:/docs:/chore:/refactor:…)。 - 确保
python -m pytest全绿。 - 开 PR,说明动机与改动点。
- 协议模型是 Pydantic
StrictModel(extra=forbid):增删字段涉及 agent 与控制面的锁步发布顺序,规则见 锁步契约。
文档维护约定
文档与代码同等重要,改了行为就改文档。
- 单一事实源——每个主题只在一处详写,其余处链接:
- 配置、环境变量、CLI → 配置参考 与 CLI 与脚本
- API → API 参考
- schema 字段 → DesiredState 参考
- 表结构 → 数据库参考
- 分层放置(Diátaxis)——手把手入门放
tutorials/;任务步骤放guides/;查得到的事实放reference/;为什么与怎么运转放internals/。导航在 文档中心。 - 与代码同步——改了接口、配置、表、运行模式或 schema,同步对应参考文档;schema 与模板变化要刷新 golden。
- 写当前状态,不写演进过程——文档描述系统现在是什么样,不叙述它曾经是什么样、也不按开发批次组织内容。历史只在解释「为什么是现在这样」时出现,且要说清约束而非编年。
- 中立表述——不用第一与第二人称。
- 示例可执行——命令能在仓库根直接复制运行,且已脱敏(不放真实 IP 与密钥)。
- 交叉引用代码——用文件路径指向源码,路径要指向当前实际存在的位置。
- 链接用相对路径,新增文档记得加进 文档中心 导航表。改文件名或拆分文档时,全量跑一遍链接检查。