Whamcloud - gitweb
LU-15617 contrib: Add shellcheck to prepare-commit-msg
[fs/lustre-release.git] / contrib / git-hooks / prepare-commit-msg
1 #!/bin/bash
2 #
3 # A Git hook script to prepare the commit log message.  Install into
4 # lustre/.git/hooks/prepare-commit-msg to enable for Lustre commits.
5 #
6 # Called by git-commit with the name of the file that has the
7 # commit message, followed by the description of the commit
8 # message's source.  The hook's purpose is to edit the commit
9 # message file.  If the hook fails with a non-zero status,
10 # the commit is aborted.
11 #
12 # Commit hook to check the patch against the Lustre coding style.
13 # It adds any checkpatch warnings/errors as commit comments, which
14 # means that they can currently be ignored, but are at least visible.
15
16 CHECKPATCH=${CHECKPATCH:-contrib/scripts/checkpatch.pl}
17 CHECKPATCH_OPTS=${CHECKPATCH_OPTS:-"--no-signoff --no-tree"}
18 SHELLCHECK=${SHELLCHECK:-$(which shellcheck)}
19 SHELLCHECK_OPTS=${SHELLCHECK_OPTS:-" -f gcc "}
20 SHELLCHECK_RUN=${SHELLCHECK_RUN:-"yes"} # run everytime by default
21
22 # If there are no comments in the commit, it is likely a rebase and
23 # this shouldn't be adding new comments, or they appear in the commit.
24 grep -q "^#" "$1" || exit 0
25
26 # Add a commented-out Signed-off-by: line.  This shouldn't be added in an
27 # uncommented form, otherwise sanity checking for an emtpy commit fails.
28 # The developer should uncomment it to include it in the commit message.
29 SIGNOFF=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
30 grep -qs "^$SIGNOFF" "$1" || echo "# $SIGNOFF" >> "$1"
31
32 # Add the checkpatch.pl output as comments, but don't cause a commit error
33 # yet, as there may be exceptions and it is better let a person decide.
34 if [ -x "$CHECKPATCH" ]; then
35         echo "" >> "$1"
36         echo "#" >> "$1"
37         [ -d ".git/rebase-apply" -o -d ".git/rebase-merge" ] &&
38                 DIFFOPT="HEAD" || DIFFOPT="--cached"
39         git diff $DIFFOPT | $CHECKPATCH $CHECKPATCH_OPTS - |
40                 sed -e 's/^/# /' >> "$1"
41 fi
42
43 # Add the shellcheck output as comments, but don't cause a commit error.
44 if [[ -x "$SHELLCHECK" && "$SHELLCHECK_RUN" == "yes" ]]; then
45         # Add header
46         echo "#" >> "$1"
47         echo "# shellcheck output:" >> "$1"
48         echo "#" >> "$1"
49         # Get file that needs to be shellchecked. We only consider *.sh files
50         # Example Start --
51         #       modified:   lustre/tests/sanity.sh
52         #       modified:   contrib/git-hooks/prepare-commit-msg
53         #            new:   lustre/utils/liblustreapi_error.c
54         # Example End   --
55         mod_files=($(awk '/modified:.*\.sh|new:.*\.sh/ { print $3 }' $1))
56         for cur_file in ${mod_files[@]}; do
57                 # Get start/end range of lines that needs to be reported
58                 # range presently not used will come in handy when dealing with
59                 # warnings reported by shellcheck
60                 # Example 'git show' output Start --
61                 #       @@ -29,6 +29,7 @@ DEF_STRIPE_COUNT=-1
62                 # Example 'git show' output End   --
63                 range=($(git show $cur_file | awk '/^@@/ { print $3 }' | \
64                         sed -e 's/+//' -e 's/,/ /'))
65                 start_line=${range[0]}
66                 end_line=$((start_line + ${range[1]}))
67
68                 # 'shellcheck' reports errors/warnings/notes as below:
69                 # Example start ---
70                 #        sanity-lnet.sh:2319:13: error: Double quote array \
71                 #        expansions to avoid re-splitting elements. [SC2068]
72                 #
73                 #        sanity-lnet.sh:2421:27: note: Double quote to prevent \
74                 #        globbing and word splitting. [SC2086]
75                 #
76                 #        sanity-lnet.sh:2411:8: warning: Declare and assign \
77                 #        separately to avoid masking return values. [SC2155]
78                 # Example end   ---
79                 $SHELLCHECK $SHELLCHECK_OPTS $cur_file |
80                         while IFS=": " read -r file line char mtype msg; do
81                         # Only filter out "errors" reported by shellcheck
82                         # We ignore "warnings" and "notes" for now.
83                         # TODO "Warnings" reported by shellcheck will come later
84                         [[ "$mtype" == "error" ]] || continue
85                         # Empty line we skip it.
86                         [[ -n "$line" ]] || continue
87                         echo "# $file:$line:$char $mtype: $msg" >> "$1"
88                 done
89         done
90         echo "#" >> "$1"
91 fi
92
93 # Cause Vim to wrap text at 70 columns to match commit message style.
94 # Adding a matching emacs modeline would be good, if I knew how to do that.
95 echo "# vim:textwidth=70:" >> "$1"
96
97 # Add these comments at the end
98 # So that Vim does not pretend
99 # The "echo" above is actually
100 # A modeline for this file. Savvy?