Whamcloud - gitweb
LU-553 build: Lustre style commit hooks for Git
authorAndreas Dilger <adilger@whamcloud.com>
Thu, 25 Aug 2011 21:08:04 +0000 (15:08 -0600)
committerOleg Drokin <green@whamcloud.com>
Thu, 6 Oct 2011 00:47:05 +0000 (20:47 -0400)
Adds recommended commit hooks for Lustre commit messages, that
can/should be installed into lustre/.git/hooks for all Lustre trees.

prepare-commit-msg: adds the output of checkpatch.pl as a
    comment to the commit message, to "soft" validate the new
    patch is matching the Lustre coding style. It doesn't check
    100% of the Lustre coding style, but at least finds most of
    the obvious errors so that they can be fixed locally before
    any manual inspection time is spent on the patch.

commit-msg: verifies the format of the commit message (somewhat).
    Checks that there is a valid-looking Signed-off-by: line.
    Adds the Gerrit Change-Id: line for change tracking.

Signed-off-by: Andreas Dilger <adilger@whamcloud.com>
Change-Id: I35fdfb8206d1f0efb3bb401522e8412c62b7c02a
Reviewed-on: http://review.whamcloud.com/1296
Tested-by: Hudson
Tested-by: Maloo <whamcloud.maloo@gmail.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
README
build/commit-msg [new file with mode: 0755]
build/prepare-commit-msg [new file with mode: 0755]

diff --git a/README b/README
index 4ed5848..8f274ba 100644 (file)
--- a/README
+++ b/README
@@ -1,3 +1,13 @@
 Instructions for building, configuring and running Lustre can be found at:
-    http://wiki.lustre.org/index.php/Use
+    http://wiki.whamcloud.com/display/PUB/Submitting+Changes
+and:
+    http://wiki.whamcloud.com/display/PUB/Using+Gerrit
 
