dependabot-nuget 0.236.0 → 0.238.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (27) 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 +72 -63
  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/metadata_finder.rb +4 -1
  13. data/lib/dependabot/nuget/native_helpers.rb +94 -0
  14. data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +85 -0
  15. data/lib/dependabot/nuget/update_checker/dependency_finder.rb +228 -0
  16. data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +114 -0
  17. data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +86 -0
  18. data/lib/dependabot/nuget/update_checker/property_updater.rb +30 -3
  19. data/lib/dependabot/nuget/update_checker/repository_finder.rb +32 -10
  20. data/lib/dependabot/nuget/update_checker/tfm_comparer.rb +31 -0
  21. data/lib/dependabot/nuget/update_checker/tfm_finder.rb +127 -0
  22. data/lib/dependabot/nuget/update_checker/version_finder.rb +47 -6
  23. data/lib/dependabot/nuget/update_checker.rb +42 -8
  24. data/lib/dependabot/nuget.rb +2 -0
  25. metadata +49 -9
  26. data/lib/dependabot/nuget/file_updater/packages_config_declaration_finder.rb +0 -70
  27. 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