# Try to get a short workflow name and a job name that start with Python
# version to make it easier to check the status inside GitHub UI.
name: CI

on:
  push:
    # Make sure to not enable `push` events for other branches as this will
    # trigger the publishing to gh-pages from any branch.
    # If you need to enable more branches look below and update
    # the conditions for which gh-pages are updated.
    branches: [ trunk ]
    tags:
      - incremental-*
  pull_request:
    branches: [ trunk ]


permissions:
  contents: read


defaults:
  run:
    shell: bash


jobs:
  build:
    runs-on: ubuntu-24.04

    steps:

    - uses: actions/checkout@v4

    - uses: ./.github/actions/build-dist

  testing:
    runs-on: ubuntu-24.04
    needs: [build]
    env:
      TOXENV: "${{ matrix.tox-env }}"
    name: ${{ matrix.python-version }}-${{ matrix.tox-env }}
    strategy:
      fail-fast: false
      matrix:
        # Run on the minimum micro Python version that we can get on CI.
        # When updating the minimum Python version here, also update the
        # `python_requires` from `setup.cfg`.
        # Run on latest minor release of each major python version.
        python-version: [3.8, 3.9, '3.10', '3.11', '3.12']
        tox-env: ['tests']

        include:
          # Run non-python version specific jobs.
          - python-version: 3.9
            tox-env: mypy,apidocs
            skip-coverage: true

    steps:
    - uses: actions/checkout@v4

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

    - uses: twisted/python-info-action@v1

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip tox

    - uses: actions/download-artifact@v4
      with:
        name: dist
        path: dist/

    - name: Run job via tox
      run: |
        export TOX_PARALLEL_NO_SPINNER=1
        export PIP_FIND_LINKS="$(realpath dist)"
        # GitHub Actions VM have 2 CPUs.
        tox --parallel 2 --installpkg dist/*.whl

    - name: Prepare GitHub Pages
      if: contains(matrix['tox-env'], 'apidocs')
      run: |
        mkdir website
        touch website/index.html
        mv apidocs website/docs

    - name: Publish documentation for push on trunk
      # Since we don't have a separate job for apidocs gh-pages updating
      # hijack the normal apidoc test and publish the resulting files.
      if: contains(matrix['tox-env'], 'apidocs') && github.event_name == 'push'
      uses: peaceiris/actions-gh-pages@v3
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        commit_message: Publish docs for ${{ github.sha }}
        publish_dir: ./website

    - name: Prepare coverage results
      if: ${{ !cancelled() && !matrix.skip-coverage }}
      run: |
        # Assign the coverage file a name unique to this job so that the
        # uploads don't collide.
        mv .coverage ".coverage-job-${{ matrix.python-version }}-${{ matrix.tox-env }}"

    - name: Store coverage file
      if: ${{ !cancelled() && !matrix.skip-coverage }}
      uses: actions/upload-artifact@v4
      with:
        name: coverage-${{ matrix.python-version }}-${{ matrix.tox-env }}
        path: .coverage-job-*

  coverage-report:
    name: Coverage report
    runs-on: ubuntu-latest
    # We want to always run the coverage, even when the
    # tests failed.
    if: always()
    needs:
      - testing  # Wait for test jobs.
    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        python -m pip install --upgrade coverage[toml] diff_cover

    - name: Download coverage reports
      uses: actions/download-artifact@v4
      with:
        pattern: coverage-*
        merge-multiple: true
        path: .

    - name: Prepare coverage
      run: |
          coverage combine .coverage-job-*
          # XML is needed for the diff-cover.
          coverage xml

    - name: Report coverage
      run: |
          # Report for the job log.
          coverage report --skip-covered --skip-empty >> $GITHUB_STEP_SUMMARY
          diff-cover --markdown-report coverage-report.md --compare-branch origin/trunk coverage.xml

    - name: Enforce diff coverage
      run: |
          diff-cover --fail-under=100 --compare-branch origin/trunk coverage.xml

    - name: Generate HTML report on failure
      if: ${{ failure() }}
      run: |
          coverage html --skip-covered --skip-empty

    - name: Upload HTML report on failure
      if: ${{ failure() }}
      uses: actions/upload-artifact@v3
      with:
        name: html-report
        path: htmlcov
