Merge pull request #10 from CocoRoF/main #11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ────────────────────────────────────────────────────────────── | |
| # f2a — Cross-platform wheel build & PyPI deploy | |
| # | |
| # Trigger : push to the `deploy` branch (only when pyproject.toml changes) | |
| # Pipeline : | |
| # 1. check-version — skip if version already on PyPI | |
| # 2. test — pytest across Python 3.10–3.13 | |
| # 3. build-wheels — maturin native wheels (5 targets × 4 Pythons) | |
| # 4. build-sdist — source distribution | |
| # 5. publish — upload to PyPI via Trusted Publisher (OIDC) | |
| # | |
| # Based on CocoRoF/googer proven workflow pattern. | |
| # ────────────────────────────────────────────────────────────── | |
| name: Build & Publish to PyPI | |
| on: | |
| push: | |
| branches: | |
| - deploy | |
| paths: | |
| - "pyproject.toml" | |
| jobs: | |
| # ── 1. Version gate ─────────────────────────────────────── | |
| check-version: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version_changed: ${{ steps.check.outputs.changed }} | |
| new_version: ${{ steps.check.outputs.new_version }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 2 | |
| - name: Check version change | |
| id: check | |
| run: | | |
| NEW_VERSION=$(grep -oP '^version\s*=\s*"\K[^"]+' pyproject.toml) | |
| echo "new_version=$NEW_VERSION" >> "$GITHUB_OUTPUT" | |
| # Verify Cargo.toml version matches | |
| CARGO_VERSION=$(grep -oP '^version\s*=\s*"\K[^"]+' Cargo.toml) | |
| if [ "$NEW_VERSION" != "$CARGO_VERSION" ]; then | |
| echo "::error::Version mismatch! pyproject.toml=$NEW_VERSION vs Cargo.toml=$CARGO_VERSION" | |
| exit 1 | |
| fi | |
| # Compare with previous commit | |
| OLD_VERSION=$(git show HEAD~1:pyproject.toml 2>/dev/null | grep -oP '^version\s*=\s*"\K[^"]+' || echo "") | |
| echo "Old version: $OLD_VERSION" | |
| echo "New version: $NEW_VERSION" | |
| if [ -z "$OLD_VERSION" ] || [ "$OLD_VERSION" != "$NEW_VERSION" ]; then | |
| echo "changed=true" >> "$GITHUB_OUTPUT" | |
| echo "✅ Version changed: $OLD_VERSION -> $NEW_VERSION" | |
| else | |
| echo "changed=false" >> "$GITHUB_OUTPUT" | |
| echo "⏭️ Version unchanged, skipping publish." | |
| fi | |
| # ── 2. Test ─────────────────────────────────────────────── | |
| test: | |
| needs: check-version | |
| if: needs.check-version.outputs.version_changed == 'true' | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ["3.10", "3.13"] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| key: publish-py${{ matrix.python-version }} | |
| cache-on-failure: true | |
| - name: Pip cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/pip | |
| key: pip-publish-py${{ matrix.python-version }}-${{ hashFiles('pyproject.toml') }} | |
| restore-keys: | | |
| pip-publish-py${{ matrix.python-version }}- | |
| - name: Install package and test deps | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install .[dev] | |
| - name: Run tests | |
| run: python -m pytest -v --tb=short | |
| # ── 3. Build wheels (maturin) ───────────────────────────── | |
| build-wheels: | |
| needs: [check-version, test] | |
| if: needs.check-version.outputs.version_changed == 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # ── Linux x86_64 ── | |
| - os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| manylinux: auto | |
| # ── Linux aarch64 ── | |
| - os: ubuntu-latest | |
| target: aarch64-unknown-linux-gnu | |
| manylinux: auto | |
| # ── macOS x86_64 (Intel, cross-compiled on ARM) ── | |
| - os: macos-14 | |
| target: x86_64-apple-darwin | |
| manylinux: "off" | |
| # ── macOS aarch64 (Apple Silicon) ── | |
| - os: macos-14 | |
| target: aarch64-apple-darwin | |
| manylinux: "off" | |
| # ── Windows x86_64 ── | |
| - os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| manylinux: "off" | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Build wheels | |
| uses: PyO3/maturin-action@v1 | |
| with: | |
| target: ${{ matrix.target }} | |
| args: --release --out dist --interpreter 3.10 3.11 3.12 3.13 | |
| manylinux: ${{ matrix.manylinux }} | |
| before-script-linux: | | |
| # Ensure Perl is available for vendored OpenSSL build (openssl-src) | |
| if command -v yum &> /dev/null; then | |
| yum install -y perl-IPC-Cmd perl-core | |
| elif command -v apk &> /dev/null; then | |
| apk add --no-cache perl make | |
| fi | |
| - name: Upload wheels | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: wheels-${{ matrix.target }} | |
| path: dist/*.whl | |
| # ── 4. Build sdist ──────────────────────────────────────── | |
| build-sdist: | |
| needs: [check-version, test] | |
| if: needs.check-version.outputs.version_changed == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Build sdist | |
| uses: PyO3/maturin-action@v1 | |
| with: | |
| command: sdist | |
| args: --out dist | |
| - name: Upload sdist | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sdist | |
| path: dist/*.tar.gz | |
| # ── 5. Publish to PyPI ──────────────────────────────────── | |
| publish: | |
| needs: [check-version, build-wheels, build-sdist] | |
| if: needs.check-version.outputs.version_changed == 'true' | |
| runs-on: ubuntu-latest | |
| environment: pypi | |
| permissions: | |
| id-token: write # Required for Trusted Publisher (OIDC) | |
| steps: | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: dist | |
| merge-multiple: true | |
| - name: List artifacts | |
| run: ls -lh dist/ | |
| - name: Publish to PyPI | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| # Uses Trusted Publisher (OIDC) — no API token needed. | |
| # Register at: https://pypi.org/manage/project/f2a/settings/publishing/ |