From 9f87ff1e01215ea6917e9c43a51ed02a0694a2b8 Mon Sep 17 00:00:00 2001 From: Henrique Medeiros Date: Mon, 5 May 2025 09:51:08 -0300 Subject: [PATCH 01/13] [wip] start moving executable code to CLI class --- exe/bundle_report | 78 +------------------------ lib/next_rails.rb | 1 + lib/next_rails/bundle_report/cli.rb | 91 +++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 76 deletions(-) create mode 100644 lib/next_rails/bundle_report/cli.rb diff --git a/exe/bundle_report b/exe/bundle_report index 25bbc8a..5a94bd9 100755 --- a/exe/bundle_report +++ b/exe/bundle_report @@ -1,78 +1,4 @@ #!/usr/bin/env ruby -# -# Print a report on our Gemfile -# Why not just use `bundle outdated`? It doesn't give us the information we care about (and it fails). -# -at_exit do - require "optparse" - require "next_rails" - options = {} - option_parser = OptionParser.new do |opts| - opts.banner = <<-EOS - Usage: #{$0} [report-type] [options] - - report-type There are two report types available: `outdated` and `compatibility` - - Examples: - #{$0} compatibility --rails-version 5.0 - #{$0} compatibility --ruby-version 3.3 - #{$0} outdated - #{$0} outdated --json - - ruby_check To find a compatible ruby version for the target rails version - - Examples: - #{$0} ruby_check --rails-version 7.0.0 - - EOS - - opts.separator "" - opts.separator "Options:" - - opts.on("--rails-version [STRING]", "Rails version to check compatibility against (defaults to 5.0)") do |rails_version| - options[:rails_version] = rails_version - end - - opts.on("--ruby-version [STRING]", "Ruby version to check compatibility against (defaults to 2.3)") do |ruby_version| - options[:ruby_version] = ruby_version - end - - opts.on("--include-rails-gems", "Include Rails gems in compatibility report (defaults to false)") do - options[:include_rails_gems] = true - end - - opts.on("--json", "Output JSON in outdated report (defaults to false)") do - options[:format] = 'json' - end - - opts.on_tail("-h", "--help", "Show this message") do - puts opts - exit - end - end - - begin - option_parser.parse! - rescue OptionParser::ParseError => e - STDERR.puts Rainbow(e.message).red - puts option_parser - exit 1 - end - - report_type = ARGV.first - - case report_type - when "ruby_check" then NextRails::BundleReport.compatible_ruby_version(rails_version: options.fetch(:rails_version)) - when "outdated" then NextRails::BundleReport.outdated(options.fetch(:format, nil)) - else - if options[:ruby_version] - NextRails::BundleReport.ruby_compatibility(ruby_version: options.fetch(:ruby_version, "2.3")) - else - NextRails::BundleReport.rails_compatibility(rails_version: options.fetch(:rails_version, "5.0"), include_rails_gems: options.fetch(:include_rails_gems, false)) - end - end -end - -# Needs to happen first -require "bundler/setup" +require 'next_rails' +NextRails::BundleReport.CLI(ARGV).generate diff --git a/lib/next_rails.rb b/lib/next_rails.rb index ec8481e..6ccc4ba 100644 --- a/lib/next_rails.rb +++ b/lib/next_rails.rb @@ -4,6 +4,7 @@ require "next_rails/version" require "next_rails/init" require "next_rails/bundle_report" +require "next_rails/bundle_report/cli" require "next_rails/bundle_report/ruby_version_compatibility" require "next_rails/bundle_report/rails_version_compatibility" require "deprecation_tracker" diff --git a/lib/next_rails/bundle_report/cli.rb b/lib/next_rails/bundle_report/cli.rb new file mode 100644 index 0000000..b43f22a --- /dev/null +++ b/lib/next_rails/bundle_report/cli.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +class NextRails::BundleReport::CLI + def initialize(argv) + validate_arguments(argv) + end + + def validate_arguments(argv) + # + end + + def generate + # Print a report on our Gemfile + # Why not just use `bundle outdated`? It doesn"t give us the information we care about (and it fails). + at_exit do + require "optparse" + require "next_rails" + + options = {} + option_parser = OptionParser.new do |opts| + opts.banner = <<-EOS + Usage: #{$0} [report-type] [options] + + report-type There are two report types available: `outdated` and `compatibility` + + Examples: + #{$0} compatibility --rails-version 5.0 + #{$0} compatibility --ruby-version 3.3 + #{$0} outdated + #{$0} outdated --json + + ruby_check To find a compatible ruby version for the target rails version + + Examples: + #{$0} ruby_check --rails-version 7.0.0 + + EOS + + opts.separator "" + opts.separator "Options:" + + opts.on("--rails-version [STRING]", "Rails version to check compatibility against (defaults to 5.0)") do |rails_version| + options[:rails_version] = rails_version + end + + opts.on("--ruby-version [STRING]", "Ruby version to check compatibility against (defaults to 2.3)") do |ruby_version| + options[:ruby_version] = ruby_version + end + + opts.on("--include-rails-gems", "Include Rails gems in compatibility report (defaults to false)") do + options[:include_rails_gems] = true + end + + opts.on("--json", "Output JSON in outdated report (defaults to false)") do + options[:format] = "json" + end + + opts.on_tail("-h", "--help", "Show this message") do + puts opts + exit + end + end + + begin + option_parser.parse! + rescue OptionParser::ParseError => e + STDERR.puts Rainbow(e.message).red + puts option_parser + exit 1 + end + + report_type = ARGV.first + + case report_type + when "ruby_check" then NextRails::BundleReport.compatible_ruby_version(rails_version: options.fetch(:rails_version)) + when "outdated" then bundle_report = NextRails::BundleReport.new + bundle_report.(options.fetch(:format, nil)) + else + if options[:ruby_version] + NextRails::BundleReport.ruby_compatibility(ruby_version: options.fetch(:ruby_version, "2.3")) + else + NextRails::BundleReport.rails_compatibility(rails_version: options.fetch(:rails_version, "5.0"), include_rails_gems: options.fetch(:include_rails_gems, false)) + end + end + end + + # Needs to happen first + require "bundler/setup" + + end +end From 5d49ec072a56b2f25e57dd677f54fdc7e9c204b1 Mon Sep 17 00:00:00 2001 From: Henrique Medeiros Date: Mon, 5 May 2025 13:23:06 -0300 Subject: [PATCH 02/13] [wip] add require to optparse --- lib/next_rails/bundle_report/cli.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/next_rails/bundle_report/cli.rb b/lib/next_rails/bundle_report/cli.rb index b43f22a..cb5be94 100644 --- a/lib/next_rails/bundle_report/cli.rb +++ b/lib/next_rails/bundle_report/cli.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true - +require "optparse" class NextRails::BundleReport::CLI def initialize(argv) validate_arguments(argv) From 66bed8cd11284c7d2419dcfc8fc5d03770d0078a Mon Sep 17 00:00:00 2001 From: Henrique Medeiros Date: Mon, 5 May 2025 13:26:06 -0300 Subject: [PATCH 03/13] [wip] remove duplicated require to optparse --- lib/next_rails/bundle_report/cli.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/next_rails/bundle_report/cli.rb b/lib/next_rails/bundle_report/cli.rb index cb5be94..193967b 100644 --- a/lib/next_rails/bundle_report/cli.rb +++ b/lib/next_rails/bundle_report/cli.rb @@ -1,5 +1,4 @@ # frozen_string_literal: true -require "optparse" class NextRails::BundleReport::CLI def initialize(argv) validate_arguments(argv) From 49928b8a009d47140d7d322a7514d9c058e5b541 Mon Sep 17 00:00:00 2001 From: Henrique Medeiros Date: Mon, 5 May 2025 14:03:31 -0300 Subject: [PATCH 04/13] move require bundler/setup to executable file --- exe/bundle_report | 4 +++- lib/next_rails/bundle_report/cli.rb | 4 ---- next_rails-1.4.6.gem | Bin 0 -> 26112 bytes 3 files changed, 3 insertions(+), 5 deletions(-) create mode 100644 next_rails-1.4.6.gem diff --git a/exe/bundle_report b/exe/bundle_report index 5a94bd9..5117d4e 100755 --- a/exe/bundle_report +++ b/exe/bundle_report @@ -1,4 +1,6 @@ #!/usr/bin/env ruby +# Needs to happen first +require 'bundler/setup' require 'next_rails' -NextRails::BundleReport.CLI(ARGV).generate +NextRails::BundleReport::CLI.new(ARGV).generate diff --git a/lib/next_rails/bundle_report/cli.rb b/lib/next_rails/bundle_report/cli.rb index 193967b..721f1d3 100644 --- a/lib/next_rails/bundle_report/cli.rb +++ b/lib/next_rails/bundle_report/cli.rb @@ -82,9 +82,5 @@ def generate end end end - - # Needs to happen first - require "bundler/setup" - end end diff --git a/next_rails-1.4.6.gem b/next_rails-1.4.6.gem new file mode 100644 index 0000000000000000000000000000000000000000..e0260d58728d5660b8ae8ff87811ab77b4b3e286 GIT binary patch literal 26112 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 Date: Mon, 5 May 2025 14:04:58 -0300 Subject: [PATCH 05/13] add todo to validate args --- lib/next_rails/bundle_report/cli.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/next_rails/bundle_report/cli.rb b/lib/next_rails/bundle_report/cli.rb index 721f1d3..8c78a57 100644 --- a/lib/next_rails/bundle_report/cli.rb +++ b/lib/next_rails/bundle_report/cli.rb @@ -5,7 +5,7 @@ def initialize(argv) end def validate_arguments(argv) - # + # TODO: validate the arguments end def generate From fb03dfaf62147b03424522f9da668b1552cd5794 Mon Sep 17 00:00:00 2001 From: Henrique Medeiros Date: Mon, 5 May 2025 14:24:14 -0300 Subject: [PATCH 06/13] remove .gem file from git --- next_rails-1.4.6.gem | Bin 26112 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 next_rails-1.4.6.gem diff --git a/next_rails-1.4.6.gem b/next_rails-1.4.6.gem deleted file mode 100644 index e0260d58728d5660b8ae8ff87811ab77b4b3e286..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26112 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 Date: Mon, 5 May 2025 17:59:04 -0300 Subject: [PATCH 07/13] refactor run method, add validation to arguments --- exe/bundle_report | 2 +- lib/next_rails/bundle_report/cli.rb | 145 +++++++++++++++++----------- 2 files changed, 92 insertions(+), 55 deletions(-) diff --git a/exe/bundle_report b/exe/bundle_report index 5117d4e..bc73f79 100755 --- a/exe/bundle_report +++ b/exe/bundle_report @@ -3,4 +3,4 @@ # Needs to happen first require 'bundler/setup' require 'next_rails' -NextRails::BundleReport::CLI.new(ARGV).generate +NextRails::BundleReport::CLI.new(ARGV).run diff --git a/lib/next_rails/bundle_report/cli.rb b/lib/next_rails/bundle_report/cli.rb index 8c78a57..68bb590 100644 --- a/lib/next_rails/bundle_report/cli.rb +++ b/lib/next_rails/bundle_report/cli.rb @@ -1,86 +1,123 @@ # frozen_string_literal: true + class NextRails::BundleReport::CLI def initialize(argv) validate_arguments(argv) end def validate_arguments(argv) - # TODO: validate the arguments + return unless argv.any? + + valid_report_types = %w[outdated compatibility ruby_check] + report_type = argv.first + + unless valid_report_types.include?(report_type) + raise ArgumentError, "Invalid report type '#{report_type}'. Valid types are: #{valid_report_types.join(', ')}." + end + + argv.each do |arg| + if arg.start_with?('--rails-version') && !arg.match?(/--rails-version=+\d+(\.\d+)*$/) + raise ArgumentError, 'Invalid Rails version format. Example: --rails-version=5.0.7' + end + + if arg.start_with?('--ruby-version') && !arg.match?(/--ruby-version=+\d+(\.\d+)*$/) + raise ArgumentError, 'Invalid Ruby version format. Example: --ruby-version=3.3' + end + end end - def generate - # Print a report on our Gemfile - # Why not just use `bundle outdated`? It doesn"t give us the information we care about (and it fails). + def run at_exit do - require "optparse" - require "next_rails" + setup_dependencies + options = parse_options + execute_report(ARGV.first, options) + end + end - options = {} - option_parser = OptionParser.new do |opts| - opts.banner = <<-EOS - Usage: #{$0} [report-type] [options] + private - report-type There are two report types available: `outdated` and `compatibility` + def setup_dependencies + require 'optparse' + require 'next_rails' + require 'next_rails/bundle_report' + end - Examples: - #{$0} compatibility --rails-version 5.0 - #{$0} compatibility --ruby-version 3.3 - #{$0} outdated - #{$0} outdated --json + def parse_options + options = {} + option_parser = OptionParser.new do |opts| + opts.banner = <<-EOS + Usage: #{$0} [report-type] [options] - ruby_check To find a compatible ruby version for the target rails version + report-type There are two report types available: `outdated` and `compatibility` - Examples: - #{$0} ruby_check --rails-version 7.0.0 + Examples: + #{$0} compatibility --rails-version 5.0 + #{$0} compatibility --ruby-version 3.3 + #{$0} outdated + #{$0} outdated --json - EOS + ruby_check To find a compatible ruby version for the target rails version - opts.separator "" - opts.separator "Options:" + Examples: + #{$0} ruby_check --rails-version 7.0.0 - opts.on("--rails-version [STRING]", "Rails version to check compatibility against (defaults to 5.0)") do |rails_version| - options[:rails_version] = rails_version - end + EOS - opts.on("--ruby-version [STRING]", "Ruby version to check compatibility against (defaults to 2.3)") do |ruby_version| - options[:ruby_version] = ruby_version - end + opts.separator '' + opts.separator 'Options:' - opts.on("--include-rails-gems", "Include Rails gems in compatibility report (defaults to false)") do - options[:include_rails_gems] = true - end + opts.on('--rails-version [STRING]', + 'Rails version to check compatibility against (defaults to 5.0)') do |rails_version| + options[:rails_version] = rails_version + end + + opts.on('--ruby-version [STRING]', + 'Ruby version to check compatibility against (defaults to 2.3)') do |ruby_version| + options[:ruby_version] = ruby_version + end - opts.on("--json", "Output JSON in outdated report (defaults to false)") do - options[:format] = "json" - end + opts.on('--include-rails-gems', 'Include Rails gems in compatibility report (defaults to false)') do + options[:include_rails_gems] = true + end - opts.on_tail("-h", "--help", "Show this message") do - puts opts - exit - end + opts.on('--json', 'Output JSON in outdated report (defaults to false)') do + options[:format] = 'json' end - begin - option_parser.parse! - rescue OptionParser::ParseError => e - STDERR.puts Rainbow(e.message).red - puts option_parser - exit 1 + opts.on_tail('-h', '--help', 'Show this message') do + puts opts + exit end + end - report_type = ARGV.first + begin + option_parser.parse! + rescue OptionParser::ParseError => e + warn Rainbow(e.message).red + puts option_parser + exit 1 + end + + options + end - case report_type - when "ruby_check" then NextRails::BundleReport.compatible_ruby_version(rails_version: options.fetch(:rails_version)) - when "outdated" then bundle_report = NextRails::BundleReport.new - bundle_report.(options.fetch(:format, nil)) + def execute_report(report_type, options) + case report_type + when 'ruby_check' + NextRails::BundleReport.compatible_ruby_version(rails_version: options.fetch(:rails_version)) + when 'outdated' + NextRails::BundleReport.outdated(options.fetch(:format, nil)) + when 'compatibility' + if options[:ruby_version] + NextRails::BundleReport.ruby_compatibility(ruby_version: options.fetch(:ruby_version, '2.3')) else - if options[:ruby_version] - NextRails::BundleReport.ruby_compatibility(ruby_version: options.fetch(:ruby_version, "2.3")) - else - NextRails::BundleReport.rails_compatibility(rails_version: options.fetch(:rails_version, "5.0"), include_rails_gems: options.fetch(:include_rails_gems, false)) - end + NextRails::BundleReport.rails_compatibility( + rails_version: options.fetch(:rails_version, '5.0'), + include_rails_gems: options.fetch(:include_rails_gems, false) + ) end + else + raise ArgumentError, "Invalid report type '#{report_type}'. Use --help for usage information." end end end From 15e36e672711ff5178415b4de1dd680ca55b295e Mon Sep 17 00:00:00 2001 From: Henrique Medeiros Date: Tue, 6 May 2025 09:57:40 -0300 Subject: [PATCH 08/13] [wip] adding tests to new CLI class --- lib/next_rails/bundle_report/cli.rb | 19 +++++--------- spec/next_rails/bundle_report/cli_spec.rb | 32 +++++++++++++++++++++++ 2 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 spec/next_rails/bundle_report/cli_spec.rb diff --git a/lib/next_rails/bundle_report/cli.rb b/lib/next_rails/bundle_report/cli.rb index 68bb590..842a12b 100644 --- a/lib/next_rails/bundle_report/cli.rb +++ b/lib/next_rails/bundle_report/cli.rb @@ -1,8 +1,12 @@ # frozen_string_literal: true +require 'optparse' +require 'next_rails' +require 'next_rails/bundle_report' class NextRails::BundleReport::CLI def initialize(argv) validate_arguments(argv) + @argv = argv end def validate_arguments(argv) @@ -27,28 +31,19 @@ def validate_arguments(argv) end def run - at_exit do - setup_dependencies - options = parse_options - execute_report(ARGV.first, options) - end + options = parse_options + execute_report(@argv.first, options) end private - def setup_dependencies - require 'optparse' - require 'next_rails' - require 'next_rails/bundle_report' - end - def parse_options options = {} option_parser = OptionParser.new do |opts| opts.banner = <<-EOS Usage: #{$0} [report-type] [options] - report-type There are two report types available: `outdated` and `compatibility` + report-type There are three report types available: `outdated`, `compatibility` and `ruby_check`. Examples: #{$0} compatibility --rails-version 5.0 diff --git a/spec/next_rails/bundle_report/cli_spec.rb b/spec/next_rails/bundle_report/cli_spec.rb new file mode 100644 index 0000000..e018982 --- /dev/null +++ b/spec/next_rails/bundle_report/cli_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' +require 'byebug' + +RSpec.describe NextRails::BundleReport::CLI do + describe '#initialize' do + it 'raises if called with invalid arguments' do + expect { described_class.new(['invalid_report_type']) } + .to raise_error(ArgumentError, + /Invalid report type 'invalid_report_type'. Valid types are: outdated, compatibility, ruby_check./) + end + + it 'calls outdated if called with outdated' do + expect(NextRails::BundleReport).to receive(:outdated) + described_class.new(['outdated']).run + end + + it 'calls compatible_ruby_version if called with ruby_check' do + expect(NextRails::BundleReport).to receive(:compatible_ruby_version) + described_class.new(['ruby_check', '--rails-version=7.0.0']).run + end + + it 'calls rails_compatibility if called with compatibility with rails-version option' do + expect(NextRails::BundleReport).to receive(:rails_compatibility) + described_class.new(['compatibility', '--rails-version=7.0.0']).run + end + + it 'calls ruby_compatibility if called with compatibility with ruby-version option' do + expect(NextRails::BundleReport).to receive(:ruby_compatibility) + described_class.new(['compatibility', '--ruby-version=3.2.0']).run + end + end +end From b050e8daa21e8a40b7a159189cb8e082fb7b22ab Mon Sep 17 00:00:00 2001 From: Henrique Medeiros Date: Tue, 6 May 2025 11:12:30 -0300 Subject: [PATCH 09/13] [wip] adjusting specs --- spec/next_rails/bundle_report/cli_spec.rb | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/spec/next_rails/bundle_report/cli_spec.rb b/spec/next_rails/bundle_report/cli_spec.rb index e018982..32deb75 100644 --- a/spec/next_rails/bundle_report/cli_spec.rb +++ b/spec/next_rails/bundle_report/cli_spec.rb @@ -14,19 +14,24 @@ described_class.new(['outdated']).run end + # it 'raises if called ruby_check without --rails-version' do + # expect { described_class.new(['ruby_check']) } + # .to raise_error(KeyError, /key not found: :rails_version/) + # end + it 'calls compatible_ruby_version if called with ruby_check' do - expect(NextRails::BundleReport).to receive(:compatible_ruby_version) - described_class.new(['ruby_check', '--rails-version=7.0.0']).run + expect(NextRails::BundleReport).to receive(:compatible_ruby_version).with(rails_version: '8.0.0') + described_class.new(['ruby_check', '--rails-version=8.0.0']).run end it 'calls rails_compatibility if called with compatibility with rails-version option' do expect(NextRails::BundleReport).to receive(:rails_compatibility) - described_class.new(['compatibility', '--rails-version=7.0.0']).run + described_class.new(['compatibility', '--rails-version=8.0.0']).run end it 'calls ruby_compatibility if called with compatibility with ruby-version option' do expect(NextRails::BundleReport).to receive(:ruby_compatibility) - described_class.new(['compatibility', '--ruby-version=3.2.0']).run + described_class.new(['compatibility', '--ruby-version=3.4.0']).run end end end From c8397dc46f8f4efa16aa50b72e154cb0d0bf4ce4 Mon Sep 17 00:00:00 2001 From: amandabizzinotto Date: Tue, 6 May 2025 11:29:41 -0300 Subject: [PATCH 10/13] Specify which array option_parser.parse! should parse --- lib/next_rails/bundle_report/cli.rb | 2 +- spec/next_rails/bundle_report/cli_spec.rb | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/next_rails/bundle_report/cli.rb b/lib/next_rails/bundle_report/cli.rb index 842a12b..2db2a63 100644 --- a/lib/next_rails/bundle_report/cli.rb +++ b/lib/next_rails/bundle_report/cli.rb @@ -86,7 +86,7 @@ def parse_options end begin - option_parser.parse! + option_parser.parse!(@argv) rescue OptionParser::ParseError => e warn Rainbow(e.message).red puts option_parser diff --git a/spec/next_rails/bundle_report/cli_spec.rb b/spec/next_rails/bundle_report/cli_spec.rb index 32deb75..712089d 100644 --- a/spec/next_rails/bundle_report/cli_spec.rb +++ b/spec/next_rails/bundle_report/cli_spec.rb @@ -14,13 +14,8 @@ described_class.new(['outdated']).run end - # it 'raises if called ruby_check without --rails-version' do - # expect { described_class.new(['ruby_check']) } - # .to raise_error(KeyError, /key not found: :rails_version/) - # end - it 'calls compatible_ruby_version if called with ruby_check' do - expect(NextRails::BundleReport).to receive(:compatible_ruby_version).with(rails_version: '8.0.0') + expect(NextRails::BundleReport).to receive(:compatible_ruby_version) described_class.new(['ruby_check', '--rails-version=8.0.0']).run end From 0eef937fba0016f96cd3c04a792ea1d87a542e23 Mon Sep 17 00:00:00 2001 From: Henrique Medeiros Date: Tue, 6 May 2025 11:52:35 -0300 Subject: [PATCH 11/13] fix default behavior --- lib/next_rails/bundle_report/cli.rb | 6 ++---- spec/next_rails/bundle_report/cli_spec.rb | 6 +++++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/next_rails/bundle_report/cli.rb b/lib/next_rails/bundle_report/cli.rb index 2db2a63..edeaf06 100644 --- a/lib/next_rails/bundle_report/cli.rb +++ b/lib/next_rails/bundle_report/cli.rb @@ -5,8 +5,8 @@ require 'next_rails/bundle_report' class NextRails::BundleReport::CLI def initialize(argv) - validate_arguments(argv) @argv = argv + validate_arguments(@argv) end def validate_arguments(argv) @@ -102,7 +102,7 @@ def execute_report(report_type, options) NextRails::BundleReport.compatible_ruby_version(rails_version: options.fetch(:rails_version)) when 'outdated' NextRails::BundleReport.outdated(options.fetch(:format, nil)) - when 'compatibility' + else if options[:ruby_version] NextRails::BundleReport.ruby_compatibility(ruby_version: options.fetch(:ruby_version, '2.3')) else @@ -111,8 +111,6 @@ def execute_report(report_type, options) include_rails_gems: options.fetch(:include_rails_gems, false) ) end - else - raise ArgumentError, "Invalid report type '#{report_type}'. Use --help for usage information." end end end diff --git a/spec/next_rails/bundle_report/cli_spec.rb b/spec/next_rails/bundle_report/cli_spec.rb index 712089d..40fdacd 100644 --- a/spec/next_rails/bundle_report/cli_spec.rb +++ b/spec/next_rails/bundle_report/cli_spec.rb @@ -1,8 +1,12 @@ require 'spec_helper' -require 'byebug' RSpec.describe NextRails::BundleReport::CLI do describe '#initialize' do + it 'calls with called with any arguemnt' do + expect(NextRails::BundleReport).to receive(:rails_compatibility) + described_class.new([]).run + end + it 'raises if called with invalid arguments' do expect { described_class.new(['invalid_report_type']) } .to raise_error(ArgumentError, From f53028c651cbe877cd64dd3081f7a5268b44c459 Mon Sep 17 00:00:00 2001 From: amandabizzinotto Date: Tue, 6 May 2025 12:05:26 -0300 Subject: [PATCH 12/13] Move from single to double quotes --- exe/bundle_report | 4 +- lib/next_rails/bundle_report/cli.rb | 45 ++++++++++++----------- spec/next_rails/bundle_report/cli_spec.rb | 14 +++---- 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/exe/bundle_report b/exe/bundle_report index bc73f79..bd0a711 100755 --- a/exe/bundle_report +++ b/exe/bundle_report @@ -1,6 +1,6 @@ #!/usr/bin/env ruby # Needs to happen first -require 'bundler/setup' -require 'next_rails' +require "bundler/setup" +require "next_rails" NextRails::BundleReport::CLI.new(ARGV).run diff --git a/lib/next_rails/bundle_report/cli.rb b/lib/next_rails/bundle_report/cli.rb index edeaf06..db578bc 100644 --- a/lib/next_rails/bundle_report/cli.rb +++ b/lib/next_rails/bundle_report/cli.rb @@ -1,12 +1,13 @@ # frozen_string_literal: true -require 'optparse' -require 'next_rails' -require 'next_rails/bundle_report' +require "optparse" +require "next_rails" +require "next_rails/bundle_report" + class NextRails::BundleReport::CLI def initialize(argv) + validate_arguments(argv) @argv = argv - validate_arguments(@argv) end def validate_arguments(argv) @@ -20,12 +21,12 @@ def validate_arguments(argv) end argv.each do |arg| - if arg.start_with?('--rails-version') && !arg.match?(/--rails-version=+\d+(\.\d+)*$/) - raise ArgumentError, 'Invalid Rails version format. Example: --rails-version=5.0.7' + if arg.start_with?("--rails-version") && !arg.match?(/--rails-version=+\d+(\.\d+)*$/) + raise ArgumentError, "Invalid Rails version format. Example: --rails-version=5.0.7" end - if arg.start_with?('--ruby-version') && !arg.match?(/--ruby-version=+\d+(\.\d+)*$/) - raise ArgumentError, 'Invalid Ruby version format. Example: --ruby-version=3.3' + if arg.start_with?("--ruby-version") && !arg.match?(/--ruby-version=+\d+(\.\d+)*$/) + raise ArgumentError, "Invalid Ruby version format. Example: --ruby-version=3.3" end end end @@ -58,28 +59,28 @@ def parse_options EOS - opts.separator '' - opts.separator 'Options:' + opts.separator "" + opts.separator "Options:" - opts.on('--rails-version [STRING]', - 'Rails version to check compatibility against (defaults to 5.0)') do |rails_version| + opts.on("--rails-version [STRING]", + "Rails version to check compatibility against (defaults to 5.0)") do |rails_version| options[:rails_version] = rails_version end - opts.on('--ruby-version [STRING]', - 'Ruby version to check compatibility against (defaults to 2.3)') do |ruby_version| + opts.on("--ruby-version [STRING]", + "Ruby version to check compatibility against (defaults to 2.3)") do |ruby_version| options[:ruby_version] = ruby_version end - opts.on('--include-rails-gems', 'Include Rails gems in compatibility report (defaults to false)') do + opts.on("--include-rails-gems", "Include Rails gems in compatibility report (defaults to false)") do options[:include_rails_gems] = true end - opts.on('--json', 'Output JSON in outdated report (defaults to false)') do - options[:format] = 'json' + opts.on("--json", "Output JSON in outdated report (defaults to false)") do + options[:format] = "json" end - opts.on_tail('-h', '--help', 'Show this message') do + opts.on_tail("-h", "--help", "Show this message") do puts opts exit end @@ -98,16 +99,16 @@ def parse_options def execute_report(report_type, options) case report_type - when 'ruby_check' + when "ruby_check" NextRails::BundleReport.compatible_ruby_version(rails_version: options.fetch(:rails_version)) - when 'outdated' + when "outdated" NextRails::BundleReport.outdated(options.fetch(:format, nil)) else if options[:ruby_version] - NextRails::BundleReport.ruby_compatibility(ruby_version: options.fetch(:ruby_version, '2.3')) + NextRails::BundleReport.ruby_compatibility(ruby_version: options.fetch(:ruby_version, "2.3")) else NextRails::BundleReport.rails_compatibility( - rails_version: options.fetch(:rails_version, '5.0'), + rails_version: options.fetch(:rails_version, "5.0"), include_rails_gems: options.fetch(:include_rails_gems, false) ) end diff --git a/spec/next_rails/bundle_report/cli_spec.rb b/spec/next_rails/bundle_report/cli_spec.rb index 40fdacd..7cb89bf 100644 --- a/spec/next_rails/bundle_report/cli_spec.rb +++ b/spec/next_rails/bundle_report/cli_spec.rb @@ -1,4 +1,4 @@ -require 'spec_helper' +require "spec_helper" RSpec.describe NextRails::BundleReport::CLI do describe '#initialize' do @@ -13,24 +13,24 @@ /Invalid report type 'invalid_report_type'. Valid types are: outdated, compatibility, ruby_check./) end - it 'calls outdated if called with outdated' do + it "calls outdated if called with outdated" do expect(NextRails::BundleReport).to receive(:outdated) - described_class.new(['outdated']).run + described_class.new(["outdated"]).run end - it 'calls compatible_ruby_version if called with ruby_check' do + it "calls compatible_ruby_version if called with ruby_check" do expect(NextRails::BundleReport).to receive(:compatible_ruby_version) - described_class.new(['ruby_check', '--rails-version=8.0.0']).run + described_class.new(["ruby_check", "--rails-version=8.0.0"]).run end it 'calls rails_compatibility if called with compatibility with rails-version option' do expect(NextRails::BundleReport).to receive(:rails_compatibility) - described_class.new(['compatibility', '--rails-version=8.0.0']).run + described_class.new(["compatibility", "--rails-version=8.0.0"]).run end it 'calls ruby_compatibility if called with compatibility with ruby-version option' do expect(NextRails::BundleReport).to receive(:ruby_compatibility) - described_class.new(['compatibility', '--ruby-version=3.4.0']).run + described_class.new(["compatibility", "--ruby-version=3.4.0"]).run end end end From a8431deefefea4de1c0320fc32e85d09ff413d66 Mon Sep 17 00:00:00 2001 From: Juan Vasquez Date: Tue, 6 May 2025 14:24:41 -0600 Subject: [PATCH 13/13] Add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3a7eae..571dc37 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # main [(unreleased)](https://github.com/fastruby/next_rails/compare/v1.4.6...main) - [BUGFIX: example](https://github.com/fastruby/next_rails/pull/) +- [CHORE: Create an entry point for the BundleReport command](https://github.com/fastruby/next_rails/pull/154) * Your changes/patches go here.