class Dependabot::Bundler::UpdateChecker::FilePreparer

This class takes a set of dependency files and sanitizes them for use in UpdateCheckers::Ruby::Bundler. In particular, it:

Constants

VERSION_REGEX

Attributes

dependency[R]

rubocop:enable Metrics/AbcSize rubocop:enable Metrics/MethodLength

dependency_files[R]

rubocop:enable Metrics/AbcSize rubocop:enable Metrics/MethodLength

latest_allowable_version[R]

rubocop:enable Metrics/AbcSize rubocop:enable Metrics/MethodLength

replacement_git_pin[R]

rubocop:enable Metrics/AbcSize rubocop:enable Metrics/MethodLength

Public Class Methods

new(dependency_files:, dependency:, remove_git_source: false, unlock_requirement: true, replacement_git_pin: nil, latest_allowable_version: nil, lock_ruby_version: true) click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 38
def initialize(dependency_files:, dependency:,
               remove_git_source: false,
               unlock_requirement: true,
               replacement_git_pin: nil,
               latest_allowable_version: nil,
               lock_ruby_version: true)
  @dependency_files         = dependency_files
  @dependency               = dependency
  @remove_git_source        = remove_git_source
  @unlock_requirement       = unlock_requirement
  @replacement_git_pin      = replacement_git_pin
  @latest_allowable_version = latest_allowable_version
  @lock_ruby_version        = lock_ruby_version
end

Public Instance Methods

gemspec_sources() click to toggle source

Can't be a constant because some of these don't exist in bundler 1.15, which Heroku uses, which causes an exception on boot.

# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 31
def gemspec_sources
  [
    ::Bundler::Source::Path,
    ::Bundler::Source::Gemspec
  ]
end
prepared_dependency_files() click to toggle source

rubocop:disable Metrics/AbcSize rubocop:disable Metrics/MethodLength

# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 55
def prepared_dependency_files
  files = []

  if gemfile
    files << DependencyFile.new(
      name: gemfile.name,
      content: gemfile_content_for_update_check(gemfile),
      directory: gemfile.directory
    )
  end

  top_level_gemspecs.each do |gemspec|
    files << DependencyFile.new(
      name: gemspec.name,
      content: gemspec_content_for_update_check(gemspec),
      directory: gemspec.directory
    )
  end

  path_gemspecs.each do |file|
    files << DependencyFile.new(
      name: file.name,
      content: sanitize_gemspec_content(file.content),
      directory: file.directory,
      support_file: file.support_file?
    )
  end

  evaled_gemfiles.each do |file|
    files << DependencyFile.new(
      name: file.name,
      content: gemfile_content_for_update_check(file),
      directory: file.directory
    )
  end

  # No editing required for lockfile or Ruby version file
  files += [
    lockfile,
    ruby_version_file,
    *imported_ruby_files,
    *specification_files
  ].compact
end

Private Instance Methods

evaled_gemfiles() click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 124
def evaled_gemfiles
  dependency_files.
    reject { |f| f.name.end_with?(".gemspec") }.
    reject { |f| f.name.end_with?(".specification") }.
    reject { |f| f.name.end_with?(".lock") }.
    reject { |f| f.name.end_with?(".ruby-version") }.
    reject { |f| f.name == "Gemfile" }.
    reject { |f| f.name == "gems.rb" }.
    reject { |f| f.name == "gems.locked" }
end
gemfile() click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 119
def gemfile
  dependency_files.find { |f| f.name == "Gemfile" } ||
    dependency_files.find { |f| f.name == "gems.rb" }
end
gemfile_content_for_update_check(file) click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 165
def gemfile_content_for_update_check(file)
  content = file.content
  content = replace_gemfile_constraint(content, file.name)
  content = remove_git_source(content) if remove_git_source?
  content = replace_git_pin(content) if replace_git_pin?
  content = lock_ruby_version(content) if lock_ruby_version?(file)
  content
end
gemspec_content_for_update_check(gemspec) click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 174
def gemspec_content_for_update_check(gemspec)
  content = gemspec.content
  content = replace_gemspec_constraint(content, gemspec.name)
  sanitize_gemspec_content(content)
end
imported_ruby_files() click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 159
def imported_ruby_files
  dependency_files.
    select { |f| f.name.end_with?(".rb") }.
    reject { |f| f.name == "gems.rb" }
end
lock_ruby_version(gemfile_content) click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 251
def lock_ruby_version(gemfile_content)
  top_level_gemspecs.each do |gs|
    gemfile_content = FileUpdater::RubyRequirementSetter.
                      new(gemspec: gs).rewrite(gemfile_content)
  end

  gemfile_content
end
lock_ruby_version?(file) click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 260
def lock_ruby_version?(file)
  @lock_ruby_version && file == gemfile
