dependabot-nuget 0.246.0 → 0.248.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +40 -6
  3. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/PathHelper.cs +27 -0
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.Sdk.cs +18 -0
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +110 -0
  6. data/lib/dependabot/nuget/cache_manager.rb +9 -3
  7. data/lib/dependabot/nuget/file_fetcher/import_paths_finder.rb +15 -12
  8. data/lib/dependabot/nuget/file_fetcher/sln_project_paths_finder.rb +13 -3
  9. data/lib/dependabot/nuget/file_fetcher.rb +89 -37
  10. data/lib/dependabot/nuget/file_parser/dotnet_tools_json_parser.rb +10 -2
  11. data/lib/dependabot/nuget/file_parser/global_json_parser.rb +10 -2
  12. data/lib/dependabot/nuget/file_parser/packages_config_parser.rb +11 -2
  13. data/lib/dependabot/nuget/file_parser/project_file_parser.rb +140 -41
  14. data/lib/dependabot/nuget/file_parser/property_value_finder.rb +57 -5
  15. data/lib/dependabot/nuget/file_parser.rb +13 -3
  16. data/lib/dependabot/nuget/file_updater/property_value_updater.rb +25 -8
  17. data/lib/dependabot/nuget/file_updater.rb +74 -38
  18. data/lib/dependabot/nuget/http_response_helpers.rb +6 -1
  19. data/lib/dependabot/nuget/metadata_finder.rb +27 -3
  20. data/lib/dependabot/nuget/nuget_client.rb +23 -0
  21. data/lib/dependabot/nuget/nuget_config_credential_helpers.rb +10 -1
  22. data/lib/dependabot/nuget/requirement.rb +21 -9
  23. data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +26 -15
  24. data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +87 -21
  25. data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +25 -3
  26. data/lib/dependabot/nuget/update_checker/repository_finder.rb +25 -3
  27. data/lib/dependabot/nuget/update_checker/requirements_updater.rb +32 -9
  28. data/lib/dependabot/nuget/update_checker/tfm_finder.rb +2 -2
  29. data/lib/dependabot/nuget/update_checker/version_finder.rb +178 -64
  30. data/lib/dependabot/nuget/update_checker.rb +76 -32
  31. data/lib/dependabot/nuget/version.rb +7 -2
  32. metadata +19 -5
@@ -1,6 +1,8 @@
1
- # typed: false
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "sorbet-runtime"
5
+
4
6
  require "dependabot/nuget/version"
5
7
  require "dependabot/nuget/requirement"
6
8
  require "dependabot/update_checkers/base"
@@ -10,16 +12,33 @@ require "dependabot/nuget/nuget_client"
10
12
  module Dependabot
11
13
  module Nuget
12
14
  class UpdateChecker < Dependabot::UpdateCheckers::Base
15
+ # rubocop:disable Metrics/ClassLength
13
16
  class VersionFinder
17
+ extend T::Sig
18
+
14
19
  require_relative "compatibility_checker"
15
20
  require_relative "repository_finder"
16
21
 
17
22
  NUGET_RANGE_REGEX = /[\(\[].*,.*[\)\]]/
18
23
 
19
- def initialize(dependency:, dependency_files:, credentials:,
20
- ignored_versions:, raise_on_ignored: false,
24
+ sig do
25
+ params(
26
+ dependency: Dependabot::Dependency,
27
+ dependency_files: T::Array[Dependabot::DependencyFile],
28
+ credentials: T::Array[Dependabot::Credential],
29
+ ignored_versions: T::Array[String],
30
+ security_advisories: T::Array[Dependabot::SecurityAdvisory],
31
+ repo_contents_path: T.nilable(String),
32
+ raise_on_ignored: T::Boolean
33
+ ).void
34
+ end
35
+ def initialize(dependency:,
36
+ dependency_files:,
37
+ credentials:,
38
+ ignored_versions:,
21
39
  security_advisories:,
22
- repo_contents_path:)
40
+ repo_contents_path:,
41
+ raise_on_ignored: false)
23
42
  @dependency = dependency
24
43
  @dependency_files = dependency_files
25
44
  @credentials = credentials
@@ -29,53 +48,89 @@ module Dependabot
29
48
  @repo_contents_path = repo_contents_path
30
49
  end
31
50
 
51
+ sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
32
52
  def latest_version_details
