自动化 Python 包发布过程

Automating Python package release process

我刚刚启动了一个开源 Python 项目,希望有一天它会流行起来。目前要发布新版本,我必须做一些事情。

  1. 测试所有东西。
  2. 编辑 mypackage.VERSION 变量,setup.py__init__
  3. 导入
  4. 使用 python setup.py sdist bdist_wheel
  5. 构建包和轮子
  6. 将变更日志条目写入 CHANGELOG 文件
  7. 提交我的更改,回显部分更改日志
  8. 将提交标记为发布,再次复制更改日志条目。
  9. 拖入我构建的文件,以便人们可以从发布中下载它们
  10. 使用 Twine 将包推送到 PyPI
  11. 通过 PyPI 在我的暂存服务器上再次测试。

如果我必须用九个要点来总结我讨厌我的项目的所有事情,我想我们会看到一个非常相似的列表。最重要的是,过去我编了一个新版本号并写了 commit/changelog 消息,这太无聊了。

我能否以这样一种方式自动执行这些任务,例如,让 GitHub CI 做 一切 来自我的提交?

我已经有十年的 Python 经验,还有一点 CI,但我对打包 Python 和积极与 PyPI 交互还很陌生。我怀疑我不是唯一一个被这里的手动重复逼疯的人,我只是在寻找可以使这个过程更容易的工具(或服务)。

我为我的一个开源工具自动化了这个。 都在文件 manage.py 中: https://github.com/tfeldmann/organize/blob/master/manage.py

我的项目使用诗歌上传到 pypi,所以这看起来有点不同,但应该是一个很好的起点。它还管理变更日志并创建所有版本。

python manage.py version 步数:

  • 提示版本号并检查有效性
  • 更新 __version__.py 文件
  • 更新 poetry 使用的 pyproject.toml 文件
  • 在 changelog.md 中搜索部分 ## WIP 并将其替换为当前版本和今天的日期。

python manage.py publish 步数:

  • 读取当前版本
  • 从变更日志中读取为此版本列出的变更
  • 创建一个 git 标签
  • 推送到 github(带标签)
  • 构建并发布到 pypi
  • 创建一个 github 版本,名称为版本号,描述为更新日志中的更改

脚本要求对每个步骤进行确认,以免事情失控,并在需要时提示您输入 github 和 pypi 密码。

以下是我对您的清单的看法。您可以在一定范围内实现自动化,我将尝试提供一个合理的起点,然后提供一些提示,告诉您如何从那里走得更远。


CI 无 CD

采用这部分应该已经摆脱了大部分烦人的手动工作,并且您可以根据需要越来越多地自动化。如果您不习惯维护大量 CI 代码,您应该从这里开始。

您需要的是 CI(正如您已经指出的)和包管理器。您无法解决的问题是使用 git 推送您的更改和一个新标签,因此第 5 步和第 6 步的部分内容仍然是手动的。

包管理

我将使用 poetry to keep things concise and because I like it[1], but there are also other options。这将处理第 2、3、7、8 步和未列出的第 10 步,"update my dependencies and test them for compatibility",一旦发现问题,这将非常烦人。

使用 poetry 的坏消息是您需要将所有打包配置移动到一个新文件中,pyproject.toml。好消息是,您不再需要单独的 setup.pysetup.cfgMANIFEST.inrequirements.txt,因为 pyproject.toml is a provisional standard for packaging and other tools, and poetry also has a walkthrough 关于如何移植所有相关信息。

设置准备就绪后,新的部署工作流将是:

$ poetry update           # update dependencies, may be skipped 
$ poetry version          # bump version
Bumping version from 1.1.2 to 1.1.3
# finalize git stuff, e.g. add -u, commit -m 'v1.1.3', tag v1.1.3, push
$ poetry publish --build  # build and publish to PyPI
Building my_django_lib (1.1.3)
 - Building sdist
 - Built my_django_lib-1.1.3.tar.gz

 - Building wheel
 - Built my_django_lib-1.1.3-py3-none-any.whl

Publishing my_django_lib (1.1.3) to PyPI
 - Uploading my_django_lib-1.1.3-py3-none-any.whl 100%
 - Uploading my_django_lib-1.1.3.tar.gz 100%

这应该比您目前正在做的要短很多。如果您总是执行完全相同的 git 命令,不怕自动推送,并妥善保管您的 .gitignore 文件,请随时将类似此功能的功能添加到您的 ~/.bashrc并改为调用它:

git_cord () {
  version=$(grep pyproject.toml -e '(?<=^version = ")(.*)(?=")' -Po)
  git add -u
  git commit -m "${version}"
  git tag "${version}"
  git push -u origin "${version}"
}

开始使用 gitlab-CI

CI原则上可以处理部署过程中的所有事情,包括版本升级和发布。但第一个要求你的 CI 可以推送到你的 repo(这有烦人的副作用),而后者可以发布到你的 PyPI(这是有风险的,并且调试 CI 很痛苦) .我认为手动执行这两个步骤的情况并不少见,因此这种最小方法只会处理第 1 步和第 9 步。之后可以包括更广泛的测试和构建作业。

CI 的正确设置取决于您打算使用哪一个。 list for github is long, so I'll instead focus on gitlab's builtin CI. It's free, has very little magic (which makes it comparably portable), and the binaries for the CI runners are open, free, and actually documented,因此您可以在本地调试您的 CI 或启动并连接新的 运行 用户(如果免费的不适合您的话)。

这是一个小 .gitlab-ci.yml,您可以将其放入项目根目录以便 运行 进行测试。管道中的每个作业(跳过设置和安装命令)也应该在您的开发环境中可执行,保持这种方式可以提供更好的维护者体验。

image: python:3.7-alpine

stages:
  - build
  - test

packaging:
  stage: build
  script:
    - pip install poetry
    - poetry build
  artifacts:
    paths: 
      - dist

pytest:
  stage: test
  script:
    - pip install dist/*.whl
    - pip install pytest
    - pytest

像这样设置 buildtest 阶段可以一次性处理第 1 步和第 9 步,同时还 运行 将测试套件针对已安装的软件包而不是您的源代码文件。尽管它只有在您的项目中有 src-layout 时才能正常工作,这使得本地源无法从项目根目录导入。关于为什么这是个好主意的一些信息 here and here

Poetry 可以创建一个 src-layout 模板,您可以使用 poetry new my_django_lib --src.

将您的代码移入其中

更新日志

虽然有一些工具 automatically create a changelog from commit messages, keeping a good changelog 是可以从手工保养中获益良多的工具之一。所以,我的建议是第 4 步不要自动化。

一种思考方式是手册 CHANGELOG 文件包含与您的用户相关的信息,并且应该只包含新功能、重要错误修复和弃用等信息。

可能对贡献者或插件作者很重要的更细粒度的信息将位于 MR、提交消息或问题讨论中,不应进入 CHANGELOG。您可以尝试以某种方式收集它,但浏览这样的 AUTOLOG 可能与筛选我刚才提到的主要来源一样麻烦。

所以简而言之,步骤 5 和 6 中与更新日志相关的部分可以跳过。


CI CD

添加 CD 并没有太大变化,只是您不必再手动释放。如果 CI 已关闭、出​​现错误,或者您不想等待管道发布修补程序,您仍然可以发布诗歌。

这将按以下方式改变工作流程:

  • 日常工作
    • 写代码(还不能避免这个)
    • 在提交消息中记录进度and/or MR(我更喜欢 MR,即使是我自己的更改,并且在合并时压缩所有提交)
    • 推送到 git实验室/合并 MR
  • 发布时
    • 创建一个标签,运行 poetry version 也许 poetry update
    • CHANGELOG
    • 中编写发行说明
    • 推送到 git实验室

如果您 supply the secrets PYPI_USERPYPI_PASSWORD:

对前 .gitlab-ci.yml 文件的添加应该会立即生效
stages:
  - build
  - test
  - release

[...]  # packaging and pytest unchanged

upload:
  stage: release
  only:
    - tags
    # Or alternatively "- /^v\d+\.\d+\.\d+/" if you also use non-release
    # tags, the regex only matches tags that look like this: "v1.12.0"
  script:
    - pip install poetry
    - poetry publish -u ${PYPI_USER} -p ${PYPI_PASSWORD} dist/*

一些有用的链接:


[1] 除此之外,poetry 还 1) 为您处理 virtualenv,2) 创建一个散列锁文件以防您需要可重现的构建,以及 3) 做出贡献更容易,因为你只需要 运行 "poetry install" 在克隆一个 repo 之后就可以开始了。