name: CI

on:
  pull_request:
  push:
    branches: [main]

jobs:

  mypy:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14']
    steps:
    - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
    - uses: ./.github/actions/setup
      with:
        python-version: ${{matrix.python-version}}
    - run: uvx hatch run +py=${{matrix.python-version}} types:check

  test:
    runs-on: ${{matrix.os}}
    strategy:
      matrix:
        python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', '3.13', '3.14', pypy3.9, pypy3.10]
        os: [ubuntu-latest, windows-latest, macos-13]
        extra_deps: ['"--with=pydantic<2"', '"--with=pydantic>2"']
        is_insider:
        - ${{contains(github.repository, '-insiders/')}}

        exclude:
        - is_insider: true
          os: windows-latest
        - is_insider: true
          os: macos-13

        - python-version: '3.14'
          extra_deps: '"--with=pydantic<2"'

        - os: macos-13
          python-version: '3.9'
        - os: macos-13
          python-version: '3.10'
        - os: macos-13
          python-version: '3.11'
        - os: macos-13
          python-version: '3.12'
        - os: macos-13
          python-version: '3.13'
        - os: macos-13
          python-version: pypy3.9
        - os: macos-13
          python-version: pypy3.10

        - os: windows-latest
          python-version: '3.9'
        - os: windows-latest
          python-version: '3.10'
        - os: windows-latest
          python-version: '3.11'
        - os: windows-latest
          python-version: '3.12'
        - os: windows-latest
          python-version: '3.13'
        - os: windows-latest
          python-version: pypy3.9
        - os: windows-latest
          python-version: pypy3.10

    env:
      TOP: ${{github.workspace}}
      COVERAGE_PROCESS_START: ${{github.workspace}}/pyproject.toml
    steps:
    - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
    - uses: ./.github/actions/setup
      with:
        python-version: ${{matrix.python-version}}

    - run: |
        uv run ${{matrix.extra_deps}} --extra black --extra dirty-equals -m ${{ matrix.os == 'ubuntu-latest' && 'coverage run -m' || '' }} pytest -n=auto -vv
    - run: |
        uv run -m coverage combine
        mv .coverage .coverage.${{ matrix.python-version }}-${{matrix.os}}-${{strategy.job-index}}
      if: matrix.os == 'ubuntu-latest'

    - name: Upload coverage data
      uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
      if: matrix.os == 'ubuntu-latest'
      with:
        name: coverage-data-${{github.run_id}}-${{ matrix.python-version }}-${{matrix.os}}-${{strategy.job-index}}
        path: .coverage.*
        include-hidden-files: true
        if-no-files-found: ignore

  coverage:
    name: Combine & check coverage
    env:
      TOP: ${{github.workspace}}
    if: always()
    needs: test
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
    - uses: ./.github/actions/setup

    - uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.1.9
      with:
        pattern: coverage-data-${{github.run_id}}-*
        merge-multiple: true

    - name: Combine coverage & fail if it's <100%
      run: |
        uv pip install --upgrade coverage[toml]

        coverage combine
        coverage html --skip-covered --skip-empty

        # Report and write to summary.
        coverage report --format=markdown >> $GITHUB_STEP_SUMMARY

        # Report again and fail if under 100%.
        coverage report --fail-under=100

    - name: Upload HTML report if check failed
      uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
      with:
        name: html-report
        path: htmlcov
      if: ${{ failure() }}


  publish:
    name: Publish new release
    runs-on: ubuntu-latest
    needs: [test, coverage]
    if: "!contains(github.repository, '-insiders/')"
    environment: pypi
    permissions:
      # IMPORTANT: this permission is mandatory for Trusted Publishing
      id-token: write
      # this permission is mandatory to create github releases
      contents: write

    steps:
    - name: Checkout main
      uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
      with:
        fetch-depth: 0
    - uses: ./.github/actions/setup

    - name: Check if the commit has a vx.y.z tag
      id: check-version
      run: |
        if git tag --list --points-at ${{ github.sha }} | grep -q -E '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
          echo "is new version"
          echo "should_continue=true" >> "$GITHUB_OUTPUT"
        else
          echo "is not a new version"
          echo "should_continue=false" >> "$GITHUB_OUTPUT"
        fi

    - run: uv pip install hatch scriv

    - name: build package
      run: hatch build

    - name: Publish package distributions to PyPI
      if: ${{ steps.check-version.outputs.should_continue == 'true' }}
      uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4

    - name: create github release
      if: ${{ steps.check-version.outputs.should_continue == 'true' }}
      env:
        GITHUB_TOKEN: ${{ github.token }}
      run: scriv github-release
