dependabot-nuget 0.238.0 → 0.240.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d913e6e79cd35b4a00551789e2d9fbea3a71476b76a12f64adfc3427cf419b1
4
- data.tar.gz: 103b3ed625f8a89133b2c53b6a49941826cf3663de6897e9baad943a78fa37c7
3
+ metadata.gz: 7d8152c074be84d639b86fe67da074f558ca1509102a5a1e9e97c3411178a747
4
+ data.tar.gz: 6562552b5b89ddfc8c521aeb7a52cf17e2d918c230439f70281663d5e8e45811
5
5
  SHA512:
6
- metadata.gz: c820263ed7825b8f7270693513d8ebab3ee73169318ca5113c75cad689887b5b42c1731fd6496e12033ba7a3ff0d3a59752b7bc512e64ae93baf4a520d485a83
7
- data.tar.gz: 7ce94d621ef880f809124364816e19aa8cb1fe1975967d8eb907cf40b1573ff2c3fe4c8fad91631f5f545433813252736c3c1db17228366dea8950f0ab50ac9a
6
+ metadata.gz: 6d91dec9cd6d5db739507bfc91d6454b6f21426a60a2086bd7b944922d4fa123886dbb1037a94b712471deeb89d175c1b0f10a2b84aeb7f6810f3aeddb92eecb
7
+ data.tar.gz: 7dbe0cacc3ffaa2d9290e09da5026a94432b8f45b839c6db49905b40636188c0201b61f6650aa1a01fa36fe590672b3e0359b8d4139d1bfe26d98dac344b494a
@@ -13,6 +13,8 @@ module Dependabot
13
13
  end
14
14
 
15
15
  def self.cache(name)
16
+ return {} if caching_disabled?
17
+
16
18
  @cache ||= {}
17
19
  @cache[name] ||= {}
18
20
  @cache[name]
@@ -3,6 +3,7 @@
3
3
 
4
4
  require "dependabot/file_fetchers"
5
5
  require "dependabot/file_fetchers/base"
6
+ require "dependabot/nuget/cache_manager"
6
7
  require "set"
7
8
  require "sorbet-runtime"
8
9
 
@@ -23,19 +24,17 @@ module Dependabot
23
24
  return true if filenames.any? { |f| f.match?("^src$") }
24
25
  return true if filenames.any? { |f| f.end_with?(".proj") }
25
26
 
26
- filenames.any? { |name| name.match?(%r{^[^/]*\.[a-z]{2}proj$}) }
27
+ filenames.any? { |name| name.match?(/\.[a-z]{2}proj$/) }
27
28
  end
28
29
 
29
30
  def self.required_files_message
30
31
  "Repo must contain a .proj file, .(cs|vb|fs)proj file, or a packages.config."
31
32
  end
32
33
 
33
- # rubocop:disable Metrics/AbcSize
34
34
  sig { override.returns(T::Array[DependencyFile]) }
35
35
  def fetch_files
36
36
  fetched_files = []
37
37
  fetched_files += project_files
38
- fetched_files += project_files.filter_map { |f| directory_packages_props_file_from_project_file(f) }
39
38
  fetched_files += directory_build_files
40
39
  fetched_files += imported_property_files
41
40
 
@@ -47,7 +46,7 @@ module Dependabot
47
46
 
48
47
  # dedup files based on their absolute path
49
48
  fetched_files = fetched_files.uniq do |fetched_file|
50
- Pathname.new(File.join(fetched_file.directory, fetched_file.name)).cleanpath.to_path
49
+ Pathname.new(fetched_file.directory).join(fetched_file.name).cleanpath.to_path
51
50
  end
52
51
 
53
52
  if project_files.none? && packages_config_files.none?
@@ -61,7 +60,6 @@ module Dependabot
61
60
 
62
61
  fetched_files
63
62
  end
64
- # rubocop:enable Metrics/AbcSize
65
63
 
66
64
  private
67
65
 
@@ -72,8 +70,9 @@ module Dependabot
72
70
  project_files += csproj_file
73
71
  project_files += vbproj_file
74
72
  project_files += fsproj_file
75
-
76
73
  project_files += sln_project_files
74
+ project_files += proj_files
75
+ project_files += project_files.filter_map { |f| directory_packages_props_file_from_project_file(f) }
77
76
  project_files
78
77
  end
79
78
  rescue Octokit::NotFound, Gitlab::Error::NotFound
@@ -120,22 +119,15 @@ module Dependabot
120
119
  @directory_build_files ||= fetch_directory_build_files
121
120
  end
122
121
 
123
- # rubocop:disable Metrics/AbcSize
124
122
  def fetch_directory_build_files
125
123
  attempted_dirs = []
126
124
  directory_build_files = []
127
125
  directory_path = Pathname.new(directory)
128
126
 
129
127
  # find all build files (Directory.Build.props/.targets) relative to the given project file
130
- project_files.map { |f| File.dirname(File.join(f.directory, f.name)) }.uniq.each do |dir|
128
+ project_files.map { |f| Pathname.new(f.directory).join(f.name).dirname }.uniq.each do |dir|
131
129
  # Simulate MSBuild walking up the directory structure looking for a file
132
- possible_dirs = dir.split("/").map.with_index do |_, i|
133
- candidate_dir = dir.split("/").first(i + 1).join("/")
134
- candidate_dir = "/#{candidate_dir}" unless candidate_dir.start_with?("/")
135
- candidate_dir
136
- end.reverse
137
-
138
- possible_dirs.each do |possible_dir|
130
+ dir.descend.each do |possible_dir|
139
131
  break if attempted_dirs.include?(possible_dir)
140
132
 
141
133
  attempted_dirs << possible_dir
@@ -150,7 +142,6 @@ module Dependabot
150
142
 
151
143
  directory_build_files
152
144
  end
153
- # rubocop:enable Metrics/AbcSize
154
145
 
155
146
  def sln_project_files
156
147
  return [] unless sln_files
@@ -196,18 +187,21 @@ module Dependabot
196
187
  @fsproj_file ||= find_and_fetch_with_suffix(".fsproj")
197
188
  end
198
189
 
190
+ def proj_files
191
+ @proj_files ||= find_and_fetch_with_suffix(".proj")
192
+ end
193
+
199
194
  def directory_packages_props_file_from_project_file(project_file)
200
195
  # walk up the tree from each project file stopping at the first `Directory.Packages.props` file found
201
196
  # https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management#central-package-management-rules
202
197
 
203
198
  found_directory_packages_props_file = nil
204
199
  directory_path = Pathname.new(directory)
205
- full_project_dir = File.dirname(File.join(project_file.directory, project_file.name))
206
- full_project_dir.split("/").each.with_index do |_, i|
200
+ full_project_dir = Pathname.new(project_file.directory).join(project_file.name).dirname
201
+ full_project_dir.ascend.each do |base|
207
202
  break if found_directory_packages_props_file
208
203
 
209
- base = full_project_dir.split("/").first(i + 1).join("/")
210
- candidate_file_path = Pathname.new(base + "/Directory.Packages.props").cleanpath.to_path
204
+ candidate_file_path = Pathname.new(base).join("Directory.Packages.props").cleanpath.to_path
211
205
  candidate_directory = Pathname.new(File.dirname(candidate_file_path))
212
206
  relative_candidate_directory = candidate_directory.relative_path_from(directory_path)
213
207
  candidate_file = repo_contents(dir: relative_candidate_directory).find do |f|
@@ -226,29 +220,32 @@ module Dependabot
226
220
  def nuget_config_files
227
221
  return @nuget_config_files if @nuget_config_files
228
222
 
229
- @nuget_config_files = []
230
- candidate_paths = [*project_files.map { |f| File.dirname(f.name) }, "."].uniq
231
- visited_directories = Set.new
232
- candidate_paths.each do |dir|
233
- search_in_directory_and_parents(dir, visited_directories)
234
- end
223
+ @nuget_config_files = [*project_files.map do |f|
224
+ named_file_up_tree_from_project_file(f, "nuget.config")
225
+ end].compact.uniq
235
226
  @nuget_config_files
