dependabot-nuget 0.289.0 → 0.291.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.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/lib/NuGetUpdater/Directory.Packages.props +1 -1
  3. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/AnalyzeCommand.cs +7 -3
  4. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli/Commands/RunCommand.cs +1 -1
  5. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Analyze.cs +26 -1
  6. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Discover.cs +2 -1
  7. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Run.cs +0 -6
  8. data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +1 -1
  9. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/AnalyzeWorker.cs +6 -1
  10. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/CompatabilityChecker.cs +24 -9
  11. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/DependencyFinder.cs +2 -0
  12. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/NuGetContext.cs +0 -13
  13. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Analyze/RequirementConverter.cs +17 -0
  14. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/DiscoveryWorker.cs +44 -5
  15. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/PackagesConfigDiscovery.cs +2 -2
  16. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/ProjectDiscoveryResult.cs +2 -0
  17. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Discover/SdkProjectDiscovery.cs +19 -11
  18. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ErrorType.cs +1 -0
  19. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/ExperimentsManager.cs +3 -0
  20. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Advisory.cs +13 -0
  21. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/AllowedUpdate.cs +18 -1
  22. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/CommitOptions.cs +8 -0
  23. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Condition.cs +19 -0
  24. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/DependencyGroup.cs +8 -0
  25. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/GroupPullRequest.cs +9 -0
  26. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/Job.cs +13 -10
  27. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/PullRequest.cs +11 -0
  28. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/ApiModel/RequirementsUpdateStrategy.cs +15 -0
  29. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/RunWorker.cs +24 -4
  30. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Run/VersionConverter.cs +19 -0
  31. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/BindingRedirectManager.cs +2 -1
  32. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/LockFileUpdater.cs +3 -2
  33. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackageReferenceUpdater.cs +43 -18
  34. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/PackagesConfigUpdater.cs +13 -12
  35. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/UpdaterWorker.cs +1 -1
  36. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/JsonHelper.cs +2 -0
  37. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +40 -14
  38. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/NuGetHelper.cs +2 -2
  39. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProcessExtensions.cs +45 -7
  40. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/ProjectHelper.cs +2 -2
  41. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Analyze/AnalyzeWorkerTestBase.cs +5 -2
  42. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.DotNetToolsJson.cs +45 -1
  43. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.GlobalJson.cs +35 -1
  44. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.Project.cs +0 -4
  45. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/DiscoveryWorkerTests.cs +41 -0
  46. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/ExpectedDiscoveryResults.cs +1 -0
  47. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Discover/SdkProjectDiscoveryTests.cs +1 -1
  48. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/MockNuGetPackage.cs +2 -1
  49. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/MiscellaneousTests.cs +85 -0
  50. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/RunWorkerTests.cs +7 -31
  51. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Run/SerializationTests.cs +340 -0
  52. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/TemporaryDirectory.cs +18 -7
  53. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/PackagesConfigUpdaterTests.cs +24 -0
  54. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTestBase.cs +0 -12
  55. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.DotNetTools.cs +84 -0
  56. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.GlobalJson.cs +66 -0
  57. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackageReference.cs +55 -0
  58. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Update/UpdateWorkerTests.PackagesConfig.cs +0 -6
  59. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/MSBuildHelperTests.cs +785 -755
  60. data/helpers/lib/NuGetUpdater/NuGetUpdater.Core.Test/Utilities/PathHelperTests.cs +2 -2
  61. data/lib/dependabot/nuget/analysis/analysis_json_reader.rb +1 -1
  62. data/lib/dependabot/nuget/analysis/dependency_analysis.rb +3 -3
  63. data/lib/dependabot/nuget/discovery/dependency_details.rb +10 -3
  64. data/lib/dependabot/nuget/discovery/dependency_file_discovery.rb +8 -12
  65. data/lib/dependabot/nuget/discovery/discovery_json_reader.rb +214 -29
  66. data/lib/dependabot/nuget/discovery/project_discovery.rb +41 -8
  67. data/lib/dependabot/nuget/discovery/workspace_discovery.rb +14 -19
  68. data/lib/dependabot/nuget/file_fetcher.rb +3 -3
  69. data/lib/dependabot/nuget/file_parser.rb +92 -3
  70. data/lib/dependabot/nuget/file_updater.rb +13 -13
  71. data/lib/dependabot/nuget/language.rb +82 -0
  72. data/lib/dependabot/nuget/native_helpers.rb +37 -5
  73. data/lib/dependabot/nuget/package_manager.rb +51 -0
  74. data/lib/dependabot/nuget/update_checker/requirements_updater.rb +23 -27
  75. data/lib/dependabot/nuget/update_checker.rb +116 -190
  76. metadata +20 -29
  77. data/lib/dependabot/nuget/discovery/directory_packages_props_discovery.rb +0 -43
  78. data/lib/dependabot/nuget/http_response_helpers.rb +0 -19
  79. data/lib/dependabot/nuget/native_discovery/native_dependency_details.rb +0 -102
  80. data/lib/dependabot/nuget/native_discovery/native_dependency_file_discovery.rb +0 -122
  81. data/lib/dependabot/nuget/native_discovery/native_discovery_json_reader.rb +0 -277
  82. data/lib/dependabot/nuget/native_discovery/native_evaluation_details.rb +0 -63
  83. data/lib/dependabot/nuget/native_discovery/native_project_discovery.rb +0 -104
  84. data/lib/dependabot/nuget/native_discovery/native_property_details.rb +0 -43
  85. data/lib/dependabot/nuget/native_discovery/native_workspace_discovery.rb +0 -61
  86. data/lib/dependabot/nuget/native_update_checker/native_requirements_updater.rb +0 -105
  87. data/lib/dependabot/nuget/native_update_checker/native_update_checker.rb +0 -214
  88. data/lib/dependabot/nuget/nuget_client.rb +0 -223
  89. data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +0 -116
  90. data/lib/dependabot/nuget/update_checker/dependency_finder.rb +0 -297
  91. data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +0 -221
  92. data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +0 -110
  93. data/lib/dependabot/nuget/update_checker/property_updater.rb +0 -196
  94. data/lib/dependabot/nuget/update_checker/repository_finder.rb +0 -466
  95. data/lib/dependabot/nuget/update_checker/tfm_comparer.rb +0 -34
  96. data/lib/dependabot/nuget/update_checker/tfm_finder.rb +0 -30
  97. data/lib/dependabot/nuget/update_checker/version_finder.rb +0 -449
