rubosquad 0.2.1 → 0.4.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/bin/rubosquad +1 -1
- data/lib/rubosquad.rb +143 -104
- metadata +7 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b1893fc681cd5d1150871642903b53296899cc9524d0a747d0dee72d3e95a388
|
|
4
|
+
data.tar.gz: bb45d13fe8ecde3a2a66e9d3e89c3edd1aca115c3d9851b12a48110737630fb6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dcd1d7ac80333b7b0289a248500661b1e929db8eb2b117a0696ae92e147afab5c0f6fb7a4d9311a06de214a70d94c84a4e9a44e4565e30cb277f707043085a63
|
|
7
|
+
data.tar.gz: a73bb07f1eb5c63a8da472e6aef8d795fdafaa7da2804abb8bba2338d4bdcdd6080e8b94d69502b392d0f003daae4eb143fcd9ebb9164923265d6acec09077d1
|
data/bin/rubosquad
CHANGED
data/lib/rubosquad.rb
CHANGED
|
@@ -4,138 +4,177 @@ require 'open3'
|
|
|
4
4
|
require 'set'
|
|
5
5
|
require 'optparse'
|
|
6
6
|
|
|
7
|
-
# Get the list of changed Ruby files in the current branch compared to main
|
|
8
7
|
module Rubosquad
|
|
9
8
|
class CLI
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
class << self
|
|
10
|
+
def run
|
|
11
|
+
options = parse_options
|
|
12
|
+
base_branch = detect_base_branch
|
|
13
|
+
|
|
14
|
+
unless base_branch
|
|
15
|
+
puts 'Error: Could not find main or master branch.'
|
|
16
|
+
exit 1
|
|
16
17
|
end
|
|
17
|
-
end.parse!
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
current_branch = resolve_current_branch
|
|
20
|
+
files = resolve_changed_files(base_branch, current_branch)
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
if files.empty?
|
|
23
|
+
puts 'No Ruby files have changed.'
|
|
24
|
+
exit 0
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
print_file_list(files, current_branch, base_branch)
|
|
28
|
+
run_rubocop(options, files)
|
|
25
29
|
end
|
|
26
30
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
else
|
|
37
|
-
# Compare current branch against base branch (all commits since divergence)
|
|
38
|
-
changed_files = `git diff --name-only #{base_branch}...HEAD`.split("\n").grep(/\.rb$/)
|
|
31
|
+
def detect_base_branch
|
|
32
|
+
candidates = %w[main master origin/main origin/master]
|
|
33
|
+
|
|
34
|
+
candidates.each do |branch|
|
|
35
|
+
stdout, _stderr, status = Open3.capture3('git', 'rev-parse', '--verify', branch)
|
|
36
|
+
return branch if status.success? && !stdout.strip.empty?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
nil
|
|
39
40
|
end
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def parse_options
|
|
45
|
+
options = {}
|
|
46
|
+
OptionParser.new do |opts|
|
|
47
|
+
opts.banner = 'Usage: rubosquad [options]'
|
|
48
|
+
opts.on('-A', '--unsafe-auto-correct', 'Run with rubocop -A (unsafe auto-corrections) instead of -a') do
|
|
49
|
+
options[:unsafe_auto_correct] = true
|
|
50
|
+
end
|
|
51
|
+
end.parse!
|
|
52
|
+
options
|
|
53
|
+
end
|
|
43
54
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
55
|
+
def resolve_current_branch
|
|
56
|
+
stdout, stderr, status = Open3.capture3('git', 'rev-parse', '--abbrev-ref', 'HEAD')
|
|
57
|
+
unless status.success?
|
|
58
|
+
puts "Error: Failed to determine current branch: #{stderr.strip}"
|
|
59
|
+
exit 1
|
|
60
|
+
end
|
|
61
|
+
stdout.strip
|
|
47
62
|
end
|
|
48
63
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
puts
|
|
58
|
-
|
|
59
|
-
# Check for available RuboCop extensions that can actually be loaded
|
|
60
|
-
extensions = %w[rubocop-factory_bot rubocop-rails rubocop-rspec rubocop-rspec_rails]
|
|
61
|
-
available_extensions = extensions.select do |ext|
|
|
62
|
-
require ext
|
|
63
|
-
true
|
|
64
|
-
rescue LoadError
|
|
65
|
-
false
|
|
64
|
+
def resolve_changed_files(base_branch, current_branch)
|
|
65
|
+
files = if current_branch == base_branch
|
|
66
|
+
puts "Warning: You are on the #{base_branch} branch. Comparing working directory changes."
|
|
67
|
+
base_branch_files
|
|
68
|
+
else
|
|
69
|
+
feature_branch_files(base_branch)
|
|
70
|
+
end
|
|
71
|
+
files.select { |f| File.exist?(f) }
|
|
66
72
|
end
|
|
67
73
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
processed_output += if seen_files.add?(file_path)
|
|
90
|
-
"\n\e[36m#{line}\e[0m"
|
|
91
|
-
else
|
|
92
|
-
"\n#{line}"
|
|
93
|
-
end
|
|
94
|
-
elsif line.match?(/^[A-Z]:/)
|
|
95
|
-
parts = line.split(':')
|
|
96
|
-
offense_type = parts.shift
|
|
97
|
-
line_col = parts.shift(2).map(&:strip).join(':')
|
|
98
|
-
message = parts.join(':').strip
|
|
99
|
-
processed_output += "[#{current_file}:#{line_col}] - #{offense_type}: #{message}\n"
|
|
100
|
-
else
|
|
101
|
-
processed_output += line
|
|
74
|
+
def base_branch_files
|
|
75
|
+
unstaged, stderr, status = Open3.capture3('git', 'diff', '--name-only', 'HEAD')
|
|
76
|
+
unless status.success?
|
|
77
|
+
puts "Error: Failed to get unstaged changes: #{stderr.strip}"
|
|
78
|
+
exit 1
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
staged, stderr, status = Open3.capture3('git', 'diff', '--name-only', '--cached')
|
|
82
|
+
unless status.success?
|
|
83
|
+
puts "Error: Failed to get staged changes: #{stderr.strip}"
|
|
84
|
+
exit 1
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
(unstaged.split("\n") + staged.split("\n")).uniq.grep(/\.rb$/)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def feature_branch_files(base_branch)
|
|
91
|
+
stdout, stderr, status = Open3.capture3('git', 'diff', '--name-only', "#{base_branch}...HEAD")
|
|
92
|
+
unless status.success?
|
|
93
|
+
puts "Error: Failed to diff against #{base_branch}: #{stderr.strip}"
|
|
94
|
+
exit 1
|
|
102
95
|
end
|
|
96
|
+
stdout.split("\n").grep(/\.rb$/)
|
|
103
97
|
end
|
|
104
98
|
|
|
105
|
-
|
|
99
|
+
def print_file_list(files, current_branch, base_branch)
|
|
100
|
+
comparison = if current_branch == base_branch
|
|
101
|
+
"working directory changes on #{base_branch}"
|
|
102
|
+
else
|
|
103
|
+
"#{current_branch} vs #{base_branch}"
|
|
104
|
+
end
|
|
105
|
+
puts "\nRunning Rubocop on changed files (#{comparison}):"
|
|
106
|
+
files.each { |f| puts " - #{f}" }
|
|
107
|
+
puts
|
|
108
|
+
end
|
|
106
109
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
def run_rubocop(options, files)
|
|
111
|
+
extensions = detect_extensions
|
|
112
|
+
cmd = build_rubocop_cmd(options, extensions, files)
|
|
113
|
+
stdout, stderr, status = Open3.capture3(*cmd)
|
|
111
114
|
|
|
112
|
-
|
|
113
|
-
|
|
115
|
+
puts "\nRubocop Output:"
|
|
116
|
+
puts '==Error type: Legend: C = Convention, W = Warning, E = Error, F = Fatal=='
|
|
117
|
+
puts format_output(stdout)
|
|
114
118
|
|
|
115
|
-
|
|
116
|
-
|
|
119
|
+
print_rubocop_result(stdout, stderr, status, extensions)
|
|
120
|
+
exit status.exitstatus unless status.success?
|
|
121
|
+
end
|
|
117
122
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
123
|
+
def detect_extensions
|
|
124
|
+
%w[rubocop-factory_bot rubocop-rails rubocop-rspec rubocop-rspec_rails].select do |ext|
|
|
125
|
+
Gem::Specification.find_by_name(ext)
|
|
126
|
+
true
|
|
127
|
+
rescue Gem::LoadError
|
|
128
|
+
false
|
|
121
129
|
end
|
|
122
130
|
end
|
|
123
131
|
|
|
124
|
-
|
|
125
|
-
|
|
132
|
+
def build_rubocop_cmd(options, extensions, files)
|
|
133
|
+
flag = options[:unsafe_auto_correct] ? '-A' : '-a'
|
|
134
|
+
cmd = ['rubocop', flag, '--format', 'offenses', '--format', 'simple']
|
|
135
|
+
extensions.each { |ext| cmd.push('--require', ext) }
|
|
136
|
+
cmd.concat(files)
|
|
137
|
+
end
|
|
126
138
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
139
|
+
def format_output(stdout)
|
|
140
|
+
lines = []
|
|
141
|
+
seen_files = Set.new
|
|
142
|
+
current_file = nil
|
|
143
|
+
|
|
144
|
+
stdout.each_line do |line|
|
|
145
|
+
if line.start_with?('==')
|
|
146
|
+
file_path = line.strip.gsub(/^==\s*|\s*==$/, '')
|
|
147
|
+
current_file = file_path
|
|
148
|
+
lines << (seen_files.add?(file_path) ? "\n\e[36m#{line}\e[0m" : "\n#{line}")
|
|
149
|
+
elsif line.match?(/^[A-Z]:/)
|
|
150
|
+
parts = line.split(':')
|
|
151
|
+
offense_type = parts.shift
|
|
152
|
+
line_col = parts.shift(2).map(&:strip).join(':')
|
|
153
|
+
message = parts.join(':').strip
|
|
154
|
+
lines << "[#{current_file || 'unknown'}:#{line_col}] - #{offense_type}: #{message}\n"
|
|
155
|
+
else
|
|
156
|
+
lines << line
|
|
157
|
+
end
|
|
158
|
+
end
|
|
131
159
|
|
|
132
|
-
|
|
133
|
-
# Check if the branch exists
|
|
134
|
-
result = `git rev-parse --verify #{branch} 2>/dev/null`.strip
|
|
135
|
-
return branch unless result.empty?
|
|
160
|
+
lines.join
|
|
136
161
|
end
|
|
137
162
|
|
|
138
|
-
|
|
163
|
+
def print_rubocop_result(stdout, stderr, status, extensions)
|
|
164
|
+
if status.success?
|
|
165
|
+
puts "\nRubocop auto-corrections complete."
|
|
166
|
+
else
|
|
167
|
+
puts "\nRubocop completed with offenses:"
|
|
168
|
+
total = stdout.scan(/(\d+) offense.* detected/).flatten.map(&:to_i).sum
|
|
169
|
+
puts "Files inspected: #{stdout[/(\d+) files? inspected/, 1] || 'Unknown'}"
|
|
170
|
+
puts "Total offenses detected: #{total}"
|
|
171
|
+
unless stderr.strip.empty?
|
|
172
|
+
puts "\nStandard error:"
|
|
173
|
+
puts stderr
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
puts "\nRuboCop extensions used: #{extensions.join(', ')}" unless extensions.empty?
|
|
177
|
+
end
|
|
139
178
|
end
|
|
140
179
|
end
|
|
141
180
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubosquad
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- LucasWaki
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-02-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rubocop
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '1.
|
|
19
|
+
version: '1.50'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '1.
|
|
26
|
+
version: '1.50'
|
|
27
27
|
description: A tool to run RuboCop with auto-correct on Ruby files changed in your
|
|
28
28
|
Git branch compared to main
|
|
29
29
|
email: lucas.waki@cloudwalk.io
|
|
@@ -37,7 +37,8 @@ files:
|
|
|
37
37
|
homepage: https://github.com/cw-lucaswaki/rubosquad
|
|
38
38
|
licenses:
|
|
39
39
|
- MIT
|
|
40
|
-
metadata:
|
|
40
|
+
metadata:
|
|
41
|
+
rubygems_mfa_required: 'true'
|
|
41
42
|
post_install_message:
|
|
42
43
|
rdoc_options: []
|
|
43
44
|
require_paths:
|
|
@@ -46,7 +47,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
46
47
|
requirements:
|
|
47
48
|
- - ">="
|
|
48
49
|
- !ruby/object:Gem::Version
|
|
49
|
-
version:
|
|
50
|
+
version: 2.7.0
|
|
50
51
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
51
52
|
requirements:
|
|
52
53
|
- - ">="
|