首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >从手动发版到全自动发布:我用 GitHub Actions + Semantic Release + Trusted Publisher 搭建 Python 包发布流水线

从手动发版到全自动发布:我用 GitHub Actions + Semantic Release + Trusted Publisher 搭建 Python 包发布流水线

作者头像
不止于python
发布2026-05-13 15:11:37
发布2026-05-13 15:11:37
1500
举报
文章被收录于专栏:不止于python不止于python

前言

很多 Python 项目在刚开始时,发布流程都比较“原始”:

代码语言:javascript
复制
改版本号
→ git tag
→ python -m build
→ twine upload

项目少的时候问题不大。

但只要:

  • • 包开始持续迭代
  • • 有多人协作
  • • 版本越来越多
  • • 需要自动生成 Release
  • • 需要自动发布 PyPI

很快就会进入一种状态:

代码语言:javascript
复制
版本号经常忘记改
tag 对不上
PyPI 版本混乱
workflow 不知道为什么不触发

最近把自己的 Python 项目完整升级了一遍,做成了:

  • • 自动测试
  • • 自动 lint
  • • 自动安全扫描
  • • 自动版本升级
  • • 自动 Git Tag
  • • 自动 GitHub Release
  • • 自动发布 PyPI

整套流程。

这一篇把完整配置、踩坑和注意事项全部整理一下。

适合:

  • • Python SDK
  • • 工具库
  • • FastAPI 项目
  • • 内部公共组件
  • • 想做工程化的 Python 项目

项目地址, 文章缺少文件可以从项目中找到。

https://github.com/Mehaei/pydify_plus


一、先看一下项目结构

这次做自动化发布的项目,是一个完整的 Python SDK。

目录结构如下:

代码语言:javascript
复制
.
├── CHANGELOG.md
├── CONTRIBUTING.md
├── docs
│   └── API_REFERENCE.md
├── examples
│   ├── example_async.py
│   ├── example_sync.py
│   ├── fastapi_example.py
│   └── README.md
├── LICENSE
├── PROJECT_STRUCTURE.md
├── PROJECT_SUMMARY.md
├── pydify_plus
│   ├── __init__.py
│   ├── apis
│   │   ├── __init__.py
│   │   ├── app_config.py
│   │   ├── base.py
│   │   ├── blocks.py
│   │   ├── chat.py
│   │   ├── dataset.py
│   │   ├── documents.py
│   │   ├── feedback.py
│   │   ├── files.py
│   │   ├── models.py
│   │   ├── sessions.py
│   │   ├── tags.py
│   │   ├── textgen.py
│   │   └── workflows.py
│   ├── async_client.py
│   ├── base.py
│   ├── config.py
│   ├── errors.py
│   ├── models.py
│   ├── sync_client.py
│   ├── types.py
│   └── utils.py
├── pyproject.toml
├── pytest.ini
├── README.md
├── RELEASE.md
├── requirements.txt
├── scripts
│   ├── bump_version.py
│   └── release.py
└── tests
    ├── __init__.py
    ├── conftest.py
    ├── test_app_config.py
    ├── test_base_client.py
    ├── test_blocks.py
    ├── test_chat.py
    ├── test_dataset.py
    ├── test_documents.py
    ├── test_feedback.py
    ├── test_files.py
    ├── test_models.py
    ├── test_sessions.py
    ├── test_streaming.py
    ├── test_tags.py
    ├── test_textgen.py
    └── test_workflows.py

整个项目已经是一个比较标准的 Python SDK 结构。

里面包含:

  • • API 模块拆分
  • • examples 示例
  • • tests 自动化测试
  • • docs 文档
  • • scripts 发布脚本
  • • CHANGELOG
  • • CONTRIBUTING

这也是后面能够顺利做 CI/CD 自动化的基础。


二、最终效果

现在整个发布流程已经变成:

开发时:

代码语言:javascript
复制
git commit -m "feat: add cache support"
git push

GitHub Actions 自动:

代码语言:javascript
复制
pytest
black
flake8
mypy
安全扫描

如果提交符合版本发布规则:

代码语言:javascript
复制
自动升级版本
自动打 tag
自动创建 Release
自动发布 PyPI

整个过程不需要手动改版本号。


三、核心技术栈

这一套主要用了:

功能

工具

CI/CD

GitHub Actions

自动版本管理

python-semantic-release

自动发布 PyPI

Trusted Publisher

测试

pytest

类型检查

mypy

代码格式化

black

lint

flake8

安全扫描

bandit + safety


四、为什么使用 pyproject.toml

以前很多 Python 项目:

代码语言:javascript
复制
setup.py
requirements.txt
setup.cfg
MANIFEST.in

混在一起。

后面维护起来非常痛苦。

现在更推荐统一:

代码语言:javascript
复制
pyproject.toml

整个项目的:

  • • 包配置
  • • 依赖
  • • lint
  • • pytest
  • • semantic-release

全部集中管理。

这也是现在 Python 官方推荐方案。


五、我的 pyproject.toml 主要配置

项目里主要包含:


项目基础信息

代码语言:javascript
复制
[project]
name = "pydify-plus"
description = "Python SDK for Dify API"
requires-python = ">=3.10"

开发依赖

代码语言:javascript
复制
[project.optional-dependencies]
dev = [
    "pytest",
    "black",
    "flake8",
    "mypy"
]

这样 workflow 里:

代码语言:javascript
复制
pip install ".[dev]"

就能一次性安装所有开发工具。


semantic-release

代码语言:javascript
复制
[tool.semantic_release]
branch = "master"
tag_format = "v{version}"

这个后面会自动:

  • • 管理版本
  • • 自动打 tag
  • • 自动生成 Release

六、为什么不用 PyPI Token

以前很多教程都还是:

代码语言:javascript
复制
PYPI_API_TOKEN

方式。

现在已经不太推荐了。

原因很简单:

  • • Token 会泄露
  • • Secret 管理麻烦
  • • 权限不好控制
  • • 长期有效风险高

现在更推荐:

代码语言:javascript
复制
Trusted Publisher(OIDC)

即:

代码语言:javascript
复制
GitHub Actions
→ GitHub 身份认证
→ PyPI 信任仓库
→ 自动发布

整个过程:

代码语言:javascript
复制
不需要任何 PyPI Token

也是目前 PyPI 官方推荐方案。


七、先配置 Trusted Publisher

打开:

PyPI 官方网站

https://pypi.org

需要提前注册账号 进入:

代码语言:javascript
复制
Manage
→ Publishing

添加:

代码语言:javascript
复制
Trusted Publisher

这里几个字段非常重要。


Project Name

必须和:

代码语言:javascript
复制
[project]
name = "pydify-plus"

完全一致。


Owner

代码语言:javascript
复制
GitHub 用户名。
Mehaei

Repository

代码语言:javascript
复制
仓库完整连接。
https://github.com/Mehaei/pydify_plus

Workflow name

代码语言:javascript
复制
填写:
  release.yml
必须和:
  .github/workflows/release.yml
一致。

否则 GitHub Actions 发布时会报:

代码语言:javascript
复制
No matching trusted publisher

这是最常见的问题之一。

Environment name

代码语言:javascript
复制
release
可以留空。

保存

点击:

代码语言:javascript
复制
Add

八、完整 release.yml 配置

这是目前项目里实际使用的 workflow。

相比网上很多“玩具教程”,这个版本已经可以直接用于生产。


触发条件

代码语言:javascript
复制
on:
  push:
    branches: [master, develop]

  pull_request:
    branches: [master]

  workflow_dispatch:

这里做了三件事:


1. push 自动运行

推送代码自动执行 CI。


2. PR 自动检查

Pull Request 自动测试。


3. workflow_dispatch

允许手动触发。 GitHub 页面可以直接点击运行。 这个功能非常实用。


九、为什么很多人 workflow 不触发

这是最常见的问题。

比如:

代码语言:javascript
复制
branches:
  - main

但实际仓库:

代码语言:javascript
复制
master

那么:

代码语言:javascript
复制
workflow 永远不会执行

我一开始也踩了这个坑。

后来统一改成:

代码语言:javascript
复制
branches: [master, develop]

就正常了。


十、测试矩阵

