1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
|
#! /bin/sh
# SPDX-License-Identifier: BSD-3-Clause
# Copyright 2016 6WIND S.A.
# Check commit logs (headlines and references)
#
# If any doubt about the formatting, please check in the most recent history:
# git log --format='%>|(15)%cr %s' --reverse | grep -i <pattern>
if [ "$1" = '-h' -o "$1" = '--help' ] ; then
cat <<- END_OF_HELP
usage: $(basename $0) [-h] [range]
Check commit log formatting.
The git range can be specified as a "git log" option,
e.g. -1 to check only the latest commit.
The default range starts from origin/master to HEAD.
END_OF_HELP
exit
fi
selfdir=$(dirname $(readlink -f $0))
range=${1:-origin/master..}
# convert -N to HEAD~N.. in order to comply with git-log-fixes.sh getopts
if printf -- $range | grep -q '^-[0-9]\+' ; then
range="HEAD$(printf -- $range | sed 's,^-,~,').."
fi
commits=$(git log --format='%h' --reverse $range)
headlines=$(git log --format='%s' --reverse $range)
bodylines=$(git log --format='%b' --reverse $range)
fixes=$(git log --format='%h %s' --reverse $range | grep -i ': *fix' | cut -d' ' -f1)
stablefixes=$($selfdir/git-log-fixes.sh $range | sed '/(N\/A)$/d' | cut -d' ' -f2)
tags=$(git log --format='%b' --reverse $range | grep -i -e 'by *:' -e 'fix.*:')
bytag='\(Reported\|Suggested\|Signed-off\|Acked\|Reviewed\|Tested\)-by:'
# check headline format (spacing, no punctuation, no code)
bad=$(echo "$headlines" | grep --color=always \
-e ' ' \
-e '^ ' \
-e ' $' \
-e '\.$' \
-e '[,;!?&|]' \
-e ':.*_' \
-e '^[^:]\+$' \
-e ':[^ ]' \
-e ' :' \
| sed 's,^,\t,')
[ -z "$bad" ] || printf "Wrong headline format:\n$bad\n"
# check headline prefix when touching only drivers, e.g. net/<driver name>
bad=$(for commit in $commits ; do
headline=$(git log --format='%s' -1 $commit)
files=$(git diff-tree --no-commit-id --name-only -r $commit)
[ -z "$(echo "$files" | grep -v '^\(drivers\|doc\|config\)/')" ] ||
continue
drv=$(echo "$files" | grep '^drivers/' | cut -d "/" -f 2,3 | sort -u)
drvgrp=$(echo "$drv" | cut -d "/" -f 1 | uniq)
if [ $(echo "$drvgrp" | wc -l) -gt 1 ] ; then
echo "$headline" | grep -v '^drivers:'
elif [ $(echo "$drv" | wc -l) -gt 1 ] ; then
echo "$headline" | grep -v "^drivers/$drvgrp"
else
echo "$headline" | grep -v "^$drv"
fi
done | sed 's,^,\t,')
[ -z "$bad" ] || printf "Wrong headline prefix:\n$bad\n"
# check headline label for common typos
bad=$(echo "$headlines" | grep --color=always \
-e '^example[:/]' \
-e '^apps/' \
-e '^testpmd' \
-e 'test-pmd' \
-e '^bond:' \
| sed 's,^,\t,')
[ -z "$bad" ] || printf "Wrong headline label:\n$bad\n"
# check headline lowercase for first words
bad=$(echo "$headlines" | grep --color=always \
-e '^.*[[:upper:]].*:' \
-e ': *[[:upper:]]' \
| sed 's,^,\t,')
[ -z "$bad" ] || printf "Wrong headline uppercase:\n$bad\n"
# check headline case (Rx/Tx, VF, L2, MAC, Linux ...)
IFS='
'
words="$selfdir/words-case.txt"
for word in $(cat $words); do
bad=$(echo "$headlines" | grep -iw $word | grep -v $word)
if [ "$word" = "Tx" ]; then
bad=$(echo $bad | grep -v 'OCTEON\ TX')
fi
for bad_line in $bad; do
bad_word=$(echo $bad_line | cut -d":" -f2 | grep -io $word)
if [ -n "$bad_word" ]; then
printf "Wrong headline case:\n\"$bad_line\": $bad_word --> $word\n"
fi
done
done
# check headline length (60 max)
bad=$(echo "$headlines" |
awk 'length>60 {print}' |
sed 's,^,\t,')
[ -z "$bad" ] || printf "Headline too long:\n$bad\n"
# check body lines length (75 max)
bad=$(echo "$bodylines" | grep -v '^Fixes:' |
awk 'length>75 {print}' |
sed 's,^,\t,')
[ -z "$bad" ] || printf "Line too long:\n$bad\n"
# check starting commit message with "It"
bad=$(for commit in $commits ; do
firstbodyline=$(git log --format='%b' -1 $commit | head -n1)
echo "$firstbodyline" | grep --color=always -ie '^It '
done | sed 's,^,\t,')
[ -z "$bad" ] || printf "Wrong beginning of commit message:\n$bad\n"
# check tags spelling
bad=$(echo "$tags" |
grep -v "^$bytag [^,]* <.*@.*>$" |
grep -v '^Fixes: [0-9a-f]\{7\}[0-9a-f]* (".*")$' |
sed 's,^.,\t&,')
[ -z "$bad" ] || printf "Wrong tag:\n$bad\n"
# check missing Coverity issue: tag
bad=$(for commit in $commits; do
body=$(git log --format='%b' -1 $commit)
echo "$body" | grep -qi coverity || continue
echo "$body" | grep -q '^Coverity issue:' && continue
git log --format='\t%s' -1 $commit
done)
[ -z "$bad" ] || printf "Missing 'Coverity issue:' tag:\n$bad\n"
# check missing Bugzilla ID: tag
bad=$(for commit in $commits; do
body=$(git log --format='%b' -1 $commit)
echo "$body" | grep -qi bugzilla || continue
echo "$body" | grep -q '^Bugzilla ID:' && continue
git log --format='\t%s' -1 $commit
done)
[ -z "$bad" ] || printf "Missing 'Bugzilla ID:' tag:\n$bad\n"
# check missing Fixes: tag
bad=$(for fix in $fixes ; do
git log --format='%b' -1 $fix | grep -q '^Fixes: ' ||
git log --format='\t%s' -1 $fix
done)
[ -z "$bad" ] || printf "Missing 'Fixes' tag:\n$bad\n"
# check Fixes: reference
fixtags=$(echo "$tags" | grep '^Fixes: ')
bad=$(for fixtag in $fixtags ; do
hash=$(echo "$fixtag" | sed 's,^Fixes: \([0-9a-f]*\).*,\1,')
if git branch --contains $hash 2>&- | grep -q '^\*' ; then
good="Fixes: $hash "$(git log --format='("%s")' -1 $hash 2>&-)
else
good="reference not in current branch"
fi
printf "$fixtag" | grep -v "^$good$"
done | sed 's,^,\t,')
[ -z "$bad" ] || printf "Wrong 'Fixes' reference:\n$bad\n"
# check Cc: stable@dpdk.org for fixes
bad=$(for fix in $stablefixes ; do
git log --format='%b' -1 $fix | grep -qi '^Cc: *stable@dpdk.org' ||
git log --format='\t%s' -1 $fix
done)
[ -z "$bad" ] || printf "Is it candidate for Cc: stable@dpdk.org backport?\n$bad\n"
|