Skip to content

Commit cdf69b9

Browse files
authored
Merge pull request #1 from kamdubiel/feat/coverage-summary-comments
Add coverage summary comparison
2 parents 64ad399 + d39ecb5 commit cdf69b9

File tree

8 files changed

+170
-14
lines changed

8 files changed

+170
-14
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name: 🗳️ Check Licenses
2+
description: 'Check package licenses for compliance'
3+
4+
runs:
5+
using: 'composite'
6+
steps:
7+
- name: 🗳️ Check licenses
8+
run: pnpm check-licenses
9+
shell: bash
Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
name: 👁️‍🗨️ Code Analysis
22
description: 'Run code analysis'
33

4+
inputs:
5+
github-token:
6+
description: 'GitHub token for API access'
7+
required: true
8+
49
runs:
510
using: 'composite'
611
steps:
@@ -11,15 +16,3 @@ runs:
1116
- name: 🫣 Lint
1217
run: pnpm lint
1318
shell: bash
14-
15-
- name: 🗳️ Check licenses
16-
run: pnpm check-licenses
17-
shell: bash
18-
19-
- name: 🧪 Test
20-
run: pnpm test:coverage
21-
shell: bash
22-
23-
- name: 📊 Aggregate coverage results
24-
run: node scripts/aggregate-coverage-results.js
25-
shell: bash
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: 🧪 Test Coverage
2+
description: 'Run tests with coverage and comment on PRs'
3+
4+
inputs:
5+
github-token:
6+
description: 'GitHub token for API access'
7+
required: true
8+
9+
runs:
10+
using: 'composite'
11+
steps:
12+
- name: 🧪 Test
13+
run: pnpm test:coverage
14+
shell: bash
15+
16+
- name: 📊 Aggregate coverage results
17+
run: node scripts/aggregate-coverage-results.js
18+
shell: bash
19+
20+
- name: 📥 Download base branch coverage artifact
21+
if: github.event_name == 'pull_request'
22+
# Downloads the base branch's coverage artifact for comparison
23+
# Finds the workflow run from the base branch commit SHA
24+
# Continues even if artifact doesn't exist (first PR or workflow hasn't run on main yet)
25+
continue-on-error: true
26+
# SECURITY: Pin to commit SHA. Visit https://github.com/dawidd6/action-download-artifact/releases
27+
uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 # v3
28+
with:
29+
name: base-coverage
30+
path: base-coverage
31+
github_token: ${{ inputs.github-token }}
32+
workflow: base-coverage.yml
33+
commit: ${{ github.event.pull_request.base.sha }}
34+
if_no_artifact_found: ignore
35+
36+
- name: 💬 Comment coverage on PR
37+
if: github.event_name == 'pull_request'
38+
# Posts coverage report as a PR comment
39+
# Note: This action tries to run tests itself even with skip-step: all
40+
# It will use the coverage-file if provided, but may still attempt to collect base branch coverage
41+
# SECURITY: Pinned to commit SHA. To update, visit:
42+
# https://github.com/ArtiomTr/jest-coverage-report-action/releases
43+
continue-on-error: true
44+
uses: ArtiomTr/jest-coverage-report-action@262a7bb0b20c4d1d6b6b026af0f008f78da72788 # v2
45+
with:
46+
github-token: ${{ inputs.github-token }}
47+
coverage-file: coverage/coverage-summary.json
48+
base-coverage-file: base-coverage/coverage-summary.json
49+
package-manager: pnpm
50+
skip-step: all
51+
threshold: 0
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: 📊 Base Branch Coverage
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
jobs:
10+
upload-coverage:
11+
runs-on: ubuntu-24.04
12+
steps:
13+
- name: 📥 Checkout Repository
14+
uses: actions/checkout@v4
15+
16+
- name: 💻 Node setup
17+
uses: ./.github/actions/node-setup
18+
19+
- name: 🧪 Test
20+
run: pnpm test:coverage
21+
shell: bash
22+
23+
- name: 📊 Aggregate coverage results
24+
run: node scripts/aggregate-coverage-results.js
25+
shell: bash
26+
27+
- name: 📤 Upload coverage artifact
28+
uses: actions/upload-artifact@v4
29+
with:
30+
name: base-coverage
31+
path: coverage/coverage-summary.json
32+
retention-days: 90

