rubosquad 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rubosquad.rb +113 -16
  3. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 77fae3245b3e08691c773b982fa3d52366df1ebf8149ad9aefee6b4cb9251433
4
- data.tar.gz: 7426d309575c100d0437a866e3c71df9975723827056c35df7bcb93a6458bc4a
3
+ metadata.gz: bdc45fe50d0678e9dd9f45bc7967aeea4ed6b3ee830593875d9ad8911f277592
4
+ data.tar.gz: 784949c827c7d611bf125f791cf3d5913f93a9b508efc1dcb0814c3d3350a607
5
5
  SHA512:
6
- metadata.gz: c55573f8492aea97c2d37f978c3f3500b9480acbc2582814b94e45ac40958c8792a242934519bbc6f0ea8c618c59b6969dabf810ebbcce9fb2494e7d960b2267
7
- data.tar.gz: 0d695d1e033226974589a79889755d963dfc3719a3bdc5d70c2410b5142f4be9e3d842111a0aa9a01a87a40094966a248e1db909b2f9de7e28b543755099377c
6
+ metadata.gz: 929f4fea15d4ab2e7396f4a1b7ba159734bad3ba7d9d889f72de7c668bf5b47981028fa24971b263afe5b2655a1a74d4c651fae5d4250cb7c0a06a02eedbe031
7
+ data.tar.gz: c62933394e08b6520233aec0180384ec8367ac9de7c84f42e7c195a05ca888e91fc23881ef75ac4b2f0997a311657e47a4e75aae52ee35a398f6aa0d2892e6e8
data/lib/rubosquad.rb CHANGED
@@ -6,6 +6,13 @@ require 'optparse'
6
6
 
7
7
  module Rubosquad
8
8
  class CLI
9
+ OFFENSE_COLORS = {
10
+ 'E' => "\e[31m",
11
+ 'F' => "\e[31m",
12
+ 'W' => "\e[33m"
13
+ }.freeze
14
+ RESET = "\e[0m"
15
+
9
16
  class << self
10
17
  def run
11
18
  options = parse_options
@@ -24,6 +31,8 @@ module Rubosquad
24
31
  exit 0
25
32
  end
26
33
 
34
+ options[:base_branch] = base_branch
35
+ options[:current_branch] = current_branch
27
36
  print_file_list(files, current_branch, base_branch)
28
37
  run_rubocop(options, files)
29
38
  end
@@ -48,6 +57,12 @@ module Rubosquad
48
57
  opts.on('-A', '--unsafe-auto-correct', 'Run with rubocop -A (unsafe auto-corrections) instead of -a') do
49
58
  options[:unsafe_auto_correct] = true
50
59
  end
60
+ opts.on('-v', '--verbose', 'Show full stderr including new-cops notices and extra detail') do
61
+ options[:verbose] = true
62
+ end
63
+ opts.on('--all', 'Report all offenses, including pre-existing ones not in this branch') do
64
+ options[:all] = true
65
+ end
51
66
  end.parse!
52
67
  options
53
68
  end
@@ -112,14 +127,59 @@ module Rubosquad
112
127
  cmd = build_rubocop_cmd(options, extensions, files)
113
128
  stdout, stderr, status = Open3.capture3(*cmd)
114
129
 
130
+ changed_lines = options[:all] ? nil : parse_changed_lines(options, files)
131
+
115
132
  puts "\nRubocop Output:"
116
133
  puts '==Error type: Legend: C = Convention, W = Warning, E = Error, F = Fatal=='
117
- puts format_output(stdout)
134
+ formatted = format_output(stdout, changed_lines: changed_lines)
135
+ puts formatted
136
+
137
+ print_rubocop_result(stdout, stderr, status, extensions, options)
138
+
139
+ exit 0 if !status.success? && changed_lines && count_new_offenses(formatted).zero?
118
140
 
119
- print_rubocop_result(stdout, stderr, status, extensions)
120
141
  exit status.exitstatus unless status.success?
121
142
  end
122
143
 
144
+ def parse_changed_lines(options, files)
145
+ base_branch = options[:base_branch]
146
+ current_branch = options[:current_branch]
147
+
148
+ files.each_with_object({}) do |file, changed|
149
+ diff_text = if current_branch == base_branch
150
+ fetch_base_branch_diff(file)
151
+ else
152
+ fetch_feature_branch_diff(base_branch, file)
153
+ end
154
+ changed[file] = parse_hunk_lines(diff_text)
155
+ end
156
+ end
157
+
158
+ def fetch_feature_branch_diff(base_branch, file)
159
+ stdout, = Open3.capture3('git', 'diff', '-U0', "#{base_branch}...HEAD", '--', file)
160
+ stdout
161
+ end
162
+
163
+ def fetch_base_branch_diff(file)
164
+ unstaged, = Open3.capture3('git', 'diff', '-U0', 'HEAD', '--', file)
165
+ staged, = Open3.capture3('git', 'diff', '-U0', '--cached', '--', file)
166
+ "#{unstaged}#{staged}"
167
+ end
168
+
169
+ def parse_hunk_lines(diff_text)
170
+ lines = Set.new
171
+ diff_text.scan(/@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@/) do |start, count|
172
+ start = start.to_i
173
+ count = count.nil? ? 1 : count.to_i
174
+ count.times { |i| lines << (start + i) } if count.positive?
175
+ end
176
+ lines
177
+ end
178
+
179
+ def count_new_offenses(formatted_output)
180
+ formatted_output.lines.count { |l| l.match?(/^\[.+:\d+:\d+\] -/) }
181
+ end
182
+
123
183
  def detect_extensions
