name: Checks

on:
  push:
    branches:
      - main
      - "maintenance/**"
  pull_request:
    branches:
      - main
      - "maintenance/**"

env:
  CACHE_VERSION: 2
  KEY_PREFIX: base-venv
  DEFAULT_PYTHON: "3.13"
  PRE_COMMIT_CACHE: ~/.cache/pre-commit

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

permissions:
  contents: read

jobs:
  prepare-base:
    name: Prepare base dependencies
    runs-on: ubuntu-latest
    timeout-minutes: 10
    outputs:
      python-key: ${{ steps.generate-python-key.outputs.key }}
      pre-commit-key: ${{ steps.generate-pre-commit-key.outputs.key }}
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python ${{ env.DEFAULT_PYTHON }}
        id: python
        uses: actions/setup-python@v5.2.0
        with:
          python-version: ${{ env.DEFAULT_PYTHON }}
          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
          pip install -U -r doc/requirements.txt
          pip install pre-commit
      - name: Generate pre-commit restore key
        id: generate-pre-commit-key
        run: >-
          echo "key=pre-commit-${{ env.CACHE_VERSION }}-${{
            hashFiles('.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT
      - name: Restore pre-commit environment
        id: cache-precommit
        uses: actions/cache@v4.2.0
        with:
          path: ${{ env.PRE_COMMIT_CACHE }}
          key: >-
            ${{ runner.os }}-${{ steps.generate-pre-commit-key.outputs.key }}
      - name: Install pre-commit dependencies
        if: steps.cache-precommit.outputs.cache-hit != 'true'
        run: |
          . venv/bin/activate
          pre-commit install --install-hooks

  pylint:
    name: pylint
    runs-on: ubuntu-latest
    timeout-minutes: 10
    needs: prepare-base
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python ${{ env.DEFAULT_PYTHON }}
        id: python
        uses: actions/setup-python@v5.2.0
        with:
          python-version: ${{ env.DEFAULT_PYTHON }}
          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.prepare-base.outputs.python-key }}
      - name: Restore pre-commit environment
        id: cache-precommit
        uses: actions/cache@v4.2.0
        with:
          path: ${{ env.PRE_COMMIT_CACHE }}
          fail-on-cache-miss: true
          key: ${{ runner.os }}-${{ needs.prepare-base.outputs.pre-commit-key }}
      - name: Install enchant and aspell
        run: |
          sudo apt-get update
          sudo apt-get install enchant-2 aspell-en
      - name: Run pylint checks
        run: |
          . venv/bin/activate
          pip install .
          pip list | grep 'astroid\|pylint'
          pre-commit run --hook-stage manual pylint-with-spelling --all-files

  spelling:
    name: spelling tests
    runs-on: ubuntu-latest
    timeout-minutes: 5
    needs: prepare-base
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python ${{ env.DEFAULT_PYTHON }}
        id: python
        uses: actions/setup-python@v5.2.0
        with:
          python-version: ${{ env.DEFAULT_PYTHON }}
          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.prepare-base.outputs.python-key }}
      - name: Run spelling checks
        run: |
          . venv/bin/activate
          pytest tests/ -k unittest_spelling

  documentation:
    name: documentation
    runs-on: ubuntu-latest
    timeout-minutes: 20
    needs: prepare-base
    steps:
      - name: Check out code from GitHub
        uses: actions/checkout@v4.1.7
      - name: Set up Python ${{ env.DEFAULT_PYTHON }}
        id: python
        uses: actions/setup-python@v5.2.0
        with:
          python-version: ${{ env.DEFAULT_PYTHON }}
          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.prepare-base.outputs.python-key }}
      - name: Run checks on documentation code examples
        run: |
          . venv/bin/activate
          tox -e test_doc
      - name: Check documentation build and links
        run: |
          . venv/bin/activate
          cd doc
          pre-commit run --hook-stage push sphinx-generated-doc --all-files || {
            echo "git diff:" ; \
            git diff ; \
            echo "End of 'git diff'" ; \
            echo "Make sure that 'make html' succeed without any modifications locally." ; \
            exit 1; \
          }
