🔧 构建约定#
本文档说明 AgentForge 项目的构建系统配置与日常开发命令约定。
构建后端#
本项目采用 scikit-build-core 作为构建后端,配置位于 pyproject.toml:
[build-system]
build-backend = "scikit_build_core.build"
requires = ["scikit-build-core[pyproject]>=0.12", "setuptools-scm>=8"]
scikit-build-core 负责 PEP 517 构建流程与 PEP 621 元数据读取,当前项目仍是纯 Python 包,不依赖主包 C/C++ 扩展。
包目录映射:源代码位于
src/taolib/,通过tool.scikit-build显式声明:
[tool.scikit-build]
wheel.packages = ["src/taolib"]
sdist.include = ["README.md", "LICENSE", "pyproject.toml", "src/taolib"]
wheel.cmake = false
sdist.cmake = false
这种 src/ 布局可避免开发时误导入未安装的源码,确保测试与 CI 均基于真实安装态运行。wheel.cmake = false 与 sdist.cmake = false 表示当前纯 Python wheel / sdist 不强制执行 CMake;后续若引入原生扩展,再按需启用 CMake 构建。
依赖分组策略#
本项目遵循 PEP 735 的 dependency-groups 规范,将依赖按使用场景拆分为独立的可选依赖与依赖组。
可选依赖(project.optional-dependencies)#
用于运行时按需安装的功能扩展:
分组名 |
用途 |
包含包 |
|---|---|---|
|
GitHub App Token 管理功能 |
|
|
工作流任务执行 |
|
安装示例:
uv sync --extra github-app
依赖组(dependency-groups)#
用于开发、测试、文档等场景的纯工具依赖,不进入运行时包:
分组名 |
用途 |
包含包 |
|---|---|---|
|
开发工具链 |
|
|
文档构建 |
|
|
测试框架 |
|
安装示例:
# 安装全部开发依赖
uv sync --group dev --group test --group docs
# 仅安装测试依赖(CI 场景)
uv sync --group test
# 仅安装文档依赖
uv sync --group dev --group docs
设计原则:
optional-dependencies面向包的使用者(运行时功能开关),dependency-groups面向包的开发者(本地/CI 工具链)。两者职责分离,避免将纯开发工具污染到最终用户环境。
mise 工具链管理#
mise.toml 锁定项目所需的全部外部工具及其精确版本:
[tools]
python = "3.14.5"
uv = "0.11.16"
node = { version = "22.22.3", postinstall = "corepack enable" }
"npm:defuddle" = { version = "0.18.1", depends = ["node"] }
版本冻结策略#
Python 运行时:精确到补丁版本(
3.14.5),确保所有开发者与 CI 环境完全一致工具链:
uv、node、defuddle均声明精确版本,并通过mise install统一安装升级流程:修改
mise.toml→mise install --force→mise run check-env→mise run test
环境变量#
[env]
PYTHONUTF8 = "1"
确保跨平台(尤其是 Windows)下 Python 默认使用 UTF-8 编码,避免中文路径或日志输出时的编码问题。
uv 包管理器使用约定#
本项目统一使用 uv 管理 Python 依赖,禁止直接使用 pip 或 conda。
常用命令#
命令 |
作用 |
|---|---|
|
根据 |
|
同步时包含指定依赖组 |
|
同步时包含指定可选依赖 |
|
在虚拟环境中执行命令 |
|
构建 wheel + sdist |
|
刷新 |
锁文件#
uv.lock必须纳入版本控制,确保所有环境安装完全一致修改
pyproject.toml中的依赖后,执行uv lock或uv sync自动更新
版本管理#
项目采用 动态版本 策略,由 setuptools-scm 从 git tag 自动派生,并通过 scikit-build-core 动态元数据提供给构建后端:
[project]
dynamic = ["version"]
[tool.scikit-build]
metadata.version.provider = "scikit_build_core.metadata.setuptools_scm"
[tool.setuptools_scm]
fallback_version = "0.0.0"
version_file = "src/taolib/_version.py"
version_file_template = "__version__ = '{version}'\n"
version_file 使用相对于项目根目录的路径,构建时实际写入 src/taolib/_version.py。
版本号不硬编码于 pyproject.toml,而是由 setuptools-scm 在打包时从 git tag 自动派生。这种方式确保:
源码中无需手动维护版本字符串
发布流程与 Git 标签天然对齐
预发布版本(alpha/beta/rc)可通过标签直接生成
文档构建时通过 importlib.metadata.version("taolib") 动态解析当前版本号。
配置要点#
⚠️
dynamic、metadata.version.provider与[tool.setuptools_scm]必须配套:
[project] dynamic = ["version"]声明版本由构建阶段动态提供。
[tool.scikit-build] metadata.version.provider = "scikit_build_core.metadata.setuptools_scm"将版本元数据交给 setuptools-scm 解析。
[tool.setuptools_scm] version_file = "src/taolib/_version.py"负责把构建版本写入运行时代码可导入的位置。
运行时入口 src/taolib/__init__.py 通过 from ._version import __version__ 暴露版本号,并在源码树直接运行(未构建安装)时回退到 importlib.metadata.version("taolib"),再降级到 0.0.0+unknown。
setuptools-scm 版本派生规则(PEP 440)#
setuptools-scm 遵循 PEP 440 规则,版本号会诚实反映工作树状态:
git 状态 |
派生版本号示例 |
适用场景 |
|---|---|---|
在 tag commit 上 + 工作树干净 |
|
✅ 正式发布到 PyPI |
tag + N 个新 commit + 工作树干净 |
|
仅 TestPyPI 或本地预览 |
在 tag commit 上 + dirty 工作树 |
|
❌ PyPI 拒收(包含 local segment) |
tag + N 个新 commit + dirty 工作树 |
|
❌ PyPI 拒收 |
关键概念:
.devN:PEP 440 预发布段(pre-release segment),N为距最近 tag 的 commit 数+g<sha>:local version identifier,g是 git 前缀,<sha>是当前 commit 短哈希+d<date>:dirty 标记,本地日期,该形态会被 PyPI 直接拒收
发布流程的工作树洁净度防线#
为防止 dirty 标记污染发布产物,CI 流程设有 三道防线:
flowchart LR
A["release.yml<br/>打 tag 前校验工作树"] --> B["python-publish.yml<br/>build 前再校验工作树"]
B --> C["pyproject.toml<br/>SCM 派生规则本身"]
第 1 道:
.github/workflows/release.yml在打 tag 前执行git status --porcelain校验第 2 道:
.github/workflows/python-publish.yml在mise run package-build之前再次校验第 3 道:
pyproject.toml中 setuptools-scm 动态版本派生规则本身
本地构建发布产物的正确姿势#
如需在本地复现 CI 的纯净构建,遵循以下流程:
git checkout v0.6.0 # 切到目标 tag
git status # 确认输出为空(工作树干净)
uv build # 产物为 taolib-0.6.0-py3-none-any.whl
twine check dist/*.whl # 上传前预校验 PyPI 兼容性
如有未提交改动,先 git stash push -u 暂存,构建完毕后再 git stash pop 恢复。
常用构建命令#
以下命令均通过 mise run 执行,确保跨平台一致性:
环境初始化#
# 一键完成信任、安装、依赖同步与环境校验
mise run init
# 仅检查工具链是否就绪
mise run init-check
# 校验本地工具链版本
mise run check-env
依赖同步#
# 同步全部开发、测试与文档依赖
mise run sync
# 仅安装测试依赖(CI 场景)
mise run install-test-deps
# 仅安装文档依赖
mise run install-docs-deps
测试#
# 运行完整测试集
mise run test
# 运行 GitHub App 专项测试
mise run test-github-app
# 运行带覆盖率的完整测试
mise run test-coverage
# 运行发布前回归测试
mise run test-release
代码质量#
# 运行 pre-commit 全量检查(包含 ruff lint + format + 其他 hooks)
mise run lint
# 仅运行 Ruff 格式化
mise run fmt
# 审计 Python 依赖安全问题
mise run audit
文档构建#
# 构建 HTML 文档
mise run docs-html
# 执行文档外链校验
mise run docs-linkcheck
# CI 文档构建入口
mise run docs-build
包构建#
# 构建 Python 包(wheel + sdist)
mise run package-build
配置速查#
配置文件 |
用途 |
|---|---|
|
Python 包元数据、构建系统、依赖分组、ruff/pytest/coverage 配置 |
|
工具链版本锁定、mise 任务定义、环境变量 |
|
依赖解析锁定文件,确保可复现安装 |
|
pre-commit hooks 配置(ruff、代码格式化等) |
|
Sphinx 文档构建配置 |
|
Sphinx 主题选项配置 |