Advertisement
Guest User

Untitled

a guest
Aug 21st, 2019
112
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.50 KB | None | 0 0
  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
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement