# internal coverage with PR comment and badge v0.0.5
# Note this works for public orgs but only for "internal" pull
# requests. In the case of fork PRs, there needs to be org-level
# github app with private key => ACCESS_TOKEN, with more job isolation
# and output passing in this workflow.
#
# This version has updated actions and coverage value regex, no fork isolation
# yet. This version checks for both repo owner and author_association = MEMBER
# so PR comments *should* be more available.
name: Coverage

on:
  workflow_dispatch:
  pull_request:
  push:
    branches:
      - master

jobs:
  pre_ci:
    name: Prepare CI environment
    runs-on: ubuntu-20.04
    outputs:
      #commit_message: ${{ steps.get_commit_message.outputs.commit_message }}
      branch: ${{ steps.extract_branch.outputs.branch }}

    steps:
    - name: Checkout Project
      uses: actions/checkout@v3
      with:
        # We need to fetch with a depth of 2 for pull_request so we can do HEAD^2
        fetch-depth: 2

    - name: Environment
      run: |
        bash -c set

    #- name: "Get commit message"
      #id: get_commit_message
      #env:
        #COMMIT_PUSH: ${{ github.event.head_commit.message }}
      #run: |
        #COMMIT_MESSAGE="${COMMIT_PUSH:-$(git log --format=%B -n 1 HEAD^2)}"
        #echo "commit_message=${COMMIT_MESSAGE}" >> $GITHUB_OUTPUT

    - name: Extract branch name
      id: extract_branch
      shell: bash
      run: |
        TMP_PULL_HEAD_REF="${{ github.head_ref }}"
        TMP_GITHUB_REF="${GITHUB_REF#refs/heads/}"
        EXPORT_VALUE=""
        if [ "${TMP_PULL_HEAD_REF}" != "" ]
        then
            EXPORT_VALUE="${TMP_PULL_HEAD_REF}"
        else
            EXPORT_VALUE="${TMP_GITHUB_REF}"
        fi
        echo "branch=${EXPORT_VALUE}" >> $GITHUB_OUTPUT

  base:
    name: Base coverage
    runs-on: ubuntu-20.04
    outputs:
      base_branch: ${{ steps.get_base.outputs.base_branch }}
      base_cov: ${{ steps.get_base.outputs.base_cov }}

    steps:
    - uses: actions/checkout@v3
      with:
        ref: badges
        path: badges

    - name: Get base ref and coverage score
      id: get_base
      env:
        FILE: 'test-coverage.txt'
      working-directory: ./badges
      shell: bash
      run: |
        TMP_PULL_BASE_REF="${{ github.base_ref }}"
        TMP_GITHUB_REF="${GITHUB_REF#refs/heads/}"
        EXPORT_VALUE=""
        if [ "${TMP_PULL_BASE_REF}" != "" ]
        then
            EXPORT_VALUE="${TMP_PULL_BASE_REF}"
        else
            EXPORT_VALUE="${TMP_GITHUB_REF}"
        fi
        echo "base_branch=${EXPORT_VALUE}" >> $GITHUB_OUTPUT
        if [ -f "${EXPORT_VALUE}/${FILE}" ]
        then
            echo "Base coverage found on ${EXPORT_VALUE}"
            BASE_COV=$(cat "${EXPORT_VALUE}/${FILE}")
            echo "Base coverage is: ${BASE_COV}"
            echo "base_cov=${BASE_COV}" >> $GITHUB_OUTPUT
        else
            echo "Base coverage NOT found on ${EXPORT_VALUE}!!"
        fi

  check:
    name: Pre CI check
    runs-on: ubuntu-20.04
    needs: [pre_ci, base]

    steps:
    - name: Check github variables
      # NOTE base coverage env var may be empty here
      env:
        #COMMIT_MESSAGE: ${{ needs.pre_ci.outputs.commit_message }}
        EXPORT_VALUE: ${{ needs.pre_ci.outputs.branch }}
        BASE_BRANCH: ${{ needs.base.outputs.base_branch }}
        BASE_COVERAGE: ${{ needs.base.outputs.base_cov }}
      run: |
        #echo "Commit message: ${COMMIT_MESSAGE}"
        echo "Export value (head_ref): ${EXPORT_VALUE}"
        echo "Base value (base_ref): ${BASE_BRANCH}"
        echo "Base coverage (percent): ${{ env.BASE_COVERAGE }}"

  cov_data:
    name: Generate test coverage data
    runs-on: ubuntu-20.04
    needs: [check]
    defaults:
      run:
        shell: bash
    outputs:
      coverage: ${{ steps.coverage.outputs.coverage }}
      coverage-rounded-display: ${{ steps.coverage.outputs.coverage-rounded-display }}
    env:
      PLATFORM: ubuntu-20.04
      PYTHON: '3.11'
      PYTHONIOENCODING: utf-8
      PIP_DOWNLOAD_CACHE: ${{ github.workspace }}/../.pip_download_cache

    steps:
    - uses: actions/checkout@v3
      with:
        fetch-depth: 0

    - uses: actions/setup-python@v4
      with:
        python-version: ${{ env.PYTHON }}

    - name: Add python requirements
      run: |
        python -m pip install --upgrade pip
        pip install tox

    - name: Generate coverage and fix pkg name
      run: |
        tox -e py

    - name: Code Coverage Summary Report (data)
      uses: irongut/CodeCoverageSummary@v1.3.0
      with:
        filename: coverage.xml
        output: 'both'

    - uses: actions/upload-artifact@v4
      with:
        name: src_coverage_rpts
        path: |
          coverage.xml
          code-coverage-results.txt
        retention-days: 1

    - name: Check code coverage
      id: coverage
      env:
        VALUE: "Branch Rate"
      run: |
        COVERAGE=$( cat code-coverage-results.txt | grep -e ^Summary | grep -o -E "${VALUE} = .{3}" | egrep -o '([0-9]+)' )
        echo "coverage=${COVERAGE}" >> $GITHUB_OUTPUT
        echo "coverage-rounded-display=${COVERAGE}%" >> $GITHUB_OUTPUT
        echo "Current coverage is: ${COVERAGE}%"

    - name: Code Coverage Summary Report
      uses: irongut/CodeCoverageSummary@v1.3.0
      if: ${{ github.event_name == 'pull_request' }}
      with:
        filename: coverage.xml
        format: 'markdown'
        output: 'both'

    - name: Add Coverage PR Comment
      uses: marocchino/sticky-pull-request-comment@v2
      if: github.event_name == 'pull_request' && (github.event.pull_request.author_association == 'MEMBER' || github.actor == github.repository_owner)
      with:
        header: coverage
        recreate: true
        path: code-coverage-results.md

  test:
    name: Coverage check
    runs-on: ubuntu-20.04
    needs: [cov_data, base]
    outputs:
      coverage: ${{ needs.cov_data.outputs.coverage }}
      coverage-base: ${{ needs.base.outputs.base_cov }}
      coverage-rounded-display: ${{ needs.cov_data.outputs.coverage-rounded-display }}

    steps:
    - name: Check test coverage
      env:
        COVERAGE: ${{ needs.cov_data.outputs.coverage }}
        COVERAGE_ROUNDED: ${{ needs.cov_data.outputs.coverage-rounded-display }}
        BASE_COVERAGE: ${{ needs.base.outputs.base_cov }}
        MEMBER: ${{ github.event.pull_request.author_association }}
      run: |
        echo "Coverage: ${COVERAGE}"
        echo "Coverage Rounded: ${COVERAGE_ROUNDED}"
        echo "Coverage on Base Branch: ${BASE_COVERAGE}"
        echo "Author assoc: ${MEMBER}"

  comment_cov_change:
    name: Comment on PR with coverage delta
    runs-on: ubuntu-20.04
    needs: [test, base]

    steps:
    - name: Environment
      run: |
        bash -c set

    - name: Set whether base coverage was found
      shell: bash
      env:
        BASE: ${{ needs.test.outputs.coverage-base }}
      run: |
        if [ -n "${BASE}" ]
        then
            BASE_RESULT="true"
        else
            BASE_RESULT="false"
        fi
        echo "HAVE_BASE_COVERAGE is ${BASE_RESULT}"
        echo "HAVE_BASE_COVERAGE=${BASE_RESULT}" >> $GITHUB_ENV
        echo "BASE_COVERAGE=${BASE}" >> $GITHUB_ENV

    - name: Collect variables and construct comment for delta message
      if: env.HAVE_BASE_COVERAGE == 'true'
      shell: bash
      env:
        BASE_BRANCH: ${{ needs.base.outputs.base_branch }}
        COVERAGE: ${{ needs.test.outputs.coverage }}
        BASE_COVERAGE: ${{ needs.test.outputs.coverage-base }}
        DELTA_WORD: "not change"
        RATE: "Branch Rate"

      run: |
        if [ "${COVERAGE}" -gt "${BASE_COVERAGE}" ]
        then
            DELTA_WORD="increase"
        elif [ "${COVERAGE}" -lt "${BASE_COVERAGE}" ]
        then
            DELTA_WORD="decrease"
        fi
        CHG=$(( COVERAGE - BASE_COVERAGE ))
        CHG="${CHG/-/}"
        echo "" > coverage-delta.md
        echo "Hello @${{ github.actor }}! Thanks for opening this PR. We found the following information based on analysis of the coverage report:" >> coverage-delta.md
        echo "" >> coverage-delta.md
        echo "__Base__ ${RATE} coverage is __${BASE_COVERAGE}%__" >> coverage-delta.md
        if [ "${CHG}" = "0" ]
        then
            echo "Merging ${{ github.sha }} into ${BASE_BRANCH} will __${DELTA_WORD}__ coverage" >> coverage-delta.md
        else
            echo "Merging ${{ github.sha }} into ${BASE_BRANCH} will __${DELTA_WORD}__ coverage by __${CHG}%__" >> coverage-delta.md
        fi
        if ! [ "${DELTA_WORD}" = "decrease" ]
        then
            echo "" >> coverage-delta.md
            echo "Nice work, @${{ github.actor }}. Cheers! :beers:" >> coverage-delta.md
        fi

    - name: Comment PR with test coverage delta
      uses: marocchino/sticky-pull-request-comment@v2
      if: env.HAVE_BASE_COVERAGE == 'true' && (github.event.pull_request.author_association == 'MEMBER' || github.actor == github.repository_owner)
      with:
        header: delta
        recreate: true
        path: coverage-delta.md

  badge:
    # Only generate and publish if these conditions are met:
    # - The test step ended successfully
    # - One of these is met:
    #   - This is a push event and the push event is on branch 'master' or 'develop'
    # Note: if this repo is personal (ie, not an org repo) then you can
    #       use the following to change the scope of the next 2 jobs
    #       instead of running on branch push as shown below:
    #   - This is a pull request event and the pull actor is the same as the repo owner
    #     if: ${{ ( github.event_name == 'pull_request' && github.actor == github.repository_owner ) || github.ref == 'refs/heads/master' }}
    name: Generate badge image with test coverage value
    runs-on: ubuntu-20.04
    needs: [test, pre_ci]
    if: github.event_name == 'push'
    outputs:
      url: ${{ steps.url.outputs.url }}
      markdown: ${{ steps.url.outputs.markdown }}

    steps:
    - uses: actions/checkout@v3
      with:
        ref: badges
        path: badges

    # Use the output from the `coverage` step
    - name: Generate the badge SVG image
      uses: emibcn/badge-action@v2.0.2
      id: badge
      with:
        label: 'Branch Coverage'
        status: ${{ needs.test.outputs.coverage-rounded-display }}
        color: ${{
          needs.test.outputs.coverage > 90 && 'green'              ||
          needs.test.outputs.coverage > 80 && 'yellow,green'       ||
          needs.test.outputs.coverage > 70 && 'yellow'             ||
          needs.test.outputs.coverage > 60 && 'orange,yellow'      ||
          needs.test.outputs.coverage > 50 && 'orange'             ||
          needs.test.outputs.coverage > 40 && 'red,orange'         ||
          needs.test.outputs.coverage > 30 && 'red,red,orange'     ||
          needs.test.outputs.coverage > 20 && 'red,red,red,orange' ||
          'red' }}
        path: badges/test-coverage.svg

    - name: Commit badge and data
      env:
        BRANCH: ${{ needs.pre_ci.outputs.branch }}
        COVERAGE: ${{ needs.test.outputs.coverage }}
        FILE: 'test-coverage.svg'
        DATA: 'test-coverage.txt'
      working-directory: ./badges
      run: |
        git config --local user.email "action@github.com"
        git config --local user.name "GitHub Action"
        mkdir -p "${BRANCH}"
        mv "${FILE}" "${BRANCH}"
        echo "${COVERAGE}" > "${BRANCH}/${DATA}"
        git add "${BRANCH}/${FILE}" "${BRANCH}/${DATA}"
        # Will give error if badge has not changed
        git commit -m "Add/Update badge" || true

    - name: Push badge commit
      uses: ad-m/github-push-action@master
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        branch: badges
        directory: badges
