---
name: Build CI wheels

on:
  # Save CI by only running this on release branches or tags.
  push:
    branches:
      - main
      - v[0-9]+.[0-9]+.x
    tags:
      - v*
  # Also allow running this action on PRs if requested by applying the
  # "Run cibuildwheel" label.
  pull_request:
    types:
      - opened
      - synchronize
      - reopened
      - labeled

permissions:
  contents: read

jobs:
  build_sdist:
    if: >-
      github.event_name == 'push' ||
      github.event_name == 'pull_request' && (
        (
          github.event.action == 'labeled' &&
          github.event.label.name == 'CI: Run cibuildwheel'
        ) ||
        contains(github.event.pull_request.labels.*.name,
                 'CI: Run cibuildwheel')
      )
    name: Build sdist
    runs-on: ubuntu-20.04
    outputs:
      SDIST_NAME: ${{ steps.sdist.outputs.SDIST_NAME }}

    steps:
      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2
        with:
          fetch-depth: 0
          persist-credentials: false

      - uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b  # v5.3.0
        name: Install Python
        with:
          python-version: '3.10'

      # Something changed somewhere that prevents the downloaded-at-build-time
      # licenses from being included in built wheels, so pre-download them so
      # that they exist before the build and are included.
      - name: Pre-download bundled licenses
        run: >
          curl -Lo LICENSE/LICENSE_QHULL
          https://github.com/qhull/qhull/raw/2020.2/COPYING.txt

      - name: Install dependencies
        run: python -m pip install build twine

      - name: Build sdist
        id: sdist
        run: |
          python -m build --sdist
          python ci/export_sdist_name.py

      - name: Check README rendering for PyPI
        run: twine check dist/*

      - name: Upload sdist result
        uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882  # v4.4.3
        with:
          name: cibw-sdist
          path: dist/*.tar.gz
          if-no-files-found: error

  build_wheels:
    if: >-
      github.event_name == 'push' ||
      github.event_name == 'pull_request' && (
        (
          github.event.action == 'labeled' &&
          github.event.label.name == 'CI: Run cibuildwheel'
        ) ||
        contains(github.event.pull_request.labels.*.name,
                 'CI: Run cibuildwheel')
      )
    needs: build_sdist
    name: Build wheels on ${{ matrix.os }} for ${{ matrix.cibw_archs }}
    runs-on: ${{ matrix.os }}
    env:
      CIBW_BEFORE_BUILD: >-
        rm -rf {package}/build
      CIBW_BEFORE_BUILD_WINDOWS: >-
        pip install delvewheel &&
        rm -rf {package}/build
      CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: >-
        delvewheel repair -w {dest_dir} {wheel}
      CIBW_AFTER_BUILD: >-
        twine check {wheel} &&
        python {package}/ci/check_wheel_licenses.py {wheel}
      # On Windows, we explicitly request MSVC compilers (as GitHub Action runners have
      # MinGW on PATH that would be picked otherwise), switch to a static build for
      # runtimes, but use dynamic linking for `VCRUNTIME140.dll`, `VCRUNTIME140_1.dll`,
      # and the UCRT. This avoids requiring specific versions of `MSVCP140.dll`, while
      # keeping shared state with the rest of the Python process/extensions.
      CIBW_CONFIG_SETTINGS_WINDOWS: >-
        setup-args="--vsenv"
        setup-args="-Db_vscrt=mt"
        setup-args="-Dcpp_link_args=['ucrt.lib','vcruntime.lib','/nodefaultlib:libucrt.lib','/nodefaultlib:libvcruntime.lib']"
      CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014
      CIBW_SKIP: "*-musllinux_aarch64"
      CIBW_TEST_COMMAND: >-
        python {package}/ci/check_version_number.py
      MACOSX_DEPLOYMENT_TARGET: "10.12"
      MPL_DISABLE_FH4: "yes"
    strategy:
      matrix:
        include:
          - os: ubuntu-20.04
            cibw_archs: "x86_64"
          - os: ubuntu-20.04
            cibw_archs: "aarch64"
          - os: windows-latest
            cibw_archs: "auto64"
          - os: macos-13
            cibw_archs: "x86_64"
          - os: macos-14
            cibw_archs: "arm64"

    steps:
      - name: Set up QEMU
        if: matrix.cibw_archs == 'aarch64'
        uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf  # v3.2.0
        with:
          platforms: arm64

      - name: Download sdist
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16  # v4.1.8
        with:
          name: cibw-sdist
          path: dist/

      - name: Build wheels for CPython 3.13
        uses: pypa/cibuildwheel@ee63bf16da6cddfb925f542f2c7b59ad50e93969  # v2.22.0
        with:
          package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }}
        env:
          CIBW_BUILD: "cp313-* cp313t-*"
          CIBW_BUILD_FRONTEND:
            "pip; args: --pre --extra-index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple"
          CIBW_FREE_THREADED_SUPPORT: true
          # No free-threading wheels available for aarch64 on Pillow.
          CIBW_TEST_SKIP: "cp313t-manylinux_aarch64"
          # We need pre-releases to get the nightly wheels.
          CIBW_BEFORE_TEST: >-
            pip install --pre
            --extra-index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple
            contourpy numpy pillow
          CIBW_ARCHS: ${{ matrix.cibw_archs }}

      - name: Build wheels for CPython 3.12
        uses: pypa/cibuildwheel@ee63bf16da6cddfb925f542f2c7b59ad50e93969  # v2.22.0
        with:
          package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }}
        env:
          CIBW_BUILD: "cp312-*"
          CIBW_ARCHS: ${{ matrix.cibw_archs }}

      - name: Build wheels for CPython 3.11
        uses: pypa/cibuildwheel@ee63bf16da6cddfb925f542f2c7b59ad50e93969  # v2.22.0
        with:
          package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }}
        env:
          CIBW_BUILD: "cp311-*"
          CIBW_ARCHS: ${{ matrix.cibw_archs }}

      - name: Build wheels for CPython 3.10
        uses: pypa/cibuildwheel@ee63bf16da6cddfb925f542f2c7b59ad50e93969  # v2.22.0
        with:
          package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }}
        env:
          CIBW_BUILD: "cp310-*"
          CIBW_ARCHS: ${{ matrix.cibw_archs }}

      - name: Build wheels for PyPy
        uses: pypa/cibuildwheel@ee63bf16da6cddfb925f542f2c7b59ad50e93969  # v2.22.0
        with:
          package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }}
        env:
          CIBW_BUILD: "pp310-*"
          CIBW_ARCHS: ${{ matrix.cibw_archs }}
          # Work around for https://github.com/pypa/setuptools/issues/4571
          # This can be removed once kiwisolver has wheels for PyPy 3.10
          # https://github.com/nucleic/kiwi/pull/182
          CIBW_BEFORE_TEST: >-
            export PIP_CONSTRAINT=pypy-constraint.txt &&
            echo "setuptools!=72.2.0" > $PIP_CONSTRAINT &&
            pip install kiwisolver &&
            unset PIP_CONSTRAINT
        if: matrix.cibw_archs != 'aarch64' && matrix.os != 'windows-latest'

      - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882  # v4.4.3
        with:
          name: cibw-wheels-${{ runner.os }}-${{ matrix.cibw_archs }}
          path: ./wheelhouse/*.whl
          if-no-files-found: error

  publish:
    if: github.event_name == 'push' && github.ref_type == 'tag'
    name: Upload release to PyPI
    needs: [build_sdist, build_wheels]
    runs-on: ubuntu-latest
    environment: release
    permissions:
      id-token: write
      attestations: write
      contents: read
    steps:
      - name: Download packages
        uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16  # v4.1.8
        with:
          pattern: cibw-*
          path: dist
          merge-multiple: true

      - name: Print out packages
        run: ls dist

      - name: Generate artifact attestation for sdist and wheel
        uses: actions/attest-build-provenance@7668571508540a607bdfd90a87a560489fe372eb  # v2.1.0
        with:
          subject-path: dist/matplotlib-*

      - name: Publish package distributions to PyPI
        uses: pypa/gh-action-pypi-publish@67339c736fd9354cd4f8cb0b744f2b82a74b5c70  # v1.12.3
