dependabot-nuget 0.247.0 → 0.249.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,
|