#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # # This file is part of Lustre, http://www.lustre.org/ # # contrib/git-hooks/prepare-commit-msg # # 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=${CHECKPATCH:-contrib/scripts/checkpatch.pl} CHECKPATCH_OPTS=${CHECKPATCH_OPTS:-"--no-signoff --no-tree"} SHELLCHECK=${SHELLCHECK:-$(which shellcheck)} SHELLCHECK_OPTS=${SHELLCHECK_OPTS:-" -f gcc "} SHELLCHECK_RUN=${SHELLCHECK_RUN:-"yes"} # run everytime by default # 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 Test-Parameters: line. This will let the developer # uncomment it out if they think it's appropriate. echo "#" >> "$1" echo "# If this patch makes only non-functional changes, or test-only" >> "$1" echo "# changes, consider adding this 'Test-Parameters' in the" >> "$1" echo "# commit message:" >> "$1" echo "#" >> "$1" echo "# Test-Parameters: trivial" >> "$1" echo "#" >> "$1" echo "# If you need to repeat the same subtest many times, consider" >> "$1" echo "# this instead:" >> "$1" echo "#" >> "$1" echo "# Test-Parameters: trivial testlist=sanity env=ONLY=1,ONLY_REPEAT=100" >> "$1" echo "#" >> "$1" echo "# https://wiki.whamcloud.com/display/PUB/Changing+Test+Parameters+with+Gerrit+Commit+Messages" >> "$1" echo "#" >> "$1" # 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. # The developer should uncomment it to include it in the commit message. echo "#" >> "$1" echo "# The 'Signed-off-by' line signifies that you agree to the Developer" >> "$1" echo "# Certificate of Origin - https://developercertificate.org/" >> "$1" echo "#" >> "$1" 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, as there may be exceptions and it is better let a person decide. if [ -x "$CHECKPATCH" ]; then echo "" >> "$1" echo "#" >> "$1" [ -d ".git/rebase-apply" -o -d ".git/rebase-merge" ] && DIFFOPT="HEAD" || DIFFOPT="--cached" git diff $DIFFOPT | $CHECKPATCH $CHECKPATCH_OPTS - | sed -e 's/^/# /' >> "$1" fi # Add the shellcheck output as comments, but don't cause a commit error. if [[ -x "$SHELLCHECK" && "$SHELLCHECK_RUN" == "yes" ]]; then # Add header echo "#" >> "$1" echo "# shellcheck output:" >> "$1" echo "#" >> "$1" # Get file that needs to be shellchecked. We only consider *.sh files # Example Start -- # modified: lustre/tests/sanity.sh # modified: contrib/git-hooks/prepare-commit-msg # new: lustre/utils/liblustreapi_error.c # Example End -- mod_files=($(awk '/modified:.*\.sh|new:.*\.sh/ { print $3 }' $1)) for cur_file in ${mod_files[@]}; do # Shebangs should prefer bash over regular sh. This allows # scripts to freely use bash-isms and lowers the risks of # failures on Debian based platforms. Output a small warning # if #!/bin/sh is found. echo "#" $(grep -Hn "#\!/bin/sh" "$cur_file" && \ echo " : Please don't use sh in shebangs.") >> "$1" # Get start/end range of lines that needs to be reported # range presently not used will come in handy when dealing with # warnings reported by shellcheck # Example 'git show' output Start -- # @@ -29,6 +29,7 @@ DEF_STRIPE_COUNT=-1 # Example 'git show' output End -- range=($(git show $cur_file | awk '/^@@/ { print $3 }' | \ sed -e 's/+//' -e 's/,/ /')) start_line=${range[0]} end_line=$((start_line + ${range[1]})) # 'shellcheck' reports errors/warnings/notes as below: # Example start --- # sanity-lnet.sh:2319:13: error: Double quote array \ # expansions to avoid re-splitting elements. [SC2068] # # sanity-lnet.sh:2421:27: note: Double quote to prevent \ # globbing and word splitting. [SC2086] # # sanity-lnet.sh:2411:8: warning: Declare and assign \ # separately to avoid masking return values. [SC2155] # Example end --- $SHELLCHECK $SHELLCHECK_OPTS $cur_file | while IFS=": " read -r file line char mtype msg; do # Only filter out "errors" reported by shellcheck # We ignore "warnings" and "notes" for now. # TODO "Warnings" reported by shellcheck will come later [[ "$mtype" == "error" ]] || continue # Empty line we skip it. [[ -n "$line" ]] || continue echo "# $file:$line:$char $mtype: $msg" >> "$1" done done echo "#" >> "$1" fi # Cause Vim to wrap text at 70 columns to match commit message style. # Adding a matching emacs modeline would be good, if I knew how to do that. echo "# vim:textwidth=70:" >> "$1" # Add these comments at the end # So that Vim does not pretend # The "echo" above is actually # A modeline for this file. Savvy?