개발/꿀팁

android 개발팀에서 husky로 git hook 공유하기

이도일 2024. 4. 19. 15:10

사건의 발단

현재 우리팀은 commit-msg title에 prefix로 브랜치 구분(feature / chore / hotfix…etc) 을 적용하고,

commit-msg content에 티켓 넘버를 자동으로 붙이는 hook을 적용중이다.

 

 

 

 

 

hook은 기본적으로 공유가 안 되어서, 굳이굳이 ignore를 풀고..

브랜치를 변경할 때마다 복잡한 cli 명령어를 쓰고…(매번 까먹어서 확인해야한다)

암튼 이런 짓을 해야하는데

 

 

 

 

 

husky 라는 node 모듈을 쓰면 hook의 공유가 가능하다는 것을 알게되었다!

 

 

 

게다가 앞으로 추가될(지 모를) 노드 모듈들과도

npm install

이 명령어 하나만으로 묶일 수 있다는 것!

 

 

물론 웹 개발자들과 다르게.. 안드로이드는 노드 모듈을 사용할 일이 많지않아서

npm install 하는것도 초반엔 매번 까먹겠지만

어쨌든 도입해보기로 했다.

 

 

 

 

 

 

 

 

 

 

 

 

 

설정 방법

  • 초기 설치
// Using npm
npx husky-init && npm install

// Using yarn
yarn dlx husky-init --yarn2 && yarn

// Using pnpm
pnpm dlx husky-init && pnpm install

 

  • 루트 프로젝트에 .husky 확인

 

  • 사용할 hook 파일 생성

  • 나는 두 개를 사용한다. (pre-commit은 자동으로 그냥 생성된다!)
    • commit-msg : 커밋 메세지 내용으로 티켓 넘버를 붙이기 위함
    • prepare-commit-msg : 커밋 메세지 타이틀에 구분을(feature / hotfix…) 를 붙이기 위함

 

  • hook file 내용 작성
# commit-msg

#!/bin/bash

COMMIT_MESSAGE_FILE_PATH=$1
MESSAGE=$(cat "$COMMIT_MESSAGE_FILE_PATH")

# 커밋 메시지가 있을 때만 티켓 넘버를 추가한다.
if [[ $(head -1 "$COMMIT_MESSAGE_FILE_PATH") == '' ]]; then
  exit 0
fi

# 브랜치 이름에서 마지막 '_' 이후의 문자열만 남긴다. '/'가 없다면 브랜치 전체 이름이 POSTFIX 된다.
# POSTFIX의 첫 번째 '-' 앞뒤의 문자열만 포함한다. '-'가 없다면 변경은 없다

POSTFIX=$(git branch | grep '\\*' | sed 's/* //' | sed 's/^.*\\///' | sed 's/^.*_//')

printf "%s\\n\\n[%s]" "$MESSAGE" "$POSTFIX" > "$COMMIT_MESSAGE_FILE_PATH"
# prepare-commit-msg

#!/bin/sh

COMMIT_MESSAGE_FILE_PATH=$1

# merge commit에 대해서는 prefix를 생성하지 않는다.
MERGE=$(grep -c -i 'merge' < "$COMMIT_MESSAGE_FILE_PATH" || true)
if [ "$MERGE" != "0" ] ; then
  exit 0
fi

TYPE=$(git branch | grep '\\*' | sed 's/\\* //' | sed 's/\\([^/]*\\).*/\\1/' || true)
DESCRIPTION=$(git config branch."$TYPE".description || true)

echo "$TYPE: $(cat "$COMMIT_MESSAGE_FILE_PATH")" > "$COMMIT_MESSAGE_FILE_PATH"
if [ -n "$DESCRIPTION" ]
then
   echo "" >> "$COMMIT_MESSAGE_FILE_PATH"
   echo "$DESCRIPTION" >> "$COMMIT_MESSAGE_FILE_PATH"
fi

