name: CI

on: [push, pull_request]

jobs:
  Pre-Commit:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: 3.9
    - name: Set Cache Key
      run: echo "PY=$(python --version --version | sha256sum | cut -d' ' -f1)" >> "$GITHUB_ENV"
    - name: Install System Deps
      run: |
        sudo apt-get update
        sudo apt-get install -y libxml2 libxml2-dev libxslt-dev
    - uses: actions/cache@v4
      with:
        path: ~/.cache/pre-commit
        key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }}
    - uses: pre-commit/action@v1.0.1

  Twine-Check:
    runs-on: ubuntu-latest
    needs: Pre-Commit

    steps:
    - uses: actions/checkout@v4
    - name: Setup Python
      uses: actions/setup-python@v5
      with:
        python-version: 3.9
    - name: Install Nox
      run: |
        python -m pip install --upgrade pip
        pip install nox
    - name: Twine check
      run: |
        nox -e twine-check


  PyLint:
    runs-on: ubuntu-latest
    needs: Pre-Commit

    timeout-minutes: 10

    steps:
    - uses: actions/checkout@v4

    - name: Set up Python 3.9 For Nox
      uses: actions/setup-python@v5
      with:
        python-version: 3.9

    - name: Install Nox
      run: |
        python -m pip install --upgrade pip
        pip install nox

    - name: Install Lint Requirements
      run: |
        nox --force-color -e lint --install-only

    - name: Build Docs
      env:
        SKIP_REQUIREMENTS_INSTALL: YES
      run: |
        nox --force-color -e lint

  Docs:
    runs-on: ubuntu-latest
    needs: Pre-Commit

    timeout-minutes: 10

    steps:
    - uses: actions/checkout@v4

    - name: Set up Python 3.9 For Nox
      uses: actions/setup-python@v5
      with:
        python-version: 3.9

    - name: Install Nox
      run: |
        python -m pip install --upgrade pip
        pip install nox

    - name: Install Doc Requirements
      run: |
        nox --force-color -e docs --install-only

    - name: Build Docs
      env:
        SKIP_REQUIREMENTS_INSTALL: YES
      run: |
        nox --force-color -e docs

  Linux:
    runs-on: ubuntu-latest
    needs: Pre-Commit

    timeout-minutes: 15

    strategy:
      fail-fast: false
      max-parallel: 15
      matrix:
        python-version:
          - "3.8"
          - "3.9"
          - "3.10"
          - "3.11"
        pytest-version:
          - "7.4.0"
          - "8.0.0"

    steps:
    - uses: actions/checkout@v4

    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python-version }}

    - name: Install Nox
      run: |
        python -m pip install --upgrade pip
        pip install nox

    - name: Install Test Requirements
      env:
        PYTEST_VERSION_REQUIREMENT: pytest~=${{ matrix.pytest-version }}
      run: |
        nox --force-color -e tests-3 --install-only

    - name: Test
      env:
        SKIP_REQUIREMENTS_INSTALL: YES
      run: |
        nox --force-color -e tests-3 -- -vv tests/

    - name: Upload Tests coverage to Codecov
      uses: codecov/codecov-action@v3
      with:
        token: ${{ secrets.CODECOV_TOKEN }}
        directory: artifacts/
        fail_ci_if_error: false
        files: coverage-tests.xml
        flags: tests,${{ runner.os }},Py${{ matrix.python-version}},PyTest${{ matrix.pytest-version }}
        name: tests-${{ runner.os }}-Py${{ matrix.python-version}}-PyTest${{ matrix.pytest-version }}
        verbose: true

    - name: Upload Project coverage to Codecov
      uses: codecov/codecov-action@v3
      with:
        token: ${{ secrets.CODECOV_TOKEN }}
        directory: artifacts/
        fail_ci_if_error: false
        files: coverage-project.xml
        flags: src,${{ runner.os }},Py${{ matrix.python-version}},PyTest${{ matrix.pytest-version }}
        name: src-${{ runner.os }}-Py${{ matrix.python-version}}-PyTest${{ matrix.pytest-version }}
        verbose: true

    - name: Upload Logs
      if: always()
      uses: actions/upload-artifact@v4
      with:
        name: runtests-${{ runner.os }}-Py${{ matrix.python-version}}-PyTest${{ matrix.pytest-version }}.log
        path: artifacts/runtests-*.log

  Windows:
    runs-on: windows-latest
    needs: Pre-Commit

    timeout-minutes: 40

    strategy:
      fail-fast: false
      max-parallel: 15
      matrix:
        python-version:
          - "3.8"
          - "3.9"
          - "3.10"
          - "3.11"
        pytest-version:
          - "7.4.0"
          - "8.0.0"

    steps:
    - uses: actions/checkout@v4

    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python-version }}

    - name: Install Nox
      run: |
        python -m pip install --upgrade pip
        pip install nox

    - name: Install Test Requirements
      shell: bash
      env:
        PYTEST_VERSION_REQUIREMENT: pytest~=${{ matrix.pytest-version }}
      run: |
        export PATH="/C/Program Files (x86)/Windows Kits/10/bin/10.0.18362.0/x64;$PATH"
        nox --force-color -e tests-3 --install-only

    - name: Test
      shell: bash
      env:
        SKIP_REQUIREMENTS_INSTALL: YES
      run: |
        export PATH="/C/Program Files (x86)/Windows Kits/10/bin/10.0.18362.0/x64;$PATH"
        nox --force-color -e tests-3 -- -vv tests/

    - name: Upload Tests coverage to Codecov
      uses: codecov/codecov-action@v3
      with:
        token: ${{ secrets.CODECOV_TOKEN }}
        directory: artifacts/
        fail_ci_if_error: false
        files: coverage-tests.xml
        flags: tests,${{ runner.os }},Py${{ matrix.python-version}},PyTest${{ matrix.pytest-version }}
        name: tests-${{ runner.os }}-Py${{ matrix.python-version}}-PyTest${{ matrix.pytest-version }}
        verbose: true

    - name: Upload Project coverage to Codecov
      uses: codecov/codecov-action@v3
      with:
        token: ${{ secrets.CODECOV_TOKEN }}
        directory: artifacts/
        fail_ci_if_error: false
        files: coverage-project.xml
        flags: src,${{ runner.os }},Py${{ matrix.python-version}},PyTest${{ matrix.pytest-version }}
        name: src-${{ runner.os }}-Py${{ matrix.python-version}}-PyTest${{ matrix.pytest-version }}
        verbose: true

    - name: Upload Logs
      if: always()
      uses: actions/upload-artifact@v4
      with:
        name: runtests-${{ runner.os }}-Py${{ matrix.python-version}}-PyTest${{ matrix.pytest-version }}.log
        path: artifacts/runtests-*.log

  macOS:
    runs-on: macOS-latest
    needs: Pre-Commit

    timeout-minutes: 40

    strategy:
      fail-fast: false
      max-parallel: 15
      matrix:
        python-version:
          - "3.8"
          - "3.9"
          - "3.10"
          - "3.11"
        pytest-version:
          - "7.4.0"
          - "8.0.0"

    steps:
    - uses: actions/checkout@v4

    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v5
      with:
        python-version: ${{ matrix.python-version }}

    - name: Install Nox
      run: |
        python -m pip install --upgrade pip
        pip install nox

    - name: Install Test Requirements
      env:
        PYTEST_VERSION_REQUIREMENT: pytest~=${{ matrix.pytest-version }}
      run: |
        nox --force-color -e tests-3 --install-only

    - name: Test
      env:
        SKIP_REQUIREMENTS_INSTALL: YES
      run: |
        nox --force-color -e tests-3 -- -vv tests/

    - name: Upload Tests coverage to Codecov
      uses: codecov/codecov-action@v3
      with:
        token: ${{ secrets.CODECOV_TOKEN }}
        directory: artifacts/
        fail_ci_if_error: false
        files: coverage-tests.xml
        flags: tests,${{ runner.os }},Py${{ matrix.python-version}},PyTest${{ matrix.pytest-version }}
        name: tests-${{ runner.os }}-Py${{ matrix.python-version}}-PyTest${{ matrix.pytest-version }}
        verbose: true

    - name: Upload Project coverage to Codecov
      uses: codecov/codecov-action@v3
      with:
        token: ${{ secrets.CODECOV_TOKEN }}
        directory: artifacts/
        fail_ci_if_error: false
        files: coverage-project.xml
        flags: src,${{ runner.os }},Py${{ matrix.python-version}},PyTest${{ matrix.pytest-version }}
        name: src-${{ runner.os }}-Py${{ matrix.python-version}}-PyTest${{ matrix.pytest-version }}
        verbose: true

    - name: Upload Logs
      if: always()
      uses: actions/upload-artifact@v4
      with:
        name: runtests-${{ runner.os }}-Py${{ matrix.python-version}}-PyTest${{ matrix.pytest-version }}.log
        path: artifacts/runtests-*.log


  Build:
    runs-on: ubuntu-latest
    environment: testing
    permissions:
      id-token: write
    needs:
      - Docs
      - PyLint
      - Twine-Check
      - Linux
      - Windows
      - macOS
    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0
    - name: Set up Python
      uses: actions/setup-python@v5
      with:
        python-version: 3.9
    - name: Install Nox
      run: |
        python -m pip install nox
    - name: Build a binary wheel and a source tarball
      run: |
        nox -e build

    - name: Publish distribution 📦 to Test PyPI
      if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
      uses: pypa/gh-action-pypi-publish@release/v1
      with:
        repository_url: https://test.pypi.org/legacy/
        print-hash: true
        skip-existing: true
        verbose: true
        verify-metadata: true
