name: Build and Publish Python Wheels
on:
push:
branches:
- main
- master
workflow_dispatch:
jobs:
check-and-tag:
name: Generate Version Tag
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
version: ${{ steps.generate_version.outputs.version }}
should_publish: ${{ steps.generate_version.outputs.should_publish }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate version tag
id: generate_version
run: |
# Get current year
YEAR=$(date +%Y)
# Get all tags for current year
LATEST_TAG=$(git tag -l "${YEAR}.*" | sort -V | tail -n 1)
if [ -z "$LATEST_TAG" ]; then
# No tags for this year, start with v1
VERSION="${YEAR}.1"
else
# Extract version number and increment
VERSION_NUM=$(echo $LATEST_TAG | cut -d'.' -f2)
NEW_VERSION_NUM=$((VERSION_NUM + 1))
VERSION="${YEAR}.${NEW_VERSION_NUM}"
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "should_publish=true" >> $GITHUB_OUTPUT
echo "Generated version: ${VERSION}"
# Create and push the tag
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag "${VERSION}"
git push origin "${VERSION}"
build-wheels:
name: Build wheels on ${{ matrix.os }}
needs: check-and-tag
if: needs.check-and-tag.outputs.should_publish == 'true'
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12'
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
- name: Install maturin
run: pip install maturin
- name: Build wheels (Linux)
if: runner.os == 'Linux'
env:
PYO3_USE_ABI3_FORWARD_COMPATIBILITY: 1
run: |
docker run --rm -v $(pwd):/io -e PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 ghcr.io/pyo3/maturin build --release -o dist --interpreter python3.12
- name: Build wheels (Windows)
if: runner.os == 'Windows'
env:
PYO3_USE_ABI3_FORWARD_COMPATIBILITY: 1
run: |
maturin build --release -o dist --interpreter python
- name: Build wheels (macOS)
if: runner.os == 'macOS'
env:
PYO3_USE_ABI3_FORWARD_COMPATIBILITY: 1
run: |
maturin build --release -o dist --interpreter python3.12
- name: Upload wheels
uses: actions/upload-artifact@v4
with:
name: wheels-${{ matrix.os }}
path: dist/*.whl
build-sdist:
name: Build source distribution
needs: check-and-tag
if: needs.check-and-tag.outputs.should_publish == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12'
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
- name: Install maturin
run: pip install maturin
- name: Build sdist
run: maturin sdist -o dist
- name: Upload sdist
uses: actions/upload-artifact@v4
with:
name: sdist
path: dist/*.tar.gz
publish:
name: Publish to PyPI
needs: [check-and-tag, build-wheels, build-sdist]
runs-on: ubuntu-latest
if: needs.check-and-tag.outputs.should_publish == 'true'
steps:
- name: Download all wheels
uses: actions/download-artifact@v4
with:
pattern: wheels-*
path: dist
merge-multiple: true
- name: Download sdist
uses: actions/download-artifact@v4
with:
name: sdist
path: dist
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
skip-existing: true
publish-crate:
name: Publish crate to crates.io
needs: check-and-tag
runs-on: ubuntu-latest
if: needs.check-and-tag.outputs.should_publish == 'true'
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
- name: Commit Cargo.lock if changed
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Cargo.lock || true
if ! git diff --staged --quiet; then
git commit -m "chore: update Cargo.lock" || true
git push origin HEAD:${{ github.ref }} || true
fi
- name: Publish to crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
run: |
# Publish the crate; requires a crates.io token in secrets.CRATES_IO_TOKEN
# WARNING: --allow-dirty will publish even if there are uncommitted changes
# This may result in a published crate that isn't reproducible from the
# repository state. Use only if you understand the risk.
cargo publish --manifest-path Cargo.toml --allow-dirty