124
184
  %w[rubocop-factory_bot rubocop-rails rubocop-rspec rubocop-rspec_rails].select do |ext|
125
185
  Gem::Specification.find_by_name(ext)
@@ -148,7 +208,7 @@ module Rubosquad
148
208
  false
149
209
  end
150
210
 
151
- def format_output(stdout)
211
+ def format_output(stdout, changed_lines: nil)
152
212
  lines = []
153
213
  seen_files = Set.new
154
214
  current_file = nil
@@ -157,13 +217,10 @@ module Rubosquad
157
217
  if line.start_with?('==')
158
218
  file_path = line.strip.gsub(/^==\s*|\s*==$/, '')
159
219
  current_file = file_path
160
- lines << (seen_files.add?(file_path) ? "\n\e[36m#{line}\e[0m" : "\n#{line}")
220
+ lines << (seen_files.add?(file_path) ? "\n\e[36m#{line.chomp}\e[0m\n" : "\n#{line}")
161
221
  elsif line.match?(/^[A-Z]:/)
162
- parts = line.split(':')
163
- offense_type = parts.shift
164
- line_col = parts.shift(2).map(&:strip).join(':')
165
- message = parts.join(':').strip
166
- lines << "[#{current_file || 'unknown'}:#{line_col}] - #{offense_type}: #{message}\n"
222
+ offense = parse_offense_line(line, current_file, changed_lines)
223
+ lines << offense if offense
167
224
  else
168
225
  lines << line
169
226
  end
@@ -172,21 +229,61 @@ module Rubosquad
172
229
  lines.join
173
230
  end
174
231
 
175
- def print_rubocop_result(stdout, stderr, status, extensions)
232
+ def parse_offense_line(line, current_file, changed_lines)
233
+ parts = line.split(':')
234
+ offense_type = parts.shift
235
+ line_num = parts.first.strip.to_i
236
+ line_col = parts.shift(2).map(&:strip).join(':')
237
+ message = parts.join(':').strip
238
+
239
+ return nil if changed_lines && !changed_lines[current_file]&.include?(line_num)
240
+
241
+ type_str = if (color = OFFENSE_COLORS[offense_type])
242
+ "#{color}#{offense_type}#{RESET}"
243
+ else
244
+ offense_type
245
+ end
246
+
247
+ "[#{current_file || 'unknown'}:#{line_col}] - #{type_str}: #{message}\n"
248
+ end
249
+
250
+ def print_rubocop_result(stdout, stderr, status, extensions, options = {})
251
+ total = stdout.scan(/(\d+) offenses? detected/).flatten.map(&:to_i).sum
252
+ corrected = stdout.scan(/(\d+) offenses? corrected/).flatten.map(&:to_i).sum
253
+ remaining = total - corrected
254
+
176
255
  if status.success?
177
256
  puts "\nRubocop auto-corrections complete."
178
257
  else
179
258
  puts "\nRubocop completed with offenses:"
180
- total = stdout.scan(/(\d+) offense.* detected/).flatten.map(&:to_i).sum
181
259
  puts "Files inspected: #{stdout[/(\d+) files? inspected/, 1] || 'Unknown'}"
182
- puts "Total offenses detected: #{total}"
183
- unless stderr.strip.empty?
184
- puts "\nStandard error:"
185
- puts stderr
186
- end
187
260
  end
261
+
262
+ puts "#{corrected} auto-corrected | #{remaining} remaining" if total.positive?
263
+ display_stderr(stderr, options[:verbose])
188
264
  puts "\nRuboCop extensions used: #{extensions.join(', ')}" unless extensions.empty?
189
265
  end
266
+
267
+ def display_stderr(stderr, verbose)
268
+ filtered = verbose ? stderr : filter_new_cops_notice(stderr)
269
+ return if filtered.strip.empty?
270
+
271
+ puts "\nStandard error:"
272
+ puts filtered
273
+ end
274
+
275
+ def filter_new_cops_notice(stderr)
276
+ return stderr unless stderr.include?('opt-in to new cops')
277
+
278
+ lines = stderr.lines
279
+ start_idx = lines.index { |l| l.include?('opt-in to new cops') }
280
+ return stderr unless start_idx
281
+
282
+ end_idx = lines.index { |l| l.include?('docs.rubocop.org/rubocop/versioning') }
283
+ end_idx ||= lines.length - 1
284
+
285
+ (lines[0...start_idx] + lines[(end_idx + 1)..]).join
286
+ end
190
287
  end
191
288
  end
192
289
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubosquad
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - LucasWaki