.github/workflows/code-analysis.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ on:
88
jobs:
99
code-analysis:
1010
runs-on: ubuntu-24.04
11+
permissions:
12+
contents: read
13+
actions: read
14+
pull-requests: write
1115
steps:
1216
- name: 📥 Checkout Repository
1317
uses: actions/checkout@v4
@@ -20,6 +24,14 @@ jobs:
2024
- name: 👁️‍🗨️ Code Analysis
2125
uses: ./.github/actions/code-analysis
2226

27+
- name: 🗳️ Check Licenses
28+
uses: ./.github/actions/check-licenses
29+
2330
- name: 🏗️ Build packages
2431
run: pnpm build
2532
shell: bash
33+
34+
- name: 🧪 Test Coverage
35+
uses: ./.github/actions/test-coverage
36+
with:
37+
github-token: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ next-env.d.ts
2020

2121
# Testing
2222
/coverage
23+
/base-coverage
24+
.actrc
2325

2426
# Cache
2527
.turbo

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"test": "turbo run test --parallel --log-order=grouped --continue",
2929
"test:watch": "turbo run test:watch --ui=tui --continue",
3030
"test:coverage": "turbo run test:coverage --parallel --log-order=grouped --continue",
31+
"test:coverage:aggregate": "pnpm test:coverage && node scripts/aggregate-coverage-results.js",
3132
"test:coverage:watch": "turbo run test:coverage:watch --ui=tui --continue"
3233
},
3334
"devDependencies": {

scripts/aggregate-coverage-results.js

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
/**
2-
* Aggregates Jest coverage-summary.json files from all workspace packages
3-
* and outputs a GitHub Actions Job Summary.
2+
* Aggregates Jest coverage-summary.json files from all workspace packages.
3+
*
4+
* Generates:
5+
* 1. GitHub Actions Job Summary (if running in CI)
6+
* 2. Combined coverage-summary.json for PR comment actions
47
*/
58

69
const fs = require('fs');
@@ -101,6 +104,49 @@ function generateSummary(results) {
101104
return md;
102105
}
103106

107+
/**
108+
* Combines multiple coverage summaries into a single coverage-summary.json
109+
* that matches Jest's format. Used by coverage comment actions to display
110+
* aggregated coverage across all monorepo packages.
111+
*/
112+
function generateCombinedCoverageSummary(results) {
113+
if (results.length === 0) {
114+
return null;
115+
}
116+
117+
const metrics = ['lines', 'statements', 'functions', 'branches'];
118+
const combined = {
119+
total: {},
120+
};
121+
122+
// Calculate weighted averages across all packages
123+
metrics.forEach((metric) => {
124+
let totalCount = 0;
125+
let coveredCount = 0;
126+
let skippedCount = 0;
127+
128+
results.forEach(({ summary }) => {
129+
const m = summary[metric];
130+
if (m && typeof m.total === 'number') {
131+
totalCount += m.total;
132+
coveredCount += m.covered || 0;
133+
skippedCount += m.skipped || 0;
134+
}
135+
});
136+
137+
const pct = totalCount > 0 ? (coveredCount / totalCount) * 100 : 0;
138+
139+
combined.total[metric] = {
140+
total: totalCount,
141+
covered: coveredCount,
142+
skipped: skippedCount,
143+
pct: Math.round(pct * 100) / 100, // Round to 2 decimal places
144+
};
145+
});
146+
147+
return combined;
148+
}
149+
104150
function main() {
105151
const results = readAllCoverage();
106152

@@ -114,6 +160,16 @@ function main() {
114160
core.summary.addRaw(ghMd).write();
115161
console.info('✅ Coverage summary written to GitHub Actions job summary');
116162
}
163+
164+
// 3) Generate combined coverage-summary.json for PR comment actions
165+
const combined = generateCombinedCoverageSummary(results);
166+
if (combined) {
167+
const outputPath = path.join(COVERAGE_ROOT, 'coverage-summary.json');
168+
fs.writeFileSync(outputPath, JSON.stringify(combined, null, 2), 'utf8');
169+
console.info(`✅ Combined coverage-summary.json written to ${outputPath}`);
170+
} else {
171+
console.warn('⚠️ No coverage data to combine');
172+
}
117173
}
118174

119175
if (require.main === module) {

0 commit comments

Comments
 (0)