dependabot-common 0.242.1 → 0.243.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/azure.rb +112 -24
- data/lib/dependabot/clients/bitbucket.rb +1 -1
- data/lib/dependabot/credential.rb +40 -0
- data/lib/dependabot/dependency_group.rb +8 -2
- data/lib/dependabot/file_fetchers/base.rb +35 -3
- data/lib/dependabot/file_parsers/base.rb +4 -3
- data/lib/dependabot/file_updaters/artifact_updater.rb +1 -1
- data/lib/dependabot/file_updaters/base.rb +4 -3
- data/lib/dependabot/file_updaters/vendor_updater.rb +1 -1
- data/lib/dependabot/git_commit_checker.rb +3 -2
- data/lib/dependabot/git_metadata_fetcher.rb +3 -2
- data/lib/dependabot/metadata_finders/base/changelog_finder.rb +151 -56
- data/lib/dependabot/metadata_finders/base/changelog_pruner.rb +45 -14
- data/lib/dependabot/metadata_finders/base/commits_finder.rb +123 -53
- data/lib/dependabot/metadata_finders/base/release_finder.rb +84 -31
- data/lib/dependabot/metadata_finders/base.rb +4 -3
- data/lib/dependabot/pull_request_creator/azure.rb +1 -1
- data/lib/dependabot/pull_request_creator/branch_namer/solo_strategy.rb +2 -2
- data/lib/dependabot/pull_request_creator/labeler.rb +3 -2
- data/lib/dependabot/pull_request_creator/message_builder/issue_linker.rb +14 -6
- data/lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb +50 -9
- data/lib/dependabot/pull_request_creator/message_builder.rb +2 -2
- data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +164 -58
- data/lib/dependabot/pull_request_creator.rb +6 -5
- data/lib/dependabot/pull_request_updater.rb +3 -2
- data/lib/dependabot/security_advisory.rb +2 -2
- data/lib/dependabot/shared_helpers.rb +3 -2
- data/lib/dependabot/utils.rb +1 -13
- data/lib/dependabot/workspace/git.rb +1 -1
- data/lib/dependabot.rb +1 -1
- metadata +4 -3
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "excon"
|
@@ -9,9 +9,11 @@ require "dependabot/clients/gitlab_with_retries"
|
|
9
9
|
require "dependabot/clients/bitbucket_with_retries"
|
10
10
|
require "dependabot/shared_helpers"
|
11
11
|
require "dependabot/metadata_finders/base"
|
12
|
+
|
12
13
|
module Dependabot
|
13
14
|
module MetadataFinders
|
14
15
|
class Base
|
16
|
+
# rubocop:disable Metrics/ClassLength
|
15
17
|
class ChangelogFinder
|
16
18
|
extend T::Sig
|
17
19
|
|
@@ -19,24 +21,49 @@ module Dependabot
|
|
19
21
|
require_relative "commits_finder"
|
20
22
|
|
21
23
|
# Earlier entries are preferred
|
22
|
-
CHANGELOG_NAMES =
|
23
|
-
changelog news changes history release whatsnew releases
|
24
|
-
|
24
|
+
CHANGELOG_NAMES = T.let(
|
25
|
+
%w(changelog news changes history release whatsnew releases).freeze,
|
26
|
+
T::Array[String]
|
27
|
+
)
|
28
|
+
|
29
|
+
sig { returns(T.nilable(Dependabot::Source)) }
|
30
|
+
attr_reader :source
|
31
|
+
|
32
|
+
sig { returns(Dependabot::Dependency) }
|
33
|
+
attr_reader :dependency
|
34
|
+
|
35
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
36
|
+
attr_reader :credentials
|
25
37
|
|
26
|
-
|
38
|
+
sig { returns(T.nilable(String)) }
|
39
|
+
attr_reader :suggested_changelog_url
|
27
40
|
|
41
|
+
sig do
|
42
|
+
params(
|
43
|
+
source: T.nilable(Dependabot::Source),
|
44
|
+
dependency: Dependabot::Dependency,
|
45
|
+
credentials: T::Array[Dependabot::Credential],
|
46
|
+
suggested_changelog_url: T.nilable(String)
|
47
|
+
)
|
48
|
+
.void
|
49
|
+
end
|
28
50
|
def initialize(source:, dependency:, credentials:,
|
29
51
|
suggested_changelog_url: nil)
|
30
52
|
@source = source
|
31
53
|
@dependency = dependency
|
32
54
|
@credentials = credentials
|
33
55
|
@suggested_changelog_url = suggested_changelog_url
|
56
|
+
|
57
|
+
@new_version = T.let(nil, T.nilable(String))
|
58
|
+
@changelog_from_suggested_url = T.let(nil, T.untyped)
|
34
59
|
end
|
35
60
|
|
61
|
+
sig { returns(T.nilable(String)) }
|
36
62
|
def changelog_url
|
37
63
|
changelog&.html_url
|
38
64
|
end
|
39
65
|
|
66
|
+
sig { returns(T.nilable(String)) }
|
40
67
|
def changelog_text
|
41
68
|
return unless full_changelog_text
|
42
69
|
|
@@ -46,19 +73,25 @@ module Dependabot
|
|
46
73
|
).pruned_text
|
47
74
|
end
|
48
75
|
|
76
|
+
sig { returns(T.nilable(String)) }
|
49
77
|
def upgrade_guide_url
|
50
78
|
upgrade_guide&.html_url
|
51
79
|
end
|
52
80
|
|
81
|
+
sig { returns(T.nilable(String)) }
|
53
82
|
def upgrade_guide_text
|
54
83
|
return unless upgrade_guide
|
55
84
|
|
56
|
-
@upgrade_guide_text ||=
|
85
|
+
@upgrade_guide_text ||= T.let(
|
86
|
+
fetch_file_text(upgrade_guide),
|
87
|
+
T.nilable(String)
|
88
|
+
)
|
57
89
|
end
|
58
90
|
|
59
91
|
private
|
60
92
|
|
61
93
|
# rubocop:disable Metrics/PerceivedComplexity
|
94
|
+
sig { returns(T.untyped) }
|
62
95
|
def changelog
|
63
96
|
return unless changelog_from_suggested_url || source
|
64
97
|
return if git_source? && !ref_changed?
|
@@ -66,13 +99,13 @@ module Dependabot
|
|
66
99
|
|
67
100
|
# If there is a changelog, and it includes the new version, return it
|
68
101
|
if new_version && default_branch_changelog &&
|
69
|
-
fetch_file_text(default_branch_changelog)&.include?(new_version)
|
102
|
+
fetch_file_text(default_branch_changelog)&.include?(T.must(new_version))
|
70
103
|
return default_branch_changelog
|
71
104
|
end
|
72
105
|
|
73
106
|
# Otherwise, look for a changelog at the tag for this version
|
74
107
|
if new_version && relevant_tag_changelog &&
|
75
|
-
fetch_file_text(relevant_tag_changelog)&.include?(new_version)
|
108
|
+
fetch_file_text(relevant_tag_changelog)&.include?(T.must(new_version))
|
76
109
|
return relevant_tag_changelog
|
77
110
|
end
|
78
111
|
|
@@ -81,8 +114,9 @@ module Dependabot
|
|
81
114
|
end
|
82
115
|
# rubocop:enable Metrics/PerceivedComplexity
|
83
116
|
|
117
|
+
sig { returns(T.nilable(Sawyer::Resource)) }
|
84
118
|
def changelog_from_suggested_url
|
85
|
-
return @changelog_from_suggested_url
|
119
|
+
return @changelog_from_suggested_url unless @changelog_from_suggested_url.nil?
|
86
120
|
return unless suggested_changelog_url
|
87
121
|
|
88
122
|
# TODO: Support other providers
|
@@ -90,29 +124,40 @@ module Dependabot
|
|
90
124
|
return unless suggested_source&.provider == "github"
|
91
125
|
|
92
126
|
opts = { path: suggested_source&.directory, ref: suggested_source&.branch }.compact
|
93
|
-
suggested_source_client = github_client_for_source(suggested_source)
|
94
|
-
tmp_files = suggested_source_client.contents(suggested_source&.repo, opts)
|
127
|
+
suggested_source_client = github_client_for_source(T.must(suggested_source))
|
128
|
+
tmp_files = T.unsafe(suggested_source_client).contents(suggested_source&.repo, opts)
|
95
129
|
|
96
|
-
filename = suggested_changelog_url.split("/").last.split("#").first
|
130
|
+
filename = T.must(T.must(suggested_changelog_url).split("/").last).split("#").first
|
97
131
|
@changelog_from_suggested_url =
|
98
132
|
tmp_files.find { |f| f.name == filename }
|
99
133
|
rescue Octokit::NotFound, Octokit::UnavailableForLegalReasons
|
100
134
|
@changelog_from_suggested_url = nil
|
101
135
|
end
|
102
136
|
|
137
|
+
sig { returns(T.nilable(T.any(OpenStruct, Sawyer::Resource))) }
|
103
138
|
def default_branch_changelog
|
104
139
|
return unless source
|
105
140
|
|
106
|
-
@default_branch_changelog ||=
|
141
|
+
@default_branch_changelog ||=
|
142
|
+
T.let(
|
143
|
+
changelog_from_ref(nil),
|
144
|
+
T.nilable(T.any(OpenStruct, Sawyer::Resource))
|
145
|
+
)
|
107
146
|
end
|
108
147
|
|
148
|
+
sig { returns(T.nilable(T.any(OpenStruct, Sawyer::Resource))) }
|
109
149
|
def relevant_tag_changelog
|
110
150
|
return unless source
|
111
151
|
return unless tag_for_new_version
|
112
152
|
|
113
|
-
@relevant_tag_changelog ||=
|
153
|
+
@relevant_tag_changelog ||=
|
154
|
+
T.let(
|
155
|
+
changelog_from_ref(tag_for_new_version),
|
156
|
+
T.nilable(T.any(OpenStruct, Sawyer::Resource))
|
157
|
+
)
|
114
158
|
end
|
115
159
|
|
160
|
+
sig { params(ref: T.nilable(String)).returns(T.nilable(T.any(OpenStruct, Sawyer::Resource))) }
|
116
161
|
def changelog_from_ref(ref)
|
117
162
|
files =
|
118
163
|
dependency_file_list(ref)
|
@@ -125,6 +170,7 @@ module Dependabot
|
|
125
170
|
end
|
126
171
|
|
127
172
|
# rubocop:disable Metrics/PerceivedComplexity
|
173
|
+
sig { params(files: T::Array[T.untyped]).returns(T.untyped) }
|
128
174
|
def select_best_changelog(files)
|
129
175
|
CHANGELOG_NAMES.each do |name|
|
130
176
|
candidates = files.select { |f| f.name =~ /#{name}/i }
|
@@ -150,15 +196,20 @@ module Dependabot
|
|
150
196
|
end
|
151
197
|
# rubocop:enable Metrics/PerceivedComplexity
|
152
198
|
|
199
|
+
sig { returns(T.nilable(String)) }
|
153
200
|
def tag_for_new_version
|
154
201
|
@tag_for_new_version ||=
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
202
|
+
T.let(
|
203
|
+
CommitsFinder.new(
|
204
|
+
dependency: dependency,
|
205
|
+
source: source,
|
206
|
+
credentials: credentials
|
207
|
+
).new_tag,
|
208
|
+
T.nilable(String)
|
209
|
+
)
|
160
210
|
end
|
161
211
|
|
212
|
+
sig { returns(T.nilable(String)) }
|
162
213
|
def full_changelog_text
|
163
214
|
return unless changelog
|
164
215
|
|
@@ -167,7 +218,7 @@ module Dependabot
|
|
167
218
|
|
168
219
|
sig { params(file: T.untyped).returns(T.nilable(String)) }
|
169
220
|
def fetch_file_text(file)
|
170
|
-
@file_text ||= {}
|
221
|
+
@file_text ||= T.let({}, T.nilable(T::Hash[String, T.untyped]))
|
171
222
|
|
172
223
|
unless @file_text.key?(file.download_url)
|
173
224
|
file_source = T.must(Source.from_url(file.html_url))
|
@@ -187,12 +238,14 @@ module Dependabot
|
|
187
238
|
@file_text[file.download_url].rstrip
|
188
239
|
end
|
189
240
|
|
241
|
+
sig { params(file_source: Dependabot::Source, file: T.untyped).returns(String) }
|
190
242
|
def fetch_github_file(file_source, file)
|
191
243
|
# Hitting the download URL directly causes encoding problems
|
192
|
-
raw_content = github_client_for_source(file_source).get(file.url).content
|
244
|
+
raw_content = T.unsafe(github_client_for_source(file_source)).get(file.url).content
|
193
245
|
Base64.decode64(raw_content).force_encoding("UTF-8").encode
|
194
246
|
end
|
195
247
|
|
248
|
+
sig { params(file: T.untyped).returns(String) }
|
196
249
|
def fetch_gitlab_file(file)
|
197
250
|
Excon.get(
|
198
251
|
file.download_url,
|
@@ -201,16 +254,19 @@ module Dependabot
|
|
201
254
|
).body.force_encoding("UTF-8").encode
|
202
255
|
end
|
203
256
|
|
257
|
+
sig { params(file: T.untyped).returns(String) }
|
204
258
|
def fetch_bitbucket_file(file)
|
205
|
-
bitbucket_client.get(file.download_url).body
|
206
|
-
|
259
|
+
T.unsafe(bitbucket_client).get(file.download_url).body
|
260
|
+
.force_encoding("UTF-8").encode
|
207
261
|
end
|
208
262
|
|
263
|
+
sig { params(file: T.untyped).returns(String) }
|
209
264
|
def fetch_azure_file(file)
|
210
265
|
azure_client.get(file.download_url).body
|
211
266
|
.force_encoding("UTF-8").encode
|
212
267
|
end
|
213
268
|
|
269
|
+
sig { returns(T.untyped) }
|
214
270
|
def upgrade_guide
|
215
271
|
return unless source
|
216
272
|
|
@@ -225,49 +281,55 @@ module Dependabot
|
|
225
281
|
.max_by(&:size)
|
226
282
|
end
|
227
283
|
|
284
|
+
sig { params(ref: T.nilable(String)).returns(T.untyped) }
|
228
285
|
def dependency_file_list(ref = nil)
|
229
|
-
@dependency_file_list ||= {}
|
286
|
+
@dependency_file_list ||= T.let({}, T.nilable(T::Hash[T.nilable(String), T.untyped]))
|
230
287
|
@dependency_file_list[ref] ||= fetch_dependency_file_list(ref)
|
231
288
|
end
|
232
289
|
|
290
|
+
sig { params(ref: T.nilable(String)).returns(T::Array[T.untyped,]) }
|
233
291
|
def fetch_dependency_file_list(ref)
|
234
|
-
case source.provider
|
292
|
+
case T.must(source).provider
|
235
293
|
when "github" then fetch_github_file_list(ref)
|
236
294
|
when "bitbucket" then fetch_bitbucket_file_list
|
237
295
|
when "gitlab" then fetch_gitlab_file_list
|
238
296
|
when "azure" then fetch_azure_file_list
|
239
297
|
when "codecommit" then [] # TODO: Fetch Files from Codecommit
|
240
|
-
else raise "Unexpected repo provider '#{source.provider}'"
|
298
|
+
else raise "Unexpected repo provider '#{T.must(source).provider}'"
|
241
299
|
end
|
242
300
|
end
|
243
301
|
|
302
|
+
# rubocop:disable Metrics/AbcSize
|
303
|
+
sig { params(ref: T.nilable(String)).returns(T::Array[T.untyped]) }
|
244
304
|
def fetch_github_file_list(ref)
|
245
305
|
files = []
|
246
306
|
|
247
|
-
if source.directory
|
248
|
-
opts = { path: source.directory, ref: ref }.compact
|
249
|
-
tmp_files = github_client.contents(source.repo, opts)
|
307
|
+
if T.must(source).directory
|
308
|
+
opts = { path: T.must(source).directory, ref: ref }.compact
|
309
|
+
tmp_files = T.unsafe(github_client).contents(T.must(source).repo, opts)
|
250
310
|
files += tmp_files if tmp_files.is_a?(Array)
|
251
311
|
end
|
252
312
|
|
253
313
|
opts = { ref: ref }.compact
|
254
|
-
files += github_client.contents(source.repo, opts)
|
314
|
+
files += T.unsafe(github_client).contents(T.must(source).repo, opts)
|
255
315
|
|
256
316
|
files.uniq.each do |f|
|
257
317
|
next unless f.type == "dir" && f.name.match?(/docs?/o)
|
258
318
|
|
259
319
|
opts = { path: f.path, ref: ref }.compact
|
260
|
-
files += github_client.contents(source.repo, opts)
|
320
|
+
files += T.unsafe(github_client).contents(T.must(source).repo, opts)
|
261
321
|
end
|
262
322
|
|
263
323
|
files
|
264
324
|
rescue Octokit::NotFound, Octokit::UnavailableForLegalReasons
|
265
325
|
[]
|
266
326
|
end
|
327
|
+
# rubocop:enable Metrics/AbcSize
|
267
328
|
|
329
|
+
sig { returns(T.untyped) }
|
268
330
|
def fetch_bitbucket_file_list
|
269
331
|
branch = default_bitbucket_branch
|
270
|
-
bitbucket_client.fetch_repo_contents(source.repo).map do |file|
|
332
|
+
T.unsafe(bitbucket_client).fetch_repo_contents(T.must(source).repo).map do |file|
|
271
333
|
type = case file.fetch("type")
|
272
334
|
when "commit_file" then "file"
|
273
335
|
when "commit_directory" then "dir"
|
@@ -277,8 +339,8 @@ module Dependabot
|
|
277
339
|
name: file.fetch("path").split("/").last,
|
278
340
|
type: type,
|
279
341
|
size: file.fetch("size", 100),
|
280
|
-
html_url: "#{source.url}/src/#{branch}/#{file['path']}",
|
281
|
-
download_url: "#{source.url}/raw/#{branch}/#{file['path']}"
|
342
|
+
html_url: "#{T.must(source).url}/src/#{branch}/#{file['path']}",
|
343
|
+
download_url: "#{T.must(source).url}/raw/#{branch}/#{file['path']}"
|
282
344
|
)
|
283
345
|
end
|
284
346
|
rescue Dependabot::Clients::Bitbucket::NotFound,
|
@@ -287,9 +349,10 @@ module Dependabot
|
|
287
349
|
[]
|
288
350
|
end
|
289
351
|
|
352
|
+
sig { returns(T.untyped) }
|
290
353
|
def fetch_gitlab_file_list
|
291
354
|
branch = default_gitlab_branch
|
292
|
-
gitlab_client.repo_tree(source.repo).map do |file|
|
355
|
+
T.unsafe(gitlab_client).repo_tree(T.must(source).repo).map do |file|
|
293
356
|
type = case file.type
|
294
357
|
when "blob" then "file"
|
295
358
|
when "tree" then "dir"
|
@@ -299,14 +362,15 @@ module Dependabot
|
|
299
362
|
name: file.name,
|
300
363
|
type: type,
|
301
364
|
size: 100, # GitLab doesn't return file size
|
302
|
-
html_url: "#{source.url}/blob/#{branch}/#{file.path}",
|
303
|
-
download_url: "#{source.url}/raw/#{branch}/#{file.path}"
|
365
|
+
html_url: "#{T.must(source).url}/blob/#{branch}/#{file.path}",
|
366
|
+
download_url: "#{T.must(source).url}/raw/#{branch}/#{file.path}"
|
304
367
|
)
|
305
368
|
end
|
306
369
|
rescue Gitlab::Error::NotFound
|
307
370
|
[]
|
308
371
|
end
|
309
372
|
|
373
|
+
sig { returns(T.untyped) }
|
310
374
|
def fetch_azure_file_list
|
311
375
|
azure_client.fetch_repo_contents.map do |entry|
|
312
376
|
type = case entry.fetch("gitObjectType")
|
@@ -320,7 +384,7 @@ module Dependabot
|
|
320
384
|
type: type,
|
321
385
|
size: entry.fetch("size"),
|
322
386
|
path: entry.fetch("relativePath"),
|
323
|
-
html_url: "#{source.url}?path=/#{entry.fetch('relativePath')}",
|
387
|
+
html_url: "#{T.must(source).url}?path=/#{entry.fetch('relativePath')}",
|
324
388
|
download_url: entry.fetch("url")
|
325
389
|
)
|
326
390
|
end
|
@@ -330,20 +394,23 @@ module Dependabot
|
|
330
394
|
[]
|
331
395
|
end
|
332
396
|
|
397
|
+
sig { returns(T.nilable(String)) }
|
333
398
|
def new_version
|
334
|
-
return @new_version
|
399
|
+
return @new_version unless @new_version.nil?
|
335
400
|
|
336
401
|
new_version = git_source? && new_ref ? new_ref : dependency.version
|
337
402
|
@new_version = new_version&.gsub(/^v/, "")
|
338
403
|
end
|
339
404
|
|
405
|
+
sig { returns(T.nilable(String)) }
|
340
406
|
def previous_ref
|
341
|
-
previous_refs = dependency.previous_requirements
|
407
|
+
previous_refs = dependency.previous_requirements&.filter_map do |r|
|
342
408
|
r.dig(:source, "ref") || r.dig(:source, :ref)
|
343
|
-
end
|
344
|
-
previous_refs
|
409
|
+
end&.uniq
|
410
|
+
previous_refs&.first if previous_refs&.count == 1
|
345
411
|
end
|
346
412
|
|
413
|
+
sig { returns(T.nilable(String)) }
|
347
414
|
def new_ref
|
348
415
|
new_refs = dependency.requirements.filter_map do |r|
|
349
416
|
r.dig(:source, "ref") || r.dig(:source, :ref)
|
@@ -351,12 +418,14 @@ module Dependabot
|
|
351
418
|
new_refs.first if new_refs.count == 1
|
352
419
|
end
|
353
420
|
|
421
|
+
sig { returns(T::Boolean) }
|
354
422
|
def ref_changed?
|
355
423
|
# We could go from multiple previous refs (nil) to a single new ref
|
356
424
|
previous_ref != new_ref
|
357
425
|
end
|
358
426
|
|
359
427
|
# TODO: Refactor me so that Composer doesn't need to be special cased
|
428
|
+
sig { returns(T::Boolean) }
|
360
429
|
def git_source?
|
361
430
|
# Special case Composer, which uses git as a source but handles tags
|
362
431
|
# internally
|
@@ -369,51 +438,77 @@ module Dependabot
|
|
369
438
|
sources.all? { |s| s[:type] == "git" || s["type"] == "git" }
|
370
439
|
end
|
371
440
|
|
441
|
+
sig { returns(T::Boolean) }
|
372
442
|
def major_version_upgrade?
|
373
443
|
return false unless dependency.version&.match?(/^\d/)
|
374
444
|
return false unless dependency.previous_version&.match?(/^\d/)
|
375
445
|
|
376
|
-
dependency.version.split(".").first.to_i -
|
377
|
-
dependency.previous_version.split(".").first.to_i >= 1
|
446
|
+
T.must(dependency.version).split(".").first.to_i -
|
447
|
+
T.must(dependency.previous_version).split(".").first.to_i >= 1
|
378
448
|
end
|
379
449
|
|
450
|
+
sig { returns(Dependabot::Clients::GitlabWithRetries) }
|
380
451
|
def gitlab_client
|
381
|
-
@gitlab_client ||=
|
382
|
-
|
452
|
+
@gitlab_client ||=
|
453
|
+
T.let(
|
454
|
+
Dependabot::Clients::GitlabWithRetries.for_gitlab_dot_com(credentials: credentials),
|
455
|
+
T.nilable(Dependabot::Clients::GitlabWithRetries)
|
456
|
+
)
|
383
457
|
end
|
384
458
|
|
459
|
+
sig { returns(Dependabot::Clients::GithubWithRetries) }
|
385
460
|
def github_client
|
386
|
-
@github_client ||=
|
387
|
-
|
461
|
+
@github_client ||=
|
462
|
+
T.let(
|
463
|
+
Dependabot::Clients::GithubWithRetries.for_source(source: source, credentials: credentials),
|
464
|
+
T.nilable(Dependabot::Clients::GithubWithRetries)
|
465
|
+
)
|
388
466
|
end
|
389
467
|
|
468
|
+
sig { returns(Dependabot::Clients::Azure) }
|
390
469
|
def azure_client
|
391
|
-
@azure_client ||=
|
392
|
-
|
470
|
+
@azure_client ||=
|
471
|
+
T.let(
|
472
|
+
Dependabot::Clients::Azure.for_source(source: T.must(source), credentials: credentials),
|
473
|
+
T.nilable(Dependabot::Clients::Azure)
|
474
|
+
)
|
393
475
|
end
|
394
476
|
|
477
|
+
sig { params(client_source: Dependabot::Source).returns(Dependabot::Clients::GithubWithRetries) }
|
395
478
|
def github_client_for_source(client_source)
|
396
479
|
return github_client if client_source == source
|
397
480
|
|
398
|
-
Dependabot::Clients::GithubWithRetries
|
399
|
-
.for_source(source: client_source, credentials: credentials)
|
481
|
+
Dependabot::Clients::GithubWithRetries.for_source(source: client_source, credentials: credentials)
|
400
482
|
end
|
401
483
|
|
484
|
+
sig { returns(Dependabot::Clients::BitbucketWithRetries) }
|
402
485
|
def bitbucket_client
|
403
|
-
@bitbucket_client ||=
|
404
|
-
|
486
|
+
@bitbucket_client ||=
|
487
|
+
T.let(
|
488
|
+
Dependabot::Clients::BitbucketWithRetries.for_bitbucket_dot_org(credentials: credentials),
|
489
|
+
T.nilable(Dependabot::Clients::BitbucketWithRetries)
|
490
|
+
)
|
405
491
|
end
|
406
492
|
|
493
|
+
sig { returns(String) }
|
407
494
|
def default_bitbucket_branch
|
408
495
|
@default_bitbucket_branch ||=
|
409
|
-
|
496
|
+
T.let(
|
497
|
+
T.unsafe(bitbucket_client).fetch_default_branch(T.must(source).repo),
|
498
|
+
T.nilable(String)
|
499
|
+
)
|
410
500
|
end
|
411
501
|
|
502
|
+
sig { returns(String) }
|
412
503
|
def default_gitlab_branch
|
413
504
|
@default_gitlab_branch ||=
|
414
|
-
|
505
|
+
T.let(
|
506
|
+
gitlab_client.fetch_default_branch(T.must(source).repo),
|
507
|
+
T.nilable(String)
|
508
|
+
)
|
415
509
|
end
|
416
510
|
end
|
511
|
+
# rubocop:enable Metrics/ClassLength
|
417
512
|
end
|
418
513
|
end
|
419
514
|
end
|
@@ -1,43 +1,60 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
4
5
|
require "dependabot/metadata_finders/base"
|
5
6
|
|
6
7
|
module Dependabot
|
7
8
|
module MetadataFinders
|
8
9
|
class Base
|
9
10
|
class ChangelogPruner
|
10
|
-
|
11
|
+
extend T::Sig
|
11
12
|
|
13
|
+
sig { returns(Dependabot::Dependency) }
|
14
|
+
attr_reader :dependency
|
15
|
+
|
16
|
+
sig { returns(T.nilable(String)) }
|
17
|
+
attr_reader :changelog_text
|
18
|
+
|
19
|
+
sig do
|
20
|
+
params(
|
21
|
+
dependency: Dependabot::Dependency,
|
22
|
+
changelog_text: T.nilable(String)
|
23
|
+
)
|
24
|
+
.void
|
25
|
+
end
|
12
26
|
def initialize(dependency:, changelog_text:)
|
13
27
|
@dependency = dependency
|
14
28
|
@changelog_text = changelog_text
|
15
29
|
end
|
16
30
|
|
31
|
+
sig { returns(T::Boolean) }
|
17
32
|
def includes_new_version?
|
18
33
|
!new_version_changelog_line.nil?
|
19
34
|
end
|
20
35
|
|
36
|
+
sig { returns(T::Boolean) }
|
21
37
|
def includes_previous_version?
|
22
38
|
!old_version_changelog_line.nil?
|
23
39
|
end
|
24
40
|
|
25
|
-
|
26
|
-
|
41
|
+
sig { returns(T.nilable(String)) }
|
42
|
+
def pruned_text # rubocop:disable Metrics/PerceivedComplexity
|
43
|
+
changelog_lines = changelog_text&.split("\n")
|
27
44
|
|
28
45
|
slice_range =
|
29
46
|
if old_version_changelog_line && new_version_changelog_line
|
30
|
-
if old_version_changelog_line < new_version_changelog_line
|
47
|
+
if T.must(old_version_changelog_line) < T.must(new_version_changelog_line)
|
31
48
|
Range.new(old_version_changelog_line, -1)
|
32
49
|
else
|
33
50
|
Range.new(new_version_changelog_line,
|
34
|
-
old_version_changelog_line - 1)
|
51
|
+
T.must(old_version_changelog_line) - 1)
|
35
52
|
end
|
36
53
|
elsif old_version_changelog_line
|
37
|
-
return if old_version_changelog_line.zero?
|
54
|
+
return if T.must(old_version_changelog_line).zero?
|
38
55
|
|
39
56
|
# Assumes changelog is in descending order
|
40
|
-
Range.new(0, old_version_changelog_line - 1)
|
57
|
+
Range.new(0, T.must(old_version_changelog_line) - 1)
|
41
58
|
elsif new_version_changelog_line
|
42
59
|
# Assumes changelog is in descending order
|
43
60
|
Range.new(new_version_changelog_line, -1)
|
@@ -49,11 +66,12 @@ module Dependabot
|
|
49
66
|
Range.new(0, -1)
|
50
67
|
end
|
51
68
|
|
52
|
-
changelog_lines
|
69
|
+
changelog_lines&.slice(slice_range)&.join("\n")&.rstrip
|
53
70
|
end
|
54
71
|
|
55
72
|
private
|
56
73
|
|
74
|
+
sig { returns(T.nilable(Integer)) }
|
57
75
|
def old_version_changelog_line
|
58
76
|
old_version = git_source? ? previous_ref : dependency.previous_version
|
59
77
|
return nil unless old_version
|
@@ -61,6 +79,7 @@ module Dependabot
|
|
61
79
|
changelog_line_for_version(old_version)
|
62
80
|
end
|
63
81
|
|
82
|
+
sig { returns(T.nilable(Integer)) }
|
64
83
|
def new_version_changelog_line
|
65
84
|
return nil unless new_version
|
66
85
|
|
@@ -68,6 +87,7 @@ module Dependabot
|
|
68
87
|
end
|
69
88
|
|
70
89
|
# rubocop:disable Metrics/PerceivedComplexity
|
90
|
+
sig { params(version: T.nilable(String)).returns(T.nilable(Integer)) }
|
71
91
|
def changelog_line_for_version(version)
|
72
92
|
raise "No changelog text" unless changelog_text
|
73
93
|
return nil unless version
|
@@ -75,7 +95,7 @@ module Dependabot
|
|
75
95
|
version = version.gsub(/^v/, "")
|
76
96
|
escaped_version = Regexp.escape(version)
|
77
97
|
|
78
|
-
changelog_lines = changelog_text.split("\n")
|
98
|
+
changelog_lines = T.must(changelog_text).split("\n")
|
79
99
|
|
80
100
|
changelog_lines.find_index.with_index do |line, index|
|
81
101
|
next false unless line.match?(/(?<!\.)#{escaped_version}(?![.\-])/)
|
@@ -92,13 +112,14 @@ module Dependabot
|
|
92
112
|
|
93
113
|
# rubocop:enable Metrics/PerceivedComplexity
|
94
114
|
|
115
|
+
sig { returns(T::Boolean) }
|
95
116
|
def changelog_contains_relevant_versions?
|
96
117
|
# Assume the changelog is relevant if we can't parse the new version
|
97
118
|
return true unless version_class.correct?(dependency.version)
|
98
119
|
|
99
120
|
# Assume the changelog is relevant if it mentions the new version
|
100
121
|
# anywhere
|
101
|
-
return true if changelog_text
|
122
|
+
return true if changelog_text&.include?(T.must(dependency.version))
|
102
123
|
|
103
124
|
# Otherwise check if any intermediate versions are included in headers
|
104
125
|
versions_in_changelog_headers.any? do |version|
|
@@ -110,8 +131,9 @@ module Dependabot
|
|
110
131
|
end
|
111
132
|
end
|
112
133
|
|
134
|
+
sig { returns(T::Array[String]) }
|
113
135
|
def versions_in_changelog_headers
|
114
|
-
changelog_lines = changelog_text.split("\n")
|
136
|
+
changelog_lines = T.must(changelog_text).split("\n")
|
115
137
|
header_lines =
|
116
138
|
changelog_lines.select.with_index do |line, index|
|
117
139
|
next true if line.start_with?("#", "!")
|
@@ -132,18 +154,25 @@ module Dependabot
|
|
132
154
|
versions
|
133
155
|
end
|
134
156
|
|
157
|
+
sig { returns(T.nilable(String)) }
|
135
158
|
def new_version
|
136
|
-
@new_version ||=
|
159
|
+
@new_version ||=
|
160
|
+
T.let(
|
161
|
+
git_source? ? new_ref : dependency.version,
|
162
|
+
T.nilable(String)
|
163
|
+
)
|
137
164
|
@new_version&.gsub(/^v/, "")
|
138
165
|
end
|
139
166
|
|
167
|
+
sig { returns(T.nilable(String)) }
|
140
168
|
def previous_ref
|
141
|
-
previous_refs = dependency.previous_requirements.filter_map do |r|
|
169
|
+
previous_refs = T.must(dependency.previous_requirements).filter_map do |r|
|
142
170
|
r.dig(:source, "ref") || r.dig(:source, :ref)
|
143
171
|
end.uniq
|
144
172
|
previous_refs.first if previous_refs.count == 1
|
145
173
|
end
|
146
174
|
|
175
|
+
sig { returns(T.nilable(String)) }
|
147
176
|
def new_ref
|
148
177
|
new_refs = dependency.requirements.filter_map do |r|
|
149
178
|
r.dig(:source, "ref") || r.dig(:source, :ref)
|
@@ -152,6 +181,7 @@ module Dependabot
|
|
152
181
|
end
|
153
182
|
|
154
183
|
# TODO: Refactor me so that Composer doesn't need to be special cased
|
184
|
+
sig { returns(T::Boolean) }
|
155
185
|
def git_source?
|
156
186
|
# Special case Composer, which uses git as a source but handles tags
|
157
187
|
# internally
|
@@ -164,6 +194,7 @@ module Dependabot
|
|
164
194
|
sources.all? { |s| s[:type] == "git" || s["type"] == "git" }
|
165
195
|
end
|
166
196
|
|
197
|
+
sig { returns(T.class_of(Dependabot::Version)) }
|
167
198
|
def version_class
|
168
199
|
dependency.version_class
|
169
200
|
end
|