diff --git a/hooks/commit-msg b/hooks/commit-msg index d9bb188b..70d67eaf 100755 --- a/hooks/commit-msg +++ b/hooks/commit-msg @@ -1,5 +1,5 @@ #!/bin/sh -# From Gerrit Code Review 2.14.6 +# From Gerrit Code Review 3.1.3 # # Part of Gerrit Code Review (https://www.gerritcodereview.com/) # @@ -16,176 +16,48 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -# -unset GREP_OPTIONS +# avoid [[ which is not POSIX sh. +if test "$#" != 1 ; then + echo "$0 requires an argument." + exit 1 +fi -CHANGE_ID_AFTER="Bug|Depends-On|Issue|Test|Feature|Fixes|Fixed" -MSG="$1" +if test ! -f "$1" ; then + echo "file does not exist: $1" + exit 1 +fi -# Check for, and add if missing, a unique Change-Id -# -add_ChangeId() { - clean_message=`sed -e ' - /^diff --git .*/{ - s/// - q - } - /^Signed-off-by:/d - /^#/d - ' "$MSG" | git stripspace` - if test -z "$clean_message" - then - return - fi +# Do not create a change id if requested +if test "false" = "`git config --bool --get gerrit.createChangeId`" ; then + exit 0 +fi - # Do not add Change-Id to temp commits - if echo "$clean_message" | head -1 | grep -q '^\(fixup\|squash\)!' - then - return - fi +# $RANDOM will be undefined if not using bash, so don't use set -u +random=$( (whoami ; hostname ; date; cat $1 ; echo $RANDOM) | git hash-object --stdin) +dest="$1.tmp.${random}" - if test "false" = "`git config --bool --get gerrit.createChangeId`" - then - return - fi +trap 'rm -f "${dest}"' EXIT - # Does Change-Id: already exist? if so, exit (no change). - if grep -i '^Change-Id:' "$MSG" >/dev/null - then - return - fi +if ! git stripspace --strip-comments < "$1" > "${dest}" ; then + echo "cannot strip comments from $1" + exit 1 +fi - id=`_gen_ChangeId` - T="$MSG.tmp.$$" - AWK=awk - if [ -x /usr/xpg4/bin/awk ]; then - # Solaris AWK is just too broken - AWK=/usr/xpg4/bin/awk - fi +if test ! -s "${dest}" ; then + echo "file is empty: $1" + exit 1 +fi - # Get core.commentChar from git config or use default symbol - commentChar=`git config --get core.commentChar` - commentChar=${commentChar:-#} +# Avoid the --in-place option which only appeared in Git 2.8 +# Avoid the --if-exists option which only appeared in Git 2.15 +if ! git -c trailer.ifexists=doNothing interpret-trailers \ + --trailer "Change-Id: I${random}" < "$1" > "${dest}" ; then + echo "cannot insert change-id line in $1" + exit 1 +fi - # How this works: - # - parse the commit message as (textLine+ blankLine*)* - # - assume textLine+ to be a footer until proven otherwise - # - exception: the first block is not footer (as it is the title) - # - read textLine+ into a variable - # - then count blankLines - # - once the next textLine appears, print textLine+ blankLine* as these - # aren't footer - # - in END, the last textLine+ block is available for footer parsing - $AWK ' - BEGIN { - # while we start with the assumption that textLine+ - # is a footer, the first block is not. - isFooter = 0 - footerComment = 0 - blankLines = 0 - } - - # Skip lines starting with commentChar without any spaces before it. - /^'"$commentChar"'/ { next } - - # Skip the line starting with the diff command and everything after it, - # up to the end of the file, assuming it is only patch data. - # If more than one line before the diff was empty, strip all but one. - /^diff --git / { - blankLines = 0 - while (getline) { } - next - } - - # Count blank lines outside footer comments - /^$/ && (footerComment == 0) { - blankLines++ - next - } - - # Catch footer comment - /^\[[a-zA-Z0-9-]+:/ && (isFooter == 1) { - footerComment = 1 - } - - /]$/ && (footerComment == 1) { - footerComment = 2 - } - - # We have a non-blank line after blank lines. Handle this. - (blankLines > 0) { - print lines - for (i = 0; i < blankLines; i++) { - print "" - } - - lines = "" - blankLines = 0 - isFooter = 1 - footerComment = 0 - } - - # Detect that the current block is not the footer - (footerComment == 0) && (!/^\[?[a-zA-Z0-9-]+:/ || /^[a-zA-Z0-9-]+:\/\//) { - isFooter = 0 - } - - { - # We need this information about the current last comment line - if (footerComment == 2) { - footerComment = 0 - } - if (lines != "") { - lines = lines "\n"; - } - lines = lines $0 - } - - # Footer handling: - # If the last block is considered a footer, splice in the Change-Id at the - # right place. - # Look for the right place to inject Change-Id by considering - # CHANGE_ID_AFTER. Keys listed in it (case insensitive) come first, - # then Change-Id, then everything else (eg. Signed-off-by:). - # - # Otherwise just print the last block, a new line and the Change-Id as a - # block of its own. - END { - unprinted = 1 - if (isFooter == 0) { - print lines "\n" - lines = "" - } - changeIdAfter = "^(" tolower("'"$CHANGE_ID_AFTER"'") "):" - numlines = split(lines, footer, "\n") - for (line = 1; line <= numlines; line++) { - if (unprinted && match(tolower(footer[line]), changeIdAfter) != 1) { - unprinted = 0 - print "Change-Id: I'"$id"'" - } - print footer[line] - } - if (unprinted) { - print "Change-Id: I'"$id"'" - } - }' "$MSG" > "$T" && mv "$T" "$MSG" || rm -f "$T" -} -_gen_ChangeIdInput() { - echo "tree `git write-tree`" - if parent=`git rev-parse "HEAD^0" 2>/dev/null` - then - echo "parent $parent" - fi - echo "author `git var GIT_AUTHOR_IDENT`" - echo "committer `git var GIT_COMMITTER_IDENT`" - echo - printf '%s' "$clean_message" -} -_gen_ChangeId() { - _gen_ChangeIdInput | - git hash-object -t commit --stdin -} - - -add_ChangeId +if ! mv "${dest}" "$1" ; then + echo "cannot mv ${dest} to $1" + exit 1 +fi