236
227
  end
237
228
 
238
- def search_in_directory_and_parents(dir, visited_directories)
239
- loop do
240
- break if visited_directories.include?(dir)
241
-
242
- visited_directories << dir
243
- file = repo_contents(dir: dir)
244
- .find { |f| f.name.casecmp("nuget.config").zero? }
245
- if file
246
- file = fetch_file_from_host(File.join(dir, file.name))
247
- file&.tap { |f| f.support_file = true }
248
- @nuget_config_files << file
229
+ def named_file_up_tree_from_project_file(project_file, expected_file_name)
230
+ found_expected_file = nil
231
+ directory_path = Pathname.new(directory)
232
+ full_project_dir = Pathname.new(project_file.directory).join(project_file.name).dirname
233
+ full_project_dir.ascend.each do |base|
234
+ break if found_expected_file
235
+
236
+ candidate_file_path = Pathname.new(base).join(expected_file_name).cleanpath.to_path
237
+ candidate_directory = Pathname.new(File.dirname(candidate_file_path))
238
+ relative_candidate_directory = candidate_directory.relative_path_from(directory_path)
239
+ candidate_file = repo_contents(dir: relative_candidate_directory).find do |f|
240
+ f.name.casecmp?(expected_file_name)
241
+ end
242
+ if candidate_file
243
+ found_expected_file = fetch_file_from_host(File.join(relative_candidate_directory,
244
+ candidate_file.name))
249
245
  end
250
- dir = File.dirname(dir)
251
246
  end
247
+
248
+ found_expected_file
252
249
  end
253
250
 
254
251
  def global_json
@@ -287,27 +284,34 @@ module Dependabot
287
284
  end
288
285
 
289
286
  def fetch_imported_property_files(file:, previously_fetched_files:)
290
- paths =
291
- ImportPathsFinder.new(project_file: file).import_paths +
292
- ImportPathsFinder.new(project_file: file).project_reference_paths +
293
- ImportPathsFinder.new(project_file: file).project_file_paths
294
-
295
- paths.flat_map do |path|
296
- next if previously_fetched_files.map(&:name).include?(path)
297
- next if file.name == path
298
- next if path.include?("$(")
299
-
300
- fetched_file = fetch_file_from_host(path)
301
- grandchild_property_files = fetch_imported_property_files(
302
- file: fetched_file,
303
- previously_fetched_files: previously_fetched_files + [file]
304
- )
305
- [fetched_file, *grandchild_property_files]
306
- rescue Dependabot::DependencyFileNotFound
307
- # Don't worry about missing files too much for now (at least
308
- # until we start resolving properties)
309
- nil
310
- end.compact
287
+ file_id = file.directory + "/" + file.name
288
+ @fetched_files ||= {}
289
+ if @fetched_files[file_id]
290
+ @fetched_files[file_id]
291
+ else
292
+ paths =
293
+ ImportPathsFinder.new(project_file: file).import_paths +
294
+ ImportPathsFinder.new(project_file: file).project_reference_paths +
295
+ ImportPathsFinder.new(project_file: file).project_file_paths
296
+
297
+ paths.flat_map do |path|
298
+ next if previously_fetched_files.map(&:name).include?(path)
299
+ next if file.name == path
300
+ next if path.include?("$(")
301
+
302
+ fetched_file = fetch_file_from_host(path)
303
+ grandchild_property_files = fetch_imported_property_files(
304
+ file: fetched_file,
305
+ previously_fetched_files: previously_fetched_files + [file]
306
+ )
307
+ @fetched_files[file_id] = [fetched_file, *grandchild_property_files]
308
+ @fetched_files[file_id]
309
+ rescue Dependabot::DependencyFileNotFound
310
+ # Don't worry about missing files too much for now (at least
311
+ # until we start resolving properties)
312
+ nil
313
+ end.compact
314
+ end
311
315
  end
