name: PyPI Publish on: push: tags: - 'python-v*' pull_request: # This should trigger a dry run (we skip the final publish step) paths: - .github/workflows/pypi-publish.yml - .github/workflows/build_linux_wheel/action.yml - .github/workflows/build_mac_wheel/action.yml - .github/workflows/build_windows_wheel/action.yml - Cargo.toml # Change in dependency frequently breaks builds - Cargo.lock env: PIP_EXTRA_INDEX_URL: "https://pypi.fury.io/lance-format/ https://pypi.fury.io/lancedb/" permissions: contents: read jobs: linux: name: Python ${{ matrix.config.platform }} manylinux${{ matrix.config.manylinux }} timeout-minutes: 60 strategy: matrix: config: - platform: x86_64 manylinux: "2_28" extra_args: "--features fp16kernels" runner: ubuntu-22.04 # For successful fat LTO builds, we need a large runner to avoid OOM errors. - platform: aarch64 manylinux: "2_28" extra_args: "--features fp16kernels" runner: ubuntu-2404-8x-arm64 runs-on: ${{ matrix.config.runner }} steps: - uses: actions/checkout@v6 with: fetch-depth: 0 lfs: true - name: Set up Python uses: actions/setup-python@v6 with: python-version: "3.10" - uses: ./.github/workflows/build_linux_wheel with: python-minor-version: 10 args: "--release --strip ${{ matrix.config.extra_args }}" arm-build: ${{ matrix.config.platform == 'aarch64' }} manylinux: ${{ matrix.config.manylinux }} - uses: actions/upload-artifact@v7 if: startsWith(github.ref, 'refs/tags/python-v') with: name: wheels-linux-${{ matrix.config.platform }}-${{ matrix.config.manylinux }} path: target/wheels/lancedb-*.whl if-no-files-found: error mac: timeout-minutes: 90 runs-on: ${{ matrix.config.runner }} strategy: matrix: config: - target: aarch64-apple-darwin runner: warp-macos-14-arm64-6x env: MACOSX_DEPLOYMENT_TARGET: 10.15 steps: - uses: actions/checkout@v6 with: fetch-depth: 0 lfs: true - name: Set up Python uses: actions/setup-python@v6 with: python-version: "3.13" - uses: ./.github/workflows/build_mac_wheel with: python-minor-version: 10 args: "--release --strip --target ${{ matrix.config.target }} --features fp16kernels" - uses: actions/upload-artifact@v7 if: startsWith(github.ref, 'refs/tags/python-v') with: name: wheels-mac-${{ matrix.config.target }} path: target/wheels/lancedb-*.whl if-no-files-found: error windows: timeout-minutes: 90 runs-on: windows-latest env: # link.exe is single-threaded and the long pole on Windows builds. Use # rustc's bundled lld-link instead. CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER: rust-lld steps: - uses: actions/checkout@v6 with: fetch-depth: 0 lfs: true - name: Set up Python uses: actions/setup-python@v6 with: python-version: "3.13" - uses: ./.github/workflows/build_windows_wheel with: python-minor-version: 10 args: "--release --strip" - uses: actions/upload-artifact@v7 if: startsWith(github.ref, 'refs/tags/python-v') with: name: wheels-windows path: target/wheels/lancedb-*.whl if-no-files-found: error publish: name: Publish wheels if: startsWith(github.ref, 'refs/tags/python-v') needs: [linux, mac, windows] runs-on: ubuntu-latest permissions: id-token: write contents: read steps: - uses: actions/checkout@v6 - name: Download wheel artifacts uses: actions/download-artifact@v8 with: pattern: wheels-* path: target/wheels merge-multiple: true - name: List wheels run: ls -la target/wheels - name: Choose repo id: choose_repo run: | if [[ ${{ github.ref }} == *beta* ]]; then echo "repo=fury" >> $GITHUB_OUTPUT else echo "repo=pypi" >> $GITHUB_OUTPUT fi - name: Publish to Fury if: steps.choose_repo.outputs.repo == 'fury' env: FURY_TOKEN: ${{ secrets.FURY_TOKEN }} run: | shopt -s nullglob WHEELS=(target/wheels/lancedb-*.whl) if [[ ${#WHEELS[@]} -eq 0 ]]; then echo "No wheels found in target/wheels/" >&2 exit 1 fi for WHEEL in "${WHEELS[@]}"; do echo "Uploading $WHEEL to Fury" curl -f -F package=@"$WHEEL" "https://$FURY_TOKEN@push.fury.io/lancedb/" done # NOTE: pypa/gh-action-pypi-publish must be invoked directly from a # workflow file, not from inside a composite action. When called from a # composite, `github.action_repository` is empty (actions/runner#2473) # and the action falls back to `github.repository`, producing a bogus # `docker://ghcr.io/:` image reference that GHA tries to pull. - name: Publish to PyPI if: steps.choose_repo.outputs.repo == 'pypi' uses: pypa/gh-action-pypi-publish@release/v1 with: packages-dir: target/wheels/ gh-release: if: startsWith(github.ref, 'refs/tags/python-v') runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v6 with: fetch-depth: 0 lfs: true - name: Extract version id: extract_version env: GITHUB_REF: ${{ github.ref }} run: | set -e echo "Extracting tag and version from $GITHUB_REF" if [[ $GITHUB_REF =~ refs/tags/python-v(.*) ]]; then VERSION=${BASH_REMATCH[1]} TAG=python-v$VERSION echo "tag=$TAG" >> $GITHUB_OUTPUT echo "version=$VERSION" >> $GITHUB_OUTPUT else echo "Failed to extract version from $GITHUB_REF" exit 1 fi echo "Extracted version $VERSION from $GITHUB_REF" if [[ $VERSION =~ beta ]]; then echo "This is a beta release" # Get last release (that is not this one) FROM_TAG=$(git tag --sort='version:refname' \ | grep ^python-v \ | grep -vF "$TAG" \ | python ci/semver_sort.py python-v \ | tail -n 1) else echo "This is a stable release" # Get last stable tag (ignore betas) FROM_TAG=$(git tag --sort='version:refname' \ | grep ^python-v \ | grep -vF "$TAG" \ | grep -v beta \ | python ci/semver_sort.py python-v \ | tail -n 1) fi echo "Found from tag $FROM_TAG" echo "from_tag=$FROM_TAG" >> $GITHUB_OUTPUT - name: Create Python Release Notes id: python_release_notes uses: mikepenz/release-changelog-builder-action@v4 with: configuration: .github/release_notes.json toTag: ${{ steps.extract_version.outputs.tag }} fromTag: ${{ steps.extract_version.outputs.from_tag }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Create Python GH release uses: softprops/action-gh-release@v2 with: prerelease: ${{ contains('beta', github.ref) }} tag_name: ${{ steps.extract_version.outputs.tag }} token: ${{ secrets.GITHUB_TOKEN }} generate_release_notes: false name: Python LanceDB v${{ steps.extract_version.outputs.version }} body: ${{ steps.python_release_notes.outputs.changelog }} report-failure: name: Report Workflow Failure runs-on: ubuntu-latest needs: [linux, mac, windows, publish] permissions: contents: read issues: write if: always() && failure() && startsWith(github.ref, 'refs/tags/python-v') steps: - uses: actions/checkout@v6 - uses: ./.github/actions/create-failure-issue with: job-results: ${{ toJSON(needs) }} workflow-name: ${{ github.workflow }}