1#! /bin/sh 2 3# BSD LICENSE 4# 5# Copyright 2016 6WIND S.A. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 11# * Redistributions of source code must retain the above copyright 12# notice, this list of conditions and the following disclaimer. 13# * Redistributions in binary form must reproduce the above copyright 14# notice, this list of conditions and the following disclaimer in 15# the documentation and/or other materials provided with the 16# distribution. 17# * Neither the name of 6WIND S.A. nor the names of its 18# contributors may be used to endorse or promote products derived 19# from this software without specific prior written permission. 20# 21# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 33# Check commit logs (headlines and references) 34# 35# If any doubt about the formatting, please check in the most recent history: 36# git log --format='%>|(15)%cr %s' --reverse | grep -i <pattern> 37 38if [ "$1" = '-h' -o "$1" = '--help' ] ; then 39 cat <<- END_OF_HELP 40 usage: $(basename $0) [-h] [range] 41 42 Check commit log formatting. 43 The git range can be specified as a "git log" option, 44 e.g. -1 to check only the latest commit. 45 The default range starts from origin/master to HEAD. 46 END_OF_HELP 47 exit 48fi 49 50selfdir=$(dirname $(readlink -e $0)) 51range=${1:-origin/master..} 52# convert -N to HEAD~N.. in order to comply with git-log-fixes.sh getopts 53if printf -- $range | grep -q '^-[0-9]\+' ; then 54 range="HEAD$(printf -- $range | sed 's,^-,~,').." 55fi 56 57commits=$(git log --format='%h' --reverse $range) 58headlines=$(git log --format='%s' --reverse $range) 59bodylines=$(git log --format='%b' --reverse $range) 60fixes=$(git log --format='%h %s' --reverse $range | grep -i ': *fix' | cut -d' ' -f1) 61stablefixes=$($selfdir/git-log-fixes.sh $range | sed '/(N\/A)$/d' | cut -d' ' -f2) 62tags=$(git log --format='%b' --reverse $range | grep -i -e 'by *:' -e 'fix.*:') 63bytag='\(Reported\|Suggested\|Signed-off\|Acked\|Reviewed\|Tested\)-by:' 64 65# check headline format (spacing, no punctuation, no code) 66bad=$(echo "$headlines" | grep --color=always \ 67 -e ' ' \ 68 -e '^ ' \ 69 -e ' $' \ 70 -e '\.$' \ 71 -e '[,;!?&|]' \ 72 -e ':.*_' \ 73 -e '^[^:]\+$' \ 74 -e ':[^ ]' \ 75 -e ' :' \ 76 | sed 's,^,\t,') 77[ -z "$bad" ] || printf "Wrong headline format:\n$bad\n" 78 79# check headline prefix when touching only drivers, e.g. net/<driver name> 80bad=$(for commit in $commits ; do 81 headline=$(git log --format='%s' -1 $commit) 82 files=$(git diff-tree --no-commit-id --name-only -r $commit) 83 [ -z "$(echo "$files" | grep -v '^\(drivers\|doc\|config\)/')" ] || 84 continue 85 drv=$(echo "$files" | grep '^drivers/' | cut -d "/" -f 2,3 | sort -u) 86 drvgrp=$(echo "$drv" | cut -d "/" -f 1 | uniq) 87 if [ $(echo "$drvgrp" | wc -l) -gt 1 ] ; then 88 echo "$headline" | grep -v '^drivers:' 89 elif [ $(echo "$drv" | wc -l) -gt 1 ] ; then 90 echo "$headline" | grep -v "^$drvgrp" 91 else 92 echo "$headline" | grep -v "^$drv" 93 fi 94done | sed 's,^,\t,') 95[ -z "$bad" ] || printf "Wrong headline prefix:\n$bad\n" 96 97# check headline label for common typos 98bad=$(echo "$headlines" | grep --color=always \ 99 -e '^example[:/]' \ 100 -e '^apps/' \ 101 -e '^testpmd' \ 102 -e 'test-pmd' \ 103 -e '^bond:' \ 104 | sed 's,^,\t,') 105[ -z "$bad" ] || printf "Wrong headline label:\n$bad\n" 106 107# check headline lowercase for first words 108bad=$(echo "$headlines" | grep --color=always \ 109 -e '^.*[A-Z].*:' \ 110 -e ': *[A-Z]' \ 111 | sed 's,^,\t,') 112[ -z "$bad" ] || printf "Wrong headline uppercase:\n$bad\n" 113 114# check headline uppercase (Rx/Tx, VF, L2, MAC, Linux, ARM...) 115bad=$(echo "$headlines" | grep -E --color=always \ 116 -e '\<(rx|tx|RX|TX)\>' \ 117 -e '\<[pv]f\>' \ 118 -e '\<[hsf]w\>' \ 119 -e '\<l[234]\>' \ 120 -e ':.*\<api\>' \ 121 -e ':.*\<arm\>' \ 122 -e ':.*\<armv7\>' \ 123 -e ':.*\<armv8\>' \ 124 -e ':.*\<dma\>' \ 125 -e ':.*\<freebsd\>' \ 126 -e ':.*\<linux\>' \ 127 -e ':.*\<lro\>' \ 128 -e ':.*\<mac\>' \ 129 -e ':.*\<mtu\>' \ 130 -e ':.*\<nic\>' \ 131 -e ':.*\<numa\>' \ 132 -e ':.*\<pci\>' \ 133 -e ':.*\<pmd\>' \ 134 -e ':.*\<rss\>' \ 135 -e ':.*\<tile-gx\>' \ 136 -e ':.*\<tilegx\>' \ 137 -e ':.*\<vlan\>' \ 138 | sed 's,^,\t,') 139[ -z "$bad" ] || printf "Wrong headline lowercase:\n$bad\n" 140 141# special case check for VMDq to give good error message 142bad=$(echo "$headlines" | grep -E --color=always \ 143 -e '\<(vmdq|VMDQ)\>' \ 144 | sed 's,^,\t,') 145[ -z "$bad" ] || printf "Wrong headline capitalization, use 'VMDq':\n$bad\n" 146 147# check headline length (60 max) 148bad=$(echo "$headlines" | 149 awk 'length>60 {print}' | 150 sed 's,^,\t,') 151[ -z "$bad" ] || printf "Headline too long:\n$bad\n" 152 153# check body lines length (75 max) 154bad=$(echo "$bodylines" | grep -v '^Fixes:' | 155 awk 'length>75 {print}' | 156 sed 's,^,\t,') 157[ -z "$bad" ] || printf "Line too long:\n$bad\n" 158 159# check starting commit message with "It" 160bad=$(for commit in $commits ; do 161 firstbodyline=$(git log --format='%b' -1 $commit | head -n1) 162 echo "$firstbodyline" | grep --color=always -ie '^It ' 163done | sed 's,^,\t,') 164[ -z "$bad" ] || printf "Wrong beginning of commit message:\n$bad\n" 165 166# check tags spelling 167bad=$(echo "$tags" | 168 grep -v "^$bytag [^,]* <.*@.*>$" | 169 grep -v '^Fixes: [0-9a-f]\{7\}[0-9a-f]* (".*")$' | 170 sed 's,^.,\t&,') 171[ -z "$bad" ] || printf "Wrong tag:\n$bad\n" 172 173# check blank line after last Fixes: tag 174bad=$(echo "$bodylines" | 175 sed -n 'N;/\nFixes:/D;/\n$/D;/^Fixes:/P' | 176 sed 's,^.,\t&,') 177[ -z "$bad" ] || printf "Missing blank line after 'Fixes' tag:\n$bad\n" 178 179# check missing Fixes: tag 180bad=$(for fix in $fixes ; do 181 git log --format='%b' -1 $fix | grep -q '^Fixes: ' || 182 git log --format='\t%s' -1 $fix 183done) 184[ -z "$bad" ] || printf "Missing 'Fixes' tag:\n$bad\n" 185 186# check Fixes: reference 187IFS=' 188' 189fixtags=$(echo "$tags" | grep '^Fixes: ') 190bad=$(for fixtag in $fixtags ; do 191 hash=$(echo "$fixtag" | sed 's,^Fixes: \([0-9a-f]*\).*,\1,') 192 if git branch --contains $hash 2>&- | grep -q '^\*' ; then 193 good="Fixes: $hash "$(git log --format='("%s")' -1 $hash 2>&-) 194 else 195 good="reference not in current branch" 196 fi 197 printf "$fixtag" | grep -v "^$good$" 198done | sed 's,^,\t,') 199[ -z "$bad" ] || printf "Wrong 'Fixes' reference:\n$bad\n" 200 201# check CC:stable for fixes 202bad=$(for fix in $stablefixes ; do 203 git log --format='%b' -1 $fix | grep -qi '^CC: *stable@dpdk.org' || 204 git log --format='\t%s' -1 $fix 205done) 206[ -z "$bad" ] || printf "Should CC: stable@dpdk.org\n$bad\n" 207