Skip to content

Instantly share code, notes, and snippets.

@buurzx
Forked from skanev/rubocop.rb
Last active September 29, 2017 08:37
Show Gist options
  • Save buurzx/355794abeb2b50c96380dcf7e687ad00 to your computer and use it in GitHub Desktop.
Save buurzx/355794abeb2b50c96380dcf7e687ad00 to your computer and use it in GitHub Desktop.
A Rubocop wrapper that checks only added/modified code
The intention of this guide is to add a git hook in order to run rubocop on any ruby application you want to force yourself to follow the rules.
First you need to run the following commands, under the rails project directory:
```
$ touch .git/hooks/pre-commit
$ chmod +x .git/hooks/pre-commit
```
Next add the following code into your `.git/hooks/pre-commit` file:
```bash
#!/bin/sh
pass=true
RED='\033[1;31m'
GREEN='\033[0;32m'
NC='\033[0m'
echo "Running Rubocop. Please wait."
# Run rubocop and get the output and return code
# +++++++++CHANGE THIS+++++++++
rubocop=$(docker-compose run --rm web bin/rubocop --index)
# +++++++++CHANGE THIS+++++++++
return_code=$?
if [ $return_code != 0 ]; then
echo "$rubocop\n"
printf "\n${RED}Rubocop failed, not commit was made"
pass=false
else
printf "${GREEN}Rubocop passed.${NC}\n"
fi
# If you reach this point, everything was cool and means you are a good player
if $pass; then
exit 0
fi
exit 1
```
And that is it, next time you try to commit something will execute and if either of those break, you will not be able to commit.
To skip this hook use `-n` flag with `git commit` command
#!/usr/bin/env ruby
# A sneaky wrapper around Rubocop that allows you to run it only against
# the recent changes, as opposed to the whole project. It lets you
# enforce the style guide for new/modified code only, as opposed to
# having to restyle everything or adding cops incrementally. It relies
# on git to figure out which files to check.
#
# Here are some options you can pass in addition to the ones in rubocop:
#
# --local Check only the changes you are about to push
# to the remote repository.
#
# --uncommitted Check only changes in files that have not been
# --index committed (i.e. either in working directory or
# staged).
#
# --against REFSPEC Check changes since REFSPEC. This can be
# anything that git will recognize.
#
# --branch Check only changes in the current branch.
#
# --courage Without this option, only the modified lines
# are inspected. When supplied, it will check
# the full contents of the file. You should have
# the courage to fix your style violations as
# you see them, you know.
#
# Caveat emptor:
#
# * Monkey patching ahead. This script relies on Rubocop internals and
# has been tested against 0.25.0. Newer (or older) versions might
# break it.
#
# * While it does try to check modified lines only, there might be some
# quirks. It might not show offenses in modified code if they are
# reported at unmodified lines. It might also show offenses in
# unmodified code if they are reported in modified lines.
require 'rubocop'
module DirtyCop
extend self # In your face, style guide!
def bury_evidence?(file, line)
!report_offense_at?(file, line)
end
def uncovered_targets
@files
end
def cover_up_unmodified(ref, only_changed_lines = true)
@files = files_modified_since(ref)
@line_filter = build_line_filter(@files, ref) if only_changed_lines
end
def process_bribe
eat_a_donut if ARGV.empty?
ref = nil
only_changed_lines = true
loop do
arg = ARGV.shift
case arg
when '--local'
ref = `git rev-parse --abbrev-ref --symbolic-full-name @{u}`.chomp
exit 1 unless $?.success?
when '--against'
ref = ARGV.shift
when '--uncommitted', '--index'
ref = 'HEAD'
when '--branch'
ref = `git merge-base HEAD master`.chomp
when '--courage'
only_changed_lines = false
else
ARGV.unshift arg
break
end
end
return unless ref
cover_up_unmodified ref, only_changed_lines
end
private
def report_offense_at?(file, line)
!@line_filter || @line_filter.fetch(file)[line]
end
def files_modified_since(ref)
`git diff --diff-filter=AM --name-only #{ref}`.
lines.
map(&:chomp).
grep(/\.rb$/).
map { |file| File.absolute_path(file) }
end
def build_line_filter(files, ref)
result = {}
suspects = files_modified_since(ref)
suspects.each do |file|
result[file] = lines_modified_since(file, ref)
end
result
end
def lines_modified_since(file, ref)
ranges =
`git diff -p -U0 #{ref} #{file}`.
lines.
grep(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/) { $1.to_i...($1.to_i + $2.to_i) }.
reverse
mask = Array.new(ranges.first.end)
ranges.each do |range|
range.each do |line|
mask[line] = true
end
end
mask
end
def eat_a_donut
puts "#$PROGRAM_NAME: The dirty cop Alex Murphy could have been"
puts
puts File.read(__FILE__)[/(?:^#(?:[^!].*)?\n)+/s].gsub(/^#/, ' ')
exit
end
end
module RuboCop
class TargetFinder
alias find_unpatched find
def find(args)
replacement = DirtyCop.uncovered_targets
return replacement if replacement
find_unpatched(args)
end
end
class Runner
alias inspect_file_unpatched inspect_file
def inspect_file(file)
offenses, updated = inspect_file_unpatched(file)
offenses = offenses.reject { |o| DirtyCop.bury_evidence?(file.path, o.line) }
[offenses, updated]
end
end
end
DirtyCop.process_bribe
exit RuboCop::CLI.new.run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment