SHARE
TWEET

Untitled

a guest Aug 21st, 2019 85 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/env ruby
  2.  
  3. # A sneaky wrapper around Rubocop that allows you to run it only against
  4. # the recent changes, as opposed to the whole project. It lets you
  5. # enforce the style guide for new/modified code only, as opposed to
  6. # having to restyle everything or adding cops incrementally. It relies
  7. # on git to figure out which files to check.
  8. #
  9. # Here are some options you can pass in addition to the ones in rubocop:
  10. #
  11. #   --local               Check only the changes you are about to push
  12. #                         to the remote repository.
  13. #
  14. #   --staged              Check only changes that are currently staged.
  15. #
  16. #   --uncommitted         Check only changes in files that have not been
  17. #   --index               committed (i.e. either in working directory or
  18. #                         staged).
  19. #
  20. #   --against REFSPEC     Check changes since REFSPEC. This can be
  21. #                         anything that git will recognize.
  22. #
  23. #   --branch              Check only changes in the current branch.
  24. #
  25. #   --courage             Without this option, only the modified lines
  26. #                         are inspected. When supplied, it will check
  27. #                         the full contents of the file. You should have
  28. #                         the courage to fix your style violations as
  29. #                         you see them, you know.
  30. #
  31. # Caveat emptor:
  32. #
  33. # * Monkey patching ahead. This script relies on Rubocop internals and
  34. #   has been tested against 0.25.0. Newer (or older) versions might
  35. #   break it.
  36. #
  37. # * While it does try to check modified lines only, there might be some
  38. #   quirks. It might not show offenses in modified code if they are
  39. #   reported at unmodified lines. It might also show offenses in
  40. #   unmodified code if they are reported in modified lines.
  41. require 'rubocop'
  42. require 'pry'
  43.  
  44. module DirtyCop
  45.   extend self # In your face, style guide!
  46.  
  47.   def bury_evidence?(file, line)
  48.     !report_offense_at?(file, line)
  49.   end
  50.  
  51.   def staged_changes_only?
  52.     !!@staged_changes_only
  53.   end
  54.  
  55.   def uncovered_targets
  56.     @files
  57.   end
  58.  
  59.   def cover_up_unmodified(ref, only_changed_lines = true)
  60.     @files = files_modified_since(ref)
  61.     @line_filter = build_line_filter(@files, ref) if only_changed_lines
  62.   end
  63.  
  64.   def process_bribe
  65.     eat_a_donut if ARGV.empty?
  66.  
  67.     ref = nil
  68.     only_changed_lines = true
  69.  
  70.     loop do
  71.       arg = ARGV.shift
  72.       case arg
  73.       when '--local'
  74.         ref = `git rev-parse --abbrev-ref --symbolic-full-name @{u}`.chomp
  75.         exit 1 unless $?.success?
  76.       when '--staged'
  77.         ref = '--cached'
  78.         @staged_changes_only = true
  79.         ARGV << "--cache=false"
  80.       when '--against'
  81.         ref = ARGV.shift
  82.       when '--uncommitted', '--index'
  83.         ref = 'HEAD'
  84.       when '--branch'
  85.         ref = `git merge-base HEAD master`.chomp
  86.       when '--courage'
  87.         only_changed_lines = false
  88.       else
  89.         ARGV.unshift arg
  90.         break
  91.       end
  92.     end
  93.  
  94.     return unless ref
  95.  
  96.     cover_up_unmodified ref, only_changed_lines
  97.   end
  98.  
  99.   private
  100.  
  101.   def report_offense_at?(file, line)
  102.     !@line_filter || @line_filter.fetch(file)[line]
  103.   end
  104.  
  105.   def files_modified_since(ref)
  106.     `git diff --diff-filter=AM --name-only #{ref}`.
  107.       lines.
  108.       map(&:chomp).
  109.       grep(/\.rb$/).
  110.       map { |file| File.absolute_path(file) }
  111.   end
  112.  
  113.   def build_line_filter(files, ref)
  114.     result = {}
  115.  
  116.     suspects = files_modified_since(ref)
  117.     suspects.each do |file|
  118.       result[file] = lines_modified_since(file, ref)
  119.     end
  120.  
  121.     result
  122.   end
  123.  
  124.   def lines_modified_since(file, ref)
  125.     ranges =
  126.       `git diff -p -U0 #{ref} #{file}`.
  127.         lines.
  128.         grep(/^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/) { $1.to_i...($1.to_i + ($2 || 1).to_i) }.
  129.         reverse
  130.  
  131.     mask = Array.new(ranges.first.end)
  132.  
  133.     ranges.each do |range|
  134.       range.each do |line|
  135.         mask[line] = true
  136.       end
  137.     end
  138.  
  139.     mask
  140.   end
  141.  
  142.   def eat_a_donut
  143.     puts "#$PROGRAM_NAME: The dirty cop Alex Murphy could have been"
  144.     puts
  145.     puts File.read(__FILE__)[/(?:^#(?:[^!].*)?\n)+/s].gsub(/^#/, '   ')
  146.     exit
  147.   end
  148. end
  149.  
  150. module RuboCop
  151.   class TargetFinder
  152.     alias find_unpatched find
  153.  
  154.     def find(args)
  155.       replacement = DirtyCop.uncovered_targets
  156.       return replacement if replacement
  157.  
  158.       find_unpatched(args)
  159.     end
  160.   end
  161.  
  162.   class Runner
  163.     alias inspect_file_unpatched inspect_file
  164.  
  165.     def inspect_file(file)
  166.       offenses, updated = inspect_file_unpatched(file)
  167.       offenses = offenses.reject { |o| DirtyCop.bury_evidence?(file.path, o.line) }
  168.       [offenses, updated]
  169.     end
  170.   end
  171. end
  172.  
  173. DirtyCop.process_bribe
  174.  
  175. exit RuboCop::CLI.new.run
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top