→ 참고로 branch naming convention은 구분/티켓명_티켓넘버다.

 

  • package.json에 권한 설정
{
  "devDependencies": {
    "husky": "^9.0.11"
  },
  "scripts": {
    "prepare": "husky",
    "postinstall": "chmod +x .husky/"
  }
}

 

  • 커밋 메세지 확인

 

 

 

 

 

 

 

 

 

 

 

트러블 슈팅

파일 위치 문제

원래는 .husky 밑에 바로 hook 파일들을 넣어야한다..그걸 몰라서 .husky/_/하위 hook 파일의 내용을 고쳤다..... (git hook 설정시 내용 변경후 .sample확장자를 제거하면 되는것처럼)

 

당연히 저렇게 하면 안 된다. npm install시 저 파일이 덮어씌워진다.

.husky/_/ 하위 파일들은 .husky/ 하위 파일의 트리거일 뿐이다…..

이걸 몰라서 한참을 헤멨다

 

 

 

 

 

 

 

 

 

파일 권한 문제

훅 초기 세팅시에 권한이 없으면 커밋 메세지를 마음대로 커스텀 할 수 없다.

그래서… npm install시에 .husky/하위 파일의 권한을 올려주는 방식으로 해결했다

  • package.json에 권한 설정 부분이 그 결과물이다.

 

 

 

 

 

 

 

 

 

 

prepare-commit-msg hook 에러

husky - prepare-commit-msg script failed (code 1)

이런 에러가 발생했다…..시부레

 

 

 

수정 전 스크립트는 다음과 같다

#!/bin/sh

COMMIT_MESSAGE_FILE_PATH=$1

# merge commit에 대해서는 prefix를 생성하지 않는다.
MERGE=$(grep -c -i 'merge' < "$COMMIT_MESSAGE_FILE_PATH")
if [ "$MERGE" != "0" ] ; then
  exit 0
fi

TYPE=$(git branch | grep '\\*' | sed 's/\\* //' | sed 's/\\([^/]*\\).*/\\1/')
DESCRIPTION=$(git config branch."$TYPE".description)
echo "$TYPE: $(cat "$COMMIT_MESSAGE_FILE_PATH")" > "$COMMIT_MESSAGE_FILE_PATH"
if [ -n "$DESCRIPTION" ]
then
   echo "" >> "$COMMIT_MESSAGE_FILE_PATH"
   echo "$DESCRIPTION" >> "$COMMIT_MESSAGE_FILE_PATH"
fi

 

 

서브 커맨드의 종료 조건이 (ex: grep -c -i 'merge' < .git/COMMIT_EDITMSG) 의 리턴값이 에러로 잡혀서..

허스키는 이 경우 아예 exit을 시켜버리기 때문에 발생한 문제였다.

 

 

 

수정 후 스크립트

#!/bin/sh

COMMIT_MESSAGE_FILE_PATH=$1

# merge commit에 대해서는 prefix를 생성하지 않는다.
MERGE=$(grep -c -i 'merge' < "$COMMIT_MESSAGE_FILE_PATH" || true)
if [ "$MERGE" != "0" ] ; then
  exit 0
fi

TYPE=$(git branch | grep '\\*' | sed 's/\\* //' | sed 's/\\([^/]*\\).*/\\1/' || true)
DESCRIPTION=$(git config branch."$TYPE".description || true)

echo "$TYPE: $(cat "$COMMIT_MESSAGE_FILE_PATH")" > "$COMMIT_MESSAGE_FILE_PATH"
if [ -n "$DESCRIPTION" ]
then
   echo "" >> "$COMMIT_MESSAGE_FILE_PATH"
   echo "$DESCRIPTION" >> "$COMMIT_MESSAGE_FILE_PATH"
fi

 

서브 커맨드에서 true를 반환하도록 수정했다.

이 에러 때문에 진짜 한 3시간은 쓴 것 같은데ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ

아무튼 해결.

 

 

 

 

 

 

 

 

 

 

 

결론

이왕 node module을 쓰게 된 거..

다양한 프로젝트 세팅에 필요한 모듈들을 찾아서 적용해봐야겠다.