33
53
  @latest_version_details ||=
34
- begin
35
- possible_versions = versions
36
- possible_versions = filter_prereleases(possible_versions)
37
- possible_versions = filter_ignored_versions(possible_versions)
38
-
39
- find_highest_compatible_version(possible_versions)
40
- end
54
+ T.let(
55
+ begin
56
+ possible_versions = versions
57
+ possible_versions = filter_prereleases(possible_versions)
58
+ possible_versions = filter_ignored_versions(possible_versions)
59
+
60
+ find_highest_compatible_version(possible_versions)
61
+ end,
62
+ T.nilable(T::Hash[Symbol, T.untyped])
63
+ )
41
64
  end
42
65
 
66
+ sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
43
67
  def lowest_security_fix_version_details
44
68
  @lowest_security_fix_version_details ||=
45
- begin
46
- possible_versions = versions
47
- possible_versions = filter_prereleases(possible_versions)
48
- possible_versions = Dependabot::UpdateCheckers::VersionFilters.filter_vulnerable_versions(
49
- possible_versions, security_advisories
50
- )
51
- possible_versions = filter_ignored_versions(possible_versions)
52
- possible_versions = filter_lower_versions(possible_versions)
53
-
54
- find_lowest_compatible_version(possible_versions)
55
- end
69
+ T.let(
70
+ begin
71
+ possible_versions = versions
72
+ possible_versions = filter_prereleases(possible_versions)
73
+ possible_versions = Dependabot::UpdateCheckers::VersionFilters.filter_vulnerable_versions(
74
+ possible_versions, security_advisories
75
+ )
76
+ possible_versions = filter_ignored_versions(possible_versions)
77
+ possible_versions = filter_lower_versions(possible_versions)
78
+
79
+ find_lowest_compatible_version(possible_versions)
80
+ end,
81
+ T.nilable(T::Hash[Symbol, T.untyped])
82
+ )
56
83
  end
57
84
 
85
+ sig { returns(T::Array[T::Hash[Symbol, T.nilable(T.any(Dependabot::Version, String))]]) }
58
86
  def versions
59
87
  available_v3_versions + available_v2_versions
60
88
  end
61
89
 
62
- attr_reader :dependency, :dependency_files, :credentials,
63
- :ignored_versions, :security_advisories, :repo_contents_path
90
+ sig { returns(Dependabot::Dependency) }
91
+ attr_reader :dependency
92
+
93
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
94
+ attr_reader :dependency_files
95
+
96
+ sig { returns(T::Array[Dependabot::Credential]) }
97
+ attr_reader :credentials
98
+
99
+ sig { returns(T::Array[String]) }
100
+ attr_reader :ignored_versions
101
+
102
+ sig { returns(T::Array[Dependabot::SecurityAdvisory]) }
103
+ attr_reader :security_advisories
104
+
105
+ sig { returns(T.nilable(String)) }
106
+ attr_reader :repo_contents_path
64
107
 
65
108
  private
66
109
 
110
+ sig do
111
+ params(possible_versions: T::Array[T::Hash[Symbol, T.untyped]])
112
+ .returns(T.nilable(T::Hash[Symbol, T.untyped]))
113
+ end
67
114
  def find_highest_compatible_version(possible_versions)
68
115
  # sorted versions descending
69
116
  sorted_versions = possible_versions.sort_by { |v| v.fetch(:version) }.reverse
70
117
  find_compatible_version(sorted_versions)
71
118
  end
72
119
 
120
+ sig do
121
+ params(possible_versions: T::Array[T::Hash[Symbol, T.untyped]])
122
+ .returns(T.nilable(T::Hash[Symbol, T.untyped]))
123
+ end
73
124
  def find_lowest_compatible_version(possible_versions)
74
125
  # sorted versions ascending
75
126
  sorted_versions = possible_versions.sort_by { |v| v.fetch(:version) }
76
127
  find_compatible_version(sorted_versions)
77
128
  end
78
129
 
130
+ sig do
131
+ params(sorted_versions: T::Array[T::Hash[Symbol, T.untyped]])
132
+ .returns(T.nilable(T::Hash[Symbol, T.untyped]))
133
+ end
79
134
  def find_compatible_version(sorted_versions)
80
135
  # By checking the first version separately, we can avoid additional network requests
81
136
  first_version = sorted_versions.first
