Merge pull request #182 from fbosch/fix/analytics-consent-tracking #381
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: PR Coverage Report | ||
| on: | ||
| workflow_run: | ||
| workflows: ['CI'] | ||
| types: [completed] | ||
| permissions: | ||
| actions: read | ||
| contents: read | ||
| pull-requests: write | ||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.ref }} | ||
| cancel-in-progress: true | ||
| jobs: | ||
| coverage-comment: | ||
| runs-on: ubuntu-latest | ||
| if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request' | ||
| steps: | ||
| - name: Resolve CI artifact metadata | ||
| id: artifact | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const runId = context.payload.workflow_run.id; | ||
| const prs = context.payload.workflow_run.pull_requests || []; | ||
| const prNumber = prs.length > 0 ? prs[0].number : null; | ||
| if (prNumber === null) { | ||
| core.setOutput('found', 'false'); | ||
| return; | ||
| } | ||
| const artifacts = await github.paginate(github.rest.actions.listWorkflowRunArtifacts, { | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| run_id: runId, | ||
| per_page: 100, | ||
| }); | ||
| const expectedName = `coverage-${context.payload.workflow_run.head_sha}`; | ||
| const coverageArtifact = artifacts.find((artifact) => artifact.name === expectedName); | ||
| core.setOutput('pr_number', String(prNumber)); | ||
| if (coverageArtifact === undefined) { | ||
| core.setOutput('found', 'false'); | ||
| core.setOutput('artifact_name', expectedName); | ||
| return; | ||
| } | ||
| core.setOutput('found', 'true'); | ||
| core.setOutput('artifact_name', coverageArtifact.name); | ||
| - name: Skip when CI produced no coverage artifact | ||
| if: steps.artifact.outputs.found != 'true' | ||
| run: echo "No coverage artifact found for this CI run (likely non-runtime-only change)." | ||
| - name: Download coverage artifact from CI run | ||
| if: steps.artifact.outputs.found == 'true' | ||
| uses: dawidd6/action-download-artifact@v9 | ||
| with: | ||
| run_id: ${{ github.event.workflow_run.id }} | ||
| name: ${{ steps.artifact.outputs.artifact_name }} | ||
| path: . | ||
| - name: Upload coverage reports to Codecov | ||
| if: steps.artifact.outputs.found == 'true' | ||
| uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4 | ||
| with: | ||
| file: ./coverage/lcov.info | ||
| flags: unittests | ||
| name: codecov-umbrella | ||
| fail_ci_if_error: false | ||
| verbose: true | ||
| - name: Comment PR with coverage | ||
| if: steps.artifact.outputs.found == 'true' | ||
| env: | ||
| PR_NUMBER: ${{ steps.artifact.outputs.pr_number }} | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const fs = require('fs'); | ||
| const prNumber = Number(process.env.PR_NUMBER); | ||
| if (Number.isFinite(prNumber) === false) { | ||
| core.setFailed('Missing PR number from workflow_run payload.'); | ||
| return; | ||
| } | ||
| try { | ||
| const coveragePath = './coverage/coverage-summary.json'; | ||
| if (fs.existsSync(coveragePath) === false) { | ||
| await github.rest.issues.createComment({ | ||
| issue_number: prNumber, | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| body: '❌ Coverage report not generated. Please check the test run.', | ||
| }); | ||
| return; | ||
| } | ||
| const coverageData = JSON.parse(fs.readFileSync(coveragePath, 'utf8')); | ||
| const total = coverageData.total; | ||
| const overallCoverage = Math.round( | ||
| (total.lines.pct + total.functions.pct + total.branches.pct + total.statements.pct) / 4, | ||
| ); | ||
| let badgeColor = 'red'; | ||
| if (overallCoverage >= 80) badgeColor = 'brightgreen'; | ||
| else if (overallCoverage >= 60) badgeColor = 'yellow'; | ||
| else if (overallCoverage >= 40) badgeColor = 'orange'; | ||
| const badge = ``; | ||
| const comment = `## 📊 Test Coverage Report ${badge} | ||
| ### Overall Coverage: **${overallCoverage}%** | ||
| | Metric | Coverage | | ||
| |--------|----------| | ||
| | Lines | ${total.lines.pct}% | | ||
| | Functions | ${total.functions.pct}% | | ||
| | Branches | ${total.branches.pct}% | | ||
| | Statements | ${total.statements.pct}% | | ||
| ### Coverage Details | ||
| <details> | ||
| <summary>📁 File Coverage Breakdown</summary> | ||
| \`\`\` | ||
| ${Object.entries(coverageData) | ||
| .filter(([key]) => key !== 'total') | ||
| .map(([file, data]) => { | ||
| const fileCoverage = Math.round( | ||
| (data.lines.pct + data.functions.pct + data.branches.pct + data.statements.pct) / 4, | ||
| ); | ||
| return `${file}: ${fileCoverage}%`; | ||
| }) | ||
| .join('\n')} | ||
| \`\`\` | ||
| </details> | ||
| --- | ||
| *This report was generated automatically by GitHub Actions.* | ||
| *View detailed coverage at: [Coverage Report](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})*`; | ||
| await github.rest.issues.createComment({ | ||
| issue_number: prNumber, | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| body: comment, | ||
| }); | ||
| } catch (error) { | ||
| console.error('Error creating coverage comment:', error); | ||
| await github.rest.issues.createComment({ | ||
| issue_number: prNumber, | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| body: '❌ Error generating coverage report. Please check the workflow logs.', | ||
| }); | ||
| } | ||