#!/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 "$ORIGINAL.XXXXXX")" SAVE="$(basename $ORIGINAL).$(date +%Y%m%d.%H%M%S)" SIGNOFF="Signed-off-by" CHANGEID="Change-Id" WIDTH_SUM=64 WIDTH_REG=70 # Check for, and add if missing, a unique Change-Id new_changeid() { NEWID=$({ 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 --stdin) if [ -z "$NEWID" ]; then error "$0: git hash-object failed for $CHANGEID:" exit 1 fi echo "$CHANGEID: I$NEWID" HAS_CHANGEID=true } error() { [ "$LINE" ] && echo "line $NUM: $LINE" 1>&2 [ "$1" ] && echo "error: commit message $1" 1>&2 [ "$2" ] && echo "$2" 1>&2 HAS_ERROR=true } usage() { cat 1>&2 <<- EOF See http://wiki.whamcloud.com/display/PUB/Commit+Comments for full details. An example valid commit comment is: LU-nnn component: short description of change under 64 columns The "component:" should be a lower-case single-word subsystem of the Lustre code that best encompasses the change being made. Examples of components include modules like: llite, lov, lmv, osc, mdc, ldlm, lnet, ptlrpc, mds, oss, osd, ldiskfs, libcfs, socklnd, o2iblnd; functional subsystems like: recovery, quota, grant; and auxilliary areas like: build, tests, docs. This list is not exhaustive, but is a guideline. The commit comment should contain a detailed explanation of the change being made. This can be as long as you'd like. Please give details of what problem was solved (including error messages or problems that were seen), a good high-level description of how it was solved, and which parts of the code were changed (including important functions that were changed, if this is useful to understand the patch, and for easier searching). Wrap lines at/under $WIDTH_REG columns. $SIGNOFF: Your Real Name $CHANGEID: Ixxxx(added automatically if missing)xxxx EOF mv "$ORIGINAL" "$SAVE" && echo "$0: saved original commit comment to $SAVE" 1>&2 } export HAS_ERROR=false export HAS_SUMMARY=false export HAS_LAST_BLANK=false export HAS_BODY=false export HAS_SIGNOFF=false case $(grep -c "^$CHANGEID:" "$ORIGINAL") in 0) export HAS_CHANGEID=false ;; 1) export HAS_CHANGEID=true ;; *) error "with multiple $CHANGEID: lines not allowed." export HAS_CHANGEID=true HAS_ERROR=true ;; esac export HAS_COMMENTS=false export HAS_DIFF=false export LINE="" export NUM=1 IFS="" # don't eat whitespace, to preserve message formatting while read LINE; do WIDTH=$(($(echo $LINE | wc -c) - 1)) # -1 for end-of-line character case "$LINE" in $SIGNOFF*) # Signed-off-by: First Last HAS_SOB=$(echo "$LINE" | grep "^$SIGNOFF: .* .* <.*@[^.]*\..*>") if [ -z "$HAS_SOB" ]; then error "missing valid commit summary line to show" \ "agreement with code submission requirements." elif ! $HAS_SUMMARY; then error "missing summary before $SIGNOFF:." elif ! $HAS_LAST_BLANK; then error "missing blank line before $SIGNOFF:." elif ! $HAS_BODY; then error "missing useful comments before $SIGNOFF:." else HAS_SIGNOFF=true # allow multiple signoff lines fi echo $LINE ! $HAS_CHANGEID && new_changeid ;; $CHANGEID*) # Change-Id: I762ab50568f25527176ae54e92c446cf06112097 HAS_ID=$(echo "$LINE" | grep "^$CHANGEID: I[0-9a-fA-F]\{40\}") if [ -z "$HAS_ID" ]; then error "has invalid $CHANGEID: line for Gerrit tracking" elif ! $HAS_SUMMARY; then error "missing summary before $CHANGEID:." elif ! $HAS_BODY; then error "missing useful comments before $CHANGEID:." # $CHANGEID used to come before $SIGNOFF in old commits. # Allow this to continue for some time, until they are gone. # elif ! $HAS_SIGNOFF; then # error "missing $SIGNOFF: before $CHANGEID:." # $HAS_CHANGEID was already checked and set above #elif $HAS_CHANGEID; then # error "does not allow multiple $CHANGEID: lines." #else # HAS_CHANGEID=true fi echo $LINE ;; "") [ $HAS_SUMMARY -a ! $HAS_BODY ] && HAS_LAST_BLANK=true [ $HAS_BODY ] && HAS_LAST_BLANK=true echo $LINE ;; diff*|index*) # Beginning of uncommented diffstat from "commit -v". If # there are diff and index lines, skip the rest of the input. # diff --git a/build/commit-msg b/build/commit-msg # index 80a3442..acb4c50 100755 DIFF=$(echo "$LINE" | grep -- "^diff --git a/") [ "$DIFF" ] && HAS_DIFF=true && continue INDEX=$(echo "$LINE" | grep -- "^index [0-9a-fA-F]\{6,\}\.\.") [ $HAS_DIFF -a "$INDEX" ] && break || HAS_DIFF=false ;; \#*) HAS_COMMENTS=true continue ;; *) if [ $NUM -eq 1 ]; then FMT="^[A-Z]\{2,5\}-[0-9]\{1,5\} [-a-z0-9]\{2,9\}: " HAS_JIRA_COMPONENT=$(echo "$LINE" | grep "$FMT") if [ -z "$HAS_JIRA_COMPONENT" ]; then FMT="^[A-Z]\{2,5\}-[0-9]\{1,5\} " HAS_JIRA=$(echo "$LINE" | grep "$FMT") if [ "$HAS_JIRA" ]; then error "has no component in summary." else error "missing JIRA ticket number." fi elif [ $WIDTH -gt $WIDTH_SUM ]; then error "summary longer than $WIDTH_SUM columns." else HAS_SUMMARY=true fi elif $HAS_SIGNOFF; then error "trailing garbage after $SIGNOFF: line." elif [ $WIDTH -gt $WIDTH_REG ]; then error "has line longer than $WIDTH_REG columns." elif ! $HAS_BODY && ! $HAS_LAST_BLANK; then error "has no blank line after summary." else HAS_BODY=true fi HAS_LAST_BLANK=false HAS_DIFF=false echo $LINE ;; esac NUM=$((NUM + 1)) done < "$ORIGINAL" > "$REVISED" [ $NUM -eq 1 ] && exit 1 # empty file LINE="" if ! $HAS_SUMMARY; then error "missing commit summary line." elif ! $HAS_BODY; then error "missing commit description." elif ! $HAS_SIGNOFF; then error "missing valid $SIGNOFF: line." elif ! $HAS_CHANGEID; then error "missing valid $CHANGEID: line." fi if $HAS_ERROR; then usage rm "$REVISED" exit 1 fi mv "$REVISED" "$ORIGINAL"