@@ -1,449 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- require "sorbet-runtime"
5
-
6
- require "dependabot/nuget/version"
7
- require "dependabot/nuget/requirement"
8
- require "dependabot/update_checkers/base"
9
- require "dependabot/update_checkers/version_filters"
10
- require "dependabot/nuget/nuget_client"
11
-
12
- module Dependabot
13
- module Nuget
14
- class UpdateChecker < Dependabot::UpdateCheckers::Base
15
- # rubocop:disable Metrics/ClassLength
16
- class VersionFinder
17
- extend T::Sig
18
-
19
- require_relative "compatibility_checker"
20
- require_relative "repository_finder"
21
-
22
- NUGET_RANGE_REGEX = /[\(\[].*,.*[\)\]]/
23
-
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:,
39
- security_advisories:,
40
- repo_contents_path:,
41
- raise_on_ignored: false)
42
- @dependency = dependency
43
- @dependency_files = dependency_files
44
- @credentials = credentials
45
- @ignored_versions = ignored_versions
46
- @raise_on_ignored = raise_on_ignored
47
- @security_advisories = security_advisories
48
- @repo_contents_path = repo_contents_path
49
- end
50
-
51
- sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
52
- def latest_version_details
53
- @latest_version_details ||=
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
- )
64
- end
65
-
66
- sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
67
- def lowest_security_fix_version_details
68
- @lowest_security_fix_version_details ||=
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
- )
83
- end
84
-
85
- sig { returns(T::Array[T::Hash[Symbol, T.nilable(T.any(Dependabot::Version, String))]]) }
86
- def versions
87
- available_v3_versions + available_v2_versions
88
- end
89
-
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
107
-
108
- private
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
114
- def find_highest_compatible_version(possible_versions)
115
- # sorted versions descending
116
- sorted_versions = possible_versions.sort_by { |v| v.fetch(:version) }.reverse
117
- find_compatible_version(sorted_versions)
118
- end
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
124
- def find_lowest_compatible_version(possible_versions)
125
- # sorted versions ascending
126
- sorted_versions = possible_versions.sort_by { |v| v.fetch(:version) }
127
- find_compatible_version(sorted_versions)
128
- end
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
134
- def find_compatible_version(sorted_versions)
135
- # By checking the first version separately, we can avoid additional network requests
136
- first_version = sorted_versions.first
137
- return unless first_version
138
- # If the current package version is incompatible, then we don't enforce compatibility.
139
- # It could appear incompatible because they are ignoring NU1701 or the package is poorly authored.
140
- return first_version unless version_compatible?(dependency.version)
141
-
142
- # once sorted by version, the best we can do is search every package, because it's entirely possible for there
143
- # to be incompatible packages both with a higher and lower version number, so no smart searching can be done.
144
- sorted_versions.find { |v| version_compatible?(v.fetch(:version)) }
145
- end
146
-
147
- sig { params(version: T.nilable(T.any(Dependabot::Version, String))).returns(T::Boolean) }
148
- def version_compatible?(version)
149
- str_version_compatible?(version.to_s)
150
- end
151
-
152
- sig { params(version: String).returns(T::Boolean) }
153
- def str_version_compatible?(version)
154
- compatibility_checker.compatible?(version)
155
- end
156
-
157
- sig { returns(Dependabot::Nuget::CompatibilityChecker) }
158
- def compatibility_checker
159
- @compatibility_checker ||=
160
- T.let(
161
- CompatibilityChecker.new(
162
- dependency_urls: dependency_urls,
163
- dependency: dependency
164
- ),
165
- T.nilable(Dependabot::Nuget::CompatibilityChecker)
166
- )
167
- end
168
-
169
- sig do
170
- params(possible_versions: T::Array[T::Hash[Symbol, T.untyped]])
171
- .returns(T::Array[T::Hash[Symbol, T.untyped]])
172
- end
173
- def filter_prereleases(possible_versions)
174
- filtered = possible_versions.reject do |d|
175
- version = d.fetch(:version)
176
- version.prerelease? && !related_to_current_pre?(version)
177
- end
178
- if possible_versions.count > filtered.count
179
- Dependabot.logger.info("Filtered out #{possible_versions.count - filtered.count} pre-release versions")
180
- end
181
- filtered
182
- end
183
-
184
- sig do
185
- params(possible_versions: T::Array[T::Hash[Symbol, T.untyped]])
186
- .returns(T::Array[T::Hash[Symbol, T.untyped]])
187
- end
188
- def filter_ignored_versions(possible_versions)
189
- filtered = possible_versions
190
- ignored_versions.each do |req|
191
- ignore_reqs = parse_requirement_string(req).map { |r| requirement_class.new(r) }
192
- filtered =
193
- filtered
194
- .reject { |v| ignore_reqs.any? { |r| r.satisfied_by?(v.fetch(:version)) } }
195
- end
196
-
197
- if @raise_on_ignored && filter_lower_versions(filtered).empty? &&
198
- filter_lower_versions(possible_versions).any?
199
- raise AllVersionsIgnored
200
- end
201
-
202
- if possible_versions.count > filtered.count
203
- Dependabot.logger.info("Filtered out #{possible_versions.count - filtered.count} ignored versions")
204
- end
205
-
206
- filtered
207
- end
208
-
209
- sig do
210
- params(possible_versions: T::Array[T::Hash[Symbol, T.untyped]])
211
- .returns(T::Array[T::Hash[Symbol, T.untyped]])
212
- end
213
- def filter_lower_versions(possible_versions)
214
- return possible_versions unless dependency.numeric_version
215
-
216
- possible_versions.select do |v|
217
- v.fetch(:version) > dependency.numeric_version
218
- end
219
- end
220
-
221
- sig { params(string: String).returns(T::Array[String]) }
222
- def parse_requirement_string(string)
223
- return [string] if string.match?(NUGET_RANGE_REGEX)
224
-
225
- string.split(",").map(&:strip)
226
- end
227
-
228
- sig { returns(T::Array[T::Hash[Symbol, T.any(Dependabot::Version, String, NilClass)]]) }
229
- def available_v3_versions
230
- v3_nuget_listings.flat_map do |listing|
231
- listing
232
- .fetch("versions", [])
233
- .map do |v|
234
- listing_details = listing.fetch("listing_details")
235
- nuspec_url = listing_details
236
- .fetch(:versions_url, nil)
237
- &.gsub(/index\.json$/, "#{v}/#{sanitized_name}.nuspec")
238
-
239
- {
240
- version: version_class.new(v),
241
- nuspec_url: nuspec_url,
242
- source_url: nil,
243
- repo_url: listing_details.fetch(:repository_url)
244
- }
245
- end
246
- end
247
- end
248
-
249
- sig { returns(T::Array[T::Hash[Symbol, T.any(Dependabot::Version, String, NilClass)]]) }
250
- def available_v2_versions
251
- v2_nuget_listings.flat_map do |listing|
252
- body = listing.fetch("xml_body", [])
253
- doc = Nokogiri::XML(body)
254
- doc.remove_namespaces!
255
-
256
- doc.xpath("/feed/entry").filter_map do |entry|
257
- listed = entry.at_xpath("./properties/Listed")&.content&.strip
258
- next if listed&.casecmp("false")&.zero?
259
-
260
- entry_details = dependency_details_from_v2_entry(entry)
261
- entry_details.merge(
262
- repo_url: listing.fetch("listing_details")
263
- .fetch(:repository_url)
264
- )
265
- end
266
- end
267
- end
268
-
269
- sig do
270
- params(entry: Nokogiri::XML::Element)
271
- .returns(T::Hash[Symbol, T.any(Dependabot::Version, String, NilClass)])
272
- end
273
- def dependency_details_from_v2_entry(entry)
274
- version = entry.at_xpath("./properties/Version").content.strip
275
- source_urls = []
276
- [
277
- entry.at_xpath("./properties/ProjectUrl")&.content,
278
- entry.at_xpath("./properties/ReleaseNotes")&.content
279
- ].compact.join(" ").scan(Source::SOURCE_REGEX) do
280
- source_urls << Regexp.last_match.to_s
281
- end
282
-
283
- source_url = source_urls.find { |url| Source.from_url(url) }
284
- source_url = Source.from_url(source_url)&.url if source_url
285
-
286
- {
287
- version: version_class.new(version),
288
- nuspec_url: nil,
289
- source_url: source_url
290
- }
291
- end
292
-
293
- # rubocop:disable Metrics/PerceivedComplexity
294
- sig { params(version: Dependabot::Version).returns(T::Boolean) }
295
- def related_to_current_pre?(version)
296
- current_version = dependency.numeric_version
297
- if current_version&.prerelease? &&
298
- current_version.release == version.release
299
- return true
300
- end
301
-
302
- dependency.requirements.any? do |req|
303
- reqs = parse_requirement_string(req.fetch(:requirement) || "")
304
- return true if reqs.any?("*-*")
305
- next unless reqs.any? { |r| r.include?("-") }
306
-
307
- requirement_class
308
- .requirements_array(req.fetch(:requirement))
309
- .any? do |r|
310
- r.requirements.any? { |a| a.last.release == version.release }
311
- end
312
- rescue Gem::Requirement::BadRequirementError
313
- false
314
- end
315
- end
316
- # rubocop:enable Metrics/PerceivedComplexity
317
-
318
- sig { returns(T::Array[T::Hash[String, T.untyped]]) }
319
- def v3_nuget_listings
320
- @v3_nuget_listings ||=
321
- T.let(
322
- dependency_urls
323
- .select { |details| details.fetch(:repository_type) == "v3" }
324
- .filter_map do |url_details|
325
- versions = NugetClient.get_package_versions(dependency.name, url_details)
326
- next unless versions
327
-
328
- { "versions" => versions, "listing_details" => url_details }
329
- end,
330
- T.nilable(T::Array[T::Hash[String, T.untyped]])
331
- )
332
- end
333
-
334
- sig { returns(T::Array[T::Hash[String, T.untyped]]) }
335
- def v2_nuget_listings
336
- @v2_nuget_listings ||=
337
- T.let(
338
- dependency_urls
339
- .select { |details| details.fetch(:repository_type) == "v2" }
340
- .flat_map { |url_details| fetch_paginated_v2_nuget_listings(url_details) }
341
- .filter_map do |url_details, response|
342
- next unless response.status == 200
343
-
344
- {
345
- "xml_body" => response.body,
346
- "listing_details" => url_details
347
- }
348
- end,
349
- T.nilable(T::Array[T::Hash[String, T.untyped]])
350
- )
351
- end
352
-
353
- sig do
354
- params(
355
- url_details: T::Hash[Symbol, T.untyped],
356
- results: T::Hash[T::Hash[Symbol, T.untyped], Excon::Response]
357
- )
358
- .returns(T::Array[T::Array[T.untyped]])
359
- end
360
- def fetch_paginated_v2_nuget_listings(url_details, results = {})
361
- response = Dependabot::RegistryClient.get(
362
- url: url_details[:versions_url],
363
- headers: url_details[:auth_header]
364
- )
365
-
366
- # NOTE: Short circuit if we get a circular next link
367
- return results.to_a if results.key?(url_details)
368
-
369
- results[url_details] = response
370
-
371
- if (link_href = fetch_v2_next_link_href(response.body))
372
- url_details = url_details.dup
373
- # Some Nuget repositories, such as JFrog's Artifactory, URL encode the "next" href
374
- # link in the paged results. If the href is not URL decoded, the paging parameters
375
- # are ignored and the first page is always returned.
376
- url_details[:versions_url] = CGI.unescape(link_href)
377
- fetch_paginated_v2_nuget_listings(url_details, results)
378
- end
379
-
380
- results.to_a
381
- end
382
-
383
- sig { params(xml_body: String).returns(T.nilable(String)) }
384
- def fetch_v2_next_link_href(xml_body)
385
- doc = Nokogiri::XML(xml_body)
386
- doc.remove_namespaces!
387
- link_node = doc.xpath("/feed/link").find do |node|
388
- rel = node.attribute("rel").value.strip
389
- rel == "next"
390
- end
391
- link_node.attribute("href").value.strip if link_node
392
- rescue Nokogiri::XML::XPath::SyntaxError
393
- nil
394
- end
395
-
396
- sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
397
- def dependency_urls
398
- @dependency_urls ||=
399
- T.let(
400
- RepositoryFinder.new(
401
- dependency: dependency,
402
- credentials: credentials,
403
- config_files: nuget_configs
404
- ).dependency_urls,
405
- T.nilable(T::Array[T::Hash[Symbol, T.untyped]])
406
- )
407
- end
408
-
409
- sig { returns(T::Array[Dependabot::DependencyFile]) }
410
- def nuget_configs
411
- @nuget_configs ||=
412
- T.let(
413
- dependency_files.select { |f| f.name.match?(/nuget\.config$/i) },
414
- T.nilable(T::Array[Dependabot::DependencyFile])
415
- )
416
- end
417
-
418
- sig { returns(String) }
419
- def sanitized_name
420
- dependency.name.downcase
421
- end
422
-
423
- sig { returns(T.class_of(Gem::Version)) }
424
- def version_class
425
- dependency.version_class
426
- end
427
-
428
- sig { returns(T.class_of(Dependabot::Requirement)) }
429
- def requirement_class
430
- dependency.requirement_class
431
- end
432
-
433
- sig { returns(T::Hash[Symbol, Integer]) }
434
- def excon_options
435
- # For large JSON files we sometimes need a little longer than for
436
- # other languages. For example, see:
437
- # https://dotnet.myget.org/F/aspnetcore-dev/api/v3/query?
438
- # q=microsoft.aspnetcore.mvc&prerelease=true&semVerLevel=2.0.0
439
- {
440
- connect_timeout: 30,
441
- write_timeout: 30,
442
- read_timeout: 30
443
- }
444
- end
445
- end
446
- # rubocop:enable Metrics/ClassLength
447
- end
448
- end
449
- end