올리브영 테크블로그 포스팅 detekt와 reviewdog으로 코드 품질 향상
Discovery

detekt와 reviewdog으로 코드 품질 향상

detekt + reviewdog + Github Actions 도입하기

2023.10.11

안녕하세요! 상품스쿼드 백엔드 개발자 빽곰입니다.
상품스쿼드에서 코드 품질 향상을 위해 새롭게 도입한 Code Detecting Process를 소개해 보려고 합니다.

왜 도입하게 되었을까?..🤫

올리브영에서는 kotlin 기반의 새로운 아키텍처를 도입한 API 개발로 각 스쿼드에서 동시에 많은 프로젝트를 진행 중 입니다.

다수의 개발자가 프로젝트를 진행하다 보면 자연스레 code convention에 대하여 고민할 수 밖에 없습니다.

저희 올리브영에서도 SonarQube와 코드 리뷰를 활용해서 진행하고 있지만 아래와 같은 여러 고민을 마주하게 되었습니다.


1️⃣ 동시에 많은 구성원들이 각기 다른 포맷으로 개발되면서, CODE CONVENTION을 갖추고 코드 품질을 올리기 위한 방법이 필요

2️⃣ 기존 사용하는 SonarQube는 기본 Rule 외에 Custom Rule을 자유롭게 작성 / 수정이 쉽지 않음

3️⃣ 각 스쿼드 구성원 간의 코드 리뷰로는 모든 문제 / 이슈를 감지할 수 없음

이러한 고민을 모두 해결할 수 있는 방법을 찾아 detekt + reviewdog + Github Actions를 도입하기로 결정했습니다!
1



How to...?

howto


detekt

  • Kotlin의 대표적인 CODE CONVENTION TOOL
  • 여러 환경에서의 확장성 및 코드 복잡성, Code Smell 탐색과 같은 코드 분석에 특화
  • Custom Rule 작성 및 관리에 용이

▶️ root gradle 설정

dependencies {
    classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.10")
}


plugins {
    id ("io.gitlab.arturbosch.detekt") version "1.21.0" // detekt 플러그인 추가
}


subprojects{  // 하위 모듈에 detekt 설정
    apply(plugin = "io.gitlab.arturbosch.detekt")

    detekt{
        toolVersion = "1.21.0"
        buildUponDefaultConfig = true
        allRules = false
        config = files("$rootDir/config/detekt/detekt.yml") // Detekt에서 제공된 yml에서 Rule 설정 On/Off 가능
        ignoreFailures = true // detekt 빌드시 실패 ignore 처리
    }
}


tasks.detekt.configure { // Reviewdog 사용을 위한 Detekt 수행결과 REPORT
    reports {
        xml.required.set(true)
        xml.outputLocation.set(file("build/reports/detekt/detekt.xml"))
    }
}

Terminal 수행

//수행시 동작
./gradlew detekt

//Detekt default Rule config 파일생성 (config/detekt/detekt.xml)
./gradlew detektGenerateConfig

▶️ Olive-rules module 추가 생성 / Custom Rule 설정


//root gradle > subprojects 추가

afterEvaluate { // kotlin compile 후 실행(custom Rule 적용을 위한 코드블럭)
    plugins.apply("io.gitlab.arturbosch.detekt")
    dependencies {
        detektPlugins(project(":olive-rules"))
    }

    val detektTaskProvider = tasks.named("detekt")

    if (project.name == "olive-rules") return@afterEvaluate
    tasks.getByName("compileKotlin").finalizedBy(detektTaskProvider)
}

Custom Rule을 작성할 olive-rules module 추가 생성


//olive-rules > gradle 설정

import org.springframework.boot.gradle.tasks.bundling.BootJar

plugins {
        kotlin("jvm")
        id("io.gitlab.arturbosch.detekt")
        }

        dependencies {
        compileOnly("io.gitlab.arturbosch.detekt:detekt-api:1.21.0")
        }

        tasks.getByName<BootJar>("bootJar") {
        enabled = false
        }

RuleSet Provider 설정

package com.oliveyoung.detekt.rules.provider


