Git hooks 이란? (+ Husky + lint-staged)
Git Hook을 이용해 코드 포맷팅 체크와 커밋 메시지 검증하기
.git/hooks 폴더에 위치한 shell 스크립트
연동하여 사용할 코드는 동일한 폴더(.git/hooks)에 저장
commit 시 가장 먼저 호출 (commit 메시지 작성 전에 호출됨)
exit code가 0이 아니면 커밋이 취소됨
코드 스타일 검사, 유닛 테스트 실행 등
commit이 생성된 이후, 편집기를 실행하기 전
입력으로 커밋 메시지 경로와 커밋 종류를 입력받음
commit 메시지를 자동으로 생성하는 용도
최종적으로 커밋이 완료되기 직전
입력으로 커밋 메시지 경로를 입력받음
exit code가 0이 아니면 커밋이 취소됨
생성된 커밋 메시지 템플릿 검증하는 용도
push 전후에 실행되어 복잡한 push 정책을 만드는 용도
push 전에 실행되는 훅은 0이 아닌 값을 반환시 push를 거절하고 클라이언트로 에러 메시지 전달
.git/gitmessage# <타입>: <제목> 의 형식으로 커밋 제목을 아래 공백줄에 작성
# 제목은 50자 이내 / 변경사항이 "무엇"인지 명확히 작성 / 끝에 마침표 금지
#### 제목 작성 시작 ####
#### 제목 작성 끝 #### (아랫 줄 공백은 지우지 말 것)
# 본문(구체적인 커밋 내용)을 아랫줄에 작성
# 한 줄은 72자 이내 / 여러 줄의 메시지를 작성할 땐 "-"로 구분
#### 본문 작성 시작 ####
#### 본문 작성 끝 ####
# 꼬릿말을 아랫줄에 작성 (현재 커밋과 관련된 이슈 번호 추가 등)
#### 꼬릿말 작성 시작 ####
#### 꼬릿말 작성 끝 ####
#############################
# 커밋 메시지 예시
# feat: 로그인 기능 추가
#
# - login_by_email() 함수 생성
# - login_by_sns() 함수 생성
#
# Close #7
# 타입 종류
# feat: 새로운 기능 추가
# fix: 버그 수정
# docs: 문서 수정
# test: 테스트 코드 추가
# refact: 코드 리팩토링
# style: 코드 의미에 영향을 주지 않는 변경사항
# chore: 빌드 부분 혹은 패키지 매니저 수정사항.git/hooks/verify_commit_msg.py#!/usr/bin/python3
import re
import sys
import io
type_list = [
"feat",
"fix",
"refactor",
"style",
"docs",
"test",
"chore",
"ci",
"perf",
]
type_regex = (
r"^(feat|fix|refactor|style|docs|test|chore|ci|perf)(\(.+\))?\:\s(.{3,})"
)
class bcolors:
FAIL = "\033[91m"
ENDC = "\033[0m"
def verify_commit_message():
commit_msg_path = sys.argv[1]
try:
# Open the COMMIT_EDITMSG file with utf-8 encoding
with io.open(commit_msg_path, "r", encoding="utf-8") as commit:
lines = commit.readlines()
# Remove comments
lines = [line for line in lines if not line.startswith("#")]
# If the last line is whitespace, remove it
while lines[-1] == "\n":
lines = lines[:-1]
if len(lines) == 0:
break
# Empty commit message
if len(lines) == 0:
sys.stderr.write(
f"\n{bcolors.FAIL} Commit failed: {bcolors.ENDC}커밋 메시지가 비어있습니다.\n"
)
sys.exit(1)
# Subject line should be less than 50 characters.
if len(lines[0]) > 50:
sys.stderr.write(
f"\n{bcolors.FAIL} Commit failed: {bcolors.ENDC}커밋 메시지 제목을 50자 이내로 작성하세요.\n"
)
sys.exit(1)
# Subject line should follow the rule.
if re.match(f"({type_regex})", lines[0]) is None:
sys.stderr.write(
f"\n{bcolors.FAIL} Commit failed: {bcolors.ENDC}커밋 메시지 제목 규칙을 확인하세요."
)
sys.stderr.write("\n<type>: <subject> is required.\n")
sys.exit(1)
# The subject should be a title-case.
# if not lines[0].split(":")[1].strip()[0].istitle():
# sys.stderr.write(
# f"\n{bcolors.FAIL} Commit failed: {bcolors.ENDC}The subject should be title-cased.\n"
# )
# sys.exit(1)
# If commit message has single line, description might be missing.
if len(lines) == 1:
sys.stderr.write(
f"\n{bcolors.FAIL} Commit failed: {bcolors.ENDC}커밋 설명을 추가하세요.\n"
)
sys.exit(1)
# After subject line, line space is required.
if lines[1] != "\n":
sys.stderr.write(
"\n제목 뒤 빈 칸을 한 줄 추가하세요.\n"
)
sys.exit(1)
for line in lines[2:]:
# Every single description should be less than 72 characters.
if len(line) > 72:
sys.stderr.write(
"\n커밋 설명의 각 행은 72자 이내로 작성하세요.\n"
)
sys.exit(1)
# Description starts with "-".
if len(lines) > 3 and not line.startswith("-"):
sys.stderr.write(line)
sys.stderr.write(
f"\n{bcolors.FAIL} Commit failed: {bcolors.ENDC}커밋 설명이 2줄 이상인 경우 각 항목을 '-'로 시작하세요.\n"
)
sys.exit(1)
except Exception as e:
print(f"\n{bcolors.FAIL} Commit failed: {bcolors.ENDC}An error occurred: {e}\n")
sys.exit(1)
sys.exit(0)
if __name__ == "__main__":
verify_commit_message().git/hooks/commit-msg#!/bin/sh
python .git/hooks/verify_commit_msg.py "$1"
if [ $? -ne 0 ]; then
echo "Error: Commit message verification failed."
exit 1
fi
echo "Commit message verification successful."
exit 0실패 케이스


성공 케이스