测试部分:

代码语言:javascript
复制
strategy:
  matrix:
    python-version: ["3.10", "3.11", "3.12"]

作用是:

代码语言:javascript
复制
自动测试多个 Python 版本

避免:

代码语言:javascript
复制
本地能跑
线上炸了

十一、依赖安装

代码语言:javascript
复制
pip install ".[dev]"

这里依赖:

代码语言:javascript
复制
[project.optional-dependencies]
dev = [
    "pytest",
    "black",
    "flake8",
    "mypy"
]

这样开发依赖统一维护。

不用 workflow 里手写一堆 pip install。


十二、自动测试

项目 tests 目录里已经拆分得比较完整:

代码语言:javascript
复制
tests/
├── test_chat.py
├── test_dataset.py
├── test_documents.py
├── test_feedback.py
├── test_files.py
├── test_models.py
├── test_sessions.py
├── test_streaming.py
├── test_tags.py
├── test_textgen.py
└── test_workflows.py

workflow 中:

代码语言:javascript
复制
pytest --cov=pydify_plus --cov-report=xml

这里顺便加了:

代码语言:javascript
复制
coverage

并上传:

代码语言:javascript
复制
codecov/codecov-action

这样每次提交:

  • • 覆盖率
  • • 测试结果

都能自动统计。


十三、Lint 检查

项目里同时用了:


black

代码语言:javascript
复制
black --check pydify_plus tests

检查格式。


flake8

代码语言:javascript
复制
flake8 --max-line-length 88

检查代码规范。


mypy

代码语言:javascript
复制
mypy pydify_plus

做类型检查。


十四、安全扫描

这个部分很多项目其实都没有。

但非常建议加。


Bandit

代码语言:javascript
复制
bandit -r pydify_plus

扫描:

  • • 危险函数
  • • subprocess
  • • eval
  • • pickle

等安全问题。


Safety

代码语言:javascript
复制
safety check

检查依赖漏洞。


十五、Build 阶段

Build 只在:

代码语言:javascript
复制
master push

时运行。

配置:

代码语言:javascript
复制
if: github.event_name == 'push' &&
    github.ref == 'refs/heads/master'

避免:

代码语言:javascript
复制
develop 分支也发版

十六、自动版本管理

这一部分是核心。

项目里使用:

代码语言:javascript
复制
python-semantic-release

十七、为什么推荐 semantic-release

它会根据:

代码语言:javascript
复制
Commit Message

自动决定版本号。

例如:

feat

代码语言:javascript
复制
git commit -m "feat: add redis cache"

自动:

代码语言:javascript
复制
1.0.0 → 1.1.0

fix

代码语言:javascript
复制
git commit -m "fix: websocket reconnect"

自动:

代码语言:javascript
复制
1.0.0 → 1.0.1

十八、版本发布配置

workflow 中:

代码语言:javascript
复制
uses: python-semantic-release/python-semantic-release@v10

这里会自动:

  • • 分析 commit
  • • 计算版本
  • • 创建 Git Tag
  • • 创建 GitHub Release

十九、Commit Message 必须规范

这一点很重要。

否则 semantic-release 不会工作。

推荐:


新功能

代码语言:javascript
复制
feat: add xxx

修复

代码语言:javascript
复制
fix: resolve xxx

文档

代码语言:javascript
复制
docs: update readme

重构

代码语言:javascript
复制
refactor: optimize api

二十、自动发布 PyPI

发布阶段:

代码语言:javascript
复制
uses: pypa/gh-action-pypi-publish@release/v1

注意:

这里没有:

代码语言:javascript
复制
PYPI_API_TOKEN

因为项目已经切换到了:

代码语言:javascript
复制
Trusted Publisher

二十一、为什么 build 和 deploy 分开

这是一个非常重要的实践。

很多教程会:

代码语言:javascript
复制
build + publish

写在一起。

但实际上:

代码语言:javascript
复制
分离更稳定

因为:

  • • build 失败不会污染 release
  • • deploy 更容易重试
  • • 日志更清晰
  • • 更适合后续扩展

二十二、examples 目录的重要性

很多 Python SDK 发布后:

