Skip to content

Instantly share code, notes, and snippets.

@landys
Created November 30, 2015 13:38
Show Gist options
  • Save landys/05a4b8e893e000f0269b to your computer and use it in GitHub Desktop.
Save landys/05a4b8e893e000f0269b to your computer and use it in GitHub Desktop.
The git pre-receive hook for java checkstyle check based on http://bluec0re.blogspot.com/2012/05/git-pre-receive-hook-with-checkstyle.html. Set checkstyle jar and xml with "git config checkstyle.checkfile google_checks.xml" and "git config checkstyle.jar checkstyle-6.12.1-all.jar".
#!/usr/bin/env python
import subprocess
import sys
import tempfile
import shutil
import os
import errno
# variables for checkstyle
CONFIG_CHECK_FILE = 'checkstyle.checkfile'
CONFIG_JAR = 'checkstyle.jar'
# implementing check_output for python < 2.7
if not hasattr(subprocess, 'check_output'):
def check_output(*popenargs, **kwargs):
if 'stdout' in kwargs:
raise ValueError('stdout argument not allowed, it will be overridden.')
process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
output, unused_err = process.communicate()
retcode = process.poll()
if retcode:
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
er = subprocess.CalledProcessError(retcode, cmd)
er.output = output
raise er
return output
subprocess.check_output = check_output
# helper for calling executables
def call(*args, **kwargs):
return subprocess.check_output(*args, **kwargs).strip()
# helper for calling git
def call_git(cmd, *args, **kwargs):
return call(['git'] + cmd, *args, **kwargs)
# get all new commits from stdin
def get_commits():
commits = {}
for line in sys.stdin:
old, new, ref = line.strip().split(' ')
if old == '0000000000000000000000000000000000000000':
old = '4b825dc642cb6eb9a060e54bf8d69288fbee4904'
if ref not in commits:
commits[ref] = []
commits[ref].append({
'old': old,
'new': new,
'files': get_changed_files(old, new)
})
return commits
# get a list of changed files between to commits
def get_changed_files(old, new):
return call_git(['diff', '--name-only', old, new]).split('\n')
# get filemode, object type (blob,tree,commit), hash for the given file at the
# given commit
def get_change_type(commit, filename):
return call_git(['ls-tree', commit, filename]).split('\t')[0].split(' ')
# get the checkstyle jar and xml from git config.
checkstyle = call_git(['config', '--get', CONFIG_JAR])
checkstyle_config = call_git(['config', '--get', CONFIG_CHECK_FILE])
commits = get_commits()
# use the latest file commit only
print "Cleaning up file list..."
files = {}
count = 0
for ref, data in commits.iteritems():
files[ref] = {}
for commit in data:
for filename in commit['files']:
if not filename.lower().endswith('.java'):
continue
files[ref][filename] = get_change_type(commit['new'], filename)
count += len(files[ref])
print "%d Files to check in %d branches" % (count, len(files))
# create temporary dir and save a copy of the new files
tempdir = tempfile.mkdtemp('git_hook')
for ref, files in files.iteritems():
for filename, data in files.iteritems():
dname = os.path.dirname(filename)
bname = os.path.basename(filename)
try:
os.makedirs(os.path.join(tempdir, dname))
except OSError, exc:
if exc.errno == errno.EEXIST: # directory exists already
pass
else:
raise
with open(os.path.join(tempdir, dname, bname), 'w') as fp:
fp.write(call_git(['cat-file', data[1], data[2]]))
try:
# call checkstyle and print output
output = call(['java', '-jar', checkstyle, '-c', checkstyle_config, tempdir])
print(output)
if output.find('warning') >= 0 or output.find('error') >= 0:
exit(2)
except subprocess.CalledProcessError, ex:
print ex.output # print checkstyle messages
exit(1)
finally:
# remove temporary directory
shutil.rmtree(tempdir)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment