rubosquad 0.3.0 → 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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/bin/rubosquad +1 -1
  3. data/lib/rubosquad.rb +143 -104
  4. metadata +5 -60
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c7e515c37ec988ae40363c20d82bd911112e580920665ad87f38ccd0ef8fbe9
4
- data.tar.gz: b17f9273f4485d9fa36a37401ac39fe5a69b7d4c174ed841f52c71c70a32e423
3
+ metadata.gz: b1893fc681cd5d1150871642903b53296899cc9524d0a747d0dee72d3e95a388
4
+ data.tar.gz: bb45d13fe8ecde3a2a66e9d3e89c3edd1aca115c3d9851b12a48110737630fb6
5
5
  SHA512:
6
- metadata.gz: e9b19ee533958d0fba40237227f1f9b495d2deb6a45d37dddf964a6d0b6ea5ae7cacf0925bd6552d68b6b8ec865fc0004ed341d9fd38648150c7366601385da2
7
- data.tar.gz: 8221ae12809121e8b9198fb7c6794d09db8af8e6fbfed1f1561a1979ae71e923184a2ebf6202b43930cd631f3aaa01936e211a477edc7dfad09e9bcc289942f2
6
+ metadata.gz: dcd1d7ac80333b7b0289a248500661b1e929db8eb2b117a0696ae92e147afab5c0f6fb7a4d9311a06de214a70d94c84a4e9a44e4565e30cb277f707043085a63
7
+ data.tar.gz: a73bb07f1eb5c63a8da472e6aef8d795fdafaa7da2804abb8bba2338d4bdcdd6080e8b94d69502b392d0f003daae4eb143fcd9ebb9164923265d6acec09077d1
data/bin/rubosquad CHANGED
@@ -3,4 +3,4 @@
3
3
 
4
4
  require 'rubosquad'
5
5
 
6
- Rubosquad::CLI.run
6
+ Rubosquad::CLI.run
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
- def self.run
11
- options = {}
12
- OptionParser.new do |opts|
13
- opts.banner = 'Usage: rubosquad [options]'
14
- opts.on('-A', '--unsafe-auto-correct', 'Run with rubocop -A (unsafe auto-corrections) instead of -a') do
15
- options[:unsafe_auto_correct] = true
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
- # Get the base branch (try main, then master, then origin/main, then origin/master)
20
- base_branch = detect_base_branch
19
+ current_branch = resolve_current_branch
20
+ files = resolve_changed_files(base_branch, current_branch)
21
21
 
22
- unless base_branch
23
- Rails.logger.debug 'Error: Could not find main or master branch.'
24
- exit 1
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
- # Get current branch name
28
- current_branch = `git rev-parse --abbrev-ref HEAD`.strip
29
-
30
- if current_branch == base_branch
31
- Rails.logger.debug "Warning: You are on the #{base_branch} branch. Comparing working directory changes."
32
- # Compare working directory + staged changes against HEAD
33
- changed_files = `git diff --name-only HEAD`.split("\n")
34
- changed_files += `git diff --name-only --cached`.split("\n")
35
- changed_files = changed_files.uniq.grep(/\.rb$/)
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
- # Filter out deleted files and files that don't exist
42
- changed_files = changed_files.select { |file| File.exist?(file) }
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
- if changed_files.empty?
45
- Rails.logger.debug 'No Ruby files have changed.'
46
- exit 0
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
- comparison_info = if current_branch == base_branch
50
- "working directory changes on #{base_branch}"
51
- else
52
- "#{current_branch} vs #{base_branch}"
53
- end
54
-
55
- Rails.logger.debug "\nRunning Rubocop on changed files (#{comparison_info}):"
56
- changed_files.each { |file| puts " - #{file}" }
57
- Rails.logger.debug
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
- # Construct the RuboCop command
69
-
70
- rubocop_option = options[:unsafe_auto_correct] ? '-A' : '-a'
71
- command = "rubocop #{rubocop_option} --format offenses --format simple #{available_extensions.map do |ext|
72
- "--require #{ext}"
73
- end.join(' ')} #{changed_files.join(' ')}"
74
-
75
- stdout, stderr, status = Open3.capture3(command)
76
-
77
- Rails.logger.debug "\nRubocop Output:"
78
- Rails.logger.debug '==Error type: Legend: C = Convention, W = Warning, E = Error, F = Fatal=='
79
-
80
- # Process and colorize output
81
- processed_output = ''
82
- seen_files = Set.new
83
- current_file = nil
84
-
85
- stdout.each_line do |line|
86
- if line.start_with?('==')
87
- file_path = line.strip.gsub(/^==\s*|\s*==$/, '')
88
- current_file = file_path
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
- Rails.logger.debug processed_output
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
- if status.success?
108
- Rails.logger.debug "\nRubocop auto-corrections complete."
109
- else
110
- Rails.logger.debug "\nRubocop completed with offenses:"
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
- offenses = stdout.scan(/(\d+) offense.* detected/)
113
- total_offenses = offenses.flatten.map(&:to_i).sum
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
- Rails.logger.debug "Files inspected: #{stdout[/(\d+) files? inspected/, 1] || 'Unknown'}"
116
- Rails.logger.debug "Total offenses detected: #{total_offenses}"
119
+ print_rubocop_result(stdout, stderr, status, extensions)
120
+ exit status.exitstatus unless status.success?
121
+ end
117
122
 
118
- unless stderr.strip.empty?
119
- Rails.logger.debug "\nStandard error:"
120
- Rails.logger.debug stderr
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
- Rails.logger.debug "\nRuboCop extensions used: #{available_extensions.join(', ')}"
125
- end
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
- # Detect the base branch to compare against
128
- def self.detect_base_branch
129
- # Try different possible base branch names
130
- candidates = ['main', 'master', 'origin/main', 'origin/master']
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
- candidates.each do |branch|
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
- nil
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.3.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: 2025-10-27 00:00:00.000000000 Z
11
+ date: 2026-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -24,62 +24,6 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.50'
27
- - !ruby/object:Gem::Dependency
28
- name: rubocop-factory_bot
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '2.0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '2.0'
41
- - !ruby/object:Gem::Dependency
42
- name: rubocop-rails
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '2.0'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '2.0'
55
- - !ruby/object:Gem::Dependency
56
- name: rubocop-rspec
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '2.0'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '2.0'
69
- - !ruby/object:Gem::Dependency
70
- name: rubocop-rspec_rails
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '2.0'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '2.0'
83
27
  description: A tool to run RuboCop with auto-correct on Ruby files changed in your
84
28
  Git branch compared to main
85
29
  email: lucas.waki@cloudwalk.io
@@ -93,7 +37,8 @@ files:
93
37
  homepage: https://github.com/cw-lucaswaki/rubosquad
94
38
  licenses:
95
39
  - MIT
96
- metadata: {}
40
+ metadata:
41
+ rubygems_mfa_required: 'true'
97
42
  post_install_message:
98
43
  rdoc_options: []
99
44
  require_paths:
@@ -102,7 +47,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
102
47
  requirements:
103
48
  - - ">="
104
49
  - !ruby/object:Gem::Version
105
- version: '0'
50
+ version: 2.7.0
106
51
  required_rubygems_version: !ruby/object:Gem::Requirement
107
52
  requirements:
108
53
  - - ">="