🤔

03-15-2020

귀찮은 것을 자동화 해보자 (1)

프로젝트 중 node 패키지가 추가됐는데 관련 사항을 전달 받지 못했거나, 특정 브랜치에 패키지가 추가됐는데 미처 파악하지 못했을 경우 빌드시 에러가 발생해 귀찮을 경우가 종종 있다. 추가되는 일이 생길 때 마다 동료 개발자에게 알려주거나 레이블을 달거나 할 수도 있겠지만 귀찮은 일이고, checkout 하거나 pull 받았을 때 자동으로 설치되는 쪽이 편할 것 같다.

0. git hooks

git에선 각 git 조작 단계에 맞춰 hook을 제공한다. .git/hooks 폴더 안에 hook 이름의 파일을 추가해 shell script를 작성해두면 해당 단계에 동작하게 된다.

패키지 설치가 필요한 단계는 아마도 checkout 후, 혹은 pull 후 일 것이고, 해당 단계의 git hook은 각각 post-checkoutpost-merge다. 이 포스트에선 일단 post-checkout 케이스부터 처리해본다1.

1. hook 추가하기

관련 hook과 같은 이름의 파일을 .git/ 폴더에 추가해주면 된다. 프로젝트 폴더의 root 위치에 있다고 가정하고, 파일을 추가하자. 확장자는 필요하지 않다.

touch .git/post-checkout

2. exec 권한 설정해주기

shell script를 실행하려면 exec 권한을 설정해주어야 한다.

chmod +x .git/post-checkout

3. 어떤 파일들이 바뀌었는지 보기

checkout 후 이전 브랜치와 비교해 바뀐 파일들의 목록은 아래 커맨드로 볼 수 있다.

git diff-tree -r --name-only --no-commit-id @{-1} HEAD

위 커맨드에서 @{-1}은 이전 브랜치의 HEAD, HEAD는 현재 브랜치의 HEAD를 가리킨다.

4. 바뀐 파일들 중 특정 문자열이 있나 보고 특정 커맨드를 실행하기

위 커맨드를 사용해 목록화한 파일명들을 grep으로 넘겨서 package-lock.json이 있을 경우, evalnpm ci를 실행시키면 될 것이다.

!#/bin/sh

# git 커맨드를 변수에 저장한다. 너무 기니까.
changed_files="$(git diff-tree -r --name-only --no-commit-id @{-1} HEAD)"

# git 커맨드를 거쳐 나온 파일명들 중 "package-lock.json" 있는지 보고, 있으면 "npm ci" 를 실행한다.
echo $changed_files | grep -q "package-lock.json" && eval "npm ci"

끝이다. 이제 위 git hook 스크립트가 있는 리포지토리는 이제 브랜치가 바뀔 때 마다 package-lock.json 파일을 체크하고 변경사항이 있으면 npm ci 를 실행하게 된다.

좀 더 재활용이 가능하도록 함수화 해보면, 아래와 같이 될 것이다.

!#/bin/sh

changed_files="$(git diff-tree -r --name-only --no-commit-id @{-1} HEAD)"

# 파일명 `$1`과 커맨드 `$2`를 받아 `$1`이 있으면 `$2`를 실행한다. 
check_and_run() {
    echo $changed_files | grep -q "$1" && eval "$2"
}

check_and_run package-lock.json "npm ci"

(끝)

Reference


  1. post-merge시엔 바뀐 파일을 보는 커맨드 중 @{-1}ORIG_HEAD로 바꿔주기만 하면 된다. git diff-tree -r --name-only --no-commit-id ORIG_HEAD HEAD

©2021 Sehyun Chung