class Dependabot::Bundler::UpdateChecker::RequirementsUpdater
Constants
- ALLOWED_UPDATE_STRATEGIES
Attributes
latest_resolvable_version[R]
latest_version[R]
requirements[R]
update_strategy[R]
updated_source[R]
Public Class Methods
new(requirements:, update_strategy:, updated_source:, latest_version:, latest_resolvable_version:)
click to toggle source
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 14 def initialize(requirements:, update_strategy:, updated_source:, latest_version:, latest_resolvable_version:) @requirements = requirements @latest_version = Gem::Version.new(latest_version) if latest_version @updated_source = updated_source @update_strategy = update_strategy check_update_strategy return unless latest_resolvable_version @latest_resolvable_version = Gem::Version.new(latest_resolvable_version) end
Public Instance Methods
updated_requirements()
click to toggle source
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 29 def updated_requirements requirements.map do |req| if req[:file].match?(/\.gemspec/) update_gemspec_requirement(req) else # If a requirement doesn't come from a gemspec, it must be from # a Gemfile. update_gemfile_requirement(req) end end end
Private Instance Methods
at_same_precision(new_version, old_version)
click to toggle source
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 112 def at_same_precision(new_version, old_version) release_precision = old_version.to_s.split("."). take_while { |i| i.match?(/^\d+$/) }.count prerelease_precision = old_version.to_s.split(".").count - release_precision new_release = new_version.to_s.split(".").first(release_precision) new_prerelease = new_version.to_s.split("."). drop_while { |i| i.match?(/^\d+$/) }. first([prerelease_precision, 1].max) [*new_release, *new_prerelease].join(".") end
binding_requirements(requirements)
click to toggle source
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 164 def binding_requirements(requirements) grouped_by_operator = requirements.group_by { |r| r.requirements.first.first } binding_reqs = grouped_by_operator.flat_map do |operator, reqs| case operator when "<", "<=" then reqs.min_by { |r| r.requirements.first.last } when ">", ">=" then reqs.max_by { |r| r.requirements.first.last } else requirements end end.uniq binding_reqs << Gem::Requirement.new if binding_reqs.empty? binding_reqs.sort_by { |r| r.requirements.first.last } end
bumped_requirements(req)
click to toggle source
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 198 def bumped_requirements(req) op, version = req.requirements.first case op when "=", nil if version < latest_resolvable_version [Gem::Requirement.new("#{op} #{latest_resolvable_version}")] else req end when "~>" [update_twiddle_version(req, latest_resolvable_version)] when "<", "<=" then [update_greatest_version(req, latest_version)] when "!=" then [] when ">", ">=" then raise UnfixableRequirement else raise "Unexpected operation for requirement: #{op}" end end
check_update_strategy()
click to toggle source
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 47 def check_update_strategy return if ALLOWED_UPDATE_STRATEGIES.include?(update_strategy) raise "Unknown update strategy: #{update_strategy}" end
convert_twiddle_to_range(requirement, version_to_be_permitted)
click to toggle source
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 217 def convert_twiddle_to_range(requirement, version_to_be_permitted) version = requirement.requirements.first.last version = version.release if version.prerelease? index_to_update = [version.segments.count - 2, 0].max ub_segments = version_to_be_permitted.segments ub_segments << 0 while ub_segments.count <= index_to_update ub_segments = ub_segments[0..index_to_update] ub_segments[index_to_update] += 1 lb_segments = version.segments lb_segments.pop while lb_segments.any? && lb_segments.last.zero? return [Gem::Requirement.new("< #{ub_segments.join('.')}")] if lb_segments.none? # Ensure versions have the same length as each other (cosmetic) length = [lb_segments.count, ub_segments.count].max lb_segments.fill(0, lb_segments.count...length) ub_segments.fill(0, ub_segments.count...length) [ Gem::Requirement.new(">= #{lb_segments.join('.')}"), Gem::Requirement.new("< #{ub_segments.join('.')}") ] end
new_version_satisfies?(req)
click to toggle source
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 88 def new_version_satisfies?(req) original_req = Gem::Requirement.new(req[:requirement].split(",")) original_req.satisfied_by?(latest_resolvable_version) end
requirement_satisfied?(req, groups)
click to toggle source
rubocop:enable Metrics/PerceivedComplexity
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 156 def requirement_satisfied?(req, groups) if groups == ["development"] req.satisfied_by?(latest_resolvable_version) else req.satisfied_by?(latest_version) end end
update_gemfile_range(requirements)
click to toggle source
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 93 def update_gemfile_range(requirements) updated_requirements = requirements.flat_map do |r| next r if r.satisfied_by?(latest_resolvable_version) case op = r.requirements.first.first when "<", "<=" [update_greatest_version(r, latest_resolvable_version)] when "!=" [] else raise "Unexpected operation for unsatisfied Gemfile "\ "requirement: #{op}" end end binding_requirements(updated_requirements) end
update_gemfile_requirement(req)
click to toggle source
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 53 def update_gemfile_requirement(req) req = req.merge(source: updated_source) return req unless latest_resolvable_version case update_strategy when :bump_versions update_version_requirement(req) when :bump_versions_if_necessary update_version_requirement_if_needed(req) else raise "Unexpected update strategy: #{update_strategy}" end end
update_gemspec_requirement(req)
click to toggle source
rubocop:disable Metrics/PerceivedComplexity
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 129 def update_gemspec_requirement(req) req = req.merge(source: updated_source) if req.fetch(:source) return req unless latest_version && latest_resolvable_version requirements = req[:requirement].split(",").map { |r| Gem::Requirement.new(r) } return req if requirements.all? do |r| requirement_satisfied?(r, req[:groups]) end updated_requirements = requirements.flat_map do |r| next r if requirement_satisfied?(r, req[:groups]) if req[:groups] == ["development"] then bumped_requirements(r) else widened_requirements(r) end end updated_requirements = binding_requirements(updated_requirements) req.merge(requirement: updated_requirements.map(&:to_s).join(", ")) rescue UnfixableRequirement req.merge(requirement: :unfixable) end
update_greatest_version(requirement, version_to_be_permitted)
click to toggle source
Updates the version in a “<” or “<=” constraint to allow the given version
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 253 def update_greatest_version(requirement, version_to_be_permitted) version_to_be_permitted = Gem::Version.new(version_to_be_permitted) if version_to_be_permitted.is_a?(String) op, version = requirement.requirements.first version = version.release if version.prerelease? index_to_update = [ version.segments.map.with_index { |seg, i| seg.zero? ? 0 : i }.max, version_to_be_permitted.segments.count - 1 ].min new_segments = version.segments.map.with_index do |_, index| if index < index_to_update version_to_be_permitted.segments[index] elsif index == index_to_update version_to_be_permitted.segments[index] + 1 elsif index > version_to_be_permitted.segments.count - 1 nil else 0 end end.compact Gem::Requirement.new("#{op} #{new_segments.join('.')}") end
update_twiddle_version(requirement, version_to_be_permitted)
click to toggle source
Updates the version in a “~>” constraint to allow the given version
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 245 def update_twiddle_version(requirement, version_to_be_permitted) old_version = requirement.requirements.first.last updated_v = at_same_precision(version_to_be_permitted, old_version) Gem::Requirement.new("~> #{updated_v}") end
update_version_requirement(req)
click to toggle source
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 72 def update_version_requirement(req) requirements = req[:requirement].split(",").map { |r| Gem::Requirement.new(r) } new_requirement = if requirements.any?(&:exact?) then latest_resolvable_version.to_s elsif requirements.any? { |r| r.to_s.start_with?("~>") } tw_req = requirements.find { |r| r.to_s.start_with?("~>") } update_twiddle_version(tw_req, latest_resolvable_version).to_s else update_gemfile_range(requirements).map(&:to_s).join(", ") end req.merge(requirement: new_requirement) end
update_version_requirement_if_needed(req)
click to toggle source
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 66 def update_version_requirement_if_needed(req) return req if new_version_satisfies?(req) update_version_requirement(req) end
widened_requirements(req)
click to toggle source
# File lib/dependabot/bundler/update_checker/requirements_updater.rb, line 180 def widened_requirements(req) op, version = req.requirements.first case op when "=", nil if version < latest_resolvable_version [Gem::Requirement.new("#{op} #{latest_resolvable_version}")] else req end when "<", "<=" then [update_greatest_version(req, latest_version)] when "~>" then convert_twiddle_to_range(req, latest_version) when "!=" then [] when ">", ">=" then raise UnfixableRequirement else raise "Unexpected operation for requirement: #{op}" end end