blob: d9fcdd406b5980dc3ca5321dd9b8cd0885d68635 [file]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
name: Publish Python 🐍 distribution 📦 to PyPI
on:
workflow_call:
inputs:
release_tag:
description: 'Release tag (e.g., v0.4.0 or v0.4.0-rc.1)'
required: true
type: string
workflow_dispatch:
inputs:
release_tag:
description: 'Release tag (e.g., v0.4.0 or v0.4.0-rc.1)'
required: true
type: string
permissions:
contents: read
jobs:
validate-release-tag:
runs-on: ubuntu-latest
outputs:
cargo-version: ${{ steps.validate.outputs.cargo-version }}
is-rc: ${{ steps.validate.outputs.is-rc }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
if: ${{ github.event_name == 'workflow_dispatch' }}
with:
persist-credentials: false
- name: Validate release tag format
id: validate
# Valid formats: v<major>.<minor>.<patch> OR v<major>.<minor>.<patch>-rc.<release_candidate>
env:
RELEASE_TAG: ${{ inputs.release_tag }}
run: |
echo "Validating release tag: $RELEASE_TAG"
if [[ ! "$RELEASE_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?$ ]]; then
echo "❌ Invalid release tag format: $RELEASE_TAG"
echo "Expected format: v<major>.<minor>.<patch> OR v<major>.<minor>.<patch>-rc.<release_candidate>"
echo "Examples: v0.4.0, v1.2.3-rc.1"
exit 1
fi
echo "✅ Release tag format is valid: $RELEASE_TAG"
# Strip 'v' prefix for cargo version
CARGO_VERSION="${RELEASE_TAG#v}"
echo "Cargo version (without v prefix): $CARGO_VERSION"
# For manual triggers, validate that the tag matches the version in Cargo.toml
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
# Extract base version (without -rc.X suffix) for comparison with Cargo.toml
BASE_VERSION="${CARGO_VERSION%-rc.*}"
echo "Base version (for Cargo.toml comparison): $BASE_VERSION"
# Read version from Cargo.toml and validate it matches
CARGO_TOML_VERSION=$(grep '^version = ' bindings/python/Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
echo "Version in bindings/python/Cargo.toml: $CARGO_TOML_VERSION"
if [ "$BASE_VERSION" != "$CARGO_TOML_VERSION" ]; then
echo "❌ Version mismatch!"
echo " Release tag base version: $BASE_VERSION"
echo " bindings/python/Cargo.toml version: $CARGO_TOML_VERSION"
echo "Please ensure the release tag matches the version in Cargo.toml"
exit 1
fi
echo "✅ Version matches bindings/python/Cargo.toml"
fi
# Check if this is a release candidate
if [[ "$RELEASE_TAG" =~ -rc\.[0-9]+$ ]]; then
IS_RC="true"
echo "This is a release candidate"
else
IS_RC="false"
echo "This is a stable release"
fi
# Set outputs for other jobs to use
echo "cargo-version=$CARGO_VERSION" >> $GITHUB_OUTPUT
echo "is-rc=$IS_RC" >> $GITHUB_OUTPUT
sdist:
runs-on: ubuntu-latest
needs: [validate-release-tag]
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- name: Install toml-cli
if: ${{ needs.validate-release-tag.outputs.is-rc == 'true' }}
run: cargo install toml-cli
- name: Set cargo version for RC
if: ${{ needs.validate-release-tag.outputs.is-rc == 'true' }}
working-directory: "bindings/python"
run: |
echo "Setting cargo version to: ${NEEDS_VALIDATE_RELEASE_TAG_OUTPUTS_CARGO_VERSION}"
toml set Cargo.toml package.version "${NEEDS_VALIDATE_RELEASE_TAG_OUTPUTS_CARGO_VERSION}" > Cargo.toml.tmp
# doing this explicitly to avoid issue in Windows where `mv` does not overwrite existing file
rm Cargo.toml
mv Cargo.toml.tmp Cargo.toml
env:
NEEDS_VALIDATE_RELEASE_TAG_OUTPUTS_CARGO_VERSION: ${{ needs.validate-release-tag.outputs.cargo-version }}
- uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1
with:
working-directory: "bindings/python"
command: sdist
args: -o dist
- name: Upload sdist
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
with:
name: wheels-sdist
path: bindings/python/dist
wheels:
runs-on: "${{ matrix.os }}"
needs: [validate-release-tag]
strategy:
max-parallel: 15
matrix:
include:
- { os: windows-latest }
- { os: macos-latest, target: "universal2-apple-darwin" }
- { os: ubuntu-latest, target: "x86_64" }
- {
os: ubuntu-latest,
target: "aarch64",
manylinux: "manylinux_2_28",
}
- { os: ubuntu-latest, target: "armv7l" }
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
persist-credentials: false
- name: Install toml-cli
if: ${{ needs.validate-release-tag.outputs.is-rc == 'true' }}
run: cargo install toml-cli
- name: Set cargo version for RC
if: ${{ needs.validate-release-tag.outputs.is-rc == 'true' }}
working-directory: "bindings/python"
env:
CARGO_VERSION: ${{ needs.validate-release-tag.outputs.cargo-version }}
run: |
echo "Setting cargo version to: $CARGO_VERSION"
toml set Cargo.toml package.version "$CARGO_VERSION" > Cargo.toml.tmp
# doing this explicitly to avoid issue in Windows where `mv` does not overwrite existing file
rm Cargo.toml
mv Cargo.toml.tmp Cargo.toml
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version: 3.12
- name: Get MSRV
id: get-msrv
uses: ./.github/actions/get-msrv
- name: Setup Rust toolchain
uses: ./.github/actions/setup-builder
with:
rust-version: ${{ steps.get-msrv.outputs.msrv }}
- uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1
with:
target: ${{ matrix.target }}
manylinux: ${{ matrix.manylinux || 'auto' }}
working-directory: "bindings/python"
command: build
args: --release -o dist -i python3.12 # Explicitly set interpreter; manylinux containers have multiple Pythons and maturin may pick an older one
- name: Upload wheels
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
with:
name: wheels-${{ matrix.os }}-${{ matrix.target }}
path: bindings/python/dist
pypi-publish:
name: Publish Python 🐍 distribution 📦 to Pypi
needs: [sdist, wheels]
runs-on: ubuntu-latest
environment:
name: pypi
url: https://pypi.org/p/pyiceberg-core
permissions:
id-token: write # IMPORTANT: mandatory for trusted publishing
steps:
- name: Download all the dists
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
with:
pattern: wheels-*
merge-multiple: true
path: bindings/python/dist
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
with:
skip-existing: true
packages-dir: bindings/python/dist
verbose: true