dependabot-nuget 0.237.0 → 0.238.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 (26) hide show
  1. checksums.yaml +4 -4
  2. data/lib/dependabot/nuget/cache_manager.rb +22 -0
  3. data/lib/dependabot/nuget/file_fetcher/import_paths_finder.rb +15 -0
  4. data/lib/dependabot/nuget/file_fetcher.rb +65 -61
  5. data/lib/dependabot/nuget/file_parser/dotnet_tools_json_parser.rb +2 -1
  6. data/lib/dependabot/nuget/file_parser/global_json_parser.rb +2 -1
  7. data/lib/dependabot/nuget/file_parser/packages_config_parser.rb +22 -4
  8. data/lib/dependabot/nuget/file_parser/project_file_parser.rb +287 -15
  9. data/lib/dependabot/nuget/file_parser/property_value_finder.rb +24 -52
  10. data/lib/dependabot/nuget/file_parser.rb +4 -1
  11. data/lib/dependabot/nuget/file_updater.rb +123 -117
  12. data/lib/dependabot/nuget/native_helpers.rb +94 -0
  13. data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +85 -0
  14. data/lib/dependabot/nuget/update_checker/dependency_finder.rb +228 -0
  15. data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +114 -0
  16. data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +86 -0
  17. data/lib/dependabot/nuget/update_checker/property_updater.rb +30 -3
  18. data/lib/dependabot/nuget/update_checker/repository_finder.rb +32 -10
  19. data/lib/dependabot/nuget/update_checker/tfm_comparer.rb +31 -0
  20. data/lib/dependabot/nuget/update_checker/tfm_finder.rb +127 -0
  21. data/lib/dependabot/nuget/update_checker/version_finder.rb +47 -6
  22. data/lib/dependabot/nuget/update_checker.rb +42 -8
  23. data/lib/dependabot/nuget.rb +2 -0
  24. metadata +33 -7
  25. data/lib/dependabot/nuget/file_updater/packages_config_declaration_finder.rb +0 -70
  26. data/lib/dependabot/nuget/file_updater/project_file_declaration_finder.rb +0 -183
