Last active
February 12, 2025 19:37
-
-
Save o6uoq/35d42cf16aecd72d5670e46015375050 to your computer and use it in GitHub Desktop.
fuzmit: Conventional Commits, but Fuzzy.
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 | |
FUZMIT_JIRA_SCOPE=${FUZMIT_JIRA_SCOPE:-false} | |
FUZMIT_SCOPE=${FUZMIT_SCOPE:-false} | |
# === How-To === | |
# - Place git-fuzmit (without an extension) in your $PATH, make it executable, and run via `git fuzmit` | |
# - Set FUZMIT_JIRA_SCOPE=true to auto-detect the Jira ID (e.g., JIRA-123) from the branch name and use it as the commit scope | |
# - Set FUZMIT_SCOPE=true to enable scope prompts for each and every commit | |
# === Function: Display Usage Information === | |
display_usage() { | |
echo -e "\033[1;38;5;81m" | |
echo "fuzmit: Conventional Commits, but Fuzzy." | |
echo -e "\033[0m" | |
echo "" | |
echo -e "\033[1;37m# Conventional Commit Message Format:\033[0m" | |
echo -e "\033[1;32m<type>\033[0m\033[1;34m(optional scope)\033[0m: \033[1;36m<description>\033[0m" | |
echo "" | |
echo -e "\033[1;37mCommit Types:\033[0m" | |
echo -e " π build - Project build or dependencies changes" | |
echo -e " π§Ή chore - Routine tasks, maintenance" | |
echo -e " π ci - Continuous integration changes" | |
echo -e " π docs - Documentation updates" | |
echo -e " π feat - New feature addition" | |
echo -e " π§ fix - Bug fixes" | |
echo -e " π perf - Performance improvements" | |
echo -e " π οΈ refactor - Code refactoring without changing behavior" | |
echo -e " π¨ style - Code style or formatting" | |
echo -e " π§ͺ test - Adding or modifying tests" | |
echo "" | |
echo -e "\033[1;37m# Example Commit Message:\033[0m" | |
echo -e "\033[1;36mfeat(authentication): add support for password reset\033[0m" | |
echo "" | |
echo -e "\033[1;37m# Usage:\033[0m" | |
echo -e " git fuzmit [--scope] [--override]" | |
echo "" | |
echo -e "\033[1;37m# Options:\033[0m" | |
echo -e " --scope Manually add a commit scope for this commit" | |
echo -e " --override Bypass main branch restriction and allow committing" | |
echo "" | |
echo -e "\033[1;37m# Notes:\033[0m" | |
echo -e " - If FUZMIT_JIRA_SCOPE=true, both --scope and FUZMIT_SCOPE are ignored since Jira scope is auto-detected" | |
echo "" | |
echo -e "\033[1;36mConventional Commits: https://www.conventionalcommits.org/en/v1.0.0/#specification\033[0m" | |
echo "" | |
} | |
# === Function: Check if fzf is installed === | |
check_fzf_installed() { | |
if ! command -v fzf >/dev/null 2>&1; then | |
echo "β fm: fzf is not installed. Please install it first." | |
exit 1 | |
fi | |
} | |
# === Function: Check if we're in a git repository === | |
check_git_repo() { | |
if ! git rev-parse --is-inside-work-tree > /dev/null 2>&1; then | |
echo "β fm: Not inside a git repository." | |
exit 1 | |
fi | |
} | |
# === Function: Check if we're on the main branch === | |
check_branch() { | |
current_branch=$(git symbolic-ref --short HEAD) | |
if [ "$current_branch" = "main" ] && [ "$1" != "--override" ]; then | |
echo "π« fm: You are on the main branch. Use --override to bypass this check." | |
exit 1 | |
fi | |
} | |
# === Function: Check if there are staged changes to commit === | |
check_staged_changes() { | |
if git diff --cached --quiet; then | |
echo "βΉοΈ fm: No staged changes to commit." | |
exit 0 | |
fi | |
} | |
# === Function: Extract Jira scope if applicable === | |
extract_jira_scope() { | |
if [ "${FUZMIT_JIRA_SCOPE}" = "true" ]; then | |
current_branch=$(git symbolic-ref --short HEAD) | |
if [[ $current_branch =~ ^([A-Za-z]+-[0-9]+) ]]; then | |
echo "${BASH_REMATCH[1]}" | |
return | |
fi | |
fi | |
echo "" | |
} | |
# === Function: Select commit type with fzf and prompt for a description === | |
select_commit_type() { | |
commit_type=$(printf "π build - Project build or dependencies changes\nπ§Ή chore - Routine tasks, maintenance\nπ ci - Continuous integration changes\nπ docs - Documentation updates\nπ feat - New feature addition\nπ§ fix - Bug fixes\nπ perf - Performance improvements\nπ οΈ refactor - Code refactoring without changing behavior\nπ¨ style - Code style or formatting\nπ§ͺ test - Adding or modifying tests" | fzf --height 12 --prompt="Pick commit type: ") | |
if [ -z "$commit_type" ]; then | |
echo "β fm: No commit type selected, aborting." | |
exit 1 | |
fi | |
commit_type=$(echo "$commit_type" | cut -d'-' -f1 | xargs) | |
jira_scope=$(extract_jira_scope) | |
if [ -n "$jira_scope" ]; then | |
echo "βΉοΈ fm: Auto-detected Jira scope '$jira_scope'" | |
commit_scope="($jira_scope)" | |
elif [ "$FUZMIT_SCOPE" = "true" ] || [ "$1" = "--scope" ]; then | |
read -r -p "Enter optional scope (leave empty if not needed): " commit_scope | |
if [ -n "$commit_scope" ]; then | |
commit_scope="($commit_scope)" | |
fi | |
else | |
commit_scope="" | |
fi | |
read -r -p "Enter commit description: " commit_message | |
if [ -z "$commit_message" ]; then | |
echo "β fm: Commit description cannot be empty, aborting." | |
exit 1 | |
fi | |
full_commit_message="$commit_type$commit_scope: $commit_message" | |
echo "πΎ fm: Commit message - '$full_commit_message'" | |
git commit -m "$full_commit_message" | |
} | |
# === Main Execution === | |
if [ "$1" = "help" ]; then | |
display_usage | |
exit 0 | |
fi | |
# Check if the --scope flag is provided and enable FUZMIT_SCOPE | |
if [ "$1" = "--scope" ]; then | |
FUZMIT_SCOPE=true | |
fi | |
check_fzf_installed | |
check_git_repo | |
check_branch "$1" | |
check_staged_changes | |
select_commit_type "$1" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment