Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for updating dependencies in target files #6913

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions maven/lib/dependabot/maven/file_fetcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def fetch_files
fetched_files << pom
fetched_files += child_poms
fetched_files += relative_path_parents(fetched_files)
fetched_files += targetfiles
fetched_files << extensions if extensions
fetched_files.uniq
end
Expand All @@ -39,6 +40,13 @@ def extensions
fetch_file_if_present(".mvn/extensions.xml")
end

def targetfiles
@targetfiles ||=
repo_contents(raise_errors: false).
select { |f| f.type == "file" && f.name.end_with?(".target") }.
map { |f| fetch_file_from_host(f.name) }
end

def child_poms
recursively_fetch_child_poms(pom, fetched_filenames: ["pom.xml"])
end
Expand Down
27 changes: 27 additions & 0 deletions maven/lib/dependabot/maven/file_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,14 @@ class FileParser < Dependabot::FileParsers::Base
# - Any dependencies (incl. those in dependencyManagement or plugins)
# - Any plugins (incl. those in pluginManagement)
# - Any extensions
# - Any eclipse-target with a location of type Maven
DEPENDENCY_SELECTOR = "project > parent, " \
"dependencies > dependency, " \
"extensions > extension, " \
"annotationProcessorPaths > path"
PLUGIN_SELECTOR = "plugins > plugin"
EXTENSION_SELECTOR = "extensions > extension"
TARGET_SELECTOR = "target > locations > location[type='Maven'] > dependencies > dependency"

# Regex to get the property name from a declaration that uses a property
PROPERTY_REGEX = /\$\{(?<property>.*?)\}/
Expand All @@ -35,6 +37,7 @@ def parse
dependency_set = DependencySet.new
pomfiles.each { |pom| dependency_set += pomfile_dependencies(pom) }
extensionfiles.each { |extension| dependency_set += extensionfile_dependencies(extension) }
targetfiles.each { |target| dependency_set += targetfile_dependencies(target) }
dependency_set.dependencies
end

Expand Down Expand Up @@ -85,6 +88,25 @@ def extensionfile_dependencies(extension)
dependency_set
end

def targetfile_dependencies(target)
dependency_set = DependencySet.new

errors = []
doc = Nokogiri::XML(target.content)
doc.remove_namespaces!

doc.css(TARGET_SELECTOR).each do |dependency_node|
dep = dependency_from_dependency_node(target, dependency_node)
dependency_set << dep if dep
rescue DependencyFileNotEvaluatable => e
errors << e
end

raise errors.first if errors.any? && dependency_set.dependencies.none?

dependency_set
end

def dependency_from_dependency_node(pom, dependency_node)
return unless (name = dependency_name(dependency_node, pom))
return if internal_dependency_names.include?(name)
Expand Down Expand Up @@ -283,6 +305,11 @@ def extensionfiles
dependency_files.select { |f| f.name.end_with?("extensions.xml") }
end

def targetfiles
@targetfiles ||=
dependency_files.select { |f| f.name.end_with?(".target") }
end

def internal_dependency_names
@internal_dependency_names ||=
dependency_files.filter_map do |pom|
Expand Down
7 changes: 6 additions & 1 deletion maven/spec/dependabot/maven/file_fetcher_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
)
end
let(:file_fetcher_instance) do
described_class.new(source: source, credentials: credentials)
described_class.new(source: source, credentials: credentials, repo_contents_path: nil)
end
let(:directory) { "/" }
let(:github_url) { "https://api.github.com/" }
Expand Down Expand Up @@ -71,6 +71,11 @@
to_return(
status: 404
)
stub_request(:get, /.*\?ref=sha/).
with(headers: { "Authorization" => "token token" }).
to_return(
status: 404
)
end

context "with a basic pom" do
Expand Down
27 changes: 27 additions & 0 deletions maven/spec/dependabot/maven/file_parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,33 @@
end
end

context "with target-file" do
let(:files) { [targetfile, pom] }
let(:targetfile) do
Dependabot::DependencyFile.new(name: "releng/myproject.target", content: targetfile_body)
end
let(:targetfile_body) { fixture("target-files", "example.target") }

describe "the sole dependency" do
subject(:dependency) { dependencies[3] }

it "has the right details" do
expect(dependency).to be_a(Dependabot::Dependency)
expect(dependency.name).to eq("commons-io:commons-io")
expect(dependency.version).to eq("2.11.0")
expect(dependency.requirements).to eq(
[{
requirement: "2.11.0",
file: "releng/myproject.target",
groups: [],
source: nil,
metadata: { packaging_type: "jar" }
}]
)
end
end
end

context "with rogue whitespace" do
let(:pom_body) { fixture("poms", "whitespace.xml") }

Expand Down
18 changes: 18 additions & 0 deletions maven/spec/fixtures/target-files/example.target
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?pde version="3.8"?>
<target name="example">
<locations>
<location path="/tmp/dummy/" type="Directory"/>
<location includeDependencyDepth="none" includeSource="true" label="An old version of commons-io" missingManifest="error" type="Maven">
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
<type>jar</type>
</dependency>
</dependencies>
</location>
<location path="${eclipse_home}" type="Profile"/>
</locations>
</target>