Last active
May 30, 2017 18:24
-
-
Save spalenza/259fbdaddf27c303fd2f to your computer and use it in GitHub Desktop.
Git hook for commit. Add in .git/hooks/pre-commit
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 | |
# .git/hooks/pre-commit | |
# Git pre-commit hook that catches errors that I commonly make. | |
# | |
# To intentionally ignore the hook (i.e., when adding an alert call), commit | |
# from the command line with "--no-verify" | |
# | |
# Loosely based on Henrik Nyh's <http://henrik.nyh.se> work (2011-10-08) | |
# under the MIT License. | |
# | |
# Bob Gilmore ([email protected]) | |
############# CONFIGURATION | |
# The two sections of regular expressions below ("forbidden" and "warning") | |
# will trigger a commit failure, *if* they are found on an added or edited line. | |
# "Forbidden" regular expressions | |
FORBIDDEN = [ | |
/TMP_DEBUG/, # My TextExpander macros for embedding debug code always include this for easy scanning. | |
/>>>>>>/, # Git conflict markers | |
/<<<<<</, # '' | |
/======/, # '' | |
/console\.debug/, # JavaScript debug code that would break IE. | |
/console\.log/, # '' | |
/binding\.pry/, # pry debugging code | |
/binding\.remote_pry/, # '' | |
/save_and_open_page/, # Launchy debugging code | |
/debugger/, # Ruby debugging code | |
/focus: true/ # Focus to rspec | |
] | |
USER = ENV["USER"] | |
USER_HOME = [ | |
Regexp.new("/home/#{USER}"), # Hard-coded path to user's HOME | |
Regexp.new("/Users/#{USER}"), # '' | |
Regexp.new("/export/home/#{USER}") # '' (for a current work config) | |
] | |
# Warning signs that someone is committing a private key | |
PRIVATE_KEY = [ | |
/PRIVATE KEY/, | |
/ssh-rsa/ | |
] | |
# Things that I probably don't want to commit. | |
# Will force a rejection, but will "label" them in the error message | |
# as "merely" warnings. | |
WARNING = [ | |
/alert/, # I *almost* never want to check in a call to commit. | |
/logger\.debug/ # Similarly, I almost never want to commit a (Ruby) call to logger.debug. error, message, etc., but not debug. | |
] | |
# For particular projects - configurable on a per-project git config basis | |
# Check to ensure that if you add JavaScript or CSS, you change production.rb. This is required at my current employer. | |
NEW_ASSETS_REQUIRE_PRODUCTION_CHANGE = ( `git config hooks.newassetsrequireproductionchange`.strip || 'false') == 'true' | |
# Prevent inadvertent .ruby-version and .rbenv-version commits. I rarely edit these files, so any attempt to commit is probably an accident. | |
ALLOW_RUBY_VERSION_CHANGES = ( `git config hooks.allowrubyversionchange`.strip || 'false') == 'true' | |
############# END OF CONFIGURATION | |
# Check for "forbidden" and "warning" strings | |
# Loop over ALL errors and warnings and return ALL problems. | |
# I want to report on *all* problems that exist in the commit before aborting, | |
# so that anyone calling --no-verify has been informed of all problems first. | |
error_found = false | |
full_diff = `git diff --cached --` | |
full_diff.scan(%r{^\+\+\+ b/(.+)\n@@.*\n([\s\S]*?)(?:^diff|\z)}).each do |file, diff| | |
added = diff.split("\n").select { |x| x.start_with?("+") }.join("\n") | |
# Scan for "forbidden" calls | |
FORBIDDEN.each do |re| | |
if added.match(re) | |
puts %{Error: git pre-commit hook forbids committing lines with "#{$1 || $&}" to #{file}\n--------------} | |
error_found = true | |
end | |
end | |
# Scan for probable HARD_CODED references to user's home directory | |
USER_HOME.each do |re| | |
if added.match(re) | |
puts %{Error: git pre-commit hook forbids committing lines that look like a hard-coded home directory: "#{$1 || $&}" to #{file}\n--------------} | |
error_found = true | |
end | |
end | |
# Scan for private key indicators | |
PRIVATE_KEY.each do |re| | |
if added.match(re) | |
puts %{Error: git pre-commit hook detected a probable private key commit: "#{$1 || $&}" to #{file}\n--------------} | |
error_found = true | |
end | |
end | |
# Scan for "suspect" calls | |
WARNING.each do |re| | |
if added.match(re) | |
puts %{Warning: git pre-commit hook is suspicious of committing lines with "#{$1 || $&}" to #{file}\n--------------} | |
error_found = true | |
end | |
end | |
end | |
=begin | |
# Syntax check .rb files. | |
toplevel = `git rev-parse --show-toplevel` | |
name_only = `git diff --cached --name-only` | |
name_only.split(/\n/).each do |fil| | |
if File.extname(fil) == '.rb' | |
fullfile = File.join(toplevel.strip, fil) | |
if File.exist?(fullfile) | |
output = `ruby -c #{fullfile}` | |
status = $?.success? | |
unless status | |
puts %{Error: git pre-commit hook found a syntax error in #{file}} | |
error_found = true | |
end | |
end | |
end | |
end | |
=end | |
name_only = `git diff --cached --name-only` | |
# Ensure that production.rb is changed when assets are added | |
if NEW_ASSETS_REQUIRE_PRODUCTION_CHANGE | |
name_only_added = `git diff --cached --name-only --diff-filter=A` | |
has_production = name_only.include?('production.rb') | |
name_only_added.split(/\n/).each do |fil| | |
ext = File.extname(fil) | |
if (ext == '.css' || ext == '.scss' || ext == '.js' || ext == '.coffee' || ext == '.less') && !has_production | |
puts %{Error: git pre-commit hook found attempt to add #{fil} without editing production.rb\nThis is probably an error.\nTo allow this for this project, run\ngit config hooks.newassetsrequireproductionchange true\nand try again.\n-------------- } | |
error_found = true | |
end | |
end | |
end | |
# Prevent changes to .ruby-version (and .rbenv-version) | |
unless ALLOW_RUBY_VERSION_CHANGES | |
name_only.split(/\n/).each do |fil| | |
base = File.basename(fil) | |
if base == '.ruby-version' || base == '.rbenv-version' | |
puts %{Warning: git pre-commit hook found attempt to edit #{fil}.\nThis is probably an error.\nTo allow this for this project, run\ngit config hooks.allowrubyversionchange true\nand try again.\n-------------- } | |
error_found = true | |
end | |
end | |
end | |
# Finally, report errors | |
if error_found | |
puts "To commit anyway, use --no-verify" | |
exit 1 | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment