spiegel-keyman/resources/git-hooks/commit-msg
Eberhard Beilharz 44116b70dd
chore(common): detect ssh remotes in git hooks
Sometime ago we lost the ability to detect git remotes that use ssh
(git@github.com:keymanapp/keyman.git) and we only detect remotes that
use https (https://github.com/keymanapp/keyman.git). This change restores
this ability.

Also add some empty lines between the different parts of the error message.

# Keyman Conventional Commit suggestions:
#
# - Link to a Sentry issue with git trailer:
#     Fixes: _MODULE_-_ID_
# - Give credit to co-authors:
#     Co-authored-by: _Name_ <_email_>
# - Use imperative, present tense ('attach' not 'attaches', 'attached' etc)
# - Don't include a period at the end of the title
# - Always include a blank line before trailers
# - More: https://github.com/keymanapp/keyman/wiki/Pull-Request-and-Commit-workflow-notes
2024-09-17 11:38:41 +02:00

143 lines
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 ""
echo -e "Min length (first line): ${t_grn}$min_length${t_end}"
echo -e "Max length (first line): ${t_grn}$max_length${t_end}"
echo -e ""
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 ""
echo -e "${t_cyn}Example:${t_end} fix(windows): Re-attach the widget plug which had fallen out"
echo -e ""
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' instead of '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