import com.oliveyoung.detekt.rules.HttpMethodCheck
import com.oliveyoung.detekt.rules.ResponseCheck
import com.oliveyoung.detekt.rules.SaveCheck
import com.oliveyoung.detekt.rules.RepositoryRule
import io.gitlab.arturbosch.detekt.api.Config
import io.gitlab.arturbosch.detekt.api.RuleSet
import io.gitlab.arturbosch.detekt.api.RuleSetProvider

class RuleProvider : RuleSetProvider {

    override val ruleSetId: String = "olive-rules"
    override fun instance(config: Config): RuleSet  {

        // custom ruleset 적용
        return RuleSet(ruleSetId, listOf(SaveCheck(config), HttpMethodCheck(config),ResponseCheck(config),RepositoryRule(config) ))
    }
}

생성된 4개의 CustomRule customRule

SPI 추가(olive-rules/src/main/resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider)

com.oliveyoung.detekt.rules.provider.RuleProvider //실제 생성한 RuleProvider 클래스의 경로

config 추가 설정 olive-rules/src/main/resources/config/config.yml

    olive-rules:  // RuleProvider클래스의 ruleSetId
        active: true
        SaveCheck: // RuleProvider에서 return하는 rule명칭
         active: true
        HttpMethodCheck:
         active: true
        ResponseCheck:
         active: true
        RepositoryRule:
         active: true

GenerateConfig 추가 설정 detektConfig



Github Actions

  • Repository에서 이벤트 발생시 특정 Workflow 를 실행할 수 있도록 하는 서비스로 CI/CD와 Code Convention 등에 활용
  • 공개 레포지토리의 경우 무료, 비공개일 경우 엔터프라이즈 기준 월 50GB / 50,000분까지 무료 이후 정책에 따른 요금 발생

▶️ PR Reivew Token 생성
Github계정의 Settings > Developer settings > Personal access tokens > Token(classic) > Generate new token 선택 후 생성 gitToken

해당 리포지토리의 Settings > Secrets and variables > Actions > New repository secret 생성 repoSet

Name - TOKEN, Secret - 생성한 token 값 입력 actionToken

▶️ Root Project .github/workflows/detekt.yml 생성

workflows

    name: run detekt
        on: [pull_request]

        jobs:
        detekt:
        runs-on: ubuntu-latest
        steps:
        - uses: actions/checkout@v3

      - uses: actions/setup-java@v3
        with:
                distribution: 'temurin'
                java-version: '11'
                cache: 'gradle'

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

                - name: build detekt
                run: ./gradlew detekt

                - uses: reviewdog/action-setup@v1
                with:
                    reviewdog_version: latest

                - name: Run reviewdog
                env:
                    REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.TOKEN }} // ACTION SECRETS에서 생성한 Name명
                run: |
                    cat olive-batch/build/reports/detekt/detekt.xml | reviewdog -f=checkstyle -name="detekt" -reporter="github-pr-review" -level="info"
                    cat olive-domain/build/reports/detekt/detekt.xml | reviewdog -f=checkstyle -name="detekt" -reporter="github-pr-review" -level="info"
                    cat olive-interfaces/build/reports/detekt/detekt.xml | reviewdog -f=checkstyle -name="detekt" -reporter="github-pr-review" -level="info"

workflows Results PR 생성 후, Github Actions Workflow 실행

prWorkflows

detekt로 작성한 CustomRule을 체크하여 ReviewDog Comment 생성완료 👍

reviewdogComment




마무리

지금까지 더 나은 개발 문화를 위해 노력하는 올리브영 백엔드 개발자의 detekt + reviewdog + Github Actions 도입 과정을 공유해 드렸습니다.

MultiModule 프로젝트에 Custom Rule을 레퍼런스 문서만 보고 적용하기 쉽지 않았고, gradle의 버전 호환성으로 시행착오를 겪었습니다. 하지만 현재는 상품스쿼드의 신규 프로젝트에 도입되어 사용 중에 있습니다.

코드의 품질을 높이는 방법을 고민하시는 분들에게 도움이 되었으면 좋겠습니다. 😊

3


References

Detekt 공식문서
Reviewdog Github
GithubActions

detektreviewdogcode convention
올리브영 테크 블로그 작성 detekt와 reviewdog으로 코드 품질 향상
‍🐻‍❄️
빽곰 |
Back-end Engineer
개발은 너무 어려워요...