@@ -0,0 +1,228 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require "nokogiri"
5
+ require "zip"
6
+ require "stringio"
7
+ require "dependabot/nuget/update_checker"
8
+ require "dependabot/nuget/version"
9
+
10
+ module Dependabot
11
+ module Nuget
12
+ class UpdateChecker
13
+ class DependencyFinder
14
+ require_relative "requirements_updater"
15
+ require_relative "nuspec_fetcher"
16
+
17
+ def self.transitive_dependencies_cache
18
+ CacheManager.cache("dependency_finder_transitive_dependencies")
19
+ end
20
+
21
+ def self.updated_peer_dependencies_cache
22
+ CacheManager.cache("dependency_finder_updated_peer_dependencies")
23
+ end
24
+
25
+ def self.fetch_dependencies_cache
26
+ CacheManager.cache("dependency_finder_fetch_dependencies")
27
+ end
28
+
29
+ def initialize(dependency:, dependency_files:, credentials:)
30
+ @dependency = dependency
31
+ @dependency_files = dependency_files
32
+ @credentials = credentials
33
+ end
34
+
35
+ def transitive_dependencies
36
+ key = "#{dependency.name.downcase}::#{dependency.version}"
37
+ cache = DependencyFinder.transitive_dependencies_cache
38
+
39
+ cache[key] ||= fetch_transitive_dependencies(
40
+ @dependency.name,
41
+ @dependency.version
42
+ ).map do |dependency_info|
43
+ package_name = dependency_info["packageName"]
44
+ target_version = dependency_info["version"]
45
+
46
+ Dependency.new(
47
+ name: package_name,
48
+ version: target_version.to_s,
49
+ requirements: [], # Empty requirements for transitive dependencies
50
+ package_manager: @dependency.package_manager
51
+ )
52
+ end
53
+
54
+ cache[key]
55
+ end
56
+
57
+ def updated_peer_dependencies
58
+ key = "#{dependency.name.downcase}::#{dependency.version}"
59
+ cache = DependencyFinder.updated_peer_dependencies_cache
60
+
61
+ cache[key] ||= fetch_transitive_dependencies(
62
+ @dependency.name,
63
+ @dependency.version
64
+ ).filter_map do |dependency_info|
65
+ package_name = dependency_info["packageName"]
66
+ target_version = dependency_info["version"]
67
+
68
+ # Find the Dependency object for the peer dependency. We will not return
69
+ # dependencies that are not referenced from dependency files.
70
+ peer_dependency = top_level_dependencies.find { |d| d.name == package_name }
71
+ next unless peer_dependency
72
+ next unless target_version > peer_dependency.numeric_version
73
+
74
+ # Use version finder to determine the source details for the peer dependency.
75
+ target_version_details = version_finder(peer_dependency).versions.find do |v|
76
+ v.fetch(:version) == target_version
77
+ end
78
+ next unless target_version_details
79
+
80
+ Dependency.new(
81
+ name: peer_dependency.name,
82
+ version: target_version_details.fetch(:version).to_s,
83
+ requirements: updated_requirements(peer_dependency, target_version_details),
84
+ previous_version: peer_dependency.version,
85
+ previous_requirements: peer_dependency.requirements,
86
+ package_manager: peer_dependency.package_manager,
87
+ metadata: { information_only: true } # Instruct updater to not directly update this dependency
88
+ )
89
+ end
90
+
91
+ cache[key]
92
+ end
93
+
94
+ private
95
+
96
+ attr_reader :dependency, :dependency_files, :credentials
97
+
98
+ def updated_requirements(dep, target_version_details)
99
+ @updated_requirements ||= {}
100
+ @updated_requirements[dep.name] ||=
101
+ RequirementsUpdater.new(
102
+ requirements: dep.requirements,
103
+ latest_version: target_version_details.fetch(:version).to_s,
104
+ source_details: target_version_details
105
+ &.slice(:nuspec_url, :repo_url, :source_url)
106
+ ).updated_requirements
107
+ end
108
+
109
+ def top_level_dependencies
110
+ @top_level_dependencies ||=
111
+ Nuget::FileParser.new(
112
+ dependency_files: dependency_files,
113
+ source: nil
114
+ ).parse.select(&:top_level?)
115
+ end
116
+
117
+ def nuget_configs
118
+ @nuget_configs ||=
119
+ @dependency_files.select { |f| f.name.match?(/nuget\.config$/i) }
120
+ end
121
+
122
+ def dependency_urls
123
+ @dependency_urls ||=
124
+ UpdateChecker::RepositoryFinder.new(
125
+ dependency: @dependency,
126
+ credentials: @credentials,
127
+ config_files: nuget_configs
128
+ ).dependency_urls
129
+ .select { |url| url.fetch(:repository_type) == "v3" }
130
+ end
131
+
132
+ def fetch_transitive_dependencies(package_id, package_version)
133
+ all_dependencies = {}
134
+ fetch_transitive_dependencies_impl(package_id, package_version, all_dependencies)
135
+ all_dependencies.map { |_, dependency_info| dependency_info }
136
+ end
137
+
138
+ def fetch_transitive_dependencies_impl(package_id, package_version, all_dependencies)
139
+ dependencies = fetch_dependencies(package_id, package_version)
140
+ return unless dependencies.any?
141
+
142
+ dependencies.each do |dependency|
143
+ next if dependency.nil?
144
+
145
+ dependency_id = dependency["packageName"]
146
+ dependency_version_range = dependency["versionRange"]
147
+
148
+ nuget_version_range_regex = /[\[(](\d+(\.\d+)*(-\w+(\.\d+)*)?)/
149
+ nuget_version_range_match_data = nuget_version_range_regex.match(dependency_version_range)
150
+
151
+ dependency_version = if nuget_version_range_match_data.nil?
152
+ dependency_version_range
153
+ else
154
+ nuget_version_range_match_data[1]
155
+ end
156
+
157
+ dependency["version"] = Version.new(dependency_version)
158
+
159
+ current_dependency = all_dependencies[dependency_id.downcase]
160
+ next unless current_dependency.nil? || current_dependency["version"] < dependency["version"]
161
+
162
+ all_dependencies[dependency_id.downcase] = dependency
163
+ fetch_transitive_dependencies_impl(dependency_id, dependency_version, all_dependencies)
164
+ end
165
+ end
166
+
167
+ def fetch_dependencies(package_id, package_version)
168
+ key = "#{package_id.downcase}::#{package_version}"
169
+ cache = DependencyFinder.fetch_dependencies_cache
170
+
171
+ cache[key] ||= begin
172
+ nuspec_xml = NuspecFetcher.fetch_nuspec(dependency_urls, package_id, package_version)
173
+ if nuspec_xml.nil?
174
+ []
175
+ else
176
+ read_dependencies_from_nuspec(nuspec_xml)
177
+ end
178
+ end
179
+
180
+ cache[key]
181
+ end
182
+
183
+ def read_dependencies_from_nuspec(nuspec_xml) # rubocop:disable Metrics/PerceivedComplexity
184
+ # we want to exclude development dependencies from the lookup
185
+ allowed_attributes = %w(all compile native runtime)
186
+
187
+ nuspec_xml_dependencies = nuspec_xml.xpath("//dependencies/child::node()/dependency").select do |dependency|
188
+ include_attr = dependency.attribute("include")
189
+ exclude_attr = dependency.attribute("exclude")
190
+
191
+ if include_attr.nil? && exclude_attr.nil?
192
+ true
193
+ elsif include_attr
194
+ include_values = include_attr.value.split(",").map(&:strip)
195
+ include_values.any? { |element1| allowed_attributes.any? { |element2| element1.casecmp?(element2) } }
196
+ else
197
+ exclude_values = exclude_attr.value.split(",").map(&:strip)
198
+ exclude_values.none? { |element1| allowed_attributes.any? { |element2| element1.casecmp?(element2) } }
199
+ end
200
+ end
201
+
202
+ dependency_list = []
203
+ nuspec_xml_dependencies.each do |dependency|
204
+ next unless dependency.attribute("version")
205
+
206
+ dependency_list << {
207
+ "packageName" => dependency.attribute("id").value,
208
+ "versionRange" => dependency.attribute("version").value
209
+ }
210
+ end
211
+
212
+ dependency_list
213
+ end
214
+
215
+ def version_finder(dep)
216
+ VersionFinder.new(
217
+ dependency: dep,
218
+ dependency_files: dependency_files,
219
+ credentials: credentials,
220
+ ignored_versions: [],
221
+ raise_on_ignored: false,
222
+ security_advisories: []
223
+ )
224
+ end
225
+ end
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,114 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ require "nokogiri"
5
+ require "zip"
6
+ require "stringio"
7
+ require "dependabot/nuget/update_checker"
8
+
9
+ module Dependabot
10
+ module Nuget
11
+ class UpdateChecker
12
+ class NupkgFetcher
13
+ require_relative "repository_finder"
14
+
15
+ def self.fetch_nupkg_buffer(dependency_urls, package_id, package_version)
16
+ # check all repositories for the first one that has the nupkg
17
+ dependency_urls.reduce(nil) do |nupkg_buffer, repository_details|
18
+ nupkg_buffer || fetch_nupkg_buffer_from_repository(repository_details, package_id, package_version)
19
+ end
20
+ end
21
+
22
+ def self.fetch_nupkg_buffer_from_repository(repository_details, package_id, package_version)
23
+ return unless package_id && package_version && !package_version.empty?
24
+
25
+ feed_url = repository_details[:repository_url]
26
+ auth_header = repository_details[:auth_header]
27
+
28
+ azure_devops_match = try_match_azure_url(feed_url)
29
+ package_url = if azure_devops_match
30
+ get_azure_package_url(azure_devops_match, package_id, package_version)
31
+ elsif feed_url.include?("/v2")
32
+ get_nuget_v2_package_url(feed_url, package_id, package_version)
33
+ elsif feed_url.include?("/v3")
34
+ get_nuget_v3_package_url(feed_url, package_id, package_version)
35
+ else
36
+ raise Dependabot::DependencyFileNotResolvable, "Unexpected NuGet feed format: #{feed_url}"
37
+ end
38
+
39
+ fetch_stream(package_url, auth_header)
40
+ end
41
+
42
+ def self.try_match_azure_url(feed_url)
43
+ # if url is azure devops
44
+ azure_devops_regexs = [
45
+ %r{https://pkgs\.dev\.azure\.com/(?<organization>[^/]+)/(?<project>[^/]+)/_packaging/(?<feedId>[^/]+)/nuget/v3/index\.json},
46
+ %r{https://pkgs\.dev\.azure\.com/(?<organization>[^/]+)/_packaging/(?<feedId>[^/]+)/nuget/v3/index\.json(?<project>)},
47
+ %r{https://(?<organization>[^\.\/]+)\.pkgs\.visualstudio\.com/_packaging/(?<feedId>[^/]+)/nuget/v3/index\.json(?<project>)}
48
+ ]
49
+ regex = azure_devops_regexs.find { |reg| reg.match(feed_url) }
50
+ return unless regex
51
+
52
+ regex.match(feed_url)
53
+ end
54
+
55
+ def self.get_azure_package_url(azure_devops_match, package_id, package_version)
56
+ organization = azure_devops_match[:organization]
57
+ project = azure_devops_match[:project]
58
+ feed_id = azure_devops_match[:feedId]
59
+
60
+ if project.empty?
61
+ "https://pkgs.dev.azure.com/#{organization}/_apis/packaging/feeds/#{feed_id}/nuget/packages/#{package_id}/versions/#{package_version}/content?sourceProtocolVersion=nuget&api-version=7.0-preview"
62
+ else
63
+ "https://pkgs.dev.azure.com/#{organization}/#{project}/_apis/packaging/feeds/#{feed_id}/nuget/packages/#{package_id}/versions/#{package_version}/content?sourceProtocolVersion=nuget&api-version=7.0-preview"
64
+ end
65
+ end
66
+
67
+ def self.get_nuget_v3_package_url(feed_url, package_id, package_version)
68
+ base_url = feed_url.gsub("/index.json", "-flatcontainer")
69
+ package_id_downcased = package_id.downcase
70
+ "#{base_url}/#{package_id_downcased}/#{package_version}/#{package_id_downcased}.#{package_version}.nupkg"
71
+ end
72
+
73
+ def self.get_nuget_v2_package_url(feed_url, package_id, package_version)
74
+ base_url = feed_url
75
+ base_url += "/" unless base_url.end_with?("/")
76
+ package_id_downcased = package_id.downcase
77
+ "#{base_url}/package/#{package_id_downcased}/#{package_version}"
78
+ end
79
+
80
+ def self.fetch_stream(stream_url, auth_header, max_redirects = 5)
81
+ current_url = stream_url
82
+ current_redirects = 0
83
+
84
+ loop do
85
+ connection = Excon.new(current_url, persistent: true)
86
+
87
+ package_data = StringIO.new
88
+ response_block = lambda do |chunk, _remaining_bytes, _total_bytes|
89
+ package_data.write(chunk)
90
+ end
91
+
92
+ response = connection.request(
93
+ method: :get,
94
+ headers: auth_header,
95
+ response_block: response_block
96
+ )
97
+
98
+ if response.status == 303
99
+ current_redirects += 1
100
+ return nil if current_redirects > max_redirects
101
+
102
+ current_url = response.headers["Location"]
103
+ elsif response.status == 200
104
+ package_data.rewind
105
+ return package_data
106
+ else
107
+ return nil
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,86 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ require "nokogiri"
5
+ require "zip"
6
+ require "stringio"
7
+ require "dependabot/nuget/update_checker"
8
+
9
+ module Dependabot
10
+ module Nuget
11
+ class UpdateChecker
12
+ class NuspecFetcher
13
+ require_relative "nupkg_fetcher"
14
+ require_relative "repository_finder"
15
+
16
+ def self.fetch_nuspec(dependency_urls, package_id, package_version)
17
+ # check all repositories for the first one that has the nuspec
18
+ dependency_urls.reduce(nil) do |nuspec_xml, repository_details|
19
+ nuspec_xml || fetch_nuspec_from_repository(repository_details, package_id, package_version)
20
+ end
21
+ end
22
+
23
+ def self.fetch_nuspec_from_repository(repository_details, package_id, package_version)
24
+ return unless package_id && package_version && !package_version.empty?
25
+
26
+ feed_url = repository_details[:repository_url]
27
+ auth_header = repository_details[:auth_header]
28
+
29
+ nuspec_xml = nil
30
+
31
+ if azure_package_feed?(feed_url)
32
+ # this is an azure devops url we can extract the nuspec from the nupkg
33
+ package_data = NupkgFetcher.fetch_nupkg_buffer_from_repository(repository_details, package_id,
34
+ package_version)
35
+ return if package_data.nil?
36
+
37
+ nuspec_string = extract_nuspec(package_data, package_id)
38
+ nuspec_xml = Nokogiri::XML(nuspec_string)
39
+ else
40
+ # we can use the normal nuget apis to get the nuspec and list out the dependencies
41
+ base_url = feed_url.gsub("/index.json", "-flatcontainer")
42
+ package_id_downcased = package_id.downcase
43
+ nuspec_url = "#{base_url}/#{package_id_downcased}/#{package_version}/#{package_id_downcased}.nuspec"
44
+
45
+ nuspec_response = Dependabot::RegistryClient.get(
46
+ url: nuspec_url,
47
+ headers: auth_header
48
+ )
49
+
50
+ return unless nuspec_response.status == 200
51
+
52
+ nuspec_response_body = remove_wrapping_zero_width_chars(nuspec_response.body)
53
+ nuspec_xml = Nokogiri::XML(nuspec_response_body)
54
+ end
55
+
56
+ nuspec_xml.remove_namespaces!
57
+ nuspec_xml
58
+ end
59
+
60
+ def self.azure_package_feed?(feed_url)
61
+ # if url is azure devops
62
+ azure_devops_regexs = [
63
+ %r{https://pkgs\.dev\.azure\.com/(?<organization>[^/]+)/(?<project>[^/]+)/_packaging/(?<feedId>[^/]+)/nuget/v3/index\.json},
64
+ %r{https://pkgs\.dev\.azure\.com/(?<organization>[^/]+)/_packaging/(?<feedId>[^/]+)/nuget/v3/index\.json(?<project>)},
65
+ %r{https://(?<organization>[^\.\/]+)\.pkgs\.visualstudio\.com/_packaging/(?<feedId>[^/]+)/nuget/v3/index\.json(?<project>)}
66
+ ]
67
+ azure_devops_regexs.any? { |reg| reg.match(feed_url) }
68
+ end
69
+
70
+ def self.extract_nuspec(zip_stream, package_id)
71
+ Zip::File.open_buffer(zip_stream) do |zip|
72
+ nuspec_entry = zip.find { |entry| entry.name == "#{package_id}.nuspec" }
73
+ return nuspec_entry.get_input_stream.read if nuspec_entry
74
+ end
75
+ nil
76
+ end
77
+
78
+ def self.remove_wrapping_zero_width_chars(string)
79
+ string.force_encoding("UTF-8").encode
80
+ .gsub(/\A[\u200B-\u200D\uFEFF]/, "")
81
+ .gsub(/[\u200B-\u200D\uFEFF]\Z/, "")
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -10,6 +10,7 @@ module Dependabot
10
10
  class PropertyUpdater
11
11
  require_relative "version_finder"
12
12
  require_relative "requirements_updater"
13
+ require_relative "dependency_finder"
13
14
 
14
15
  def initialize(dependency:, dependency_files:, credentials:,
15
16
  target_version_details:, ignored_versions:,
@@ -45,9 +46,15 @@ module Dependabot
45
46
  def updated_dependencies
46
47
  raise "Update not possible!" unless update_possible?
47
48
 
48
- @updated_dependencies ||=
49
- dependencies_using_property.map do |dep|
50
- Dependency.new(
49
+ @updated_dependencies ||= begin
50
+ dependencies = {}
51
+
52
+ dependencies_using_property.each do |dep|
53
+ # Only keep one copy of each dependency, the one with the highest target version.
54
+ visited_dependency = dependencies[dep.name.downcase]
55
+ next unless visited_dependency.nil? || visited_dependency.numeric_version < target_version
56
+
57
+ updated_dependency = Dependency.new(
51
58
  name: dep.name,
52
59
  version: target_version.to_s,
53
60
  requirements: updated_requirements(dep),
@@ -55,7 +62,13 @@ module Dependabot
55
62
  previous_requirements: dep.requirements,
56
63
  package_manager: dep.package_manager
57
64
  )
65
+ dependencies[updated_dependency.name.downcase] = updated_dependency
66
+ # Add peer dependencies to the list of updated dependencies.
67
+ process_updated_peer_dependencies(updated_dependency, dependencies)
58
68
  end
69
+
70
+ dependencies.map { |_, dependency| dependency }
71
+ end
59
72
  end
60
73
 
61
74
  private
@@ -63,6 +76,20 @@ module Dependabot
63
76
  attr_reader :dependency, :dependency_files, :target_version,
64
77
  :source_details, :credentials, :ignored_versions
65
78
 
79
+ def process_updated_peer_dependencies(dependency, dependencies)
80
+ DependencyFinder.new(
81
+ dependency: dependency,
82
+ dependency_files: dependency_files,
83
+ credentials: credentials
84
+ ).updated_peer_dependencies.each do |peer_dependency|
85
+ # Only keep one copy of each dependency, the one with the highest target version.
86
+ visited_dependency = dependencies[peer_dependency.name.downcase]
87
+ next unless visited_dependency.nil? || visited_dependency.numeric_version < peer_dependency.numeric_version
88
+
89
+ dependencies[peer_dependency.name.downcase] = peer_dependency
90
+ end
91
+ end
92
+
66
93
  def dependencies_using_property
67
94
  @dependencies_using_property ||=
68
95
  Nuget::FileParser.new(
@@ -24,6 +24,18 @@ module Dependabot
24
24
  find_dependency_urls
25
25
  end
26
26
 
27
+ def self.get_default_repository_details(dependency_name)
28
+ {
29
+ repository_url: DEFAULT_REPOSITORY_URL,
30
+ versions_url: "https://api.nuget.org/v3-flatcontainer/" \
31
+ "#{dependency_name.downcase}/index.json",
32
+ search_url: "https://azuresearch-usnc.nuget.org/query" \
33
+ "?q=#{dependency_name.downcase}&prerelease=true&semVerLevel=2.0.0",
34
+ auth_header: {},
35
+ repository_type: "v3"
36
+ }
37
+ end
38
+
27
39
  private
28
40
 
29
41
  attr_reader :dependency, :credentials, :config_files
@@ -85,9 +97,16 @@ module Dependabot
85
97
  end
86
98
 
87
99
  def search_url_from_v3_metadata(metadata)
100
+ # allowable values from here: https://learn.microsoft.com/en-us/nuget/api/search-query-service-resource#versioning
101
+ allowed_search_types = %w(
102
+ SearchQueryService
103
+ SearchQueryService/3.0.0-beta
104
+ SearchQueryService/3.0.0-rc
105
+ SearchQueryService/3.5.0
106
+ )
88
107
  metadata
89
108
  .fetch("resources", [])
90
- .find { |r| r.fetch("@type") == "SearchQueryService" }
109
+ .find { |r| allowed_search_types.find { |s| r.fetch("@type") == s } }
91
110
  &.fetch("@id")
92
111
  end
93
112
 
@@ -157,6 +176,8 @@ module Dependabot
157
176
  base_sources = [{ url: DEFAULT_REPOSITORY_URL, key: "nuget.org" }]
158
177
 
159
178
  sources = []
179
+
180
+ # regular package sources
160
181
  doc.css("configuration > packageSources").children.each do |node|
161
182
  if node.name == "clear"
162
183
  sources.clear
@@ -167,6 +188,15 @@ module Dependabot
167
188
  sources << { url: url, key: key }
168
189
  end
169
190
  end
191
+
192
+ # signed package sources
193
+ # https://learn.microsoft.com/en-us/nuget/reference/nuget-config-file#trustedsigners-section
194
+ doc.xpath("/configuration/trustedSigners/repository").each do |node|
195
+ name = node.attribute("name")&.value&.strip
196
+ service_index = node.attribute("serviceIndex")&.value&.strip
197
+ sources << { url: service_index, key: name }
198
+ end
199
+
170
200
  sources += base_sources # TODO: quirky overwrite behavior
171
201
  disabled_sources = disabled_sources(doc)
172
202
  sources.reject! do |s|
@@ -190,15 +220,7 @@ module Dependabot
190
220
  # rubocop:enable Metrics/CyclomaticComplexity
191
221
 
192
222
  def default_repository_details
193
- {
194
- repository_url: DEFAULT_REPOSITORY_URL,
195
- versions_url: "https://api.nuget.org/v3-flatcontainer/" \
196
- "#{dependency.name.downcase}/index.json",
197
- search_url: "https://azuresearch-usnc.nuget.org/query" \
198
- "?q=#{dependency.name.downcase}&prerelease=true&semVerLevel=2.0.0",
199
- auth_header: {},
200
- repository_type: "v3"
201
- }
223
+ RepositoryFinder.get_default_repository_details(dependency.name)
202
224
  end
203
225
 
204
226
  # rubocop:disable Metrics/PerceivedComplexity
@@ -0,0 +1,31 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require "dependabot/nuget/version"
5
+ require "dependabot/nuget/requirement"
6
+ require "dependabot/nuget/native_helpers"
7
+ require "dependabot/nuget/update_checker"
8
+ require "dependabot/shared_helpers"
9
+
10
+ module Dependabot
11
+ module Nuget
12
+ class UpdateChecker
13
+ class TfmComparer
14
+ def self.are_frameworks_compatible?(project_tfms, package_tfms)
15
+ return false if package_tfms.empty?
16
+ return false if project_tfms.empty?
17
+
18
+ key = "project_ftms:#{project_tfms.sort.join(',')}:package_tfms:#{package_tfms.sort.join(',')}".downcase
19
+
20
+ @cached_framework_check ||= {}
21
+ unless @cached_framework_check.key?(key)
22
+ @cached_framework_check[key] =
23
+ NativeHelpers.run_nuget_framework_check(project_tfms,
24
+ package_tfms)
25
+ end
26
+ @cached_framework_check[key]
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end