Created
July 16, 2012 20:34
-
-
Save knowshan/3124875 to your computer and use it in GitHub Desktop.
A Git pre-commit hook for Puppet to validate syntax and style
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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, [email protected] | |
# 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