Skip to content

Commit

Permalink
Dep: Move manifest updating logic into separate class
Browse files Browse the repository at this point in the history
  • Loading branch information
greysteil committed Jul 25, 2018
1 parent f46c1c2 commit d41cc69
Show file tree
Hide file tree
Showing 4 changed files with 358 additions and 277 deletions.
123 changes: 6 additions & 117 deletions lib/dependabot/file_updaters/go/dep.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ module Dependabot
module FileUpdaters
module Go
class Dep < Dependabot::FileUpdaters::Base
require_relative "dep/manifest_updater"

def self.updated_files_regex
[
/^Gopkg\.toml$/,
Expand Down Expand Up @@ -50,130 +52,17 @@ def lockfile
end

def updated_manifest_content
dependencies.
select { |dep| requirement_changed?(manifest, dep) }.
reduce(manifest.content.dup) do |content, dep|
updated_content = content
updated_content = update_requirements(
content: updated_content,
filename: manifest.name,
dependency: dep
)
updated_content = update_git_pin(
content: updated_content,
filename: manifest.name,
dependency: dep
)

raise "Expected content to change!" if content == updated_content
updated_content
end
ManifestUpdater.new(
dependencies: dependencies,
manifest: manifest
).updated_manifest_content
end

def updated_lockfile_content
# TODO: This normally needs to be written in the native language.
# We do so by shelling out to a helper method (see other languages)
lockfile.content
end

def update_requirements(content:, filename:, dependency:)
updated_content = content.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
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]
next unless new_req[:file] == filename

updated_content = update_manifest_req(
content: updated_content,
dep: dependency,
old_req: old_req.fetch(:requirement),
new_req: new_req.fetch(:requirement)
)
end

updated_content
end

def update_git_pin(content:, filename:, dependency:)
updated_pin =
dependency.requirements.
find { |r| r[:file] == filename }&.
dig(:source, :ref)

old_pin =
dependency.previous_requirements.
find { |r| r[:file] == filename }&.
dig(:source, :ref)

return content unless old_pin

update_manifest_pin(
content: content,
dep: dependency,
old_pin: old_pin,
new_pin: updated_pin
)
end

# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
def update_manifest_req(content:, dep:, old_req:, new_req:)
declaration = content.scan(declaration_regex(dep)).
find { |m| old_req.nil? || m.include?(old_req) }

return content unless declaration

if old_req && new_req
content.gsub(declaration) do |line|
line.gsub(old_req, new_req)
end
elsif old_req && new_req.nil?
content.gsub(declaration) do |line|
line.gsub(/\R+.*version\s*=.*/, "")
end
elsif old_req.nil? && new_req
content.gsub(declaration) do |line|
indent = line.match(/(?<indent>\s*)name/).named_captures["indent"]
version_declaration = indent + "version = \"#{new_req}\""
line.gsub(/name\s*=.*/) { |nm_ln| nm_ln + version_declaration }
end
end
end
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/PerceivedComplexity

def update_manifest_pin(content:, dep:, old_pin:, new_pin:)
declaration = content.scan(declaration_regex(dep)).
find { |m| m.include?(old_pin) }

return content unless declaration

if old_pin && new_pin
content.gsub(declaration) do |line|
line.gsub(old_pin, new_pin)
end
elsif old_pin && new_pin.nil?
content.gsub(declaration) do |line|
line.gsub(/\R+.*revision\s*=.*/, "").gsub(/\R+.*branch\s*=.*/, "")
end
end
end

def declaration_regex(dep)
/
(?<=\]\])
(?:(?!^\[).)*
name\s*=\s*["']#{Regexp.escape(dep.name)}["']
(?:(?!^\[).)*
/mx
end
end
end
end
Expand Down
155 changes: 155 additions & 0 deletions lib/dependabot/file_updaters/go/dep/manifest_updater.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# frozen_string_literal: true

require "parser/current"
require "dependabot/file_updaters/go/dep"

module Dependabot
module FileUpdaters
module Go
class Dep
class ManifestUpdater
def initialize(dependencies:, manifest:)
@dependencies = dependencies
@manifest = manifest
end

def updated_manifest_content
dependencies.
select { |dep| requirement_changed?(manifest, dep) }.
reduce(manifest.content.dup) do |content, dep|
updated_content = content

updated_content = update_requirements(
content: updated_content,
filename: manifest.name,
dependency: dep
)
updated_content = update_git_pin(
content: updated_content,
filename: manifest.name,
dependency: dep
)

if content == updated_content
raise "Expected content to change!"
end

updated_content
end
end

private

attr_reader :dependencies, :manifest

def requirement_changed?(file, dependency)
changed_requirements =
dependency.requirements - dependency.previous_requirements

changed_requirements.any? { |f| f[:file] == file.name }
end

def update_requirements(content:, filename:, dependency:)
updated_content = content.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
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]
next unless new_req[:file] == filename

updated_content = update_manifest_req(
content: updated_content,
dep: dependency,
old_req: old_req.fetch(:requirement),
new_req: new_req.fetch(:requirement)
)
end

updated_content
end

def update_git_pin(content:, filename:, dependency:)
updated_pin =
dependency.requirements.
find { |r| r[:file] == filename }&.
dig(:source, :ref)

old_pin =
dependency.previous_requirements.
find { |r| r[:file] == filename }&.
dig(:source, :ref)

return content unless old_pin

update_manifest_pin(
content: content,
dep: dependency,
old_pin: old_pin,
new_pin: updated_pin
)
end

# rubocop:disable Metrics/CyclomaticComplexity
# rubocop:disable Metrics/PerceivedComplexity
def update_manifest_req(content:, dep:, old_req:, new_req:)
declaration = content.scan(declaration_regex(dep)).
find { |m| old_req.nil? || m.include?(old_req) }

return content unless declaration

if old_req && new_req
content.gsub(declaration) do |line|
line.gsub(old_req, new_req)
end
elsif old_req && new_req.nil?
content.gsub(declaration) do |line|
line.gsub(/\R+.*version\s*=.*/, "")
end
elsif old_req.nil? && new_req
content.gsub(declaration) do |line|
indent = line.match(/(?<indent>\s*)name/).named_captures["indent"]
version_declaration = indent + "version = \"#{new_req}\""
line.gsub(/name\s*=.*/) { |nm_ln| nm_ln + version_declaration }
end
end
end
# rubocop:enable Metrics/CyclomaticComplexity
# rubocop:enable Metrics/PerceivedComplexity

def update_manifest_pin(content:, dep:, old_pin:, new_pin:)
declaration = content.scan(declaration_regex(dep)).
find { |m| m.include?(old_pin) }

return content unless declaration

if old_pin && new_pin
content.gsub(declaration) do |line|
line.gsub(old_pin, new_pin)
end
elsif old_pin && new_pin.nil?
content.gsub(declaration) do |line|
line.gsub(/\R+.*revision\s*=.*/, "").gsub(/\R+.*branch\s*=.*/, "")
end
end
end

def declaration_regex(dep)
/
(?<=\]\])
(?:(?!^\[).)*
name\s*=\s*["']#{Regexp.escape(dep.name)}["']
(?:(?!^\[).)*
/mx
end
end
end
end
end
end
Loading

0 comments on commit d41cc69

Please sign in to comment.