end
lockfile() click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 135
def lockfile
  dependency_files.find { |f| f.name == "Gemfile.lock" } ||
    dependency_files.find { |f| f.name == "gems.locked" }
end
path_gemspecs() click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 154
def path_gemspecs
  all = dependency_files.select { |f| f.name.end_with?(".gemspec") }
  all - top_level_gemspecs
end
remove_git_source(content) click to toggle source

rubocop:enable Metrics/PerceivedComplexity

# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 238
def remove_git_source(content)
  FileUpdater::GitSourceRemover.new(
    dependency: dependency
  ).rewrite(content)
end
remove_git_source?() click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 107
def remove_git_source?
  @remove_git_source
end
replace_gemfile_constraint(content, filename) click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 180
def replace_gemfile_constraint(content, filename)
  FileUpdater::RequirementReplacer.new(
    dependency: dependency,
    file_type: :gemfile,
    updated_requirement: updated_version_requirement_string(filename),
    insert_if_bare: true
  ).rewrite(content)
end
replace_gemspec_constraint(content, filename) click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 189
def replace_gemspec_constraint(content, filename)
  FileUpdater::RequirementReplacer.new(
    dependency: dependency,
    file_type: :gemspec,
    updated_requirement: updated_version_requirement_string(filename),
    insert_if_bare: true
  ).rewrite(content)
end
replace_git_pin(content) click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 244
def replace_git_pin(content)
  FileUpdater::GitPinReplacer.new(
    dependency: dependency,
    new_pin: replacement_git_pin
  ).rewrite(content)
end
replace_git_pin?() click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 115
def replace_git_pin?
  !replacement_git_pin.nil?
end
replacement_version_for_gemspec(gemspec_content) click to toggle source

rubocop:disable Metrics/PerceivedComplexity

# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 265
def replacement_version_for_gemspec(gemspec_content)
  return "0.0.1" unless lockfile

  gemspec_specs =
    ::Bundler::LockfileParser.new(sanitized_lockfile_content).specs.
    select { |s| gemspec_sources.include?(s.source.class) }

  gem_name =
    FileUpdater::GemspecDependencyNameFinder.
    new(gemspec_content: gemspec_content).
    dependency_name

  return gemspec_specs.first&.version || "0.0.1" unless gem_name

  spec = gemspec_specs.find { |s| s.name == gem_name }
  spec&.version || gemspec_specs.first&.version || "0.0.1"
end
ruby_version_file() click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 150
def ruby_version_file
  dependency_files.find { |f| f.name == ".ruby-version" }
end
sanitize_gemspec_content(gemspec_content) click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 198
def sanitize_gemspec_content(gemspec_content)
  new_version = replacement_version_for_gemspec(gemspec_content)

  FileUpdater::GemspecSanitizer.
    new(replacement_version: new_version).
    rewrite(gemspec_content)
end
sanitized_lockfile_content() click to toggle source

TODO: Stop sanitizing the lockfile once we have bundler 2 installed

# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 285
def sanitized_lockfile_content
  re = FileUpdater::LockfileUpdater::LOCKFILE_ENDING
  lockfile.content.gsub(re, "")
end
specification_files() click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 140
def specification_files
  dependency_files.select { |f| f.name.end_with?(".specification") }
end
top_level_gemspecs() click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 144
def top_level_gemspecs
  dependency_files.
    select { |f| f.name.end_with?(".gemspec") }.
    reject(&:support_file?)
end
unlock_requirement?() click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 111
def unlock_requirement?
  @unlock_requirement
end
updated_version_req_lower_bound(filename) click to toggle source

rubocop:disable Metrics/PerceivedComplexity

# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 216
def updated_version_req_lower_bound(filename)
  original_req = dependency.requirements.
                 find { |r| r.fetch(:file) == filename }&.
                 fetch(:requirement)

  if original_req && !unlock_requirement? then original_req
  elsif dependency.version&.match?(/^[0-9a-f]{40}$/) then ">= 0"
  elsif dependency.version then ">= #{dependency.version}"
  else
    version_for_requirement =
      dependency.requirements.map { |r| r[:requirement] }.
      reject { |req_string| req_string.start_with?("<") }.
      select { |req_string| req_string.match?(VERSION_REGEX) }.
      map { |req_string| req_string.match(VERSION_REGEX) }.
      select { |version| Gem::Version.correct?(version) }.
      max_by { |version| Gem::Version.new(version) }

    ">= #{version_for_requirement || 0}"
  end
end
updated_version_requirement_string(filename) click to toggle source
# File lib/dependabot/bundler/update_checker/file_preparer.rb, line 206
def updated_version_requirement_string(filename)
  lower_bound_req = updated_version_req_lower_bound(filename)

  return lower_bound_req if latest_allowable_version.nil?
  return lower_bound_req unless Gem::Version.correct?(latest_allowable_version)

  lower_bound_req + ", <= #{latest_allowable_version}"
end