dependabot-nuget 0.246.0 → 0.247.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/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +40 -6
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathHelper.cs +27 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs +18 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +110 -0
- data/lib/dependabot/nuget/cache_manager.rb +9 -3
- data/lib/dependabot/nuget/file_fetcher/import_paths_finder.rb +15 -12
- data/lib/dependabot/nuget/file_fetcher/sln_project_paths_finder.rb +13 -3
- data/lib/dependabot/nuget/file_fetcher.rb +79 -31
- data/lib/dependabot/nuget/file_parser/dotnet_tools_json_parser.rb +10 -2
- data/lib/dependabot/nuget/file_parser/global_json_parser.rb +10 -2
- data/lib/dependabot/nuget/file_parser/packages_config_parser.rb +11 -2
- data/lib/dependabot/nuget/file_parser/project_file_parser.rb +140 -41
- data/lib/dependabot/nuget/file_parser/property_value_finder.rb +57 -5
- data/lib/dependabot/nuget/file_parser.rb +3 -3
- data/lib/dependabot/nuget/file_updater/property_value_updater.rb +25 -8
- data/lib/dependabot/nuget/file_updater.rb +74 -38
- data/lib/dependabot/nuget/http_response_helpers.rb +6 -1
- data/lib/dependabot/nuget/metadata_finder.rb +27 -3
- data/lib/dependabot/nuget/nuget_client.rb +23 -0
- data/lib/dependabot/nuget/requirement.rb +4 -1
- data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +26 -15
- data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +11 -13
- data/lib/dependabot/nuget/update_checker/repository_finder.rb +25 -3
- data/lib/dependabot/nuget/update_checker/tfm_finder.rb +2 -2
- data/lib/dependabot/nuget/update_checker/version_finder.rb +15 -6
- data/lib/dependabot/nuget/update_checker.rb +4 -4
- data/lib/dependabot/nuget/version.rb +7 -2
- metadata +19 -5
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "nokogiri"
|
@@ -40,20 +40,31 @@ module Dependabot
|
|
40
40
|
PROPERTY_REGEX = /\$\((?<property>.*?)\)/
|
41
41
|
ITEM_REGEX = /\@\((?<property>.*?)\)/
|
42
42
|
|
43
|
+
sig { returns(T::Hash[String, Dependabot::FileParsers::Base::DependencySet]) }
|
43
44
|
def self.dependency_set_cache
|
44
45
|
CacheManager.cache("project_file_dependency_set")
|
45
46
|
end
|
46
47
|
|
48
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
47
49
|
def self.dependency_url_search_cache
|
48
50
|
CacheManager.cache("dependency_url_search_cache")
|
49
51
|
end
|
50
52
|
|
53
|
+
sig do
|
54
|
+
params(dependency_files: T::Array[DependencyFile],
|
55
|
+
credentials: T::Array[Credential],
|
56
|
+
repo_contents_path: T.nilable(String)).void
|
57
|
+
end
|
51
58
|
def initialize(dependency_files:, credentials:, repo_contents_path:)
|
52
59
|
@dependency_files = dependency_files
|
53
60
|
@credentials = credentials
|
54
61
|
@repo_contents_path = repo_contents_path
|
55
62
|
end
|
56
63
|
|
64
|
+
sig do
|
65
|
+
params(project_file: DependencyFile, visited_project_files: T::Set[String])
|
66
|
+
.returns(Dependabot::FileParsers::Base::DependencySet)
|
67
|
+
end
|
57
68
|
def dependency_set(project_file:, visited_project_files: Set.new)
|
58
69
|
key = "#{project_file.name.downcase}::#{project_file.content.hash}"
|
59
70
|
cache = ProjectFileParser.dependency_set_cache
|
@@ -64,8 +75,9 @@ module Dependabot
|
|
64
75
|
cache[key] ||= parse_dependencies(project_file, visited_project_files)
|
65
76
|
end
|
66
77
|
|
78
|
+
sig { params(project_file: DependencyFile).returns(T::Set[String]) }
|
67
79
|
def downstream_file_references(project_file:)
|
68
|
-
file_set = Set.new
|
80
|
+
file_set = T.let(Set.new, T::Set[String])
|
69
81
|
|
70
82
|
doc = Nokogiri::XML(project_file.content)
|
71
83
|
doc.remove_namespaces!
|
@@ -74,9 +86,11 @@ module Dependabot
|
|
74
86
|
ref_nodes = proj_refs + proj_files
|
75
87
|
ref_nodes.each do |project_reference_node|
|
76
88
|
dep_file = get_attribute_value(project_reference_node, "Include")
|
89
|
+
next unless dep_file
|
90
|
+
|
77
91
|
full_project_path = full_path(project_file, dep_file)
|
78
92
|
full_project_path = full_project_path[1..-1] if full_project_path.start_with?("/")
|
79
|
-
full_project_paths = expand_wildcards_in_project_reference_path(full_project_path)
|
93
|
+
full_project_paths = expand_wildcards_in_project_reference_path(T.must(full_project_path))
|
80
94
|
full_project_paths.each do |full_project_path_expanded|
|
81
95
|
file_set << full_project_path_expanded if full_project_path_expanded
|
82
96
|
end
|
@@ -85,30 +99,37 @@ module Dependabot
|
|
85
99
|
file_set
|
86
100
|
end
|
87
101
|
|
102
|
+
sig { params(project_file: DependencyFile).returns(T::Array[String]) }
|
88
103
|
def target_frameworks(project_file:)
|
89
104
|
target_framework = details_for_property("TargetFramework", project_file)
|
90
|
-
return [target_framework
|
105
|
+
return [target_framework.fetch(:value)] if target_framework
|
91
106
|
|
92
107
|
target_frameworks = details_for_property("TargetFrameworks", project_file)
|
93
|
-
return target_frameworks
|
108
|
+
return target_frameworks.fetch(:value)&.split(";") if target_frameworks
|
94
109
|
|
95
110
|
target_framework = details_for_property("TargetFrameworkVersion", project_file)
|
96
111
|
return [] unless target_framework
|
97
112
|
|
98
113
|
# TargetFrameworkVersion is a string like "v4.7.2"
|
99
|
-
value = target_framework
|
114
|
+
value = target_framework.fetch(:value)
|
100
115
|
# convert it to a string like "net472"
|
101
116
|
["net#{value[1..-1].delete('.')}"]
|
102
117
|
end
|
103
118
|
|
119
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
104
120
|
def nuget_configs
|
105
121
|
dependency_files.select { |f| f.name.match?(%r{(^|/)nuget\.config$}i) }
|
106
122
|
end
|
107
123
|
|
108
124
|
private
|
109
125
|
|
110
|
-
|
126
|
+
sig { returns(T::Array[DependencyFile]) }
|
127
|
+
attr_reader :dependency_files
|
128
|
+
|
129
|
+
sig { returns(T::Array[Credential]) }
|
130
|
+
attr_reader :credentials
|
111
131
|
|
132
|
+
sig { params(project_file: DependencyFile, ref_path: String).returns(String) }
|
112
133
|
def full_path(project_file, ref_path)
|
113
134
|
project_file_directory = File.dirname(project_file.name)
|
114
135
|
is_rooted = project_file_directory.start_with?("/")
|
@@ -121,9 +142,13 @@ module Dependabot
|
|
121
142
|
relative_path = File.join(project_file_directory, relative_path)
|
122
143
|
result = File.expand_path(relative_path)
|
123
144
|
result = result[1..-1] unless is_rooted
|
124
|
-
result
|
145
|
+
T.must(result)
|
125
146
|
end
|
126
147
|
|
148
|
+
sig do
|
149
|
+
params(project_file: DependencyFile, visited_project_files: T.untyped)
|
150
|
+
.returns(Dependabot::FileParsers::Base::DependencySet)
|
151
|
+
end
|
127
152
|
def parse_dependencies(project_file, visited_project_files)
|
128
153
|
dependency_set = Dependabot::FileParsers::Base::DependencySet.new
|
129
154
|
|
@@ -152,6 +177,7 @@ module Dependabot
|
|
152
177
|
dependency_set
|
153
178
|
end
|
154
179
|
|
180
|
+
sig { params(dependency_set: Dependabot::FileParsers::Base::DependencySet).void }
|
155
181
|
def add_global_package_references(dependency_set)
|
156
182
|
project_import_files.each do |file|
|
157
183
|
doc = Nokogiri::XML(file.content)
|
@@ -169,11 +195,25 @@ module Dependabot
|
|
169
195
|
end
|
170
196
|
end
|
171
197
|
|
198
|
+
sig do
|
199
|
+
params(project_file: DependencyFile,
|
200
|
+
doc: Nokogiri::XML::Document,
|
201
|
+
dependency_set: Dependabot::FileParsers::Base::DependencySet,
|
202
|
+
visited_project_files: T::Set[String])
|
203
|
+
.void
|
204
|
+
end
|
172
205
|
def add_transitive_dependencies(project_file, doc, dependency_set, visited_project_files)
|
173
206
|
add_transitive_dependencies_from_packages(dependency_set)
|
174
207
|
add_transitive_dependencies_from_project_references(project_file, doc, dependency_set, visited_project_files)
|
175
208
|
end
|
176
209
|
|
210
|
+
sig do
|
211
|
+
params(project_file: DependencyFile,
|
212
|
+
doc: Nokogiri::XML::Document,
|
213
|
+
dependency_set: Dependabot::FileParsers::Base::DependencySet,
|
214
|
+
visited_project_files: T::Set[String])
|
215
|
+
.void
|
216
|
+
end
|
177
217
|
def add_transitive_dependencies_from_project_references(project_file, doc, dependency_set,
|
178
218
|
visited_project_files)
|
179
219
|
|
@@ -216,31 +256,33 @@ module Dependabot
|
|
216
256
|
end
|
217
257
|
end
|
218
258
|
|
219
|
-
sig { params(full_path:
|
259
|
+
sig { params(full_path: String).returns(T::Array[T.nilable(String)]) }
|
220
260
|
def expand_wildcards_in_project_reference_path(full_path)
|
221
|
-
full_path =
|
222
|
-
expanded_wildcard = Dir.glob(T.must(full_path))
|
223
|
-
|
224
|
-
filtered_paths = []
|
261
|
+
full_path = File.join(@repo_contents_path, full_path)
|
225
262
|
|
226
263
|
# For each expanded path, remove the @repo_contents_path prefix and leading slash
|
227
|
-
|
264
|
+
filtered_paths = Dir.glob(full_path).map do |path|
|
228
265
|
# Remove @repo_contents_path prefix
|
229
|
-
path = path.sub(@repo_contents_path, "")
|
266
|
+
path = path.sub(@repo_contents_path, "") if @repo_contents_path
|
230
267
|
# Remove leading slash
|
231
268
|
path = path[1..-1] if path.start_with?("/")
|
232
|
-
filtered_paths << path
|
233
269
|
path # Return the modified path
|
234
270
|
end
|
235
271
|
|
272
|
+
return filtered_paths if filtered_paths.any?
|
273
|
+
|
236
274
|
# If the wildcard didn't match anything, strip the @repo_contents_path prefix and return the original path.
|
237
|
-
|
275
|
+
full_path = full_path.sub(@repo_contents_path, "") if @repo_contents_path
|
276
|
+
full_path = full_path[1..-1] if full_path.start_with?("/")
|
277
|
+
[full_path]
|
238
278
|
end
|
239
279
|
|
280
|
+
sig { params(dependency_set: Dependabot::FileParsers::Base::DependencySet).void }
|
240
281
|
def add_transitive_dependencies_from_packages(dependency_set)
|
241
282
|
transitive_dependencies_from_packages(dependency_set.dependencies).each { |dep| dependency_set << dep }
|
242
283
|
end
|
243
284
|
|
285
|
+
sig { params(dependencies: T::Array[Dependency]).returns(T::Array[Dependency]) }
|
244
286
|
def transitive_dependencies_from_packages(dependencies)
|
245
287
|
transitive_dependencies = {}
|
246
288
|
|
@@ -261,6 +303,11 @@ module Dependabot
|
|
261
303
|
transitive_dependencies.values
|
262
304
|
end
|
263
305
|
|
306
|
+
sig do
|
307
|
+
params(doc: Nokogiri::XML::Document,
|
308
|
+
dependency_set: Dependabot::FileParsers::Base::DependencySet,
|
309
|
+
project_file: DependencyFile).void
|
310
|
+
end
|
264
311
|
def add_sdk_references(doc, dependency_set, project_file)
|
265
312
|
# These come in 3 flavours:
|
266
313
|
# - <Project Sdk="Name/Version">
|
@@ -273,8 +320,13 @@ module Dependabot
|
|
273
320
|
add_sdk_refs_from_import_tags(doc, dependency_set, project_file)
|
274
321
|
end
|
275
322
|
|
323
|
+
sig do
|
324
|
+
params(sdk_references: String,
|
325
|
+
dependency_set: Dependabot::FileParsers::Base::DependencySet,
|
326
|
+
project_file: DependencyFile).void
|
327
|
+
end
|
276
328
|
def add_sdk_ref_from_project(sdk_references, dependency_set, project_file)
|
277
|
-
sdk_references.split(";")
|
329
|
+
sdk_references.split(";").each do |sdk_reference|
|
278
330
|
m = sdk_reference.match(PROJECT_SDK_REGEX)
|
279
331
|
if m
|
280
332
|
dependency = build_dependency(m[1], m[2], m[2], nil, project_file)
|
@@ -283,6 +335,11 @@ module Dependabot
|
|
283
335
|
end
|
284
336
|
end
|
285
337
|
|
338
|
+
sig do
|
339
|
+
params(doc: Nokogiri::XML::Document,
|
340
|
+
dependency_set: Dependabot::FileParsers::Base::DependencySet,
|
341
|
+
project_file: DependencyFile).void
|
342
|
+
end
|
286
343
|
def add_sdk_refs_from_import_tags(doc, dependency_set, project_file)
|
287
344
|
doc.xpath("/Project/Import").each do |import_node|
|
288
345
|
next unless import_node.attribute("Sdk") && import_node.attribute("Version")
|
@@ -295,6 +352,11 @@ module Dependabot
|
|
295
352
|
end
|
296
353
|
end
|
297
354
|
|
355
|
+
sig do
|
356
|
+
params(doc: Nokogiri::XML::Document,
|
357
|
+
dependency_set: Dependabot::FileParsers::Base::DependencySet,
|
358
|
+
project_file: DependencyFile).void
|
359
|
+
end
|
298
360
|
def add_sdk_refs_from_project(doc, dependency_set, project_file)
|
299
361
|
doc.xpath("/Project").each do |project_node|
|
300
362
|
sdk_references = project_node.attribute("Sdk")&.value&.strip
|
@@ -304,6 +366,11 @@ module Dependabot
|
|
304
366
|
end
|
305
367
|
end
|
306
368
|
|
369
|
+
sig do
|
370
|
+
params(doc: Nokogiri::XML::Document,
|
371
|
+
dependency_set: Dependabot::FileParsers::Base::DependencySet,
|
372
|
+
project_file: DependencyFile).void
|
373
|
+
end
|
307
374
|
def add_sdk_refs_from_sdk_tags(doc, dependency_set, project_file)
|
308
375
|
doc.xpath("/Project/Sdk").each do |sdk_node|
|
309
376
|
next unless sdk_node.attribute("Version")
|
@@ -316,6 +383,15 @@ module Dependabot
|
|
316
383
|
end
|
317
384
|
end
|
318
385
|
|
386
|
+
sig do
|
387
|
+
params(name: T.nilable(String),
|
388
|
+
req: T.nilable(String),
|
389
|
+
version: T.nilable(String),
|
390
|
+
prop_name: T.nilable(String),
|
391
|
+
project_file: Dependabot::DependencyFile,
|
392
|
+
dev: T.untyped)
|
393
|
+
.returns(T.nilable(Dependabot::Dependency))
|
394
|
+
end
|
319
395
|
def build_dependency(name, req, version, prop_name, project_file, dev: false)
|
320
396
|
return unless name
|
321
397
|
|
@@ -350,6 +426,7 @@ module Dependabot
|
|
350
426
|
dependency
|
351
427
|
end
|
352
428
|
|
429
|
+
sig { params(dependency: Dependency).returns(T::Boolean) }
|
353
430
|
def dependency_has_search_results?(dependency)
|
354
431
|
dependency_urls = RepositoryFinder.new(
|
355
432
|
dependency: dependency,
|
@@ -362,11 +439,13 @@ module Dependabot
|
|
362
439
|
end
|
363
440
|
end
|
364
441
|
|
442
|
+
sig { params(dependency_name: String, dependency_url: T::Hash[Symbol, String]).returns(T.nilable(T::Boolean)) }
|
365
443
|
def dependency_url_has_matching_result?(dependency_name, dependency_url)
|
366
444
|
versions = NugetClient.get_package_versions(dependency_name, dependency_url)
|
367
445
|
versions&.any?
|
368
446
|
end
|
369
447
|
|
448
|
+
sig { params(dependency_node: Nokogiri::XML::Node, project_file: DependencyFile).returns(T.nilable(String)) }
|
370
449
|
def dependency_name(dependency_node, project_file)
|
371
450
|
raw_name = get_attribute_value(dependency_node, "Include") ||
|
372
451
|
get_attribute_value(dependency_node, "Update")
|
@@ -379,6 +458,7 @@ module Dependabot
|
|
379
458
|
evaluated_value(raw_name, project_file)
|
380
459
|
end
|
381
460
|
|
461
|
+
sig { params(dependency_node: Nokogiri::XML::Node, project_file: DependencyFile).returns(T.nilable(String)) }
|
382
462
|
def dependency_requirement(dependency_node, project_file)
|
383
463
|
raw_requirement = get_node_version_value(dependency_node) ||
|
384
464
|
find_package_version(dependency_node, project_file)
|
@@ -387,6 +467,7 @@ module Dependabot
|
|
387
467
|
evaluated_value(raw_requirement, project_file)
|
388
468
|
end
|
389
469
|
|
470
|
+
sig { params(dependency_node: Nokogiri::XML::Node, project_file: DependencyFile).returns(T.nilable(String)) }
|
390
471
|
def find_package_version(dependency_node, project_file)
|
391
472
|
name = dependency_name(dependency_node, project_file)
|
392
473
|
return unless name
|
@@ -397,28 +478,34 @@ module Dependabot
|
|
397
478
|
package_version_string
|
398
479
|
end
|
399
480
|
|
481
|
+
sig { returns(T::Hash[String, String]) }
|
400
482
|
def package_versions
|
401
|
-
@package_versions ||=
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
483
|
+
@package_versions ||= T.let(parse_package_versions, T.nilable(T::Hash[String, String]))
|
484
|
+
end
|
485
|
+
|
486
|
+
sig { returns(T::Hash[String, String]) }
|
487
|
+
def parse_package_versions
|
488
|
+
package_versions = T.let({}, T::Hash[String, String])
|
489
|
+
directory_packages_props_files.each do |file|
|
490
|
+
doc = Nokogiri::XML(file.content)
|
491
|
+
doc.remove_namespaces!
|
492
|
+
doc.css(PACKAGE_VERSION_SELECTOR).each do |package_node|
|
493
|
+
name = dependency_name(package_node, file)
|
494
|
+
version = dependency_version(package_node, file)
|
495
|
+
next unless name && version
|
496
|
+
|
497
|
+
package_versions[name] = version
|
413
498
|
end
|
414
|
-
package_versions
|
415
499
|
end
|
500
|
+
package_versions
|
416
501
|
end
|
417
502
|
|
503
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
418
504
|
def directory_packages_props_files
|
419
505
|
dependency_files.select { |df| df.name.match?(/[Dd]irectory.[Pp]ackages.props/) }
|
420
506
|
end
|
421
507
|
|
508
|
+
sig { params(dependency_node: Nokogiri::XML::Node, project_file: DependencyFile).returns(T.nilable(String)) }
|
422
509
|
def dependency_version(dependency_node, project_file)
|
423
510
|
requirement = dependency_requirement(dependency_node, project_file)
|
424
511
|
return unless requirement
|
@@ -434,22 +521,24 @@ module Dependabot
|
|
434
521
|
version
|
435
522
|
end
|
436
523
|
|
524
|
+
sig { params(dependency_node: Nokogiri::XML::Node).returns(T.nilable(String)) }
|
437
525
|
def req_property_name(dependency_node)
|
438
526
|
raw_requirement = get_node_version_value(dependency_node)
|
439
527
|
return unless raw_requirement
|
440
528
|
|
441
529
|
return unless raw_requirement.match?(PROPERTY_REGEX)
|
442
530
|
|
443
|
-
raw_requirement
|
444
|
-
|
445
|
-
.named_captures.fetch("property")
|
531
|
+
T.must(raw_requirement.match(PROPERTY_REGEX))
|
532
|
+
.named_captures.fetch("property")
|
446
533
|
end
|
447
534
|
|
535
|
+
sig { params(node: Nokogiri::XML::Node).returns(T.nilable(String)) }
|
448
536
|
def get_node_version_value(node)
|
449
537
|
get_attribute_value(node, "Version") || get_attribute_value(node, "VersionOverride")
|
450
538
|
end
|
451
539
|
|
452
540
|
# rubocop:disable Metrics/PerceivedComplexity
|
541
|
+
sig { params(node: Nokogiri::XML::Node, attribute: String).returns(T.nilable(String)) }
|
453
542
|
def get_attribute_value(node, attribute)
|
454
543
|
value =
|
455
544
|
node.attribute(attribute)&.value&.strip ||
|
@@ -461,20 +550,24 @@ module Dependabot
|
|
461
550
|
end
|
462
551
|
# rubocop:enable Metrics/PerceivedComplexity
|
463
552
|
|
553
|
+
sig { params(value: String, project_file: Dependabot::DependencyFile).returns(String) }
|
464
554
|
def evaluated_value(value, project_file)
|
465
555
|
return value unless value.match?(PROPERTY_REGEX)
|
466
556
|
|
467
|
-
property_name = value.match(PROPERTY_REGEX)
|
468
|
-
.named_captures.fetch("property")
|
557
|
+
property_name = T.must(value.match(PROPERTY_REGEX)&.named_captures&.fetch("property"))
|
469
558
|
property_details = details_for_property(property_name, project_file)
|
470
559
|
|
471
560
|
# Don't halt parsing for a missing property value until we're
|
472
561
|
# confident we're fetching property values correctly
|
473
562
|
return value unless property_details&.fetch(:value)
|
474
563
|
|
475
|
-
value.gsub(PROPERTY_REGEX, property_details
|
564
|
+
value.gsub(PROPERTY_REGEX, property_details.fetch(:value))
|
476
565
|
end
|
477
566
|
|
567
|
+
sig do
|
568
|
+
params(property_name: String, project_file: Dependabot::DependencyFile)
|
569
|
+
.returns(T.nilable(T::Hash[T.untyped, T.untyped]))
|
570
|
+
end
|
478
571
|
def details_for_property(property_name, project_file)
|
479
572
|
property_value_finder
|
480
573
|
.property_details(
|
@@ -483,11 +576,13 @@ module Dependabot
|
|
483
576
|
)
|
484
577
|
end
|
485
578
|
|
579
|
+
sig { returns(PropertyValueFinder) }
|
486
580
|
def property_value_finder
|
487
581
|
@property_value_finder ||=
|
488
|
-
PropertyValueFinder.new(dependency_files: dependency_files)
|
582
|
+
T.let(PropertyValueFinder.new(dependency_files: dependency_files), T.nilable(PropertyValueFinder))
|
489
583
|
end
|
490
584
|
|
585
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
491
586
|
def project_import_files
|
492
587
|
dependency_files -
|
493
588
|
project_files -
|
@@ -497,22 +592,26 @@ module Dependabot
|
|
497
592
|
[dotnet_tools_json]
|
498
593
|
end
|
499
594
|
|
595
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
500
596
|
def project_files
|
501
597
|
dependency_files.select { |f| f.name.match?(/\.[a-z]{2}proj$/) }
|
502
598
|
end
|
503
599
|
|
600
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
504
601
|
def packages_config_files
|
505
602
|
dependency_files.select do |f|
|
506
|
-
f.name.split("/").last
|
603
|
+
f.name.split("/").last&.casecmp("packages.config")&.zero?
|
507
604
|
end
|
508
605
|
end
|
509
606
|
|
607
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
510
608
|
def global_json
|
511
|
-
dependency_files.find { |f| f.name.casecmp("global.json")
|
609
|
+
dependency_files.find { |f| f.name.casecmp("global.json")&.zero? }
|
512
610
|
end
|
513
611
|
|
612
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
514
613
|
def dotnet_tools_json
|
515
|
-
dependency_files.find { |f| f.name.casecmp(".config/dotnet-tools.json")
|
614
|
+
dependency_files.find { |f| f.name.casecmp(".config/dotnet-tools.json")&.zero? }
|
516
615
|
end
|
517
616
|
end
|
518
617
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "dependabot/nuget/file_fetcher/import_paths_finder"
|
@@ -11,12 +11,21 @@ module Dependabot
|
|
11
11
|
module Nuget
|
12
12
|
class FileParser
|
13
13
|
class PropertyValueFinder
|
14
|
+
extend T::Sig
|
15
|
+
|
14
16
|
PROPERTY_REGEX = /\$\((?<property>.*?)\)/
|
15
17
|
|
18
|
+
sig { params(dependency_files: T::Array[Dependabot::DependencyFile]).void }
|
16
19
|
def initialize(dependency_files:)
|
17
20
|
@dependency_files = dependency_files
|
18
21
|
end
|
19
22
|
|
23
|
+
sig do
|
24
|
+
params(property_name: String,
|
25
|
+
callsite_file: Dependabot::DependencyFile,
|
26
|
+
stack: T::Array[[String, String]])
|
27
|
+
.returns(T.nilable(T::Hash[T.untyped, T.untyped]))
|
28
|
+
end
|
20
29
|
def property_details(property_name:, callsite_file:, stack: [])
|
21
30
|
stack += [[property_name, callsite_file.name]]
|
22
31
|
return if property_name.include?("(")
|
@@ -53,12 +62,18 @@ module Dependabot
|
|
53
62
|
check_next_level_of_stack(node_details, stack)
|
54
63
|
end
|
55
64
|
|
65
|
+
sig do
|
66
|
+
params(node_details: T.untyped,
|
67
|
+
stack: T::Array[[String, String]])
|
68
|
+
.returns(T.nilable(T::Hash[T.untyped, T.untyped]))
|
69
|
+
end
|
56
70
|
def check_next_level_of_stack(node_details, stack)
|
57
71
|
property_name = node_details.fetch(:value)
|
58
72
|
.match(PROPERTY_REGEX)
|
59
73
|
.named_captures.fetch("property")
|
60
74
|
callsite_file = dependency_files
|
61
75
|
.find { |f| f.name == node_details.fetch(:file) }
|
76
|
+
return unless callsite_file
|
62
77
|
|
63
78
|
raise "Circular reference!" if stack.include?([property_name, callsite_file.name])
|
64
79
|
|
@@ -71,8 +86,14 @@ module Dependabot
|
|
71
86
|
|
72
87
|
private
|
73
88
|
|
89
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
74
90
|
attr_reader :dependency_files
|
75
91
|
|
92
|
+
sig do
|
93
|
+
params(property: String,
|
94
|
+
file: Dependabot::DependencyFile)
|
95
|
+
.returns(T.nilable(T::Hash[Symbol, T.untyped]))
|
96
|
+
end
|
76
97
|
def deep_find_prop_node(property:, file:)
|
77
98
|
doc = Nokogiri::XML(file.content)
|
78
99
|
doc.remove_namespaces!
|
@@ -100,21 +121,34 @@ module Dependabot
|
|
100
121
|
deep_find_prop_node(property: property, file: file)
|
101
122
|
end
|
102
123
|
|
124
|
+
sig do
|
125
|
+
params(property: String, callsite_file: Dependabot::DependencyFile)
|
126
|
+
.returns(T.nilable(T::Hash[Symbol, T.untyped]))
|
127
|
+
end
|
103
128
|
def find_property_in_directory_build_targets(property:, callsite_file:)
|
104
129
|
find_property_in_up_tree_files(property: property, callsite_file: callsite_file,
|
105
130
|
expected_file_name: "Directory.Build.targets")
|
106
131
|
end
|
107
132
|
|
133
|
+
sig do
|
134
|
+
params(property: String, callsite_file: Dependabot::DependencyFile)
|
135
|
+
.returns(T.nilable(T::Hash[Symbol, T.untyped]))
|
136
|
+
end
|
108
137
|
def find_property_in_directory_build_props(property:, callsite_file:)
|
109
138
|
find_property_in_up_tree_files(property: property, callsite_file: callsite_file,
|
110
139
|
expected_file_name: "Directory.Build.props")
|
111
140
|
end
|
112
141
|
|
142
|
+
sig do
|
143
|
+
params(property: String, callsite_file: Dependabot::DependencyFile)
|
144
|
+
.returns(T.nilable(T::Hash[Symbol, T.untyped]))
|
145
|
+
end
|
113
146
|
def find_property_in_directory_packages_props(property:, callsite_file:)
|
114
147
|
find_property_in_up_tree_files(property: property, callsite_file: callsite_file,
|
115
148
|
expected_file_name: "Directory.Packages.props")
|
116
149
|
end
|
117
150
|
|
151
|
+
sig { params(property: String).returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
118
152
|
def find_property_in_packages_props(property:)
|
119
153
|
file = packages_props_file
|
120
154
|
return unless file
|
@@ -122,15 +156,25 @@ module Dependabot
|
|
122
156
|
deep_find_prop_node(property: property, file: file)
|
123
157
|
end
|
124
158
|
|
159
|
+
sig do
|
160
|
+
params(property: String,
|
161
|
+
callsite_file: Dependabot::DependencyFile,
|
162
|
+
expected_file_name: String)
|
163
|
+
.returns(T.untyped)
|
164
|
+
end
|
125
165
|
def find_property_in_up_tree_files(property:, callsite_file:, expected_file_name:)
|
126
166
|
files = up_tree_files_for_project(callsite_file, expected_file_name)
|
127
|
-
return unless files
|
128
167
|
return if files.empty?
|
129
168
|
|
130
169
|
# first file where we were able to find the node
|
131
|
-
files.reduce(nil)
|
170
|
+
files.reduce(T.let(nil, T.nilable(String))) do |acc, file|
|
171
|
+
acc || deep_find_prop_node(property: property, file: file)
|
172
|
+
end
|
132
173
|
end
|
133
174
|
|
175
|
+
sig do
|
176
|
+
params(project_file: DependencyFile, expected_file_name: String).returns(T::Array[Dependabot::DependencyFile])
|
177
|
+
end
|
134
178
|
def up_tree_files_for_project(project_file, expected_file_name)
|
135
179
|
dir = File.dirname(project_file.name)
|
136
180
|
|
@@ -142,21 +186,29 @@ module Dependabot
|
|
142
186
|
|
143
187
|
paths =
|
144
188
|
possible_paths.uniq
|
145
|
-
.select { |p| dependency_files.find { |f| f.name.casecmp(p)
|
189
|
+
.select { |p| dependency_files.find { |f| f.name.casecmp(p)&.zero? } }
|
146
190
|
|
147
191
|
dependency_files.select { |f| paths.include?(f.name) }
|
148
192
|
end
|
149
193
|
|
194
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
150
195
|
def packages_props_file
|
151
|
-
dependency_files.find { |f| f.name.casecmp("Packages.props")
|
196
|
+
dependency_files.find { |f| f.name.casecmp("Packages.props")&.zero? }
|
152
197
|
end
|
153
198
|
|
199
|
+
sig { params(property_name: String).returns(String) }
|
154
200
|
def property_xpath(property_name)
|
155
201
|
# only return properties that don't have a `Condition` attribute or the `Condition` attribute is checking for
|
156
202
|
# an empty string, e.g., Condition="$(SomeProperty) == ''"
|
157
203
|
%{/Project/PropertyGroup/#{property_name}[not(@Condition) or @Condition="$(#{property_name}) == ''"]}
|
158
204
|
end
|
159
205
|
|
206
|
+
sig do
|
207
|
+
params(file: DependencyFile,
|
208
|
+
node: Nokogiri::XML::Node,
|
209
|
+
property: String)
|
210
|
+
.returns(T::Hash[Symbol, T.untyped])
|
211
|
+
end
|
160
212
|
def node_details(file:, node:, property:)
|
161
213
|
{
|
162
214
|
file: file.name,
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strong
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "nokogiri"
|
@@ -77,14 +77,14 @@ module Dependabot
|
|
77
77
|
def global_json_dependencies
|
78
78
|
return DependencySet.new unless global_json
|
79
79
|
|
80
|
-
GlobalJsonParser.new(global_json: global_json).dependency_set
|
80
|
+
GlobalJsonParser.new(global_json: T.must(global_json)).dependency_set
|
81
81
|
end
|
82
82
|
|
83
83
|
sig { returns(Dependabot::FileParsers::Base::DependencySet) }
|
84
84
|
def dotnet_tools_json_dependencies
|
85
85
|
return DependencySet.new unless dotnet_tools_json
|
86
86
|
|
87
|
-
DotNetToolsJsonParser.new(dotnet_tools_json: dotnet_tools_json).dependency_set
|
87
|
+
DotNetToolsJsonParser.new(dotnet_tools_json: T.must(dotnet_tools_json)).dependency_set
|
88
88
|
end
|
89
89
|
|
90
90
|
sig { returns(Dependabot::Nuget::FileParser::ProjectFileParser) }
|