development #240

Merged
lmiranda merged 29 commits from development into main 2026-01-28 16:02:47 +00:00
3 changed files with 195 additions and 0 deletions
Showing only changes of commit af6a42b2ac - Show all commits

View File

@@ -0,0 +1,102 @@
#!/bin/bash
# git-flow branch name validation hook
# Validates branch names follow the convention: <type>/<description>
# Command hook - guaranteed predictable behavior
# Read tool input from stdin (JSON format)
INPUT=$(cat)
# Extract command from JSON input
# The Bash tool sends {"command": "..."} format
COMMAND=$(echo "$INPUT" | grep -o '"command"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*"command"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/')
# If no command found, exit silently (allow)
if [ -z "$COMMAND" ]; then
exit 0
fi
# Check if this is a branch creation command
# Patterns: git checkout -b, git branch (without -d/-D), git switch -c/-C
IS_BRANCH_CREATE=false
BRANCH_NAME=""
# git checkout -b <branch>
if echo "$COMMAND" | grep -qE 'git\s+checkout\s+(-b|--branch)\s+'; then
IS_BRANCH_CREATE=true
BRANCH_NAME=$(echo "$COMMAND" | sed -n 's/.*git\s\+checkout\s\+\(-b\|--branch\)\s\+\([^ ]*\).*/\2/p')
fi
# git switch -c/-C <branch>
if echo "$COMMAND" | grep -qE 'git\s+switch\s+(-c|-C|--create|--force-create)\s+'; then
IS_BRANCH_CREATE=true
BRANCH_NAME=$(echo "$COMMAND" | sed -n 's/.*git\s\+switch\s\+\(-c\|-C\|--create\|--force-create\)\s\+\([^ ]*\).*/\2/p')
fi
# git branch <name> (without -d/-D/-m/-M which are delete/rename)
if echo "$COMMAND" | grep -qE 'git\s+branch\s+[^-]' && ! echo "$COMMAND" | grep -qE 'git\s+branch\s+(-d|-D|-m|-M|--delete|--move|--list|--show-current)'; then
IS_BRANCH_CREATE=true
BRANCH_NAME=$(echo "$COMMAND" | sed -n 's/.*git\s\+branch\s\+\([^ -][^ ]*\).*/\1/p')
fi
# If not a branch creation command, exit silently (allow)
if [ "$IS_BRANCH_CREATE" = false ]; then
exit 0
fi
# If we couldn't extract the branch name, exit silently (allow)
if [ -z "$BRANCH_NAME" ]; then
exit 0
fi
# Remove any quotes from branch name
BRANCH_NAME=$(echo "$BRANCH_NAME" | tr -d '"' | tr -d "'")
# Skip validation for special branches
case "$BRANCH_NAME" in
main|master|develop|development|staging|release|hotfix)
exit 0
;;
esac
# Allowed branch types
VALID_TYPES="feat|fix|chore|docs|refactor|test|perf|debug"
# Validate branch name format: <type>/<description>
# Description: lowercase letters, numbers, hyphens only, max 50 chars total
if ! echo "$BRANCH_NAME" | grep -qE "^($VALID_TYPES)/[a-z0-9][a-z0-9-]*$"; then
echo ""
echo "[git-flow] Branch name validation failed"
echo ""
echo "Branch: $BRANCH_NAME"
echo ""
echo "Expected format: <type>/<description>"
echo ""
echo "Valid types: feat, fix, chore, docs, refactor, test, perf, debug"
echo ""
echo "Description rules:"
echo " - Lowercase letters, numbers, and hyphens only"
echo " - Must start with letter or number"
echo " - No spaces or special characters"
echo ""
echo "Examples:"
echo " feat/add-user-auth"
echo " fix/login-timeout"
echo " chore/update-deps"
echo " docs/api-reference"
echo ""
exit 1
fi
# Check total length (max 50 chars)
if [ ${#BRANCH_NAME} -gt 50 ]; then
echo ""
echo "[git-flow] Branch name too long"
echo ""
echo "Branch: $BRANCH_NAME (${#BRANCH_NAME} chars)"
echo "Maximum: 50 characters"
echo ""
exit 1
fi
# Valid branch name
exit 0

View File

@@ -0,0 +1,74 @@
#!/bin/bash
# git-flow commit message validation hook
# Validates git commit messages follow conventional commit format
# PreToolUse hook for Bash commands - type: command
# Read tool input from stdin
INPUT=$(cat)
# Use Python to properly parse JSON and extract the command
COMMAND=$(echo "$INPUT" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('command',''))" 2>/dev/null)
# If no command or python failed, allow through
if [ -z "$COMMAND" ]; then
exit 0
fi
# Check if it is a git commit command with -m flag
if ! echo "$COMMAND" | grep -qE 'git\s+commit.*-m'; then
# Not a git commit with -m, allow through
exit 0
fi
# Extract commit message - handle various quoting styles
# Try double quotes first
COMMIT_MSG=$(echo "$COMMAND" | sed -n 's/.*-m[[:space:]]*"\([^"]*\)".*/\1/p')
# If empty, try single quotes
if [ -z "$COMMIT_MSG" ]; then
COMMIT_MSG=$(echo "$COMMAND" | sed -n "s/.*-m[[:space:]]*'\\([^']*\\)'.*/\\1/p")
fi
# If still empty, try HEREDOC pattern
if [ -z "$COMMIT_MSG" ]; then
if echo "$COMMAND" | grep -qE -- '-m[[:space:]]+"\$\(cat <<'; then
# HEREDOC pattern - too complex to parse, allow through
exit 0
fi
fi
# If no message extracted, allow through
if [ -z "$COMMIT_MSG" ]; then
exit 0
fi
# Validate conventional commit format
# Format: <type>(<scope>): <description>
# or: <type>: <description>
# Valid types: feat, fix, docs, style, refactor, perf, test, chore, build, ci
VALID_TYPES="feat|fix|docs|style|refactor|perf|test|chore|build|ci"
# Check if message matches conventional commit format
if echo "$COMMIT_MSG" | grep -qE "^($VALID_TYPES)(\([a-zA-Z0-9_-]+\))?:[[:space:]]+.+"; then
# Valid format
exit 0
fi
# Invalid format - output warning
echo "[git-flow] WARNING: Commit message does not follow conventional commit format"
echo ""
echo "Expected format: <type>(<scope>): <description>"
echo " or: <type>: <description>"
echo ""
echo "Valid types: feat, fix, docs, style, refactor, perf, test, chore, build, ci"
echo ""
echo "Examples:"
echo " feat(auth): add password reset functionality"
echo " fix: resolve login timeout issue"
echo " docs(readme): update installation instructions"
echo ""
echo "Your message: $COMMIT_MSG"
echo ""
echo "To proceed anyway, use /commit command which auto-generates valid messages."
# Exit with non-zero to block
exit 1

View File

@@ -0,0 +1,19 @@
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/branch-check.sh"
},
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/commit-msg-check.sh"
}
]
}
]
}
}