312
316
  end
313
317
  end
@@ -26,16 +26,10 @@ module Dependabot
26
26
  end
27
27
 
28
28
  def dependency_set
29
- return parse_dependencies if CacheManager.caching_disabled?
30
-
31
29
  key = "#{packages_config.name.downcase}::#{packages_config.content.hash}"
32
30
  cache = PackagesConfigParser.dependency_set_cache
33
31
 
34
32
  cache[key] ||= parse_dependencies
35
-
36
- dependency_set = Dependabot::FileParsers::Base::DependencySet.new
37
- dependency_set += cache[key]
38
- dependency_set
39
33
  end
40
34
 
41
35
  private
@@ -7,13 +7,13 @@ require "dependabot/dependency"
7
7
  require "dependabot/nuget/file_parser"
8
8
  require "dependabot/nuget/update_checker"
9
9
  require "dependabot/nuget/cache_manager"
10
+ require "dependabot/nuget/nuget_client"
10
11
 
11
12
  # For details on how dotnet handles version constraints, see:
12
13
  # https://docs.microsoft.com/en-us/nuget/reference/package-versioning
13
14
  module Dependabot
14
15
  module Nuget
15
16
  class FileParser
16
- # rubocop:disable Metrics/ClassLength
17
17
  class ProjectFileParser
18
18
  require "dependabot/file_parsers/base/dependency_set"
19
19
  require_relative "property_value_finder"
@@ -50,16 +50,10 @@ module Dependabot
50
50
  end
51
51
 
52
52
  def dependency_set(project_file:)
53
- return parse_dependencies(project_file) if CacheManager.caching_disabled?
54
-
55
53
  key = "#{project_file.name.downcase}::#{project_file.content.hash}"
56
54
  cache = ProjectFileParser.dependency_set_cache
57
55
 
58
56
  cache[key] ||= parse_dependencies(project_file)
59
-
60
- dependency_set = Dependabot::FileParsers::Base::DependencySet.new
61
- dependency_set += cache[key]
62
- dependency_set
63
57
  end
64
58
 
65
59
  def target_frameworks(project_file:)
@@ -78,6 +72,10 @@ module Dependabot
78
72
  ["net#{value[1..-1].delete('.')}"]
79
73
  end
80
74
 
75
+ def nuget_configs
76
+ dependency_files.select { |f| f.name.match?(%r{(^|/)nuget\.config$}i) }
77
+ end
78
+
81
79
  private
82
80
 
83
81
  attr_reader :dependency_files, :credentials
@@ -281,7 +279,6 @@ module Dependabot
281
279
  end
282
280
 
283
281
  def dependency_has_search_results?(dependency)
284
- nuget_configs = dependency_files.select { |f| f.name.casecmp?("nuget.config") }
285
282
  dependency_urls = UpdateChecker::RepositoryFinder.new(
286
283
  dependency: dependency,
287
284
  credentials: credentials,
@@ -307,16 +304,9 @@ module Dependabot
307
304
  end
308
305
 
309
306
  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?
307
+ versions = NugetClient.get_package_versions_v3(dependency_name, dependency_url)
318
308
 
319
- data.any? { |result| result["id"].casecmp?(dependency_name) }
309
+ versions != nil
320
310
  end
321
311
 
322
312
  def dependency_url_has_matching_result_v2?(dependency_name, dependency_url)
@@ -490,10 +480,6 @@ module Dependabot
490
480
  end
491
481
  end
492
482
 
493
- def nuget_configs
494
- dependency_files.select { |f| f.name.match?(/nuget\.config$/i) }
495
- end
496
-
497
483
  def global_json
498
484
  dependency_files.find { |f| f.name.casecmp("global.json").zero? }
499
485
  end
@@ -502,7 +488,6 @@ module Dependabot
502
488
  dependency_files.find { |f| f.name.casecmp(".config/dotnet-tools.json").zero? }
503
489
  end
504
490
  end
505
- # rubocop:enable Metrics/ClassLength
506
491
  end
507
492
  end
508
493
  end
@@ -74,7 +74,7 @@ module Dependabot
74
74
  end
75
75
 
76
76
  def project_files
77
- projfile = /\.[a-z]{2}proj$/
77
+ projfile = /\.([a-z]{2})?proj$/
78
78
  packageprops = /[Dd]irectory.[Pp]ackages.props/
79
79
 
80
80
  dependency_files.select do |df|
@@ -62,7 +62,9 @@ module Dependabot
62
62
 
63
63
  next unless project_dependencies.any? { |dep| dep.name.casecmp(dependency.name).zero? }
64
64
 
65
- NativeHelpers.run_nuget_updater_tool(repo_contents_path, proj_path, dependency, !dependency.top_level?)
65
+ NativeHelpers.run_nuget_updater_tool(repo_root: repo_contents_path, proj_path: proj_path,
66
+ dependency: dependency, is_transitive: !dependency.top_level?,
67
+ credentials: credentials)
66
68
  update_ran = true
67
69
  end
68
70
 
@@ -77,7 +79,9 @@ module Dependabot
77
79
  project_file = project_files.first
78
80
  proj_path = dependency_file_path(project_file)
79
81
 
80
- NativeHelpers.run_nuget_updater_tool(repo_contents_path, proj_path, dependency, !dependency.top_level?)
82
+ NativeHelpers.run_nuget_updater_tool(repo_root: repo_contents_path, proj_path: proj_path,
83
+ dependency: dependency, is_transitive: !dependency.top_level?,
84
+ credentials: credentials)
81
85
  return true
82
86
  end
83
87
 
@@ -1,6 +1,8 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
+ require_relative "nuget_config_credential_helpers"
5
+
4
6
  module Dependabot
5
7
  module Nuget
6
8
  module NativeHelpers
@@ -46,7 +48,7 @@ module Dependabot
46
48
  end
47
49
 
48
50
  # rubocop:disable Metrics/MethodLength
49
- def self.run_nuget_updater_tool(repo_root, proj_path, dependency, is_transitive)
51
+ def self.run_nuget_updater_tool(repo_root:, proj_path:, dependency:, is_transitive:, credentials:)
50
52
  exe_path = File.join(native_helpers_root, "NuGetUpdater", "NuGetUpdater.Cli")
51
53
  command = [
52
54
  exe_path,
@@ -84,9 +86,10 @@ module Dependabot
84
86
 
85
87
  puts "running NuGet updater:\n" + command
86
88
 
87
- output = SharedHelpers.run_shell_command(command, fingerprint: fingerprint)
88
-
89
- puts output
89
+ NuGetConfigCredentialHelpers.patch_nuget_config_for_action(credentials) do
90
+ output = SharedHelpers.run_shell_command(command, fingerprint: fingerprint)
91
+ puts output
92
+ end
90
93
  end
91
94
  # rubocop:enable Metrics/MethodLength
92
95
  end
@@ -0,0 +1,99 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require "dependabot/nuget/cache_manager"
5
+ require "dependabot/nuget/update_checker/repository_finder"
6
+
7
+ module Dependabot
8
+ module Nuget
9
+ class NugetClient
10
+ def self.get_package_versions_v3(dependency_name, repository_details)
11
+ # Use the registration URL if possible because it is fast and correct
12
+ if repository_details[:registration_url]
13
+ get_versions_from_registration_v3(repository_details)
14
+ # use the search API if not because it is slow but correct
15
+ elsif repository_details[:search_url]
16
+ get_versions_from_search_url_v3(repository_details, dependency_name)
17
+ # Otherwise, use the versions URL (fast but wrong because it includes unlisted versions)
18
+ elsif repository_details[:versions_url]
19
+ get_versions_from_versions_url_v3(repository_details)
20
+ end
21
+ end
22
+
23
+ private_class_method def self.get_versions_from_versions_url_v3(repository_details)
24
+ body = execute_search_for_dependency_url(repository_details[:versions_url], repository_details)
25
+ body&.fetch("versions")
26
+ end
27
+
28
+ private_class_method def self.get_versions_from_registration_v3(repository_details)
29
+ url = repository_details[:registration_url]
30
+ body = execute_search_for_dependency_url(url, repository_details)
31
+
32
+ return unless body
33
+
34
+ pages = body.fetch("items")
35
+ versions = Set.new
36
+ pages.each do |page|
37
+ items = page["items"]
38
+ if items
39
+ # inlined entries
40
+ items.each do |item|
41
+ catalog_entry = item["catalogEntry"]
42
+ if catalog_entry["listed"] == true
43
+ vers = catalog_entry["version"]
44
+ versions << vers
45
+ end
46
+ end
47
+ else
48
+ # paged entries
49
+ page_url = page["@id"]
50
+ page_body = execute_search_for_dependency_url(page_url, repository_details)
51
+ items = page_body.fetch("items")
52
+ items.each do |item|
53
+ catalog_entry = item.fetch("catalogEntry")
54
+ versions << catalog_entry.fetch("version") if catalog_entry["listed"] == true
55
+ end
56
+ end
57
+ end
58
+
59
+ versions
60
+ end
61
+
62
+ private_class_method def self.get_versions_from_search_url_v3(repository_details, dependency_name)
63
+ search_url = repository_details[:search_url]
64
+ body = execute_search_for_dependency_url(search_url, repository_details)
65
+
66
+ body&.fetch("data")
67
+ &.find { |d| d.fetch("id").casecmp(dependency_name.downcase).zero? }
68
+ &.fetch("versions")
69
+ &.map { |d| d.fetch("version") }
70
+ end
71
+
72
+ private_class_method def self.execute_search_for_dependency_url(url, repository_details)
73
+ cache = CacheManager.cache("dependency_url_search_cache")
74
+ cache[url] ||= Dependabot::RegistryClient.get(
75
+ url: url,
76
+ headers: repository_details[:auth_header]
77
+ )
78
+
79
+ response = cache[url]
80
+
81
+ return unless response.status == 200
82
+
83
+ body = remove_wrapping_zero_width_chars(response.body)
84
+ JSON.parse(body)
85
+ rescue Excon::Error::Timeout, Excon::Error::Socket
86
+ repo_url = repository_details[:repository_url]
87
+ raise if repo_url == Dependabot::Nuget::UpdateChecker::RepositoryFinder::DEFAULT_REPOSITORY_URL
88
+
89
+ raise PrivateSourceTimedOut, repo_url
90
+ end
91
+
92
+ private_class_method def self.remove_wrapping_zero_width_chars(string)
93
+ string.force_encoding("UTF-8").encode
94
+ .gsub(/\A[\u200B-\u200D\uFEFF]/, "")
95
+ .gsub(/[\u200B-\u200D\uFEFF]\Z/, "")
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,71 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Dependabot
5
+ module Nuget
6
+ module NuGetConfigCredentialHelpers
7
+ def self.user_nuget_config_path
8
+ home_directory = Dir.home
9
+ File.join(home_directory, ".nuget", "NuGet", "NuGet.Config")
10
+ end
11
+
12
+ def self.temporary_nuget_config_path
13
+ user_nuget_config_path + "_ORIGINAL"
14
+ end
15
+
16
+ def self.add_credentials_to_nuget_config(credentials)
17
+ return unless File.exist?(user_nuget_config_path)
18
+
19
+ nuget_credentials = credentials.select { |cred| cred["type"] == "nuget_feed" }
20
+ return if nuget_credentials.empty?
21
+
22
+ File.rename(user_nuget_config_path, temporary_nuget_config_path)
23
+
24
+ package_sources = []
25
+ package_source_credentials = []
26
+ nuget_credentials.each_with_index do |c, i|
27
+ source_name = "nuget_source_#{i + 1}"
28
+ package_sources << " <add key=\"#{source_name}\" value=\"#{c['url']}\" />"
29
+ next unless c["token"]
30
+
31
+ package_source_credentials << " <#{source_name}>"
32
+ package_source_credentials << " <add key=\"Username\" value=\"user\" />"
33
+ package_source_credentials << " <add key=\"ClearTextPassword\" value=\"#{c['token']}\" />"
34
+ package_source_credentials << " </#{source_name}>"
35
+ end
36
+
37
+ nuget_config = <<~NUGET_XML
38
+ <?xml version="1.0" encoding="utf-8"?>
39
+ <configuration>
40
+ <packageSources>
41
+ #{package_sources.join("\n")}
42
+ </packageSources>
43
+ <packageSourceCredentials>
44
+ #{package_source_credentials.join("\n")}
45
+ </packageSourceCredentials>
46
+ </configuration>
47
+ NUGET_XML
48
+ File.write(user_nuget_config_path, nuget_config)
49
+ end
50
+
51
+ def self.restore_user_nuget_config
52
+ return unless File.exist?(temporary_nuget_config_path)
53
+
54
+ File.delete(user_nuget_config_path)
55
+ File.rename(temporary_nuget_config_path, user_nuget_config_path)
56
+ end
57
+
58
+ # rubocop:disable Lint/SuppressedException
59
+ def self.patch_nuget_config_for_action(credentials, &_block)
60
+ add_credentials_to_nuget_config(credentials)
61
+ begin
62
+ yield
63
+ rescue StandardError
64
+ ensure
65
+ restore_user_nuget_config
66
+ end
67
+ end
68
+ # rubocop:enable Lint/SuppressedException
69
+ end
70
+ end
71
+ end
@@ -1,6 +1,9 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "sorbet-runtime"
5
+
6
+ require "dependabot/requirement"
4
7
  require "dependabot/utils"
5
8
  require "dependabot/nuget/version"
6
9
 
@@ -8,7 +11,7 @@ require "dependabot/nuget/version"
8
11
  # https://docs.microsoft.com/en-us/nuget/reference/package-versioning
9
12
  module Dependabot
10
13
  module Nuget
11
- class Requirement < Gem::Requirement
14
+ class Requirement < Dependabot::Requirement
12
15
  def self.parse(obj)
13
16
  return ["=", Nuget::Version.new(obj.to_s)] if obj.is_a?(Gem::Version)
14
17
 
@@ -19,12 +22,13 @@ module Dependabot
19
22
 
20
23
  return DefaultRequirement if matches[1] == ">=" && matches[2] == "0"
21
24
 
22
- [matches[1] || "=", Nuget::Version.new(matches[2])]
25
+ [matches[1] || "=", Nuget::Version.new(T.must(matches[2]))]
23
26
  end
24
27
 
25
28
  # For consistency with other languages, we define a requirements array.
26
29
  # Dotnet doesn't have an `OR` separator for requirements, so it always
27
30
  # contains a single element.
31
+ sig { override.params(requirement_string: T.nilable(String)).returns(T::Array[Requirement]) }
28
32
  def self.requirements_array(requirement_string)
29
33
  [new(requirement_string)]
30
34
  end
@@ -1,11 +1,11 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
- require "dependabot/nuget/update_checker"
4
+ require "dependabot/update_checkers/base"
5
5
 
6
6
  module Dependabot
7
7
  module Nuget
8
- class UpdateChecker
8
+ class UpdateChecker < Dependabot::UpdateCheckers::Base
9
9
  class CompatibilityChecker
10
10
  require_relative "nuspec_fetcher"
11
11
  require_relative "nupkg_fetcher"
@@ -4,12 +4,12 @@
4
4
  require "nokogiri"
5
5
  require "zip"
6
6
  require "stringio"
7
- require "dependabot/nuget/update_checker"
7
+ require "dependabot/update_checkers/base"
8
8
  require "dependabot/nuget/version"
9
9
 
10
10
  module Dependabot
11
11
  module Nuget
12
- class UpdateChecker
12
+ class UpdateChecker < Dependabot::UpdateCheckers::Base
13
13
  class DependencyFinder
14
14
  require_relative "requirements_updater"
15
15
  require_relative "nuspec_fetcher"