name: Python-package

on:
  push:
    branches:
      - master
  pull_request:
    branches:
      - master

# automatically cancel in-progress builds if another commit is pushed
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

env:
  CMAKE_BUILD_PARALLEL_LEVEL: 4
  SKBUILD_STRICT_CONFIG: true

jobs:
  test-linux-aarch64:
    name: bdist wheel (ubuntu-24.04-arm)
    runs-on: ubuntu-24.04-arm
    timeout-minutes: 60
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 5
          submodules: true
      - name: Setup and run tests
        shell: bash
        # this uses 'docker run' instead of just setting 'container:'
        # because actions/checkout requires GLIBC 2.28 and that is too
        # new for manylinux2014
        env:
          BUILD_DIRECTORY: /LightGBM
        run: |
          cat > ./docker-script.sh <<EOF
          mkdir -p \$BUILD_ARTIFACTSTAGINGDIRECTORY
          export CONDA=\$HOME/miniforge
          export PATH=\$CONDA/bin:\$PATH
          ${{ env.BUILD_DIRECTORY }}/.ci/setup.sh || exit 1
          ${{ env.BUILD_DIRECTORY }}/.ci/test.sh || exit 1
          EOF
          IMAGE_URI="lightgbm/vsts-agent:manylinux2014_aarch64"
          docker pull "${IMAGE_URI}" || exit 1
          docker run \
            --platform "${PLATFORM}" \
            --rm \
            --env BUILD_DIRECTORY=${{ env.BUILD_DIRECTORY }} \
            --env BUILD_ARTIFACTSTAGINGDIRECTORY=${{ env.BUILD_DIRECTORY }}/artifacts/ \
            --env COMPILER=gcc \
            --env METHOD=wheel \
            --env OS_NAME=linux \
            --env PRODUCES_ARTIFACTS=true \
            --env PYTHON_VERSION="3.13" \
            --env TASK=bdist \
            -v "${PWD}":"${{ env.BUILD_DIRECTORY }}" \
            -w ${{ env.BUILD_DIRECTORY }} \
            "${IMAGE_URI}" \
            /bin/bash ./docker-script.sh
      - name: upload wheels
        uses: actions/upload-artifact@v4
        with:
          name: linux-aarch64-wheel
          path: artifacts/*.whl
  test-macos:
    name: ${{ matrix.task }} ${{ matrix.method }} (${{ matrix.os }}, Python ${{ matrix.python_version }})
    runs-on: ${{ matrix.os }}
    timeout-minutes: 60
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: macos-13
            task: regular
            python_version: '3.11'
          - os: macos-13
            task: sdist
            python_version: '3.12'
          - os: macos-13
            task: bdist
            python_version: '3.9'
          - os: macos-13
            task: if-else
            python_version: '3.10'
          - os: macos-14
            task: bdist
            method: wheel
            python_version: '3.11'
          - os: macos-13
            task: mpi
            method: source
            python_version: '3.12'
          - os: macos-13
            task: mpi
            method: pip
            python_version: '3.13'
          - os: macos-13
            task: mpi
            method: wheel
            python_version: '3.10'
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 5
          submodules: true
      - name: Setup and run tests
        shell: bash
        run: |
          export TASK="${{ matrix.task }}"
          export METHOD="${{ matrix.method }}"
          export OS_NAME="macos"
          export PYTHON_VERSION="${{ matrix.python_version }}"
          if [[ "${{ matrix.os }}" == "macos-14" ]]; then
              # use clang when creating macOS release artifacts
              export COMPILER="clang"
          else
              export COMPILER="gcc"
          fi
          export BUILD_DIRECTORY="$GITHUB_WORKSPACE"
          export CONDA=${HOME}/miniforge
          export PATH=${CONDA}/bin:${PATH}
          $GITHUB_WORKSPACE/.ci/setup.sh || exit 1
          $GITHUB_WORKSPACE/.ci/test.sh || exit 1
      - name: upload wheels
        if: ${{ matrix.method == 'wheel' && matrix.os == 'macos-14' }}
        uses: actions/upload-artifact@v4
        with:
          name: macosx-arm64-wheel
          path: dist/*.whl
  test-latest-versions:
    name: Python - latest versions (ubuntu-latest)
    runs-on: ubuntu-latest
    timeout-minutes: 60
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 5
          submodules: true
      - name: Create wheel
        run: |
          docker run \
            --rm \
            --env CMAKE_BUILD_PARALLEL_LEVEL=${{ env.CMAKE_BUILD_PARALLEL_LEVEL }} \
            -v $(pwd):/opt/lgb-build \
            -w /opt/lgb-build \
            lightgbm/vsts-agent:manylinux_2_28_x86_64 \
            /bin/bash -c 'PATH=/opt/miniforge/bin:$PATH sh ./build-python.sh bdist_wheel --nomp'
      - name: Test compatibility
        run: |
          docker run \
            --rm \
            -v $(pwd):/opt/lgb-build \
            -w /opt/lgb-build \
            python:3.13 \
            /bin/bash ./.ci/test-python-latest.sh
  test-old-versions:
    name: Python - oldest supported versions (ubuntu-latest)
    runs-on: ubuntu-latest
    timeout-minutes: 60
    strategy:
      fail-fast: false
      matrix:
        # end-of-life Python versions
        python_version:
          - '3.7'
          - '3.8'
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 5
          submodules: true
      - name: Create wheel
        run: |
          docker run \
            --rm \
            --env CMAKE_BUILD_PARALLEL_LEVEL=${{ env.CMAKE_BUILD_PARALLEL_LEVEL }} \
            -v $(pwd):/opt/lgb-build \
            -w /opt/lgb-build \
            lightgbm/vsts-agent:manylinux_2_28_x86_64 \
            /bin/bash -c 'PATH=/opt/miniforge/bin:$PATH sh ./build-python.sh bdist_wheel --nomp'
      - name: Test compatibility
        run: |
          docker run \
            --rm \
            -v $(pwd):/opt/lgb-build \
            -w /opt/lgb-build \
            python:${{ matrix.python_version }} \
            /bin/bash ./.ci/test-python-oldest.sh
  all-python-package-jobs-successful:
    if: always()
    runs-on: ubuntu-latest
    needs:
      - test-latest-versions
      - test-macos
      - test-linux-aarch64
      - test-old-versions
    steps:
      - name: Note that all tests succeeded
        uses: re-actors/alls-green@v1.2.2
        with:
          jobs: ${{ toJSON(needs) }}
