|
| 1 | +#!/bin/bash |
| 2 | + |
| 3 | +# Commit-msg hook for TelemetryFlow projects |
| 4 | +# Enforces Conventional Commits format |
| 5 | +# https://www.conventionalcommits.org/ |
| 6 | + |
| 7 | +set -e |
| 8 | + |
| 9 | +COMMIT_MSG_FILE=$1 |
| 10 | +COMMIT_MSG=$(cat "$COMMIT_MSG_FILE") |
| 11 | + |
| 12 | +# Colors for output |
| 13 | +RED='\033[0;31m' |
| 14 | +GREEN='\033[0;32m' |
| 15 | +YELLOW='\033[1;33m' |
| 16 | +NC='\033[0m' # No Color |
| 17 | + |
| 18 | +# Skip merge commits |
| 19 | +if echo "$COMMIT_MSG" | grep -qE "^Merge"; then |
| 20 | + exit 0 |
| 21 | +fi |
| 22 | + |
| 23 | +# Conventional commit pattern |
| 24 | +# Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert |
| 25 | +# Optional scope in parentheses |
| 26 | +# Optional breaking change indicator (!) |
| 27 | +# Colon and space, then description |
| 28 | +PATTERN="^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?(!)?: .{1,}" |
| 29 | + |
| 30 | +# Check if commit message follows conventional commits format |
| 31 | +if ! echo "$COMMIT_MSG" | head -1 | grep -qE "$PATTERN"; then |
| 32 | + echo -e "${RED}ERROR: Commit message does not follow Conventional Commits format.${NC}" |
| 33 | + echo "" |
| 34 | + echo -e "${YELLOW}Your commit message:${NC}" |
| 35 | + echo "$COMMIT_MSG" | head -1 |
| 36 | + echo "" |
| 37 | + echo -e "${YELLOW}Expected format:${NC}" |
| 38 | + echo " <type>[optional scope][!]: <description>" |
| 39 | + echo "" |
| 40 | + echo -e "${YELLOW}Allowed types:${NC}" |
| 41 | + echo " feat: A new feature" |
| 42 | + echo " fix: A bug fix" |
| 43 | + echo " docs: Documentation only changes" |
| 44 | + echo " style: Code style changes (formatting, semicolons, etc)" |
| 45 | + echo " refactor: Code change that neither fixes a bug nor adds a feature" |
| 46 | + echo " perf: Performance improvement" |
| 47 | + echo " test: Adding or updating tests" |
| 48 | + echo " build: Build system or external dependency changes" |
| 49 | + echo " ci: CI configuration changes" |
| 50 | + echo " chore: Other changes that don't modify src or test files" |
| 51 | + echo " revert: Reverts a previous commit" |
| 52 | + echo "" |
| 53 | + echo -e "${YELLOW}Examples:${NC}" |
| 54 | + echo " feat: add user authentication" |
| 55 | + echo " fix(api): resolve null pointer in handler" |
| 56 | + echo " docs: update README with installation steps" |
| 57 | + echo " feat(auth)!: change token format (breaking change)" |
| 58 | + echo "" |
| 59 | + exit 1 |
| 60 | +fi |
| 61 | + |
| 62 | +# Check minimum description length (at least 10 characters after the type) |
| 63 | +DESCRIPTION=$(echo "$COMMIT_MSG" | head -1 | sed -E 's/^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?(!)?: //') |
| 64 | +if [ ${#DESCRIPTION} -lt 10 ]; then |
| 65 | + echo -e "${RED}ERROR: Commit description is too short (minimum 10 characters).${NC}" |
| 66 | + echo -e "${YELLOW}Current description:${NC} $DESCRIPTION" |
| 67 | + exit 1 |
| 68 | +fi |
| 69 | + |
| 70 | +# Check that description doesn't start with capital letter (optional but recommended) |
| 71 | +if echo "$DESCRIPTION" | grep -qE "^[A-Z]"; then |
| 72 | + echo -e "${YELLOW}WARNING: Description should start with lowercase letter.${NC}" |
| 73 | + echo -e "${YELLOW}Current:${NC} $DESCRIPTION" |
| 74 | + # This is just a warning, not a failure |
| 75 | +fi |
| 76 | + |
| 77 | +# Check commit message line length (first line should be <= 72 characters) |
| 78 | +FIRST_LINE_LENGTH=$(echo "$COMMIT_MSG" | head -1 | wc -c | tr -d ' ') |
| 79 | +if [ "$FIRST_LINE_LENGTH" -gt 72 ]; then |
| 80 | + echo -e "${YELLOW}WARNING: First line exceeds 72 characters (${FIRST_LINE_LENGTH} chars).${NC}" |
| 81 | + echo -e "${YELLOW}Consider shortening the commit message.${NC}" |
| 82 | + # This is just a warning, not a failure |
| 83 | +fi |
| 84 | + |
| 85 | +echo -e "${GREEN}Commit message follows Conventional Commits format.${NC}" |
| 86 | +exit 0 |
0 commit comments