dependabot-nuget 0.247.0 → 0.249.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.
- checksums.yaml +4 -4
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Cli.Test/EntryPointTests.Update.cs +57 -0
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Updater/SdkPackageUpdater.cs +1 -1
- data/helpers/lib/NuGetUpdater/NuGetUpdater.Core/Utilities/MSBuildHelper.cs +25 -5
- data/lib/dependabot/nuget/file_fetcher/import_paths_finder.rb +1 -0
- data/lib/dependabot/nuget/file_fetcher/sln_project_paths_finder.rb +2 -0
- data/lib/dependabot/nuget/file_fetcher.rb +12 -8
- data/lib/dependabot/nuget/file_parser/dotnet_tools_json_parser.rb +1 -0
- data/lib/dependabot/nuget/file_parser/global_json_parser.rb +1 -0
- data/lib/dependabot/nuget/file_parser/packages_config_parser.rb +1 -0
- data/lib/dependabot/nuget/file_parser/project_file_parser.rb +1 -0
- data/lib/dependabot/nuget/file_parser/property_value_finder.rb +2 -0
- data/lib/dependabot/nuget/file_parser.rb +42 -11
- data/lib/dependabot/nuget/file_updater/property_value_updater.rb +1 -0
- data/lib/dependabot/nuget/nuget_config_credential_helpers.rb +10 -1
- data/lib/dependabot/nuget/requirement.rb +17 -8
- data/lib/dependabot/nuget/update_checker/compatibility_checker.rb +28 -7
- data/lib/dependabot/nuget/update_checker/dependency_finder.rb +70 -19
- data/lib/dependabot/nuget/update_checker/nupkg_fetcher.rb +76 -8
- data/lib/dependabot/nuget/update_checker/nuspec_fetcher.rb +25 -3
- data/lib/dependabot/nuget/update_checker/property_updater.rb +108 -44
- data/lib/dependabot/nuget/update_checker/repository_finder.rb +90 -18
- data/lib/dependabot/nuget/update_checker/requirements_updater.rb +32 -9
- data/lib/dependabot/nuget/update_checker/tfm_comparer.rb +8 -3
- data/lib/dependabot/nuget/update_checker/tfm_finder.rb +51 -13
- data/lib/dependabot/nuget/update_checker/version_finder.rb +167 -62
- data/lib/dependabot/nuget/update_checker.rb +73 -29
- metadata +5 -5
@@ -1,9 +1,11 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "nokogiri"
|
5
|
-
require "
|
5
|
+
require "sorbet-runtime"
|
6
6
|
require "stringio"
|
7
|
+
require "zip"
|
8
|
+
|
7
9
|
require "dependabot/update_checkers/base"
|
8
10
|
require "dependabot/nuget/version"
|
9
11
|
|
@@ -11,21 +13,34 @@ module Dependabot
|
|
11
13
|
module Nuget
|
12
14
|
class UpdateChecker < Dependabot::UpdateCheckers::Base
|
13
15
|
class DependencyFinder
|
16
|
+
extend T::Sig
|
17
|
+
|
14
18
|
require_relative "requirements_updater"
|
15
19
|
require_relative "nuspec_fetcher"
|
16
20
|
|
21
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
17
22
|
def self.transitive_dependencies_cache
|
18
23
|
CacheManager.cache("dependency_finder_transitive_dependencies")
|
19
24
|
end
|
20
25
|
|
26
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
21
27
|
def self.updated_peer_dependencies_cache
|
22
28
|
CacheManager.cache("dependency_finder_updated_peer_dependencies")
|
23
29
|
end
|
24
30
|
|
31
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
25
32
|
def self.fetch_dependencies_cache
|
26
33
|
CacheManager.cache("dependency_finder_fetch_dependencies")
|
27
34
|
end
|
28
35
|
|
36
|
+
sig do
|
37
|
+
params(
|
38
|
+
dependency: Dependabot::Dependency,
|
39
|
+
dependency_files: T::Array[Dependabot::DependencyFile],
|
40
|
+
credentials: T::Array[Dependabot::Credential],
|
41
|
+
repo_contents_path: T.nilable(String)
|
42
|
+
).void
|
43
|
+
end
|
29
44
|
def initialize(dependency:, dependency_files:, credentials:, repo_contents_path:)
|
30
45
|
@dependency = dependency
|
31
46
|
@dependency_files = dependency_files
|
@@ -33,6 +48,7 @@ module Dependabot
|
|
33
48
|
@repo_contents_path = repo_contents_path
|
34
49
|
end
|
35
50
|
|
51
|
+
sig { returns(T::Array[Dependabot::Dependency]) }
|
36
52
|
def transitive_dependencies
|
37
53
|
key = "#{dependency.name.downcase}::#{dependency.version}"
|
38
54
|
cache = DependencyFinder.transitive_dependencies_cache
|
@@ -44,7 +60,7 @@ module Dependabot
|
|
44
60
|
|
45
61
|
cache[key] = fetch_transitive_dependencies(
|
46
62
|
@dependency.name,
|
47
|
-
@dependency.version
|
63
|
+
T.must(@dependency.version)
|
48
64
|
).map do |dependency_info|
|
49
65
|
package_name = dependency_info["packageName"]
|
50
66
|
target_version = dependency_info["version"]
|
@@ -65,13 +81,14 @@ module Dependabot
|
|
65
81
|
cache[key]
|
66
82
|
end
|
67
83
|
|
84
|
+
sig { returns(T::Array[Dependabot::Dependency]) }
|
68
85
|
def updated_peer_dependencies
|
69
86
|
key = "#{dependency.name.downcase}::#{dependency.version}"
|
70
87
|
cache = DependencyFinder.updated_peer_dependencies_cache
|
71
88
|
|
72
89
|
cache[key] ||= fetch_transitive_dependencies(
|
73
90
|
@dependency.name,
|
74
|
-
@dependency.version
|
91
|
+
T.must(@dependency.version)
|
75
92
|
).filter_map do |dependency_info|
|
76
93
|
package_name = dependency_info["packageName"]
|
77
94
|
target_version = dependency_info["version"]
|
@@ -104,48 +121,79 @@ module Dependabot
|
|
104
121
|
|
105
122
|
private
|
106
123
|
|
107
|
-
|
124
|
+
sig { returns(Dependabot::Dependency) }
|
125
|
+
attr_reader :dependency
|
126
|
+
|
127
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
128
|
+
attr_reader :dependency_files
|
129
|
+
|
130
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
131
|
+
attr_reader :credentials
|
108
132
|
|
133
|
+
sig { returns(T.nilable(String)) }
|
134
|
+
attr_reader :repo_contents_path
|
135
|
+
|
136
|
+
sig do
|
137
|
+
params(
|
138
|
+
dep: Dependabot::Dependency,
|
139
|
+
target_version_details: T::Hash[Symbol, T.untyped]
|
140
|
+
)
|
141
|
+
.returns(T::Array[T::Hash[String, T.untyped]])
|
142
|
+
end
|
109
143
|
def updated_requirements(dep, target_version_details)
|
110
|
-
@updated_requirements ||= {}
|
144
|
+
@updated_requirements ||= T.let({}, T.nilable(T::Hash[String, T.untyped]))
|
111
145
|
@updated_requirements[dep.name] ||=
|
112
146
|
RequirementsUpdater.new(
|
113
147
|
requirements: dep.requirements,
|
114
148
|
latest_version: target_version_details.fetch(:version).to_s,
|
115
|
-
source_details: target_version_details
|
116
|
-
&.slice(:nuspec_url, :repo_url, :source_url)
|
149
|
+
source_details: target_version_details.slice(:nuspec_url, :repo_url, :source_url)
|
117
150
|
).updated_requirements
|
118
151
|
end
|
119
152
|
|
153
|
+
sig { returns(T::Array[Dependabot::Dependency]) }
|
120
154
|
def top_level_dependencies
|
121
155
|
@top_level_dependencies ||=
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
156
|
+
T.let(
|
157
|
+
Nuget::FileParser.new(
|
158
|
+
dependency_files: dependency_files,
|
159
|
+
source: nil
|
160
|
+
).parse.select(&:top_level?),
|
161
|
+
T.nilable(T::Array[Dependabot::Dependency])
|
162
|
+
)
|
126
163
|
end
|
127
164
|
|
165
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
128
166
|
def nuget_configs
|
129
167
|
@nuget_configs ||=
|
130
|
-
|
168
|
+
T.let(
|
169
|
+
@dependency_files.select { |f| f.name.match?(/nuget\.config$/i) },
|
170
|
+
T.nilable(T::Array[Dependabot::DependencyFile])
|
171
|
+
)
|
131
172
|
end
|
132
173
|
|
174
|
+
sig { returns(T::Array[T::Hash[Symbol, String]]) }
|
133
175
|
def dependency_urls
|
134
176
|
@dependency_urls ||=
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
177
|
+
T.let(
|
178
|
+
RepositoryFinder.new(
|
179
|
+
dependency: @dependency,
|
180
|
+
credentials: @credentials,
|
181
|
+
config_files: nuget_configs
|
182
|
+
)
|
183
|
+
.dependency_urls
|
184
|
+
.select { |url| url.fetch(:repository_type) == "v3" },
|
185
|
+
T.nilable(T::Array[T::Hash[Symbol, String]])
|
186
|
+
)
|
141
187
|
end
|
142
188
|
|
189
|
+
sig { params(package_id: String, package_version: String).returns(T::Array[T::Hash[String, T.untyped]]) }
|
143
190
|
def fetch_transitive_dependencies(package_id, package_version)
|
144
191
|
all_dependencies = {}
|
145
192
|
fetch_transitive_dependencies_impl(package_id, package_version, all_dependencies)
|
146
193
|
all_dependencies.map { |_, dependency_info| dependency_info }
|
147
194
|
end
|
148
195
|
|
196
|
+
sig { params(package_id: String, package_version: String, all_dependencies: T::Hash[String, T.untyped]).void }
|
149
197
|
def fetch_transitive_dependencies_impl(package_id, package_version, all_dependencies)
|
150
198
|
dependencies = fetch_dependencies(package_id, package_version)
|
151
199
|
return unless dependencies.any?
|
@@ -175,6 +223,7 @@ module Dependabot
|
|
175
223
|
end
|
176
224
|
end
|
177
225
|
|
226
|
+
sig { params(package_id: String, package_version: String).returns(T::Array[T::Hash[String, T.untyped]]) }
|
178
227
|
def fetch_dependencies(package_id, package_version)
|
179
228
|
key = "#{package_id.downcase}::#{package_version}"
|
180
229
|
cache = DependencyFinder.fetch_dependencies_cache
|
@@ -191,6 +240,7 @@ module Dependabot
|
|
191
240
|
cache[key]
|
192
241
|
end
|
193
242
|
|
243
|
+
sig { params(nuspec_xml: Nokogiri::XML::Document).returns(T::Array[T::Hash[String, String]]) }
|
194
244
|
def read_dependencies_from_nuspec(nuspec_xml) # rubocop:disable Metrics/PerceivedComplexity
|
195
245
|
# we want to exclude development dependencies from the lookup
|
196
246
|
allowed_attributes = %w(all compile native runtime)
|
@@ -223,6 +273,7 @@ module Dependabot
|
|
223
273
|
dependency_list
|
224
274
|
end
|
225
275
|
|
276
|
+
sig { params(dep: Dependabot::Dependency).returns(Dependabot::Nuget::UpdateChecker::VersionFinder) }
|
226
277
|
def version_finder(dep)
|
227
278
|
VersionFinder.new(
|
228
279
|
dependency: dep,
|
@@ -1,23 +1,43 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "nokogiri"
|
5
|
-
require "zip"
|
6
5
|
require "stringio"
|
6
|
+
require "sorbet-runtime"
|
7
|
+
require "zip"
|
8
|
+
|
7
9
|
require "dependabot/nuget/http_response_helpers"
|
8
10
|
|
9
11
|
module Dependabot
|
10
12
|
module Nuget
|
11
13
|
class NupkgFetcher
|
14
|
+
extend T::Sig
|
15
|
+
|
12
16
|
require_relative "repository_finder"
|
13
17
|
|
18
|
+
sig do
|
19
|
+
params(
|
20
|
+
dependency_urls: T::Array[T::Hash[Symbol, String]],
|
21
|
+
package_id: String,
|
22
|
+
package_version: String
|
23
|
+
)
|
24
|
+
.returns(T.nilable(String))
|
25
|
+
end
|
14
26
|
def self.fetch_nupkg_buffer(dependency_urls, package_id, package_version)
|
15
27
|
# check all repositories for the first one that has the nupkg
|
16
|
-
dependency_urls.reduce(nil) do |nupkg_buffer, repository_details|
|
28
|
+
dependency_urls.reduce(T.let(nil, T.nilable(String))) do |nupkg_buffer, repository_details|
|
17
29
|
nupkg_buffer || fetch_nupkg_buffer_from_repository(repository_details, package_id, package_version)
|
18
30
|
end
|
19
31
|
end
|
20
32
|
|
33
|
+
sig do
|
34
|
+
params(
|
35
|
+
repository_details: T::Hash[Symbol, T.untyped],
|
36
|
+
package_id: T.nilable(String),
|
37
|
+
package_version: T.nilable(String)
|
38
|
+
)
|
39
|
+
.returns(T.nilable(String))
|
40
|
+
end
|
21
41
|
def self.fetch_nupkg_url_from_repository(repository_details, package_id, package_version)
|
22
42
|
return unless package_id && package_version && !package_version.empty?
|
23
43
|
|
@@ -35,6 +55,14 @@ module Dependabot
|
|
35
55
|
package_url
|
36
56
|
end
|
37
57
|
|
58
|
+
sig do
|
59
|
+
params(
|
60
|
+
repository_details: T::Hash[Symbol, T.untyped],
|
61
|
+
package_id: String,
|
62
|
+
package_version: String
|
63
|
+
)
|
64
|
+
.returns(T.nilable(String))
|
65
|
+
end
|
38
66
|
def self.fetch_nupkg_buffer_from_repository(repository_details, package_id, package_version)
|
39
67
|
package_url = fetch_nupkg_url_from_repository(repository_details, package_id, package_version)
|
40
68
|
return unless package_url
|
@@ -43,6 +71,14 @@ module Dependabot
|
|
43
71
|
fetch_stream(package_url, auth_header)
|
44
72
|
end
|
45
73
|
|
74
|
+
sig do
|
75
|
+
params(
|
76
|
+
repository_details: T::Hash[Symbol, T.untyped],
|
77
|
+
package_id: String,
|
78
|
+
package_version: String
|
79
|
+
)
|
80
|
+
.returns(T.nilable(String))
|
81
|
+
end
|
46
82
|
def self.get_nuget_v3_package_url(repository_details, package_id, package_version)
|
47
83
|
base_url = repository_details[:base_url]
|
48
84
|
unless base_url
|
@@ -57,15 +93,23 @@ module Dependabot
|
|
57
93
|
|
58
94
|
# rubocop:disable Metrics/CyclomaticComplexity
|
59
95
|
# rubocop:disable Metrics/PerceivedComplexity
|
96
|
+
sig do
|
97
|
+
params(
|
98
|
+
repository_details: T::Hash[Symbol, T.untyped],
|
99
|
+
package_id: String,
|
100
|
+
package_version: String
|
101
|
+
)
|
102
|
+
.returns(T.nilable(String))
|
103
|
+
end
|
60
104
|
def self.get_nuget_v3_package_url_from_search(repository_details, package_id, package_version)
|
61
105
|
search_url = repository_details[:search_url]
|
62
106
|
return nil unless search_url
|
63
107
|
|
64
108
|
# get search result
|
65
109
|
search_result_response = fetch_url(search_url, repository_details)
|
66
|
-
return nil unless search_result_response
|
110
|
+
return nil unless search_result_response&.status == 200
|
67
111
|
|
68
|
-
search_response_body = HttpResponseHelpers.remove_wrapping_zero_width_chars(search_result_response.body)
|
112
|
+
search_response_body = HttpResponseHelpers.remove_wrapping_zero_width_chars(T.must(search_result_response).body)
|
69
113
|
search_results = JSON.parse(search_response_body)
|
70
114
|
|
71
115
|
# find matching package and version
|
@@ -90,15 +134,23 @@ module Dependabot
|
|
90
134
|
# rubocop:enable Metrics/PerceivedComplexity
|
91
135
|
# rubocop:enable Metrics/CyclomaticComplexity
|
92
136
|
|
137
|
+
sig do
|
138
|
+
params(
|
139
|
+
repository_details: T::Hash[Symbol, T.untyped],
|
140
|
+
package_id: String,
|
141
|
+
package_version: String
|
142
|
+
)
|
143
|
+
.returns(T.nilable(String))
|
144
|
+
end
|
93
145
|
def self.get_nuget_v2_package_url(repository_details, package_id, package_version)
|
94
146
|
# get package XML
|
95
147
|
base_url = repository_details[:base_url].delete_suffix("/")
|
96
148
|
package_url = "#{base_url}/Packages(Id='#{package_id}',Version='#{package_version}')"
|
97
149
|
response = fetch_url(package_url, repository_details)
|
98
|
-
return nil unless response
|
150
|
+
return nil unless response&.status == 200
|
99
151
|
|
100
152
|
# find relevant element
|
101
|
-
doc = Nokogiri::XML(response.body)
|
153
|
+
doc = Nokogiri::XML(T.must(response).body)
|
102
154
|
doc.remove_namespaces!
|
103
155
|
|
104
156
|
content_element = doc.xpath("/entry/content")
|
@@ -106,6 +158,14 @@ module Dependabot
|
|
106
158
|
nupkg_url
|
107
159
|
end
|
108
160
|
|
161
|
+
sig do
|
162
|
+
params(
|
163
|
+
stream_url: String,
|
164
|
+
auth_header: T::Hash[String, String],
|
165
|
+
max_redirects: Integer
|
166
|
+
)
|
167
|
+
.returns(T.nilable(String))
|
168
|
+
end
|
109
169
|
def self.fetch_stream(stream_url, auth_header, max_redirects = 5)
|
110
170
|
current_url = stream_url
|
111
171
|
current_redirects = 0
|
@@ -128,17 +188,25 @@ module Dependabot
|
|
128
188
|
current_redirects += 1
|
129
189
|
return nil if current_redirects > max_redirects
|
130
190
|
|
131
|
-
current_url = response.headers["Location"]
|
191
|
+
current_url = T.must(response.headers["Location"])
|
132
192
|
else
|
133
193
|
return nil
|
134
194
|
end
|
135
195
|
end
|
136
196
|
end
|
137
197
|
|
198
|
+
sig do
|
199
|
+
params(
|
200
|
+
url: String,
|
201
|
+
repository_details: T::Hash[Symbol, T.untyped]
|
202
|
+
)
|
203
|
+
.returns(T.nilable(Excon::Response))
|
204
|
+
end
|
138
205
|
def self.fetch_url(url, repository_details)
|
139
206
|
fetch_url_with_auth(url, repository_details.fetch(:auth_header))
|
140
207
|
end
|
141
208
|
|
209
|
+
sig { params(url: String, auth_header: T::Hash[T.any(String, Symbol), T.untyped]).returns(Excon::Response) }
|
142
210
|
def self.fetch_url_with_auth(url, auth_header)
|
143
211
|
cache = CacheManager.cache("nupkg_fetcher_cache")
|
144
212
|
cache[url] ||= Dependabot::RegistryClient.get(
|
@@ -1,23 +1,42 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "nokogiri"
|
5
|
-
require "zip"
|
6
5
|
require "stringio"
|
6
|
+
require "sorbet-runtime"
|
7
|
+
require "zip"
|
7
8
|
|
8
9
|
module Dependabot
|
9
10
|
module Nuget
|
10
11
|
class NuspecFetcher
|
12
|
+
extend T::Sig
|
13
|
+
|
11
14
|
require_relative "nupkg_fetcher"
|
12
15
|
require_relative "repository_finder"
|
13
16
|
|
17
|
+
sig do
|
18
|
+
params(
|
19
|
+
dependency_urls: T::Array[T::Hash[Symbol, String]],
|
20
|
+
package_id: String,
|
21
|
+
package_version: T.nilable(String)
|
22
|
+
)
|
23
|
+
.returns(T.nilable(Nokogiri::XML::Document))
|
24
|
+
end
|
14
25
|
def self.fetch_nuspec(dependency_urls, package_id, package_version)
|
15
26
|
# check all repositories for the first one that has the nuspec
|
16
|
-
dependency_urls.reduce(nil) do |nuspec_xml, repository_details|
|
27
|
+
dependency_urls.reduce(T.let(nil, T.nilable(Nokogiri::XML::Document))) do |nuspec_xml, repository_details|
|
17
28
|
nuspec_xml || fetch_nuspec_from_repository(repository_details, package_id, package_version)
|
18
29
|
end
|
19
30
|
end
|
20
31
|
|
32
|
+
sig do
|
33
|
+
params(
|
34
|
+
repository_details: T::Hash[Symbol, T.untyped],
|
35
|
+
package_id: T.nilable(String),
|
36
|
+
package_version: T.nilable(String)
|
37
|
+
)
|
38
|
+
.returns(T.nilable(Nokogiri::XML::Document))
|
39
|
+
end
|
21
40
|
def self.fetch_nuspec_from_repository(repository_details, package_id, package_version)
|
22
41
|
return unless package_id && package_version && !package_version.empty?
|
23
42
|
|
@@ -55,6 +74,7 @@ module Dependabot
|
|
55
74
|
nuspec_xml
|
56
75
|
end
|
57
76
|
|
77
|
+
sig { params(feed_url: String).returns(T::Boolean) }
|
58
78
|
def self.feed_supports_nuspec_download?(feed_url)
|
59
79
|
feed_regexs = [
|
60
80
|
# nuget
|
@@ -67,6 +87,7 @@ module Dependabot
|
|
67
87
|
feed_regexs.any? { |reg| reg.match(feed_url) }
|
68
88
|
end
|
69
89
|
|
90
|
+
sig { params(zip_stream: String, package_id: String).returns(T.nilable(String)) }
|
70
91
|
def self.extract_nuspec(zip_stream, package_id)
|
71
92
|
Zip::File.open_buffer(zip_stream) do |zip|
|
72
93
|
nuspec_entry = zip.find { |entry| entry.name == "#{package_id}.nuspec" }
|
@@ -75,6 +96,7 @@ module Dependabot
|
|
75
96
|
nil
|
76
97
|
end
|
77
98
|
|
99
|
+
sig { params(string: String).returns(String) }
|
78
100
|
def self.remove_invalid_characters(string)
|
79
101
|
string.dup
|
80
102
|
.force_encoding(Encoding::UTF_8)
|
@@ -1,6 +1,8 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
4
6
|
require "dependabot/update_checkers/base"
|
5
7
|
require "dependabot/nuget/file_parser"
|
6
8
|
|
@@ -8,28 +10,47 @@ module Dependabot
|
|
8
10
|
module Nuget
|
9
11
|
class UpdateChecker < Dependabot::UpdateCheckers::Base
|
10
12
|
class PropertyUpdater
|
13
|
+
extend T::Sig
|
14
|
+
|
11
15
|
require_relative "version_finder"
|
12
16
|
require_relative "requirements_updater"
|
13
17
|
require_relative "dependency_finder"
|
14
18
|
|
19
|
+
sig do
|
20
|
+
params(
|
21
|
+
dependency: Dependabot::Dependency,
|
22
|
+
dependency_files: T::Array[Dependabot::DependencyFile],
|
23
|
+
credentials: T::Array[Dependabot::Credential],
|
24
|
+
target_version_details: T.nilable(T::Hash[Symbol, String]),
|
25
|
+
ignored_versions: T::Array[String],
|
26
|
+
repo_contents_path: T.nilable(String),
|
27
|
+
raise_on_ignored: T::Boolean
|
28
|
+
).void
|
29
|
+
end
|
15
30
|
def initialize(dependency:, dependency_files:, credentials:,
|
16
31
|
target_version_details:, ignored_versions:,
|
17
|
-
raise_on_ignored: false
|
32
|
+
repo_contents_path:, raise_on_ignored: false)
|
18
33
|
@dependency = dependency
|
19
34
|
@dependency_files = dependency_files
|
20
35
|
@credentials = credentials
|
21
36
|
@ignored_versions = ignored_versions
|
22
37
|
@raise_on_ignored = raise_on_ignored
|
23
|
-
@target_version =
|
24
|
-
|
25
|
-
|
38
|
+
@target_version = T.let(
|
39
|
+
target_version_details&.fetch(:version),
|
40
|
+
T.nilable(T.any(String, Dependabot::Nuget::Version))
|
41
|
+
)
|
42
|
+
@source_details = T.let(
|
43
|
+
target_version_details&.slice(:nuspec_url, :repo_url, :source_url),
|
44
|
+
T.nilable(T::Hash[Symbol, String])
|
45
|
+
)
|
26
46
|
@repo_contents_path = repo_contents_path
|
27
47
|
end
|
28
48
|
|
49
|
+
sig { returns(T::Boolean) }
|
29
50
|
def update_possible?
|
30
51
|
return false unless target_version
|
31
52
|
|
32
|
-
@update_possible ||=
|
53
|
+
@update_possible ||= T.let(
|
33
54
|
dependencies_using_property.all? do |dep|
|
34
55
|
versions = VersionFinder.new(
|
35
56
|
dependency: dep,
|
@@ -42,42 +63,73 @@ module Dependabot
|
|
42
63
|
).versions.map { |v| v.fetch(:version) }
|
43
64
|
|
44
65
|
versions.include?(target_version) || versions.none?
|
45
|
-
end
|
66
|
+
end,
|
67
|
+
T.nilable(T::Boolean)
|
68
|
+
)
|
46
69
|
end
|
47
70
|
|
71
|
+
sig { returns(T::Array[Dependabot::Dependency]) }
|
48
72
|
def updated_dependencies
|
49
73
|
raise "Update not possible!" unless update_possible?
|
50
74
|
|
51
|
-
@updated_dependencies ||=
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
75
|
+
@updated_dependencies ||= T.let(
|
76
|
+
begin
|
77
|
+
dependencies = T.let({}, T::Hash[String, Dependabot::Dependency])
|
78
|
+
|
79
|
+
dependencies_using_property.each do |dep|
|
80
|
+
# Only keep one copy of each dependency, the one with the highest target version.
|
81
|
+
visited_dependency = dependencies[dep.name.downcase]
|
82
|
+
next unless visited_dependency.nil? || T.must(visited_dependency.numeric_version) < target_version
|
83
|
+
|
84
|
+
updated_dependency = Dependency.new(
|
85
|
+
name: dep.name,
|
86
|
+
version: target_version.to_s,
|
87
|
+
requirements: updated_requirements(dep),
|
88
|
+
previous_version: dep.version,
|
89
|
+
previous_requirements: dep.requirements,
|
90
|
+
package_manager: dep.package_manager
|
91
|
+
)
|
92
|
+
dependencies[updated_dependency.name.downcase] = updated_dependency
|
93
|
+
# Add peer dependencies to the list of updated dependencies.
|
94
|
+
process_updated_peer_dependencies(updated_dependency, dependencies)
|
95
|
+
end
|
71
96
|
|
72
|
-
|
73
|
-
|
97
|
+
dependencies.map { |_, dependency| dependency }
|
98
|
+
end,
|
99
|
+
T.nilable(T::Array[Dependabot::Dependency])
|
100
|
+
)
|
74
101
|
end
|
75
102
|
|
76
103
|
private
|
77
104
|
|
78
|
-
|
79
|
-
|
105
|
+
sig { returns(Dependabot::Dependency) }
|
106
|
+
attr_reader :dependency
|
107
|
+
|
108
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
109
|
+
attr_reader :dependency_files
|
110
|
+
|
111
|
+
sig { returns(T.nilable(T.any(String, Dependabot::Nuget::Version))) }
|
112
|
+
attr_reader :target_version
|
80
113
|
|
114
|
+
sig { returns(T.nilable(T::Hash[Symbol, String])) }
|
115
|
+
attr_reader :source_details
|
116
|
+
|
117
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
118
|
+
attr_reader :credentials
|
119
|
+
|
120
|
+
sig { returns(T::Array[String]) }
|
121
|
+
attr_reader :ignored_versions
|
122
|
+
|
123
|
+
sig { returns(T.nilable(String)) }
|
124
|
+
attr_reader :repo_contents_path
|
125
|
+
|
126
|
+
sig do
|
127
|
+
params(
|
128
|
+
dependency: Dependabot::Dependency,
|
129
|
+
dependencies: T::Hash[String, Dependabot::Dependency]
|
130
|
+
)
|
131
|
+
.returns(T::Array[Dependabot::Dependency])
|
132
|
+
end
|
81
133
|
def process_updated_peer_dependencies(dependency, dependencies)
|
82
134
|
DependencyFinder.new(
|
83
135
|
dependency: dependency,
|
@@ -87,36 +139,48 @@ module Dependabot
|
|
87
139
|
).updated_peer_dependencies.each do |peer_dependency|
|
88
140
|
# Only keep one copy of each dependency, the one with the highest target version.
|
89
141
|
visited_dependency = dependencies[peer_dependency.name.downcase]
|
90
|
-
|
142
|
+
unless visited_dependency.nil? ||
|
143
|
+
T.must(visited_dependency.numeric_version) < peer_dependency.numeric_version
|
144
|
+
next
|
145
|
+
end
|
91
146
|
|
92
147
|
dependencies[peer_dependency.name.downcase] = peer_dependency
|
93
148
|
end
|
94
149
|
end
|
95
150
|
|
151
|
+
sig { returns(T::Array[Dependabot::Dependency]) }
|
96
152
|
def dependencies_using_property
|
97
153
|
@dependencies_using_property ||=
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
154
|
+
T.let(
|
155
|
+
Nuget::FileParser.new(
|
156
|
+
dependency_files: dependency_files,
|
157
|
+
source: nil
|
158
|
+
).parse.select do |dep|
|
159
|
+
dep.requirements.any? do |r|
|
160
|
+
r.dig(:metadata, :property_name) == property_name
|
161
|
+
end
|
162
|
+
end,
|
163
|
+
T.nilable(T::Array[Dependabot::Dependency])
|
164
|
+
)
|
106
165
|
end
|
107
166
|
|
167
|
+
sig { returns(String) }
|
108
168
|
def property_name
|
109
|
-
@property_name ||=
|
110
|
-
|
111
|
-
|
169
|
+
@property_name ||= T.let(
|
170
|
+
dependency.requirements
|
171
|
+
.find { |r| r.dig(:metadata, :property_name) }
|
172
|
+
&.dig(:metadata, :property_name),
|
173
|
+
T.nilable(String)
|
174
|
+
)
|
112
175
|
|
113
176
|
raise "No requirement with a property name!" unless @property_name
|
114
177
|
|
115
178
|
@property_name
|
116
179
|
end
|
117
180
|
|
181
|
+
sig { params(dep: Dependabot::Dependency).returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
118
182
|
def updated_requirements(dep)
|
119
|
-
@updated_requirements ||= {}
|
183
|
+
@updated_requirements ||= T.let({}, T.nilable(T::Hash[String, T::Array[T::Hash[Symbol, T.untyped]]]))
|
120
184
|
@updated_requirements[dep.name] ||=
|
121
185
|
RequirementsUpdater.new(
|
122
186
|
requirements: dep.requirements,
|