name: Lint check
run-name: Lint code
on:
  pull_request:
  push:
    branches:
      - master

concurrency:
  # Cancel previous workflow run when a new commit is pushed to a feature branch
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

env:
  PYTHON_VERSION: "3.10"

jobs:
  changed-files:
    runs-on: ubuntu-latest
    name: Get changed files
    outputs:
      any_docs_changed: ${{ steps.changed-doc-files.outputs.any_changed }}
      any_python_changed: ${{ steps.raw-changed-python-files.outputs.any_changed }}
      changed_doc_files: ${{ steps.changed-doc-files.outputs.all_changed_files }}
      changed_python_files: ${{ steps.changed-python-files.outputs.all_changed_files }}
    steps:
      - uses: actions/checkout@v5
      - name: Get changed docs files
        id: changed-doc-files
        uses: tj-actions/changed-files@v46
        with:
          files: |
            docs/**
      - name: Get changed python files
        id: raw-changed-python-files
        uses: tj-actions/changed-files@v46
        with:
          files: |
            **.py
            poetry.lock

      - name: Check changed python files
        id: changed-python-files
        env:
          CHANGED_PYTHON_FILES: ${{ steps.raw-changed-python-files.outputs.all_changed_files }}
        run: |
          if [[ " $CHANGED_PYTHON_FILES " == *" poetry.lock "* ]]; then
            # if poetry.lock is changed, we need to check everything
            CHANGED_PYTHON_FILES="."
          fi
          echo "all_changed_files=$CHANGED_PYTHON_FILES" >> "$GITHUB_OUTPUT"

  format:
    if: needs.changed-files.outputs.any_python_changed == 'true'
    runs-on: ubuntu-latest
    name: Check formatting
    needs: changed-files
    steps:
      - uses: actions/checkout@v5
      - name: Install Python tools
        uses: BrandonLWhite/pipx-install-action@v1.0.3
      - uses: actions/setup-python@v6
        with:
          python-version: ${{ env.PYTHON_VERSION }}
          cache: poetry

      - name: Install dependencies
        run: poetry install --only=lint

      - name: Check code formatting
        # the job output will contain colored diffs with what needs adjusting
        run: poe check-format

  lint:
    if: needs.changed-files.outputs.any_python_changed == 'true'
    runs-on: ubuntu-latest
    name: Check linting
    needs: changed-files
    steps:
      - uses: actions/checkout@v5
      - name: Install Python tools
        uses: BrandonLWhite/pipx-install-action@v1.0.3
      - uses: actions/setup-python@v6
        with:
          python-version: ${{ env.PYTHON_VERSION }}
          cache: poetry

      - name: Install dependencies
        run: poetry install --only=lint

      - name: Lint code
        run: poe lint --output-format=github ${{ needs.changed-files.outputs.changed_python_files }}

  mypy:
    if: needs.changed-files.outputs.any_python_changed == 'true'
    runs-on: ubuntu-latest
    name: Check types with mypy
    needs: changed-files
    steps:
      - uses: actions/checkout@v5
      - name: Install Python tools
        uses: BrandonLWhite/pipx-install-action@v1.0.3
      - uses: actions/setup-python@v6
        with:
          python-version: ${{ env.PYTHON_VERSION }}
          cache: poetry

      - name: Install dependencies
        run: poetry install --only=typing

      - name: Type check code
        uses: liskin/gh-problem-matcher-wrap@v3
        with:
          linters: mypy
          run: poe check-types --show-column-numbers --no-error-summary .

  docs:
    if: needs.changed-files.outputs.any_docs_changed == 'true'
    runs-on: ubuntu-latest
    name: Check docs
    needs: changed-files
    steps:
      - uses: actions/checkout@v5
        with:
          fetch-depth: 0 # needed to get the full git history for the changelog check
      - name: Install Python tools
        uses: BrandonLWhite/pipx-install-action@v1.0.3
      - uses: actions/setup-python@v6
        with:
          python-version: ${{ env.PYTHON_VERSION }}
          cache: poetry

      - name: Install dependencies
        run: poetry install --extras=docs

      - name: Add Sphinx problem matchers
        run: |
          echo "::add-matcher::.github/problem-matchers/sphinx-build.json"
          echo "::add-matcher::.github/problem-matchers/sphinx-lint.json"

      - name: Check docs formatting
        run: poe format-docs --check

      - name: Lint docs
        run: poe lint-docs

      - name: Check changelog entries are added under Unreleased section
        run: |
          git diff --word-diff=plain -U1000 origin/${{ github.base_ref }} -- docs/changelog.rst | awk '
            # match the new version header
            /^[0-9]+\.[0-9]+\.[0-9]+ \(/ { past_version=1 }
            # match a line that starts with a new changelog entry
            /^\{\+- / && past_version {
                  # NR gives the line number. Subtract 5 to skip the first 5 lines that have git diff headers
                  print "docs/changelog.rst:" NR - 5 ": Changelog entry must be added under Unreleased section above. (changelog-unreleased)"; exit 1
                }
          '

      - name: Build docs
        run: poe docs -- -e 'SPHINXOPTS=--fail-on-warning --keep-going'
