Skip to content

[feat] jacoco 커밋메시지 추가 #196

[feat] jacoco 커밋메시지 추가

[feat] jacoco 커밋메시지 추가 #196

Workflow file for this run

name: CI
on:
pull_request:
branches: [ main, dev ]
permissions:
contents: read
pull-requests: write
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
cache: 'gradle'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
# ✅ Spotless 검사
- name: Run Spotless Check
run: ./gradlew spotlessCheck
- name: Build and Test
run: ./gradlew build
- name: JaCoCo 커버리지 PR 코멘트
uses: madrapps/jacoco-report@v1.7.1
with:
paths: ${{ github.workspace }}/build/reports/jacoco/test/jacocoTestReport.xml
token: ${{ secrets.GITHUB_TOKEN }}
title: "테스트 커버리지 리포트"
update-comment: true
min-coverage-overall: 0
min-coverage-changed-files: 0
- name: JaCoCo 패키지별 상세 커버리지 코멘트
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const xml = fs.readFileSync('build/reports/jacoco/test/jacocoTestReport.xml', 'utf8');
const packageMatches = [...xml.matchAll(/<package name="([^"]+)"[\s\S]*?<\/package>/g)];
const pct = (covered, missed) => {
const total = covered + missed;
if (total === 0) return -1;
return parseFloat(((covered / total) * 100).toFixed(1));
};
const packages = packageMatches.map(match => {
const pkgRaw = match[1];
const parts = pkgRaw.split('/');
const pkg = parts.slice(-2).join('/');
const counters = [...match[0].matchAll(/<counter type="([^"]+)" missed="(\d+)" covered="(\d+)"/g)];
const lineCounter = counters.find(c => c[1] === 'LINE');
const branchCounter = counters.find(c => c[1] === 'BRANCH');
const linePct = lineCounter ? pct(parseInt(lineCounter[3]), parseInt(lineCounter[2])) : -1;
const branchPct = branchCounter ? pct(parseInt(branchCounter[3]), parseInt(branchCounter[2])) : -1;
return { pkg, linePct, branchPct };
});
packages.sort((a, b) => b.linePct - a.linePct);
const rows = packages.map(({ pkg, linePct, branchPct }) => {
const lineStr = linePct < 0 ? 'N/A' : linePct + '%';
const branchStr = branchPct < 0 ? 'N/A' : branchPct + '%';
const emoji = linePct >= 80 ? '🟢' : linePct >= 50 ? '🟡' : '🔴';
return `| ${emoji} \`${pkg}\` | ${lineStr} | ${branchStr} |`;
});
const body = [
'## 📦 패키지별 테스트 커버리지',
'',
'| 패키지 | Line | Branch |',
'|--------|------|--------|',
...rows,
'',
'> 🟢 80% 이상 &nbsp; 🟡 50~79% &nbsp; 🔴 50% 미만',
].join('\n');
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const existing = comments.find(c =>
c.user.login === 'github-actions[bot]' &&
c.body.includes('패키지별 테스트 커버리지')
);
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}
- name: Discord 알림 (CI 실패)
if: failure()
run: |
curl -s -H "Content-Type: application/json" \
-d "{\"embeds\":[{\"title\":\"CI 빌드 실패 ❌\",\"description\":\"**브랜치**: ${{ github.head_ref }}\\n**PR**: ${{ github.event.pull_request.title }}\\n**커밋**: ${{ github.sha }}\",\"color\":15158332}]}" \
${{ secrets.DISCORD_WEBHOOK_URL }}