mirror of
https://github.com/keymanapp/keyman.git
synced 2026-08-05 00:15:32 +00:00
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'.
165 lines
No EOL
5.2 KiB
Bash
Executable file
165 lines
No EOL
5.2 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
#
|
|
# This prepare-commit-msg hook prepares commit messages to ensure
|
|
# that they meet our conventional commit standard.
|
|
#
|
|
# Whenever `git` detects an incoming commit, it will trigger this hook. If the message does not
|
|
# our conventional commit format, it will set it to the following format. (commit and merge only)
|
|
#
|
|
# "type(scope): message"
|
|
# If an issue number is detected at the front of the message and it is not a merge, also adds "___. Fixes #1234"
|
|
#
|
|
# Reference: https://github.com/keymanapp/keyman/wiki/Pull-Request-and-Commit-workflow-notes
|
|
#
|
|
|
|
COMMIT_MSG_FILE="$1"
|
|
COMMIT_SOURCE="$2"
|
|
SHA1="$3"
|
|
|
|
# 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
|
|
|
|
# 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%?})?"
|
|
|
|
recherry="(cherry-pick\/)?"
|
|
|
|
# Optionally captures an issue number at the front of the branch's name.
|
|
rebranchname="(([[:digit:]]+)\-)?(.+)"
|
|
|
|
regexp="^${retypes}\/${rescope}\/?${recherry}${rebranchname}\s*$"
|
|
}
|
|
|
|
function prepend_scope() {
|
|
# COMMIT_MSG_FILE and $COMMIT_SOURCE are already available.
|
|
|
|
# Step 1: if the branch follows our preferred branch conventions, we can use that!
|
|
branch="$(git rev-parse --abbrev-ref HEAD)"
|
|
build_regex
|
|
|
|
# Perform the actual regex check.
|
|
if [[ $branch =~ $regexp ]]; then
|
|
TYPE="${BASH_REMATCH[1]}"
|
|
SCOPE="${BASH_REMATCH[2]}"
|
|
CHERRYPICK="${BASH_REMATCH[3]}"
|
|
# 4 - just ISSUE, but with an appended '-'. Ashame BASH doesn't support non-capture groups.
|
|
ISSUE="${BASH_REMATCH[5]}"
|
|
NAME="${BASH_REMATCH[6]}"
|
|
|
|
EXTRA_WHITESPACE="\n"
|
|
|
|
# For known merge commits, consider the merge operation to be a 'chore'.
|
|
if [ "${COMMIT_SOURCE}" = "merge" ]; then
|
|
TYPE="chore"
|
|
ISSUE= # Invalidates adding the 'postfix' for these commit types.
|
|
EXTRA_WHITESPACE=
|
|
fi
|
|
|
|
if [ -z "$SCOPE" ]; then
|
|
prefix="$TYPE: $EXTRA_WHITESPACE"
|
|
else
|
|
prefix="$TYPE($SCOPE): $EXTRA_WHITESPACE"
|
|
fi
|
|
|
|
# Now that we have the components finalized, we can proceed.
|
|
if [ -n "${ISSUE// }" ]; then # Refer to https://unix.stackexchange.com/a/146945 for explanation.
|
|
# This technically does pass the conventional commits test - it doesn't -ensure- that the
|
|
# "Fixes #____" section doesn't count toward the core message.
|
|
prefix="${prefix}\n"
|
|
prefix="${prefix}Fixes: #$ISSUE\n"
|
|
fi
|
|
|
|
if [ ! -z "$CHERRYPICK" ]; then
|
|
postfix_cherrypick="\n# - Add a cherry pick trailer:\n# Cherry-pick-of: #_ID_"
|
|
else
|
|
postfix_cherrypick=
|
|
fi
|
|
|
|
postfix=$(
|
|
cat <<EOF
|
|
\n# Keyman Conventional Commit suggestions:
|
|
#$postfix_cherrypick
|
|
# - 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
|
|
EOF
|
|
)
|
|
|
|
# Reuse any existing message text, wrapping it in our conventional commit formatting before
|
|
# presenting it to the user for any final edits.
|
|
echo -e "$prefix$(cat $COMMIT_MSG_FILE)$postfix" > $COMMIT_MSG_FILE
|
|
fi
|
|
|
|
# If it doesn't follow our branch-name format, we can't provide any help.
|
|
}
|
|
|
|
#
|
|
# Configurable options for types, scopes and message length.
|
|
#
|
|
|
|
# Step 1 - is the prepared message already in our conventional commits format?
|
|
$HOOK_DIRECTORY/commit-msg -q $COMMIT_MSG_FILE
|
|
isConventional=$? # Grabs the exit code.
|
|
|
|
if [ $isConventional -eq 0 ]; then
|
|
# If so, great! Don't do a thing!
|
|
exit 0
|
|
fi
|
|
|
|
# Debugging aides
|
|
#echo "COMMIT_MSG_FILE=$COMMIT_MSG_FILE"
|
|
#echo "COMMIT_SOURCE=$COMMIT_SOURCE"
|
|
|
|
# The default message is NOT in conventional format. Time to help out with that.
|
|
case $COMMIT_SOURCE in
|
|
squash)
|
|
# We don't help with squashes - this tends to combine two separate messages,
|
|
# and that can be messy.
|
|
exit 0
|
|
;;
|
|
merge|commit|'') # '' = plain `git commit`
|
|
# We can help here!
|
|
prepend_scope
|
|
;;
|
|
*)
|
|
# Default handler - we don't handle these types yet. Might be worth considering.
|
|
# Known possibilities: message (-m), template (-t)
|
|
exit 0
|
|
;;
|
|
esac |