class Dependabot::Gradle::FileUpdater

Constants

SUPPORTED_BUILD_FILE_NAMES

Public Class Methods

updated_files_regex() click to toggle source
# File lib/dependabot/gradle/file_updater.rb, line 15
def self.updated_files_regex
  [/^build\.gradle(\.kts)?$/, %r{/build\.gradle(\.kts)?$}]
end

Public Instance Methods

updated_dependency_files() click to toggle source
# File lib/dependabot/gradle/file_updater.rb, line 19
def updated_dependency_files
  updated_files = buildfiles.dup

  # Loop through each of the changed requirements, applying changes to
  # all buildfiles for that change. Note that the logic is different
  # here to other languages because Java has property inheritance across
  # files (although we're not supporting it for gradle yet).
  dependencies.each do |dependency|
    updated_files = update_buildfiles_for_dependency(
      buildfiles: updated_files,
      dependency: dependency
    )
  end

  updated_files = updated_files.reject { |f| buildfiles.include?(f) }

  raise "No files changed!" if updated_files.none?

  updated_files
end

Private Instance Methods

buildfiles() click to toggle source
# File lib/dependabot/gradle/file_updater.rb, line 183
def buildfiles
  @buildfiles ||= dependency_files.reject(&:support_file?)
end
check_required_files() click to toggle source
# File lib/dependabot/gradle/file_updater.rb, line 42
def check_required_files
  raise "No build.gradle or build.gradle.kts!" unless original_file
end
evaluate_properties(string, buildfile) click to toggle source
# File lib/dependabot/gradle/file_updater.rb, line 151
def evaluate_properties(string, buildfile)
  result = string.dup

  string.scan(Gradle::FileParser::PROPERTY_REGEX) do
    prop_name = Regexp.last_match.named_captures.fetch("property_name")
    property_value = property_value_finder.property_value(
      property_name: prop_name,
      callsite_buildfile: buildfile
    )
    next unless property_value

    result.sub!(Regexp.last_match.to_s, property_value)
  end

  result
end
original_buildfile_declaration(dependency, requirement) click to toggle source
# File lib/dependabot/gradle/file_updater.rb, line 130
def original_buildfile_declaration(dependency, requirement)
  # This implementation is limited to declarations that appear on a
  # single line.
  buildfile = buildfiles.find { |f| f.name == requirement.fetch(:file) }
  buildfile.content.lines.find do |line|
    line = evaluate_properties(line, buildfile)
    line = line.gsub(%r{(?<=^|\s)//.*$}, "")

    if dependency.name.include?(":")
      next false unless line.include?(dependency.name.split(":").first)
      next false unless line.include?(dependency.name.split(":").last)
    else
      name_regex_value = /['"]#{Regexp.quote(dependency.name)}['"]/
      name_regex = /(id|kotlin)(\s+#{name_regex_value}|\(#{name_regex_value}\))/
      next false unless line.match?(name_regex)
    end

    line.include?(requirement.fetch(:requirement))
  end
end
original_file() click to toggle source
# File lib/dependabot/gradle/file_updater.rb, line 46
def original_file
  dependency_files.find do |f|
    SUPPORTED_BUILD_FILE_NAMES.include?(f.name)
  end
end
property_value_finder() click to toggle source
# File lib/dependabot/gradle/file_updater.rb, line 168
def property_value_finder
  @property_value_finder ||=
    Gradle::FileParser::PropertyValueFinder.
    new(dependency_files: dependency_files)
end
update_buildfiles_for_dependency(buildfiles:, dependency:) click to toggle source
# File lib/dependabot/gradle/file_updater.rb, line 52
def update_buildfiles_for_dependency(buildfiles:, dependency:)
  files = buildfiles.dup

  # The UpdateChecker ensures the order of requirements is preserved
  # when updating, so we can zip them together in new/old pairs.
  reqs = dependency.requirements.zip(dependency.previous_requirements).
         reject { |new_req, old_req| new_req == old_req }

  # Loop through each changed requirement and update the buildfiles
  reqs.each do |new_req, old_req|
    raise "Bad req match" unless new_req[:file] == old_req[:file]
    next if new_req[:requirement] == old_req[:requirement]

    buildfile = files.find { |f| f.name == new_req.fetch(:file) }

    if new_req.dig(:metadata, :property_name)
      files = update_files_for_property_change(files, old_req, new_req)
    elsif new_req.dig(:metadata, :dependency_set)
      files = update_files_for_dep_set_change(files, old_req, new_req)
    else
      files[files.index(buildfile)] =
        update_version_in_buildfile(
          dependency,
          buildfile,
          old_req,
          new_req
        )
    end
  end

  files
end
update_files_for_dep_set_change(buildfiles, old_req, new_req) click to toggle source
# File lib/dependabot/gradle/file_updater.rb, line 99
def update_files_for_dep_set_change(buildfiles, old_req, new_req)
  files = buildfiles.dup
  dependency_set = new_req.fetch(:metadata).fetch(:dependency_set)
  buildfile = files.find { |f| f.name == new_req.fetch(:file) }

  DependencySetUpdater.new(dependency_files: files).
    update_files_for_dep_set_change(
      dependency_set: dependency_set,
      buildfile: buildfile,
      previous_requirement: old_req.fetch(:requirement),
      updated_requirement: new_req.fetch(:requirement)
    )
end
update_files_for_property_change(buildfiles, old_req, new_req) click to toggle source
# File lib/dependabot/gradle/file_updater.rb, line 85
def update_files_for_property_change(buildfiles, old_req, new_req)
  files = buildfiles.dup
  property_name = new_req.fetch(:metadata).fetch(:property_name)
  buildfile = files.find { |f| f.name == new_req.fetch(:file) }

  PropertyValueUpdater.new(dependency_files: files).
    update_files_for_property_change(
      property_name: property_name,
      callsite_buildfile: buildfile,
      previous_value: old_req.fetch(:requirement),
      updated_value: new_req.fetch(:requirement)
    )
end
update_version_in_buildfile(dependency, buildfile, previous_req, requirement) click to toggle source
# File lib/dependabot/gradle/file_updater.rb, line 113
def update_version_in_buildfile(dependency, buildfile, previous_req,
                                requirement)
  updated_content =
    buildfile.content.gsub(
      original_buildfile_declaration(dependency, previous_req),
      updated_buildfile_declaration(
        dependency,
        previous_req,
        requirement
      )
    )

  raise "Expected content to change!" if updated_content == buildfile.content

  updated_file(file: buildfile, content: updated_content)
end
updated_buildfile_declaration(dependency, previous_req, requirement) click to toggle source
# File lib/dependabot/gradle/file_updater.rb, line 174
def updated_buildfile_declaration(dependency, previous_req, requirement)
  original_req_string = previous_req.fetch(:requirement)

  original_buildfile_declaration(dependency, previous_req).gsub(
    original_req_string,
    requirement.fetch(:requirement)
  )
end