Skip to content

Commit c699726

Browse files
committed
refactor: extract shared validation logic for git hooks
1 parent bab4fde commit c699726

3 files changed

Lines changed: 64 additions & 22 deletions

File tree

.githooks/commit-msg

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,16 @@
33
# SPDX-FileCopyrightText: 2025 Alexander Minges
44
set -euo pipefail
55

6+
# Source shared validation logic
7+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8+
source "$SCRIPT_DIR/validate-commit-msg.sh"
9+
610
msg_file="$1"
711
msg=$(head -n1 "$msg_file")
812

9-
# Conventional Commits pattern (type[!][scope]: subject)
10-
regex='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([^)]+\))?(!)?: .+'
11-
if [[ ! $msg =~ $regex ]]; then
12-
echo "commit message must follow Conventional Commits, e.g., 'feat: add feature'" >&2
13-
exit 1
13+
if ! validate_commit_msg "$msg"; then
14+
print_error "$msg"
15+
exit 1
1416
fi
1517

1618
exit 0

.githooks/pre-push

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ set -euo pipefail
66
# Pre-push hook to validate that all commits being pushed follow Conventional Commits
77
# This prevents malformed commits that may have bypassed commit-msg hook during rebases
88

9+
# Source shared validation logic
10+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11+
source "$SCRIPT_DIR/validate-commit-msg.sh"
12+
913
remote="$1"
1014
url="$2"
1115

12-
# Conventional Commits pattern (type[!][scope]: subject)
13-
regex='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([^)]+\))?(!)?: .+'
14-
1516
has_errors=0
1617

1718
# Read stdin to get the refs being pushed
@@ -31,21 +32,9 @@ while read local_ref local_sha remote_ref remote_sha; do
3132

3233
# Get all commit messages in the range
3334
while IFS= read -r commit_msg; do
34-
# Skip merge commits
35-
if [[ "$commit_msg" =~ ^Merge ]]; then
36-
continue
37-
fi
38-
39-
# Check if commit message follows Conventional Commits
40-
if [[ ! "$commit_msg" =~ $regex ]]; then
41-
echo "ERROR: Invalid commit message format:" >&2
42-
echo " '$commit_msg'" >&2
43-
echo >&2
44-
echo "Commit messages must follow Conventional Commits specification." >&2
45-
echo "Example: feat: add new feature" >&2
46-
echo " fix(ui): correct button alignment" >&2
35+
if ! validate_commit_msg "$commit_msg"; then
36+
print_error "$commit_msg"
4737
echo >&2
48-
echo "Valid types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert" >&2
4938
has_errors=1
5039
fi
5140
done < <(git log --format=%s "$range")

.githooks/validate-commit-msg.sh

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/usr/bin/env bash
2+
# SPDX-License-Identifier: MIT
3+
# SPDX-FileCopyrightText: 2025 Alexander Minges
4+
5+
# Shared validation logic for commit messages
6+
# Used by both commit-msg and pre-push hooks to ensure consistency
7+
8+
set -euo pipefail
9+
10+
# Conventional Commits pattern (type[!][scope]: subject)
11+
readonly COMMIT_MSG_REGEX='^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([^)]+\))?(!)?: .+'
12+
13+
# Valid commit types for reference
14+
readonly VALID_TYPES="feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert"
15+
16+
# Validate a single commit message
17+
# Arguments:
18+
# $1 - commit message to validate
19+
# Returns:
20+
# 0 if valid, 1 if invalid
21+
validate_commit_msg() {
22+
local msg="$1"
23+
24+
# Skip merge commits
25+
if [[ "$msg" =~ ^Merge ]]; then
26+
return 0
27+
fi
28+
29+
# Check if commit message follows Conventional Commits
30+
if [[ ! "$msg" =~ $COMMIT_MSG_REGEX ]]; then
31+
return 1
32+
fi
33+
34+
return 0
35+
}
36+
37+
# Print error message for invalid commit
38+
# Arguments:
39+
# $1 - invalid commit message
40+
print_error() {
41+
local msg="$1"
42+
43+
echo "ERROR: Invalid commit message format:" >&2
44+
echo " '$msg'" >&2
45+
echo >&2
46+
echo "Commit messages must follow Conventional Commits specification." >&2
47+
echo "Example: feat: add new feature" >&2
48+
echo " fix(ui): correct button alignment" >&2
49+
echo >&2
50+
echo "Valid types: $VALID_TYPES" >&2
51+
}

0 commit comments

Comments
 (0)