关于 python3-publish-release-pipeline
用于配置 Python 包 CI/CD 发布流水线的技能,可识别 GitHub Actions 或 GitLab CI,并提供测试、检查、发布、版本管理和发布文档的配置指导。
主要功能
- 01配置 GitHub Actions 和 GitLab CI
- 02测试与代码检查工作流
- 03配置 PyPI 发布
- 04通过 Git 标签管理版本
- 05编写发布流程文档
- 06Trusted Publishing 指引
适用场景
- 01自动化发布 Python 包
- 02设置 PyPI 发布流程
- 03通过 TestPyPI 测试发布
- 04记录基于标签的发布流程
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ jamie-bitflight/ claude_skills --skill python3-publish-release-pipeline安装后在 Claude Code 中输入/python3-publish-release-pipeline确认已加载。
详细介绍
<pipeline_target>$ARGUMENTS</pipeline_target>
Python 发布流水线配置
该模型负责配置 CI/CD 流水线,以自动发布 Python 软件包。
参数
<pipeline_target/>
如果未提供参数,则从仓库中检测(查找 .github/ 或 .gitlab-ci.yml)。
说明
应用通用架构、类型标注、测试或 CLI 规则时,请加载并遵循 /python-engineering:standards-for-python-development 中的标准。
- 检测 CI 平台(GitHub Actions 或 GitLab CI)
- 创建工作流文件,用于测试、Lint 和发布
- 编写 PyPI 令牌密钥的配置文档
- 使用 git 标签设置版本管理
- 编写发布流程文档
GitHub Actions 流水线
目录结构
.github/
├── workflows/
│ ├── ci.yml # Run on every push/PR
│ ├── release.yml # Run on version tags
│ └── docs.yml # Optional: documentation
└── dependabot.yml # Optional: dependency updates
CI 工作流(ci.yml)
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Set up Python
run: uv python install 3.11
- name: Install dependencies
run: uv sync --all-extras
- name: Run ruff
run: |
uv run ruff check --no-fix src/ tests/
uv run ruff format --check src/ tests/
- name: Run type check (ty default; swap to mypy if hooks/CI run mypy — not merely [tool.mypy])
run: uv run ty check src/ tests/
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Set up Python ${{ matrix.python-version }}
run: uv python install ${{ matrix.python-version }}
- name: Install dependencies
run: uv sync --all-extras
- name: Run tests
run: uv run pytest tests/ -v --cov=src --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
files: coverage.xml
fail_ci_if_error: false
发布工作流(release.yml)
name: Release
on:
push:
tags:
- "v*.*.*"
permissions:
contents: write
id-token: write # Required for trusted publishing
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v4
- run: uv python install 3.11
- run: uv sync --all-extras
- run: uv run ruff check --no-fix src/ tests/
- run: uv run ruff format --check src/ tests/
- run: uv run ty check src/ tests/
- run: uv run pytest tests/ --cov=src --cov-report=term-missing
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v4
- name: Set up Python
run: uv python install 3.11
- name: Build package
run: uv build
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
# Option 1: Trusted Publishing (Recommended)
publish-pypi:
# Publish only an artifact from this release workflow after its tests pass.
needs: [build, test]
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/your-package
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
# No token needed with trusted publishing!
# Option 2: Token-based Publishing (Alternative)
# publish-pypi:
# needs: [build, test]
# runs-on: ubuntu-latest
# steps:
# - name: Download artifacts
# uses: actions/download-artifact@v4
# with:
# name: dist
# path: dist/
#
# - name: Publish to PyPI
# uses: pypa/gh-action-pypi-publish@release/v1
# with:
# password: ${{ secrets.PYPI_API_TOKEN }}
github-release:
needs: [build, publish-pypi]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
files: dist/*
generate_release_notes: true
GitLab CI 流水线
.gitlab-ci.yml
stages:
- lint
- test
- build
- publish
variables:
UV_CACHE_DIR: "$CI_PROJECT_DIR/.uv-cache"
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.pip-cache"
default:
image: python:3.11-slim
before_script:
- pip install uv
- uv sync --all-extras
cache:
key: "${CI_JOB_NAME}"
paths:
- .uv-cache/
- .pip-cache/
- .venv/
lint:
stage: lint
script:
- uv run ruff check --no-fix src/ tests/
- uv run ruff format --check src/ tests/
- uv run ty check src/ tests/
test:
stage: test
parallel:
matrix:
- PYTHON_VERSION: ["3.11", "3.12", "3.13"]
image: python:${PYTHON_VERSION}-slim
script:
- uv run pytest tests/ -v --cov=src --cov-report=xml --junitxml=report.xml
coverage: '/TOTAL.*\s+(\d+%)/'
artifacts:
reports:
junit: report.xml
coverage_report:
coverage_format: cobertura
path: coverage.xml
build:
stage: build
script:
- uv build
artifacts:
paths:
- dist/
expire_in: 1 week
# Publish to PyPI on tags
publish:pypi:
stage: publish
rules:
- if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
script:
- uv publish --token $PYPI_TOKEN
environment:
name: pypi
url: https://pypi.org/project/your-package
# Publish to GitLab Package Registry on tags
publish:gitlab:
stage: publish
rules:
- if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
script:
- |
TWINE_PASSWORD=${CI_JOB_TOKEN} \
TWINE_USERNAME=gitlab-ci-token \
uv publish --publish-url ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi
environment:
name: gitlab-registry
可信发布设置(PyPI)
为什么使用可信发布?
- 无需管理 API 令牌
- 无需轮换密钥
- 不会泄露
- 限定用于特定工作流
设置步骤
-
前往 PyPI → 你的项目 → Publishing
-
添加 GitHub 发布者:
- Owner:
your-username - Repository:
your-repo - Workflow name:
release.yml - Environment:
pypi(可选,但建议设置)
- Owner:
-
创建 GitHub 环境:
- Settings → Environments → New environment:
pypi - 添加保护规则(可选):
- 必需的审核者
- 仅限标签
- Settings → Environments → New environment:
替代方案:API 令牌
如果无法使用可信发布:
-
创建 PyPI 令牌:
- PyPI → Account Settings → API tokens
- 创建限定用于你的项目的令牌
-
添加到仓库密钥:
- GitHub:Settings → Secrets →
PYPI_API_TOKEN - GitLab:Settings → CI/CD → Variables →
PYPI_TOKEN
- GitHub:Settings → Secrets →
版本管理
手动设置版本(pyproject.toml)
打标签前,在 pyproject.toml 中更新版本:
[project]
version = "1.2.3"
从 Git 标签动态获取版本
使用 hatch-vcs:
[build-system]
requires = ["hatchling", "hatch-vcs"]
build-backend = "hatchling.build"
[project]
dynamic = ["version"]
[tool.hatch.version]
source = "vcs"
[tool.hatch.build.hooks.vcs]
version-file = "src/my_package/_version.py"
发布工作流
# 1. Update CHANGELOG.md
# 2. Commit changes
git add CHANGELOG.md pyproject.toml
git commit -m "Prepare release v1.2.3"
# 3. Create annotated tag
git tag -a v1.2.3 -m "Release v1.2.3"
# 4. Push with tags
git push origin main
git push origin v1.2.3
使用 TestPyPI 进行测试
GitHub Actions TestPyPI 作业
publish-testpypi:
needs: build
runs-on: ubuntu-latest
environment:
name: testpypi
url: https://test.pypi.org/p/your-package
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
手动上传到 TestPyPI
# Build
uv build
# Upload to TestPyPI
uv publish --publish-url https://test.pypi.org/legacy/ --token $TESTPYPI_TOKEN
# Test install
uv pip install --index-url https://test.pypi.org/simple/ your-package
必需的配置文件
发布所需的最少文件
your-package/
├── pyproject.toml # Package metadata and build config
├── README.md # Required by PyPI
├── LICENSE # Required for distribution
├── src/
│ └── your_package/
│ ├── __init__.py
│ └── py.typed # PEP 561 marker
└── .github/
└── workflows/
├── ci.yml
└── release.yml
pyproject.toml 检查清单
- [ ] [build-system] with requires and build-backend
- [ ] [project] with name, version, description
- [ ] readme = "README.md"
- [ ] license specified
- [ ] requires-python = ">=3.11"
- [ ] authors with name and email
- [ ] classifiers (Development Status, License, Python versions)
- [ ] dependencies list
- [ ] [project.urls] with Documentation, Issues, Source
- [ ] [project.scripts] if CLI tool
安全最佳实践
- 优先使用可信发布,而非 API 令牌
- 将令牌限定用于特定项目(而非整个账户)
- 使用带保护规则的环境
- 使用完整 SHA 或版本标签固定 Action 版本
- 仔细审核工作流变更
- 为 main 启用分支保护
故障排除
构建失败
# Check package metadata
uv run python -m build --no-isolation
uvx twine check dist/*
上传失败
# Never print any portion of a publishing credential.
# Verify authentication only by a non-secret-bearing API/tool response.
# Check package name availability
curl https://pypi.org/pypi/your-package/json
版本已存在
PyPI 不允许重新上传相同版本。请递增版本号并创建新标签。
参考资料
评论
支持 Markdown