name: Python Release
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
version:
description: "Version to release (without the leading v)"
required: true
default: "0.3.1"
type: string
publish:
description: "Enable PyPI publication"
required: false
default: false
type: boolean
permissions:
contents: read
env:
CARGO_TERM_COLOR: always
RELEASE_VERSION: ${{ github.event_name == 'workflow_dispatch' && inputs.version || github.ref_name }}
concurrency:
group: python-release-${{ github.ref }}
cancel-in-progress: false
jobs:
validate:
name: Validate Python release version
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
- name: Install Python 3.12
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: '3.12'
- name: Install Rust 1.85.0
uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4
with:
toolchain: 1.85.0
- name: Validate package versions
env:
RELEASE_VERSION_INPUT: ${{ env.RELEASE_VERSION }}
shell: bash
run: |
set -euo pipefail
expected="${RELEASE_VERSION_INPUT#v}"
[[ "$expected" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || {
echo "Release version must be a semantic X.Y.Z value: $expected" >&2
exit 1
}
root_version="$(
cargo metadata --locked --no-deps --format-version 1 |
python3 -c 'import json, sys; print(next(p["version"] for p in json.load(sys.stdin)["packages"] if p["name"] == "ripex"))'
)"
py_cargo_version="$(
cargo metadata --manifest-path bindings/python/Cargo.toml --locked --no-deps --format-version 1 |
python3 -c 'import json, sys; print(next(p["version"] for p in json.load(sys.stdin)["packages"] if p["name"] == "ripex-python"))'
)"
pyproject_version="$(
python3 -c '
import tomllib
with open("bindings/python/pyproject.toml", "rb") as f:
print(tomllib.load(f)["project"]["version"])
'
)"
for pair in \
"root ripex $root_version" \
"python-cargo ripex-python $py_cargo_version" \
"pyproject ripex $pyproject_version"; do
read -r kind package version <<<"$pair"
test "$version" = "$expected" || {
echo "$kind package $package is $version, expected $expected" >&2
exit 1
}
done
linux:
name: Build Linux Wheels (${{ matrix.target }})
needs: validate
runs-on: ubuntu-latest
timeout-minutes: 45
permissions:
contents: read
strategy:
fail-fast: false
matrix:
target: [x86_64, aarch64]
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
- name: Install Python 3.12
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: '3.12'
- name: Build Linux wheel via maturin-action
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --manifest-path bindings/python/Cargo.toml
manylinux: auto
- name: Upload wheel artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: python-wheels-linux-${{ matrix.target }}
path: dist/*.whl
if-no-files-found: error
retention-days: 14
macos:
name: Build macOS Wheels (${{ matrix.target }})
needs: validate
runs-on: ${{ matrix.os }}
timeout-minutes: 45
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- os: macos-14
target: x86_64
- os: macos-14
target: aarch64
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
- name: Install Python 3.12
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: '3.12'
- name: Install Rust 1.85.0
uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4
with:
toolchain: 1.85.0
- name: Build macOS wheel via maturin-action
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --manifest-path bindings/python/Cargo.toml
- name: Upload wheel artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: python-wheels-macos-${{ matrix.target }}
path: dist/*.whl
if-no-files-found: error
retention-days: 14
windows:
name: Build Windows Wheels (${{ matrix.target }})
needs: validate
runs-on: windows-latest
timeout-minutes: 45
permissions:
contents: read
strategy:
fail-fast: false
matrix:
target: [x64]
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
- name: Install Python 3.12
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: '3.12'
- name: Install Rust 1.85.0
uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4
with:
toolchain: 1.85.0
- name: Build Windows wheel via maturin-action
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist --manifest-path bindings/python/Cargo.toml
- name: Upload wheel artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: python-wheels-windows-${{ matrix.target }}
path: dist/*.whl
if-no-files-found: error
retention-days: 14
sdist:
name: Build Python Source Distribution (sdist)
needs: validate
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
- name: Install Python 3.12
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065
with:
python-version: '3.12'
- name: Install Rust 1.85.0
uses: dtolnay/rust-toolchain@4cda84d5c5c54efe2404f9d843567869ab1699d4
with:
toolchain: 1.85.0
- name: Build sdist via maturin-action
uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist --manifest-path bindings/python/Cargo.toml
- name: Upload sdist artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: python-sdist
path: dist/*
if-no-files-found: error
retention-days: 14
release:
name: Release Python Packages
needs: [linux, macos, windows, sdist]
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
- name: Download all built artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
pattern: python-*
path: dist
merge-multiple: true
- name: Display package directory contents
shell: bash
run: |
ls -la dist/
- name: Publish to PyPI
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && env.PYPI_API_TOKEN != ''
env:
PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
uses: PyO3/maturin-action@v1
with:
command: upload
args: --non-interactive --skip-existing dist/*