X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=build%2Fcommit-msg;h=422117e9363642c9b2e6879284dbc8aff25f305c;hp=1fab5095a4d8a372fe46a69c1d6be58c84a63317;hb=68cdeeb2f587f5cf16a87b14644d6366b1ccb9d9;hpb=3f5e72e4cff0d5238fa3ef7a7acf27c86ea973e8 diff --git a/build/commit-msg b/build/commit-msg index 1fab509..422117e 100755 --- a/build/commit-msg +++ b/build/commit-msg @@ -12,42 +12,159 @@ # 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 +init() { + set -a + readonly ORIGINAL="$1" + readonly REVISED="$(mktemp "$ORIGINAL.XXXXXX")" + readonly SAVE="$(basename $ORIGINAL).$(date +%Y%m%d.%H%M%S)" + readonly SIGNOFF="Signed-off-by:" + readonly CHANGEID="Change-Id:" + readonly TESTPARAMS="Test-Parameters:" + readonly INNOCUOUS=$(echo \ + Acked-by \ + Tested-by \ + Reported-by \ + Reviewed-by \ + CC \ + | tr ' ' '|') + readonly WIDTH_SUM=62 + readonly WIDTH_REG=70 + readonly JIRA_FMT_A="^[A-Z]\{2,5\}-[0-9]\{1,5\} [-a-z0-9]\{2,9\}: " + readonly JIRA_FMT_B="^[A-Z]\{2,5\}-[0-9]\{1,5\} " + + # Identify a name followed by an email address. + # + readonly EMAILPAT=$'[ \t]*[^<> ]* [^<>]* <[^@ \t>]+@[a-zA-Z0-9.-]+\.[a-z]+>' + + HAS_ERROR=false + HAS_SUMMARY=false + HAS_LAST_BLANK=false + HAS_BODY=false + HAS_SIGNOFF=false + HAS_CHANGEID=false + + IS_WRAPPING_UP=false + + LINE="" + NUM=0 + set +a } -error() { - [ "$LINE" ] && echo "line $NUM: $LINE" 1>&2 - [ "$1" ] && echo "error: commit message $1" 1>&2 - [ "$2" ] && echo "$2" 1>&2 +# die: commit-msg fatal error: script error or empty input message +# All output redirected to stderr. +# +die() { + echo "commit-msg fatal error: $*" + test -f "$REVISED" && rm -f "$REVISED" + exit 1 +} 1>&2 + +# Called when doing the final "wrap up" clause because we've found +# one of the tagged lines that belongs in the final section. +# +function ck_wrapup() { + $IS_WRAPPING_UP && return + + $HAS_LAST_BLANK || error "blank line must preceed signoff section" + $HAS_SUMMARY || error "missing commit summary line." + $HAS_BODY || error "missing commit description." + + HAS_LAST_BLANK=false + IS_WRAPPING_UP=true +} + +function do_signoff() { + ck_wrapup + # Signed-off-by: First Last + local txt=$(echo "${LINE#*: }" | grep -E "${EMAILPAT}") + if (( ${#txt} == 0 )); then + error "$SIGNOFF line requires name and email address" + else + HAS_SIGNOFF=true # require at least one + fi +} + +function do_changeid() { + ck_wrapup + $HAS_CHANGEID && error "multiple $CHANGEID lines are not allowed" + + # Change-Id: I1234567890123456789012345678901234567890 + # capital "I" plus 40 hex digits + # + local txt=$(echo "$LINE" | grep "^$CHANGEID I[0-9a-fA-F]\{40\}\$") + (( ${#txt} > 0 )) || + error "has invalid $CHANGEID line for Gerrit tracking" + + HAS_CHANGEID=true +} + +# All "innocuous" lines specify a person and email address +# +function do_innocuous() { + ck_wrapup + local txt=$(echo "${LINE#*: }" | grep -E "${EMAILPAT}") + (( ${#txt} == 0 )) && error "invalid name and address" +} + +function do_default_line() { + $IS_WRAPPING_UP && { + error "invalid signoff section line" + return + } + if (( NUM == 1 )); then + HAS_JIRA_COMPONENT=$(echo "$LINE" | grep "$JIRA_FMT_A") + + if (( ${#HAS_JIRA_COMPONENT} == 0 )); then + HAS_JIRA=$(echo "$LINE" | grep "$JIRA_FMT_B") + if (( ${#HAS_JIRA} > 0 )); then + error "has no component in summary." + else + error "missing JIRA ticket number." + fi + elif (( ${#LINE} > WIDTH_SUM )); then + error "summary longer than $WIDTH_SUM columns." + else + HAS_SUMMARY=true + fi - HAS_ERROR=true + elif (( ${#LINE} > 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 } +# Add a new unique Change-Id +# +new_changeid() { + local 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) + (( ${#NEWID} > 0 )) || + die "git hash-object failed for $CHANGEID:" + + echo "$CHANGEID I$NEWID" +} + +# A commit message error was encountered. +# All output redirected to stderr. +# +error() { + (( ${#LINE} > 0 )) && echo "line $NUM: $LINE" + echo "error: commit message $*" | fmt + HAS_ERROR=true +} 1>&2 + usage() { - cat 1>&2 <<- EOF + exec 1>&2 + cat <<- EOF See http://wiki.whamcloud.com/display/PUB/Commit+Comments for full details. An example valid commit comment is: @@ -69,148 +186,106 @@ usage() { 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 + Finish the comment with a blank line and a blank-line-free + sign off section: + + $SIGNOFF Your Real Name + $CHANGEID Ixxxx(added automatically if missing)xxxx + The "$CHANGEID" line should only be there when updating a previous + commit/submission. Copy the one from the original commit. + + The "sign off section" may also include several other tag lines: + $(for T in $(tr '|' ' ' <<< "$INNOCUOUS"); do \ + echo " $T: Some Person "; \ + done) + $TESTPARAMS optional additional test parameters + {Organization}-bug-id: associated external change identifier EOF - mv "$ORIGINAL" "$SAVE" && - echo "$0: saved original commit comment to $SAVE" 1>&2 + 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 +init ${1+"$@"} +exec 3< "$ORIGINAL" 4> "$REVISED" || exit 1 + +while IFS= read -u3 LINE; do + ((NUM += 1)) + case "$LINE" in + $SIGNOFF* ) do_signoff ;; + $CHANGEID* ) do_changeid ;; + $TESTPARAMS* ) ck_wrapup ;; + + "") + HAS_LAST_BLANK=true + $IS_WRAPPING_UP && continue + ;; + + \#*) + continue ## ignore and suppress comments + ;; + + "diff --git a/"* ) + # 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 + # deleted file mode 100644 + # old mode 100644 + # If a "diff --git" line is not followed by one of these + # lines, do the default line processing on both lines. + # + IFS= read -u3 INDEX || break + ((NUM += 1)) + case "$INDEX" in + "index "[0-9a-fA-F]*) break ;; + "deleted file mode "*) break ;; + "old mode "*) break ;; + esac + LINE=${LINE}$'\n'${INDEX} + do_default_line + ;; + + *) + if [[ "$LINE" =~ ^($INNOCUOUS): ]]; then + do_innocuous + elif [[ "$LINE" =~ ^[A-Za-z0-9_-]+-bug-id: ]]; then + ck_wrapup + else + # Allow arbitrary external bug identifiers for tracking. + # I can't seem to find a pattern for the "case" that + # checks for "*-bug-id", so this is checked here. + do_default_line + fi + ;; + esac + + echo "$LINE" >&4 +done + +(( NUM <= 0 )) && die "empty commit message" + +unset LINE +$HAS_SIGNOFF || error "missing valid $SIGNOFF: line." + if $HAS_ERROR; then - usage - rm "$REVISED" - exit 1 + exec 3<&- 4>&- + usage + rm "$REVISED" + exit 1 fi +$HAS_CHANGEID || new_changeid >&4 +exec 3<&- 4>&- + mv "$REVISED" "$ORIGINAL" + +## Local Variables: +## Mode: shell-script +## sh-basic-offset: 8 +## sh-indent-after-do: 8 +## sh-indentation: 8 +## sh-indent-for-case-label: 0 +## sh-indent-for-case-alt: 8 +## End: