diff options
author | Chris Smith <toonarmy@phpbb.com> | 2010-07-12 02:04:29 +0100 |
---|---|---|
committer | Chris Smith <toonarmy@phpbb.com> | 2010-08-10 14:48:46 +0100 |
commit | db13dc2d433ad635b8de3454292362d681a92fb4 (patch) | |
tree | 835d9ba60a883b0d545e5c63bfee0248d1b7d6ca | |
parent | 66e58234ecf05a4c9cbc401490c602694c920ed4 (diff) | |
download | forums-db13dc2d433ad635b8de3454292362d681a92fb4.tar forums-db13dc2d433ad635b8de3454292362d681a92fb4.tar.gz forums-db13dc2d433ad635b8de3454292362d681a92fb4.tar.bz2 forums-db13dc2d433ad635b8de3454292362d681a92fb4.tar.xz forums-db13dc2d433ad635b8de3454292362d681a92fb4.zip |
[task/git-tools] Vastly expanded commit-msg hook.
This updated hook supports validates each line of the commit message
confirms to the phpBB standards [1], there are two git config options
which adjust the behaviour of the hook. They are:
* phpbb.hooks.commit-msg.fatal: Set to false for the hook to allow
commits with malformed structure, useful if you'll be squashing
or editing the commits later. True is the default value.
* phpbb.hooks.commit-msg.debug: Any integer value greater than 0 will
increase the debugging verbosity of the hook, the default value is 0.
[1] http://wiki.phpbb.com/display/DEV/Git
PHPBB3-9768
-rwxr-xr-x | git-tools/hooks/commit-msg | 229 |
1 files changed, 224 insertions, 5 deletions
diff --git a/git-tools/hooks/commit-msg b/git-tools/hooks/commit-msg index be1923ab6b..894e67aa09 100755 --- a/git-tools/hooks/commit-msg +++ b/git-tools/hooks/commit-msg @@ -12,15 +12,234 @@ # ln -s ../../git-tools/hooks/commit-msg \\ # .git/hooks/commit-msg -status=0; +config_ns="phpbb.hooks.commit-msg"; + +if [ "$(git config --bool $config_ns.fatal)" = "false" ] +then + fatal=0; +else + fatal=1; +fi + +debug_level=$(git config --int $config_ns.debug || echo 0); + +# Error codes +ERR_LENGTH=1; +ERR_HEADER=2; +ERR_EMPTY=3; +ERR_DESCRIPTION=4; +ERR_FOOTER=5; +ERR_EOF=6; +ERR_UNKNOWN=42; + +debug() +{ + local level; + + level=$1; + shift; + + if [ $debug_level -ge $level ] + then + echo $@; + fi +} + +quit() +{ + if [ $1 -gt 0 ] && [ $1 -ne $ERR_UNKNOWN ] && [ $fatal -eq 0 ] + then + exit 0; + else + exit $1; + fi +} if [ "$(wc --max-line-length "$1" | cut -f1 -d" ")" -gt 80 ] then - echo "The following lines are greater than 80 characters long:\n"; + echo "The following lines are greater than 80 characters long:\n" >&2; - grep -nE '.{81,}' "$1"; + grep -nE '.{81,}' "$1" >&2; - status=1; + quit $ERR_LENGTH; fi -exit $status; +lines=$(wc --lines "$1" | cut -f1 -d" "); +expecting=header; +in_description=0; +in_empty=0; +ticket=0; +branch_regex="[a-z]+[a-z0-9-]*[a-z0-9]+"; +i=1; +tickets=""; + +while [ $i -le $lines ] +do + # Grab the line we are studying + line=$(head -n$i "$1" | tail -n1); + + debug 1 "==> [$i] $line (description: $in_description, empty: $in_empty)"; + + err=$ERR_UNKNOWN; + + if [ -z "$expecting" ] + then + quit $err; + fi + + debug 2 "Expecting: $expecting"; + + # Loop over each of the expected line formats + for expect in $expecting + do + # Reset the error code each iteration + err=$ERR_UNKNOWN; + + # Test for validity of each line format + # This is done first so $? contains the result + case $expect in + "header") + err=$ERR_HEADER; + echo "$line" | grep -Eq "^\[(ticket/[0-9]+|feature/$branch_regex|task/$branch_regex)\] [A-Z].+$" + ;; + "empty") + err=$ERR_EMPTY; + echo "$line" | grep -Eq "^$" + ;; + "description") + err=$ERR_DESCRIPTION; + # Free flow text, the line length was constrained by the initial check + echo "$line" | grep -Eq "^.+$"; + ;; + "footer") + err=$ERR_FOOTER; + # Each ticket is on its own line + echo "$line" | grep -Eq "^PHPBB3-[0-9]+$"; + ;; + "eof") + err=$ERR_EOF; + # Should not end up here + false + ;; + *) + echo "Unrecognised token $expect" >&2; + quit $err; + ;; + esac + + # Preserve the result of the line check + result=$?; + + debug 2 "$expect - '$line' - $result"; + + if [ $result -eq 0 ] + then + # Break out the loop on success + # otherwise roll on round and keep looking for a match + break; + fi + done + + if [ $result -eq 0 ] + then + # Have we switched out of description mode? + if [ $in_description -eq 1 ] && [ "$expect" != "description" ] && [ "$expect" != "empty" ] + then + # Yes, okay we need to backtrace one line and reanalyse + in_description=0; + i=$(( $i - $in_empty )); + + # Reset the empty counter + in_empty=0; + continue; + fi + + # Successful match, but on which line format + case $expect in + "header") + expecting="empty eof"; + + echo "$line" | grep -Eq "^\[ticket/[0-9]+\]$" && ( + ticket=$(echo "$line" | sed 's,\[ticket/\([0-9]*\)\].*,\1,'); + ) + ;; + "empty") + # Description might have empty lines as spacing + expecting="footer description"; + in_empty=$(($in_empty + 1)); + + if [ $in_description -eq 1 ] + then + expecting="$expecting empty"; + fi + ;; + "description") + expecting="description empty eof"; + in_description=1; + ;; + "footer") + expecting="footer eof"; + if [ "$tickets" = "" ] + then + tickets="$line"; + else + tickets="$tickets $line"; + fi + ;; + *) + echo "Unrecognised token $expect" >&2; + quit 254; + ;; + esac + + if [ "$expect" != "empty" ] + then + in_empty=0; + fi + + debug 3 "Now expecting: $expecting"; + else + # None of the expected line formats matched + # Guess we'll call it a day here then + echo "Syntax error on line $i:" >&2; + echo ">> $line" >&2; + echo -n "Expecting: " >&2; + echo "$expecting" | sed 's/ /, /g' >&2; + exit $err; + fi + + i=$(( $i + 1 )); +done + +# If EOF is expected exit cleanly +echo "$expecting" | grep -q "eof" || ( + # Unexpected EOF, error + echo "Unexpected EOF encountered" >&2; + quit $ERR_EOF; +) && ( + # Do post scan checks + if [ ! -z "$tickets" ] + then + # Check for duplicate tickets + dupes=$(echo "$tickets" | sed 's/ /\n/g' | sort | uniq -d); + + if [ ! -z "$dupes" ] + then + echo "The following tickets are repeated:" >&2; + echo "$dupes" | sed 's/ /\n/g;s/^/* /g' >&2; + quit $ERR_FOOTER; + fi + fi + # Check the branch ticket is mentioned, doesn't make sense otherwise + if [ $ticket -gt 0 ] + then + echo "$tickets" | grep -Eq "\bPHPBB3-$ticket\b" || ( + echo "Ticket ID [$ticket] of branch missing from list of tickets:" >&2; + echo "$tickets" | sed 's/ /\n/g;s/^/* /g' >&2; + quit $ERR_FOOTER; + ) || exit $?; + fi + # Got here okay exit to reality + exit 0; +); +exit $?; |