diff --git a/CHANGELOG.md b/CHANGELOG.md index caffef8..667bfcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # main [(unreleased)](https://github.com/fastruby/next_rails/compare/v1.4.4...main) - [BUGFIX: example](https://github.com/fastruby/next_rails/pull/) +- [Move rails_version compatibility to its own class](https://github.com/fastruby/next_rails/pull/137) * Your changes/patches go here. diff --git a/exe/bundle_report b/exe/bundle_report index 0708464..25bbc8a 100755 --- a/exe/bundle_report +++ b/exe/bundle_report @@ -67,9 +67,9 @@ at_exit do when "outdated" then NextRails::BundleReport.outdated(options.fetch(:format, nil)) else if options[:ruby_version] - NextRails::BundleReport.compatibility(ruby_version: options.fetch(:ruby_version, "2.3")) + NextRails::BundleReport.ruby_compatibility(ruby_version: options.fetch(:ruby_version, "2.3")) else - NextRails::BundleReport.compatibility(rails_version: options.fetch(:rails_version, "5.0"), include_rails_gems: options.fetch(:include_rails_gems, false)) + NextRails::BundleReport.rails_compatibility(rails_version: options.fetch(:rails_version, "5.0"), include_rails_gems: options.fetch(:include_rails_gems, false)) end end end diff --git a/lib/next_rails.rb b/lib/next_rails.rb index 27412cf..ec8481e 100644 --- a/lib/next_rails.rb +++ b/lib/next_rails.rb @@ -5,6 +5,7 @@ require "next_rails/init" require "next_rails/bundle_report" require "next_rails/bundle_report/ruby_version_compatibility" +require "next_rails/bundle_report/rails_version_compatibility" require "deprecation_tracker" module NextRails diff --git a/lib/next_rails/bundle_report.rb b/lib/next_rails/bundle_report.rb index 771035c..76fec87 100644 --- a/lib/next_rails/bundle_report.rb +++ b/lib/next_rails/bundle_report.rb @@ -8,69 +8,18 @@ module NextRails module BundleReport extend self - def compatibility(rails_version: nil, ruby_version: nil, include_rails_gems: nil) - return puts RubyVersionCompatibility.new(options: { ruby_version: ruby_version }).generate if ruby_version + def ruby_compatibility(ruby_version: nil) + return unless ruby_version - incompatible_gems = NextRails::GemInfo.all.reject do |gem| - gem.compatible_with_rails?(rails_version: rails_version) || (!include_rails_gems && gem.from_rails?) - end.sort_by { |gem| gem.name } - - incompatible_gems.each { |gem| gem.find_latest_compatible(rails_version: rails_version) } - - incompatible_gems_by_state = incompatible_gems.group_by { |gem| gem.state(rails_version) } - - puts erb_output(incompatible_gems_by_state, incompatible_gems, rails_version) + options = { ruby_version: ruby_version } + puts RubyVersionCompatibility.new(options: options).generate end - def erb_output(incompatible_gems_by_state, incompatible_gems, rails_version) - template = <<-ERB -<% if incompatible_gems_by_state[:found_compatible] -%> -<%= Rainbow("=> Incompatible with Rails #{rails_version} (with new versions that are compatible):").white.bold %> -<%= Rainbow("These gems will need to be upgraded before upgrading to Rails #{rails_version}.").italic %> - -<% incompatible_gems_by_state[:found_compatible].each do |gem| -%> -<%= gem_header(gem) %> - upgrade to <%= gem.latest_compatible_version.version %> -<% end -%> - -<% end -%> -<% if incompatible_gems_by_state[:incompatible] -%> -<%= Rainbow("=> Incompatible with Rails #{rails_version} (with no new compatible versions):").white.bold %> -<%= Rainbow("These gems will need to be removed or replaced before upgrading to Rails #{rails_version}.").italic %> - -<% incompatible_gems_by_state[:incompatible].each do |gem| -%> -<%= gem_header(gem) %> - new version, <%= gem.latest_version.version %>, is not compatible with Rails #{rails_version} -<% end -%> - -<% end -%> -<% if incompatible_gems_by_state[:no_new_version] -%> -<%= Rainbow("=> Incompatible with Rails #{rails_version} (with no new versions):").white.bold %> -<%= Rainbow("These gems will need to be upgraded by us or removed before upgrading to Rails #{rails_version}.").italic %> -<%= Rainbow("This list is likely to contain internal gems, like Cuddlefish.").italic %> - -<% incompatible_gems_by_state[:no_new_version].each do |gem| -%> -<%= gem_header(gem) %> - new version not found -<% end -%> - -<% end -%> -<%= Rainbow(incompatible_gems.length.to_s).red %> gems incompatible with Rails <%= rails_version %> - ERB - - erb_version = ERB.version - if erb_version =~ /erb.rb \[([\d\.]+) .*\]/ - erb_version = $1 - end - - if Gem::Version.new(erb_version) < Gem::Version.new("2.2") - ERB.new(template, nil, "-").result(binding) - else - ERB.new(template, trim_mode: "-").result(binding) - end - end + def rails_compatibility(rails_version: nil, include_rails_gems: nil) + return unless rails_version - def gem_header(_gem) - header = Rainbow("#{_gem.name} #{_gem.version}").bold - header << Rainbow(" (loaded from git)").magenta if _gem.sourced_from_git? - header + options = { rails_version: rails_version, include_rails_gems: include_rails_gems } + puts RailsVersionCompatibility.new(options: options).generate end def compatible_ruby_version(rails_version) diff --git a/lib/next_rails/bundle_report/rails_version_compatibility.rb b/lib/next_rails/bundle_report/rails_version_compatibility.rb new file mode 100644 index 0000000..8d661ef --- /dev/null +++ b/lib/next_rails/bundle_report/rails_version_compatibility.rb @@ -0,0 +1,84 @@ +class NextRails::BundleReport::RailsVersionCompatibility + def initialize(gems: NextRails::GemInfo.all, options: {}) + @gems = gems + @options = options + end + + def generate + erb_output + end + + def incompatible_gems_by_state + @incompatible_gems_by_state ||= begin + incompatible_gems.each { |gem| gem.find_latest_compatible(rails_version: rails_version) } + incompatible_gems.group_by { |gem| gem.state(rails_version) } + end + end + + private + + def erb_output + template = <<-ERB +<% if incompatible_gems_by_state[:found_compatible] -%> +<%= Rainbow("=> Incompatible with Rails #{rails_version} (with new versions that are compatible):").white.bold %> +<%= Rainbow("These gems will need to be upgraded before upgrading to Rails #{rails_version}.").italic %> + +<% incompatible_gems_by_state[:found_compatible].each do |gem| -%> +<%= gem_header(gem) %> - upgrade to <%= gem.latest_compatible_version.version %> +<% end -%> + +<% end -%> +<% if incompatible_gems_by_state[:incompatible] -%> +<%= Rainbow("=> Incompatible with Rails #{rails_version} (with no new compatible versions):").white.bold %> +<%= Rainbow("These gems will need to be removed or replaced before upgrading to Rails #{rails_version}.").italic %> + +<% incompatible_gems_by_state[:incompatible].each do |gem| -%> +<%= gem_header(gem) %> - new version, <%= gem.latest_version.version %>, is not compatible with Rails #{rails_version} +<% end -%> + +<% end -%> +<% if incompatible_gems_by_state[:no_new_version] -%> +<%= Rainbow("=> Incompatible with Rails #{rails_version} (with no new versions):").white.bold %> +<%= Rainbow("These gems will need to be upgraded by us or removed before upgrading to Rails #{rails_version}.").italic %> +<%= Rainbow("This list is likely to contain internal gems, like Cuddlefish.").italic %> + +<% incompatible_gems_by_state[:no_new_version].each do |gem| -%> +<%= gem_header(gem) %> - new version not found +<% end -%> + +<% end -%> +<%= Rainbow(incompatible_gems.length.to_s).red %> gems incompatible with Rails <%= rails_version %> + ERB + + erb_version = ERB.version + if erb_version =~ /erb.rb \[([\d\.]+) .*\]/ + erb_version = $1 + end + + if Gem::Version.new(erb_version) < Gem::Version.new("2.2") + ERB.new(template, nil, "-").result(binding) + else + ERB.new(template, trim_mode: "-").result(binding) + end + end + + def gem_header(_gem) + header = Rainbow("#{_gem.name} #{_gem.version}").bold + header << Rainbow(" (loaded from git)").magenta if _gem.sourced_from_git? + header + end + + def incompatible_gems + @incompatible_gems ||= @gems.reject do |gem| + gem.compatible_with_rails?(rails_version: rails_version) || (!include_rails_gems && gem.from_rails?) + end.sort_by { |gem| gem.name } + end + + def rails_version + @options[:rails_version] + end + + def include_rails_gems + @options[:include_rails_gems] + end +end diff --git a/spec/next_rails/bundle_report/rails_version_compatibility_spec.rb b/spec/next_rails/bundle_report/rails_version_compatibility_spec.rb new file mode 100644 index 0000000..eda4ca4 --- /dev/null +++ b/spec/next_rails/bundle_report/rails_version_compatibility_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe NextRails::BundleReport::RailsVersionCompatibility do + describe "#generate" do + it "returns non incompatible gems" do + output = NextRails::BundleReport::RailsVersionCompatibility.new(options: { rails_version: 7.0 }).generate + expect(output).to match "gems incompatible with Rails 7.0" + end + + it "returns incompatible with compatible versions" do + next_rails_version = 7.1 + specification = Gem::Specification.new do |s| + s.name = "audited" + s.version = "5.1.0" + s.add_dependency "rails", ">= 5.0", "< 7.1" + end + audited = NextRails::GemInfo.new(specification) + gems = [audited] + + allow_any_instance_of(described_class).to receive(:incompatible_gems_by_state) + .and_return({ found_compatible: gems }) + + allow(audited).to receive(:latest_compatible_version).and_return(Gem::Version.new("5.8.0")) + + output = + NextRails::BundleReport::RailsVersionCompatibility.new( + gems: gems, + options: { rails_version: next_rails_version, include_rails_gems: false } + ).generate + + expect(output).to include("Incompatible with Rails 7.1 (with new versions that are compatible):") + expect(output).to include("These gems will need to be upgraded before upgrading to Rails 7.1.") + expect(output).to include("- upgrade to 5.8.0") + expect(output).to include("gems incompatible with Rails 7.1") + end + end +end + diff --git a/spec/next_rails/bundle_report/ruby_version_compatibility_spec.rb b/spec/next_rails/bundle_report/ruby_version_compatibility_spec.rb index ff416f3..be617c9 100644 --- a/spec/next_rails/bundle_report/ruby_version_compatibility_spec.rb +++ b/spec/next_rails/bundle_report/ruby_version_compatibility_spec.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "spec_helper" -require "next_rails/bundle_report/ruby_version_compatibility" RSpec.describe NextRails::BundleReport::RubyVersionCompatibility do let(:ruby_3_0_gem) do diff --git a/spec/next_rails/bundle_report_spec.rb b/spec/next_rails/bundle_report_spec.rb index e159a7a..6eeb17a 100644 --- a/spec/next_rails/bundle_report_spec.rb +++ b/spec/next_rails/bundle_report_spec.rb @@ -64,12 +64,21 @@ end end - describe ".compatibility" do - describe "output" do - it "returns ERB generated output" do - output = NextRails::BundleReport.erb_output({}, [], 7.0) - expect(output).to match "gems incompatible with Rails 7.0" + describe ".rails_compatibility" do + it "returns empty output invalid rails version" do + output = with_captured_stdout do + NextRails::BundleReport.rails_compatibility(rails_version: nil) end + expect(output).to be_empty + end + end + + describe ".ruby_compatibility" do + it "returns empty output invalid ruby version" do + output = with_captured_stdout do + NextRails::BundleReport.ruby_compatibility(ruby_version: nil) + end + expect(output).to be_empty end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 819479b..1c55882 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -48,3 +48,12 @@ def with_env(env_hash) stub_const("ENV", ENV.to_hash.merge!(env_hash)) end + +def with_captured_stdout + old_stdout = $stdout + $stdout = StringIO.new + yield + $stdout.string +ensure + $stdout = old_stdout +end