name: Publish
on:
push:
tags:
- 'v*'
env:
CARGO_TERM_COLOR: always
permissions:
contents: read
concurrency:
group: publish-${{ github.ref }}
cancel-in-progress: false
jobs:
validate:
name: Validate
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install protoc
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Cache Cargo dependencies
uses: Swatinem/rust-cache@v2
- name: Check formatting
run: cargo fmt --all --check
- name: Run Clippy
run: cargo clippy --all-targets --all-features -- -D warnings
- name: Run tests
run: cargo test --all-targets --verbose
- name: Verify version consistency
run: |
TAG_VERSION=${GITHUB_REF#refs/tags/v}
CARGO_VERSION=$(cargo metadata --no-deps --format-version 1 \
| jq -r '.packages[] | select(.name == "p2o") | .version')
echo "Tag version: $TAG_VERSION"
echo "Cargo.toml version: $CARGO_VERSION"
if [ "$CARGO_VERSION" != "$TAG_VERSION" ]; then
echo "::error::Cargo.toml version ($CARGO_VERSION) does not match Git tag ($TAG_VERSION)."
exit 1
fi
publish-crates:
name: Publish to crates.io
needs: validate
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install protoc
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache Cargo dependencies
uses: Swatinem/rust-cache@v2
- name: Publish
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: cargo publish
pypi-linux:
name: PyPI wheels (linux-${{ matrix.target }})
needs: publish-crates
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64
runner: ubuntu-latest
- target: aarch64
runner: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v6
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist
sccache: 'true'
manylinux: auto
before-script-linux: |
set -eux
PROTOC_VERSION=28.3
case "$(uname -m)" in
x86_64) PROTOC_ARCH=x86_64 ;;
aarch64) PROTOC_ARCH=aarch_64 ;;
*) echo "Unsupported host arch: $(uname -m)"; exit 1 ;;
esac
if command -v apt-get >/dev/null 2>&1; then
apt-get update && apt-get install -y curl unzip
elif command -v yum >/dev/null 2>&1; then
yum install -y curl unzip
elif command -v apk >/dev/null 2>&1; then
apk add --no-cache curl unzip
fi
curl -fL "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip" -o /tmp/protoc.zip
unzip -o /tmp/protoc.zip -d /usr/local
rm /tmp/protoc.zip
protoc --version
- uses: actions/upload-artifact@v7
with:
name: wheels-linux-${{ matrix.target }}
path: dist
pypi-musllinux:
name: PyPI wheels (musllinux-${{ matrix.target }})
needs: publish-crates
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- target: x86_64
runner: ubuntu-latest
- target: aarch64
runner: ubuntu-24.04-arm
steps:
- uses: actions/checkout@v6
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.target }}
args: --release --out dist
sccache: 'true'
manylinux: musllinux_1_2
before-script-linux: |
set -eux
PROTOC_VERSION=28.3
case "$(uname -m)" in
x86_64) PROTOC_ARCH=x86_64 ;;
aarch64) PROTOC_ARCH=aarch_64 ;;
*) echo "Unsupported host arch: $(uname -m)"; exit 1 ;;
esac
if command -v apt-get >/dev/null 2>&1; then
apt-get update && apt-get install -y curl unzip
elif command -v yum >/dev/null 2>&1; then
yum install -y curl unzip
elif command -v apk >/dev/null 2>&1; then
apk add --no-cache curl unzip
fi
curl -fL "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip" -o /tmp/protoc.zip
unzip -o /tmp/protoc.zip -d /usr/local
rm /tmp/protoc.zip
protoc --version
- uses: actions/upload-artifact@v7
with:
name: wheels-musllinux-${{ matrix.target }}
path: dist
pypi-windows:
name: PyPI wheels (windows-x64)
needs: publish-crates
runs-on: windows-latest
steps:
- uses: actions/checkout@v6
- name: Install protoc
run: choco install protoc
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: x64
args: --release --out dist
sccache: 'true'
rust-toolchain: stable
- uses: actions/upload-artifact@v7
with:
name: wheels-windows-x64
path: dist
pypi-macos:
name: PyPI wheels (macos-${{ matrix.platform.target }})
needs: publish-crates
runs-on: ${{ matrix.platform.runner }}
strategy:
fail-fast: false
matrix:
platform:
- runner: macos-13
target: x86_64
- runner: macos-latest
target: aarch64
steps:
- uses: actions/checkout@v6
- name: Install protoc
run: brew install protobuf
- name: Build wheels
uses: PyO3/maturin-action@v1
with:
target: ${{ matrix.platform.target }}
args: --release --out dist
sccache: 'true'
- uses: actions/upload-artifact@v7
with:
name: wheels-macos-${{ matrix.platform.target }}
path: dist
pypi-sdist:
name: PyPI sdist
needs: publish-crates
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Build sdist
uses: PyO3/maturin-action@v1
with:
command: sdist
args: --out dist
- uses: actions/upload-artifact@v7
with:
name: wheels-sdist
path: dist
publish-pypi:
name: Publish to PyPI
needs: [pypi-linux, pypi-musllinux, pypi-windows, pypi-macos, pypi-sdist]
runs-on: ubuntu-latest
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v8
with:
pattern: wheels-*
path: dist
merge-multiple: true
- name: Publish to PyPI via Trusted Publisher (OIDC)
uses: pypa/gh-action-pypi-publish@release/v1
with:
skip-existing: true
build-binaries:
name: Build binary (${{ matrix.target }})
needs: publish-pypi
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
artifact: p2o-linux-x86_64
- os: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
artifact: p2o-linux-aarch64
- os: macos-latest
target: aarch64-apple-darwin
artifact: p2o-macos-aarch64
- os: macos-13
target: x86_64-apple-darwin
artifact: p2o-macos-x86_64
- os: windows-latest
target: x86_64-pc-windows-msvc
artifact: p2o-windows-x86_64
steps:
- name: Checkout
uses: actions/checkout@v6
- name: Install protoc (Ubuntu)
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler
- name: Install protoc (macOS)
if: runner.os == 'macOS'
run: brew install protobuf
- name: Install protoc (Windows)
if: runner.os == 'Windows'
run: choco install protoc
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Cache Cargo dependencies
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Build
run: cargo build --release --target ${{ matrix.target }}
- name: Package (Unix)
if: runner.os != 'Windows'
run: |
mkdir -p staging
cp target/${{ matrix.target }}/release/p2o staging/
tar czf ${{ matrix.artifact }}.tar.gz -C staging p2o
- name: Package (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path staging
Copy-Item "target/${{ matrix.target }}/release/p2o.exe" -Destination staging/
Compress-Archive -Path staging/p2o.exe -DestinationPath ${{ matrix.artifact }}.zip
- uses: actions/upload-artifact@v7
with:
name: ${{ matrix.artifact }}
path: |
${{ matrix.artifact }}.tar.gz
${{ matrix.artifact }}.zip
github-release:
name: GitHub Release
needs: build-binaries
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v6
- uses: actions/download-artifact@v8
with:
path: artifacts
- name: Create release
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
files: |
artifacts/**/*.tar.gz
artifacts/**/*.zip