+The Lustre Coding Style Guidelines can be found at:
+    http://wiki.whamcloud.com/display/PUB/Coding+Guidelines
+
+In order to improve the quality of patches submitted to the Lustre tree,
+it is possible to automatically check every patch and commit against the
+Lustre Coding Guidelines.  To do this, run in the top-level lustre/ tree:
+
+    cp build/{prepare-,}commit-msg .git/hooks/
diff --git a/build/commit-msg b/build/commit-msg
new file mode 100755 (executable)
index 0000000..80a3442
--- /dev/null
@@ -0,0 +1,119 @@
+#!/bin/bash
+#
+# A hook script to check the commit log message to ensure that it has
+# a well-formed commit summary and body, a valid Signed-off-by: line,
+# and a Gerrit Change-Id: line (added automatically if missing).
+#
+# 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.
+#
+# Should be installed as .git/hooks/commit-msg.
+#
+
+ORIGINAL="$1"
+REVISED="$(mktemp "$1.XXXXXX")"
+SIGNOFF="Signed-off-by:"
+CHANGEID="Change-Id:"
+
+# Check for, and add if missing, a unique Change-Id
+new_changeid() {
+       {
+               git var GIT_AUTHOR_IDENT
+               git var GIT_COMMITTER_IDENT
+               git write-tree
+               git rev-parse HEAD 2>/dev/null
+               grep -v "$SIGNOFF" "$ORIGINAL" | git stripspace -s
+       } | git hash-object -t commit --stdin
+}
+
+usage() {
+       [ "$LINE" ] && echo "error:$NUM: $LINE" 1>&2 && echo "" 1>&2
+
+       cat 1>&2 <<- EOF
+       Commit message $1
+       $2
+       See http://wiki.whamcloud.com/display/PUB/Submitting+Changes
+       for full details.  An example valid commit comment is:
+
+       LU-nnn component: short description of change under 64 columns
+
+       A more detailed explanation.  This can be as detailed as you'd like.
+       Please explain both what problem was solved and a good high-level
+       description of how it was solved.  Wrap lines at 70 columns or less.
+
+       $SIGNOFF Your Real Name <your_email@domain.name>
+       $CHANGEID Ixxxx(added automatically if missing)xxxx
+       EOF
+
+       exit 1
+}
+
+export HAS_SIGNOFF=false
+export HAS_SUMMARY=false
+export HAS_BLANK=false
+export HAS_COMMENTS=false
+
+grep -q "^$CHANGEID" "$ORIGINAL" && HAS_CHANGEID=true || HAS_CHANGEID=false
+
+export LINE=""
+export NUM=1
+
+IFS=""
+while read LINE; do
+       LENGTH=$(echo $LINE | wc -c)
+
+       case "$LINE" in
+       $SIGNOFF*)
+               $HAS_SUMMARY || usage "missing summary before $SIGNOFF."
+               $HAS_BLANK || usage "missing blank line before $SIGNOFF."
+               GOOD=$(echo "$LINE" | grep "^$SIGNOFF .* .* <.*@.*>")
+               [ -z "$GOOD" ] &&
+                       usage "missing valid commit summary line to show" \
+                             "agreement with code submission requirements at"
+               HAS_SIGNOFF=true
+               echo $LINE
+               $HAS_CHANGEID || echo "$CHANGEID I$(new_changeid)"
+               ;;
+       $CHANGEID*)
+               $HAS_SUMMARY || usage "missing summary before $CHANGEID line."
+               $HAS_BLANK || usage "missing blank line before $CHANGEID line."
+               HAS_CHANGEID=true
+               echo $LINE
+               ;;
+       "")     [ $HAS_SUMMARY -a $NUM -eq 2 ] && HAS_BLANK=true
+               echo $LINE
+               ;;
+       \#*)    HAS_COMMENTS=true
+               continue
+               ;;
+       *)      if [ $NUM -eq 1 ]; then
+                       FMT="^[A-Z]\{2,5\}-[0-9]\{1,5\} [-a-z0-9]\{2,9\}: "
+                       GOOD=$(echo "$LINE" | grep "$FMT")
+                       [ $LENGTH -gt 64 ] &&
+                               usage "summary longer than 64 columns."
+                       if [ -z "$GOOD" ]; then
+                               FMT="^[A-Z]\{2,5\}-[0-9]\{1,5\} "
+                               NO_SUBSYS=$(echo "$LINE" | grep "$FMT")
+                               [ "$NO_SUBSYS" ] &&
+                                       usage "has no subsys: in commit summary"
+                               usage "missing valid commit summary line."
+                       fi
+                       HAS_SUMMARY=true
+               elif [ $LENGTH -gt 70 ]; then
+                       usage "has lines longer than 70 columns."
+               fi
+               echo $LINE
+               ;;
+       esac
+
+       NUM=$((NUM + 1))
+done < "$ORIGINAL" > "$REVISED"
+
+[ $NUM -eq 1 ] && exit 1 # empty file
+
+LINE=""
+$HAS_SUMMARY || usage "missing commit summary line."
+$HAS_SIGNOFF || usage "missing $SIGNOFF line."
+$HAS_CHANGEID && rm "$REVISED" || mv "$REVISED" "$ORIGINAL"
diff --git a/build/prepare-commit-msg b/build/prepare-commit-msg
new file mode 100755 (executable)
index 0000000..b84609e
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/bash
+#
+# A Git hook script to prepare the commit log message.  Install into
+# lustre/.git/hooks/prepare-commit-msg to enable for Lustre commits.
+#
+# Called by git-commit with the name of the file that has the
+# commit message, followed by the description of the commit
+# message's source.  The hook's purpose is to edit the commit
+# message file.  If the hook fails with a non-zero status,
+# the commit is aborted.
+#
+# Commit hook to check the patch against the Lustre coding style.
+# It adds any checkpatch warnings/errors as commit comments, which
+# means that they can currently be ignored, but are at least visible.
+
+CHECKPATCH=build/checkpatch.pl
+CHECKPATCH_OPTS="--no-signoff --no-tree --no-tabs"
+[ -r "$CHECKPATCH" ] || exit 0
+
+# If there are no comments in the commit, it is likely a rebase and
+# this shouldn't be adding new comments, or they appear in the commit.
+grep -q "^#" "$1" || exit 0
+
+# Add a commented-out Signed-off-by: line.  This shouldn't be added in an
+# uncommented form, otherwise sanity checking for an emtpy commit fails.
+SIGNOFF=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
+grep -qs "^$SIGNOFF" "$1" || echo "# $SIGNOFF" >> "$1"
+
+# Add the checkpatch.pl output as comments, but don't cause a commit error
+# yet, until there is more certainty that it is working correctly.
+echo "" >> "$1"
+echo "#" >> "$1"
+git diff --cached | $CHECKPATCH $CHECKPATCH_OPTS - | sed -e 's/^/# /' >> "$1"