Skip to content

A git checkstyle pre-receive hook

When multiple developers work on one project it is also essential that they all commit source code that matches some formatting rules. Otherwise reviewing changes and merging source code can be a great challenge.

When using git repositories you can install hooks. Hooks are any kind of executables that can be run before something happens in a git repository like creating a commit or updating the refs during a push command.

I developed a small bash script that can be used to execute checkstyle on every push and that rejects changes that have checkstyle errors. The script is simple and easy to configure so I want to share it here.

Just install the following script in the remote repository as a file named pre-receive in the hooks folder. Make sure that the script is executable, e.g. chmod +x pre-receive.

#!/bin/sh
 
checkstyle_cmd=`git config --get checkstyle.cmd`
 
if [ -z "$checkstyle_cmd" ]; then
   echo "Checkstyle command not defined."
   echo "Configure server repository using \"git config --add checkstyle.cmd java -cp ... com.puppycrawl.tools.checkstyle.Main -c ../checkstyle.xml\""
   exit 1
fi

REJECT=0
 
while read oldrev newrev refname; do

    if [ "$oldrev" == "0000000000000000000000000000000000000000" ];then
        oldrev="${newrev}^"
    fi
    
    files=`git diff --name-only ${oldrev} ${newrev}  | grep -e "\.java$"`
    
    if [ -n "$files" ]; then
        TEMPDIR=`mktemp -d`
        for file in ${files}; do
            mkdir -p "${TEMPDIR}/`dirname ${file}`" &>/dev/null
            git show $newrev:$file > ${TEMPDIR}/${file} 
        done;
    
        files_to_check=`find $TEMPDIR -name '*.java'`
                        
        CHECKS=`${checkstyle_cmd} ${files_to_check} | sed 's/\\\\/\//g' | sed '1d;$d' | sed -e "s#${TEMPDIR}/##g" | sed 's/\(:[0-9]\+\)\+:\?.*//' | sort | uniq -c;exit ${PIPESTATUS[0]}`
        CHECKS_EXIT=$?
        
        if [ ${CHECKS_EXIT} -ne 0 ] ; then
            echo -e "\e[1;31mExecution of checkstyle cmd failed:\e[0m"
            echo -e "\e[1;33m${checkstyle_cmd} [files]\e[0m"
            exit ${CHECKS_EXIT}
        fi
                
        if [ -n "$CHECKS" ]; then 
            echo -e "\e[1;31mCHECKSTYLE ISSUES DETECTED -- REJECTED [$refname]\e[0m"
            echo -e "$CHECKS" | while read num check; do
                 printf '  \e[1;33m%4s\e[0m' $num
                 echo -e "\e[1;33m $check\e[0m"
            done
            REJECT=1
        fi
        rm -rf $TEMPDIR
    fi    
done
 
exit $REJECT

Now you just have to configure the checkstyle.cmd git configuration property. This property must contains the full executable checkstyle command. E.g.

git config --add checkstyle.cmd "java -cp <CLASSPATH> com.puppycrawl.tools.checkstyle.Main -c <CHECKSTYLE_CONFIG_PATH>/checkstyle.xml"

This is all you need to get it running. Now if someone tries to push changes to the remote repository that do not conform to the checkstyle checks you  configured, the remote repository will reject the push. E.g.

checkstyle_rejected_push

The script will reject the push and print out the path of the file that violates the checkstyle checks and the violation count in front of the file path.

 

1 thought on “A git checkstyle pre-receive hook”

  1. 1. what oldrev newrev refname indicates in the above script ?
    2. what is the significance of this line
    if [ “$oldrev” == “0000000000000000000000000000000000000000” ];then

Leave a Reply

Your email address will not be published. Required fields are marked *

 

GDPR Cookie Consent with Real Cookie Banner