Created
August 6, 2012 15:00
-
-
Save jumanjiman/3275053 to your computer and use it in GitHub Desktop.
cross-platform git pre-commit hook for puppet repos
This file contains 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
#!/usr/bin/env ruby | |
# An example cross-platform (Linux, Windows, Mac, etc.) | |
# pre-commit hook script to verify what is about to be committed. | |
# Called by "git commit" with no arguments. The hook should | |
# exit with non-zero status after issuing an appropriate message if | |
# it wants to stop the commit. | |
# To enable this hook: | |
# - save this file as <path-to-git-clone>/.git/hooks/pre-commit | |
# - mark file as executable | |
# Current checks: | |
# - ruby syntax | |
# - erb (template) syntax | |
# - puppet syntax | |
# - puppet style | |
# - unresolved merge conflicts | |
# - yaml (just check if well-formed) | |
# assume everything is good; override as things go bad | |
rc = 0 | |
dependencies = [ | |
'puppet', | |
'puppet-lint', | |
'open3', | |
] | |
dependencies.each do |d| | |
begin | |
require d | |
rescue | |
rc = 1 | |
puts "Missing dependency: #{d}" | |
end | |
end | |
# create a reusable puppet parser object for checking syntax | |
parser = Puppet::Parser::Parser.new('') | |
# create a reusable puppet-lint object for checking style | |
linter = PuppetLint.new | |
begin | |
linter.quiet = true # suppress normal output | |
rescue | |
rc = 1 | |
puts 'Oops. Need puppet-lint version from https://github.com/rodjek/puppet-lint/pull/124' | |
end | |
if rc != 0 | |
puts 'Bailing before I hurt myself' | |
exit(rc) | |
end | |
if `git rev-parse --quiet --verify HEAD`.empty? | |
# Initial commit: diff against an empty tree object | |
treeish = '4b825dc642cb6eb9a060e54bf8d69288fbee4904' | |
else | |
treeish = 'HEAD' | |
end | |
# get list of staged files | |
filenames = `git diff-index --diff-filter=AM --name-only --cached #{treeish}`.split(/\n/) | |
filenames.each do |f| | |
# get file content from index, not from workdir | |
# (but skip to next filename if this commit removes the file) | |
(content = `git cat-file -p :0:#{f}`).empty? && next | |
# look for unresolved merge conflicts | |
# content.split(/\n/).each do |line| | |
# if /^<<<<<<<|^>>>>>>>|^=======$/.match(line) | |
# rc = 1 | |
# puts "ERROR: #{f} appears to have unresolved merge conflicts" | |
# end | |
# end | |
# check for well-formed yaml | |
if /\.yaml$/.match(f) | |
begin | |
YAML.load(content) | |
rescue ArgumentError, Psych::SyntaxError | |
rc = 1 | |
puts "ERROR: #{f} is not well-formed YAML" | |
end | |
end | |
# Ruby (.rb) and template (.erb) files | |
if /\.e{0,1}rb$/.match(f) | |
if /\.erb$/.match(f) | |
# convert content from erb to ruby | |
content = ERB.new(content, nil, '-').src | |
end | |
begin | |
# check ruby syntax | |
Open3.popen3('ruby -Ku -c') do |stdin, stdout, stderr| | |
stdin.puts(content) | |
stdin.close | |
output = (stdout.readline rescue '') | |
unless /^Syntax OK$/.match(output) | |
rc = 1 | |
error = (stderr.readline rescue '') | |
puts "ERROR: #{f} #{error}" | |
end | |
end | |
rescue => except | |
rc = 1 | |
puts "ERROR: #{except.message}" | |
end | |
end | |
# puppet (.pp) files | |
if /\.pp$/.match(f) | |
begin | |
# check puppet syntax | |
parser.parse(content) | |
# check puppet style, but only if parser didn't raise exception | |
linter.run_virtual(f, content) | |
if linter.errors? | |
rc = 1 | |
puts "#{f}: #{linter.statistics[:error]} puppet-lint errors (fatal)" | |
end | |
rescue => except | |
# if we're here, puppet parser found bad syntax | |
rc = 1 | |
puts "ERROR: #{f} #{except.message}" | |
end | |
end | |
end | |
# if we exit non-zero, git will abort the commit | |
exit(rc) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment