chore: migrate from nyc to c8 and enhance coverage reporting #6
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Coverage Report | |
| on: | |
| pull_request: | |
| branches: | |
| - main | |
| - v11.0.0 | |
| jobs: | |
| coverage-report: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Use Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22.x | |
| cache: npm | |
| - run: npm ci | |
| - name: Run base branch tests for comparison | |
| run: | | |
| git fetch origin ${{ github.event.pull_request.base.ref }} --depth=1 | |
| git checkout FETCH_HEAD | |
| echo "Running tests on base branch for comparison..." | |
| if npm run test:unit:justTest:ci 2>/dev/null && [ -f coverage/lcov.info ]; then | |
| mv coverage/lcov.info coverage-base.lcov | |
| echo "Base branch coverage saved" | |
| else | |
| echo "Base branch coverage failed, will skip comparison" | |
| touch coverage-base-failed | |
| fi | |
| git checkout - | |
| - name: Wait for test workflow to complete | |
| id: wait-tests | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const maxWaitTime = 30 * 60 * 1000; // 30 minutes | |
| const pollInterval = 30 * 1000; // 30 seconds | |
| const startTime = Date.now(); | |
| // Find the Tests workflow run for this PR | |
| while (Date.now() - startTime < maxWaitTime) { | |
| const runs = await github.rest.actions.listWorkflowRuns({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| workflow_id: 'ci.yml', | |
| event: 'pull_request', | |
| head_sha: context.sha, | |
| }); | |
| const testRun = runs.data.workflow_runs[0]; | |
| if (testRun) { | |
| console.log(`Test workflow status: ${testRun.status}, conclusion: ${testRun.conclusion}`); | |
| if (testRun.status === 'completed') { | |
| if (testRun.conclusion === 'success' || testRun.conclusion === 'failure') { | |
| console.log('Test workflow completed, artifact should be available'); | |
| core.setOutput('tests_completed', 'true'); | |
| core.setOutput('run_id', testRun.id); | |
| return; | |
| } else { | |
| core.setFailed(`Test workflow completed with conclusion: ${testRun.conclusion}`); | |
| return; | |
| } | |
| } | |
| } | |
| // Wait before polling again | |
| console.log('Waiting for test workflow to complete...'); | |
| await new Promise(resolve => setTimeout(resolve, pollInterval)); | |
| } | |
| core.setFailed('Timeout waiting for test workflow to complete'); | |
| - name: Download coverage artifact | |
| if: steps.wait-tests.outputs.tests_completed == 'true' | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: coverage-report | |
| path: coverage/ | |
| run-id: ${{ steps.wait-tests.outputs.run_id }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Generate coverage comparison and comment | |
| if: steps.wait-tests.outputs.tests_completed == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| PR_NUMBER: ${{ github.event.pull_request.number }} | |
| BASE_REF: ${{ github.event.pull_request.base.ref }} | |
| run: | | |
| if [ -f coverage/lcov.info ]; then | |
| # Parse current coverage from lcov.info | |
| LINES_FOUND=$(grep -o "LF:[0-9]*" coverage/lcov.info | cut -d: -f2 | awk '{s+=$1} END {print s}') | |
| LINES_HIT=$(grep -o "LH:[0-9]*" coverage/lcov.info | cut -d: -f2 | awk '{s+=$1} END {print s}') | |
| FUNCS_FOUND=$(grep -o "FNF:[0-9]*" coverage/lcov.info | cut -d: -f2 | awk '{s+=$1} END {print s}') | |
| FUNCS_HIT=$(grep -o "FNH:[0-9]*" coverage/lcov.info | cut -d: -f2 | awk '{s+=$1} END {print s}') | |
| BRANCHES_FOUND=$(grep -o "BRF:[0-9]*" coverage/lcov.info | cut -d: -f2 | awk '{s+=$1} END {print s}') | |
| BRANCHES_HIT=$(grep -o "BRH:[0-9]*" coverage/lcov.info | cut -d: -f2 | awk '{s+=$1} END {print s}') | |
| LINES_PCT=$(awk "BEGIN {printf \"%.2f\", ($LINES_HIT/$LINES_FOUND)*100}") | |
| FUNCS_PCT=$(awk "BEGIN {printf \"%.2f\", ($FUNCS_HIT/$FUNCS_FOUND)*100}") | |
| BRANCHES_PCT=$(awk "BEGIN {printf \"%.2f\", ($BRANCHES_HIT/$BRANCHES_FOUND)*100}") | |
| # Check if we have base branch coverage for comparison | |
| BASE_COVERAGE="" | |
| if [ -f coverage-base.lcov ] && [ ! -f coverage-base-failed ]; then | |
| echo "Using pre-computed base branch coverage..." | |
| BASE_LINES_FOUND=$(grep -o "LF:[0-9]*" coverage-base.lcov | cut -d: -f2 | awk '{s+=$1} END {print s}') | |
| BASE_LINES_HIT=$(grep -o "LH:[0-9]*" coverage-base.lcov | cut -d: -f2 | awk '{s+=$1} END {print s}') | |
| BASE_FUNCS_FOUND=$(grep -o "FNF:[0-9]*" coverage-base.lcov | cut -d: -f2 | awk '{s+=$1} END {print s}') | |
| BASE_FUNCS_HIT=$(grep -o "FNH:[0-9]*" coverage-base.lcov | cut -d: -f2 | awk '{s+=$1} END {print s}') | |
| BASE_BRANCHES_FOUND=$(grep -o "BRF:[0-9]*" coverage-base.lcov | cut -d: -f2 | awk '{s+=$1} END {print s}') | |
| BASE_BRANCHES_HIT=$(grep -o "BRH:[0-9]*" coverage-base.lcov | cut -d: -f2 | awk '{s+=$1} END {print s}') | |
| BASE_LINES_PCT=$(awk "BEGIN {printf \"%.2f\", ($BASE_LINES_HIT/$BASE_LINES_FOUND)*100}") | |
| BASE_FUNCS_PCT=$(awk "BEGIN {printf \"%.2f\", ($BASE_FUNCS_HIT/$BASE_FUNCS_FOUND)*100}") | |
| BASE_BRANCHES_PCT=$(awk "BEGIN {printf \"%.2f\", ($BASE_BRANCHES_HIT/$BASE_BRANCHES_FOUND)*100}") | |
| LINES_DIFF=$(awk "BEGIN {printf \"%.2f\", $LINES_PCT - $BASE_LINES_PCT}") | |
| FUNCS_DIFF=$(awk "BEGIN {printf \"%.2f\", $FUNCS_PCT - $BASE_FUNCS_PCT}") | |
| BRANCHES_DIFF=$(awk "BEGIN {printf \"%.2f\", $BRANCHES_PCT - $BASE_BRANCHES_PCT}") | |
| # Add emoji indicators | |
| LINES_INDICATOR=$(awk "BEGIN {if ($LINES_DIFF > 0) print \"π’ +\"; else if ($LINES_DIFF < 0) print \"π΄ \"; else print \"\"}") | |
| FUNCS_INDICATOR=$(awk "BEGIN {if ($FUNCS_DIFF > 0) print \"π’ +\"; else if ($FUNCS_DIFF < 0) print \"π΄ \"; else print \"\"}") | |
| BRANCHES_INDICATOR=$(awk "BEGIN {if ($BRANCHES_DIFF > 0) print \"π’ +\"; else if ($BRANCHES_DIFF < 0) print \"π΄ \"; else print \"\"}") | |
| BASE_COVERAGE=$(cat <<EOFTABLE | |
| ### Compared to base branch (\`${BASE_REF}\`) | |
| | Metric | Base | Current | Change | | |
| |--------|------|---------|--------| | |
| | Lines | ${BASE_LINES_PCT}% | ${LINES_PCT}% | ${LINES_INDICATOR}${LINES_DIFF}% | | |
| | Functions | ${BASE_FUNCS_PCT}% | ${FUNCS_PCT}% | ${FUNCS_INDICATOR}${FUNCS_DIFF}% | | |
| | Branches | ${BASE_BRANCHES_PCT}% | ${BRANCHES_PCT}% | ${BRANCHES_INDICATOR}${BRANCHES_DIFF}% | | |
| EOFTABLE | |
| ) | |
| fi | |
| # Create comment body using printf to avoid YAML pipe issues | |
| printf -v COMMENT_BODY '%s\n' \ | |
| "## π Coverage Report" \ | |
| "" \ | |
| "| Metric | Coverage |" \ | |
| "|--------|----------|" \ | |
| "| Lines | ${LINES_PCT}% (${LINES_HIT}/${LINES_FOUND}) |" \ | |
| "| Functions | ${FUNCS_PCT}% (${FUNCS_HIT}/${FUNCS_FOUND}) |" \ | |
| "| Branches | ${BRANCHES_PCT}% (${BRANCHES_HIT}/${BRANCHES_FOUND}) |${BASE_COVERAGE}" \ | |
| "" \ | |
| "<details>" \ | |
| "<summary>View full coverage report</summary>" \ | |
| "" \ | |
| "Download the coverage artifact from the [workflow run](${{ github.event.workflow_run.html_url }}) to see the full HTML report." \ | |
| "</details>" | |
| # Delete old coverage comments | |
| gh pr view ${PR_NUMBER} --json comments --jq '.comments[] | select(.body | startswith("## π Coverage Report")) | .id' | \ | |
| xargs -I {} gh api -X DELETE /repos/${{ github.repository }}/issues/comments/{} || true | |
| # Post new comment | |
| gh pr comment ${PR_NUMBER} --body "$COMMENT_BODY" | |
| fi |