evoc-rs 0.4.0

Rust port of the EVoC clustering algorithm for high dimensional data
Documentation
name: Release the Python bindings

# Triggered by a completed test run, not by a push, so a broken build can never
# be published. `workflows:` must match the `name:` of python-test.yml.
#
# The tag prefix is `py-v`, not `v`: release.yml already owns `v$version` for
# the crate. The two versions are independent lines, so a Python patch release
# and a crate release never collide and never imply each other. The wheel
# reports which crate it vendored as `evoc_rs.__core_version__`.

on:
  workflow_run:
    workflows: ["Test the Python bindings"]
    branches: [ main ]
    types: [ completed ]
  workflow_dispatch:
    inputs:
      publish:
        description: Upload the wheels. Off by default, so a dispatch only builds.
        type: boolean
        default: false
      index:
        description: Which index to upload to.
        type: choice
        options:
          - testpypi
          - pypi
        default: testpypi
      tag:
        description: Create the py-v tag and the GitHub release.
        type: boolean
        default: false

permissions:
  contents: write
  # PyPI trusted publishing. A called workflow's permissions are capped by the
  # caller's token, so leaving this out makes the publish 403.
  id-token: write

jobs:
  # Version check, tag, GitHub release and the wheel matrix. Leaves the built
  # wheels as `dist-*` artefacts.
  build:
    uses: GregorLueg/personal-actions/.github/workflows/python-maturin-release.yml@v1
    with:
      # Always true, and it does not mean "upload". It only decides whether the
      # version is checked against the index before anything is built, so an
      # already-published version costs one cheap job instead of three wheel
      # builds. Whether an upload happens is the `publish` job's `if:` below.
      publish: true

      # ARMED. A dispatch still takes the form's value, so a rehearsal can opt
      # out; anything else tags, which is what a version bump on main should do.
      tag: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || true }}
      # A choice rather than a free-text URL: there are only ever two answers
      # here, and a typo costs the whole wheel matrix before it is noticed.
      repository-url: ${{ (github.event_name == 'workflow_dispatch' && inputs.index == 'testpypi') && 'https://test.pypi.org/legacy/' || '' }}

      # The sdist would carry a `path` dependency on the parent crate, which is
      # not known to round-trip. Wheels only until `maturin sdist` plus a clean
      # install has been shown to work.
      sdist: false

  # The upload lives here rather than in the reusable workflow, and has to.
  # PyPI's trusted publishing matches the OIDC token's `job_workflow_ref`, which
  # for a reusable workflow points at the *other* repository, and the publisher
  # form cannot express that (pypi/warehouse#11096). Running it here makes
  # `job_workflow_ref` this file, which is what the PyPI publisher names.
  #
  # So the trusted publisher on PyPI must be configured as:
  #   owner GregorLueg, repo evoc-rs, workflow python-release.yml,
  #   environment pypi
  publish:
    name: Publish to PyPI
    needs: build
    # ARMED. `should-build` is false when the version is already on PyPI, so an
    # ordinary push to main reaches here, finds nothing to do and stops. A
    # version bump is what makes this fire. The `pypi` environment still holds
    # it for a review before the upload, which is the last reversible moment.
    if: >-
      needs.build.outputs.should-build == 'true' &&
      (github.event_name == 'workflow_dispatch' && inputs.publish
       || github.event_name != 'workflow_dispatch')
    runs-on: ubuntu-latest
    timeout-minutes: 20
    environment: pypi
    permissions:
      id-token: write
    steps:
      - uses: actions/download-artifact@v4
        with:
          pattern: dist-*
          merge-multiple: true
          path: dist

      - name: List what is about to be uploaded
        run: ls -la dist

      - uses: pypa/gh-action-pypi-publish@release/v1
        with:
          packages-dir: dist
          repository-url: ${{ inputs.index == 'testpypi' && 'https://test.pypi.org/legacy/' || 'https://upload.pypi.org/legacy/' }}
          print-hash: true