Skip to content

Commit

Permalink
Go (modules): handle local module replacements
Browse files Browse the repository at this point in the history
  • Loading branch information
hmarr committed Jun 6, 2019
1 parent 985205d commit 5d16dcf
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 1 deletion.
40 changes: 39 additions & 1 deletion go_modules/lib/dependabot/go_modules/file_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,15 @@ def module_info(go_mod)
@module_info ||=
SharedHelpers.in_a_temporary_directory do |path|
SharedHelpers.with_git_configured(credentials: credentials) do
File.write("go.mod", go_mod.content)
# Create a fake empty module for each local module so that
# `go list` works, even if some modules have been `replace`d with
# a local module that we don't have access to.
local_replacements.each do |_, stub_path|
Dir.mkdir(stub_path) unless Dir.exist?(stub_path)
FileUtils.touch(File.join(stub_path, "go.mod"))
end

File.write("go.mod", go_mod_content)

command = "go mod edit -print > /dev/null"
command += " && go list -m -json all"
Expand All @@ -89,6 +97,36 @@ def module_info(go_mod)
end
end

def local_replacements
@local_replacements ||=
SharedHelpers.in_a_temporary_directory do |path|
File.write("go.mod", go_mod.content)

# Parse the go.mod to get a JSON representation of the replace
# directives
command = "go mod edit -json"
env = { "GO111MODULE" => "on" }
stdout, stderr, status = Open3.capture3(env, command)
handle_parser_error(path, stderr) unless status.success?

# Find all the local replacements, and return them with a stub path
# we can use in their place. Using generated paths is safer as it
# means we don't need to worry about references to parent
# directories, etc.
(JSON.parse(stdout)["Replace"] || []).
map { |r| r["New"]["Path"] }.
compact.
select { |path| path.start_with?(".") || path.start_with?("/") }.
map { |path| [path, "./" + Digest::SHA2.hexdigest(path)] }
end
end

def go_mod_content
local_replacements.reduce(go_mod.content) do |body, (path, stub_path)|
body.sub(path, stub_path)
end
end

GIT_ERROR_REGEX = /go: .*: git fetch .*: exit status 128/.freeze

# rubocop:disable Metrics/AbcSize
Expand Down
16 changes: 16 additions & 0 deletions go_modules/spec/dependabot/go_modules/file_parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -204,5 +204,21 @@
end
end
end

describe "a dependency replaced by a local override" do
let(:go_mod_content) do
go_mod = fixture("go_mods", go_mod_fixture_name)
go_mod.sub("=> github.com/rsc/qr v0.2.0", "=> ./foo/bar/baz")
end

subject(:dependency) do
dependencies.find { |d| d.name == "rsc.io/qr" }
end

it "has the right details" do
expect(dependency).to be_a(Dependabot::Dependency)
expect(dependency.name).to eq("rsc.io/qr")
end
end
end
end

0 comments on commit 5d16dcf

Please sign in to comment.