代码语言:javascript
复制
只有 README

用户其实很难快速上手。

这个项目里专门保留了:

代码语言:javascript
复制
examples/

包括:

代码语言:javascript
复制
example_async.py
example_sync.py
fastapi_example.py

这样:

  • • 同步调用
  • • 异步调用
  • • FastAPI 集成

都能快速演示。

对 SDK 类型项目来说非常重要。


二十三、docs 文档目录建议保留

项目里:

代码语言:javascript
复制
docs/API_REFERENCE.md

也是后面做:

  • • mkdocs
  • • sphinx
  • • GitHub Pages

的基础。

很多人前期不做 docs,后面维护成本会越来越高。


二十四、自动发布完整流程

现在整个流程:

代码语言:javascript
复制
git push
    ↓
pytest
    ↓
black
    ↓
flake8
    ↓
mypy
    ↓
bandit
    ↓
semantic-release
    ↓
auto tag
    ↓
build wheel
    ↓
trusted publisher
    ↓
publish pypi

已经完全自动化。


二十五、几个踩坑记录


1. workflow 不触发

原因:

代码语言:javascript
复制
branches:
  - main

但仓库实际:

代码语言:javascript
复制
master

2. PyPI 发布失败

原因:

代码语言:javascript
复制
Trusted Publisher workflow 名不一致

PyPI 配的是:

代码语言:javascript
复制
publish.yml

实际:

代码语言:javascript
复制
release.yml

3. wheel 里只有 dist-info

原因:

代码语言:javascript
复制
缺少 __init__.py

4. twine check 报错

原因:

代码语言:javascript
复制
多个 Python 环境混用

Mac 上尤其容易出现。

后来统一:

代码语言:javascript
复制
python -m xxx

问题基本解决。


二十六、现在推荐的 Python 工程化组合

目前这套组合已经比较稳定:

功能

推荐

环境管理

uv

打包

setuptools

自动版本

semantic-release

自动发布

Trusted Publisher

测试

pytest

lint

black + flake8

类型检查

mypy

安全扫描

bandit + safety


二十七、最后

Python 项目做到后面,其实核心已经不是:

代码语言:javascript
复制
功能开发

而是:

代码语言:javascript
复制
工程化

包括:

  • • 自动测试
  • • 自动发版
  • • 自动版本管理
  • • 自动发布
  • • CI/CD
  • • 安全扫描

这些东西一开始看起来复杂。

但真正搭起来之后,后续维护成本会低很多。

尤其是:

代码语言:javascript
复制
自动版本 + 自动发布

一旦习惯之后,基本就回不去了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-05-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、先看一下项目结构
  • 二、最终效果
  • 三、核心技术栈
  • 四、为什么使用 pyproject.toml
  • 五、我的 pyproject.toml 主要配置
    • 项目基础信息
    • 开发依赖
    • semantic-release
  • 六、为什么不用 PyPI Token
  • 七、先配置 Trusted Publisher
    • Project Name
    • Owner
    • Repository
    • Workflow name
    • Environment name
    • 保存
  • 八、完整 release.yml 配置
    • 触发条件
  • 九、为什么很多人 workflow 不触发
  • 十、测试矩阵
  • 十一、依赖安装
  • 十二、自动测试
  • 十三、Lint 检查
    • black
    • flake8
    • mypy
  • 十四、安全扫描
    • Bandit
    • Safety
  • 十五、Build 阶段
  • 十六、自动版本管理
  • 十七、为什么推荐 semantic-release
    • feat
    • fix
  • 十八、版本发布配置
  • 十九、Commit Message 必须规范
    • 新功能
    • 修复
    • 文档
    • 重构
  • 二十、自动发布 PyPI
  • 二十一、为什么 build 和 deploy 分开
  • 二十二、examples 目录的重要性
  • 二十三、docs 文档目录建议保留
  • 二十四、自动发布完整流程
  • 二十五、几个踩坑记录
    • 1. workflow 不触发
    • 2. PyPI 发布失败
    • 3. wheel 里只有 dist-info
    • 4. twine check 报错
  • 二十六、现在推荐的 Python 工程化组合
  • 二十七、最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档