Skip to content

Commit 20d6b04

Browse files
authored
Merge pull request #207 from prgrms-be-devcourse/feat/206-jacoco도입
[feat] jacoco 커밋메시지 추가
2 parents 25397ca + 4fa5715 commit 20d6b04

1 file changed

Lines changed: 87 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ on:
66

77
permissions:
88
contents: read
9+
pull-requests: write
910

1011
jobs:
1112
build-and-test:
@@ -31,6 +32,92 @@ jobs:
3132
- name: Build and Test
3233
run: ./gradlew build
3334

35+
- name: JaCoCo 커버리지 PR 코멘트
36+
uses: actions/github-script@v7
37+
with:
38+
github-token: ${{ secrets.GITHUB_TOKEN }}
39+
script: |
40+
const fs = require('fs');
41+
const xml = fs.readFileSync('build/reports/jacoco/test/jacocoTestReport.xml', 'utf8');
42+
43+
const pct = (covered, missed) => {
44+
const total = covered + missed;
45+
if (total === 0) return -1;
46+
return parseFloat(((covered / total) * 100).toFixed(1));
47+
};
48+
49+
// Overall 커버리지: 마지막 </package> 이후의 <counter> 태그에서 추출
50+
const lastPackageEnd = xml.lastIndexOf('</package>');
51+
const reportTail = lastPackageEnd >= 0 ? xml.slice(lastPackageEnd + '</package>'.length) : xml;
52+
const overallLine = reportTail.match(/<counter type="LINE" missed="(\d+)" covered="(\d+)"/);
53+
const overallBranch = reportTail.match(/<counter type="BRANCH" missed="(\d+)" covered="(\d+)"/);
54+
const overallLinePct = overallLine ? pct(parseInt(overallLine[2]), parseInt(overallLine[1])) : -1;
55+
const overallBranchPct = overallBranch ? pct(parseInt(overallBranch[2]), parseInt(overallBranch[1])) : -1;
56+
const overallEmoji = overallLinePct >= 80 ? '🟢' : overallLinePct >= 50 ? '🟡' : '🔴';
57+
58+
// 패키지별 커버리지
59+
const packageMatches = [...xml.matchAll(/<package name="([^"]+)"[\s\S]*?<\/package>/g)];
60+
const packages = packageMatches.map(match => {
61+
const parts = match[1].split('/');
62+
const pkg = parts.slice(-2).join('/');
63+
const counters = [...match[0].matchAll(/<counter type="([^"]+)" missed="(\d+)" covered="(\d+)"/g)];
64+
const lineCounter = counters.find(c => c[1] === 'LINE');
65+
const branchCounter = counters.find(c => c[1] === 'BRANCH');
66+
const linePct = lineCounter ? pct(parseInt(lineCounter[3]), parseInt(lineCounter[2])) : -1;
67+
const branchPct = branchCounter ? pct(parseInt(branchCounter[3]), parseInt(branchCounter[2])) : -1;
68+
return { pkg, linePct, branchPct };
69+
});
70+
71+
packages.sort((a, b) => b.linePct - a.linePct);
72+
73+
const rows = packages.map(({ pkg, linePct, branchPct }) => {
74+
const emoji = linePct >= 80 ? '🟢' : linePct >= 50 ? '🟡' : '🔴';
75+
return `| ${emoji} \`${pkg}\` | ${linePct < 0 ? 'N/A' : linePct + '%'} | ${branchPct < 0 ? 'N/A' : branchPct + '%'} |`;
76+
});
77+
78+
const body = [
79+
'## 📊 테스트 커버리지 리포트',
80+
'',
81+
`### Overall: ${overallEmoji} Line \`${overallLinePct < 0 ? 'N/A' : overallLinePct + '%'}\` | Branch \`${overallBranchPct < 0 ? 'N/A' : overallBranchPct + '%'}\``,
82+
'',
83+
'---',
84+
'',
85+
'### 📦 패키지별 커버리지',
86+
'',
87+
'| 패키지 | Line | Branch |',
88+
'|--------|------|--------|',
89+
...rows,
90+
'',
91+
'> 🟢 80% 이상 &nbsp; 🟡 50~79% &nbsp; 🔴 50% 미만',
92+
].join('\n');
93+
94+
const { data: comments } = await github.rest.issues.listComments({
95+
owner: context.repo.owner,
96+
repo: context.repo.repo,
97+
issue_number: context.issue.number,
98+
});
99+
100+
const existing = comments.find(c =>
101+
c.user.login === 'github-actions[bot]' &&
102+
c.body.includes('테스트 커버리지 리포트')
103+
);
104+
105+
if (existing) {
106+
await github.rest.issues.updateComment({
107+
owner: context.repo.owner,
108+
repo: context.repo.repo,
109+
comment_id: existing.id,
110+
body,
111+
});
112+
} else {
113+
await github.rest.issues.createComment({
114+
owner: context.repo.owner,
115+
repo: context.repo.repo,
116+
issue_number: context.issue.number,
117+
body,
118+
});
119+
}
120+
34121
- name: Discord 알림 (CI 실패)
35122
if: failure()
36123
run: |

0 commit comments

Comments
 (0)