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

config#4/Jacoco 룰 설정 및 Jacoco 관련 깃허브 액션 추가 #8

Merged
merged 5 commits into from
Aug 12, 2024
Merged
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
3 changes: 1 addition & 2 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# PR 제목
## PR 체크
## ✅ PR 체크
- [ ] 하나의 PR 에는 100줄 정도의 커밋을 한다는 규칙을 지키고 있나요?
- [ ] 무엇을 변경했는지 충분히 설명하고 있나요?
- [ ] 새로운 기술을 사용했다면, 그 기술을 설명하고 있나요?
Expand Down
62 changes: 62 additions & 0 deletions .github/workflows/jacoco-rule.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
name: jacoco-rule

on:
pull_request:
branches: [ main, dev ]

permissions:
pull-requests: write
contents: read


jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Set up JDK 17
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'adopt'

- name: Grant execute permission for gradlew
run: chmod +x gradlew

- name: Build with Gradle
run: ./gradlew build

- name: Run tests and generate Jacoco report
run: ./gradlew test jacocoTestReport jacocoTestCoverageVerification

- name: Upload Jacoco coverage report
uses: actions/upload-artifact@v2
with:
name: jacoco-report
path: build/reports/jacoco/

- name: Jacoco Report to PR
id: jacoco
uses: madrapps/[email protected]
with:
paths: ${{ github.workspace }}/build/reports/jacoco/test/jacocoTestReport.xml
token: ${{ secrets.GITHUB_TOKEN }}
min-coverage-overall: 80
min-coverage-changed-files: 80
title: Code Coverage Report
update-comment: true

- name: Check coverage and fail if below threshold
run: |
overall_coverage=$(echo "${{ steps.jacoco.outputs.coverage-overall }}" | cut -d'.' -f1)
changed_files_coverage=$(echo "${{ steps.jacoco.outputs.coverage-changed-files }}" | cut -d'.' -f1)

if [ $overall_coverage -lt 80 ] || [ $changed_files_coverage -lt 80 ]; then
echo "Coverage is below the required threshold."
echo "Overall coverage: $overall_coverage%"
echo "Changed files coverage: $changed_files_coverage%"
exit 1
fi

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 코드는 Java 백엔드 프로젝트의 GitHub Actions 설정으로, JaCoCo 코드 커버리지 리포트를 처리합니다. 아래는 몇 가지 주요 점검 사항입니다.

1. 코드 품질 및 Java 최선의 관행

  • Gradle wrapper 사용: gradlew를 사용하는 것은 좋은 접근입니다. 그러나 Gradle 버전을 명시적으로 정의하여 일관성을 유지하는 것도 고려해볼 수 있습니다.
  • 환경 설정: JDK 17을 사용하는 것은 현재 최신 버전 중 하나로, 장점이 있습니다.

2. 성능 및 효율성

  • 커버리지 검사 명령어: Jacoco 및 Gradle 테스트가 한 번에 실행되므로, 문제가 발생할 경우 디버깅이 어려워질 수 있습니다. 각 단계를 세분화하거나 로그 출력을 추가하는 것이 좋습니다.

3. API 설계 및 백엔드 아키텍처

  • 코드 검토위한 PR 주기: Pull Request에서 자동으로 코드 커버리지를 확인할 수 있는 부분은 유용하지만, 리포트가 잘못될 경우 수정이 필요합니다. 지속적인 통합(CI) 도구에서 안정적인 커밋 후 QA 절차를 고려하세요.

4. 보안 취약점

  • GitHub Token 관리: GITHUB_TOKEN을 사용하는 것은 일반적이지만, 보다 민감한 리소스를 다룰 때는 이 추가 정보를 보호하는 별도의 방법을 고려해야 합니다.

5. 테스트 범위

  • 테스트 임계값 설정: 전체 및 변경 파일 커버리지 기준이 각각 80%로 설정되어 있는 것은 긍정적이나, 실제 환경에 따라 조정할 수 있으며, 프로덕션에 대한 테스트 커버리지를 강화할 필요가 있습니다.

개선 제안 요약

  • Gradle 버전을 명시적으로 정의하여 환경 일관성 확보.
  • 단계별 빌드를 통해 문제 발생 시 로깅 및 디버깅 용이성 향상.
  • PR 제공 시 안정된 코드 품질을 보장하기 위한 추가적인 QA 절차 도입.
  • 민감한 정보 관리를 위한 보안 절차 추가.
  • 테스트 커버리지 기준의 정기적인 리뷰 및 조정.

이러한 변화를 통해 코드 품질과 시스템 성능을 더욱 향상시킬 수 있을 것입니다.

137 changes: 96 additions & 41 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,75 +1,130 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.2'
id 'io.spring.dependency-management' version '1.1.6'
id 'org.asciidoctor.jvm.convert' version '3.3.2'
id 'java'
id 'org.springframework.boot' version '3.3.2'
id 'io.spring.dependency-management' version '1.1.6'
id 'org.asciidoctor.jvm.convert' version '3.3.2'
id 'jacoco'
}

group = 'com.wootecam'
version = '0.0.1-SNAPSHOT'

java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}

configurations {
compileOnly {
extendsFrom annotationProcessor
}
asciidoctorExt
compileOnly {
extendsFrom annotationProcessor
}
asciidoctorExt
}

repositories {
mavenCentral()
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-mail'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.session:spring-session-core'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-mail'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.session:spring-session-core'

developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.mysql:mysql-connector-j'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.mysql:mysql-connector-j'

compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'

testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'

// Rest docs
asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor'
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
// Rest docs
asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor'
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
}

ext {
set('snippetsDir', file("build/generated-snippets"))
set('snippetsDir', file("build/generated-snippets"))
}

tasks.named('test') {
outputs.dir snippetsDir
useJUnitPlatform()
outputs.dir snippetsDir
useJUnitPlatform()
}

tasks.named('asciidoctor') {
inputs.dir snippetsDir
configurations 'asciidoctorExt'
inputs.dir snippetsDir
configurations 'asciidoctorExt'

sources {
include("**/index.adoc")
}
sources {
include("**/index.adoc")
}

baseDirFollowsSourceFile()
dependsOn test
baseDirFollowsSourceFile()
dependsOn test
}

bootJar {
dependsOn asciidoctor
from("${asciidoctor.outputDir}") {
into 'static/docs'
}
}
dependsOn asciidoctor
from("${asciidoctor.outputDir}") {
into 'static/docs'
}
}

jacoco {
toolVersion = "0.8.8"
reportsDirectory = layout.buildDirectory.dir('reports/jacoco')
}

jacocoTestCoverageVerification {
// exclude class, package from coverage verification
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, exclude: [
'**/FestivalsApplication.class' // exclude main class
])
}))
}
violationRules {
rule {
element = 'BUNDLE'
limit {
counter = 'LINE'
value = 'COVEREDRATIO'
minimum = 0.8
}
limit {
counter = 'BRANCH'
value = 'COVEREDRATIO'
minimum = 0.7
}
}
}
}

test {
finalizedBy jacocoTestReport
finalizedBy jacocoTestCoverageVerification
}

jacocoTestReport {
dependsOn test
reports {
html.required = true
xml.required = true
}
// exclude class, package from coverage report
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, exclude: [
'**/FestivalsApplication.class' // exclude main class
])
}))
}
}


Loading