---
name: tox

on:
  create: # is used for publishing to PyPI and TestPyPI
    tags: # any tag regardless of its name, no branches
      - "**"
  push: # only publishes pushes to the main branch to TestPyPI
    branches: # any integration branch but not tag
      - "main"
  pull_request:
    branches:
      - "main"
  release:
    types:
      - published # It seems that you can publish directly without creating
  schedule:
    - cron: 1 0 * * * # Run daily at 0:01 UTC
  # Run every Friday at 18:02 UTC
  # https://crontab.guru/#2_18_*_*_5
  # - cron: 2 18 * * 5

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

env:
  FORCE_COLOR: 1 # tox, pytest, ansible-lint
  PY_COLORS: 1

jobs:
  pre:
    name: pre
    runs-on: ubuntu-22.04
    outputs:
      matrix: ${{ steps.generate_matrix.outputs.matrix }}
    steps:
      - name: Determine matrix
        id: generate_matrix
        uses: coactions/dynamic-matrix@v1
        with:
          min_python: "3.7"
          max_python: "3.12"
          other_names: |
            lint
            pkg,docs
          platforms: linux,macos

  build:
    name: ${{ matrix.name }}
    runs-on: ${{ matrix.os || 'ubuntu-22.04' }}
    needs: pre
    defaults:
      run:
        shell: ${{ matrix.shell || 'bash'}}
    strategy:
      fail-fast: false
      matrix: ${{ fromJson(needs.pre.outputs.matrix) }}

    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0 # needed by setuptools-scm

      - name: Set pre-commit cache
        uses: actions/cache@v4
        if: ${{ matrix.passed_name == 'lint' }}
        with:
          path: |
            ~/.cache/pre-commit
          key: pre-commit-${{ matrix.name || matrix.passed_name }}-${{ hashFiles('.pre-commit-config.yaml') }}

      - name: Set up Python ${{ matrix.python_version || '3.9' }}
        uses: actions/setup-python@v5
        with:
          cache: pip
          python-version: ${{ matrix.python_version || '3.9' }}

      - name: Install tox
        run: |
          python3 -m pip install --upgrade pip
          python3 -m pip install --upgrade "tox>=4.0.0"

      - name: Log installed dists
        run: python3 -m pip freeze --all

      - name: Initialize tox envs ${{ matrix.passed_name }}
        run: python3 -m tox --notest --skip-missing-interpreters false -vv -e ${{ matrix.passed_name }}
        timeout-minutes: 5 # average is under 1, but macos can be over 3

      # sequential run improves browsing experience (almost no speed impact)
      - name: tox -e ${{ matrix.passed_name }}
        run: python3 -m tox -e ${{ matrix.passed_name }}

      - name: Combine coverage data
        if: ${{ startsWith(matrix.passed_name, 'py') }}
        # produce a single .coverage file at repo root
        run: tox -e py

      - name: Upload coverage data
        if: ${{ startsWith(matrix.passed_name, 'py') }}
        uses: codecov/codecov-action@v4
        with:
          name: ${{ matrix.passed_name }}
          fail_ci_if_error: false # see https://github.com/codecov/codecov-action/issues/598
          token: ${{ secrets.CODECOV_TOKEN }}
          verbose: true # optional (default = false)

      - name: Archive logs
        uses: actions/upload-artifact@v4
        with:
          name: logs.zip
          path: .tox/**/log/
        # https://github.com/actions/upload-artifact/issues/123
        continue-on-error: true

      - name: Report failure if git reports dirty status
        run: |
          if [[ -n $(git status -s) ]]; then
            # shellcheck disable=SC2016
            echo -n '::error file=git-status::'
            printf '### Failed as git reported modified and/or untracked files\n```\n%s\n```\n' "$(git status -s)" | tee -a "$GITHUB_STEP_SUMMARY"
            exit 99
          fi
        # https://github.com/actions/toolkit/issues/193

  check: # This job does nothing and is only used for the branch protection
    if: always()
    permissions:
      pull-requests: write # allow codenotify to comment on pull-request

    needs:
      - build

    runs-on: ubuntu-latest

    steps:
      - name: Decide whether the needed jobs succeeded or failed
        uses: re-actors/alls-green@release/v1
        with:
          jobs: ${{ toJSON(needs) }}

      - name: Check out src from Git
        uses: actions/checkout@v4

      - name: Notify repository owners about lint change affecting them
        uses: sourcegraph/codenotify@v0.6.4
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        # https://github.com/sourcegraph/codenotify/issues/19
        continue-on-error: true
