发布流程¶
*Black* 在标准化和自动化其发布流程方面付出了很多努力。本文档旨在解释一切是如何运作的,以及如何使用上述自动化发布 *Black*。
发布节奏¶
**我们的目标是每 1-2 个月发布一次 main
分支上的内容。** 这样可以确保合并的改进和错误修复能够以合理的频率提供给用户,同时不会因为太多版本而导致用户群体严重分散。这也使维护人员的工作量保持一致和可预测。
如果 main
分支上没有太多新内容值得发布,可以跳过当月的发布。理想情况下,不应该跳过 1 月份的发布,因为根据我们的 稳定性策略,新日历年的第一个发布可能会对 *稳定* 风格进行更改。虽然该策略适用于第一个发布(而不是仅限于 1 月份发布),但将对稳定风格的更改限制在 1 月份将使事情对用户而言更可预测(和更友善)。
除非出现严重的回归或错误需要立即修补,**每个月不应发布超过一次**。虽然版本号并不昂贵,但发布需要维护人员承诺进行实际的版本切割,同时还要能够处理发布后的潜在影响。比每月发布更频繁的发布会带来迅速减少的回报。
切割发布¶
要切割发布,你必须对 *Black* 存储库具有 write
权限。
发布流程的概览是,你需要准备一个发布 PR,然后发布一个 GitHub 发布。这将触发 发布自动化,该自动化会构建所有发布工件并将其发布到我们发布的各个平台。
我们现在有一个 scripts/release.py
脚本可以帮助切割发布 PR。
python3 scripts/release.py --help
是你的好帮手。release.py
仅在 Python 3.12 中测试过(所以赶快跟上时代吧 :D)
要切割发布
确定发布的版本号
*Black* 遵循 CalVer 版本控制标准,使用
YY.M.N
格式因此,除非本月已经发布过,否则
N
应为0
例如:2022 年 1 月的第一个发布 →
22.1.0
release.py
将计算此值并将其记录到 stderr 中,供你方便地复制粘贴
提交一个 PR,修改
CHANGES.md
和文档以对最新的更改进行版本化运行
python3 scripts/release.py [--debug]
生成大多数更改模板中的子标题,如果它们没有项目符号,则需要手动删除 *欢迎提交 PR 进行改进 :D*
如果
release.py
失败,则需要手动修改;否则,太棒了,跳过此步骤!将
## Unreleased
标题替换为版本号删除当前发布的任何空部分
(*可选*) 阅读并编辑变更日志(例如,通过移动条目、更正拼写错误或重新措辞条目)
仔细检查自上次发布以来的任何变更日志条目是否被放在了错误的部分(例如,运行
git diff <last release> CHANGES.md
)
示例 PR:GH-3139
发布 PR 合并后,等待所有 CI 通过
如果 CI 未通过,请**停止**并调查失败的原因,因为通常情况下,我们希望在切割发布之前修复失败的 CI
-
点击
Choose a tag
并输入版本号,然后选择出现的Create new tag: YY.M.N on publish
选项验证新标签是否指向
main
分支你可以将发布标题留空,GitHub 将默认使用标签名称
将当前发布的 *原始变更日志 Markdown* 复制粘贴到描述框中
发布 GitHub 发布,触发 发布自动化,该自动化将处理剩余的工作
CI 完成后,添加 + 提交(git push - 无需审核)一个新的空模板以供下次发布到 CHANGES.md 中 *(如果我们失败,可以从 release.py 中复制粘贴模板)*
python3 scripts/release.py --add-changes-template|-a [--debug]
如果失败,请返回到复制 + 粘贴
此时,你基本上就完成了。最佳做法是去 观察并验证所有发布工作流是否通过,虽然如果出现问题,你将收到 GitHub 通知。
如果出现问题,不要惊慌。请阅读相应工作流的日志和配置文件,以反向工程修复/解决方案。
恭喜!你已成功发布了一个新的 *Black* 版本。去站起来休息一下,你应得的。
重要
一旦发布工件到达 PyPI,你可能会看到新提交的问题,表明出现回归。虽然回归不是好事,但它们并不一定意味着需要进行热修复发布。除非回归很严重并且影响了许多用户,否则热修复发布可能没有必要。
最后,请使用你的最佳判断,并征求其他维护人员的意见。
发布工作流¶
*Black* 的所有发布自动化都使用 GitHub Actions。因此,所有工作流都是使用 *Black* 存储库的 .github/workflows
目录中的 YAML 文件配置的。
它们由 GitHub 发布 的发布触发。
以下是我们的发布工作流的描述。
发布到 PyPI¶
这是我们的主要工作流。它构建一个 sdist 和 轮子,以上传到 PyPI,绝大多数用户将从那里下载 Black。它分为三个作业组
sdist + 纯轮子¶
这个单一作业使用 build 构建 sdist 和纯 Python 轮子(即,仅包含 Python 代码的轮子),然后使用 twine 将它们上传到 PyPI。这些工件是通用的,可以在基本支持 Python 的任何平台上使用。
mypyc 轮子 (…)¶
我们使用 mypyc 将 *Black* 编译成 CPython C 扩展,以显著提高性能。使用 mypyc 构建的轮子是特定于平台和 Python 版本的。支持的平台在常见问题解答中列出。
这些矩阵作业使用 cibuildwheel,它可以帮助我们处理为许多环境构建 C 扩展的复杂任务。由于构建这些轮子很慢,因此有多个 mypyc 轮子作业(因此称为“矩阵”),它们为特定平台构建(如作业名称中括号内的内容所示)。
与之前的作业组类似,构建的轮子会使用 twine 上传到 PyPI。
更新稳定分支¶
因此,这个作业并不真正属于这里,但在其他 PyPI 作业通过后更新 stable
分支(这些作业必须通过才能启动此作业)是最有意义的。这样可以省去我们在切割发布后的一段时间内记住更新分支的麻烦。
目前,此工作流使用与 @ambv 的 PyPI 帐户关联的 API 令牌
发布可执行文件¶
此工作流使用 PyInstaller 为多个平台构建本机可执行文件。这允许用户下载其平台的可执行文件,并在未安装 Python 运行时 的情况下运行 *Black*。
创建的二进制文件存储在关联的 GitHub 发布中,用于通过 *仅 IPv4* 进行下载(GitHub 仍然没有 IPv6 访问权限 😢)。
docker¶
此工作流使用 Docker 的 QEMU 支持的 buildx
功能上传官方 *Black* Docker 镜像™ 的 arm64
和 amd64
/x86_64
构建。
目前,此工作流使用与 @cooperlees 帐户关联的 API 令牌
注意
这也将在每次推送到 main
分支时运行。