@@ -89,33 +144,52 @@ module Dependabot
89
144
  sorted_versions.find { |v| version_compatible?(v.fetch(:version)) }
90
145
  end
91
146
 
147
+ sig { params(version: T.nilable(T.any(Dependabot::Version, String))).returns(T::Boolean) }
92
148
  def version_compatible?(version)
93
149
  str_version_compatible?(version.to_s)
94
150
  end
95
151
 
152
+ sig { params(version: String).returns(T::Boolean) }
96
153
  def str_version_compatible?(version)
97
154
  compatibility_checker.compatible?(version)
98
155
  end
99
156
 
157
+ sig { returns(Dependabot::Nuget::CompatibilityChecker) }
100
158
  def compatibility_checker
101
- @compatibility_checker ||= CompatibilityChecker.new(
102
- dependency_urls: dependency_urls,
103
- dependency: dependency,
104
- tfm_finder: TfmFinder.new(
105
- dependency_files: dependency_files,
106
- credentials: credentials,
107
- repo_contents_path: repo_contents_path
159
+ @compatibility_checker ||=
160
+ T.let(
161
+ CompatibilityChecker.new(
162
+ dependency_urls: dependency_urls,
163
+ dependency: dependency,
164
+ tfm_finder: TfmFinder.new(
165
+ dependency_files: dependency_files,
166
+ credentials: credentials,
167
+ repo_contents_path: repo_contents_path
168
+ )
169
+ ),
170
+ T.nilable(Dependabot::Nuget::CompatibilityChecker)
108
171
  )
109
- )
110
172
  end
111
173
 
174
+ sig do
175
+ params(possible_versions: T::Array[T::Hash[Symbol, T.untyped]])
176
+ .returns(T::Array[T::Hash[Symbol, T.untyped]])
177
+ end
112
178
  def filter_prereleases(possible_versions)
113
- possible_versions.reject do |d|
179
+ filtered = possible_versions.reject do |d|
114
180
  version = d.fetch(:version)
115
181
  version.prerelease? && !related_to_current_pre?(version)
116
182
  end
183
+ if possible_versions.count > filtered.count
184
+ Dependabot.logger.info("Filtered out #{possible_versions.count - filtered.count} pre-release versions")
185
+ end
186
+ filtered
117
187
  end
118
188
 
189
+ sig do
190
+ params(possible_versions: T::Array[T::Hash[Symbol, T.untyped]])
191
+ .returns(T::Array[T::Hash[Symbol, T.untyped]])
192
+ end
119
193
  def filter_ignored_versions(possible_versions)
120
194
  filtered = possible_versions
121
195
 
@@ -131,9 +205,17 @@ module Dependabot
131
205
  raise AllVersionsIgnored
132
206
  end
133
207
 
208
+ if possible_versions.count > filtered.count
209
+ Dependabot.logger.info("Filtered out #{possible_versions.count - filtered.count} ignored versions")
210
+ end
211
+
134
212
  filtered
135
213
  end
136
214
 
215
+ sig do
216
+ params(possible_versions: T::Array[T::Hash[Symbol, T.untyped]])
217
+ .returns(T::Array[T::Hash[Symbol, T.untyped]])
218
+ end
137
219
  def filter_lower_versions(possible_versions)
138
220
  return possible_versions unless dependency.numeric_version
139
221
 
@@ -142,12 +224,14 @@ module Dependabot
142
224
  end
143
225
  end
144
226
 
227
+ sig { params(string: String).returns(T::Array[String]) }
145
228
  def parse_requirement_string(string)
146
229
  return [string] if string.match?(NUGET_RANGE_REGEX)
147
230
 
148
231
  string.split(",").map(&:strip)
149
232
  end
150
233
 
234
+ sig { returns(T::Array[T::Hash[Symbol, T.any(Dependabot::Version, String, NilClass)]]) }
151
235
  def available_v3_versions
152
236
  v3_nuget_listings.flat_map do |listing|
153
237
  listing
@@ -168,6 +252,7 @@ module Dependabot
168
252
  end
169
253
  end
170
254
 
255
+ sig { returns(T::Array[T::Hash[Symbol, T.any(Dependabot::Version, String, NilClass)]]) }
171
256
  def available_v2_versions
172
257
  v2_nuget_listings.flat_map do |listing|
173
258
  body = listing.fetch("xml_body", [])
@@ -187,6 +272,10 @@ module Dependabot
187
272
  end
188
273
  end
189
274
 
275
+ sig do
276
+ params(entry: Nokogiri::XML::Element)
277
+ .returns(T::Hash[Symbol, T.any(Dependabot::Version, String, NilClass)])
278
+ end
190
279
  def dependency_details_from_v2_entry(entry)
191
280
  version = entry.at_xpath("./properties/Version").content.strip
192
281
  source_urls = []
@@ -208,10 +297,11 @@ module Dependabot
208
297
  end
209
298
 
210
299
  # rubocop:disable Metrics/PerceivedComplexity
300
+ sig { params(version: Dependabot::Version).returns(T::Boolean) }
211
301
  def related_to_current_pre?(version)
212
302
  current_version = dependency.numeric_version
213
303
  if current_version&.prerelease? &&
214
- current_version&.release == version.release
304
+ current_version.release == version.release
215
305
  return true
216
306
  end
217
307
 
@@ -229,40 +319,50 @@ module Dependabot
229
319
  false
230
320
  end
231
321
  end
232
-
233
322
  # rubocop:enable Metrics/PerceivedComplexity
234
323
 
324
+ sig { returns(T::Array[T::Hash[String, T.untyped]]) }
235
325
  def v3_nuget_listings
236
- return @v3_nuget_listings unless @v3_nuget_listings.nil?
237
-
238
326
  @v3_nuget_listings ||=
239
- dependency_urls
240
- .select { |details| details.fetch(:repository_type) == "v3" }
241
- .filter_map do |url_details|
242
- versions = NugetClient.get_package_versions(dependency.name, url_details)
243
- next unless versions
244
-
245
- { "versions" => versions, "listing_details" => url_details }
246
- end
327
+ T.let(
328
+ dependency_urls
329
+ .select { |details| details.fetch(:repository_type) == "v3" }
330
+ .filter_map do |url_details|
331
+ versions = NugetClient.get_package_versions(dependency.name, url_details)
332
+ next unless versions
333
+
334
+ { "versions" => versions, "listing_details" => url_details }
335
+ end,
336
+ T.nilable(T::Array[T::Hash[String, T.untyped]])
337
+ )
247
338
  end
248
339
 
340
+ sig { returns(T::Array[T::Hash[String, T.untyped]]) }
249
341
  def v2_nuget_listings
250
- return @v2_nuget_listings unless @v2_nuget_listings.nil?
251
-
252
342
  @v2_nuget_listings ||=
253
- dependency_urls
254
- .select { |details| details.fetch(:repository_type) == "v2" }
255
- .flat_map { |url_details| fetch_paginated_v2_nuget_listings(url_details) }
256
- .filter_map do |url_details, response|
257
- next unless response.status == 200
258
-
259
- {
260
- "xml_body" => response.body,
261
- "listing_details" => url_details
262
- }
263
- end
343
+ T.let(
344
+ dependency_urls
345
+ .select { |details| details.fetch(:repository_type) == "v2" }
346
+ .flat_map { |url_details| fetch_paginated_v2_nuget_listings(url_details) }
347
+ .filter_map do |url_details, response|
348
+ next unless response.status == 200
349
+
350
+ {
351
+ "xml_body" => response.body,
352
+ "listing_details" => url_details
353
+ }
354
+ end,
355
+ T.nilable(T::Array[T::Hash[String, T.untyped]])
356
+ )
264
357
  end
265
358
 
359
+ sig do
360
+ params(
361
+ url_details: T::Hash[Symbol, T.untyped],
362
+ results: T::Hash[T::Hash[Symbol, T.untyped], Excon::Response]
363
+ )
364
+ .returns(T::Array[T::Array[T.untyped]])
365
+ end
266
366
  def fetch_paginated_v2_nuget_listings(url_details, results = {})
267
367
  response = Dependabot::RegistryClient.get(
268
368
  url: url_details[:versions_url],
@@ -286,6 +386,7 @@ module Dependabot
286
386
  results.to_a
287
387
  end
288
388
 
389
+ sig { params(xml_body: String).returns(T.nilable(String)) }
289
390
  def fetch_v2_next_link_href(xml_body)
290
391
  doc = Nokogiri::XML(xml_body)
291
392
  doc.remove_namespaces!
@@ -298,32 +399,44 @@ module Dependabot
298
399
  nil
299
400
  end
300
401
 
402
+ sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
301
403
  def dependency_urls
302
404
  @dependency_urls ||=
303
- RepositoryFinder.new(
304
- dependency: dependency,
305
- credentials: credentials,
306
- config_files: nuget_configs
307
- ).dependency_urls
405
+ T.let(
406
+ RepositoryFinder.new(
407
+ dependency: dependency,
408
+ credentials: credentials,
409
+ config_files: nuget_configs
410
+ ).dependency_urls,
411
+ T.nilable(T::Array[T::Hash[Symbol, T.untyped]])
412
+ )
308
413
  end
309
414
 
415
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
310
416
  def nuget_configs
311
417
  @nuget_configs ||=
312
- dependency_files.select { |f| f.name.match?(/nuget\.config$/i) }
418
+ T.let(
419
+ dependency_files.select { |f| f.name.match?(/nuget\.config$/i) },
420
+ T.nilable(T::Array[Dependabot::DependencyFile])
421
+ )
313
422
  end
314
423
 
424
+ sig { returns(String) }
315
425
  def sanitized_name
316
426
  dependency.name.downcase
317
427
  end
318
428
 
429
+ sig { returns(T.class_of(Gem::Version)) }
319
430
  def version_class
320
431
  dependency.version_class
321
432
  end
322
433
 
434
+ sig { returns(T.class_of(Dependabot::Requirement)) }
323
435
  def requirement_class
324
436
  dependency.requirement_class
325
437
  end
326
438
 
439
+ sig { returns(T::Hash[Symbol, Integer]) }
327
440
  def excon_options
328
441
  # For large JSON files we sometimes need a little longer than for
329
442
  # other languages. For example, see:
@@ -336,6 +449,7 @@ module Dependabot
336
449
  }
337
450
  end
338
451
  end
452
+ # rubocop:enable Metrics/ClassLength
339
453
  end
340
454
  end
341
455
  end
@@ -1,55 +1,68 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "dependabot/nuget/file_parser"
5
5
  require "dependabot/update_checkers"
6
6
  require "dependabot/update_checkers/base"
7
+ require "sorbet-runtime"
7
8
 
8
9
  module Dependabot
9
10
  module Nuget
10
11
  class UpdateChecker < Dependabot::UpdateCheckers::Base
12
+ extend T::Sig
13
+
11
14
  require_relative "update_checker/version_finder"
12
15
  require_relative "update_checker/property_updater"
13
16
  require_relative "update_checker/requirements_updater"
14
17
  require_relative "update_checker/dependency_finder"
15
18
 
19
+ sig { override.returns(T.nilable(String)) }
16
20
  def latest_version
17
21
  # No need to find latest version for transitive dependencies unless they have a vulnerability.
18
22
  return dependency.version if !dependency.top_level? && !vulnerable?
19
23
 
20
- @latest_version = latest_version_details&.fetch(:version)
24
+ # if no update sources have the requisite package, then we can only assume that the current version is correct
25
+ @latest_version = T.let(
26
+ latest_version_details&.fetch(:version)&.to_s || dependency.version,
27
+ T.nilable(String)
28
+ )
21
29
  end
22
30
 
31
+ sig { override.returns(T.nilable(T.any(String, Gem::Version))) }
23
32
  def latest_resolvable_version
24
33
  # We always want a full unlock since any package update could update peer dependencies as well.
25
34
  # To force a full unlock instead of an own unlock, we return nil.
26
35
  nil
27
36
  end
28
37
 
38
+ sig { override.returns(Dependabot::Nuget::Version) }
29
39
  def lowest_security_fix_version
30
40
  lowest_security_fix_version_details&.fetch(:version)
31
41
  end
32
42
 
43
+ sig { override.returns(T.nilable(Dependabot::Version)) }
33
44
  def lowest_resolvable_security_fix_version
34
45
  return nil if version_comes_from_multi_dependency_property?
35
46
 
36
47
  lowest_security_fix_version
37
48
  end
38
49
 
50
+ sig { override.returns(NilClass) }
39
51
  def latest_resolvable_version_with_no_unlock
40
52
  # Irrelevant, since Nuget has a single dependency file
41
53
  nil
42
54
  end
43
55
 
56
+ sig { override.returns(T::Array[T::Hash[Symbol, T.untyped]]) }
44
57
  def updated_requirements
45
58
  RequirementsUpdater.new(
46
59
  requirements: dependency.requirements,
47
- latest_version: preferred_resolvable_version_details.fetch(:version)&.to_s,
48
- source_details: preferred_resolvable_version_details
49
- &.slice(:nuspec_url, :repo_url, :source_url)
60
+ latest_version: preferred_resolvable_version_details&.fetch(:version, nil)&.to_s,
61
+ source_details: preferred_resolvable_version_details&.slice(:nuspec_url, :repo_url, :source_url)
50
62
  ).updated_requirements
51
63
  end
52
64
 
65
+ sig { returns(T::Boolean) }
53
66
  def up_to_date?
54
67
  # No need to update transitive dependencies unless they have a vulnerability.
55
68
  return true if !dependency.top_level? && !vulnerable?
@@ -62,6 +75,7 @@ module Dependabot
62
75
  super
63
76
  end
64
77
 
78
+ sig { returns(T::Boolean) }
65
79
  def requirements_unlocked_or_can_be?
66
80
  # If any requirements have an uninterpolated property in them then
67
81
  # that property couldn't be found, and the requirement therefore
@@ -73,6 +87,7 @@ module Dependabot
73
87
 
74
88
  private
75
89
 
90
+ sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
76
91
  def preferred_resolvable_version_details
77
92
  # If this dependency is vulnerable, prefer trying to update to the
78
93
  # lowest_resolvable_security_fix_version. Otherwise update all the way
@@ -82,6 +97,7 @@ module Dependabot
82
97
  latest_version_details
83
98
  end
84
99
 
100
+ sig { override.returns(T::Boolean) }
85
101
  def latest_version_resolvable_with_full_unlock?
86
102
  # We always want a full unlock since any package update could update peer dependencies as well.
87
103
  return true unless version_comes_from_multi_dependency_property?
@@ -89,6 +105,7 @@ module Dependabot
89
105
  property_updater.update_possible?
90
106
  end
91
107
 
108
+ sig { override.returns(T::Array[Dependabot::Dependency]) }
92
109
  def updated_dependencies_after_full_unlock
93
110
  return property_updater.updated_dependencies if version_comes_from_multi_dependency_property?
94
111
 
@@ -96,7 +113,7 @@ module Dependabot
96
113
 
97
114
  updated_dependency = Dependency.new(
98
115
  name: dependency.name,
99
- version: latest_version&.to_s,
116
+ version: latest_version,
100
117
  requirements: updated_requirements,
101
118
  previous_version: dependency.version,
102
119
  previous_requirements: dependency.requirements,
@@ -112,47 +129,66 @@ module Dependabot
112
129
  updated_dependencies
113
130
  end
114
131
 
132
+ sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
115
133
  def preferred_version_details
116
134
  return lowest_security_fix_version_details if vulnerable?
117
135
 
118
136
  latest_version_details
119
137
  end
120
138
 
139
+ sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
121
140
  def latest_version_details
122
- @latest_version_details ||= version_finder.latest_version_details
141
+ @latest_version_details ||=
142
+ T.let(
143
+ version_finder.latest_version_details,
144
+ T.nilable(T::Hash[Symbol, T.untyped])
145
+ )
123
146
  end
124
147
 
148
+ sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
125
149
  def lowest_security_fix_version_details
126
150
  @lowest_security_fix_version_details ||=
127
- version_finder.lowest_security_fix_version_details
151
+ T.let(
152
+ version_finder.lowest_security_fix_version_details,
153
+ T.nilable(T::Hash[Symbol, T.untyped])
154
+ )
128
155
  end
129
156
 
157
+ sig { returns(Dependabot::Nuget::UpdateChecker::VersionFinder) }
130
158
  def version_finder
131
159
  @version_finder ||=
132
- VersionFinder.new(
133
- dependency: dependency,
134
- dependency_files: dependency_files,
135
- credentials: credentials,
136
- ignored_versions: ignored_versions,
137
- raise_on_ignored: @raise_on_ignored,
138
- security_advisories: security_advisories,
139
- repo_contents_path: @repo_contents_path
160
+ T.let(
161
+ VersionFinder.new(
162
+ dependency: dependency,
163
+ dependency_files: dependency_files,
164
+ credentials: credentials,
165
+ ignored_versions: ignored_versions,
166
+ raise_on_ignored: @raise_on_ignored,
167
+ security_advisories: security_advisories,
168
+ repo_contents_path: @repo_contents_path
169
+ ),
170
+ T.nilable(Dependabot::Nuget::UpdateChecker::VersionFinder)
140
171
  )
141
172
  end
142
173
 
174
+ sig { returns(Dependabot::Nuget::UpdateChecker::PropertyUpdater) }
143
175
  def property_updater
144
176
  @property_updater ||=
145
- PropertyUpdater.new(
146
- dependency: dependency,
147
- dependency_files: dependency_files,
148
- target_version_details: latest_version_details,
149
- credentials: credentials,
150
- ignored_versions: ignored_versions,
151
- raise_on_ignored: @raise_on_ignored,
152
- repo_contents_path: @repo_contents_path
177
+ T.let(
178
+ PropertyUpdater.new(
179
+ dependency: dependency,
180
+ dependency_files: dependency_files,
181
+ target_version_details: latest_version_details,
182
+ credentials: credentials,
183
+ ignored_versions: ignored_versions,
184
+ raise_on_ignored: @raise_on_ignored,
185
+ repo_contents_path: @repo_contents_path
186
+ ),
187
+ T.nilable(Dependabot::Nuget::UpdateChecker::PropertyUpdater)
153
188
  )
154
189
  end
155
190
 
191
+ sig { returns(T::Boolean) }
156
192
  def version_comes_from_multi_dependency_property?
157
193
  declarations_using_a_property.any? do |requirement|
158
194
  property_name = requirement.fetch(:metadata).fetch(:property_name)
@@ -167,20 +203,28 @@ module Dependabot
167
203
  end
168
204
  end
169
205
 
206
+ sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
170
207
  def declarations_using_a_property
171
208
  @declarations_using_a_property ||=
172
- dependency.requirements
173
- .select { |req| req.dig(:metadata, :property_name) }
209
+ T.let(
210
+ dependency.requirements
211
+ .select { |req| req.dig(:metadata, :property_name) },
212
+ T.nilable(T::Array[T::Hash[Symbol, T.untyped]])
213
+ )
174
214
  end
175
215
 
216
+ sig { returns(T::Array[Dependabot::Dependency]) }
176
217
  def all_property_based_dependencies
177
218
  @all_property_based_dependencies ||=
178
- Nuget::FileParser.new(
179
- dependency_files: dependency_files,
180
- source: nil
181
- ).parse.select do |dep|
182
- dep.requirements.any? { |req| req.dig(:metadata, :property_name) }
183
- end
219
+ T.let(
220
+ Nuget::FileParser.new(
221
+ dependency_files: dependency_files,
222
+ source: nil
223
+ ).parse.select do |dep|
224
+ dep.requirements.any? { |req| req.dig(:metadata, :property_name) }
225
+ end,
226
+ T.nilable(T::Array[Dependabot::Dependency])
227
+ )
184
228
  end
185
229
  end
186
230
  end
@@ -17,14 +17,14 @@ module Dependabot
17
17
  VERSION_PATTERN = T.let(Gem::Version::VERSION_PATTERN + '(\+[0-9a-zA-Z\-.]+)?', String)
18
18
  ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/
19
19
 
20
- sig { override.params(version: T.nilable(T.any(String, Integer, Float, Gem::Version))).returns(T::Boolean) }
20
+ sig { override.params(version: VersionParameter).returns(T::Boolean) }
21
21
  def self.correct?(version)
22
22
  return false if version.nil?
23
23
 
24
24
  version.to_s.match?(ANCHORED_VERSION_PATTERN)
25
25
  end
26
26
 
27
- sig { override.params(version: T.nilable(T.any(String, Integer, Float, Gem::Version))).void }
27
+ sig { override.params(version: VersionParameter).void }
28
28
  def initialize(version)
29
29
  version = version.to_s.split("+").first || ""
30
30
  @version_string = T.let(version, String)
@@ -32,6 +32,11 @@ module Dependabot
32
32
  super
33
33
  end
34
34
 
35
+ sig { override.params(version: VersionParameter).returns(Dependabot::Nuget::Version) }
36
+ def self.new(version)
37
+ T.cast(super, Dependabot::Nuget::Version)
38
+ end
39
+
35
40
  sig { returns(String) }
36
41
  def to_s
37
42
  @version_string