name: Python
on:
  workflow_dispatch:
    inputs:
      build:
        required: true
        type: number
      force-sdist:
        required: false
        type: boolean
        default: false
permissions:
  contents: read
jobs:
  wheel-linux:
    name: Linux ${{ matrix.os }}, ${{ matrix.arch.name }}, Python ${{ matrix.ver }}
    runs-on: ${{ matrix.arch.runs-on }}
    container:
      image: quay.io/pypa/${{ matrix.os }}_${{ matrix.arch.python-name }}
      # Don't run as root within the container.
      # Neither Git nor Bazel appreciates that.
      # 1001 is the GitHub Actions runner user.
      options: --init --user 1001
    strategy:
      fail-fast: false
      matrix:
        arch:
          - { name: X64,   python-name: x86_64,  runs-on: [ubuntu-latest]              }
          # TODO(junyer): Update the label after ARM64 graduates from beta.
          - { name: ARM64, python-name: aarch64, runs-on: [arm-ubuntu-arm-22.04-4core] }
        os: [manylinux_2_28]
        ver: ['3.8', '3.9', '3.10', '3.11', '3.12']
    env:
      BAZELISK_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      PYTHON: /usr/local/bin/python${{ matrix.ver }}
      # Bazel fails if the username is unknown.
      USER: runner
    steps:
      - uses: actions/checkout@v4.1.7
      # Stash the timestamp for the commit SHA that triggered the workflow.
      - run: echo "timestamp=$(git log -1 --pretty=%ct)" >> "${GITHUB_ENV}"
        shell: bash
      - uses: bazel-contrib/setup-bazel@0.8.5
        with:
          bazelisk-version: '1.x'
      - name: Prepare Python ${{ matrix.ver }} environment
        run: |
          "${PYTHON}" -m pip install --upgrade pip
          "${PYTHON}" -m pip install --upgrade setuptools build wheel auditwheel
          "${PYTHON}" -m pip install --upgrade absl-py mypy
          "${PYTHON}" python/toolchains/generate.py
        shell: bash
      - name: Build wheel
        env:
          SOURCE_DATE_EPOCH: ${{ env.timestamp }}
        run: |
          "${PYTHON}" -m build --wheel
          "${PYTHON}" -m auditwheel repair --wheel-dir=. dist/*
        shell: bash
        working-directory: python
      - name: Test wheel
        run: |
          "${PYTHON}" -m pip install google_re2-*.whl
          # Pivot out of the repository so that we test the wheel.
          DIR=$(mktemp -d)
          cp re2_test.py "${DIR}"
          cd "${DIR}"
          "${PYTHON}" re2_test.py
        shell: bash
        working-directory: python
      - uses: actions/upload-artifact@v4.3.3
        with:
          name: ${{ hashFiles('python/google_re2-*.whl') }}
          path: python/google_re2-*.whl
          retention-days: 1
  wheel-macos:
    name: macOS ${{ matrix.os }}, ${{ matrix.arch.name }}, Python ${{ matrix.ver }}
    runs-on: macos-${{ matrix.os }}-large
    strategy:
      fail-fast: false
      matrix:
        arch:
          - { name: X64,   bazel-name: x86_64, python-name: x86_64 }
          - { name: ARM64, bazel-name: arm64,  python-name: arm64  }
        # TODO(junyer): Stop cross-compiling after we drop support for macOS 12;
        # instead, specify `-large` suffix on X64 and `-xlarge` suffix on ARM64.
        os: [12, 13, 14]
        ver: ['3.8', '3.9', '3.10', '3.11', '3.12']
    env:
      BAZELISK_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      BAZEL_CPU: darwin_${{ matrix.arch.bazel-name }}
      PLAT_NAME: macosx-${{ matrix.os }}.0-${{ matrix.arch.python-name }}
      # Force a specific target version of macOS.
      # Otherwise, `delocate` renames the wheels!
      MACOSX_DEPLOYMENT_TARGET: ${{ matrix.os }}.0
      # Stop macOS from reporting the system version as 10.x.
      # Otherwise, Python refuses to install the built wheel!
      SYSTEM_VERSION_COMPAT: 0
    steps:
      - uses: actions/checkout@v4.1.7
      # Stash the timestamp for the commit SHA that triggered the workflow.
      - run: echo "timestamp=$(git log -1 --pretty=%ct)" >> "${GITHUB_ENV}"
        shell: bash
      - uses: bazel-contrib/setup-bazel@0.8.5
        with:
          bazelisk-version: '1.x'
      - uses: actions/setup-python@v5.1.0
        with:
          python-version: ${{ matrix.ver }}
      - name: Prepare Python ${{ matrix.ver }} environment
        run: |
          python -m pip install --upgrade pip
          python -m pip install --upgrade setuptools build wheel delocate
          python -m pip install --upgrade absl-py mypy
          python python/toolchains/generate.py
        shell: bash
      - name: Build wheel
        env:
          SOURCE_DATE_EPOCH: ${{ env.timestamp }}
        run: |
          python -m build --wheel
          python -m delocate.cmd.delocate_wheel --wheel-dir=. dist/*
        shell: bash
        working-directory: python
      - if: matrix.arch.name == runner.arch
        name: Test wheel
        run: |
          python -m pip install google_re2-*.whl
          # Pivot out of the repository so that we test the wheel.
          DIR=$(mktemp -d)
          cp re2_test.py "${DIR}"
          cd "${DIR}"
          python re2_test.py
        shell: bash
        working-directory: python
      - uses: actions/upload-artifact@v4.3.3
        with:
          name: ${{ hashFiles('python/google_re2-*.whl') }}
          path: python/google_re2-*.whl
          retention-days: 1
  wheel-windows:
    name: Windows, ${{ matrix.arch.name }}, Python ${{ matrix.ver }}
    runs-on: windows-latest
    strategy:
      fail-fast: false
      matrix:
        arch:
          - { name: X86, bazel-name: x64_x86, python-name: win32     }
          - { name: X64, bazel-name: x64,     python-name: win_amd64 }
        ver: ['3.8', '3.9', '3.10', '3.11', '3.12']
    env:
      BAZELISK_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      BAZEL_CPU: ${{ matrix.arch.bazel-name }}_windows
      PLAT_NAME: ${{ matrix.arch.python-name }}
    steps:
      - uses: actions/checkout@v4.1.7
      # Stash the timestamp for the commit SHA that triggered the workflow.
      - run: echo "timestamp=$(git log -1 --pretty=%ct)" >> "${GITHUB_ENV}"
        shell: bash
      - uses: bazel-contrib/setup-bazel@0.8.5
        with:
          bazelisk-version: '1.x'
      # Lowercase the architecture name for `actions/setup-python`.
      - run: |
          ARCHITECTURE=${{ matrix.arch.name }}
          echo "architecture=${ARCHITECTURE,,}" >> "${GITHUB_ENV}"
        shell: bash
      - uses: actions/setup-python@v5.1.0
        with:
          python-version: ${{ matrix.ver }}
          architecture: ${{ env.architecture }}
      - name: Prepare Python ${{ matrix.ver }} environment
        run: |
          python -m pip install --upgrade pip
          python -m pip install --upgrade setuptools build wheel delvewheel
          python -m pip install --upgrade absl-py mypy
          python python/toolchains/generate.py
        shell: bash
      - name: Build wheel
        env:
          SOURCE_DATE_EPOCH: ${{ env.timestamp }}
        run: |
          python -m build --wheel
          python -m delvewheel repair --wheel-dir=. dist/*
        shell: bash
        working-directory: python
      - name: Test wheel
        run: |
          python -m pip install google_re2-*.whl
          # Pivot out of the repository so that we test the wheel.
          DIR=$(mktemp -d)
          cp re2_test.py "${DIR}"
          cd "${DIR}"
          python re2_test.py
        shell: bash
        working-directory: python
      - uses: actions/upload-artifact@v4.3.3
        with:
          name: ${{ hashFiles('python/google_re2-*.whl') }}
          path: python/google_re2-*.whl
          retention-days: 1
  publish:
    needs:
      - wheel-linux
      - wheel-macos
      - wheel-windows
    permissions:
      contents: read
      # Required for PyPI publishing.
      id-token: write
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4.1.7
      # Stash the timestamp for the commit SHA that triggered the workflow.
      - run: echo "timestamp=$(git log -1 --pretty=%ct)" >> "${GITHUB_ENV}"
        shell: bash
      - uses: actions/setup-python@v5.1.0
        with:
          python-version: '3.x'
      - name: Prepare Python 3.x environment
        run: |
          python -m pip install --upgrade pip
          python -m pip install --upgrade setuptools build wheel
        shell: bash
      - if: inputs.build <= 1 || inputs.force-sdist == true
        name: Build sdist
        env:
          SOURCE_DATE_EPOCH: ${{ env.timestamp }}
        run: |
          python -m build --sdist
        shell: bash
        working-directory: python
      - uses: actions/download-artifact@v4.1.7
        with:
          path: python
      - name: Set build number to ${{ inputs.build }}
        env:
          SOURCE_DATE_EPOCH: ${{ env.timestamp }}
        run: |
          mkdir -p dist
          for WHL in */google_re2-*.whl; do
            python -m wheel unpack "${WHL}"
            python -m wheel pack --dest-dir=dist --build-number=${{ inputs.build }} google_re2-*
            rm -rf google_re2-*
          done
        shell: bash
        working-directory: python
      - if: inputs.build >= 1
        uses: pypa/gh-action-pypi-publish@v1.9.0
        with:
          packages-dir: python/dist
