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.
- checksums.yaml +4 -4
- data/lib/rubosquad.rb +113 -16
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bdc45fe50d0678e9dd9f45bc7967aeea4ed6b3ee830593875d9ad8911f277592
|
|
4
|
+
data.tar.gz: 784949c827c7d611bf125f791cf3d5913f93a9b508efc1dcb0814c3d3350a607
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
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
|
-
|
|
163
|
-
|
|
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
|
|
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
|