fix(commit): AGENTS 규칙과 커밋 메시지 검사 스크립트를 정합화한다
This commit is contained in:
@@ -118,10 +118,16 @@ fix(member): 마이페이지 API의 null 인증 주체 처리를 보완한다
|
|||||||
refactor(content): 랭킹 조회 로직을 전용 리포지토리로 분리한다
|
refactor(content): 랭킹 조회 로직을 전용 리포지토리로 분리한다
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 커밋 메시지 검증 절차
|
||||||
|
- `git commit` 실행 직전에 `work/scripts/check-commit-message-rules.sh`를 실행해 규칙 준수 여부를 확인한다.
|
||||||
|
- `git commit` 실행 직후에도 `work/scripts/check-commit-message-rules.sh`를 다시 실행해 최종 메시지를 재검증한다.
|
||||||
|
- 스크립트 결과가 `[FAIL]`이면 커밋 메시지를 규칙에 맞게 수정한 뒤 다시 검증한다.
|
||||||
|
|
||||||
## 작업 절차 체크리스트
|
## 작업 절차 체크리스트
|
||||||
- 변경 전: 유사 기능 코드를 먼저 찾아 네이밍/예외/응답 패턴을 맞춘다.
|
- 변경 전: 유사 기능 코드를 먼저 찾아 네이밍/예외/응답 패턴을 맞춘다.
|
||||||
- 변경 중: 공개 API 스키마를 임의 변경하지 말고, 작은 단위로 안전하게 수정한다.
|
- 변경 중: 공개 API 스키마를 임의 변경하지 말고, 작은 단위로 안전하게 수정한다.
|
||||||
- 변경 후: 최소 단일 테스트 또는 `./gradlew test`를 실행하고, 필요 시 `./gradlew ktlintCheck`를 수행한다.
|
- 변경 후: 최소 단일 테스트 또는 `./gradlew test`를 실행하고, 필요 시 `./gradlew ktlintCheck`를 수행한다.
|
||||||
|
- 커밋 전/후: `git commit` 직전과 직후에 `work/scripts/check-commit-message-rules.sh`를 실행해 커밋 메시지 규칙 준수 여부를 확인한다.
|
||||||
|
|
||||||
## 작업 계획 문서 규칙 (docs)
|
## 작업 계획 문서 규칙 (docs)
|
||||||
- 모든 작업 시작 전에 `docs` 폴더 아래에 계획 문서를 먼저 생성하고, 해당 문서를 기준으로 구현을 진행한다.
|
- 모든 작업 시작 전에 `docs` 폴더 아래에 계획 문서를 먼저 생성하고, 해당 문서를 기준으로 구현을 진행한다.
|
||||||
|
|||||||
15
docs/20260220_커밋메시지검증규칙추가.md
Normal file
15
docs/20260220_커밋메시지검증규칙추가.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# 20260220 커밋 메시지 검증 규칙 추가
|
||||||
|
|
||||||
|
## 구현 계획
|
||||||
|
- [x] AGENTS.md의 커밋 메시지 규칙 섹션에 커밋 전/후 검증 절차를 추가한다.
|
||||||
|
- [x] AGENTS.md의 작업 절차 체크리스트에 커밋 전/후 스크립트 실행 규칙을 추가한다.
|
||||||
|
- [x] 문서 변경 검증을 위해 `./gradlew tasks --all`을 실행한다.
|
||||||
|
- [x] AGENTS.md 커밋 메시지 규칙과 불일치하는 `work/scripts/check-commit-message-rules.sh` 검증 로직을 정합성 있게 수정한다.
|
||||||
|
- [x] 수정한 스크립트에 대해 문법 및 실행 검증을 수행한다.
|
||||||
|
|
||||||
|
## 검증 기록
|
||||||
|
- [x] 검증 결과를 작업 완료 후 기록한다.
|
||||||
|
|
||||||
|
- 무엇을: `AGENTS.md`에 커밋 전/후 검증 절차를 추가했고, `work/scripts/check-commit-message-rules.sh`를 AGENTS.md 기준(Conventional Commit 형식, 소문자 type, 한글 description, `Refs:` footer 형식)으로 정합성 있게 수정했다.
|
||||||
|
- 왜: 문서 규칙과 실제 검증 로직이 어긋나면 커밋 메시지 정책이 일관되게 강제되지 않기 때문이다.
|
||||||
|
- 어떻게 검증했는지: `bash -n ./work/scripts/check-commit-message-rules.sh`, 유효/무효 메시지 실행 검증(`--message`), `Refs` footer 유효/무효 케이스 검증을 수행했다. 추가로 `./gradlew tasks --all`과 `./gradlew build`를 실행해 저장소 명령 유효성과 전체 빌드 성공(`BUILD SUCCESSFUL`)을 확인했다.
|
||||||
@@ -1,71 +1,121 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
# Check if a commit message follows project rules
|
print_usage() {
|
||||||
# Rules: 50/72 formatting, no advertisements/branding
|
echo "Usage:"
|
||||||
# Usage: ./check-commit-message-rules.sh [commit-hash]
|
echo " $0"
|
||||||
# If no commit-hash is provided, checks the latest commit
|
echo " $0 <commit-hash>"
|
||||||
|
echo " $0 --message \"<commit-message>\""
|
||||||
|
echo " $0 --message-file <file-path>"
|
||||||
|
}
|
||||||
|
|
||||||
# Determine which commit to check
|
load_commit_message() {
|
||||||
if [ $# -eq 0 ]; then
|
if [ $# -eq 0 ]; then
|
||||||
commit_ref="HEAD"
|
local commit_ref="HEAD"
|
||||||
echo "Checking latest commit..."
|
echo "Checking latest commit..." >&2
|
||||||
else
|
git log -1 --pretty=format:"%s%n%b" "$commit_ref"
|
||||||
commit_ref="$1"
|
return
|
||||||
echo "Checking commit: $commit_ref"
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
# Get the commit message
|
case "$1" in
|
||||||
commit_message=$(git log -1 --pretty=format:"%s%n%b" "$commit_ref")
|
-h|--help)
|
||||||
|
print_usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
--message)
|
||||||
|
shift
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
|
echo "[FAIL] --message option requires a commit message"
|
||||||
|
print_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Checking provided commit message..." >&2
|
||||||
|
printf '%s' "$*"
|
||||||
|
;;
|
||||||
|
--message-file)
|
||||||
|
shift
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
echo "[FAIL] --message-file option requires a file path"
|
||||||
|
print_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ ! -f "$1" ]; then
|
||||||
|
echo "[FAIL] Commit message file not found: $1"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Checking commit message file: $1" >&2
|
||||||
|
cat "$1"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
echo "[FAIL] Invalid arguments"
|
||||||
|
print_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Split into subject and body
|
local commit_ref="$1"
|
||||||
subject=$(echo "$commit_message" | head -n1)
|
if ! git rev-parse --verify "$commit_ref^{commit}" >/dev/null 2>&1; then
|
||||||
body=$(echo "$commit_message" | tail -n +2 | sed '/^$/d')
|
echo "[FAIL] Invalid commit reference: $commit_ref"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Checking commit: $commit_ref" >&2
|
||||||
|
git log -1 --pretty=format:"%s%n%b" "$commit_ref"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
commit_message=$(load_commit_message "$@")
|
||||||
|
subject=$(printf '%s\n' "$commit_message" | head -n1)
|
||||||
|
body=$(printf '%s\n' "$commit_message" | tail -n +2)
|
||||||
|
|
||||||
echo "Checking commit message format..."
|
echo "Checking commit message format..."
|
||||||
echo "Subject: $subject"
|
echo "Subject: $subject"
|
||||||
|
|
||||||
# Check subject line length
|
exit_code=0
|
||||||
subject_length=${#subject}
|
|
||||||
if [ $subject_length -gt 50 ]; then
|
if [ -z "$subject" ]; then
|
||||||
echo "[FAIL] Subject line too long: $subject_length characters (max 50)"
|
echo "[FAIL] Subject must not be empty"
|
||||||
exit_code=1
|
exit 1
|
||||||
else
|
|
||||||
echo "[PASS] Subject line length OK: $subject_length characters"
|
|
||||||
exit_code=0
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check body line lengths if body exists
|
subject_pattern='^([a-z]+)(\([a-z0-9._/-]+\))?(!)?: (.+)$'
|
||||||
if [ -n "$body" ]; then
|
if [[ "$subject" =~ $subject_pattern ]]; then
|
||||||
echo "Checking body line lengths..."
|
type="${BASH_REMATCH[1]}"
|
||||||
while IFS= read -r line; do
|
description="${BASH_REMATCH[4]}"
|
||||||
line_length=${#line}
|
|
||||||
if [ $line_length -gt 72 ]; then
|
|
||||||
echo "[FAIL] Body line too long: $line_length characters (max 72)"
|
|
||||||
echo "Line: $line"
|
|
||||||
exit_code=1
|
|
||||||
fi
|
|
||||||
done <<< "$body"
|
|
||||||
|
|
||||||
if [ $exit_code -eq 0 ]; then
|
echo "[PASS] Subject follows Conventional Commit format"
|
||||||
echo "[PASS] All body lines within 72 characters"
|
echo "[PASS] Type is lowercase: $type"
|
||||||
|
|
||||||
|
if printf '%s\n' "$description" | grep -Eq '[가-힣]'; then
|
||||||
|
echo "[PASS] Description contains Korean text"
|
||||||
|
else
|
||||||
|
echo "[FAIL] Description must contain Korean text"
|
||||||
|
exit_code=1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "[INFO] No body content to check"
|
echo "[FAIL] Subject must match: <type>(scope): <description>"
|
||||||
|
echo " scope is optional, example: feat: 기능을 추가한다"
|
||||||
|
exit_code=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check for advertisements, branding, or promotional content
|
if [ -n "$body" ] && printf '%s\n' "$body" | grep -Eq '^Refs:'; then
|
||||||
echo "Checking for advertisements and branding..."
|
while IFS= read -r refs_line; do
|
||||||
if echo "$commit_message" | grep -qi "generated with\|claude code\|anthropic\|co-authored-by.*claude\|🤖"; then
|
if ! printf '%s\n' "$refs_line" | grep -Eq '^Refs: #[0-9]+(, #[0-9]+)*$'; then
|
||||||
echo "[FAIL] Commit message contains advertisements, branding, or promotional content"
|
echo "[FAIL] Refs footer format is invalid: $refs_line"
|
||||||
exit_code=1
|
echo " expected format: Refs: #123 or Refs: #123, #456"
|
||||||
else
|
exit_code=1
|
||||||
echo "[PASS] No advertisements or branding detected"
|
fi
|
||||||
|
done < <(printf '%s\n' "$body" | grep -E '^Refs:')
|
||||||
|
|
||||||
|
if [ $exit_code -eq 0 ]; then
|
||||||
|
echo "[PASS] Refs footer format is valid"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ $exit_code -eq 0 ]; then
|
if [ $exit_code -eq 0 ]; then
|
||||||
echo "[PASS] Commit message follows all rules"
|
echo "[PASS] Commit message follows AGENTS.md rules"
|
||||||
else
|
else
|
||||||
echo "[FAIL] Commit message violates project rules"
|
echo "[FAIL] Commit message violates AGENTS.md rules"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exit $exit_code
|
exit $exit_code
|
||||||
|
|||||||
Reference in New Issue
Block a user