pytest 预发布公告模板解析:从release.pre.rst到 RC 版本发布的完整流水线
【免费下载链接】pytestThe pytest framework makes it easy to write small tests, yet scales to support complex functional testing项目地址: https://gitcode.com/GitHub_Trending/py/pytest
导读
pytest 在正式发布大版本之前,会先发布 RC(Release Candidate)预发布版本,并生成一份面向社区的公告文档。本文以仓库中的 scripts/release.pre.rst 为绝对主线,完整解读这份预发布公告模板的每个组成部分,并结合 scripts/release.py、scripts/prepare-release-pr.py、RELEASING.rst 等源码,讲清模板中的{version}、{contributors}、{doc_version}占位符如何被替换、RC 版本号如何自动推导、公告如何写入 doc/en/announce 目录并被 toctree 收录。读完本文,你将理解 pytest 预发布公告从"模板"到"真实发布页面"的完整生成链路,并掌握自行发布/复现 RC 版本公告的每一步操作。
一、模板在 pytest 发布体系中的定位
pytest 的发布采用"模板驱动"的方式:所有版本公告都从同一组 RST 模板生成,再由脚本填充版本号与贡献者名单。仓库scripts/目录下共有四个公告模板,按发布类型区分:
| 模板文件 | 适用场景 |
|---|---|
| scripts/release.major.rst | 主版本(major)发布公告 |
| scripts/release.minor.rst | 次版本(minor)发布公告 |
| scripts/release.patch.rst | 补丁(bugfix)发布公告 |
| scripts/release.pre.rst | 预发布(prerelease / RC)公告 |
模板的选择逻辑位于 scripts/prepare-release-pr.py:优先major,其次prerelease,再次minor(存在.feature.rst或.breaking.rst变更时),兜底为patch。也就是说,只要发布了 RC 版本,无论它对应的最终版本是主版本还是次版本,使用的都是release.pre.rst这份模板。
这份模板本身是一份"待填充"的 RST 文档,包含三个占位符:{version}、{doc_version}、{contributors}。真实渲染产物可见 doc/en/announce/release-7.0.0rc1.rst 与 doc/en/announce/release-8.0.0rc2.rst。
二、逐段拆解release.pre.rst模板内容
2.1 标题与开篇声明
模板首行为一级标题pytest-{version},其下是等号组成的 RST 标题下划线。渲染后形如pytest-8.0.0rc1。接着是预发布的核心声明:
The pytest team is proud to announce the {version} prerelease! This is a prerelease, not intended for production use, but to test the upcoming features and improvements in order to catch any major problems before the final version is released to the major public.
这里明确了预发布版本的定位:不面向生产环境,目的是在正式版本推向公众前,通过社区提前验证新功能与改进、暴露重大问题。这也是 RC 版本与正式版本在公告措辞上的根本区别——对照 scripts/release.major.rst 可以看到正式版公告直接表述 "pytest {version} has just been released",而预发布版始终强调 "not intended for production use"。
2.2 回归问题报告约定([prerelease]标签)
模板要求测试者将发现的回归问题提交到项目的 issue 跟踪器,并在标题中包含[prerelease]字符串:
We appreciate your help testing this out before the final release, making sure to report any regressions to our issue tracker. When doing so, please include the string
[prerelease]in the title.
这是一个可执行的协作协议:[prerelease]前缀让维护者在海量 issue 中快速识别与 RC 版本相关的回归报告,是预发布质量闭环的关键一环。
2.3 安装命令
模板给出精确版本锁定式安装命令:
pip install pytest=={version}与正式版公告的pip install -U pytest(见 scripts/release.patch.rst)不同,预发布版本强制使用==精确指定版本号(如pip install pytest==8.0.0rc1)。原因在于:RC 版本不会作为最新稳定版被-U自动选中,只有显式指定版本号才能安装到预发布构建。渲染实例见 release-7.0.0rc1.rst 中的pip install pytest==7.0.0rc1。
2.4 CHANGELOG 指引
模板提示用户仔细阅读 CHANGELOG,其中文档链接的版本路径同样由{doc_version}占位符控制,指向该 RC 对应分支的在线文档(如7.0.x分支)。这正是doc_version参数存在的意义:预发布版本的文档链接必须指向仍在维护的分支路径,而不是stable。
2.5 贡献者名单与签名
模板末尾以占位符形式列出:
{contributors} Happy testing, The pytest Development Team贡献者名单由脚本从 git 提交历史中自动提取,渲染后是一个以*开头的无序列表(如 release-7.0.0rc1.rst 中列出的数十位贡献者)。
三、占位符的填充机制:release.py源码级解析
模板本身不能直接发布,所有占位符都由 scripts/release.py 的announce()函数(release.py)填充。整个填充过程分四步:
3.1 从 git 历史提取贡献者
last_version = git describe --abbrev=0 --tags rev_range = f"{last_version}..HEAD" authors = git log rev_range --format=%aN co_authors = git log rev_range --format=%(trailers:key=Co-authored-by)(release.py)贡献者 = 上个 tag 到当前 HEAD 之间的提交作者(%aN)与Co-authored-by 尾注作者的并集,并过滤掉[bot]结尾及pytest bot的自动化账号。名单去重后按字典序排序,再逐行拼成* name形式的 RST 列表,最终作为{contributors}注入模板。
3.2 模板读取与格式化
template_text = Path(__file__).parent.joinpath(template_name).read_text(...) text = template_text.format( version=version, contributors=contributors_text, doc_version=doc_version )(release.py)模板从scripts/目录按传入的template_name读取,用 Python 的str.format()完成占位符替换。这也解释了模板中三个字段的写法:{version}、{contributors}、{doc_version}正是format()的关键字参数名。
3.3 写出公告文件
target = Path(__file__).parent.joinpath(f"../doc/en/announce/release-{version}.rst") target.write_text(text, encoding="UTF-8")(release.py)渲染结果写入 doc/en/announce/release-{version}.rst,文件名为release-+ 版本号,因此 7.0.0rc1 的公告文件名是release-7.0.0rc1.rst。
3.4 更新发布索引
announce()还会把新公告插入 doc/en/announce/index.rst 的 toctree(release.py):在首个release-条目之前插入新文件名,从而保证公告列表按新版本在前排列;若已存在同名条目则跳过并打印提示。这也解释了为什么 index.rst 中release-8.0.0rc2、release-8.0.0rc1排在正式版 8.0.0 之前。
四、RC 版本号如何自动推导
公告的{version}并非人工输入,而是由 prepare-release-pr.py 的find_next_version()根据 git tag 自动计算:
| 发布类型 | 推导公式 | 示例 |
|---|---|---|
| 主版本 | 主版本号+1.0.0+ 预发布后缀 | 7.0.0 →8.0.0rc1 |
| 次版本(有 feature/breaking) | 主.次+1.0+ 后缀 | 7.0.0 →7.1.0rc1 |
| 补丁版本 | 主.次.补丁+1+ 后缀 | 7.0.0 →7.0.1rc1 |
预发布后缀由命令行参数--prerelease提供(如rc1、rc2)。脚本先从git tag中收集所有形如数字.数字.数字的稳定 tag 并排序取最大,再叠加is_major/is_feature_release/prerelease三个因素拼接出下一个版本号。
在 RELEASING.rst 中,"Release candidates"一节给出的实际操作是触发 GitHub Actions workflow:
gh workflow run prepare-release-pr.yml -f branch=8.0.x -f major=yes -f prerelease=rc1该 workflow 会创建release-8.0.0rc1分支、生成公告并提交一个 Release PR。注意prerelease输入为空时(-f prerelease=)则按正式版本发布。
五、从模板到发布:完整流水线调用链
将 scripts/release.py 与 scripts/prepare-release-pr.py 串联起来,一份预发布公告从模板到上线共经历以下环节:
- 入口:tox.ini 定义
[testenv:release]环境,执行python scripts/release.py {posargs};自动化流程则使用[testenv:prepare-release-pr](tox.ini)执行prepare-release-pr.py。tox 环境声明了colorama、pre-commit>=2.9.3、towncrier依赖。 - 分支准备:
prepare-release-pr.py检出origin/{base_branch},根据changelog/目录下是否存在*.feature.rst/*.breaking.rst判断是否功能版本(prepare-release-pr.py),然后创建release-{version}分支并配置pytest bot的 git 身份。 - 版本与模板决策:
find_next_version()计算版本号,按 major → prerelease → minor → patch 顺序选择模板。 - 发布主流程:
pre_release()(release.py)依次执行:announce():填充模板并写出公告、更新 toctree 索引;regen():通过tox -e regen重新生成文档中的示例输出(以SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PYTEST固定版本);changelog():调用towncrier build --yes --version {version}汇总 changelog 目录下的片段(写入时用--draft预览,正式构建时写盘);fix_formatting():pre-commit run --all-files统一格式;check_links():tox -e docs-checklinks校验文档链接(可用--skip-check-links跳过);- 最后
git commit -a生成提交。
- 推送与 PR:强制推送
release-{version}分支,并用gh pr create --draft创建草稿 PR(prepare-release-pr.py),PR 正文提示维护者后续在release-{version}分支上运行 deploy workflow 完成 PyPI 上传与 tag。
由此可以看出:release.pre.rst虽然是全文不到 30 行的模板,但它驱动了"贡献者提取 → 版本渲染 → 公告归档 → 索引更新 → 发布分支 PR"这一整套自动化流水线,是预发布环节的"公告骨架"。
六、真实渲染产物对照与验证
把模板与真实产物对照,可以直观验证占位符替换的正确性:
- release-7.0.0rc1.rst:标题
pytest-7.0.0rc1({version}→7.0.0rc1),安装命令pip install pytest==7.0.0rc1,贡献者列表含数十个* name条目({contributors}渲染结果),文档链接指向7.0.x分支({doc_version}→7.0.x)。 - release-8.0.0rc2.rst:同一模板的第二次 RC 渲染,对应
8.0.0rc2。
此外,从仓库的语义化版本约定看,预发布版本号中 "rc" 前缀遵循 "主.次.补丁+rc序号" 的模式,这也与 doc/en/reference/reference.rst 中对预发布版本组件的描述一致:预发布版本的最后一段为字符串形式的预发布标识。
七、实践要点与注意事项
7.1 安装 RC 版本的正确姿势
预发布公告明确要求使用精确版本安装:
pip install pytest=={version}不要在 RC 阶段使用pip install -U pytest,否则大概率不会命中预发布构建。
7.2 反馈回归问题
发现 RC 回归时,在 issue 标题中带上[prerelease]标记(模板原文要求 exactly[prerelease]),便于维护者分类处理。
7.3 维护者操作要点
- 发布必须基于
release-{version}分支,合并 Release PR 时不要 squash merge,以保证后续 tag 落在主分支提交上(RELEASING.rst); - RC 阶段可向维护分支合入小幅改进,但应避免引入重大变更(RELEASING.rst);
- 发布完成后需将 CHANGELOG 与公告文件 cherry-pick 回
main分支(RELEASING.rst)。
7.4 模板的可扩展性
release.pre.rst与另外三份模板同处 scripts 目录,通过template_name参数切换。若未来要调整公告措辞或新增发布类型,只需修改对应模板或扩展 release.py 的模板选择逻辑,无需改动流水线其余部分——这正是"模板 + 占位符"设计带来的低耦合收益。
结语
release.pre.rst是 pytest 预发布公告的最小事实源:它以三个占位符定义了 RC 公告的完整信息结构(版本、协作协议、安装命令、变更指引、致谢名单),再经由 release.py 的announce()填充、prepare-release-pr.py 的版本推导与分支管理,最终沉淀为 doc/en/announce 目录中一份份可发布的公告文档。理解这条链路,既能帮助测试者正确参与 RC 验证与反馈,也能为其他开源项目设计类似的公告自动化提供可直接借鉴的范本。
【免费下载链接】pytestThe pytest framework makes it easy to write small tests, yet scales to support complex functional testing项目地址: https://gitcode.com/GitHub_Trending/py/pytest
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考