dependabot-common 0.245.0 → 0.247.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/dependabot/clients/bitbucket.rb +113 -5
- data/lib/dependabot/clients/codecommit.rb +107 -12
- data/lib/dependabot/clients/github_with_retries.rb +61 -19
- data/lib/dependabot/clients/gitlab_with_retries.rb +60 -7
- data/lib/dependabot/dependency.rb +1 -1
- data/lib/dependabot/errors.rb +20 -2
- data/lib/dependabot/file_fetchers/base.rb +8 -19
- data/lib/dependabot/file_updaters/base.rb +2 -0
- data/lib/dependabot/git_commit_checker.rb +3 -2
- data/lib/dependabot/metadata_finders/base/changelog_finder.rb +1 -1
- data/lib/dependabot/metadata_finders/base/commits_finder.rb +1 -1
- data/lib/dependabot/metadata_finders/base/release_finder.rb +1 -1
- data/lib/dependabot/pull_request_creator/azure.rb +80 -9
- data/lib/dependabot/pull_request_creator/bitbucket.rb +73 -9
- data/lib/dependabot/pull_request_creator/branch_namer/solo_strategy.rb +1 -1
- data/lib/dependabot/pull_request_creator/codecommit.rb +96 -25
- data/lib/dependabot/pull_request_creator/github.rb +162 -49
- data/lib/dependabot/pull_request_creator/gitlab.rb +109 -21
- data/lib/dependabot/pull_request_creator/message_builder/issue_linker.rb +13 -4
- data/lib/dependabot/pull_request_creator/message_builder.rb +246 -89
- data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +11 -9
- data/lib/dependabot/pull_request_creator.rb +32 -27
- data/lib/dependabot/pull_request_updater/azure.rb +75 -11
- data/lib/dependabot/pull_request_updater/github.rb +89 -28
- data/lib/dependabot/pull_request_updater/gitlab.rb +61 -12
- data/lib/dependabot/pull_request_updater.rb +1 -1
- data/lib/dependabot/registry_client.rb +2 -2
- data/lib/dependabot/requirements_update_strategy.rb +13 -0
- data/lib/dependabot/update_checkers/base.rb +123 -32
- data/lib/dependabot/update_checkers/version_filters.rb +15 -5
- data/lib/dependabot/version.rb +6 -43
- data/lib/dependabot.rb +1 -1
- metadata +18 -3
@@ -1,7 +1,9 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "pathname"
|
5
|
+
require "sorbet-runtime"
|
6
|
+
|
5
7
|
require "dependabot/clients/github_with_retries"
|
6
8
|
require "dependabot/clients/gitlab_with_retries"
|
7
9
|
require "dependabot/dependency_group"
|
@@ -15,19 +17,72 @@ module Dependabot
|
|
15
17
|
class PullRequestCreator
|
16
18
|
# MessageBuilder builds PR message for a dependency update
|
17
19
|
class MessageBuilder
|
20
|
+
extend T::Sig
|
21
|
+
|
18
22
|
require_relative "message_builder/metadata_presenter"
|
19
23
|
require_relative "message_builder/issue_linker"
|
20
24
|
require_relative "message_builder/link_and_mention_sanitizer"
|
21
25
|
require_relative "pr_name_prefixer"
|
22
26
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
sig { returns(Dependabot::Source) }
|
28
|
+
attr_reader :source
|
29
|
+
|
30
|
+
sig { returns(T::Array[Dependabot::Dependency]) }
|
31
|
+
attr_reader :dependencies
|
32
|
+
|
33
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
34
|
+
attr_reader :files
|
35
|
+
|
36
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
37
|
+
attr_reader :credentials
|
38
|
+
|
39
|
+
sig { returns(T.nilable(String)) }
|
40
|
+
attr_reader :pr_message_header
|
41
|
+
|
42
|
+
sig { returns(T.nilable(String)) }
|
43
|
+
attr_reader :pr_message_footer
|
44
|
+
|
45
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
46
|
+
attr_reader :commit_message_options
|
47
|
+
|
48
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
49
|
+
attr_reader :vulnerabilities_fixed
|
50
|
+
|
51
|
+
sig { returns(T.nilable(String)) }
|
52
|
+
attr_reader :github_redirection_service
|
53
|
+
|
54
|
+
sig { returns(T.nilable(Dependabot::DependencyGroup)) }
|
55
|
+
attr_reader :dependency_group
|
56
|
+
|
57
|
+
sig { returns(T.nilable(Integer)) }
|
58
|
+
attr_reader :pr_message_max_length
|
59
|
+
|
60
|
+
sig { returns(T.nilable(Encoding)) }
|
61
|
+
attr_reader :pr_message_encoding
|
62
|
+
|
63
|
+
sig { returns(T::Array[T::Hash[String, String]]) }
|
64
|
+
attr_reader :ignore_conditions
|
28
65
|
|
29
66
|
TRUNCATED_MSG = "...\n\n_Description has been truncated_"
|
30
67
|
|
68
|
+
sig do
|
69
|
+
params(
|
70
|
+
source: Dependabot::Source,
|
71
|
+
dependencies: T::Array[Dependabot::Dependency],
|
72
|
+
files: T::Array[Dependabot::DependencyFile],
|
73
|
+
credentials: T::Array[Dependabot::Credential],
|
74
|
+
pr_message_header: T.nilable(String),
|
75
|
+
pr_message_footer: T.nilable(String),
|
76
|
+
commit_message_options: T.nilable(T::Hash[Symbol, T.untyped]),
|
77
|
+
vulnerabilities_fixed: T::Hash[String, T.untyped],
|
78
|
+
github_redirection_service: T.nilable(String),
|
79
|
+
dependency_group: T.nilable(Dependabot::DependencyGroup),
|
80
|
+
pr_message_max_length: T.nilable(Integer),
|
81
|
+
pr_message_encoding: T.nilable(Encoding),
|
82
|
+
ignore_conditions: T::Array[T::Hash[String, String]]
|
83
|
+
)
|
84
|
+
.void
|
85
|
+
end
|
31
86
|
def initialize(source:, dependencies:, files:, credentials:,
|
32
87
|
pr_message_header: nil, pr_message_footer: nil,
|
33
88
|
commit_message_options: {}, vulnerabilities_fixed: {},
|
@@ -48,16 +103,20 @@ module Dependabot
|
|
48
103
|
@ignore_conditions = ignore_conditions
|
49
104
|
end
|
50
105
|
|
106
|
+
sig { params(pr_message_max_length: Integer).returns(Integer) }
|
51
107
|
attr_writer :pr_message_max_length
|
52
108
|
|
109
|
+
sig { params(pr_message_encoding: Encoding).returns(Encoding) }
|
53
110
|
attr_writer :pr_message_encoding
|
54
111
|
|
112
|
+
sig { returns(String) }
|
55
113
|
def pr_name
|
56
114
|
name = dependency_group ? group_pr_name : solo_pr_name
|
57
|
-
name[0] = name[0].capitalize if pr_name_prefixer.capitalize_first_word?
|
115
|
+
name[0] = T.must(name[0]).capitalize if pr_name_prefixer.capitalize_first_word?
|
58
116
|
"#{pr_name_prefix}#{name}"
|
59
117
|
end
|
60
118
|
|
119
|
+
sig { returns(String) }
|
61
120
|
def pr_message
|
62
121
|
msg = "#{suffixed_pr_message_header}" \
|
63
122
|
"#{commit_message_intro}" \
|
@@ -73,35 +132,42 @@ module Dependabot
|
|
73
132
|
|
74
133
|
# Truncate PR message as determined by the pr_message_max_length and pr_message_encoding instance variables
|
75
134
|
# The encoding is used when calculating length, all messages are returned as ruby UTF_8 encoded string
|
135
|
+
sig { params(msg: String).returns(String) }
|
76
136
|
def truncate_pr_message(msg)
|
77
137
|
return msg if pr_message_max_length.nil?
|
78
138
|
|
79
139
|
msg = msg.dup
|
80
|
-
msg = msg.force_encoding(pr_message_encoding) unless pr_message_encoding.nil?
|
140
|
+
msg = msg.force_encoding(T.must(pr_message_encoding)) unless pr_message_encoding.nil?
|
81
141
|
|
82
|
-
if msg.length > pr_message_max_length
|
83
|
-
tr_msg = pr_message_encoding.nil?
|
84
|
-
|
85
|
-
|
142
|
+
if msg.length > T.must(pr_message_max_length)
|
143
|
+
tr_msg = if pr_message_encoding.nil?
|
144
|
+
TRUNCATED_MSG
|
145
|
+
else
|
146
|
+
(+TRUNCATED_MSG).dup.force_encoding(T.must(pr_message_encoding))
|
147
|
+
end
|
148
|
+
trunc_length = T.must(pr_message_max_length) - tr_msg.length
|
149
|
+
msg = (T.must(msg[0..trunc_length]) + tr_msg)
|
86
150
|
end
|
87
151
|
# if we used a custom encoding for calculating length, then we need to force back to UTF-8
|
88
152
|
msg = msg.encode("utf-8", "binary", invalid: :replace, undef: :replace) unless pr_message_encoding.nil?
|
89
153
|
msg
|
90
154
|
end
|
91
155
|
|
156
|
+
sig { returns(String) }
|
92
157
|
def commit_message
|
93
158
|
message = commit_subject + "\n\n"
|
94
159
|
message += commit_message_intro
|
95
160
|
message += metadata_links
|
96
|
-
message += "\n\n" + message_trailers if message_trailers
|
161
|
+
message += "\n\n" + T.must(message_trailers) if message_trailers
|
97
162
|
message
|
98
163
|
rescue StandardError => e
|
99
164
|
Dependabot.logger.error("Error while generating commit message: #{e.message}")
|
100
165
|
message = commit_subject
|
101
|
-
message += "\n\n" + message_trailers if message_trailers
|
166
|
+
message += "\n\n" + T.must(message_trailers) if message_trailers
|
102
167
|
message
|
103
168
|
end
|
104
169
|
|
170
|
+
sig { returns(Dependabot::PullRequestCreator::Message) }
|
105
171
|
def message
|
106
172
|
Dependabot::PullRequestCreator::Message.new(
|
107
173
|
pr_name: pr_name,
|
@@ -112,65 +178,81 @@ module Dependabot
|
|
112
178
|
|
113
179
|
private
|
114
180
|
|
181
|
+
sig { returns(String) }
|
115
182
|
def solo_pr_name
|
116
183
|
name = library? ? library_pr_name : application_pr_name
|
117
184
|
"#{name}#{pr_name_directory}"
|
118
185
|
end
|
119
186
|
|
187
|
+
sig { returns(String) }
|
120
188
|
def library_pr_name
|
121
189
|
"update " +
|
122
190
|
if dependencies.count == 1
|
123
|
-
"#{dependencies.first.display_name} requirement " \
|
124
|
-
"#{from_version_msg(old_library_requirement(dependencies.first))}" \
|
125
|
-
"to #{new_library_requirement(dependencies.first)}"
|
191
|
+
"#{T.must(dependencies.first).display_name} requirement " \
|
192
|
+
"#{from_version_msg(old_library_requirement(T.must(dependencies.first)))}" \
|
193
|
+
"to #{new_library_requirement(T.must(dependencies.first))}"
|
126
194
|
else
|
127
195
|
names = dependencies.map(&:name).uniq
|
128
196
|
if names.count == 1
|
129
197
|
"requirements for #{names.first}"
|
130
198
|
else
|
131
|
-
"requirements for #{names[0..-2].join(', ')} and #{names[-1]}"
|
199
|
+
"requirements for #{T.must(names[0..-2]).join(', ')} and #{names[-1]}"
|
132
200
|
end
|
133
201
|
end
|
134
202
|
end
|
135
203
|
|
204
|
+
# rubocop:disable Metrics/AbcSize
|
205
|
+
sig { returns(String) }
|
136
206
|
def application_pr_name
|
137
207
|
"bump " +
|
138
208
|
if dependencies.count == 1
|
139
209
|
dependency = dependencies.first
|
140
|
-
"#{dependency.display_name} " \
|
141
|
-
"#{from_version_msg(dependency.humanized_previous_version)}" \
|
142
|
-
"to #{dependency.humanized_version}"
|
210
|
+
"#{T.must(dependency).display_name} " \
|
211
|
+
"#{from_version_msg(T.must(dependency).humanized_previous_version)}" \
|
212
|
+
"to #{T.must(dependency).humanized_version}"
|
143
213
|
elsif updating_a_property?
|
144
214
|
dependency = dependencies.first
|
145
215
|
"#{property_name} " \
|
146
|
-
"#{from_version_msg(dependency.humanized_previous_version)}" \
|
147
|
-
"to #{dependency.humanized_version}"
|
216
|
+
"#{from_version_msg(T.must(dependency).humanized_previous_version)}" \
|
217
|
+
"to #{T.must(dependency).humanized_version}"
|
148
218
|
elsif updating_a_dependency_set?
|
149
219
|
dependency = dependencies.first
|
150
220
|
"#{dependency_set.fetch(:group)} dependency set " \
|
151
|
-
"#{from_version_msg(dependency.humanized_previous_version)}" \
|
152
|
-
"to #{dependency.humanized_version}"
|
221
|
+
"#{from_version_msg(T.must(dependency).humanized_previous_version)}" \
|
222
|
+
"to #{T.must(dependency).humanized_version}"
|
153
223
|
else
|
154
224
|
names = dependencies.map(&:name).uniq
|
155
225
|
if names.count == 1
|
156
|
-
names.first
|
226
|
+
T.must(names.first)
|
157
227
|
else
|
158
|
-
"#{names[0..-2].join(', ')} and #{names[-1]}"
|
228
|
+
"#{T.must(names[0..-2]).join(', ')} and #{names[-1]}"
|
159
229
|
end
|
160
230
|
end
|
161
231
|
end
|
232
|
+
# rubocop:enable Metrics/AbcSize
|
162
233
|
|
234
|
+
sig { returns(String) }
|
163
235
|
def group_pr_name
|
236
|
+
directories_from_dependencies = dependencies.to_set { |dep| dep.metadata[:directory] }
|
237
|
+
|
238
|
+
directories_with_updates = source.directories&.filter do |directory|
|
239
|
+
directories_from_dependencies.include?(directory)
|
240
|
+
end
|
241
|
+
|
164
242
|
updates = dependencies.map(&:name).uniq.count
|
165
243
|
|
166
|
-
if source
|
167
|
-
"bump the #{dependency_group.name} across #{
|
244
|
+
if source.directories
|
245
|
+
"bump the #{T.must(dependency_group).name} across #{T.must(directories_with_updates).count} " \
|
246
|
+
"#{T.must(directories_with_updates).count > 1 ? 'directories' : 'directory'} " \
|
168
247
|
"with #{updates} update#{'s' if updates > 1}"
|
169
248
|
else
|
170
|
-
"bump the #{dependency_group.name} group#{pr_name_directory} with #{updates} update#{
|
249
|
+
"bump the #{T.must(dependency_group).name} group#{pr_name_directory} with #{updates} update#{if updates > 1
|
250
|
+
's'
|
251
|
+
end}"
|
171
252
|
end
|
172
253
|
end
|
173
254
|
|
255
|
+
sig { returns(String) }
|
174
256
|
def pr_name_prefix
|
175
257
|
pr_name_prefixer.pr_name_prefix
|
176
258
|
rescue StandardError => e
|
@@ -178,12 +260,14 @@ module Dependabot
|
|
178
260
|
""
|
179
261
|
end
|
180
262
|
|
263
|
+
sig { returns(String) }
|
181
264
|
def pr_name_directory
|
182
|
-
return "" if files.first.directory == "/"
|
265
|
+
return "" if T.must(files.first).directory == "/"
|
183
266
|
|
184
|
-
" in #{files.first.directory}"
|
267
|
+
" in #{T.must(files.first).directory}"
|
185
268
|
end
|
186
269
|
|
270
|
+
sig { returns(String) }
|
187
271
|
def commit_subject
|
188
272
|
subject = pr_name.gsub("⬆️", ":arrow_up:").gsub("🔒", ":lock:")
|
189
273
|
return subject unless subject.length > 72
|
@@ -191,57 +275,65 @@ module Dependabot
|
|
191
275
|
subject = subject.gsub(/ from [^\s]*? to [^\s]*/, "")
|
192
276
|
return subject unless subject.length > 72
|
193
277
|
|
194
|
-
subject.split(" in ").first
|
278
|
+
T.must(subject.split(" in ").first)
|
195
279
|
end
|
196
280
|
|
281
|
+
sig { returns(String) }
|
197
282
|
def commit_message_intro
|
198
283
|
return requirement_commit_message_intro if library?
|
199
284
|
|
200
285
|
version_commit_message_intro
|
201
286
|
end
|
202
287
|
|
288
|
+
sig { returns(String) }
|
203
289
|
def prefixed_pr_message_footer
|
204
290
|
return "" unless pr_message_footer
|
205
291
|
|
206
292
|
"\n\n#{pr_message_footer}"
|
207
293
|
end
|
208
294
|
|
295
|
+
sig { returns(String) }
|
209
296
|
def suffixed_pr_message_header
|
210
297
|
return "" unless pr_message_header
|
211
298
|
|
212
299
|
"#{pr_message_header}\n\n"
|
213
300
|
end
|
214
301
|
|
302
|
+
sig { returns(T.nilable(String)) }
|
215
303
|
def message_trailers
|
216
304
|
return unless signoff_trailers || custom_trailers
|
217
305
|
|
218
306
|
[signoff_trailers, custom_trailers].compact.join("\n")
|
219
307
|
end
|
220
308
|
|
309
|
+
sig { returns(T.nilable(String)) }
|
221
310
|
def custom_trailers
|
222
|
-
trailers = commit_message_options
|
311
|
+
trailers = commit_message_options&.dig(:trailers)
|
223
312
|
return if trailers.nil?
|
224
313
|
raise("Commit trailers must be a Hash object") unless trailers.is_a?(Hash)
|
225
314
|
|
226
315
|
trailers.compact.map { |k, v| "#{k}: #{v}" }.join("\n")
|
227
316
|
end
|
228
317
|
|
318
|
+
sig { returns(T.nilable(String)) }
|
229
319
|
def signoff_trailers
|
230
320
|
return unless on_behalf_of_message || signoff_message
|
231
321
|
|
232
322
|
[on_behalf_of_message, signoff_message].compact.join("\n")
|
233
323
|
end
|
234
324
|
|
325
|
+
sig { returns(T.nilable(String)) }
|
235
326
|
def signoff_message
|
236
|
-
signoff_details = commit_message_options
|
327
|
+
signoff_details = commit_message_options&.dig(:signoff_details)
|
237
328
|
return unless signoff_details.is_a?(Hash)
|
238
329
|
return unless signoff_details[:name] && signoff_details[:email]
|
239
330
|
|
240
331
|
"Signed-off-by: #{signoff_details[:name]} <#{signoff_details[:email]}>"
|
241
332
|
end
|
242
333
|
|
334
|
+
sig { returns(T.nilable(String)) }
|
243
335
|
def on_behalf_of_message
|
244
|
-
signoff_details = commit_message_options
|
336
|
+
signoff_details = commit_message_options&.dig(:signoff_details)
|
245
337
|
return unless signoff_details.is_a?(Hash)
|
246
338
|
return unless signoff_details[:org_name] && signoff_details[:org_email]
|
247
339
|
|
@@ -249,6 +341,7 @@ module Dependabot
|
|
249
341
|
"<#{signoff_details[:org_email]}>"
|
250
342
|
end
|
251
343
|
|
344
|
+
sig { returns(String) }
|
252
345
|
def requirement_commit_message_intro
|
253
346
|
msg = "Updates the requirements on "
|
254
347
|
|
@@ -256,7 +349,7 @@ module Dependabot
|
|
256
349
|
if dependencies.count == 1
|
257
350
|
"#{dependency_links.first} "
|
258
351
|
else
|
259
|
-
"#{dependency_links[0..-2].join(', ')} and #{dependency_links[-1]} "
|
352
|
+
"#{T.must(dependency_links[0..-2]).join(', ')} and #{dependency_links[-1]} "
|
260
353
|
end
|
261
354
|
|
262
355
|
msg + "to permit the latest version."
|
@@ -265,8 +358,9 @@ module Dependabot
|
|
265
358
|
# rubocop:disable Metrics/CyclomaticComplexity
|
266
359
|
# rubocop:disable Metrics/PerceivedComplexity
|
267
360
|
# rubocop:disable Metrics/AbcSize
|
361
|
+
sig { returns(String) }
|
268
362
|
def version_commit_message_intro
|
269
|
-
return multi_directory_group_intro if dependency_group && source
|
363
|
+
return multi_directory_group_intro if dependency_group && source.directories
|
270
364
|
|
271
365
|
return group_intro if dependency_group
|
272
366
|
|
@@ -283,14 +377,16 @@ module Dependabot
|
|
283
377
|
|
284
378
|
dependency = dependencies.first
|
285
379
|
msg = "Bumps #{dependency_links.first} " \
|
286
|
-
"#{from_version_msg(dependency.humanized_previous_version)}" \
|
287
|
-
"to #{dependency.humanized_version}."
|
380
|
+
"#{from_version_msg(T.must(dependency).humanized_previous_version)}" \
|
381
|
+
"to #{T.must(dependency).humanized_version}."
|
288
382
|
|
289
|
-
|
383
|
+
if switching_from_ref_to_release?(T.must(dependency))
|
384
|
+
msg += " This release includes the previously tagged commit."
|
385
|
+
end
|
290
386
|
|
291
|
-
if vulnerabilities_fixed[dependency.name]&.one?
|
387
|
+
if vulnerabilities_fixed[T.must(dependency).name]&.one?
|
292
388
|
msg += " **This update includes a security fix.**"
|
293
|
-
elsif vulnerabilities_fixed[dependency.name]&.any?
|
389
|
+
elsif vulnerabilities_fixed[T.must(dependency).name]&.any?
|
294
390
|
msg += " **This update includes security fixes.**"
|
295
391
|
end
|
296
392
|
|
@@ -300,35 +396,39 @@ module Dependabot
|
|
300
396
|
# rubocop:enable Metrics/PerceivedComplexity
|
301
397
|
# rubocop:enable Metrics/AbcSize
|
302
398
|
|
399
|
+
sig { returns(String) }
|
303
400
|
def multidependency_property_intro
|
304
401
|
dependency = dependencies.first
|
305
402
|
|
306
403
|
"Bumps `#{property_name}` " \
|
307
|
-
"#{from_version_msg(dependency.humanized_previous_version)}" \
|
308
|
-
"to #{dependency.humanized_version}."
|
404
|
+
"#{from_version_msg(T.must(dependency).humanized_previous_version)}" \
|
405
|
+
"to #{T.must(dependency).humanized_version}."
|
309
406
|
end
|
310
407
|
|
408
|
+
sig { returns(String) }
|
311
409
|
def dependency_set_intro
|
312
410
|
dependency = dependencies.first
|
313
411
|
|
314
412
|
"Bumps `#{dependency_set.fetch(:group)}` " \
|
315
|
-
"dependency set #{from_version_msg(dependency.humanized_previous_version)}" \
|
316
|
-
"to #{dependency.humanized_version}."
|
413
|
+
"dependency set #{from_version_msg(T.must(dependency).humanized_previous_version)}" \
|
414
|
+
"to #{T.must(dependency).humanized_version}."
|
317
415
|
end
|
318
416
|
|
417
|
+
sig { returns(String) }
|
319
418
|
def multidependency_intro
|
320
|
-
"Bumps #{dependency_links[0..-2].join(', ')} " \
|
419
|
+
"Bumps #{T.must(dependency_links[0..-2]).join(', ')} " \
|
321
420
|
"and #{dependency_links[-1]}. These " \
|
322
421
|
"dependencies needed to be updated together."
|
323
422
|
end
|
324
423
|
|
424
|
+
sig { returns(String) }
|
325
425
|
def transitive_multidependency_intro
|
326
426
|
dependency = dependencies.first
|
327
427
|
|
328
|
-
msg = "Bumps #{dependency_links[0]} to #{dependency.humanized_version}"
|
428
|
+
msg = "Bumps #{dependency_links[0]} to #{T.must(dependency).humanized_version}"
|
329
429
|
|
330
430
|
msg += if dependencies.count > 2
|
331
|
-
" and updates ancestor dependencies #{dependency_links[0..-2].join(', ')} " \
|
431
|
+
" and updates ancestor dependencies #{T.must(dependency_links[0..-2]).join(', ')} " \
|
332
432
|
"and #{dependency_links[-1]}. "
|
333
433
|
else
|
334
434
|
" and updates ancestor dependency #{dependency_links[1]}. "
|
@@ -339,11 +439,12 @@ module Dependabot
|
|
339
439
|
msg
|
340
440
|
end
|
341
441
|
|
442
|
+
sig { returns(String) }
|
342
443
|
def transitive_removed_dependency_intro
|
343
444
|
msg = "Removes #{dependency_links[0]}. It's no longer used after updating"
|
344
445
|
|
345
446
|
msg += if dependencies.count > 2
|
346
|
-
" ancestor dependencies #{dependency_links[0..-2].join(', ')} " \
|
447
|
+
" ancestor dependencies #{T.must(dependency_links[0..-2]).join(', ')} " \
|
347
448
|
"and #{dependency_links[-1]}. "
|
348
449
|
else
|
349
450
|
" ancestor dependency #{dependency_links[1]}. "
|
@@ -354,16 +455,18 @@ module Dependabot
|
|
354
455
|
msg
|
355
456
|
end
|
356
457
|
|
458
|
+
# rubocop:disable Metrics/AbcSize
|
459
|
+
sig { returns(String) }
|
357
460
|
def multi_directory_group_intro
|
358
461
|
msg = ""
|
359
462
|
|
360
|
-
source.directories.each do |directory|
|
463
|
+
T.must(source.directories).each do |directory|
|
361
464
|
dependencies_in_directory = dependencies.select { |dep| dep.metadata[:directory] == directory }
|
362
465
|
next unless dependencies_in_directory.any?
|
363
466
|
|
364
467
|
update_count = dependencies_in_directory.map(&:name).uniq.count
|
365
468
|
|
366
|
-
msg += "Bumps the #{dependency_group.name} " \
|
469
|
+
msg += "Bumps the #{T.must(dependency_group).name} " \
|
367
470
|
"with #{update_count} update#{update_count > 1 ? 's' : ''} in the #{directory} directory:"
|
368
471
|
|
369
472
|
msg += if update_count >= 5
|
@@ -378,10 +481,11 @@ module Dependabot
|
|
378
481
|
"\n\n#{table([header] + rows)}"
|
379
482
|
elsif update_count > 1
|
380
483
|
dependency_links_in_directory = dependency_links_for_directory(directory)
|
381
|
-
" #{dependency_links_in_directory[0..-2].join(', ')}
|
484
|
+
" #{T.must(T.must(dependency_links_in_directory)[0..-2]).join(', ')}" \
|
485
|
+
" and #{T.must(dependency_links_in_directory)[-1]}."
|
382
486
|
else
|
383
487
|
dependency_links_in_directory = dependency_links_for_directory(directory)
|
384
|
-
" #{dependency_links_in_directory.first}."
|
488
|
+
" #{T.must(dependency_links_in_directory).first}."
|
385
489
|
end
|
386
490
|
|
387
491
|
msg += "\n"
|
@@ -389,11 +493,13 @@ module Dependabot
|
|
389
493
|
|
390
494
|
msg
|
391
495
|
end
|
496
|
+
# rubocop:enable Metrics/AbcSize
|
392
497
|
|
498
|
+
sig { returns(String) }
|
393
499
|
def group_intro
|
394
500
|
update_count = dependencies.map(&:name).uniq.count
|
395
501
|
|
396
|
-
msg = "Bumps the #{dependency_group.name} group#{pr_name_directory} " \
|
502
|
+
msg = "Bumps the #{T.must(dependency_group).name} group#{pr_name_directory} " \
|
397
503
|
"with #{update_count} update#{update_count > 1 ? 's' : ''}:"
|
398
504
|
|
399
505
|
msg += if update_count >= 5
|
@@ -407,7 +513,7 @@ module Dependabot
|
|
407
513
|
end
|
408
514
|
"\n\n#{table([header] + rows)}"
|
409
515
|
elsif update_count > 1
|
410
|
-
" #{dependency_links[0..-2].join(', ')} and #{dependency_links[-1]}."
|
516
|
+
" #{T.must(dependency_links[0..-2]).join(', ')} and #{dependency_links[-1]}."
|
411
517
|
else
|
412
518
|
" #{dependency_links.first}."
|
413
519
|
end
|
@@ -417,66 +523,86 @@ module Dependabot
|
|
417
523
|
msg
|
418
524
|
end
|
419
525
|
|
526
|
+
sig { params(previous_version: T.nilable(String)).returns(String) }
|
420
527
|
def from_version_msg(previous_version)
|
421
528
|
return "" unless previous_version
|
422
529
|
|
423
530
|
"from #{previous_version} "
|
424
531
|
end
|
425
532
|
|
533
|
+
sig { returns(T::Boolean) }
|
426
534
|
def updating_a_property?
|
427
|
-
dependencies.first
|
428
|
-
|
429
|
-
|
535
|
+
T.must(dependencies.first)
|
536
|
+
.requirements
|
537
|
+
.any? { |r| r.dig(:metadata, :property_name) }
|
430
538
|
end
|
431
539
|
|
540
|
+
sig { returns(T::Boolean) }
|
432
541
|
def updating_a_dependency_set?
|
433
|
-
dependencies.first
|
434
|
-
|
435
|
-
|
542
|
+
T.must(dependencies.first)
|
543
|
+
.requirements
|
544
|
+
.any? { |r| r.dig(:metadata, :dependency_set) }
|
436
545
|
end
|
437
546
|
|
547
|
+
sig { returns(T::Boolean) }
|
438
548
|
def removing_a_transitive_dependency?
|
439
549
|
dependencies.any?(&:removed?)
|
440
550
|
end
|
441
551
|
|
552
|
+
sig { returns(T::Boolean) }
|
442
553
|
def updating_top_level_and_transitive_dependencies?
|
443
554
|
dependencies.any?(&:top_level?) &&
|
444
555
|
dependencies.any? { |dep| !dep.top_level? }
|
445
556
|
end
|
446
557
|
|
558
|
+
sig { returns(String) }
|
447
559
|
def property_name
|
448
|
-
@property_name ||=
|
449
|
-
|
450
|
-
|
560
|
+
@property_name ||=
|
561
|
+
T.let(
|
562
|
+
dependencies.first
|
563
|
+
&.requirements
|
564
|
+
&.find { |r| r.dig(:metadata, :property_name) }
|
565
|
+
&.dig(:metadata, :property_name),
|
566
|
+
T.nilable(String)
|
567
|
+
)
|
451
568
|
|
452
569
|
raise "No property name!" unless @property_name
|
453
570
|
|
454
571
|
@property_name
|
455
572
|
end
|
456
573
|
|
574
|
+
sig { returns(T::Hash[Symbol, String]) }
|
457
575
|
def dependency_set
|
458
|
-
@dependency_set ||=
|
459
|
-
|
460
|
-
|
576
|
+
@dependency_set ||=
|
577
|
+
T.let(
|
578
|
+
dependencies.first
|
579
|
+
&.requirements
|
580
|
+
&.find { |r| r.dig(:metadata, :dependency_set) }
|
581
|
+
&.dig(:metadata, :dependency_set),
|
582
|
+
T.nilable(T.nilable(T::Hash[Symbol, String]))
|
583
|
+
)
|
461
584
|
|
462
585
|
raise "No dependency set!" unless @dependency_set
|
463
586
|
|
464
587
|
@dependency_set
|
465
588
|
end
|
466
589
|
|
590
|
+
sig { returns(T::Array[String]) }
|
467
591
|
def dependency_links
|
468
|
-
return @dependency_links if defined?(@dependency_links)
|
592
|
+
return T.must(@dependency_links) if defined?(@dependency_links)
|
469
593
|
|
470
594
|
uniq_deps = dependencies.each_with_object({}) { |dep, memo| memo[dep.name] ||= dep }.values
|
471
595
|
@dependency_links = uniq_deps.map { |dep| dependency_link(dep) }
|
472
596
|
end
|
473
597
|
|
598
|
+
sig { params(directory: String).returns(T.nilable(T::Array[String])) }
|
474
599
|
def dependency_links_for_directory(directory)
|
475
600
|
dependencies_in_directory = dependencies.select { |dep| dep.metadata[:directory] == directory }
|
476
601
|
uniq_deps = dependencies_in_directory.each_with_object({}) { |dep, memo| memo[dep.name] ||= dep }.values
|
477
|
-
@dependency_links = uniq_deps.map { |dep| dependency_link(dep) }
|
602
|
+
@dependency_links = T.let(uniq_deps.map { |dep| dependency_link(dep) }, T.nilable(T::Array[String]))
|
478
603
|
end
|
479
604
|
|
605
|
+
sig { params(dependency: Dependabot::Dependency).returns(String) }
|
480
606
|
def dependency_link(dependency)
|
481
607
|
if source_url(dependency)
|
482
608
|
"[#{dependency.display_name}](#{source_url(dependency)})"
|
@@ -487,12 +613,14 @@ module Dependabot
|
|
487
613
|
end
|
488
614
|
end
|
489
615
|
|
616
|
+
sig { params(dependency: Dependabot::Dependency).returns(String) }
|
490
617
|
def dependency_version_update(dependency)
|
491
618
|
"#{dependency.humanized_previous_version} to #{dependency.humanized_version}"
|
492
619
|
end
|
493
620
|
|
621
|
+
sig { returns(String) }
|
494
622
|
def metadata_links
|
495
|
-
return metadata_links_for_dep(dependencies.first) if dependencies.count == 1 && dependency_group.nil?
|
623
|
+
return metadata_links_for_dep(T.must(dependencies.first)) if dependencies.count == 1 && dependency_group.nil?
|
496
624
|
|
497
625
|
dependencies.map do |dep|
|
498
626
|
if dep.removed?
|
@@ -506,6 +634,7 @@ module Dependabot
|
|
506
634
|
end.join
|
507
635
|
end
|
508
636
|
|
637
|
+
sig { params(dep: Dependabot::Dependency).returns(String) }
|
509
638
|
def metadata_links_for_dep(dep)
|
510
639
|
msg = ""
|
511
640
|
msg += "\n- [Release notes](#{releases_url(dep)})" if releases_url(dep)
|
@@ -515,13 +644,15 @@ module Dependabot
|
|
515
644
|
msg
|
516
645
|
end
|
517
646
|
|
647
|
+
sig { params(rows: T::Array[T::Array[String]]).returns(String) }
|
518
648
|
def table(rows)
|
519
649
|
[
|
520
|
-
table_header(rows[0]),
|
521
|
-
rows[1..].map { |r| table_row(r) }
|
650
|
+
table_header(T.must(rows[0])),
|
651
|
+
T.must(rows[1..]).map { |r| table_row(r) }
|
522
652
|
].join("\n")
|
523
653
|
end
|
524
654
|
|
655
|
+
sig { params(row: T::Array[String]).returns(String) }
|
525
656
|
def table_header(row)
|
526
657
|
[
|
527
658
|
table_row(row),
|
@@ -529,12 +660,14 @@ module Dependabot
|
|
529
660
|
].join("\n")
|
530
661
|
end
|
531
662
|
|
663
|
+
sig { params(row: T::Array[String]).returns(String) }
|
532
664
|
def table_row(row)
|
533
665
|
"| #{row.join(' | ')} |"
|
534
666
|
end
|
535
667
|
|
668
|
+
sig { returns(String) }
|
536
669
|
def metadata_cascades # rubocop:disable Metrics/PerceivedComplexity
|
537
|
-
return metadata_cascades_for_dep(dependencies.first) if dependencies.one? && !dependency_group
|
670
|
+
return metadata_cascades_for_dep(T.must(dependencies.first)) if dependencies.one? && !dependency_group
|
538
671
|
|
539
672
|
dependencies.map do |dep|
|
540
673
|
msg = if dep.removed?
|
@@ -555,6 +688,7 @@ module Dependabot
|
|
555
688
|
end.join
|
556
689
|
end
|
557
690
|
|
691
|
+
sig { params(dependency: Dependabot::Dependency).returns(String) }
|
558
692
|
def metadata_cascades_for_dep(dependency)
|
559
693
|
return "" if dependency.removed?
|
560
694
|
|
@@ -567,6 +701,7 @@ module Dependabot
|
|
567
701
|
).to_s
|
568
702
|
end
|
569
703
|
|
704
|
+
sig { returns(String) }
|
570
705
|
def ignore_conditions_table
|
571
706
|
# Return an empty string if ignore_conditions is empty
|
572
707
|
return "" if @ignore_conditions.empty?
|
@@ -580,7 +715,9 @@ module Dependabot
|
|
580
715
|
return "" if valid_ignore_conditions.empty?
|
581
716
|
|
582
717
|
# Sort them by updated_at (or created_at if updated_at is nil), taking the latest 20
|
583
|
-
sorted_ignore_conditions = valid_ignore_conditions.sort_by
|
718
|
+
sorted_ignore_conditions = valid_ignore_conditions.sort_by do |ic|
|
719
|
+
ic["updated_at"].nil? ? T.must(ic["created_at"]) : T.must(ic["updated_at"])
|
720
|
+
end.last(20)
|
584
721
|
|
585
722
|
# Map each condition to a row string
|
586
723
|
table_rows = sorted_ignore_conditions.map do |ic|
|
@@ -591,6 +728,7 @@ module Dependabot
|
|
591
728
|
build_table(summary, table_rows)
|
592
729
|
end
|
593
730
|
|
731
|
+
sig { params(summary: String, rows: T::Array[String]).returns(String) }
|
594
732
|
def build_table(summary, rows)
|
595
733
|
table_header = "| Dependency Name | Ignore Conditions |"
|
596
734
|
table_divider = "| --- | --- |"
|
@@ -607,74 +745,87 @@ module Dependabot
|
|
607
745
|
end
|
608
746
|
end
|
609
747
|
|
748
|
+
sig { params(dependency: Dependabot::Dependency).returns(T.nilable(String)) }
|
610
749
|
def changelog_url(dependency)
|
611
750
|
metadata_finder(dependency).changelog_url
|
612
751
|
end
|
613
752
|
|
753
|
+
sig { params(dependency: Dependabot::Dependency).returns(T.nilable(String)) }
|
614
754
|
def commits_url(dependency)
|
615
755
|
metadata_finder(dependency).commits_url
|
616
756
|
end
|
617
757
|
|
758
|
+
sig { params(dependency: Dependabot::Dependency).returns(T.nilable(String)) }
|
618
759
|
def homepage_url(dependency)
|
619
760
|
metadata_finder(dependency).homepage_url
|
620
761
|
end
|
621
762
|
|
763
|
+
sig { params(dependency: Dependabot::Dependency).returns(T.nilable(String)) }
|
622
764
|
def releases_url(dependency)
|
623
765
|
metadata_finder(dependency).releases_url
|
624
766
|
end
|
625
767
|
|
768
|
+
sig { params(dependency: Dependabot::Dependency).returns(T.nilable(String)) }
|
626
769
|
def source_url(dependency)
|
627
770
|
metadata_finder(dependency).source_url
|
628
771
|
end
|
629
772
|
|
773
|
+
sig { params(dependency: Dependabot::Dependency).returns(T.nilable(String)) }
|
630
774
|
def upgrade_url(dependency)
|
631
775
|
metadata_finder(dependency).upgrade_guide_url
|
632
776
|
end
|
633
777
|
|
778
|
+
sig { params(dependency: Dependabot::Dependency).returns(Dependabot::MetadataFinders::Base) }
|
634
779
|
def metadata_finder(dependency)
|
635
|
-
@metadata_finder ||= {}
|
780
|
+
@metadata_finder ||= T.let({}, T.nilable(T::Hash[String, Dependabot::MetadataFinders::Base]))
|
636
781
|
@metadata_finder[dependency.name] ||=
|
637
782
|
MetadataFinders
|
638
783
|
.for_package_manager(dependency.package_manager)
|
639
784
|
.new(dependency: dependency, credentials: credentials)
|
640
785
|
end
|
641
786
|
|
787
|
+
sig { returns(Dependabot::PullRequestCreator::PrNamePrefixer) }
|
642
788
|
def pr_name_prefixer
|
643
789
|
@pr_name_prefixer ||=
|
644
|
-
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
790
|
+
T.let(
|
791
|
+
PrNamePrefixer.new(
|
792
|
+
source: source,
|
793
|
+
dependencies: dependencies,
|
794
|
+
credentials: credentials,
|
795
|
+
commit_message_options: commit_message_options,
|
796
|
+
security_fix: vulnerabilities_fixed.values.flatten.any?
|
797
|
+
),
|
798
|
+
T.nilable(Dependabot::PullRequestCreator::PrNamePrefixer)
|
650
799
|
)
|
651
800
|
end
|
652
801
|
|
802
|
+
sig { params(dependency: Dependabot::Dependency).returns(T.nilable(String)) }
|
653
803
|
def old_library_requirement(dependency)
|
654
804
|
old_reqs =
|
655
|
-
dependency.previous_requirements - dependency.requirements
|
805
|
+
T.must(dependency.previous_requirements) - dependency.requirements
|
656
806
|
|
657
807
|
gemspec =
|
658
808
|
old_reqs.find { |r| r[:file].match?(%r{^[^/]*\.gemspec$}) }
|
659
809
|
return gemspec.fetch(:requirement) if gemspec
|
660
810
|
|
661
|
-
req = old_reqs.first.fetch(:requirement)
|
811
|
+
req = T.must(old_reqs.first).fetch(:requirement)
|
662
812
|
return req if req
|
663
813
|
|
664
814
|
dependency.previous_ref if dependency.ref_changed?
|
665
815
|
end
|
666
816
|
|
817
|
+
sig { params(dependency: Dependabot::Dependency).returns(String) }
|
667
818
|
def new_library_requirement(dependency)
|
668
819
|
updated_reqs =
|
669
|
-
dependency.requirements - dependency.previous_requirements
|
820
|
+
dependency.requirements - T.must(dependency.previous_requirements)
|
670
821
|
|
671
822
|
gemspec =
|
672
823
|
updated_reqs.find { |r| r[:file].match?(%r{^[^/]*\.gemspec$}) }
|
673
824
|
return gemspec.fetch(:requirement) if gemspec
|
674
825
|
|
675
|
-
req = updated_reqs.first.fetch(:requirement)
|
826
|
+
req = T.must(updated_reqs.first).fetch(:requirement)
|
676
827
|
return req if req
|
677
|
-
return dependency.new_ref if dependency.ref_changed? && dependency.new_ref
|
828
|
+
return T.must(dependency.new_ref) if dependency.ref_changed? && dependency.new_ref
|
678
829
|
|
679
830
|
raise "No new requirement!"
|
680
831
|
end
|
@@ -684,6 +835,7 @@ module Dependabot
|
|
684
835
|
# `requirements_update_strategy`.
|
685
836
|
#
|
686
837
|
# TODO reuse in BranchNamer
|
838
|
+
sig { returns(T::Boolean) }
|
687
839
|
def library?
|
688
840
|
# Reject any nested child gemspecs/vendored git dependencies
|
689
841
|
root_files = files.map(&:name)
|
@@ -693,6 +845,7 @@ module Dependabot
|
|
693
845
|
dependencies.any? { |d| d.humanized_previous_version.nil? }
|
694
846
|
end
|
695
847
|
|
848
|
+
sig { params(dependency: Dependabot::Dependency).returns(T::Boolean) }
|
696
849
|
def switching_from_ref_to_release?(dependency)
|
697
850
|
unless dependency.previous_version&.match?(/^[0-9a-f]{40}$/) ||
|
698
851
|
(dependency.previous_version.nil? && dependency.previous_ref)
|
@@ -702,8 +855,12 @@ module Dependabot
|
|
702
855
|
Gem::Version.correct?(dependency.version)
|
703
856
|
end
|
704
857
|
|
858
|
+
sig { returns(String) }
|
705
859
|
def package_manager
|
706
|
-
@package_manager ||=
|
860
|
+
@package_manager ||= T.let(
|
861
|
+
T.must(dependencies.first).package_manager,
|
862
|
+
T.nilable(String)
|
863
|
+
)
|
707
864
|
end
|
708
865
|
end
|
709
866
|
end
|