79 lines
2.6 KiB
Bash
Executable File
79 lines
2.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# A hook script to check the commit log message.
|
|
# Called by "git commit" with one argument, the name of the file that has the
|
|
# commit message.
|
|
# The hook should exit with non-zero status after issuing an appropriate message
|
|
# if it wants to stop the commit.
|
|
# The hook is allowed to edit the commit message file.
|
|
#
|
|
# To enable this hook, save this file in ".git/hooks/commit-msg".
|
|
|
|
# Source die()
|
|
repo_root="$(git rev-parse --show-toplevel)"
|
|
. "$repo_root"/.local/bin/helpers.sh
|
|
|
|
subject="$(head -1 "$1")"
|
|
# Ignore "fixup! " and "squash! " prefix' added by `git-commit`
|
|
subject="${subject#fixup! }"
|
|
subject="${subject#squash! }"
|
|
|
|
# git's character to comment out lines in commit messages. The `auto` value is
|
|
# handled specially (see the different uses of $git_comment_char).
|
|
# NOTE: Only `^` is escaped as $git_comment_char is used in character classes
|
|
# and thus all other characters are free to use.
|
|
git_comment_char="$(git config --get --default='#' core.commentChar \
|
|
| sed 's:\^:\\&:g')"
|
|
# git's cut-line to cut off everything behind it (e.g. commit patch with
|
|
# `commit.verbose`)
|
|
cut_line='------------------------ >8 ------------------------'
|
|
|
|
# Take all lines after the subject until EOF or the cut-line (here `auto` is
|
|
# replaced with 'any character' as the cut-line in itself should hopefully be
|
|
# unambiguous enough) and remove all lines starting with the comment-char
|
|
# (`auto` is not handled properly but rather replaced with the default `#`)
|
|
body="$(
|
|
tail +2 "$1" \
|
|
| sed -n "/^[${git_comment_char/auto/[:print:]\t}] $cut_line\$/q
|
|
/^[^${git_comment_char/auto/\#}]/p"
|
|
)"
|
|
|
|
if [[ ${#subject} -gt 60 ]]; then
|
|
die "Subject too long. (<= 60)"
|
|
elif [[ ${#subject} -gt 50 ]]; then
|
|
>&2 printf "%s: Subject exceeds recommendation of 50 characters!\n\n" "$0"
|
|
fi
|
|
|
|
# The subject line has to match "${pats[@]}", but to be more verbose different
|
|
# error messages are printed for the different 'levels' of the pattern.
|
|
declare -a pats msg
|
|
pats=(
|
|
"^(.+:)+ "
|
|
"([A-Z\`'\"])"
|
|
".*[^.]$"
|
|
)
|
|
msg=(
|
|
"Specify which program was modified. (e.g. \"zsh:p10k: <subject>\")\n"
|
|
"Start subject with a capital letter.\n"
|
|
"Remove punctuation mark from end.\n"
|
|
)
|
|
[[ ${#msg[@]} -ge ${#pats[@]} ]] || die "Something went wrong internally."
|
|
for ((i = 0; i < ${#pats[@]}; i++)); do
|
|
if ! grep -qE "$(printf "%s" "${pats[@]:0:$i+1}")" <<<"$subject"; then
|
|
die "${msg[$i]}"
|
|
fi
|
|
done
|
|
|
|
BKP_IFS="$IFS"
|
|
IFS='
|
|
'
|
|
for line in $body; do
|
|
[[ ${#line} -gt 72 ]] || continue
|
|
|
|
# Allow links on single lines and in trailers
|
|
[[ ! $line =~ ^([-A-Za-z0-9]*:)?[\ \ ]*https?://[^\ ]*$ ]] || continue
|
|
|
|
die "Body lines too long. (<= 72)"
|
|
done
|
|
IFS="$BKP_IFS"
|