Skip to content

Commit

Permalink
Merge pull request #49 from fastruby/feature/find-latest-compatible-v…
Browse files Browse the repository at this point in the history
…ersion

Find latest compatible version when checking compatibility
  • Loading branch information
bronzdoc authored May 26, 2022
2 parents 2137aed + 3aa910a commit a5373a8
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 45 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# main [(unreleased)](https://github.com/fastruby/next_rails/compare/v1.0.4...main)

* [FEATURE: Try to find the latest **compatible** version of a gem if the latest version is not compatible with the desired Rails version when checking compatibility](https://github.com/fastruby/next_rails/pull/49)

# v1.0.5 / 2022-03-29 [(commits)](https://github.com/fastruby/next_rails/compare/v1.0.4...v1.0.5)

* [FEATURE: Initialize the Gemfile.next.lock to avoid major version jumps when used without an initial Gemfile.next.lock](https://github.com/fastruby/next_rails/pull/25)
Expand All @@ -14,6 +16,7 @@

* [BUGFIX: Update README.md to better document this `ten_years_rails` fork](https://github.com/fastruby/next_rails/pull/11)
* [BUGFIX: Make ActionView an optional dependency](https://github.com/fastruby/next_rails/pull/6)

# v1.0.2 / 2020-01-20

# v1.0.1 / 2019-07-26
Expand Down
15 changes: 6 additions & 9 deletions lib/next_rails/bundle_report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,19 @@ class BundleReport
def self.compatibility(rails_version:, include_rails_gems:)
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 do |gem|
[
gem.latest_version.compatible_with_rails?(rails_version: rails_version) ? 0 : 1,
gem.name
].join("-")
end
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) }

template = <<~ERB
<% if incompatible_gems_by_state[:latest_compatible] -%>
<% if incompatible_gems_by_state[:found_compatible] -%>
<%= "=> Incompatible with Rails #{rails_version} (with new versions that are compatible):".white.bold %>
<%= "These gems will need to be upgraded before upgrading to Rails #{rails_version}.".italic %>
<% incompatible_gems_by_state[:latest_compatible].each do |gem| -%>
<%= gem_header(gem) %> - upgrade to <%= gem.latest_version.version %>
<% incompatible_gems_by_state[:found_compatible].each do |gem| -%>
<%= gem_header(gem) %> - upgrade to <%= gem.latest_compatible_version.version %>
<% end -%>
<% end -%>
Expand Down
97 changes: 61 additions & 36 deletions lib/next_rails/gem_info.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,28 @@ def state(_)
end
end

RAILS_GEMS = [
"rails",
"activemodel",
"activerecord",
"actionmailer",
"actioncable",
"actionpack",
"actionview",
"activejob",
"activestorage",
"activesupport",
"railties",
].freeze

def self.all
Gem::Specification.each.map do |gem_specification|
new(gem_specification)
end
end

attr_reader :gem_specification, :version, :name
attr_reader :gem_specification, :version, :name, :latest_compatible_version

def initialize(gem_specification)
@gem_specification = gem_specification
@version = gem_specification.version
Expand All @@ -57,59 +72,69 @@ def up_to_date?
version == latest_version.version
end

def from_rails?
RAILS_GEMS.include?(name)
end

def state(rails_version)
if compatible_with_rails?(rails_version: rails_version)
:compatible
elsif latest_version.compatible_with_rails?(rails_version: rails_version)
:latest_compatible
elsif latest_version.version == "NOT FOUND"
elsif latest_compatible_version.version == "NOT FOUND"
:no_new_version
elsif latest_compatible_version
:found_compatible
else
:incompatible
end
end

def latest_version
@latest_version ||= begin
latest_gem_specification = Gem.latest_spec_for(name)
if latest_gem_specification
GemInfo.new(latest_gem_specification)
else
NullGemInfo.new
end
end
end

def compatible_with_rails?(rails_version: Gem::Version.new("5.0"))
def compatible_with_rails?(rails_version:)
unsatisfied_rails_dependencies(rails_version: rails_version).empty?
end

def unsatisfied_rails_dependencies(rails_version:)
rails_dependencies = gem_specification.runtime_dependencies.select {|dependency| rails_gems.include?(dependency.name) }
spec_compatible_with_rails?(specification: gem_specification, rails_version: rails_version)
end

rails_dependencies.reject do |rails_dependency|
rails_dependency.requirement.satisfied_by?(Gem::Version.new(rails_version))
def find_latest_compatible(rails_version:)
dependency = Gem::Dependency.new(@name)
fetcher = Gem::SpecFetcher.new

# list all available data for released gems
list, errors = fetcher.available_specs(:released)

specs = []
# filter only specs for the current gem and older versions
list.each do |source, gem_tuples|
gem_tuples.each do |gem_tuple|
if gem_tuple.name == @name && gem_tuple.version > @version
specs << source.fetch_spec(gem_tuple)
end
end
end
end

def from_rails?
rails_gems.include?(name)
# if nothing is found, consider gem incompatible
if specs.empty?
@latest_compatible_version = NullGemInfo.new
return
end

# if specs are found, look for the first one from that is compatible
# with the desired rails version starting from the end
specs.reverse.each do |spec|
if spec_compatible_with_rails?(specification: spec, rails_version: rails_version).empty?
@latest_compatible_version = spec
break
end
end
end

private def rails_gems
[
"rails",
"activemodel",
"activerecord",
"actionmailer",
"actioncable",
"actionpack",
"actionview",
"activejob",
"activestorage",
"activesupport",
"railties",
]
def spec_compatible_with_rails?(specification:, rails_version:)
rails_dependencies = specification.runtime_dependencies.select {|dependency| RAILS_GEMS.include?(dependency.name) }

rails_dependencies.reject do |rails_dependency|
rails_dependency.requirement.satisfied_by?(Gem::Version.new(rails_version))
end
end
end
end

0 comments on commit a5373a8

Please sign in to comment.