---
name: CI

on:
  push:
    branches: [main]
  pull_request:
  workflow_dispatch:

env:
  FORCE_COLOR: "1" # Make tools pretty.
  PIP_DISABLE_PIP_VERSION_CHECK: "1"
  PIP_NO_PYTHON_VERSION_WARNING: "1"

permissions: {}


jobs:
  lint:
    name: Run pre-commit
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version-file: .python-version-default

      - uses: tox-dev/action-pre-commit-uv@41a04ab74d5ec7ca33c8db8a59b6e3291d576033 # v1.0.4


  build-package:
    name: Build & verify package
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          fetch-depth: 0
          persist-credentials: false

      - uses: hynek/build-and-inspect-python-package@d44ca7d91762de7a7d5436ddae667c6da6d1c3df # v2.18.0
        id: baipp

    outputs:
      # Used to define the matrix for tests below. The value is based on
      # packaging metadata (trove classifiers).
      python-versions: ${{ steps.baipp.outputs.supported_python_classifiers_json_array }}


  tests:
    name: Tests & Mypy API on ${{ matrix.python-version }}
    runs-on: ubuntu-latest
    needs: build-package

    strategy:
      fail-fast: false
      matrix:
        # Created by the build-and-inspect-python-package action above.
        python-version: ${{ fromJson(needs.build-package.outputs.python-versions) }}

    env:
      PYTHON: ${{ matrix.python-version }}

    steps:
      - name: Download pre-built packages
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          name: Packages
          path: dist
      - run: |
          tar xf dist/*.tar.gz --strip-components=1
          rm -rf src
      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version: ${{ matrix.python-version }}
          allow-prereleases: true
      - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0

      - name: Run tests
        run: >
          uvx --with tox-uv tox run
          --installpkg dist/*.whl
          -f py${PYTHON//./}

      - name: Upload coverage data
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: coverage-data-${{ matrix.python-version }}
          path: .coverage.*
          include-hidden-files: true
          if-no-files-found: ignore

      - name: Check public API with Mypy
        run: >
          uvx --with tox-uv tox run
          --installpkg dist/*.whl
          -e mypy-api


  coverage:
    name: Ensure 100% test coverage
    runs-on: ubuntu-latest
    needs: tests
    if: always()

    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version-file: .python-version-default
      - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0

      - name: Download coverage data
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          pattern: coverage-data-*
          merge-multiple: true

      - name: Combine coverage and fail if it's <100%.
        run: |
          uv tool install coverage

          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@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: html-report
          path: htmlcov
        if: ${{ failure() }}


  mypy-pkg:
    name: Mypy Codebase
    runs-on: ubuntu-latest
    needs: build-package

    steps:
      - name: Download pre-built packages
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          name: Packages
          path: dist
      - run: tar xf dist/*.tar.gz --strip-components=1
      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version-file: .python-version-default
      - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0

      - run: >
          uvx --with tox-uv
          tox run -e mypy-pkg


  install-dev:
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest]

    name: Verify dev env
    runs-on: ${{ matrix.os }}

    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          persist-credentials: false
      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          python-version-file: .python-version-default

      - name: Install in dev mode & import
        run: |
          python -Im pip install --group dev -e .
          python -Ic 'import service_identity; print(service_identity.__version__)'
          python -Ic 'import service_identity.pyopenssl'
          python -Ic 'import service_identity.cryptography'


  docs:
    name: Build docs & run doctests
    needs: build-package
    runs-on: ubuntu-latest

    steps:
      - name: Download pre-built packages
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          name: Packages
          path: dist
      - run: tar xf dist/*.tar.gz --strip-components=1
      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
        with:
          # Keep in sync with tox.ini/docs & .readthedocs.yaml
          python-version: "3.14"
      - uses: hynek/setup-cached-uv@4300ec2180bc77d705e626a34e381b81a4772c51 # v2.5.0

      - run: >
          uvx --with tox-uv
          tox run -e docs-build,docs-doctests


  required-checks-pass:
    name: Ensure everything required is passing for branch protection
    if: always()

    needs:
      - coverage
      - lint
      - mypy-pkg
      - docs
      - install-dev

    runs-on: ubuntu-latest

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