# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0
# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt

name: "Coverage"

on:
  # As currently structured, this adds too many jobs (checks?), so don't run it
  # on pull requests yet.
  push:
    branches:
      - master
      - "**/*metacov*"
  workflow_dispatch:

defaults:
  run:
    shell: bash

env:
  PIP_DISABLE_PIP_VERSION_CHECK: 1
  FORCE_COLOR: 1    # Get colored pytest output

permissions:
  contents: read

concurrency:
  group: "${{ github.workflow }}-${{ github.ref }}"
  cancel-in-progress: true

jobs:
  coverage:
    name: "${{ matrix.python-version }} on ${{ matrix.os }}"
    runs-on: "${{ matrix.os }}-${{ matrix.os-version || 'latest' }}"
    timeout-minutes: 30
    env:
      MATRIX_ID: "${{ matrix.python-version }}.${{ matrix.os }}"

    strategy:
      matrix:
        os:
          - ubuntu
          - macos
          - windows
        python-version:
          # When changing this list, be sure to check the [gh] list in
          # tox.ini so that tox will run properly. PYVERSIONS
          # Available versions:
          # https://github.com/actions/python-versions/blob/main/versions-manifest.json
          - "3.9"
          - "3.10"
          - "3.11"
          - "3.12"
          - "3.13"
          - "3.14"
          - "pypy-3.9"
          - "pypy-3.10"
        exclude:
          # Mac PyPy always takes the longest, and doesn't add anything.
          - os: macos
            python-version: "pypy-3.9"
          - os: macos
            python-version: "pypy-3.10"
          # Windows pypy 3.9 and 3.10 get stuck with PyPy 7.3.15.  I hope to
          # unstick them, but I don't want that to block all other progress, so
          # skip them for now.
          - os: windows
            python-version: "pypy-3.9"
          - os: windows
            python-version: "pypy-3.10"
        # If we need to tweak the os version we can do it with an include like
        # this:
        #  include:
        #    - python-version: "3.8"
        #      os: "macos"
        #      os-version: "13"

      # If one job fails, stop the whole thing.
      fail-fast: true

    steps:
      - name: "Check out the repo"
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          persist-credentials: false

      - name: "Set up Python"
        uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
        with:
          python-version: "${{ matrix.python-version }}"
          allow-prereleases: true
          # At a certain point, installing dependencies failed on pypy 3.9 and
          # 3.10 on Windows.  Commenting out the cache here fixed it.  Someday
          # try using the cache again.
          #cache: pip
          #cache-dependency-path: 'requirements/*.pip'

      - name: "Show environment"
        run: |
          set -xe
          python -VV
          python -m site
          env

      - name: "Install dependencies"
        run: |
          echo matrix id: $MATRIX_ID
          set -xe
          python -VV
          python -m site
          python -m pip install -r requirements/tox.pip

      - name: "Run tox coverage for ${{ matrix.python-version }}"
        env:
          COVERAGE_COVERAGE: "yes"
          COVERAGE_CONTEXT: "${{ matrix.python-version }}.${{ matrix.os }}"
        run: |
          set -xe
          python -m tox

      - name: "Combine data"
        env:
          COVERAGE_RCFILE: "metacov.ini"
        run: |
          python -m coverage combine
          mv .metacov .metacov.$MATRIX_ID

      - name: "Upload coverage data"
        uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
        with:
          name: metacov-${{ env.MATRIX_ID }}
          path: .metacov.*
          include-hidden-files: true

  combine:
    name: "Combine coverage data"
    needs: coverage
    runs-on: ubuntu-latest
    outputs:
      total: ${{ steps.total.outputs.total }}
    env:
      COVERAGE_RCFILE: "metacov.ini"

    steps:
      - name: "Check out the repo"
        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
        with:
          persist-credentials: false

      - name: "Set up Python"
        uses: actions/setup-python@42375524e23c412d93fb67b49958b491fce71c38 # v5.4.0
        with:
          python-version: "3.9" # Minimum of PYVERSIONS
          # At a certain point, installing dependencies failed on pypy 3.9 and
          # 3.10 on Windows.  Commenting out the cache here fixed it.  Someday
          # try using the cache again.
          #cache: pip
          #cache-dependency-path: 'requirements/*.pip'

      - name: "Show environment"
        run: |
          set -xe
          python -VV
          python -m site
          env | sort

      - name: "Install dependencies"
        run: |
          set -xe
          python -m pip install -e .
          python igor.py zip_mods

      - name: "Download coverage data"
        uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.1.9
        with:
          pattern: metacov-*
          merge-multiple: true

      - name: "Combine and report"
        id: combine
        env:
          COVERAGE_CONTEXT: "yes"
        run: |
          set -xe
          python igor.py combine_html

      - name: "Upload HTML report"
        uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
        with:
          name: html_report
          path: htmlcov
          include-hidden-files: true

      - name: "Get total"
        id: total
        run: |
          echo "total=$(python -m coverage report --format=total)" >> $GITHUB_OUTPUT

  publish:
    name: "Publish coverage report"
    needs: combine
    runs-on: ubuntu-latest

    steps:
      - name: "Show environment"
        run: |
          set -xe
          env | sort

      - name: "Compute info for later steps"
        id: info
        env:
          REF: ${{ github.ref }}
        run: |
          export SHA10=$(echo ${{ github.sha }} | cut -c 1-10)
          export SLUG=$(date +'%Y%m%d')_$SHA10
          echo "sha10=$SHA10" >> $GITHUB_ENV
          echo "slug=$SLUG" >> $GITHUB_ENV
          echo "report_dir=reports/$SLUG/htmlcov" >> $GITHUB_ENV
          echo "url=https://htmlpreview.github.io/?https://github.com/nedbat/coverage-reports/blob/main/reports/$SLUG/htmlcov/index.html" >> $GITHUB_ENV
          echo "branch=${REF#refs/heads/}" >> $GITHUB_ENV

      - name: "Summarize"
        env:
          TOTAL: ${{ needs.combine.outputs.total }}
        run: |
          echo "### TOTAL coverage: ${TOTAL}%" >> $GITHUB_STEP_SUMMARY

      - name: "Checkout reports repo"
        if: ${{ github.ref == 'refs/heads/master' }}
        run: |
          set -xe
          git clone --depth=1 --no-checkout https://${{ secrets.COVERAGE_REPORTS_TOKEN }}@github.com/nedbat/coverage-reports reports_repo
          cd reports_repo
          git sparse-checkout init --cone
          git sparse-checkout set --skip-checks '/*' '!/reports'
          git config user.name nedbat
          git config user.email ned@nedbatchelder.com
          git checkout main

      - name: "Download coverage HTML report"
        if: ${{ github.ref == 'refs/heads/master' }}
        uses: actions/download-artifact@cc203385981b70ca67e1cc392babf9cc229d5806 # v4.1.9
        with:
          name: html_report
          path: reports_repo/${{ env.report_dir }}

      - name: "Push to report repo"
        if: |
          github.repository_owner == 'nedbat'
          && github.ref == 'refs/heads/master'
        env:
          COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
          TOTAL: ${{ needs.combine.outputs.total }}
        run: |
          set -xe
          # Make the redirect to the latest report.
          echo "<html><head>" > reports_repo/latest.html
          echo "<meta http-equiv='refresh' content='0;url=${url}' />" >> reports_repo/latest.html
          echo "<body>Coverage report redirect..." >> reports_repo/latest.html
          # Make the commit message.
          echo "${TOTAL}% - ${COMMIT_MESSAGE}" > commit.txt
          echo "" >> commit.txt
          echo "${url}" >> commit.txt
          echo "${sha10}: ${branch}" >> commit.txt
          # Commit.
          cd ./reports_repo
          git sparse-checkout set --skip-checks '/*' ${report_dir}
          rm ${report_dir}/.gitignore
          git add ${report_dir} latest.html
          git commit --file=../commit.txt
          git push
          echo "[${url}](${url})" >> $GITHUB_STEP_SUMMARY

      - name: "Create badge"
        if: |
          github.repository_owner == 'nedbat'
          && github.ref == 'refs/heads/master'
        # https://gist.githubusercontent.com/nedbat/8c6980f77988a327348f9b02bbaf67f5
        uses: schneegans/dynamic-badges-action@e9a478b16159b4d31420099ba146cdc50f134483 # v1.7.0
        with:
          auth: ${{ secrets.METACOV_GIST_SECRET }}
          gistID: 8c6980f77988a327348f9b02bbaf67f5
          filename: metacov.json
          label: Coverage
          message: ${{ needs.combine.outputs.total }}%
          minColorRange: 60
          maxColorRange: 95
          valColorRange: ${{ needs.combine.outputs.total }}
