diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b51ce5..09a3023 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * Your changes/patches go here. +- [FEATURE: Support compatibility for Ruby versions](https://github.com/fastruby/next_rails/pull/116) - [CHORE: Remove GPL licensed dependency Colorize and replace it with Rainbow] # v1.3.0 / 2023-06-16 [(commits)](https://github.com/fastruby/next_rails/compare/v1.2.4...v1.3.0) diff --git a/README.md b/README.md index ebdd766..d6a4add 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,14 @@ bundle_report outdated --json # Show gems that don't work with Rails 5.2.0 bundle_report compatibility --rails-version=5.2.0 -# Show the usual help message -bundle_report --help +# Show gems that don't work with Ruby 3.0 +bundle_report compatibility --ruby-version=3.0 + # Find minimum compatible ruby version with Rails 7.0.0 bundle_report ruby_check --rails-version=7.0.0 + +# Show the usual help message +bundle_report --help ``` ### Application usage diff --git a/exe/bundle_report b/exe/bundle_report index 8408433..d8b92de 100755 --- a/exe/bundle_report +++ b/exe/bundle_report @@ -16,6 +16,7 @@ at_exit do Examples: #{$0} compatibility --rails-version 5.0 + #{$0} compatibility --ruby-version 3.3 #{$0} outdated #{$0} outdated --json @@ -33,6 +34,10 @@ at_exit do 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 @@ -61,7 +66,11 @@ at_exit do 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 - NextRails::BundleReport.compatibility(rails_version: options.fetch(:rails_version, "5.0"), include_rails_gems: options.fetch(:include_rails_gems, false)) + if options[:ruby_version] + NextRails::BundleReport.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)) + end end end diff --git a/lib/next_rails.rb b/lib/next_rails.rb index c25dc9f..7da5a14 100644 --- a/lib/next_rails.rb +++ b/lib/next_rails.rb @@ -3,6 +3,7 @@ require "next_rails/gem_info" require "next_rails/version" require "next_rails/bundle_report" +require "next_rails/bundle_report/ruby_version_compatibility" require "deprecation_tracker" module NextRails diff --git a/lib/next_rails/bundle_report.rb b/lib/next_rails/bundle_report.rb index 49070c4..d30812b 100644 --- a/lib/next_rails/bundle_report.rb +++ b/lib/next_rails/bundle_report.rb @@ -10,7 +10,9 @@ module NextRails module BundleReport extend self - def compatibility(rails_version: nil, include_rails_gems: nil) + 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 + 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 } diff --git a/lib/next_rails/bundle_report/ruby_version_compatibility.rb b/lib/next_rails/bundle_report/ruby_version_compatibility.rb new file mode 100644 index 0000000..7fa8f74 --- /dev/null +++ b/lib/next_rails/bundle_report/ruby_version_compatibility.rb @@ -0,0 +1,44 @@ +require "colorize" + +class NextRails::BundleReport::RubyVersionCompatibility + MINIMAL_VERSION = 1.0 + attr_reader :gems, :options + + def initialize(gems: NextRails::GemInfo.all, options: {}) + @gems = gems + @options = options + end + + def generate + return invalid_message unless valid? + + message + end + + private + + def message + output = "=> Incompatible gems with Ruby #{ruby_version}:".white.bold + incompatible.each do |gem| + output += "\n#{gem.name} - required Ruby version: #{gem.gem_specification.required_ruby_version}".magenta + end + output += "\n\n#{incompatible.length} incompatible #{incompatible.one? ? 'gem' : 'gems' } with Ruby #{ruby_version}".red + output + end + + def incompatible + gems.reject { |gem| gem.compatible_with_ruby?(ruby_version) } + end + + def ruby_version + options[:ruby_version].to_f + end + + def invalid_message + "=> Invalid Ruby version: #{options[:ruby_version]}.".red.bold + end + + def valid? + ruby_version > MINIMAL_VERSION + end +end diff --git a/lib/next_rails/gem_info.rb b/lib/next_rails/gem_info.rb index 1b1a210..d6060f9 100644 --- a/lib/next_rails/gem_info.rb +++ b/lib/next_rails/gem_info.rb @@ -147,5 +147,9 @@ def spec_compatible_with_rails?(specification: nil, rails_version: nil) rails_dependency.requirement.satisfied_by?(Gem::Version.new(rails_version)) end end + + def compatible_with_ruby?(ruby_version) + gem_specification.required_ruby_version.satisfied_by?(Gem::Version.new(ruby_version)) + 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 new file mode 100644 index 0000000..ff416f3 --- /dev/null +++ b/spec/next_rails/bundle_report/ruby_version_compatibility_spec.rb @@ -0,0 +1,86 @@ +# 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 + Gem::Specification.new do |s| + s.name = "ruby_3_0_gem" + s.version = "1.0.0" + s.required_ruby_version = ">= 3.0" + end + end + + let(:ruby_2_5_gem) do + Gem::Specification.new do |s| + s.name = "ruby_2_5_gem" + s.version = "1.0.0" + s.required_ruby_version = ">= 2.5" + end + end + + let(:ruby_2_3_to_2_5_gem) do + Gem::Specification.new do |s| + s.name = "ruby_2_3_to_2_5_gem" + s.version = "1.0.0" + s.required_ruby_version = [">= 2.3", "< 2.5"] + end + end + + let(:no_ruby_version_gem) do + Gem::Specification.new do |s| + s.name = "no_ruby_version_gem" + s.version = "1.0.0" + end + end + + describe "#generate" do + context "with invalid ruby version" do + it "returns invalid message" do + options = { ruby_version: "hola" } + + result = described_class.new(gems: [], options: options).generate + expect(result).to include "Invalid Ruby version: hola" + end + end + + context "with valid ruby version" do + it "returns 0 incompatible gems" do + options = { ruby_version: "3.0" } + gems = [NextRails::GemInfo.new(ruby_3_0_gem)] + + result = described_class.new(gems: gems, options: options).generate + expect(result).to include "0 incompatible gems with Ruby 3.0" + end + + it "returns 1 incompatible gem" do + options = { ruby_version: "2.5" } + gems = [NextRails::GemInfo.new(ruby_3_0_gem)] + + result = described_class.new(gems: gems, options: options).generate + + expect(result).to include "Incompatible gems with Ruby 2.5" + expect(result).to include "ruby_3_0_gem - required Ruby version: >= 3.0" + expect(result).to include "1 incompatible gem with Ruby 2.5" + end + + it "returns 2 incompatible gems" do + options = { ruby_version: "2.7" } + gems = [ + NextRails::GemInfo.new(ruby_3_0_gem), + NextRails::GemInfo.new(ruby_2_5_gem), + NextRails::GemInfo.new(ruby_2_3_to_2_5_gem), + NextRails::GemInfo.new(no_ruby_version_gem) + ] + + result = described_class.new(gems: gems, options: options).generate + + expect(result).to include "Incompatible gems with Ruby 2.7" + expect(result).to include "ruby_3_0_gem - required Ruby version: >= 3.0" + expect(result).to include "ruby_2_3_to_2_5_gem - required Ruby version:" # >= 2.3, < 2.5" + expect(result).to include "2 incompatible gems with Ruby 2.7" + end + end + end +end