팀 프로젝트를 시작할 때마다 마주하는 문제들은 항상 있지만 그 중에서 매번 나타나고 가장 신경 쓰이는 것은 코드 형식을 통일하는 방법이라고 생각합니다. 어떻게 하면 언제 어디서나 통일된 형식을 유지하고 환경 설정을 빠르게 할 수 있을까요? 이번 글에서 알아봅시다.

참고한 자료는 아래와 같습니다.

Spotless 적용하기

Spotless는 여러 언어에 대한 포매팅을 지원하는 프로그램입니다. 주로 JVM 언어 계열에서 사용하며 Gradle이나 Maven을 이용해 쉽게 사용하고 IDE와의 통합까지 가능합니다.

이번 글에서는 Gradle와 Java을 기준으로 설명합니다. 다른 환경의 경우 공식 레포지터리를 참고해주세요.

플러그인 추가

우선 build.gradle에 Spotless 플러그인을 추가합니다. 최신 버전은 이 곳에서 확인할 수 있습니다.

plugins {
  id "com.diffplug.spotless" version "6.25.0" // latest version
}

Spotless 설정 추가

다음으로 build.gradle에 Spotless 설정을 추가합니다.

spotless {
    java {
        importOrder()                       // (1)
        removeUnusedImports()               // (2)
        cleanthat()                         // (3)
        googleJavaFormat()                  // (4)
        formatAnnotations()                 // (5)
        licenseHeader '/* (C) $YEAR */'     // (6)
    }
}

각 설정 별 기능은 다음과 같습니다.

  1. importOrder(): import 순서를 변경합니다.
  2. removeUnusedImports(): 사용하지 않는 import를 제거합니다.
  3. cleanthat(): Cleanthat을 적용합니다.
  4. googleJavaFormat(): Google Java convention을 이용하여 코드를 포매팅합니다.
  5. formatAnnotations(): 애너테이션을 포매팅합니다.
  6. licenseHeader: 코드 상단에 라이센스 정보를 추가합니다.

위 설정은 가장 기본적인 설정이며 설정마다 추가로 커스텀 할 수 있는 옵션들이 존재합니다.

Spotless task 실행

마지막으로 Gradle을 다시 로드하면 Spotless와 관련된 task가 추가됩니다. 주요 task는 다음과 같습니다.

  • spotlessApply: 코드 포매팅 진행
  • spotlessCheck: 잘못된 코드 확인

Commit 할 때 자동으로 적용하기

Spotless를 사용하는 가장 큰 목적은 코드 포매팅입니다. 그러나 코드를 작성할 때마다 포매팅을 위해 task를 실행하는 것은 번거롭습니다. 따라서, Git hook을 이용하여 커밋할 때마다 자동으로 task를 실행하도록 구성해보겠습니다.

우선, 다음과 같은 쉘 스크립트 파일을 pre-commit이란 이름으로 저장합니다. 제 경우 scripts/pre-commit에 저장하였습니다.

#!/bin/sh

stagedFiles=$(git diff --staged --name-only)

./gradlew spotlessApply

for file in $stagedFiles; do
  if test -f "$file"; then
    git add $file
  fi
done

이후 해당 쉘 스크립트를 실행할 수 있도록 실행 권한을 부여합니다.

chmod +x scripts/pre-commit # Your scripts path

마지막으로 Git hook 폴더에 해당 스크립트를 복사하여 commit 시 Git이 스크립트를 실행하도록 합니다.

cp scripts/pre-commit .git/hooks/pre-commit

이제 Git을 이용하여 commit 할 때마다 Spotless task를 수행하게 됩니다.

새로운 환경에서 Git hook 쉽게 적용하기

.git 디렉토리는 원격 저장소에 저장되지 않으므로 환경마다 Git hook 설정을 해야합니다. 위에서 했던 방법처럼 수동으로 구성할 수 있지만 Gradle task를 이용하여 자동화할 수 있습니다.

Git hook 구성 task 추가

Git hook 구성을 처리하는 task를 build.gradle에 추가합니다.

task updateGitHooks(type: Copy) {
    from './scripts/pre-commit'
    into './.git/hooks'
}
compileJava.dependsOn(updateGitHooks) // Run updateGitHooks after compileJava task

Gradle을 다시 로드 후 updateGitHooks를 실행하면 Git hook 설정이 완료됩니다.

마지막 줄에 있는 compileJava.dependsOn(updateGitHooks)compileJava 실행 시 updateGitHooks를 자동으로 실행하는 코드입니다. 프로젝트를 실행하면 compileJava가 실행되므로 Git hook 구성을 깜빡하고 잊더라도 자동으로 구성하도록 설정하였습니다.

마무리하며

이번 글에서는 Gradle과 Java 환경에서 Spotless과 Git hook을 이용하여 코드 포매팅을 자동화하였습니다. 팀 프로젝트를 하면서 포매팅으로 귀찮았던 적이 있었다면 가볍게 사용해보시고 취향에 맞게 설정하여 원하는 환경을 구축할 수 있길 바랍니다!

댓글남기기