Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Coverage/jacoco report PR test #7

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 34 additions & 25 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,60 +1,70 @@
# 워크플로우의 이름을 지정합니다
# 대시보드에서 워크플로우를 구분할 때 사용됩니다
name: CI Pipeline

# Event
on: # 워크플로우가 실행될 조건을 정의합니다
pull_request: # PR을 조건으로 설정합니다
on:
pull_request:
branches:
- test # test 브랜치로 PR이 열리면 실행되도록 지정
- test

# Jobs: 필요한 Job을 병렬 또는 (의존성에 의해)순차적으로 실행
jobs: # 아래 계층에 수행할 Job을 정의합니다
jobs:

# Build Job
build:
runs-on: ubuntu-latest # 해당 Job의 러너 환경을 지정합니다
runs-on: ubuntu-latest

# 아래에 build의 Step들을 정의합니다
steps:
# 1. 리포지토리에서 소스 코드를 체크아웃(복제)
- name: Checkout code # name으로 각 Step의 이름을 부여합니다
uses: actions/checkout@v3 # uses를 통해 액션을 호출합니다
- name: Checkout code
uses: actions/checkout@v3

# 2. Gradle 라이브러리 캐싱
- name: Cache Gradle packages
uses: actions/cache@v3
with: # with를 통해 액션에 대한 추가적인 설정을 지정할 수 있습니다
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-

# 3. Java 17 설치
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'

# 4. gradlew에 권한 부여
- name: Grant execute permission for gradlew
run: chmod +x gradlew # run으로 직접 명령어를 실행할 수 있습니다
run: chmod +x gradlew

# 5. 의존성 설치 및 빌드
- name: Build with Gradle
run: ./gradlew build --no-daemon

# Test Job
# 빌드에서 테스트를 진행하기 때문에 해당 Job은 제외해도 됩니다. 그러나 needs를 설명하기 위해 편의상 추가했습니다.
# 추가
- name: Leave a comment for test coverage
id: jacoco
uses: madrapps/[email protected]
with:
title: 📊 Test Coverage Report
paths: ${{ github.workspace }}/build/reports/jacoco/test/jacocoTestReport.xml # JaCoCo 리포트 위치
token: ${{ github.token }}
min-coverage-overall: 80 # 전체 프로젝트의 커버리지가 80% 이상이어야 통과
min-coverage-changed-files: 80 # 수정된 파일에 대한 최소 커버리지가 80% 이상이어야 통과
pass-emoji: '✅' # 통과 이모지 (default : ":apple:")
# update-comment: true # true로 설정하는 경우 기존 코멘트를 업데이트하는 형태로 동작

# 슬랙 알림 추가
- name: Slack message with build result
if: always()
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
fields: repo,message,commit,author,action,eventName,ref,workflow,job,took
if_mention: failure,cancelled
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

test:
runs-on: ubuntu-latest
needs: build # build가 성공적으로 완료되어야 수행된다는 의미(의존성 설정)
needs: build

steps:
# 기존 체크아웃, JDK 설치 과정
- name: Checkout code
uses: actions/checkout@v3

Expand All @@ -64,6 +74,5 @@ jobs: # 아래 계층에 수행할 Job을 정의합니다
distribution: 'temurin'
java-version: '17'

