Skip to content

Commit

Permalink
Move bundle_report rails compatibility logic into a class
Browse files Browse the repository at this point in the history
I extracted it into a class because I think it will be easier to use the `incompatible_gems_by_state` data there.

Based on the code review
  • Loading branch information
JuanVqz committed Mar 3, 2025
1 parent aca1c12 commit d7e4eb5
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 68 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

# v1.4.3 / 2025-02-20 [(commits)](https://github.com/fastruby/next_rails/compare/v1.4.2...v1.4.3)

- [Move rails_version compatibility to its own class](https://github.com/fastruby/next_rails/pull/137)
- [Add next_rails --init](https://github.com/fastruby/next_rails/pull/139)
- [Add Ruby 3.4 support](https://github.com/fastruby/next_rails/pull/133)

Expand Down
4 changes: 2 additions & 2 deletions exe/bundle_report
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions lib/next_rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
67 changes: 8 additions & 59 deletions lib/next_rails/bundle_report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
84 changes: 84 additions & 0 deletions lib/next_rails/bundle_report/rails_version_compatibility.rb
Original file line number Diff line number Diff line change
@@ -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

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_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

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
38 changes: 38 additions & 0 deletions spec/next_rails/bundle_report/rails_version_compatibility_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# 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 audited incompatible gem" do
next_rails_version = 7.1
audited = Gem::Specification.new do |s|
s.name = "audited"
s.version = "4.2.1"
s.add_dependency "rails", ">= 6.2", "< 7.0"
end
gems = [NextRails::GemInfo.new(audited)]

allow_any_instance_of(NextRails::GemInfo).to receive(:find_latest_compatible)
.with(rails_version: next_rails_version)
.and_return(Gem::Specification.new(name: "audited", version: "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 "These gems will need to be removed or replaced before upgrading to Rails #{next_rails_version}"
expect(output).to include "audited 4.2.1"
expect(output).to include "new version, 5.8.0, is not compatible with Rails #{next_rails_version}"
expect(output).to include "gems incompatible with Rails #{next_rails_version}"
end
end
end

Original file line number Diff line number Diff line change
@@ -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
Expand Down
17 changes: 11 additions & 6 deletions spec/next_rails/bundle_report_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,17 @@
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"
end
describe ".rails_compatibility" do
it "returns nil for invalid rails version" do
output = NextRails::BundleReport.rails_compatibility(rails_version: nil)
expect(output).to eq(nil)
end
end

describe ".ruby_compatibility" do
it "returns nil for invalid ruby version" do
output = NextRails::BundleReport.ruby_compatibility(ruby_version: nil)
expect(output).to eq(nil)
end
end

Expand Down

0 comments on commit d7e4eb5

Please sign in to comment.