Skip to content

Instantly share code, notes, and snippets.

@thomet
Last active September 4, 2018 09:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thomet/53e810e54f3937a487b552618de44067 to your computer and use it in GitHub Desktop.
Save thomet/53e810e54f3937a487b552618de44067 to your computer and use it in GitHub Desktop.
Rubocop pre commit
#!/usr/bin/env ruby
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
ref = '--staged HEAD'
only_changed_lines = true
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
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
def print_header(header)
puts "\e[33m#{header}\e[0m"
end
failed = false
# ESLint
print_header 'Strat eslint analysis...'
`PATH="$(npm bin)":"$PATH"`
if `which eslint` == 'eslint not found'
puts 'WARNING: You need to install ESLint to lint your files (SKIP ESLint)'
else
files_js = `git diff --staged --name-only --diff-filter=d`.lines.map(&:chomp).grep(/\.coffee|\.js$/)
files_js.each do |file|
result = `git show :#{file} | eslint --stdin --stdin-filename "#{file}"`
puts result
failed = result.lines.count > 1
end
puts '[SKIPPED] Nothing to check' if files_js.empty?
end
puts "\n"
print_header 'Start Rubocop analysis...'
if DirtyCop.process_bribe.any?
failed ||= RuboCop::CLI.new.run != 0
else
puts '[SKIPPED] No ruby files changed'
end
puts "\n"
merge_branch = ENV['MERGE_BRANCH'] || 'master'
staged_diff = "git diff --staged #{merge_branch} --name-only --relative --diff-filter=d"
only_rb_without_specs = %x( #{staged_diff} | grep '\\.rb' | grep -v '_spec' ).gsub(/\n/, ' ')
print_header 'Start yaml_check analysis...'
if `which yaml_check` == 'yaml_check not found'
puts 'WARNING: You need to install yaml_check (SKIP yaml_check)'
else
i18n_files = %x( #{staged_diff} | grep '\\/config\\/locales' | grep '\\.yml' ).gsub(/\n/, ' ')
result = %x( yaml_check #{i18n_files} )
if result == ''
puts '[SKIPPED] No yaml files to check'
else
puts result
end
failed ||= result.include?('[FAILED]')
end
puts "\n"
print_header 'Start yardoc analysis...'
if `which yard` == `yard not found`
puts 'WARNING: You need to install yard (SKIP yard)'
else
if only_rb_without_specs != ''
result = %x( cd `git rev-parse --show-toplevel` && yard stats --list-undoc )
puts result
failed ||= !result.include?('100.00% documented')
else
puts '[SKIPPED] No ruby files changed'
end
end
puts "\n"
print_header 'Start flay analysis...'
if `which flay` == 'flay not found'
puts 'WARNING: You need to install flay (SKIP flay)'
else
if only_rb_without_specs != ''
result = %x( flay -v --diff #{only_rb_without_specs} )
puts result
else
puts '[SKIPPED] No ruby files changed'
end
end
puts "\n"
print_header 'Start flog analysis...'
if `which flog` == 'flog not found'
puts 'WARNING: You need to install flog (SKIP flog)'
else
if only_rb_without_specs != ''
result = %x( flog -m #{only_rb_without_specs} )
puts result
else
puts '[SKIPPED] No ruby files changed.'
end
end
puts "\n"
exit 1 if failed
exit 0
#!/usr/bin/env ruby
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
ref = '--staged HEAD'
only_changed_lines = true
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
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
if DirtyCop.process_bribe.any?
exit RuboCop::CLI.new.run
end
# ESLint
`PATH="$(npm bin)":"$PATH"`
if `which eslint` == 'eslint not found'
puts 'WARNING: You need to install ESLint to lint your files (SKIP ESLint)'
else
failure = false
files_js = `git diff --staged --name-only --diff-filter=d`.lines.map(&:chomp).grep(/\.coffee|\.js$/)
files_js.each do |file|
result = `git show :#{file} | eslint --stdin --stdin-filename "#{file}"`
puts result if result != ''
failure = failure || result.lines.count > 1
end
exit failure ? 1 : 0
end
@thomet
Copy link
Author

thomet commented Sep 4, 2018

Update: Rubocop now checks only changed lines instead of files

@thomet
Copy link
Author

thomet commented Sep 4, 2018

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