name: Tests

on:
  push:
    branches:
      - main
      - "maintenance/**"
    paths-ignore:
      - doc/data/messages/**
  pull_request:
    branches:
      - main
      - "maintenance/**"

env:
  CACHE_VERSION: 4
  KEY_PREFIX: venv

permissions:
  contents: read

concurrency:
  group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs:
  tests-linux:
    name: run / ${{ matrix.python-version }} / Linux
    runs-on: ubuntu-latest
    timeout-minutes: 25
    strategy:
      fail-fast: false
      matrix:
        python-version: [3.9, "3.10", "3.11", "3.12", "3.13"]
    outputs:
      python-key: ${{ steps.generate-python-key.outputs.key }}
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python ${{ matrix.python-version }}
        id: python
        uses: actions/setup-python@v5.2.0
        with:
          python-version: ${{ matrix.python-version }}
          check-latest: true
      - name: Generate partial Python venv restore key
        id: generate-python-key
        run: >-
          echo "key=${{ env.KEY_PREFIX }}-${{ env.CACHE_VERSION }}-${{
            hashFiles('pyproject.toml', 'requirements_test.txt',
          'requirements_test_min.txt', 'requirements_test_pre_commit.txt') }}" >>
          $GITHUB_OUTPUT
      - name: Restore Python virtual environment
        id: cache-venv
        uses: actions/cache@v4.2.0
        with:
          path: venv
          key: >-
            ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
            steps.generate-python-key.outputs.key }}
      - name: Create Python virtual environment
        if: steps.cache-venv.outputs.cache-hit != 'true'
        run: |
          python -m venv venv
          . venv/bin/activate
          python -m pip install -U pip setuptools wheel
          pip install -U -r requirements_test.txt
      - name: Run pytest
        run: |
          . venv/bin/activate
          pip list | grep 'astroid\|pylint'
          python -m pytest --durations=10 --benchmark-disable --cov --cov-report= tests/
      - name: Run functional tests with minimal messages config
        run: |
          . venv/bin/activate
          pip list | grep 'astroid\|pylint'
          python -m pytest -vv --minimal-messages-config tests/test_functional.py
      - name: Upload coverage artifact
        uses: actions/upload-artifact@v4.4.0
        with:
          name: coverage-${{ matrix.python-version }}
          include-hidden-files: true
          path: .coverage

  coverage:
    name: process / coverage
    runs-on: ubuntu-latest
    timeout-minutes: 5
    needs: tests-linux
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python 3.12
        id: python
        uses: actions/setup-python@v5.2.0
        with:
          python-version: "3.13"
          check-latest: true
      - name: Restore Python virtual environment
        id: cache-venv
        uses: actions/cache@v4.2.0
        with:
          path: venv
          fail-on-cache-miss: true
          key:
            ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
            needs.tests-linux.outputs.python-key }}
      - name: Download all coverage artifacts
        uses: actions/download-artifact@v4.1.8
      - name: Combine coverage results
        run: |
          . venv/bin/activate
          coverage combine coverage*/.coverage
          coverage xml
      - uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          fail_ci_if_error: true
          verbose: true

  benchmark-linux:
    name: run benchmark / ${{ matrix.python-version }} / Linux
    runs-on: ubuntu-latest
    timeout-minutes: 10
    needs: tests-linux
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.13"]
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python ${{ matrix.python-version }}
        id: python
        uses: actions/setup-python@v5.2.0
        with:
          python-version: ${{ matrix.python-version }}
          check-latest: true
      - name: Restore Python virtual environment
        id: cache-venv
        uses: actions/cache@v4.2.0
        with:
          path: venv
          fail-on-cache-miss: true
          key:
            ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
            needs.tests-linux.outputs.python-key }}
      - name: Run pytest
        run: |
          . venv/bin/activate
          pip install pygal
          pip install .
          pip list | grep 'astroid\|pylint'
          pytest --exitfirst \
            --benchmark-only \
            --benchmark-autosave \
            --benchmark-save-data \
            --benchmark-group-by="group"
      - name: Create partial artifact name suffix
        id: artifact-name-suffix
        run: >-
          echo "datetime="$(date "+%Y%m%d_%H%M") >> $GITHUB_OUTPUT
      - name: Upload benchmark artifact
        uses: actions/upload-artifact@v4.4.0
        with:
          name:
            benchmark-${{ runner.os }}-${{ matrix.python-version }}_${{
            steps.artifact-name-suffix.outputs.datetime }}
          include-hidden-files: true
          path: .benchmarks/

  tests-windows:
    name: run / ${{ matrix.python-version }} / Windows
    runs-on: windows-latest
    timeout-minutes: 25
    needs: tests-linux
    strategy:
      fail-fast: false
      matrix:
        python-version: [3.9, "3.10", "3.11", "3.12", "3.13"]
    steps:
      - name: Set temp directory
        run: echo "TEMP=$env:USERPROFILE\AppData\Local\Temp" >> $env:GITHUB_ENV
        # Workaround to set correct temp directory on Windows
        # https://github.com/actions/virtual-environments/issues/712
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python ${{ matrix.python-version }}
        id: python
        uses: actions/setup-python@v5.2.0
        with:
          python-version: ${{ matrix.python-version }}
          check-latest: true
      - name: Generate partial Python venv restore key
        id: generate-python-key
        run: >-
          echo "key=venv-${{ env.CACHE_VERSION }}-${{
            hashFiles('pyproject.toml', 'requirements_test_min.txt')
          }}" >> $env:GITHUB_OUTPUT
      - name: Restore Python virtual environment
        id: cache-venv
        uses: actions/cache@v4.2.0
        with:
          path: venv
          key: >-
            ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
            steps.generate-python-key.outputs.key }}
      - name: Create Python virtual environment
        if: steps.cache-venv.outputs.cache-hit != 'true'
        run: |
          python -m venv venv
          . venv\\Scripts\\activate
          python -m pip install -U pip setuptools wheel
          pip install -U -r requirements_test_min.txt
      - name: Run pytest
        run: |
          . venv\\Scripts\\activate
          pip list | grep 'astroid\|pylint'
          python -m pytest --durations=10 --benchmark-disable tests/

  tests-macos:
    name: run / ${{ matrix.python-version }} / macOS
    runs-on: macos-latest
    timeout-minutes: 25
    needs: tests-linux
    strategy:
      fail-fast: false
      matrix:
        # We only run on the oldest supported version on Mac
        python-version: [3.9]
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python ${{ matrix.python-version }}
        id: python
        uses: actions/setup-python@v5.2.0
        with:
          python-version: ${{ matrix.python-version }}
          check-latest: true
      - name: Generate partial Python venv restore key
        id: generate-python-key
        run: >-
          echo "key=venv-${{ env.CACHE_VERSION }}-${{
            hashFiles('pyproject.toml', 'requirements_test_min.txt')
          }}" >> $GITHUB_OUTPUT
      - name: Restore Python virtual environment
        id: cache-venv
        uses: actions/cache@v4.2.0
        with:
          path: venv
          key: >-
            ${{ runner.os }}-${{ steps.python.outputs.python-version }}-${{
            steps.generate-python-key.outputs.key }}
      - name: Create Python virtual environment
        if: steps.cache-venv.outputs.cache-hit != 'true'
        run: |
          python -m venv venv
          . venv/bin/activate
          python -m pip install -U pip setuptools wheel
          pip install -U -r requirements_test_min.txt
      - name: Run pytest
        run: |
          . venv/bin/activate
          pip list | grep 'astroid\|pylint'
          python -m pytest --durations=10 --benchmark-disable tests/

  tests-pypy:
    name: run / ${{ matrix.python-version }} / Linux
    runs-on: ubuntu-latest
    timeout-minutes: 25
    strategy:
      fail-fast: false
      matrix:
        python-version: ["pypy-3.9", "pypy-3.10"]
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python ${{ matrix.python-version }}
        id: python
        uses: actions/setup-python@v5.2.0
        with:
          python-version: ${{ matrix.python-version }}
          check-latest: true
      - name: Generate partial Python venv restore key
        id: generate-python-key
        run: >-
          echo "key=venv-${{ env.CACHE_VERSION }}-${{
            hashFiles('pyproject.toml', 'requirements_test_min.txt')
          }}" >> $GITHUB_OUTPUT
      - name: Restore Python virtual environment
        id: cache-venv
        uses: actions/cache@v4.2.0
        with:
          path: venv
          key: >-
            ${{ runner.os }}-${{ matrix.python-version }}-${{
            steps.generate-python-key.outputs.key }}
      - name: Create Python virtual environment
        if: steps.cache-venv.outputs.cache-hit != 'true'
        run: |
          python -m venv venv
          . venv/bin/activate
          python -m pip install -U pip setuptools wheel
          pip install -U -r requirements_test_min.txt
      - name: Run pytest
        run: |
          . venv/bin/activate
          pip list | grep 'astroid\|pylint'
          python -m pytest --durations=10 --benchmark-disable tests/
