dependabot-nuget 0.237.0 → 0.239.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/dependabot/nuget/cache_manager.rb +22 -0
- data/lib/dependabot/nuget/file_fetcher/import_paths_finder.rb +15 -0
- data/lib/dependabot/nuget/file_fetcher.rb +61 -64
- data/lib/dependabot/nuget/file_parser/dotnet_tools_json_parser.rb +2 -1
- data/lib/dependabot/nuget/file_parser/global_json_parser.rb +2 -1
- data/lib/dependabot/nuget/file_parser/packages_config_parser.rb +22 -4
- data/lib/dependabot/nuget/file_parser/project_file_parser.rb +287 -15
- data/lib/dependabot/nuget/file_parser/property_value_finder.rb +24 -52
- data/lib/dependabot/nuget/file_parser.rb +4 -1
- data/lib/dependabot/nuget/file_updater.rb +123 -117
- data/lib/dependabot/nuget/native_helpers.rb +94 -0
- data/lib/dependabot/nuget/requirement.rb +5 -1
- data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +85 -0
- data/lib/dependabot/nuget/update_checker/dependency_finder.rb +228 -0
- data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +119 -0
- data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +83 -0
- data/lib/dependabot/nuget/update_checker/property_updater.rb +30 -3
- data/lib/dependabot/nuget/update_checker/repository_finder.rb +36 -10
- data/lib/dependabot/nuget/update_checker/tfm_comparer.rb +31 -0
- data/lib/dependabot/nuget/update_checker/tfm_finder.rb +127 -0
- data/lib/dependabot/nuget/update_checker/version_finder.rb +47 -6
- data/lib/dependabot/nuget/update_checker.rb +42 -8
- data/lib/dependabot/nuget.rb +2 -0
- metadata +35 -9
- data/lib/dependabot/nuget/file_updater/packages_config_declaration_finder.rb +0 -70
- data/lib/dependabot/nuget/file_updater/project_file_declaration_finder.rb +0 -183
@@ -5,15 +5,19 @@ require "nokogiri"
|
|
5
5
|
|
6
6
|
require "dependabot/dependency"
|
7
7
|
require "dependabot/nuget/file_parser"
|
8
|
+
require "dependabot/nuget/update_checker"
|
9
|
+
require "dependabot/nuget/cache_manager"
|
8
10
|
|
9
11
|
# For details on how dotnet handles version constraints, see:
|
10
12
|
# https://docs.microsoft.com/en-us/nuget/reference/package-versioning
|
11
13
|
module Dependabot
|
12
14
|
module Nuget
|
13
15
|
class FileParser
|
16
|
+
# rubocop:disable Metrics/ClassLength
|
14
17
|
class ProjectFileParser
|
15
18
|
require "dependabot/file_parsers/base/dependency_set"
|
16
19
|
require_relative "property_value_finder"
|
20
|
+
require_relative "../update_checker/repository_finder"
|
17
21
|
|
18
22
|
DEPENDENCY_SELECTOR = "ItemGroup > PackageReference, " \
|
19
23
|
"ItemGroup > GlobalPackageReference, " \
|
@@ -21,15 +25,64 @@ module Dependabot
|
|
21
25
|
"ItemGroup > Dependency, " \
|
22
26
|
"ItemGroup > DevelopmentDependency"
|
23
27
|
|
28
|
+
PROJECT_REFERENCE_SELECTOR = "ItemGroup > ProjectReference"
|
29
|
+
|
30
|
+
PACKAGE_REFERENCE_SELECTOR = "ItemGroup > PackageReference, " \
|
31
|
+
"ItemGroup > GlobalPackageReference"
|
32
|
+
|
33
|
+
PACKAGE_VERSION_SELECTOR = "ItemGroup > PackageVersion"
|
34
|
+
|
24
35
|
PROJECT_SDK_REGEX = %r{^([^/]+)/(\d+(?:[.]\d+(?:[.]\d+)?)?(?:[+-].*)?)$}
|
25
36
|
PROPERTY_REGEX = /\$\((?<property>.*?)\)/
|
26
37
|
ITEM_REGEX = /\@\((?<property>.*?)\)/
|
27
38
|
|
28
|
-
def
|
29
|
-
|
39
|
+
def self.dependency_set_cache
|
40
|
+
CacheManager.cache("project_file_dependency_set")
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.dependency_url_search_cache
|
44
|
+
CacheManager.cache("dependency_url_search_cache")
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize(dependency_files:, credentials:)
|
48
|
+
@dependency_files = dependency_files
|
49
|
+
@credentials = credentials
|
30
50
|
end
|
31
51
|
|
32
52
|
def dependency_set(project_file:)
|
53
|
+
return parse_dependencies(project_file) if CacheManager.caching_disabled?
|
54
|
+
|
55
|
+
key = "#{project_file.name.downcase}::#{project_file.content.hash}"
|
56
|
+
cache = ProjectFileParser.dependency_set_cache
|
57
|
+
|
58
|
+
cache[key] ||= parse_dependencies(project_file)
|
59
|
+
|
60
|
+
dependency_set = Dependabot::FileParsers::Base::DependencySet.new
|
61
|
+
dependency_set += cache[key]
|
62
|
+
dependency_set
|
63
|
+
end
|
64
|
+
|
65
|
+
def target_frameworks(project_file:)
|
66
|
+
target_framework = details_for_property("TargetFramework", project_file)
|
67
|
+
return [target_framework&.fetch(:value)] if target_framework
|
68
|
+
|
69
|
+
target_frameworks = details_for_property("TargetFrameworks", project_file)
|
70
|
+
return target_frameworks&.fetch(:value)&.split(";") if target_frameworks
|
71
|
+
|
72
|
+
target_framework = details_for_property("TargetFrameworkVersion", project_file)
|
73
|
+
return [] unless target_framework
|
74
|
+
|
75
|
+
# TargetFrameworkVersion is a string like "v4.7.2"
|
76
|
+
value = target_framework&.fetch(:value)
|
77
|
+
# convert it to a string like "net472"
|
78
|
+
["net#{value[1..-1].delete('.')}"]
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
attr_reader :dependency_files, :credentials
|
84
|
+
|
85
|
+
def parse_dependencies(project_file)
|
33
86
|
dependency_set = Dependabot::FileParsers::Base::DependencySet.new
|
34
87
|
|
35
88
|
doc = Nokogiri::XML(project_file.content)
|
@@ -46,6 +99,10 @@ module Dependabot
|
|
46
99
|
dependency_set << dependency if dependency
|
47
100
|
end
|
48
101
|
|
102
|
+
add_global_package_references(dependency_set)
|
103
|
+
|
104
|
+
add_transitive_dependencies(project_file, doc, dependency_set)
|
105
|
+
|
49
106
|
# Look for SDK references; see:
|
50
107
|
# https://docs.microsoft.com/en-us/visualstudio/msbuild/how-to-use-project-sdk
|
51
108
|
add_sdk_references(doc, dependency_set, project_file)
|
@@ -53,9 +110,86 @@ module Dependabot
|
|
53
110
|
dependency_set
|
54
111
|
end
|
55
112
|
|
56
|
-
|
113
|
+
def add_global_package_references(dependency_set)
|
114
|
+
project_import_files.each do |file|
|
115
|
+
doc = Nokogiri::XML(file.content)
|
116
|
+
doc.remove_namespaces!
|
57
117
|
|
58
|
-
|
118
|
+
doc.css(PACKAGE_REFERENCE_SELECTOR).each do |dependency_node|
|
119
|
+
name = dependency_name(dependency_node, file)
|
120
|
+
req = dependency_requirement(dependency_node, file)
|
121
|
+
version = dependency_version(dependency_node, file)
|
122
|
+
prop_name = req_property_name(dependency_node)
|
123
|
+
|
124
|
+
dependency = build_dependency(name, req, version, prop_name, file)
|
125
|
+
dependency_set << dependency if dependency
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def add_transitive_dependencies(project_file, doc, dependency_set)
|
131
|
+
add_transitive_dependencies_from_packages(dependency_set)
|
132
|
+
add_transitive_dependencies_from_project_references(project_file, doc, dependency_set)
|
133
|
+
end
|
134
|
+
|
135
|
+
def add_transitive_dependencies_from_project_references(project_file, doc, dependency_set)
|
136
|
+
project_file_directory = File.dirname(project_file.name)
|
137
|
+
is_rooted = project_file_directory.start_with?("/")
|
138
|
+
# Root the directory path to avoid expand_path prepending the working directory
|
139
|
+
project_file_directory = "/" + project_file_directory unless is_rooted
|
140
|
+
|
141
|
+
# Look for regular project references
|
142
|
+
doc.css(PROJECT_REFERENCE_SELECTOR).each do |reference_node|
|
143
|
+
relative_path = dependency_name(reference_node, project_file)
|
144
|
+
# This could result from a <ProjectReference Remove="..." /> item.
|
145
|
+
next unless relative_path
|
146
|
+
|
147
|
+
# normalize path separators
|
148
|
+
relative_path = relative_path.tr("\\", "/")
|
149
|
+
# path is relative to the project file directory
|
150
|
+
relative_path = File.join(project_file_directory, relative_path)
|
151
|
+
|
152
|
+
# get absolute path
|
153
|
+
full_path = File.expand_path(relative_path)
|
154
|
+
full_path = full_path[1..-1] unless is_rooted
|
155
|
+
|
156
|
+
referenced_file = dependency_files.find { |f| f.name == full_path }
|
157
|
+
next unless referenced_file
|
158
|
+
|
159
|
+
dependency_set(project_file: referenced_file).dependencies.each do |dep|
|
160
|
+
dependency = Dependency.new(
|
161
|
+
name: dep.name,
|
162
|
+
version: dep.version,
|
163
|
+
package_manager: dep.package_manager,
|
164
|
+
requirements: []
|
165
|
+
)
|
166
|
+
dependency_set << dependency
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def add_transitive_dependencies_from_packages(dependency_set)
|
172
|
+
transitive_dependencies_from_packages(dependency_set.dependencies).each { |dep| dependency_set << dep }
|
173
|
+
end
|
174
|
+
|
175
|
+
def transitive_dependencies_from_packages(dependencies)
|
176
|
+
transitive_dependencies = {}
|
177
|
+
|
178
|
+
dependencies.each do |dependency|
|
179
|
+
UpdateChecker::DependencyFinder.new(
|
180
|
+
dependency: dependency,
|
181
|
+
dependency_files: dependency_files,
|
182
|
+
credentials: credentials
|
183
|
+
).transitive_dependencies.each do |transitive_dep|
|
184
|
+
visited_dep = transitive_dependencies[transitive_dep.name.downcase]
|
185
|
+
next if !visited_dep.nil? && visited_dep.numeric_version > transitive_dep.numeric_version
|
186
|
+
|
187
|
+
transitive_dependencies[transitive_dep.name.downcase] = transitive_dep
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
transitive_dependencies.values
|
192
|
+
end
|
59
193
|
|
60
194
|
def add_sdk_references(doc, dependency_set, project_file)
|
61
195
|
# These come in 3 flavours:
|
@@ -133,21 +267,88 @@ module Dependabot
|
|
133
267
|
requirement[:metadata] = { property_name: root_prop_name }
|
134
268
|
end
|
135
269
|
|
136
|
-
Dependency.new(
|
270
|
+
dependency = Dependency.new(
|
137
271
|
name: name,
|
138
272
|
version: version,
|
139
273
|
package_manager: "nuget",
|
140
274
|
requirements: [requirement]
|
141
275
|
)
|
276
|
+
|
277
|
+
# only include dependency if one of the sources has it
|
278
|
+
return unless dependency_has_search_results?(dependency)
|
279
|
+
|
280
|
+
dependency
|
281
|
+
end
|
282
|
+
|
283
|
+
def dependency_has_search_results?(dependency)
|
284
|
+
nuget_configs = dependency_files.select { |f| f.name.casecmp?("nuget.config") }
|
285
|
+
dependency_urls = UpdateChecker::RepositoryFinder.new(
|
286
|
+
dependency: dependency,
|
287
|
+
credentials: credentials,
|
288
|
+
config_files: nuget_configs
|
289
|
+
).dependency_urls
|
290
|
+
if dependency_urls.empty?
|
291
|
+
dependency_urls = [UpdateChecker::RepositoryFinder.get_default_repository_details(dependency.name)]
|
292
|
+
end
|
293
|
+
dependency_urls.any? do |dependency_url|
|
294
|
+
dependency_url_has_matching_result?(dependency.name, dependency_url)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def dependency_url_has_matching_result?(dependency_name, dependency_url)
|
299
|
+
repository_type = dependency_url.fetch(:repository_type)
|
300
|
+
if repository_type == "v3"
|
301
|
+
dependency_url_has_matching_result_v3?(dependency_name, dependency_url)
|
302
|
+
elsif repository_type == "v2"
|
303
|
+
dependency_url_has_matching_result_v2?(dependency_name, dependency_url)
|
304
|
+
else
|
305
|
+
raise "Unknown repository type: #{repository_type}"
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def dependency_url_has_matching_result_v3?(dependency_name, dependency_url)
|
310
|
+
url = dependency_url.fetch(:search_url)
|
311
|
+
auth_header = dependency_url.fetch(:auth_header)
|
312
|
+
response = execute_search_for_dependency_url(url, auth_header)
|
313
|
+
return false unless response.status == 200
|
314
|
+
|
315
|
+
body = JSON.parse(response.body)
|
316
|
+
data = body["data"]
|
317
|
+
return false unless data.length.positive?
|
318
|
+
|
319
|
+
data.any? { |result| result["id"].casecmp?(dependency_name) }
|
320
|
+
end
|
321
|
+
|
322
|
+
def dependency_url_has_matching_result_v2?(dependency_name, dependency_url)
|
323
|
+
url = dependency_url.fetch(:versions_url)
|
324
|
+
auth_header = dependency_url.fetch(:auth_header)
|
325
|
+
response = execute_search_for_dependency_url(url, auth_header)
|
326
|
+
return false unless response.status == 200
|
327
|
+
|
328
|
+
doc = Nokogiri::XML(response.body)
|
329
|
+
doc.remove_namespaces!
|
330
|
+
id_nodes = doc.xpath("/feed/entry/properties/Id")
|
331
|
+
found_matching_result = id_nodes.any? do |id_node|
|
332
|
+
return false unless id_node.text
|
333
|
+
|
334
|
+
id_node.text.casecmp?(dependency_name)
|
335
|
+
end
|
336
|
+
found_matching_result
|
337
|
+
end
|
338
|
+
|
339
|
+
def execute_search_for_dependency_url(url, auth_header)
|
340
|
+
cache = ProjectFileParser.dependency_url_search_cache
|
341
|
+
cache[url] ||= Dependabot::RegistryClient.get(
|
342
|
+
url: url,
|
343
|
+
headers: auth_header
|
344
|
+
)
|
345
|
+
|
346
|
+
cache[url]
|
142
347
|
end
|
143
348
|
|
144
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
145
349
|
def dependency_name(dependency_node, project_file)
|
146
|
-
raw_name =
|
147
|
-
|
148
|
-
dependency_node.at_xpath("./Include")&.content&.strip ||
|
149
|
-
dependency_node.attribute("Update")&.value&.strip ||
|
150
|
-
dependency_node.at_xpath("./Update")&.content&.strip
|
350
|
+
raw_name = get_attribute_value(dependency_node, "Include") ||
|
351
|
+
get_attribute_value(dependency_node, "Update")
|
151
352
|
return unless raw_name
|
152
353
|
|
153
354
|
# If the item contains @(ItemGroup) then ignore as it
|
@@ -156,15 +357,51 @@ module Dependabot
|
|
156
357
|
|
157
358
|
evaluated_value(raw_name, project_file)
|
158
359
|
end
|
159
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
160
360
|
|
161
361
|
def dependency_requirement(dependency_node, project_file)
|
162
|
-
raw_requirement = get_node_version_value(dependency_node)
|
362
|
+
raw_requirement = get_node_version_value(dependency_node) ||
|
363
|
+
find_package_version(dependency_node, project_file)
|
163
364
|
return unless raw_requirement
|
164
365
|
|
165
366
|
evaluated_value(raw_requirement, project_file)
|
166
367
|
end
|
167
368
|
|
369
|
+
def find_package_version(dependency_node, project_file)
|
370
|
+
name = dependency_name(dependency_node, project_file)
|
371
|
+
return unless name
|
372
|
+
|
373
|
+
package_version_string = package_versions[name].to_s
|
374
|
+
return unless package_version_string != ""
|
375
|
+
|
376
|
+
package_version_string
|
377
|
+
end
|
378
|
+
|
379
|
+
def package_versions
|
380
|
+
@package_versions ||= begin
|
381
|
+
package_versions = {}
|
382
|
+
directory_packages_props_files.each do |file|
|
383
|
+
doc = Nokogiri::XML(file.content)
|
384
|
+
doc.remove_namespaces!
|
385
|
+
doc.css(PACKAGE_VERSION_SELECTOR).each do |package_node|
|
386
|
+
name = dependency_name(package_node, file)
|
387
|
+
version = dependency_version(package_node, file)
|
388
|
+
next unless name && version
|
389
|
+
|
390
|
+
version = Version.new(version)
|
391
|
+
existing_version = package_versions[name]
|
392
|
+
next if existing_version && existing_version > version
|
393
|
+
|
394
|
+
package_versions[name] = version
|
395
|
+
end
|
396
|
+
end
|
397
|
+
package_versions
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
def directory_packages_props_files
|
402
|
+
dependency_files.select { |df| df.name.match?(/[Dd]irectory.[Pp]ackages.props/) }
|
403
|
+
end
|
404
|
+
|
168
405
|
def dependency_version(dependency_node, project_file)
|
169
406
|
requirement = dependency_requirement(dependency_node, project_file)
|
170
407
|
return unless requirement
|
@@ -191,9 +428,12 @@ module Dependabot
|
|
191
428
|
.named_captures.fetch("property")
|
192
429
|
end
|
193
430
|
|
194
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
195
431
|
def get_node_version_value(node)
|
196
|
-
|
432
|
+
get_attribute_value(node, "Version") || get_attribute_value(node, "VersionOverride")
|
433
|
+
end
|
434
|
+
|
435
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
436
|
+
def get_attribute_value(node, attribute)
|
197
437
|
value =
|
198
438
|
node.attribute(attribute)&.value&.strip ||
|
199
439
|
node.at_xpath("./#{attribute}")&.content&.strip ||
|
@@ -230,7 +470,39 @@ module Dependabot
|
|
230
470
|
@property_value_finder ||=
|
231
471
|
PropertyValueFinder.new(dependency_files: dependency_files)
|
232
472
|
end
|
473
|
+
|
474
|
+
def project_import_files
|
475
|
+
dependency_files -
|
476
|
+
project_files -
|
477
|
+
packages_config_files -
|
478
|
+
nuget_configs -
|
479
|
+
[global_json] -
|
480
|
+
[dotnet_tools_json]
|
481
|
+
end
|
482
|
+
|
483
|
+
def project_files
|
484
|
+
dependency_files.select { |f| f.name.match?(/\.[a-z]{2}proj$/) }
|
485
|
+
end
|
486
|
+
|
487
|
+
def packages_config_files
|
488
|
+
dependency_files.select do |f|
|
489
|
+
f.name.split("/").last.casecmp("packages.config").zero?
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
def nuget_configs
|
494
|
+
dependency_files.select { |f| f.name.match?(/nuget\.config$/i) }
|
495
|
+
end
|
496
|
+
|
497
|
+
def global_json
|
498
|
+
dependency_files.find { |f| f.name.casecmp("global.json").zero? }
|
499
|
+
end
|
500
|
+
|
501
|
+
def dotnet_tools_json
|
502
|
+
dependency_files.find { |f| f.name.casecmp(".config/dotnet-tools.json").zero? }
|
503
|
+
end
|
233
504
|
end
|
505
|
+
# rubocop:enable Metrics/ClassLength
|
234
506
|
end
|
235
507
|
end
|
236
508
|
end
|
@@ -39,7 +39,7 @@ module Dependabot
|
|
39
39
|
)
|
40
40
|
|
41
41
|
node_details ||=
|
42
|
-
|
42
|
+
find_property_in_directory_packages_props(
|
43
43
|
property: property_name,
|
44
44
|
callsite_file: callsite_file
|
45
45
|
)
|
@@ -101,24 +101,18 @@ module Dependabot
|
|
101
101
|
end
|
102
102
|
|
103
103
|
def find_property_in_directory_build_targets(property:, callsite_file:)
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
deep_find_prop_node(property: property, file: file)
|
104
|
+
find_property_in_up_tree_files(property: property, callsite_file: callsite_file,
|
105
|
+
expected_file_name: "Directory.Build.targets")
|
108
106
|
end
|
109
107
|
|
110
108
|
def find_property_in_directory_build_props(property:, callsite_file:)
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
deep_find_prop_node(property: property, file: file)
|
109
|
+
find_property_in_up_tree_files(property: property, callsite_file: callsite_file,
|
110
|
+
expected_file_name: "Directory.Build.props")
|
115
111
|
end
|
116
112
|
|
117
|
-
def
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
deep_find_prop_node(property: property, file: file)
|
113
|
+
def find_property_in_directory_packages_props(property:, callsite_file:)
|
114
|
+
find_property_in_up_tree_files(property: property, callsite_file: callsite_file,
|
115
|
+
expected_file_name: "Directory.Packages.props")
|
122
116
|
end
|
123
117
|
|
124
118
|
def find_property_in_packages_props(property:)
|
@@ -128,53 +122,29 @@ module Dependabot
|
|
128
122
|
deep_find_prop_node(property: property, file: file)
|
129
123
|
end
|
130
124
|
|
131
|
-
def
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
# Directory.Build.targets file
|
136
|
-
possible_paths = dir.split("/").map.with_index do |_, i|
|
137
|
-
base = dir.split("/").first(i + 1).join("/")
|
138
|
-
Pathname.new(base + "/Directory.Build.targets").cleanpath.to_path
|
139
|
-
end.reverse + ["Directory.Build.targets"]
|
140
|
-
|
141
|
-
path = possible_paths.uniq
|
142
|
-
.find { |p| dependency_files.find { |f| f.name == p } }
|
125
|
+
def find_property_in_up_tree_files(property:, callsite_file:, expected_file_name:)
|
126
|
+
files = up_tree_files_for_project(callsite_file, expected_file_name)
|
127
|
+
return unless files
|
128
|
+
return if files.empty?
|
143
129
|
|
144
|
-
|
130
|
+
# first file where we were able to find the node
|
131
|
+
files.reduce(nil) { |acc, file| acc || deep_find_prop_node(property: property, file: file) }
|
145
132
|
end
|
146
133
|
|
147
|
-
def
|
134
|
+
def up_tree_files_for_project(project_file, expected_file_name)
|
148
135
|
dir = File.dirname(project_file.name)
|
149
136
|
|
150
|
-
#
|
151
|
-
# Directory.Build.props file
|
137
|
+
# Simulate MSBuild walking up the directory structure looking for a file
|
152
138
|
possible_paths = dir.split("/").map.with_index do |_, i|
|
153
139
|
base = dir.split("/").first(i + 1).join("/")
|
154
|
-
Pathname.new(base + "
|
155
|
-
end.reverse + [
|
140
|
+
Pathname.new(base + "/#{expected_file_name}").cleanpath.to_path
|
141
|
+
end.reverse + [expected_file_name]
|
156
142
|
|
157
|
-
|
143
|
+
paths =
|
158
144
|
possible_paths.uniq
|
159
|
-
.
|
160
|
-
|
161
|
-
dependency_files.find { |f| f.name == path }
|
162
|
-
end
|
163
|
-
|
164
|
-
def build_packages_file_for_project(project_file)
|
165
|
-
dir = File.dirname(project_file.name)
|
166
|
-
|
167
|
-
# Nuget walks up the directory structure looking for a
|
168
|
-
# Directory.Packages.props file
|
169
|
-
possible_paths = dir.split("/").map.with_index do |_, i|
|
170
|
-
base = dir.split("/").first(i + 1).join("/")
|
171
|
-
Pathname.new(base + "/Directory.Packages.props").cleanpath.to_path
|
172
|
-
end.reverse + ["Directory.Packages.props"]
|
173
|
-
|
174
|
-
path = possible_paths.uniq
|
175
|
-
.find { |p| dependency_files.find { |f| f.name == p } }
|
145
|
+
.select { |p| dependency_files.find { |f| f.name.casecmp(p).zero? } }
|
176
146
|
|
177
|
-
dependency_files.
|
147
|
+
dependency_files.select { |f| paths.include?(f.name) }
|
178
148
|
end
|
179
149
|
|
180
150
|
def packages_props_file
|
@@ -182,7 +152,9 @@ module Dependabot
|
|
182
152
|
end
|
183
153
|
|
184
154
|
def property_xpath(property_name)
|
185
|
-
|
155
|
+
# only return properties that don't have a `Condition` attribute or the `Condition` attribute is checking for
|
156
|
+
# an empty string, e.g., Condition="$(SomeProperty) == ''"
|
157
|
+
%{/Project/PropertyGroup/#{property_name}[not(@Condition) or @Condition="$(#{property_name}) == ''"]}
|
186
158
|
end
|
187
159
|
|
188
160
|
def node_details(file:, node:, property:)
|
@@ -67,7 +67,10 @@ module Dependabot
|
|
67
67
|
|
68
68
|
def project_file_parser
|
69
69
|
@project_file_parser ||=
|
70
|
-
ProjectFileParser.new(
|
70
|
+
ProjectFileParser.new(
|
71
|
+
dependency_files: dependency_files,
|
72
|
+
credentials: credentials
|
73
|
+
)
|
71
74
|
end
|
72
75
|
|
73
76
|
def project_files
|