@@ -364,7 +364,7 @@ while true; do
364364 validate_commit_message
365365
366366 # if there are no WARNINGS are empty then we're good to break out of here
367- test ${# WARNINGS[@]} -eq 0 && exit 0
367+ test ${# WARNINGS[@]} -eq 0 && break
368368
369369 display_warnings
370370
@@ -389,3 +389,100 @@ while true; do
389389 esac
390390
391391done
392+
393+ #
394+ # Append a deterministic Change-Id (Gerrit algorithm) when not already present.
395+ #
396+
397+ if grep -q ' ^Change-Id: I[0-9a-f]\{40\}' " $COMMIT_MSG_FILE " ; then
398+ exit 0
399+ fi
400+
401+ clean_message= $( sed -n -e ' /^#/d' -e ' /^diff --git /q' \
402+ -e ' /^Signed-off-by:/d' -e p " $COMMIT_MSG_FILE " | git stripspace)
403+
404+ # Nothing to sign: skip.
405+ [ -z " $clean_message " ] && exit 0
406+
407+ _gen_changeid_input ()
408+ {
409+ local tree parent author committer
410+
411+ tree=$( git write-tree) || return 1
412+ author=$( git var GIT_AUTHOR_IDENT) || return 1
413+ committer=$( git var GIT_COMMITTER_IDENT) || return 1
414+
415+ echo " tree $tree "
416+ if parent=$( git rev-parse " HEAD^0" 2> /dev/null) ; then
417+ echo " parent $parent "
418+ fi
419+ echo " author $author "
420+ echo " committer $committer "
421+ echo
422+ printf ' %s' " $clean_message "
423+ }
424+
425+ if ! change_id_input=$( _gen_changeid_input) ; then
426+ echo " Failed to build Change-Id input" >&2
427+ exit 1
428+ fi
429+
430+ if ! change_id=$( printf ' %s' " $change_id_input " | git hash-object -t commit --stdin) ; then
431+ echo " Failed to compute Change-Id" >&2
432+ exit 1
433+ fi
434+
435+ if [[ ! " $change_id " =~ ^[0-9a-f]{40}$ ]]; then
436+ echo " Failed to compute valid Change-Id" >&2
437+ exit 1
438+ fi
439+
440+ commentChar= $( git config --get core.commentChar 2> /dev/null || echo ' #' )
441+ # 'auto' means Git picks dynamically; treat as '#' for our purposes.
442+ [[ " $commentChar " == " auto" || -z " $commentChar " ]] && commentChar= ' #'
443+
444+ awk -v id= " $change_id " -v cc= " $commentChar " '
445+ BEGIN {
446+ isFooter = 0; footerComment = 0; blankLines = 0
447+ }
448+ index($0, cc) == 1 { next }
449+ /^diff --git / { blankLines = 0; while (getline) {}; next }
450+ /^$/ && (footerComment == 0) { blankLines++; next }
451+ /^\[[a-zA-Z0-9-]+:/ && (isFooter == 1) { footerComment = 1 }
452+ /]$/ && (footerComment == 1) { footerComment = 2 }
453+ (blankLines > 0) {
454+ print lines
455+ for (i = 0; i < blankLines; i++) print ""
456+ lines = ""; blankLines = 0; isFooter = 1; footerComment = 0
457+ }
458+ (footerComment == 0) && (!/^\[?[a-zA-Z0-9-]+:/ || /^[a-zA-Z0-9-]+:\/\//) {
459+ isFooter = 0
460+ }
461+ {
462+ if (footerComment == 2) footerComment = 0
463+ if (lines != "") lines = lines "\n"
464+ lines = lines $0
465+ }
466+ END {
467+ unprinted = 1
468+ if (isFooter == 0) { print lines "\n"; lines = "" }
469+ numlines = split(lines, footer, "\n")
470+ trailers = ""; other = ""
471+ for (i = 1; i <= numlines; i++) {
472+ low = tolower(footer[i])
473+ if (low ~ /^(signed-off|reviewed|co-authored|acked|suggested|tested|reported)-by:/) {
474+ trailers = trailers footer[i] "\n"
475+ } else {
476+ other = other footer[i] "\n"
477+ }
478+ }
479+ if (other != "") printf "%s", other
480+ if (trailers != "") printf "%s", trailers
481+ printf "Change-Id: I%s\n", id
482+ }' " $COMMIT_MSG_FILE " > " ${COMMIT_MSG_FILE} .tmp"
483+
484+ if ! mv " ${COMMIT_MSG_FILE} .tmp" " $COMMIT_MSG_FILE " ; then
485+ rm -f " ${COMMIT_MSG_FILE} .tmp"
486+ echo " Failed to write Change-Id to commit message" >&2
487+ exit 1
488+ fi
0 commit comments