# 6. 테스트 실행
- name: Run tests
run: ./gradlew test --no-daemon
226 changes: 208 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,24 @@
2. [🗣️ GitHub Actions 소개](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EF%B8%8F-github-actions-%EC%86%8C%EA%B0%9C)
3. [🎯 GitHub Actions 주요 개념](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#-github-actions-%EC%A3%BC%EC%9A%94-%EA%B0%9C%EB%85%90)
4. [🚀 GitHub Actions 사용법](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#-github-actions-%EC%82%AC%EC%9A%A9%EB%B2%95)
* [대략적인 과정](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EB%8C%80%EB%9E%B5%EC%A0%81%EC%9D%B8-%EA%B3%BC%EC%A0%95)
* [예시](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EC%98%88%EC%8B%9C)
* [`uses` 필드](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#uses-%ED%95%84%EB%93%9C)
* [`run` 필드](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#run-%ED%95%84%EB%93%9C)
* [대략적인 과정](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EB%8C%80%EB%9E%B5%EC%A0%81%EC%9D%B8-%EA%B3%BC%EC%A0%95)
* [예시](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EC%98%88%EC%8B%9C)
* [`uses` 필드](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#uses-%ED%95%84%EB%93%9C)
* [`run` 필드](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#run-%ED%95%84%EB%93%9C)
5. [🗃️ 캐싱(Caching)](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EF%B8%8F-%EC%BA%90%EC%8B%B1caching)
6. [❌ 테스트 실패 살펴보기](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%8B%A4%ED%8C%A8-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0)
7. [☑️ 조건문 사용하기](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EF%B8%8F-%EC%A1%B0%EA%B1%B4%EB%AC%B8-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0)
8. [💬 슬랙으로 알림 설정하기(Secrets 사용)](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#-%EC%8A%AC%EB%9E%99%EC%9C%BC%EB%A1%9C-%EC%95%8C%EB%A6%BC-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0secrets-%EC%82%AC%EC%9A%A9%ED%95%B4%EB%B3%B4%EA%B8%B0)
* [슬랙 채널 추가](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EC%8A%AC%EB%9E%99-%EC%B1%84%EB%84%90-%EC%B6%94%EA%B0%80)
* [슬랙 앱 생성: Webhook URL 발급](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EC%8A%AC%EB%9E%99-%EC%95%B1-%EC%83%9D%EC%84%B1-webhook-url-%EB%B0%9C%EA%B8%89)
* [시크릿 등록](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EC%8B%9C%ED%81%AC%EB%A6%BF-%EB%93%B1%EB%A1%9D)
* [워크플로우 작성1: `slack-github-action`(버그)](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C%EC%9A%B0-%EC%9E%91%EC%84%B11-slack-github-action%ED%98%84%EC%9E%AC-%EB%B2%84%EA%B7%B8-%EC%9E%88%EC%9D%8C)
* [워크플로우 작성2: `slack-github-action`(버그 우회)](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C%EC%9A%B0-%EC%9E%91%EC%84%B12-slack-github-action%EB%B2%84%EA%B7%B8-%EC%9A%B0%ED%9A%8C)
* [워크플로우 작성3: `action-slack`](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C%EC%9A%B0-%EC%9E%91%EC%84%B13-action-slack)
* [슬랙 채널 추가](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EC%8A%AC%EB%9E%99-%EC%B1%84%EB%84%90-%EC%B6%94%EA%B0%80)
* [슬랙 앱 생성: Webhook URL 발급](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EC%8A%AC%EB%9E%99-%EC%95%B1-%EC%83%9D%EC%84%B1-webhook-url-%EB%B0%9C%EA%B8%89)
* [시크릿 등록](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EC%8B%9C%ED%81%AC%EB%A6%BF-%EB%93%B1%EB%A1%9D)
* [워크플로우 작성1: `slack-github-action`(버그)](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C%EC%9A%B0-%EC%9E%91%EC%84%B11-slack-github-action%ED%98%84%EC%9E%AC-%EB%B2%84%EA%B7%B8-%EC%9E%88%EC%9D%8C)
* [워크플로우 작성2: `slack-github-action`(버그 우회)](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C%EC%9A%B0-%EC%9E%91%EC%84%B12-slack-github-action%EB%B2%84%EA%B7%B8-%EC%9A%B0%ED%9A%8C)
* [워크플로우 작성3: `action-slack`](https://github.com/seungki1011/CICD-using-Github-Actions/tree/main?tab=readme-ov-file#%EC%9B%8C%ED%81%AC%ED%94%8C%EB%A1%9C%EC%9A%B0-%EC%9E%91%EC%84%B13-action-slack)
9. [📊 JaCoCo를 이용한 코드 커버리지 추가]()
* [`build.gradle` 설정]()
* [워크플로우 추가]()


<br>

Expand All @@ -40,11 +44,10 @@

<br>

아래 브랜치는 `main`을 기반으로 합니다.

* **[`slack/slack-github-action-bug`](https://github.com/seungki1011/CICD-using-Github-Actions/tree/slack/slack-github-action-bug)**: `slackapi/[email protected]`을 사용합니다. 버그가 있습니다.
* **[`slack/slack-github-action-workaround`](https://github.com/seungki1011/CICD-using-Github-Actions/tree/slack/slack-github-action-workaround)**: `slackapi/[email protected]`을 사용하지만, 버그를 우회한 방법입니다.
* **[`slack/action-slack`](https://github.com/seungki1011/CICD-using-Github-Actions/tree/slack/action-slack)**: `8398a7/action-slack`을 사용합니다
* **[`coverage/jacoco-report`](https://github.com/Madrapps/jacoco-report?tab=readme-ov-file)**: `Madrapps/jacoco-report`를 사용합니다. (슬랙 알림도 추가)

<br>

Expand Down Expand Up @@ -169,7 +172,7 @@ Github Action으로 워크플로우를 정의해서 사용하기 위해서는

---

### 예시 1
### 예시

워크플로우를 정의해서 사용하기 위해서 `.github/workflows/` 아래에 `ci.yml`이라는 파일을 만들어서 사용합니다.

Expand Down Expand Up @@ -941,12 +944,199 @@ jobs:

<br>

---

## 📊 JaCoCo를 이용한 코드 커버리지 추가

### `build.gradle` 설정

[JaCoCo (Java Code Coverage)](https://docs.gradle.org/current/userguide/jacoco_plugin.html)는 **Java 애플리케이션의 코드 커버리지를 측정하기 위한 오픈 소스 도구**입니다. 코드 커버리지는 단위 테스트나 통합 테스트에서 코드의 어느 부분이 실행되었는지를 나타내는 지표입니다. 이를 통해 작성된 테스트가 얼마나 효과적인지, 코드의 어느 부분이 테스트되지 않았는지 확인할 수 있습니다.

JaCoCo를 이용해서 **코드 커버리지(code coverage)를 측정**하고, **해당 커버리지 리포트를 댓글(comment)로 달아주는 워크플로우를 추가** 해봅시다.

<br>

먼저 JaCoCo를 사용하기 위해서 `build.gradle`에 필요한 설정을 추가해줍니다.

```groovy
plugins {
// ...
id 'jacoco' // 추가
}

jacoco {
toolVersion = "0.8.10" // jacoco 버전 명시
}

jacocoTestReport {
reports {
xml.required = true // madrapps/jacoco-report를 사용하기 위해서 xml 리포트 사용
html.required = true
}

// 각 리포트 타입 마다 저장 경로를 설정할 수 있다
// html.destination file("$buildDir/jacoco/html")
// xml.destination file("$buildDir/jacoco/xml")

// xml 기본 저장 경로: $buildDir/reports/jacoco/test/jacocoTestReport.xml

// 보고서에 표시되는 걸 제외하고 싶은 클래스를 명시
afterEvaluate {
classDirectories.setFrom(
files(classDirectories.files.collect {
fileTree(dir: it, excludes: [
// 나의 프로젝트에 맞게 변경 {그룹이름}/{프로젝트명}
"seungki/cicdpractice/api/domain/**",
"**/*Application*",
"**/*Request*",
"**/*Response*",
"**/*Exception*"
])
})
)
// 보고서를 생성하고 나서야 테스트 커버리지 검증을 진행
finalizedBy(jacocoTestCoverageVerification)
}

// 커버리지 검증을 위한 기준 제시
jacocoTestCoverageVerification {
violationRules {
rule {

/**
* element: 커버리지를 체크하는 기준
*
* BUNDLE: 전체 프로젝트의 모든 파일(default)
* CLASS: 클래스
* METHOD: 메서드
* PACKAGE: 패키지
* SOURCEFILE: 소스 파일
**/
enabled = true
element = 'CLASS'

/**
* counter: 커버리지 측정을 위한 최소의 단위
*
* BRANCH: 조건문의 분기 수
* CLASS: 클래스의 수
* COMPLEXITY: 복잡도
* INSTRUCTION: Java 바이트코드 명령의 수(default)
* METHOD: 메서드의 수
* LINE: 빈 줄을 제외한 실제 코드의 라인 수
**/

/**
* value: 커버리지의 측정 메트릭(metric)
*
* TOTALCOUNT: 전체 개수
* MISSEDCOUNT: 커버되지 않은 개수
* COVEREDCOUNT: 커버된 개수
* MISSEDRATIO: 커버되지 않은 비율. 0 ~ 1 사이의 숫자로, 1이 100%.
* COVEREDRATIO: 커버된 비율. 0 ~ 1 사이의 숫자로, 1이 100%. (default)
**/

limit {
counter = 'LINE'
value = 'COVEREDRATIO'
minimum = 0.80 // value에 대한 최소 통과 기준
}

// 커버리지 체크를 제외할 클래스를 명시
// jacocoTestReport과 가르게 패키지 경로를 적어줘야 한다
excludes = [
"seungki.cicdpractice.api.domain.**",
"**.*Application*",
"**.*Request*",
"**.*Response*",
"**.*Exception*"
]
}
}
}

tasks.named('test') {
useJUnitPlatform()
finalizedBy jacocoTestReport // 항상 테스트가 완료되어야 리포트 생성
}
```

<br>

`.gradlew test` 또는 인텔리제이의 Gradle 도구에 들어가서 `Tasks>verification>test`를 실행해봅시다.

<br>

![cifail2](./img/README/gradletest.png)

<p align="center">Gradle > Tasks > verification > test</p>

<br>

다음과 같은 결과를 얻었습니다.

<br>

![cifail2](./img/README/coveragefail.png)

![cifail2](./img/README/failreport.png)

<p align="center">service 커버리지의 최소 조건을 만족하지 못한다</p>

현재 컨트롤러 계층의 테스트만 작성했기 때문에, **서비스 계층에 대한 커버리지 조건을 만족하지 못하여 실패**했습니다. 서비스에 대한 **테스트를 추가하고 다시 시도**해보겠습니다.

<br>

![cifail2](./img/README/jacocosuccess.png)

<p align="center">최소 기준을 만족하고, 통과된다</p>

<br>

---

### 워크플로우 추가

이번에는 [`madrapps/jacoco-report`](https://github.com/Madrapps/jacoco-report)를 사용해서 **코드 커버리지에 대한 리포트를 자동으로 댓글로 달아주는 스텝을 추가**해봅시다.

<br>

```yaml
# 추가
- name: Leave a comment for test coverage
id: jacoco
uses: madrapps/[email protected]
with:
title: 📊 Test Coverage Report
paths: ${{ github.workspace }}/build/reports/jacoco/test/jacocoTestReport.xml # JaCoCo 리포트 위치
token: ${{ github.token }}
min-coverage-overall: 80 # 전체 프로젝트의 커버리지가 80% 이상이어야 통과
min-coverage-changed-files: 80 # 수정된 파일에 대한 최소 커버리지가 80% 이상이어야 통과
pass-emoji: '✅' # 통과 이모지 (default : ":apple:")
# update-comment: true # true로 설정하는 경우 기존 코멘트를 업데이트하는 형태로 동작
```

<br>





---

## 📑 Reference

1. [https://pozafly.github.io/dev-ops/cache-and-restore-keys-in-github-actions/](https://pozafly.github.io/dev-ops/cache-and-restore-keys-in-github-actions/)
2. [https://fe-developers.kakaoent.com/2022/220106-github-actions/](https://fe-developers.kakaoent.com/2022/220106-github-actions/)
3. [https://hyperconnect.github.io/2021/11/08/github-actions-for-everyone-1.html](https://hyperconnect.github.io/2021/11/08/github-actions-for-everyone-1.html)
4. [https://github.com/8398a7/action-slack](https://github.com/8398a7/action-slack)
5. [https://github.com/slackapi/slack-github-action](https://github.com/slackapi/slack-github-action)
* **GitHub Actions 설정**
* [https://pozafly.github.io/dev-ops/cache-and-restore-keys-in-github-actions/](https://pozafly.github.io/dev-ops/cache-and-restore-keys-in-github-actions/)
* [https://fe-developers.kakaoent.com/2022/220106-github-actions/](https://fe-developers.kakaoent.com/2022/220106-github-actions/)
* [https://hyperconnect.github.io/2021/11/08/github-actions-for-everyone-1.html](https://hyperconnect.github.io/2021/11/08/github-actions-for-everyone-1.html)

* **Slack Notification 설정**
* [https://github.com/8398a7/action-slack](https://github.com/8398a7/action-slack)
* [https://github.com/slackapi/slack-github-action](https://github.com/slackapi/slack-github-action)

* **JaCoCo 설정**
* [https://techblog.woowahan.com/2661/](https://techblog.woowahan.com/2661/)
* [https://docs.gradle.org/current/userguide/jacoco_plugin.html](https://docs.gradle.org/current/userguide/jacoco_plugin.html)
* [https://cl8d.tistory.com/119](https://cl8d.tistory.com/119)
* [https://github.com/Madrapps/jacoco-report?tab=readme-ov-file](https://github.com/Madrapps/jacoco-report?tab=readme-ov-file)
Loading
Loading