feat: add commit message validation scripts
This commit is contained in:
commit
6ca6480c96
2 changed files with 247 additions and 0 deletions
78
hooks/pre-recieve.sh
Normal file
78
hooks/pre-recieve.sh
Normal file
|
@ -0,0 +1,78 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Semantic commit pattern:
|
||||
# feat|fix|docs|style|refactor|test|perf|build|ci|chore|revert(optional scope): message
|
||||
# Allow dots (.), uppercase letters, and other common filename characters in scope
|
||||
PATTERN='^(feat|fix|docs|style|refactor|test|perf|build|ci|chore|revert)(\([a-zA-Z0-9\-\.\_]+\))?: .{1,}$'
|
||||
|
||||
# Pattern for merge commits from pull requests - simplified to catch all formats
|
||||
PR_MERGE_PATTERN='^Merge pull request'
|
||||
|
||||
# Pattern for standard Git merge commits
|
||||
GIT_MERGE_PATTERN='^Merge (branch|remote-tracking branch) .+ into .+$'
|
||||
|
||||
# Set text colors
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
INVALID_COMMITS=0
|
||||
|
||||
# Read stdin (format: <old-value> <new-value> <ref-name>)
|
||||
while read -r OLD_REV NEW_REV REF_NAME; do
|
||||
# Skip if it's a branch deletion
|
||||
if [[ "$NEW_REV" = "0000000000000000000000000000000000000000" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Skip if it's a new branch (no old revision)
|
||||
if [[ "$OLD_REV" = "0000000000000000000000000000000000000000" ]]; then
|
||||
OLD_REV=$(git rev-list --max-parents=0 "$NEW_REV")
|
||||
fi
|
||||
|
||||
echo -e "${YELLOW}Checking commits in $REF_NAME${NC}"
|
||||
|
||||
# Get all commit hashes between old and new revision
|
||||
COMMITS=$(git rev-list "$OLD_REV".."$NEW_REV")
|
||||
|
||||
# Check each commit message
|
||||
for COMMIT in $COMMITS; do
|
||||
COMMIT_MSG=$(git log --format=%B -n 1 "$COMMIT")
|
||||
COMMIT_SUBJECT=$(echo "$COMMIT_MSG" | head -n 1)
|
||||
PARENT_COUNT=$(git rev-list --parents -n 1 "$COMMIT" | awk '{print NF - 1}')
|
||||
|
||||
# Skip validation for merge commits (both PR merges and standard Git merges)
|
||||
if [[ $PARENT_COUNT -gt 1 ]] && ([[ "$COMMIT_SUBJECT" =~ $PR_MERGE_PATTERN ]] || [[ "$COMMIT_SUBJECT" =~ $GIT_MERGE_PATTERN ]]); then
|
||||
echo -e "${BLUE}➜ Skipping merge commit:${NC} $COMMIT_SUBJECT"
|
||||
continue
|
||||
fi
|
||||
|
||||
if ! [[ "$COMMIT_SUBJECT" =~ $PATTERN ]]; then
|
||||
echo -e "${RED}✗ Invalid commit message:${NC} $COMMIT_SUBJECT"
|
||||
echo -e "${RED} Commit:${NC} $COMMIT"
|
||||
echo -e "${YELLOW} Message should follow semantic commit format:${NC}"
|
||||
echo -e " type(scope): message"
|
||||
echo -e " ${YELLOW}where type is one of:${NC} feat, fix, docs, style, refactor, test, perf, build, ci, chore, revert"
|
||||
echo ""
|
||||
INVALID_COMMITS=$((INVALID_COMMITS + 1))
|
||||
else
|
||||
echo -e "${GREEN}✓ Valid commit:${NC} $COMMIT_SUBJECT"
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
# If any commits were invalid, reject the push
|
||||
if [[ $INVALID_COMMITS -gt 0 ]]; then
|
||||
echo -e "${RED}Push rejected: $INVALID_COMMITS commit(s) have invalid messages.${NC}"
|
||||
echo -e "${YELLOW}Please rewrite your commit messages to follow the semantic commit format:${NC}"
|
||||
echo "type(scope): message"
|
||||
echo "Examples:"
|
||||
echo " feat(auth): add login with Google"
|
||||
echo " fix: correct calculation in billing module"
|
||||
echo " style(release.yml): format permissions section in YAML"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
169
verify-commits.sh
Normal file
169
verify-commits.sh
Normal file
|
@ -0,0 +1,169 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Semantic commit pattern:
|
||||
# feat|fix|docs|style|refactor|test|perf|build|ci|chore|revert(optional scope): message
|
||||
# Allow dots (.), uppercase letters, and other common filename characters in scope
|
||||
PATTERN='^(feat|fix|docs|style|refactor|test|perf|build|ci|chore|revert)(\([a-zA-Z0-9\-\.\_]+\))?: .{1,}$'
|
||||
|
||||
# Pattern for merge commits from pull requests - simplified to catch all formats
|
||||
PR_MERGE_PATTERN='^Merge pull request'
|
||||
|
||||
# Pattern for standard Git merge commits
|
||||
GIT_MERGE_PATTERN='^Merge (branch|remote-tracking branch) .+ into .+$'
|
||||
|
||||
# Counters for reporting
|
||||
TOTAL_COMMITS=0
|
||||
VALID_COMMITS=0
|
||||
INVALID_COMMITS=0
|
||||
MERGE_COMMITS=0
|
||||
|
||||
# Check if colors should be used
|
||||
USE_COLORS=1
|
||||
if [ "$1" = "--no-color" ] || [ "$1" = "-n" ]; then
|
||||
USE_COLORS=0
|
||||
fi
|
||||
|
||||
# Define color functions that check if colors should be used
|
||||
color() {
|
||||
if [ $USE_COLORS -eq 1 ] && [ -t 1 ]; then
|
||||
case "$1" in
|
||||
"red") echo -en "\033[0;31m" ;;
|
||||
"green") echo -en "\033[0;32m" ;;
|
||||
"yellow") echo -en "\033[0;33m" ;;
|
||||
"blue") echo -en "\033[0;34m" ;;
|
||||
"reset") echo -en "\033[0m" ;;
|
||||
esac
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check if current directory is a Git repository
|
||||
check_git_repo() {
|
||||
if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
|
||||
color "red"
|
||||
echo "Error: This is not a Git repository"
|
||||
color "reset"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Ask for commit range or use default
|
||||
get_commit_range() {
|
||||
color "yellow"
|
||||
echo "Enter commit range to check (default: all commits):"
|
||||
color "reset"
|
||||
echo "Examples:"
|
||||
echo " - HEAD~10..HEAD (last 10 commits)"
|
||||
echo " - main..feature (commits in feature branch not in main)"
|
||||
echo " - Press Enter for all commits"
|
||||
read -r RANGE
|
||||
|
||||
if [ -z "$RANGE" ]; then
|
||||
RANGE="--all"
|
||||
fi
|
||||
|
||||
color "yellow"
|
||||
echo "Checking commits in range: "
|
||||
color "reset"
|
||||
echo "$RANGE"
|
||||
}
|
||||
|
||||
# Initialize
|
||||
check_git_repo
|
||||
get_commit_range
|
||||
|
||||
# Get all commit hashes
|
||||
if [ "$RANGE" = "--all" ]; then
|
||||
COMMITS=$(git log --format="%H")
|
||||
else
|
||||
COMMITS=$(git log "$RANGE" --format="%H")
|
||||
fi
|
||||
|
||||
# Check each commit message
|
||||
for COMMIT in $COMMITS; do
|
||||
TOTAL_COMMITS=$((TOTAL_COMMITS + 1))
|
||||
COMMIT_MSG=$(git log --format=%B -n 1 "$COMMIT")
|
||||
COMMIT_SUBJECT=$(echo "$COMMIT_MSG" | head -n 1)
|
||||
COMMIT_DATE=$(git show -s --format=%ci "$COMMIT")
|
||||
COMMIT_AUTHOR=$(git show -s --format="%an <%ae>" "$COMMIT")
|
||||
PARENT_COUNT=$(git rev-list --parents -n 1 "$COMMIT" | awk '{print NF - 1}')
|
||||
|
||||
echo
|
||||
color "yellow"
|
||||
echo -n "Commit: "
|
||||
color "reset"
|
||||
echo "${COMMIT:0:8} - $COMMIT_DATE - $COMMIT_AUTHOR"
|
||||
echo " $COMMIT_SUBJECT"
|
||||
|
||||
# Check if it's a merge commit
|
||||
if [ $PARENT_COUNT -gt 1 ] && (echo "$COMMIT_SUBJECT" | grep -E "$PR_MERGE_PATTERN" >/dev/null || echo "$COMMIT_SUBJECT" | grep -E "$GIT_MERGE_PATTERN" >/dev/null); then
|
||||
color "blue"
|
||||
echo -n " ➜ Merge commit (exempt from validation)"
|
||||
color "reset"
|
||||
echo
|
||||
MERGE_COMMITS=$((MERGE_COMMITS + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
# Validate against semantic pattern
|
||||
if echo "$COMMIT_SUBJECT" | grep -E "$PATTERN" >/dev/null; then
|
||||
color "green"
|
||||
echo -n " ✓ Valid semantic commit"
|
||||
color "reset"
|
||||
echo
|
||||
VALID_COMMITS=$((VALID_COMMITS + 1))
|
||||
else
|
||||
color "red"
|
||||
echo -n " ✗ Invalid commit message"
|
||||
color "reset"
|
||||
echo
|
||||
color "yellow"
|
||||
echo -n " Should follow pattern:"
|
||||
color "reset"
|
||||
echo " type(scope): message"
|
||||
INVALID_COMMITS=$((INVALID_COMMITS + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
# Print summary
|
||||
echo
|
||||
color "yellow"
|
||||
echo "========== Validation Summary =========="
|
||||
color "reset"
|
||||
echo "Total commits checked: ${TOTAL_COMMITS}"
|
||||
|
||||
color "green"
|
||||
echo -n "Valid semantic commits: ${VALID_COMMITS}"
|
||||
color "reset"
|
||||
echo
|
||||
|
||||
color "blue"
|
||||
echo -n "Merge commits (exempted): ${MERGE_COMMITS}"
|
||||
color "reset"
|
||||
echo
|
||||
|
||||
color "red"
|
||||
echo -n "Invalid semantic commits: ${INVALID_COMMITS}"
|
||||
color "reset"
|
||||
echo
|
||||
|
||||
# Print percentage
|
||||
if [ $TOTAL_COMMITS -gt 0 ]; then
|
||||
VALID_PERCENT=$((($VALID_COMMITS + $MERGE_COMMITS) * 100 / $TOTAL_COMMITS))
|
||||
echo "Compliance rate: ${VALID_PERCENT}%"
|
||||
|
||||
if [ $INVALID_COMMITS -gt 0 ]; then
|
||||
echo
|
||||
color "yellow"
|
||||
echo "Recommendations:"
|
||||
color "reset"
|
||||
echo "- Review invalid commits and consider amending them for consistency"
|
||||
echo "- Run this script periodically to ensure commit message standards"
|
||||
else
|
||||
echo
|
||||
color "green"
|
||||
echo "All commits comply with semantic commit standards!"
|
||||
color "reset"
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
Loading…
Add table
Add a link
Reference in a new issue