Last active
February 6, 2025 20:25
-
-
Save Adi-ty/30e97a0caccabfdae2889180c1044e4b to your computer and use it in GitHub Desktop.
Bash-based Git commit message enforcer with auto-versioning and emoji support
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
CONFIG_FILE=".gitlintwizardrc" | |
HOOK_FILE=".git/hooks/prepare-commit-msg" | |
VERSION_FILE="VERSION" | |
# Default configuration | |
DEFAULT_CONFIG=( | |
"# Allowed commit types (comma-separated)" | |
"TYPES=feat,fix,chore,docs,style,refactor,test" | |
"# Max subject length" | |
"MAX_LENGTH=50" | |
"# Require JIRA ticket? (true/false)" | |
"REQUIRE_JIRA=false" | |
"# Emoji support (true/false)" | |
"USE_EMOJI=true" | |
"# Auto-versioning (true/false)" | |
"AUTO_VERSION=true" | |
) | |
install() { | |
cp "$0" "$HOOK_FILE" && chmod +x "$HOOK_FILE" | |
if [ ! -f "$CONFIG_FILE" ]; then | |
printf "%s\n" "${DEFAULT_CONFIG[@]}" > "$CONFIG_FILE" | |
fi | |
[ ! -f "$VERSION_FILE" ] && echo "0.1.0" > "$VERSION_FILE" | |
echo "GitLint Wizard installed! Configuration: $CONFIG_FILE" | |
} | |
uninstall() { | |
rm -f "$HOOK_FILE" && echo "GitLint Wizard removed!" | |
} | |
validate_commit() { | |
local msg=$1 | |
local type_regex='^[a-z]+(\([a-z-]+\))?!?: .+' | |
source "$CONFIG_FILE" 2>/dev/null | |
# Split commit message | |
IFS=': ' read -r type scope <<< "$msg" | |
# Validate format | |
[[ ! "$msg" =~ $type_regex ]] && return 1 | |
# Check allowed types | |
local allowed_types="${TYPES//,/|}" | |
[[ ! "$type" =~ ($allowed_types) ]] && return 2 | |
# Check subject length | |
local subject=$(echo "$msg" | cut -d: -f2- | xargs) | |
[ ${#subject} -gt "$MAX_LENGTH" ] && return 3 | |
if [ "$REQUIRE_JIRA" = true ] && [[ ! "$msg" =~ [A-Z]+-[0-9]+ ]]; then | |
return 4 | |
fi | |
return 0 | |
} | |
bump_version() { | |
[ "$AUTO_VERSION" != "true" ] && return | |
local current_version=$(cat "$VERSION_FILE") | |
IFS='.' read -r major minor patch <<< "${current_version//[!0-9]/ }" | |
case "$1" in | |
feat) minor=$((minor + 1)) ;; | |
fix) patch=$((patch + 1)) ;; | |
*) return ;; | |
esac | |
new_version="$major.$minor.$patch" | |
echo "$new_version" > "$VERSION_FILE" | |
echo "Version bumped to $new_version!" | |
} | |
add_emoji() { | |
[ "$USE_EMOJI" != "true" ] && echo "$1" && return | |
declare -A emoji_map=( | |
[feat]="✨" [fix]="🐛" [docs]="📚" | |
[style]="💄" [refactor]="♻️" [test]="✅" | |
) | |
local type=$(echo "$1" | cut -d: -f1) | |
echo "${emoji_map[$type]} $1" | |
} | |
commit_hook() { | |
[ -z "$2" ] && exit 0 # Skip for merge commits | |
if [[ "$2" == "message" ]]; then | |
msg=$(cat "$1") | |
else | |
msg=$(echo "$@" | sed -n "s/.*'-m' '\([^']*\).*/\1/p") | |
fi | |
validate_commit "$msg" | |
case $? in | |
1) echo "Invalid format! Use: type(scope): description" >&2 ;; | |
2) echo "Invalid type! Allowed: ${TYPES}" >&2 ;; | |
3) echo "Subject too long! Max ${MAX_LENGTH} chars" >&2 ;; | |
4) echo "Missing JIRA ticket!" >&2 ;; | |
0) | |
bump_version "$(echo "$msg" | cut -d: -f1)" | |
new_msg=$(add_emoji "$msg") | |
echo "$new_msg" > "$1" | |
exit 0 | |
;; | |
esac | |
exit 1 | |
} | |
case "$1" in | |
install) install ;; | |
uninstall) uninstall ;; | |
*) commit_hook "$@" ;; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment