Skip to content

Instantly share code, notes, and snippets.

@amacdougall
Last active August 31, 2015 15:27
Show Gist options
  • Save amacdougall/1602cd2671a9050ddfa6 to your computer and use it in GitHub Desktop.
Save amacdougall/1602cd2671a9050ddfa6 to your computer and use it in GitHub Desktop.
Viewport pre-commit hook
#!/usr/bin/ruby
#
# Prevents commit, with an informative message, if any of the following
# conditions are true:
#
# Any js file in the src directory does not pass eslint.
#
# Any js file in the src directory requires formatting with js-beautify.
#
# Must have eslint and js-beautify installed as CLI apps. If they are not
# installed, error messages will offer a helping hand.
#
# Must be saved as .git/hooks/pre-commit, and must be executable.
# Use chmod a+x .git/hooks/pre-commmit if necessary.
# hack to permit user input during commit hook
# http://stackoverflow.com/questions/3417896/how-do-i-prompt-the-user-from-within-a-commit-msg-hook
STDIN.reopen('/dev/tty')
if `which npm`.empty?
puts "npm is not installed as a CLI app; pre-commit hook cannot run. See http://npmjs.com/."
print "Ask for help! Your dev setup is incomplete."
end
if `which eslint`.empty?
puts "eslint is not installed as a CLI app; pre-commit hook cannot run. See http://eslint.org/."
print "Install it now? y/n > "
if STDIN.gets =~ /[Yy]/
puts "Installing eslint..."
`npm install -g eslint`
puts "Complete! Proceeding..."
else
puts "Run again after installing eslint; or rename/delete .git/hooks/pre-commit to disable this script."
exit 1 # exit with error, preventing commit
end
end
if `npm list -g babel-eslint` =~ /empty/
puts "The babel-eslint module is not installed; pre-commit hook cannot run. See https://github.com/babel/babel-eslint."
print "Install it now? y/n > "
if STDIN.gets =~ /[Yy]/
puts "Installing babel-eslint..."
`npm install -g babel-eslint`
puts "Complete! Proceeding..."
else
puts "Run again after installing babel-eslint; or rename/delete .git/hooks/pre-commit to disable this script."
exit 1 # exit with error, preventing commit
end
end
if `which js-beautify`.empty?
puts "js-beautify is not installed as a CLI app; pre-commit hook cannot run. See https://github.com/beautify-web/js-beautify."
print "Install it now? y/n > "
if STDIN.gets =~ /[Yy]/
puts "Installing js-beautify..."
`npm install -g js-beautify`
puts "Installed! Proceeding..."
else
puts "Run again after installing js-beautify; or rename/delete .git/hooks/pre-commit to disable this script."
exit 1 # exit with error, preventing commit
end
end
jsbeautify_config = "../paperless-post/app/javascripts/design/.jsbeautifyrc"
eslint_config = "../paperless-post/app/javascripts/design/.eslintrc"
unless File.exists?(jsbeautify_config)
puts "File #{jsbeautify_config} not found; update your Rails repo."
end
unless File.exists?(eslint_config)
puts "File #{eslint_config} not found; update your Rails repo."
end
modified_files = `git diff --name-only --cached --diff-filter=AM`.split # only staged files, ignore deleted
if modified_files.empty?
exit 0 # nothing to commit; this hook passes, but git will issue an error message
end
files_to_beautify = [] # array of filenames
eslint_errors = [] # array of eslint error outputs
results = modified_files.each do |fname|
# js-beautify sends the beautified version to stdout;
# sed adds a trailing newline if there is not one already;
# diff compares the beautified and newlinified version to the original.
#
# Why add the newline? Curiously, js-beautify produces slightly different
# output from the grunt plugin, even if they run precisely the same
# executable; this is a workaround.
beautify_result = `js-beautify -f #{fname} --config="#{jsbeautify_config}" | sed -e '$a\\' | diff #{fname} -`
files_to_beautify << fname unless beautify_result.length == 0
eslint_result = `eslint --config="#{eslint_config}" #{fname}`
eslint_errors << eslint_result if eslint_result =~ /\d+:\d+\s+error/ # must be in "col:row error" format
end
unless files_to_beautify.empty?
puts "The following #{files_to_beautify.count} files must be formatted with js-beautify:"
files_to_beautify.each {|f| puts f}
end
unless eslint_errors.empty?
puts "The following #{eslint_errors.count} files have lint errors:"
eslint_errors.each {|error| puts error}
end
if eslint_errors.empty? && files_to_beautify.empty?
exit 0 # exit without error, allowing commit
else
exit 1 # exit with error, preventing commit
end
@amacdougall
Copy link
Author

Updated to allow eslint warnings; only blocks on errors.

@amacdougall
Copy link
Author

Updated to check only staged files, ignoring unstaged ones.

@amacdougall
Copy link
Author

Updated to ignored deleted files.

@amacdougall
Copy link
Author

Updated to read .eslintrc from ../paperless-post/app/javascripts/design/.eslintrc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment