Reusable GitHub Actions workflows for building and publishing Python wheels across Explosion AI projects.
This repository provides two reusable workflows:
cibuildwheel.yml: Builds Python wheels and source distributions, creates GitHub releasespublish_pypi.yml: Publishes releases to PyPI
The workflows support both:
- C-extension packages: Multi-platform wheel building using cibuildwheel
- Pure Python packages: Universal wheel building without platform-specific compilation
For packages with C extensions (like spaCy, thinc, cymem, etc.):
name: Build
on:
push:
tags:
- 'release-v[0-9]+.[0-9]+.[0-9]+**'
- 'prerelease-v[0-9]+.[0-9]+.[0-9]+**'
jobs:
build:
uses: explosion/gha-cibuildwheel/cibuildwheel.yml@main
secrets:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}name: Publish to PyPI
on:
release:
types:
- published
jobs:
publish:
uses: explosion/gha-cibuildwheel/publish_pypi.yml@main
with:
pypi-package-name: 'your-package-name'For pure Python packages (like confection, wasabi, catalogue):
name: Build
on:
push:
tags:
- 'release-v[0-9]+.[0-9]+.[0-9]+**'
- 'prerelease-v[0-9]+.[0-9]+.[0-9]+**'
jobs:
build:
uses: explosion/gha-cibuildwheel/cibuildwheel.yml@main
with:
pure-python: true
secrets:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Handles wheel building and GitHub release creation.
| Input | Description | Default | Required |
|---|---|---|---|
pure-python |
Whether this is a pure Python package | false |
No |
package-dir |
Directory containing the package to build | . |
No |
output-dir |
Output directory for built wheels | wheelhouse |
No |
config-file |
Path to cibuildwheel config file | {package}/pyproject.toml |
No |
cibw-archs-linux |
Architectures to build on Linux | auto |
No |
cibw-env-vars |
JSON object of environment variables for cibuildwheel | {} |
No |
build-sdist |
Whether to build source distribution | true |
No |
create-release |
Whether to create a GitHub release | true |
No |
release-name-prefix |
Prefix to remove from tag for release name | release- |
No |
prerelease-name-prefix |
Prefix for prerelease tags | prerelease- |
No |
os-matrix |
JSON array of OS runners to build on | See below | No |
python-version |
Python version for sdist build | 3.11 |
No |
cibuildwheel-version |
Version of cibuildwheel to use | v2.21.3 |
No |
Default OS Matrix:
["ubuntu-latest", "windows-latest", "macos-13", "macos-14"]| Secret | Description | Required |
|---|---|---|
GITHUB_TOKEN |
GitHub token for creating releases | No (uses default if not provided) |
jobs:
build:
uses: explosion/gha-cibuildwheel/cibuildwheel.yml@main
with:
os-matrix: '["ubuntu-latest", "windows-latest", "macos-13", "macos-14", "ubuntu-24.04-arm"]'
secrets:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}jobs:
build:
uses: explosion/gha-cibuildwheel/cibuildwheel.yml@main
with:
cibw-env-vars: '{"CIBW_SOME_OPTION": "value", "CIBW_BUILD": "cp38-*"}'
secrets:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}jobs:
build:
uses: explosion/gha-cibuildwheel/cibuildwheel.yml@main
with:
create-release: false
secrets:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}Handles PyPI publishing when a GitHub release is published.
| Input | Description | Default | Required |
|---|---|---|---|
pypi-package-name |
PyPI project name (for environment URL) | - | Yes |
name: Publish to PyPI
on:
release:
types:
- published
jobs:
publish:
uses: explosion/gha-cibuildwheel/publish_pypi.yml@main
with:
pypi-package-name: 'spacy'- Push tag matching pattern (e.g.,
release-v3.7.0) - cibuildwheel.yml triggers:
- Builds wheels for all platforms using
cibuildwheel - Builds source distribution
- Creates draft GitHub release with artifacts
- Builds wheels for all platforms using
- Review and publish the GitHub release
- publish_pypi.yml triggers:
- Downloads artifacts from release
- Publishes to PyPI using trusted publishing (OIDC)
- Push tag matching pattern
- cibuildwheel.yml triggers:
- Builds single universal wheel on Ubuntu
- Builds source distribution
- Creates draft GitHub release with artifacts
- Review and publish the GitHub release
- publish_pypi.yml triggers (same as above)
- pyproject.toml with build configuration
- Trusted publishing configured on PyPI (recommended)
- GitHub environment named "pypi" with deployment protection rules (optional)
- cibuildwheel configuration in pyproject.toml:
[tool.cibuildwheel] build = "cp38-* cp39-* cp310-* cp311-* cp312-*" skip = "*-musllinux_*"
- Replace your
.github/workflows/cibuildwheel.ymlwith the minimal version above - Replace your
.github/workflows/publish_pypi.ymlwith the minimal version above - Add
pypi-package-nameparameter with your actual PyPI package name - For pure Python packages, add
pure-python: true
For production use, pin to a specific version instead of using @main:
uses: explosion/gha-cibuildwheel/[email protected]Currently used by:
- spaCy - Industrial-strength NLP (C-extension)
- thinc - Functional deep learning (C-extension)
- cymem - Memory management helpers (C-extension)
- murmurhash - Cython bindings for MurmurHash (C-extension)
- preshed - Cython hash tables (C-extension)
- srsly - Serialization utilities (C-extension)
- confection - Configuration system (Pure Python)
Check your os-matrix input includes all required platforms.
Ensure cibw-env-vars is valid JSON. Test with:
echo '{"CIBW_SOME_OPTION": "value"}' | jq .Verify:
- Tag matches the pattern (e.g.,
release-v1.0.0) GITHUB_TOKENhas appropriate permissionscreate-releaseis not set tofalse
Check:
- Trusted publishing is configured correctly
pypi-package-namematches your actual PyPI project- GitHub environment "pypi" exists (if using environment protection)
MIT