spiegel-keyman/resources/git-hooks/commit-msg
Marc Durdin 222ff6a182 change(common): add extra commit message hints
These changes come out of discussion in the team; we want to make use of
git trailers and improve the quality of our commit messages. Starting by
adding more hints to the commit suggestions. Includes some minor cleanup
of the hooks, and hopefully also improves tests so that they don't
interfere with interactions with non-Keyman repos.

Note: the scopes list may need maintenance as the list still includes
sub-scopes and 'oem'.
2024-05-28 10:57:46 +07:00

139 lines
No EOL
4.4 KiB
Bash
Executable file

#!/usr/bin/env bash
#
# This commit-msg hook validates commit messages
# to ensure that they meet our conventional commit standard.
#
#
# "type: message"
# "type(scope): message"
# Optionally, append ". Fixes #1234"
#
# Reference: https://github.com/keymanapp/keyman/wiki/Pull-Request-and-Commit-workflow-notes
#
# Get the directory where this script lives, i.e. resources/git-hooks
HOOK_DIRECTORY="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
if [ -f $(dirname "${BASH_SOURCE[0]}")/commit-msg-defs ]; then
# This script was run from a symlink and the repo in question has its own commit-msg-defs.
. $(dirname "${BASH_SOURCE[0]}")/commit-msg-defs
else
# We'll grab the settings from the keymanapp/keyman repository.
. "$HOOK_DIRECTORY/../build/jq.inc.sh"
# Configurable options for message length.
min_length=4
max_length=128
# Read from our globally shared JSON-formatted scopes and types
scopes=( $("$JQ" -r '[.scopes | paths | reduce .[] as $item (""; if . == "" then $item else . + "/" + $item end)] | join(" ")' < "$HOOK_DIRECTORY/../scopes/scopes.json") )
types=( $("$JQ" -r '.commitTypes | join(" ")' < "$HOOK_DIRECTORY/../scopes/commit-types.json") )
fi
#
# Define terminal colours.
#
if [ -t 2 ]; then
t_red=$'\e[1;31m'
t_grn=$'\e[1;32m'
t_yel=$'\e[1;33m'
t_blu=$'\e[1;34m'
t_mag=$'\e[1;35m'
t_cyn=$'\e[1;36m'
t_end=$'\e[0m'
fi
#
# Test the repository upstream/origin: ignore if not keymanapp/keyman
#
GIT_ORIGIN="$(git remote get-url origin)"
if [[ ! "$GIT_ORIGIN" =~ github\.com/keymanapp ]]; then
# Not a Keyman repository. We have no opinion.
# echo "DEBUG: Not a Keyman repository. We don't care"
exit 0
fi
if [[ "$GIT_ORIGIN" =~ keyboards|lexical-models ]]; then
# We don't enforce commit messages on keyboards or lexical-models repositories
# echo "DEBUG: Keyboards or Lexical-Models. We still don't care."
exit 0
fi
# If this script is called by another hook, it may insert a -q parameter to silence the help text.
QUIET=0
case $1 in
-q|--quiet)
shift # Remove the parameter, making it equivalent to a standard git-hook call.
QUIET=1
;;
esac
# build the regex pattern based on the config file
function build_regex() {
retypes=
for type in "${types[@]}"
do
retypes="${retypes}$type|"
done
retypes="(${retypes%?})"
rescope=
for scope in "${scopes[@]}"
do
rescope="${rescope}$scope|"
done
# %? removes last |
rescope="(\((${rescope%?})\))?"
remessage=".{$min_length,$max_length}[^.]"
refixes="(\. Fixes #[[:digit:]]+)?"
# Regex for the commit message title. It's ok if the commit message starts with "fixup!".
# (This allows to run `git commit --fixup=<sha>` without complaining about the commit
# message not being in conventional commit format. This helps in squashing with a previous
# commit.)
regexp="^(fixup\! )?${retypes}${rescope}: ${remessage}${refixes}[[:space:]]*$"
}
# Print out a standard error message which explains
# how the commit message should be structured
function print_error() {
echo -e "\n${t_red}ERROR: Commit message is not in Conventional Commit format"
echo -e "----------------------------------------------------------${t_end}"
echo -e "Valid types: ${t_grn}${types[@]}${t_end}"
echo -e "Valid scopes: ${t_grn}${scopes[@]}${t_end}"
echo -e "Max length (first line): ${t_grn}$max_length${t_end}"
echo -e "Min length (first line): ${t_grn}$min_length${t_end}"
echo -e "If possible, append git trailers:"
echo -e " * ${t_grn}Fixes: #1234${t_end}"
echo -e " * ${t_grn}Fixes: KEYMAN-MODULE-XYZ${t_end}"
echo -e " * ${t_grn}Cherry-pick-of: #2468${t_end}"
echo -e " * ${t_grn}Co-authored-by: Firstname Lastname <email@keyman.com>${t_end}"
echo -e "${t_cyn}Example:${t_end} fix(windows): Re-attach the widget plug which had fallen out"
echo -e "${t_cyn}Reference${t_end}: https://github.com/keymanapp/keyman/wiki/Pull-Request-and-Commit-workflow-notes"
echo -e ""
echo -e "Tips: "
echo -e " * Don't include a period at the end of the title"
echo -e " * Always include a blank line before trailers"
echo -e " * Use imperative, present tense ('attach' not 'attaches', 'attached' etc)"
echo -e ""
echo -e "This script: $0"
}
# get the first line of the commit message
msg=$(head -1 $1)
build_regex
if [[ ! $msg =~ $regexp ]]; then
# commit message is invalid according to config - block commit
if [ $QUIET -eq 0 ]; then
print_error
fi
exit 1
fi