首页 > 解决方案 > 自动化 Python 包发布过程

问题描述

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

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

如果我必须用九个要点来总结我讨厌我的项目的所有内容,我想我们会看到一个非常相似的列表。最重要的是,在我编写新版本号并编写提交/更改日志消息之前,这非常无聊。

我能否以某种方式自动化这些任务,例如,让 GitHub CI仅从我的提交中完成所有事情?

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

标签: pythonbuildcontinuous-integrationpypipython-packaging

解决方案


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


无 CD 的 CI

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

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

包管理

我将使用诗歌来保持简洁,因为我喜欢它[1],但也有其他选择。这将处理第 2、3、7、8 步和未列出的第 10 步,“更新我的依赖项并测试它们的兼容性”,一旦出现问题,这将非常烦人。

使用诗歌时的坏消息是您需要将所有打包配置移动到一个新文件中,pyproject.toml. 好消息是,您不再需要单独setup.py的 , setup.cfg,MANIFEST.inrequirements.txt任何其他工具,因为pyproject.toml它是包装和其他工具的临时标准,并且诗歌还提供了有关如何移植所有相关信息的演练。

设置完成后,新的部署工作流程将是:

$ 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 的正确设置取决于您打算使用哪一个。github的列表很长,所以我将重点介绍 gitlab 的内置 CI。它是免费的,几乎没有什么魔力(这使得它具有相当的便携性),并且 CI 运行器的二进制文件是开放的、免费的,并且实际记录在案,因此您可以在本地调试您的 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

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

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

变更日志

虽然有一些工具可以根据提交消息自动创建变更日志,但保持良好的变更日志是从手工处理中受益匪浅的事情之一。所以,我的建议是第 4 步不要自动化。

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

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

所以简而言之,可以跳过第 5 步和第 6 步的变更日志相关部分。


带有 CD 的 CI

添加CD并没有太大的变化,只是不再需要手动释放。如果 CI 出现故障、出现错误,或者您不想等待管道发布修补程序,您仍然可以使用诗歌进行发布。

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

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

.gitlab-ci.yml如果您提供秘密 PYPI_USERPYPI_PASSWORD

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”回购并准备就绪。


推荐阅读