Skip to content

Instantly share code, notes, and snippets.

@hron84
Last active December 12, 2015 12:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save hron84/4774014 to your computer and use it in GitHub Desktop.
Save hron84/4774014 to your computer and use it in GitHub Desktop.

Git pre-commit hook for Ruby on Rails

This pre-commit hook is checks the files being committed to fits two rules:

  • No syntax error (both for Ruby and YAML files)
  • If this is an TestUnit, Cucumber, or RSpec test, it should pass

TODO

  • Add checks for XML files
  • Add checks for deep checks for .rb files
  • Make it configurable from project's code
#!/usr/bin/env ruby
require 'yaml'
require 'pp'
begin
require 'action_view'
require 'action_view/template'
require 'action_view/template/handlers'
require 'action_view/template/handlers/erb'
def geterb(src)
ActionView::Template::Handlers::Erubis.new(src)
end
rescue LoadError
require 'erb'
def geterb(src)
ERB.new(src, nil, '-')
end
end
def valid_syntax?(code, fname)
eval("BEGIN {return true}\n#{code}", nil, fname, 0)
rescue Exception => e
puts e # $!.message
puts e.backtrace
false
end
lines = %x{git diff-index --cached --name-only HEAD}.split(/[\r\n]+/)
ENV['RAILS_ENV'] = 'test'
lines.each do |file|
if File.exists?(file) and file =~ /\.(rb|rake|god)$/
print "[SYNTAX] #{file} - "
ret = system("ruby -c '#{file}'")
exit 1 unless ret
if file =~ /_test\.rb$/
print "[UNIT ] #{file} - "
unitcmd = "ruby -Ilib:test #{file}"
unitcmd = "bundle exec #{unitcmd}" if File.exists?('Gemfile')
ret = system(unitcmd)
exit 1 unless ret
end
if file =~ /_spec\.rb$/
print "[SPEC ] #{file} - "
rspeccmd = "rspec #{file}"
rspeccmd = "bundle exec #{rspeccmd}" if File.exists?('Gemfile')
ret = system(rspeccmd)
exit 1 unless ret
end
end
if File.exists?(file) and File.basename(file) =~ /^(Capfile|Gemfile|Guardfile|Rakefile|config.ru)$/
print "[SYNTAX] #{file} - "
ret = system("ruby -c '#{file}'")
exit 1 unless ret
end
if File.exists?(file) and file =~ /\.feature$/
print "[ (::) ] #{file} - "
ENV['CUCUMBER_FORMAT'] = 'progress'
cuccmd = "cucumber #{file}"
cuccmd = "bundle exec #{cuccmd}" if File.exists?('Gemfile')
ret = system(cuccmd)
exit 1 unless ret
end
if File.exists?(file) and file =~ /\.erb$/
print "[SYNTAX] #{file} - "
begin
# code = ERBTemplate.new(IO.read(file), nil, '-').src
code = geterb(IO.read(file))
valid_syntax?(code, file)
puts "Syntax OK"
rescue Exception => ex
puts ex.message
puts ex.backtrace
exit 1
end
end
if File.exists?(file) and file =~ /\.(yml|yaml)$/
print "[SYNTAX] #{file} - "
begin
# Load with erb to avoid problems with cucumber's yml
# erb = ERB.new(IO.read(file), nil, '-').result(binding)
# erb = ERB.new(IO.read(file), nil, '-')
erb = geterb(IO.read(file))
exit 1 unless valid_syntax?(code, file)
yaml = YAML.load erb.result(binding)
puts "Syntax OK"
rescue SyntaxError => ex
puts ex.message
exit 1
rescue ArgumentError => ex
puts ex.message
exit 1
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment