Last active
August 29, 2015 14:01
-
-
Save ianchesal/14c0c51c5710ec40e2ca to your computer and use it in GitHub Desktop.
breathalyzer -- Run Rubocop on Changed Files in a Git-Managed Directory
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 | |
## | |
# Runs rubocop on just the modified and new files in a repoistory. Handy for | |
# checking your compliance before you commit. It only runs against files that | |
# end in .rb. Maybe it should do more than that? | |
# | |
# Easy to run. In a dirty working directory: | |
# | |
# breathalyzer | |
# | |
# It runs rubocop on each dirty file separately. | |
require 'logger' | |
require 'optparse' | |
require 'shellwords' | |
def git_status(args = nil) | |
## | |
# Returns the git status output as an array of strings. | |
# Optional args appended to the git status call. | |
# Raises an error if git doesn't return a 0 error code. | |
git_command = Shellwords.join(%w(git status) + args.split) | |
git_output = `#{git_command}` | |
fail "git error: #{git_command}" unless $CHILD_STATUS.to_i | |
git_output.split("\n") | |
end | |
def get_ruby_files(options = {}) | |
## | |
# Returns a list of ruby files that need to be rubocop'ed | |
rubyfiles = [] | |
git_status('--short').each do |line| | |
(status, file) = line.split(' ', 2) | |
case status | |
when 'M', 'A', 'R', 'C', 'U' | |
rubyfiles.push(file) if ruby_file?(file) | |
when '??' | |
unless options[:exclude_unmanaged] | |
rubyfiles.push(file) if ruby_file?(file) | |
end | |
else | |
# Unrecognized status, do nothing | |
end | |
end | |
rubyfiles | |
end | |
def ruby_file?(name) | |
## | |
# Returns true if this is a file that rubocop can check. | |
# Otherwise false. | |
File.extname(name).casecmp('.rb') == 0 | |
end | |
def breathalyzer(options = {}) | |
## | |
# Run rubocop on some files | |
files = get_ruby_files(options) | |
if files.length == 0 | |
puts 'No changes detected, no reason to run rubocop' | |
else | |
if options[:batch] | |
system(Shellwords.join(['rubocop'] + files)) | |
else | |
files.each do |file| | |
puts "------ #{file} ------" | |
system(Shellwords.join(['rubocop', file])) | |
break if options[:stop] && $CHILD_STATUS != 0 | |
end | |
end | |
end | |
end | |
options = { batch: true, stop: false, exclude_unmanaged: false } | |
opt_parser = OptionParser.new do |opt| | |
script_name = File.basename($PROGRAM_NAME) | |
opt.banner = 'Run Rubocop on Changed Files in a Git-Managed Directory' | |
opt.separator '' | |
opt.define_head( | |
'', | |
"Usage: #{script_name} [OPTIONS]", | |
'', | |
'Examples:', | |
'', | |
' * Check everything that\'s changed in batch mode', | |
" #{script_name}", | |
'', | |
' * Check one file at a time, stop on first violating file', | |
" #{script_name} -os") | |
opt.separator '' | |
opt.separator 'Options:' | |
opt.on( | |
'-x', | |
'--exclude-unmanaged', | |
'exclude unmanaged files from checks?') do | |
options[:exclude_unmanaged] = true | |
end | |
opt.on( | |
'-o', | |
'--one-at-a-time', | |
'run rubocop on file at a time?') do | |
options[:batch] = false | |
end | |
opt.on( | |
'-s', | |
'--stop-on-error', | |
'stop after the first rubocop error?') do | |
options[:stop] = true | |
end | |
opt.on( | |
'-h', | |
'--help', | |
'help') do | |
puts opt_parser | |
exit 0 | |
end | |
opt.separator '' | |
opt.separator 'See Also:' | |
opt.separator '' | |
opt.separator ' * Rubocop: https://github.com/bbatsov/rubocop' | |
opt.separator ' * My Rubocop Settings: https://gist.github.com/ianchesal/352a7963b97a92562a45' | |
end | |
opt_parser.parse! | |
breathalyzer(options) | |
exit 0 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment