Skip to content

Instantly share code, notes, and snippets.

@awmv
Last active September 18, 2023 19:32
Show Gist options
  • Save awmv/9c268c224135ed848574d9b8f0cb8a0f to your computer and use it in GitHub Desktop.
Save awmv/9c268c224135ed848574d9b8f0cb8a0f to your computer and use it in GitHub Desktop.
Git hooks to auto-detect Jira ticket numbers and offer a fuzzy finder or GUI for semantic commit prefixes

WIP

Install

/bin/bash -c "$(curl -fsSL https://gist.githubusercontent.com/awmv/9c268c224135ed848574d9b8f0cb8a0f/raw/90368c8a5e7d6a65c413f165beaaf41b7e1848f6/install.sh)"

Uninstall

/bin/bash -c "$(curl -fsSL https://gist.githubusercontent.com/awmv/9c268c224135ed848574d9b8f0cb8a0f/raw/10339b25330d83e5cc9402fdfc6ca8ef60a5d6db/uninstall.sh)"
#!/bin/bash
check_and_install_dependencies() {
if [[ "$OSTYPE" == "darwin"* ]]; then
if ! command -v brew &>/dev/null; then
echo "Homebrew is required but not installed. Please install Homebrew and try again."
exit 1
fi
if ! command -v fzf &>/dev/null; then
brew install fzf
fi
if ! command -v zenity &>/dev/null; then
brew install zenity
fi
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
if command -v apt-get &>/dev/null; then
if ! command -v fzf &>/dev/null; then
sudo apt-get update
sudo apt-get install -y fzf
fi
if ! command -v zenity &>/dev/null; then
sudo apt-get update
sudo apt-get install -y zenity
fi
else
echo "Unsupported package manager. Please install fzf and zenity manually."
exit 1
fi
else
echo "Unsupported OS. Exiting."
exit 1
fi
}
check_and_install_dependencies
mkdir -p ~/.global-git-hooks
choice=$(printf "CLI\nGUI" | fzf --prompt "Use command line fuzzy finder or GUI selection for commit type selection? [CLI/GUI]: ")
if [[ $choice == 'CLI' ]]; then
is_command_line_user="true"
else
is_command_line_user="false"
fi
cat <<'EOL' >~/.global-git-hooks/prepare-commit-msg
#!/bin/bash
is_command_line_user=REPLACE_IS_COMMAND_LINE_USER
capitalize_first_letter() {
echo "$1" | awk '{ $1=toupper(substr($1,1,1)) substr($1,2); print }'
}
commit_types=("feat" "refactor" "fix" "chore" "style" "test" "docs" "localize" "init")
if [ -n "$1" ] && [ -f "$1" ]; then
commit_message=$(cat "$1")
else
echo "Error: Commit message file not found."
exit 1
fi
if [[ $commit_message == "Merge branch"* ]]; then
echo "Merge commit detected. Skipping validation."
exit 0
fi
if [ -d "$(git rev-parse --git-dir)/rebase-merge" ] || [ -d "$(git rev-parse --git-dir)/rebase-apply" ]; then
echo "Rebase in progress. Skipping validation."
exit 0
fi
if [ "${SKIP_COMMIT_VALIDATION:-false}" == "true" ]; then
echo "SKIP_COMMIT_VALIDATION is true. Skipping validation."
exit 0
fi
valid_format_regex="^($(
IFS="|"
echo "${commit_types[*]}"
)): (\[[A-Z]+-[0-9]+\] )?.+"
if [[ ! $commit_message =~ $valid_format_regex ]]; then
echo "Commit message format is invalid."
if $is_command_line_user; then
type=$(printf '%s\n' "${commit_types[@]}" | fzf)
if [ $? -ne 0 ]; then
echo "Commit aborted."
exit 1
fi
else
zenity_options=()
for type in "${commit_types[@]}"; do
zenity_options+=("FALSE")
zenity_options+=("$type")
done
type=$(zenity --list --radiolist \
--text "Select commit type:" \
--height=310 --width=150 \
--column "Pick" --column "Type" \
"${zenity_options[@]}")
if [ $? -ne 0 ]; then
echo "Commit aborted."
exit 1
fi
fi
current_branch=$(git branch --show-current)
ticket_number=$(echo "$current_branch" | grep -oE '([A-Z]+-[0-9]+)')
if [ -z "$ticket_number" ]; then
commit_message="$type: $(capitalize_first_letter "$commit_message")"
else
commit_message="$type: [$ticket_number] $(capitalize_first_letter "$commit_message")"
fi
echo "$commit_message" >"$1"
else
echo "Commit message is valid."
fi
EOL
sed -i.bak "s/REPLACE_IS_COMMAND_LINE_USER/$is_command_line_user/g" ~/.global-git-hooks/prepare-commit-msg
rm ~/.global-git-hooks/prepare-commit-msg.bak
chmod +x ~/.global-git-hooks/prepare-commit-msg
git config --global core.hooksPath ~/.global-git-hooks
echo "Installation complete for $choice."
#!/bin/bash
uninstall_dependencies() {
read -p "Do you want to uninstall the dependencies (fzf and zenity)? [y/N]: " uninstall_dep
if [[ $uninstall_dep == 'y' || $uninstall_dep == 'Y' ]]; then
if [[ "$OSTYPE" == "darwin"* ]]; then
brew uninstall fzf zenity
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
if command -v apt-get &>/dev/null; then
sudo apt-get remove --purge -y fzf zenity
else
echo "Unsupported package manager. Cannot uninstall fzf and zenity."
fi
else
echo "Unsupported OS. Cannot uninstall fzf and zenity."
fi
fi
}
if [ -f ~/.global-git-hooks/prepare-commit-msg ]; then
rm ~/.global-git-hooks/prepare-commit-msg
echo "Removed the prepare-commit-msg hook."
else
echo "prepare-commit-msg hook not found. Skipping."
fi
uninstall_dependencies
read -p "Do you want to reset the global Git core.hooksPath? [y/N]: " reset_hooks_path
if [[ $reset_hooks_path == 'y' || $reset_hooks_path == 'Y' ]]; then
git config --global --unset core.hooksPath
echo "Reset the global Git core.hooksPath."
else
echo "Skipped resetting the global Git core.hooksPath."
fi
echo "Uninstallation complete."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment