Skip to content

Instantly share code, notes, and snippets.

@knowshan
Created July 16, 2012 20:34
Show Gist options
  • Save knowshan/3124875 to your computer and use it in GitHub Desktop.
Save knowshan/3124875 to your computer and use it in GitHub Desktop.
A Git pre-commit hook for Puppet to validate syntax and style
#!/bin/bash
# Description: A Git pre-commit hook for Puppet manifests
# Validates Puppet manifest syntax amd style
# * Syntax validation: Using puppet parser as documented on Puppet wiki
# - http://projects.puppetlabs.com/projects/1/wiki/Puppet_Version_Control
# * Style validation: Using puppet lint
# Requirements:
# * Ruby 1.8.7
# * Puppet 2.7
# * puppte-lint
# * rspec-puppet (seems like puppet 2.7 requires it, the hook doesn't use it)
# I have installed Puppet gems in my dev envrionment using rvm, but you can use
# this hook with system installed Puppet and system wide gem installations as
# well. You will need to modify script according to your Puppet/gem
# environment.
# Author: Shantanu Pavgi, pavgi@uab.edu
# Load RVM and puppet gemsets
. $HOME/bashrc/rvm
rvm use 1.8.7
rvm gemset use puppet
# Stash modifications done after file(s) were added to the index
# Check contents that are currently indexed
git stash -q --keep-index
syntax_errors=0
style_errors=0
error_msg=$(mktemp /tmp/error_msg.XXXXXX)
# prepare diff context
if git rev-parse --quiet --verify HEAD > /dev/null
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# remove empty files from given file array and return modified array
function remove_empty_files(){
# passing/reading array parameter like this will be buggy - IF - multiple
# arrays are being passed. However, it's okay for this script as params
# are being passed within the script and we are aware of the issue!
indexfiles="${@}"
indexfiles_cur=()
for indexfile in $indexfiles; do
if [ `git cat-file -s :0:$indexfile` == "0" ]; then
indexfiles_cur+=${indexfiles/${indexfile}/}
fi
done
echo "${indexfiles_cur[@]}"
}
# Check puppet syntax
# Accept file array and validate each file's syntax based on it's file type
function check_syntax(){
indexfiles="${@}"
for indexfile in $indexfiles; do
case $indexfile in
*.pp )
# Check puppet manifest syntax
# git cat-file blob :0:$indexfile | puppet --color=false --parseonly --ignoreimport > $error_msg ;;
# Updated for 2.7.x
puppet parser validate $indexfile > $error_msg ;;
*.erb )
# Check ERB template syntax
# -P : ignore lines which start with "%"
git cat-file blob :0:$indexfile | erb -P -x -T - | ruby -c 2> $error_msg > /dev/null ;;
*)
echo "Unsupported file name extension. Style validation is performed only for *.pp files";;
esac
# if exit code is non-zero then display error message
if [ "$?" -ne 0 ]; then
echo -n "$indexfile: "
cat $error_msg
syntax_errors=`expr $syntax_errors + 1`
fi
done
# remove error_msg from last iteration
rm -f $error_msg
# Return non-zero exit code if syntax errors are present
if [ "$syntax_errors" -ne 0 ]; then
echo "Error: $syntax_errors syntax errors found, aborting commit."
return 1
fi
return 0
}
# validate puppet style of staged manifest (*.pp) files using puppet lint
function check_style(){
indexfiles="${@}"
for indexfile in $indexfiles; do
case $indexfile in
*.pp )
puppet-lint $indexfile > $error_msg ;;
*)
echo "Unsupported file name extension. Style validation is performed only for *.pp files" ;;
esac
# Return non-zero exit code if style errors are present
if [ "$?" -ne 0 ]; then
echo -n "$indexfile: "
cat $error_msg
style_errors=`expr $style_errors + 1`
fi
done
# remove error_msg from last iteration
rm -f $error_msg
# Return non-zero exit code if style validations fail
if [ "$style_errors" -ne 0 ]; then
echo "Error: $style_errors style errors found, aborting commit."
return 1
fi
return 0
}
# Get list of new/modified manifest and template files to check (in git index)
pp_files=`git diff-index --diff-filter=AM --name-only --cached $against | egrep '\.pp'`
erb_files=`git diff-index --diff-filter=AM --name-only --cached $against | egrep '\.erb'`
# Remove empty files - empty files will be skipped from validation!
pp_files=( `remove_empty_files $pp_files` )
erb_files=( `remove_empty_files $erb_files` )
all_files=( ${pp_files[@]} ${erb_files[@]} )
# check style errors only if there are no syntax errors
check_syntax "${all_files[@]}" && check_style "${pp_files[@]}"
# exit with exit code 1 in case of errors
# unstash changes in both cases
if [ $? -eq 0 ]; then
git stash pop -q
else
exit 1
git stash pop -q
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment