효율적인 개발환경을 위한 Git Hooks, Husky, 그리고 lint-staged

hodu·2024년 2월 12일
11
post-thumbnail

✅ 개요

오픈 소스 라이브러리를 분석하며 깨달은 점은, 세심한 환경 설정의 중요성입니다.
바쁜 일정 속에서도 이러한 설정에 주의를 기울이는 것이 코드에 더 집중할 수 있는 기반이 됩니다.

본 글에서는 pnpm과 모노레포 환경에서의 환경 설정 방법을 공유합니다.
모노레포가 아닌 경우도 고려하여서 글을 작성하였습니다.


😀 Git Hooks

Git Hooks는 Git의 특정 이벤트에 반응하여 자동으로 실행하는 스크립트입니다. 이를 활용하면 커밋, 푸시 등의 작업 전후에 커스텀 작업을 수행할 수 있습니다. 예를 들어, pre-commit Hook을 사용하면 커밋 전에 코드 스타일을 자동으로 검사할 수 있습니다.

Git Hooks 위치 및 예시

Git Hooks는 .git/hooks 디렉토리에 위치하며, 다양한 기본 스크립트를 제공합니다. 하지만 이러한 스크립트를 직접 수정하고 팀원 간에 공유하는 것은 번거로운 일입니다.

🚀 Husky를 통한 Git Hooks 관리

Husky를 사용하면 Git Hooks를 쉽게 관리하고 프로젝트에 통합할 수 있습니다. 이를 통해 코드 컨벤션 검사, 린트, 테스트 자동화 등을 구현할 수 있으며, 이는 팀의 협업 효율성을 크게 향상시킵니다.

Husky를 활용한 Git Hooks 설정 방법과 예시 코드를 소개하며, 모노레포 환경에서의 효과적인 환경 설정 전략을 제시합니다.

🐶 Husky를 이용한 Gitmoji 커밋 메시지 강제화

Git 커밋 메시지에 gitmoji를 사용하면, 커밋의 목적이나 변경 사항의 유형을 한눈에 알아보기 쉽게 만들 수 있습니다. Husky는 이러한 규칙을 프로젝트에 적용하고 강제하는 데 유용한 도구입니다.

💻 설치 및 초기 설정

Husky는 개발 의존성으로 프로젝트에 쉽게 추가할 수 있습니다. 모노레포와 같은 복잡한 프로젝트 구조에서는 루트 디렉토리에 Husky를 설치하는 것이 좋습니다.

# pnpm을 사용하는 경우
pnpm add --save-dev husky -w

# npm을 사용하는 경우
npm install --save-dev husky -w

모노레포가 아니라면 -w를 제거하면 됩니다.

# pnpm을 사용하는 경우
pnpm exec husky init

# npm을 사용하는 경우
npx husky init

husky init 명령어를 실행하면 Husky의 초기 설정이 진행되며, .husky 폴더와 아래와 같은 pre-commmit 훅이 생성됩니다.

.husky/pre-commit

echo "pre-commit 훅 테스트 중입니다."
exit 1

위처럼 작성을 하고 commit 을 해보겠습니다.

echo를 통해 문구를 보여줍니다.
exit 1은 commit이 올라가는 것을 막기 위해 넣었습니다
exit 0으로 작성하면 commit이 올라가고, 1일 경우에는 취소합니다.

이제 본격적으로 .husky 예제 파일을 통해 이를 사용해보겠습니다.

📝 커밋 메시지 검증 스크립트

gitmoji를 사용하면 커밋의 의도와 범위를 쉽게 파악할 수 있어, 커밋 로그를 더욱 명확하고 가독성 높게 만들 수 있습니다.

Husky를 사용하여 이를 자동화하는 방법을 예시로 소개합니다.

프로젝트 루트에 .husky/commit-msg 파일을 생성합니다.
commit-msg는 이름처럼 이를 검증하거나 다루는 훅을 작성합니다.

아래와 같은 스크립트를 추가합니다.

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

COMMIT_MESSAGE_FILE=$1
COMMIT_MESSAGE=$(cat "$COMMIT_MESSAGE_FILE")

if ! echo "$COMMIT_MESSAGE" | grep -qE "^:.+: .+"; then
  echo "💕 Please use gitmoji in your commit message"
  echo "💕 Commit message should follow the pattern: ^:[a-zA-Z]+: .+"
  exit 1
fi

echo "🔆 Thanks for keeping the convention 🔆"

이 스크립트는 Husky의 훅을 활용하여 커밋 메시지가 gitmoji 형식(:emoji:)을 따르는지 검증합니다. 여기서 사용된 변수 설명은 다음과 같습니다:

  • $0은 현재 실행 중인 스크립트의 경로를 나타냅니다. Husky 설정 스크립트를 로드하는 데 사용됩니다.
  • $1은 스크립트에 전달된 첫 번째 인자로, 커밋 메시지가 저장된 파일의 경로입니다. 이 파일에서 커밋 메시지를 읽어옵니다.
  • 부정문이 들어간 이유는 grep은 패턴과 일치하는 경우 실패로 간주합니다. 이를 통해 if문을 구분하였습니다.

🚀 테스트 및 적용

스크립트 적용 후, 실제 커밋을 시도해보면 다음과 같은 결과를 얻을 수 있습니다:

첫 번째 시도에서 gitmoji가 누락되어 커밋이 거부되었고, 두 번째 시도에서는 gitmoji가 포함되어 커밋이 성공적으로 이루어졌습니다. 이는 테스트 목적으로 exit 1을 포함시켰기 때문에 발생한 결과입니다.

이렇게 Husky와 gitmoji를 활용한 커밋 메시지 검증 스크립트를 통해, 프로젝트의 커밋 메시지에 일관성과 가독성을 높이고, 팀원 간의 커뮤니케이션 효율성을 개선할 수 있습니다.

이와 더불어 husky를 더 효율적으로 사용할 수 있는 2가지 라이브러리를 추가적으로 소개하겠습니다.

먼저 commit lint입니다.

commit lint를 활용한 커밋 메시지 규칙 강제

프로젝트의 커밋 메시지에 규칙을 적용하는 것은 코드베이스의 일관성을 유지하고, 변경 사항을 명확히 이해하는 데 중요합니다.
커밋 규칙이 많아지고 복잡해질수록 코드 관리의 어려움이 증가하는데, 이를 해결하기 위해 commit lint를 도입할 수 있습니다.

📦 설치 방법

commitlint는 프로젝트의 개발 의존성으로 추가됩니다. 모노레포와 같은 복잡한 프로젝트 구조에서는 루트 디렉토리에 설치하는 것이 좋습니다.

cli과 권장사항(config-conventional)을 같이 설치하도록 하겠습니다.

# pnpm을 사용하는 경우
pnpm add --save-dev @commitlint/{cli,config-conventional}

# npm을 사용하는 경우
npm install --save-dev @commitlint/{cli,config-conventional}

🛠 기본 설정

설치 후, 프로젝트에 commitlint.config.js 파일을 생성하여 기본 설정을 적용합니다. 다음 명령어를 사용하여 파일을 생성할 수 있습니다:

echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js

이 설정 파일은 extends: ['@commitlint/config-conventional']를 작성함으로써 commitlint가 제공하는 conventional 규칙을 확장하여 사용합니다.

✅ 검증 테스트

커밋 메시지를 검증하려면, 다음과 같이 테스트 커밋 메시지를 commitlint에 전달합니다:

echo 'foo: bar' | commitlint

이 명령은 foo: bar 형식의 커밋 메시지가 규칙에 부합하는지 검증합니다.

가장 최근의 커밋 또한 검증할 수 있으며, 모든 커밋의 규칙 준수 여부를 확인하기 위해서는 첫 커밋부터 현재까지의 커밋을 검증하면 됩니다

commitlint --from=<첫 커밋 해시>

위 실패한 이유가 적혀있는 것을 볼 수 있습니다.
우리가 extend를 통해 등록한 규칙입니다.
이에 관해 알아보도록 하겠습니다.

📋 commitlint.config.js의 규칙

@commitlint/config-conventional 확장을 사용하면 다음과 같은 규칙을 적용합니다.

  • type-enum: 커밋 타입이 feat, fix, docs 등으로 시작해야 합니다.
  • type-case: 커밋 타입은 소문자여야 합니다.
  • type-empty: 커밋 타입은 비어 있으면 안 됩니다.
  • subject-empty: 커밋 제목은 비어 있으면 안 됩니다.
  • header-max-length: 커밋 메시지의 헤더는 100자를 넘으면 안 됩니다.

이 규칙들은 필요에 따라 커스텀하여 조정할 수 있습니다.

🔄 Husky와의 통합

Husky를 사용하여 커밋 메시지 검증을 자동화할 수 있습니다. 다음과 같은 스크립트를 .husky/commit-msg 파일에 추가하여 커밋 시 commitlint를 통한 검증을 실행하도록 설정하겠습니다.

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

COMMIT_MESSAGE_FILE=$1
COMMIT_MESSAGE=$(cat "$COMMIT_MESSAGE_FILE")

echo "❤️‍🩹 Commit Message: $COMMIT_MESSAGE"

npx commitlint --edit $1

if [ $? -eq 0 ]; then
  echo "🔆 Commit message meets the convention 🔆"
  exit 0
else
  echo "❌ Commit message does not meet the convention ❌"
  exit 1
fi
  • $? -eq 0 를 활용하여서 직전에 실행한 명령어의 종료 코드를 확인합니다 0일 경우 성공, 1일 경우 실패입니다.

이 스크립트는 커밋 시 commitlint를 통해 커밋 메시지의 규칙 준수 여부를 검증하고, 결과에 따라 적절한 메시지를 출력합니다.

디테일하게 설정하고 싶다면 링크에서 확인할 수 있습니다.

이번에는 커밋 이전에 린트 검사를 추가하여서 ESLint 같은 검사를 자동화 하는 것을 만들어보겠습니다.
pre-commit에 이를 넣어주고 eslint를 돌리면 가능하지만, 기본적으로 모든 것을 검사하기 때문에 오래 걸립니다.

우리는 이때 lint-staged를 쓸 수 있습니다.


lint-staged로 효율적인 린트 자동화 구현

lint-staged는 Git에 스테이징된 파일들만을 대상으로 린트 검사를 실행하여, 효율적인 코드 검증 과정을 제공합니다.

📦 설치 방법

lint-staged는 개발 의존성으로 프로젝트에 추가됩니다. pnpm 또는 npm을 사용하여 설치할 수 있습니다.

# pnpm을 사용하는 경우
pnpm add -D lint-staged
 
# npm을 사용하는 경우
npm install --save-dev lint-staged

🛠 설정 방법

설치 후, 프로젝트의 package.json 파일에 lint-staged 설정을 추가합니다. 다음 예시는 JavaScript 및 TypeScript 파일에 ESLint를 적용하고, package.json 파일을 정렬하는 설정입니다:

"lint-staged": {
  "*.{js,jsx,ts,tsx}": [
    "eslint --fix"
  ],
  "package.json": [
    "pnpm lint:package"
  ]
},

여기서 eslint --fix 명령은 스테이징된 파일에 대해 ESLint 검사를 실행하고 자동으로 수정할 수 있는 문제를 수정합니다. pnpm lint:package 명령은 sort-package-json 라이브러리를 사용하여 package.json 파일을 정렬합니다.

🚀 husky와의 통합

린트 검사를 커밋 전 과정에 자동으로 통합하기 위해 husky의 pre-commit 훅을 사용합니다. .husky/pre-commit 파일을 생성하고 다음 스크립트를 추가합니다

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

echo "🔍 commit 이전에 lint 규칙을 적용합니다..."
if npx lint-staged; then
  echo "✅ 모든 lint 규칙이 성공적으로 적용되었습니다."
  exit 0
else
  echo "❌ lint 규칙 검사에서 오류가 발생했습니다."
  exit 1
fi

이 스크립트는 커밋을 시도하기 전에 lint-staged를 실행하여 설정된 린트 검사를 수행합니다. 검사가 성공적으로 완료되면 커밋이 진행되고, 오류가 발생하면 커밋이 중단됩니다.

✨ 실제 적용 결과

lint-staged와 husky를 통합한 결과, 커밋 시 스테이징된 파일에 대해서만 린트 검사가 실행되며, 이는 개발 효율성을 크게 향상시킵니다. 오류가 있는 경우 커밋 전에 바로 수정할 수 있어, 코드 품질 관리가 용이해집니다.

이러한 설정을 통해, 커밋 메시지의 규칙성을 commitlint로 관리하고, 코드 품질을 lint-staged로 자동 검사함으로써 프로젝트의 일관성과 품질을 유지할 수 있습니다. 이 방법은 특히 대규모 프로젝트나 모노레포 환경에서 그 효과가 극대화됩니다.


출처 :

https://github.com/storybookjs/design-system
https://typicode.github.io/husky/
https://dkmqflx.netlify.app/js-env/
https://github.com/xionhub/xion
https://commitlint.js.org/#/./guides-local-setup?id=guides-local-setup

profile
잘부탁드립니다.

0개의 댓글