dependabot-common 0.236.0 → 0.238.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 +3 -3
- data/lib/dependabot/clients/codecommit.rb +1 -0
- data/lib/dependabot/config/file.rb +17 -6
- data/lib/dependabot/config/update_config.rb +23 -5
- data/lib/dependabot/dependency.rb +137 -27
- data/lib/dependabot/dependency_file.rb +84 -14
- data/lib/dependabot/dependency_group.rb +29 -5
- data/lib/dependabot/errors.rb +335 -13
- data/lib/dependabot/file_fetchers/base.rb +227 -93
- data/lib/dependabot/file_updaters/base.rb +1 -1
- data/lib/dependabot/git_commit_checker.rb +6 -0
- data/lib/dependabot/git_metadata_fetcher.rb +58 -20
- data/lib/dependabot/git_ref.rb +71 -0
- data/lib/dependabot/metadata_finders/base/changelog_finder.rb +13 -6
- data/lib/dependabot/pull_request_creator/github.rb +11 -8
- data/lib/dependabot/pull_request_creator/message.rb +21 -2
- data/lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb +37 -16
- data/lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb +4 -2
- data/lib/dependabot/pull_request_creator/message_builder.rb +54 -4
- data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +10 -4
- data/lib/dependabot/shared_helpers.rb +117 -33
- data/lib/dependabot/simple_instrumentor.rb +22 -3
- data/lib/dependabot/source.rb +65 -17
- data/lib/dependabot/update_checkers/version_filters.rb +12 -1
- data/lib/dependabot/utils.rb +21 -2
- data/lib/dependabot/workspace/base.rb +42 -7
- data/lib/dependabot/workspace/change_attempt.rb +31 -3
- data/lib/dependabot/workspace/git.rb +34 -4
- data/lib/dependabot/workspace.rb +16 -2
- data/lib/dependabot.rb +1 -1
- metadata +38 -9
@@ -1,7 +1,8 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "stringio"
|
5
|
+
require "sorbet-runtime"
|
5
6
|
require "dependabot/config"
|
6
7
|
require "dependabot/dependency_file"
|
7
8
|
require "dependabot/source"
|
@@ -17,15 +18,33 @@ require "dependabot/shared_helpers"
|
|
17
18
|
module Dependabot
|
18
19
|
module FileFetchers
|
19
20
|
class Base
|
20
|
-
|
21
|
+
extend T::Sig
|
22
|
+
extend T::Helpers
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
abstract!
|
25
|
+
|
26
|
+
sig { returns(Dependabot::Source) }
|
27
|
+
attr_reader :source
|
28
|
+
|
29
|
+
sig { returns(T::Array[T::Hash[String, String]]) }
|
30
|
+
attr_reader :credentials
|
31
|
+
|
32
|
+
sig { returns(T.nilable(String)) }
|
33
|
+
attr_reader :repo_contents_path
|
34
|
+
|
35
|
+
sig { returns(T::Hash[String, String]) }
|
36
|
+
attr_reader :options
|
37
|
+
|
38
|
+
CLIENT_NOT_FOUND_ERRORS = T.let(
|
39
|
+
[
|
40
|
+
Octokit::NotFound,
|
41
|
+
Gitlab::Error::NotFound,
|
42
|
+
Dependabot::Clients::Azure::NotFound,
|
43
|
+
Dependabot::Clients::Bitbucket::NotFound,
|
44
|
+
Dependabot::Clients::CodeCommit::NotFound
|
45
|
+
].freeze,
|
46
|
+
T::Array[T.class_of(StandardError)]
|
47
|
+
)
|
29
48
|
|
30
49
|
GIT_SUBMODULE_INACCESSIBLE_ERROR =
|
31
50
|
/^fatal: unable to access '(?<url>.*)': The requested URL returned error: (?<code>\d+)$/
|
@@ -33,13 +52,11 @@ module Dependabot
|
|
33
52
|
/^fatal: clone of '(?<url>.*)' into submodule path '.*' failed$/
|
34
53
|
GIT_SUBMODULE_ERROR_REGEX = /(#{GIT_SUBMODULE_INACCESSIBLE_ERROR})|(#{GIT_SUBMODULE_CLONE_ERROR})/
|
35
54
|
|
36
|
-
|
37
|
-
|
38
|
-
end
|
55
|
+
sig { abstract.params(filenames: T::Array[String]).returns(T::Boolean) }
|
56
|
+
def self.required_files_in?(filenames); end
|
39
57
|
|
40
|
-
|
41
|
-
|
42
|
-
end
|
58
|
+
sig { abstract.returns(String) }
|
59
|
+
def self.required_files_message; end
|
43
60
|
|
44
61
|
# Creates a new FileFetcher for retrieving `DependencyFile`s.
|
45
62
|
#
|
@@ -52,38 +69,58 @@ module Dependabot
|
|
52
69
|
# by repo_contents_path and still use an API trip.
|
53
70
|
#
|
54
71
|
# options supports custom feature enablement
|
72
|
+
sig do
|
73
|
+
params(
|
74
|
+
source: Dependabot::Source,
|
75
|
+
credentials: T::Array[T::Hash[String, String]],
|
76
|
+
repo_contents_path: T.nilable(String),
|
77
|
+
options: T::Hash[String, String]
|
78
|
+
)
|
79
|
+
.void
|
80
|
+
end
|
55
81
|
def initialize(source:, credentials:, repo_contents_path: nil, options: {})
|
56
82
|
@source = source
|
57
83
|
@credentials = credentials
|
58
84
|
@repo_contents_path = repo_contents_path
|
59
|
-
@linked_paths = {}
|
60
|
-
@submodules = []
|
85
|
+
@linked_paths = T.let({}, T::Hash[T.untyped, T.untyped])
|
86
|
+
@submodules = T.let([], T::Array[T.untyped])
|
61
87
|
@options = options
|
62
88
|
end
|
63
89
|
|
90
|
+
sig { returns(String) }
|
64
91
|
def repo
|
65
92
|
source.repo
|
66
93
|
end
|
67
94
|
|
95
|
+
sig { returns(String) }
|
68
96
|
def directory
|
69
97
|
Pathname.new(source.directory || "/").cleanpath.to_path
|
70
98
|
end
|
71
99
|
|
100
|
+
sig { returns(T.nilable(String)) }
|
72
101
|
def target_branch
|
73
102
|
source.branch
|
74
103
|
end
|
75
104
|
|
105
|
+
sig { returns(T::Array[DependencyFile]) }
|
76
106
|
def files
|
77
|
-
@files ||=
|
107
|
+
@files ||= T.let(
|
108
|
+
fetch_files.each { |f| f.job_directory = directory },
|
109
|
+
T.nilable(T::Array[DependencyFile])
|
110
|
+
)
|
78
111
|
end
|
79
112
|
|
113
|
+
sig { abstract.returns(T::Array[DependencyFile]) }
|
114
|
+
def fetch_files; end
|
115
|
+
|
116
|
+
sig { returns(T.nilable(String)) }
|
80
117
|
def commit
|
81
|
-
return cloned_commit if cloned_commit
|
82
|
-
return source.commit if source.commit
|
118
|
+
return T.must(cloned_commit) if cloned_commit
|
119
|
+
return T.must(source.commit) if source.commit
|
83
120
|
|
84
121
|
branch = target_branch || default_branch_for_repo
|
85
122
|
|
86
|
-
@commit ||= client_for_provider.fetch_commit(repo, branch)
|
123
|
+
@commit ||= T.let(T.unsafe(client_for_provider).fetch_commit(repo, branch), T.nilable(String))
|
87
124
|
rescue *CLIENT_NOT_FOUND_ERRORS
|
88
125
|
raise Dependabot::BranchNotFound, branch
|
89
126
|
rescue Octokit::Conflict => e
|
@@ -91,9 +128,12 @@ module Dependabot
|
|
91
128
|
end
|
92
129
|
|
93
130
|
# Returns the path to the cloned repo
|
131
|
+
sig { returns(String) }
|
94
132
|
def clone_repo_contents
|
95
|
-
@clone_repo_contents ||=
|
96
|
-
_clone_repo_contents(target_directory: repo_contents_path)
|
133
|
+
@clone_repo_contents ||= T.let(
|
134
|
+
_clone_repo_contents(target_directory: repo_contents_path),
|
135
|
+
T.nilable(String)
|
136
|
+
)
|
97
137
|
rescue Dependabot::SharedHelpers::HelperSubprocessFailed => e
|
98
138
|
if e.message.include?("fatal: Remote branch #{target_branch} not found in upstream origin")
|
99
139
|
raise Dependabot::BranchNotFound, target_branch
|
@@ -104,16 +144,17 @@ module Dependabot
|
|
104
144
|
raise Dependabot::RepoNotFound.new(source, e.message)
|
105
145
|
end
|
106
146
|
|
107
|
-
|
108
|
-
|
109
|
-
end
|
147
|
+
sig { overridable.returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
148
|
+
def ecosystem_versions; end
|
110
149
|
|
111
150
|
private
|
112
151
|
|
152
|
+
sig { params(name: String).returns(T.nilable(Dependabot::DependencyFile)) }
|
113
153
|
def fetch_support_file(name)
|
114
154
|
fetch_file_if_present(name)&.tap { |f| f.support_file = true }
|
115
155
|
end
|
116
156
|
|
157
|
+
sig { params(filename: String, fetch_submodules: T::Boolean).returns(T.nilable(DependencyFile)) }
|
117
158
|
def fetch_file_if_present(filename, fetch_submodules: false)
|
118
159
|
unless repo_contents_path.nil?
|
119
160
|
begin
|
@@ -137,6 +178,7 @@ module Dependabot
|
|
137
178
|
nil
|
138
179
|
end
|
139
180
|
|
181
|
+
sig { params(filename: T.any(Pathname, String)).returns(Dependabot::DependencyFile) }
|
140
182
|
def load_cloned_file_if_present(filename)
|
141
183
|
path = Pathname.new(File.join(directory, filename)).cleanpath.to_path
|
142
184
|
repo_path = File.join(clone_repo_contents, path)
|
@@ -160,6 +202,14 @@ module Dependabot
|
|
160
202
|
)
|
161
203
|
end
|
162
204
|
|
205
|
+
sig do
|
206
|
+
params(
|
207
|
+
filename: T.any(Pathname, String),
|
208
|
+
type: String,
|
209
|
+
fetch_submodules: T::Boolean
|
210
|
+
)
|
211
|
+
.returns(Dependabot::DependencyFile)
|
212
|
+
end
|
163
213
|
def fetch_file_from_host(filename, type: "file", fetch_submodules: false)
|
164
214
|
return load_cloned_file_if_present(filename) unless repo_contents_path.nil?
|
165
215
|
|
@@ -169,7 +219,7 @@ module Dependabot
|
|
169
219
|
|
170
220
|
linked_path = symlinked_subpath(clean_path)
|
171
221
|
type = "symlink" if linked_path
|
172
|
-
symlink_target = clean_path.sub(linked_path, @linked_paths.dig(linked_path, :path)) if type == "symlink"
|
222
|
+
symlink_target = clean_path.sub(T.must(linked_path), @linked_paths.dig(linked_path, :path)) if type == "symlink"
|
173
223
|
|
174
224
|
DependencyFile.new(
|
175
225
|
name: Pathname.new(filename).cleanpath.to_path,
|
@@ -183,65 +233,87 @@ module Dependabot
|
|
183
233
|
end
|
184
234
|
|
185
235
|
# Finds the first subpath in path that is a symlink
|
236
|
+
sig { params(path: String).returns(T.nilable(String)) }
|
186
237
|
def symlinked_subpath(path)
|
187
238
|
subpaths(path).find { |subpath| @linked_paths.key?(subpath) }
|
188
239
|
end
|
189
240
|
|
241
|
+
sig { params(path: String).returns(T::Boolean) }
|
190
242
|
def in_submodule?(path)
|
191
243
|
subpaths(path.delete_prefix("/")).any? { |subpath| @submodules.include?(subpath) }
|
192
244
|
end
|
193
245
|
|
194
246
|
# Given a "foo/bar/baz" path, returns ["foo", "foo/bar", "foo/bar/baz"]
|
247
|
+
sig { params(path: String).returns(T::Array[String]) }
|
195
248
|
def subpaths(path)
|
196
249
|
components = path.split("/")
|
197
|
-
components.map { |component| components[0..components.index(component)].join("/") }
|
250
|
+
components.map { |component| T.must(components[0..components.index(component)]).join("/") }
|
198
251
|
end
|
199
252
|
|
253
|
+
sig do
|
254
|
+
params(
|
255
|
+
dir: T.any(Pathname, String),
|
256
|
+
ignore_base_directory: T::Boolean,
|
257
|
+
raise_errors: T::Boolean,
|
258
|
+
fetch_submodules: T::Boolean
|
259
|
+
)
|
260
|
+
.returns(T::Array[T.untyped])
|
261
|
+
end
|
200
262
|
def repo_contents(dir: ".", ignore_base_directory: false,
|
201
263
|
raise_errors: true, fetch_submodules: false)
|
202
264
|
dir = File.join(directory, dir) unless ignore_base_directory
|
203
265
|
path = Pathname.new(dir).cleanpath.to_path.gsub(%r{^/*}, "")
|
204
266
|
|
205
|
-
@repo_contents ||= {}
|
206
|
-
@repo_contents[dir] ||= if repo_contents_path
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
267
|
+
@repo_contents ||= T.let({}, T.nilable(T::Hash[String, T::Array[T.untyped]]))
|
268
|
+
@repo_contents[dir.to_s] ||= if repo_contents_path
|
269
|
+
_cloned_repo_contents(path)
|
270
|
+
else
|
271
|
+
_fetch_repo_contents(path, raise_errors: raise_errors,
|
272
|
+
fetch_submodules: fetch_submodules)
|
273
|
+
end
|
212
274
|
end
|
213
275
|
|
276
|
+
sig { returns(T.nilable(String)) }
|
214
277
|
def cloned_commit
|
215
278
|
return if repo_contents_path.nil? || !File.directory?(File.join(repo_contents_path, ".git"))
|
216
279
|
|
217
280
|
SharedHelpers.with_git_configured(credentials: credentials) do
|
218
|
-
Dir.chdir(repo_contents_path) do
|
219
|
-
return SharedHelpers.run_shell_command("git rev-parse HEAD")
|
281
|
+
Dir.chdir(T.must(repo_contents_path)) do
|
282
|
+
return SharedHelpers.run_shell_command("git rev-parse HEAD").strip
|
220
283
|
end
|
221
284
|
end
|
222
285
|
end
|
223
286
|
|
287
|
+
sig { returns(String) }
|
224
288
|
def default_branch_for_repo
|
225
|
-
@default_branch_for_repo ||= client_for_provider
|
226
|
-
.fetch_default_branch(repo)
|
289
|
+
@default_branch_for_repo ||= T.let(T.unsafe(client_for_provider).fetch_default_branch(repo), T.nilable(String))
|
227
290
|
rescue *CLIENT_NOT_FOUND_ERRORS
|
228
291
|
raise Dependabot::RepoNotFound, source
|
229
292
|
end
|
230
293
|
|
294
|
+
sig do
|
295
|
+
params(
|
296
|
+
repo: String,
|
297
|
+
path: String,
|
298
|
+
commit: String,
|
299
|
+
github_response: Sawyer::Resource
|
300
|
+
)
|
301
|
+
.returns(T.nilable(T::Hash[String, T.untyped]))
|
302
|
+
end
|
231
303
|
def update_linked_paths(repo, path, commit, github_response)
|
232
|
-
case github_response.type
|
304
|
+
case T.unsafe(github_response).type
|
233
305
|
when "submodule"
|
234
|
-
sub_source = Source.from_url(github_response.submodule_git_url)
|
306
|
+
sub_source = Source.from_url(T.unsafe(github_response).submodule_git_url)
|
235
307
|
return unless sub_source
|
236
308
|
|
237
309
|
@linked_paths[path] = {
|
238
310
|
repo: sub_source.repo,
|
239
311
|
provider: sub_source.provider,
|
240
|
-
commit: github_response.sha,
|
312
|
+
commit: T.unsafe(github_response).sha,
|
241
313
|
path: "/"
|
242
314
|
}
|
243
315
|
when "symlink"
|
244
|
-
updated_path = File.join(File.dirname(path), github_response.target)
|
316
|
+
updated_path = File.join(File.dirname(path), T.unsafe(github_response).target)
|
245
317
|
@linked_paths[path] = {
|
246
318
|
repo: repo,
|
247
319
|
provider: "github",
|
@@ -251,10 +323,22 @@ module Dependabot
|
|
251
323
|
end
|
252
324
|
end
|
253
325
|
|
326
|
+
sig { returns(T::Boolean) }
|
254
327
|
def recurse_submodules_when_cloning?
|
255
328
|
false
|
256
329
|
end
|
257
330
|
|
331
|
+
sig do
|
332
|
+
returns(
|
333
|
+
T.any(
|
334
|
+
Dependabot::Clients::GithubWithRetries,
|
335
|
+
Dependabot::Clients::GitlabWithRetries,
|
336
|
+
Dependabot::Clients::Azure,
|
337
|
+
Dependabot::Clients::BitbucketWithRetries,
|
338
|
+
Dependabot::Clients::CodeCommit
|
339
|
+
)
|
340
|
+
)
|
341
|
+
end
|
258
342
|
def client_for_provider
|
259
343
|
case source.provider
|
260
344
|
when "github" then github_client
|
@@ -266,46 +350,75 @@ module Dependabot
|
|
266
350
|
end
|
267
351
|
end
|
268
352
|
|
353
|
+
sig { returns(Dependabot::Clients::GithubWithRetries) }
|
269
354
|
def github_client
|
270
355
|
@github_client ||=
|
271
|
-
|
272
|
-
|
273
|
-
|
356
|
+
T.let(
|
357
|
+
Dependabot::Clients::GithubWithRetries.for_source(
|
358
|
+
source: source,
|
359
|
+
credentials: credentials
|
360
|
+
),
|
361
|
+
T.nilable(Dependabot::Clients::GithubWithRetries)
|
274
362
|
)
|
275
363
|
end
|
276
364
|
|
365
|
+
sig { returns(Dependabot::Clients::GitlabWithRetries) }
|
277
366
|
def gitlab_client
|
278
367
|
@gitlab_client ||=
|
279
|
-
|
280
|
-
|
281
|
-
|
368
|
+
T.let(
|
369
|
+
Dependabot::Clients::GitlabWithRetries.for_source(
|
370
|
+
source: source,
|
371
|
+
credentials: credentials
|
372
|
+
),
|
373
|
+
T.nilable(Dependabot::Clients::GitlabWithRetries)
|
282
374
|
)
|
283
375
|
end
|
284
376
|
|
377
|
+
sig { returns(Dependabot::Clients::Azure) }
|
285
378
|
def azure_client
|
286
379
|
@azure_client ||=
|
287
|
-
|
288
|
-
|
380
|
+
T.let(
|
381
|
+
Dependabot::Clients::Azure.for_source(
|
382
|
+
source: source,
|
383
|
+
credentials: credentials
|
384
|
+
),
|
385
|
+
T.nilable(Dependabot::Clients::Azure)
|
386
|
+
)
|
289
387
|
end
|
290
388
|
|
389
|
+
sig { returns(Dependabot::Clients::BitbucketWithRetries) }
|
291
390
|
def bitbucket_client
|
292
391
|
# TODO: When self-hosted Bitbucket is supported this should use
|
293
392
|
# `Bitbucket.for_source`
|
294
393
|
@bitbucket_client ||=
|
295
|
-
|
296
|
-
|
394
|
+
T.let(
|
395
|
+
Dependabot::Clients::BitbucketWithRetries.for_bitbucket_dot_org(
|
396
|
+
credentials: credentials
|
397
|
+
),
|
398
|
+
T.nilable(Dependabot::Clients::BitbucketWithRetries)
|
399
|
+
)
|
297
400
|
end
|
298
401
|
|
402
|
+
sig { returns(Dependabot::Clients::CodeCommit) }
|
299
403
|
def codecommit_client
|
300
404
|
@codecommit_client ||=
|
301
|
-
|
302
|
-
|
405
|
+
T.let(
|
406
|
+
Dependabot::Clients::CodeCommit.for_source(
|
407
|
+
source: source,
|
408
|
+
credentials: credentials
|
409
|
+
),
|
410
|
+
T.nilable(Dependabot::Clients::CodeCommit)
|
411
|
+
)
|
303
412
|
end
|
304
413
|
|
305
414
|
#################################################
|
306
415
|
# INTERNAL METHODS (not for use by sub-classes) #
|
307
416
|
#################################################
|
308
417
|
|
418
|
+
sig do
|
419
|
+
params(path: String, fetch_submodules: T::Boolean, raise_errors: T::Boolean)
|
420
|
+
.returns(T::Array[OpenStruct])
|
421
|
+
end
|
309
422
|
def _fetch_repo_contents(path, fetch_submodules: false,
|
310
423
|
raise_errors: true)
|
311
424
|
path = path.gsub(" ", "%20")
|
@@ -337,6 +450,10 @@ module Dependabot
|
|
337
450
|
retry
|
338
451
|
end
|
339
452
|
|
453
|
+
sig do
|
454
|
+
params(provider: String, repo: String, path: String, commit: String)
|
455
|
+
.returns(T::Array[OpenStruct])
|
456
|
+
end
|
340
457
|
def _fetch_repo_contents_fully_specified(provider, repo, path, commit)
|
341
458
|
case provider
|
342
459
|
when "github"
|
@@ -353,9 +470,10 @@ module Dependabot
|
|
353
470
|
end
|
354
471
|
end
|
355
472
|
|
473
|
+
sig { params(repo: String, path: String, commit: String).returns(T::Array[OpenStruct]) }
|
356
474
|
def _github_repo_contents(repo, path, commit)
|
357
475
|
path = path.gsub(" ", "%20")
|
358
|
-
github_response = github_client.contents(repo, path: path, ref: commit)
|
476
|
+
github_response = T.unsafe(github_client).contents(repo, path: path, ref: commit)
|
359
477
|
|
360
478
|
if github_response.respond_to?(:type)
|
361
479
|
update_linked_paths(repo, path, commit, github_response)
|
@@ -365,6 +483,7 @@ module Dependabot
|
|
365
483
|
github_response.map { |f| _build_github_file_struct(f) }
|
366
484
|
end
|
367
485
|
|
486
|
+
sig { params(relative_path: String).returns(T::Array[OpenStruct]) }
|
368
487
|
def _cloned_repo_contents(relative_path)
|
369
488
|
repo_path = File.join(clone_repo_contents, relative_path)
|
370
489
|
return [] unless Dir.exist?(repo_path)
|
@@ -390,37 +509,40 @@ module Dependabot
|
|
390
509
|
end
|
391
510
|
end
|
392
511
|
|
512
|
+
sig { params(file: Sawyer::Resource).returns(OpenStruct) }
|
393
513
|
def _build_github_file_struct(file)
|
394
514
|
OpenStruct.new(
|
395
|
-
name: file.name,
|
396
|
-
path: file.path,
|
397
|
-
type: file.type,
|
398
|
-
sha: file.sha,
|
399
|
-
size: file.size
|
515
|
+
name: T.unsafe(file).name,
|
516
|
+
path: T.unsafe(file).path,
|
517
|
+
type: T.unsafe(file).type,
|
518
|
+
sha: T.unsafe(file).sha,
|
519
|
+
size: T.unsafe(file).size
|
400
520
|
)
|
401
521
|
end
|
402
522
|
|
523
|
+
sig { params(repo: String, path: String, commit: String).returns(T::Array[OpenStruct]) }
|
403
524
|
def _gitlab_repo_contents(repo, path, commit)
|
404
|
-
gitlab_client
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
525
|
+
T.unsafe(gitlab_client)
|
526
|
+
.repo_tree(repo, path: path, ref: commit, per_page: 100)
|
527
|
+
.map do |file|
|
528
|
+
# GitLab API essentially returns the output from `git ls-tree`
|
529
|
+
type = case file.type
|
530
|
+
when "blob" then "file"
|
531
|
+
when "tree" then "dir"
|
532
|
+
when "commit" then "submodule"
|
533
|
+
else file.fetch("type")
|
534
|
+
end
|
535
|
+
|
536
|
+
OpenStruct.new(
|
537
|
+
name: file.name,
|
538
|
+
path: file.path,
|
539
|
+
type: type,
|
540
|
+
size: 0 # GitLab doesn't return file size
|
541
|
+
)
|
542
|
+
end
|
422
543
|
end
|
423
544
|
|
545
|
+
sig { params(path: String, commit: String).returns(T::Array[OpenStruct]) }
|
424
546
|
def _azure_repo_contents(path, commit)
|
425
547
|
response = azure_client.fetch_repo_contents(commit, path)
|
426
548
|
|
@@ -440,12 +562,14 @@ module Dependabot
|
|
440
562
|
end
|
441
563
|
end
|
442
564
|
|
565
|
+
sig { params(repo: String, path: String, commit: String).returns(T::Array[OpenStruct]) }
|
443
566
|
def _bitbucket_repo_contents(repo, path, commit)
|
444
|
-
response =
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
567
|
+
response = T.unsafe(bitbucket_client)
|
568
|
+
.fetch_repo_contents(
|
569
|
+
repo,
|
570
|
+
commit,
|
571
|
+
path
|
572
|
+
)
|
449
573
|
|
450
574
|
response.map do |file|
|
451
575
|
type = case file.fetch("type")
|
@@ -463,6 +587,7 @@ module Dependabot
|
|
463
587
|
end
|
464
588
|
end
|
465
589
|
|
590
|
+
sig { params(repo: String, path: String, commit: String).returns(T::Array[OpenStruct]) }
|
466
591
|
def _codecommit_repo_contents(repo, path, commit)
|
467
592
|
response = codecommit_client.fetch_repo_contents(
|
468
593
|
repo,
|
@@ -480,11 +605,12 @@ module Dependabot
|
|
480
605
|
end
|
481
606
|
end
|
482
607
|
|
608
|
+
sig { params(path: String, fetch_submodules: T::Boolean).returns(T::Hash[Symbol, T.untyped]) }
|
483
609
|
def _full_specification_for(path, fetch_submodules:)
|
484
610
|
if fetch_submodules && _linked_dir_for(path)
|
485
611
|
linked_dir_details = @linked_paths[_linked_dir_for(path)]
|
486
612
|
sub_path =
|
487
|
-
path.gsub(%r{^#{Regexp.quote(_linked_dir_for(path))}(/|$)}, "")
|
613
|
+
path.gsub(%r{^#{Regexp.quote(T.must(_linked_dir_for(path)))}(/|$)}, "")
|
488
614
|
new_path =
|
489
615
|
Pathname.new(File.join(linked_dir_details.fetch(:path), sub_path))
|
490
616
|
.cleanpath.to_path
|
@@ -505,6 +631,7 @@ module Dependabot
|
|
505
631
|
end
|
506
632
|
end
|
507
633
|
|
634
|
+
sig { params(path: String, fetch_submodules: T::Boolean).returns(String) }
|
508
635
|
def _fetch_file_content(path, fetch_submodules: false)
|
509
636
|
path = path.gsub(%r{^/*}, "")
|
510
637
|
|
@@ -525,17 +652,18 @@ module Dependabot
|
|
525
652
|
retry
|
526
653
|
end
|
527
654
|
|
655
|
+
sig { params(provider: String, repo: String, path: String, commit: String).returns(String) }
|
528
656
|
def _fetch_file_content_fully_specified(provider, repo, path, commit)
|
529
657
|
case provider
|
530
658
|
when "github"
|
531
659
|
_fetch_file_content_from_github(path, repo, commit)
|
532
660
|
when "gitlab"
|
533
|
-
tmp = gitlab_client.get_file(repo, path, commit).content
|
661
|
+
tmp = T.unsafe(gitlab_client).get_file(repo, path, commit).content
|
534
662
|
decode_binary_string(tmp)
|
535
663
|
when "azure"
|
536
664
|
azure_client.fetch_file_contents(commit, path)
|
537
665
|
when "bitbucket"
|
538
|
-
bitbucket_client.fetch_file_contents(repo, commit, path)
|
666
|
+
T.unsafe(bitbucket_client).fetch_file_contents(repo, commit, path)
|
539
667
|
when "codecommit"
|
540
668
|
codecommit_client.fetch_file_contents(repo, commit, path)
|
541
669
|
else raise "Unsupported provider '#{source.provider}'."
|
@@ -543,8 +671,9 @@ module Dependabot
|
|
543
671
|
end
|
544
672
|
|
545
673
|
# rubocop:disable Metrics/AbcSize
|
674
|
+
sig { params(path: String, repo: String, commit: String).returns(String) }
|
546
675
|
def _fetch_file_content_from_github(path, repo, commit)
|
547
|
-
tmp = github_client.contents(repo, path: path, ref: commit)
|
676
|
+
tmp = T.unsafe(github_client).contents(repo, path: path, ref: commit)
|
548
677
|
|
549
678
|
raise Octokit::NotFound if tmp.is_a?(Array)
|
550
679
|
|
@@ -555,7 +684,7 @@ module Dependabot
|
|
555
684
|
commit: commit,
|
556
685
|
path: Pathname.new(tmp.target).cleanpath.to_path
|
557
686
|
}
|
558
|
-
tmp = github_client.contents(
|
687
|
+
tmp = T.unsafe(github_client).contents(
|
559
688
|
repo,
|
560
689
|
path: Pathname.new(tmp.target).cleanpath.to_path,
|
561
690
|
ref: commit
|
@@ -565,7 +694,7 @@ module Dependabot
|
|
565
694
|
if tmp.content == ""
|
566
695
|
# The file may have exceeded the 1MB limit
|
567
696
|
# see https://github.blog/changelog/2022-05-03-increased-file-size-limit-when-retrieving-file-contents-via-rest-api/
|
568
|
-
github_client.contents(repo, path: path, ref: commit, accept: "application/vnd.github.v3.raw")
|
697
|
+
T.unsafe(github_client).contents(repo, path: path, ref: commit, accept: "application/vnd.github.v3.raw")
|
569
698
|
else
|
570
699
|
decode_binary_string(tmp.content)
|
571
700
|
end
|
@@ -579,7 +708,7 @@ module Dependabot
|
|
579
708
|
file_details = repo_contents(dir: dir).find { |f| f.name == basename }
|
580
709
|
raise unless file_details
|
581
710
|
|
582
|
-
tmp = github_client.blob(repo, file_details.sha)
|
711
|
+
tmp = T.unsafe(github_client).blob(repo, file_details.sha)
|
583
712
|
return tmp.content if tmp.encoding == "utf-8"
|
584
713
|
|
585
714
|
decode_binary_string(tmp.content)
|
@@ -589,6 +718,7 @@ module Dependabot
|
|
589
718
|
# Update the @linked_paths hash by exploiting a side-effect of
|
590
719
|
# recursively calling `repo_contents` for each directory up the tree
|
591
720
|
# until a submodule or symlink is found
|
721
|
+
sig { params(path: String).returns(T.nilable(T::Array[T.untyped])) }
|
592
722
|
def _find_linked_dirs(path)
|
593
723
|
path = Pathname.new(path).cleanpath.to_path.gsub(%r{^/*}, "")
|
594
724
|
dir = File.dirname(path)
|
@@ -603,6 +733,7 @@ module Dependabot
|
|
603
733
|
)
|
604
734
|
end
|
605
735
|
|
736
|
+
sig { params(path: String).returns(T.nilable(String)) }
|
606
737
|
def _linked_dir_for(path)
|
607
738
|
linked_dirs = @linked_paths.keys
|
608
739
|
linked_dirs
|
@@ -614,6 +745,7 @@ module Dependabot
|
|
614
745
|
# rubocop:disable Metrics/MethodLength
|
615
746
|
# rubocop:disable Metrics/PerceivedComplexity
|
616
747
|
# rubocop:disable Metrics/BlockLength
|
748
|
+
sig { params(target_directory: T.nilable(String)).returns(String) }
|
617
749
|
def _clone_repo_contents(target_directory:)
|
618
750
|
SharedHelpers.with_git_configured(credentials: credentials) do
|
619
751
|
path = target_directory || File.join("tmp", source.repo)
|
@@ -645,7 +777,7 @@ module Dependabot
|
|
645
777
|
raise unless e.message.match(GIT_SUBMODULE_ERROR_REGEX) && e.message.downcase.include?("submodule")
|
646
778
|
|
647
779
|
submodule_cloning_failed = true
|
648
|
-
match = e.message.match(GIT_SUBMODULE_ERROR_REGEX)
|
780
|
+
match = T.must(e.message.match(GIT_SUBMODULE_ERROR_REGEX))
|
649
781
|
url = match.named_captures["url"]
|
650
782
|
code = match.named_captures["code"]
|
651
783
|
|
@@ -688,11 +820,13 @@ module Dependabot
|
|
688
820
|
# rubocop:enable Metrics/PerceivedComplexity
|
689
821
|
# rubocop:enable Metrics/BlockLength
|
690
822
|
|
823
|
+
sig { params(str: String).returns(String) }
|
691
824
|
def decode_binary_string(str)
|
692
825
|
bom = (+"\xEF\xBB\xBF").force_encoding(Encoding::BINARY)
|
693
826
|
Base64.decode64(str).delete_prefix(bom).force_encoding("UTF-8").encode
|
694
827
|
end
|
695
828
|
|
829
|
+
sig { params(path: String).returns(T::Array[String]) }
|
696
830
|
def find_submodules(path)
|
697
831
|
SharedHelpers.run_shell_command(
|
698
832
|
<<~CMD
|
@@ -702,7 +836,7 @@ module Dependabot
|
|
702
836
|
info = line.split
|
703
837
|
|
704
838
|
type = info.first
|
705
|
-
path = info.last
|
839
|
+
path = T.must(info.last)
|
706
840
|
|
707
841
|
next path if type == DependencyFile::Mode::SUBMODULE
|
708
842
|
end
|
@@ -73,7 +73,7 @@ module Dependabot
|
|
73
73
|
|
74
74
|
sig { params(file: Dependabot::DependencyFile, dependency: Dependabot::Dependency).returns(T::Boolean) }
|
75
75
|
def requirement_changed?(file, dependency)
|
76
|
-
changed_requirements = dependency.requirements - dependency.previous_requirements
|
76
|
+
changed_requirements = dependency.requirements - T.must(dependency.previous_requirements)
|
77
77
|
|
78
78
|
changed_requirements.any? { |f| f[:file] == file.name }
|
79
79
|
end
|
@@ -153,6 +153,12 @@ module Dependabot
|
|
153
153
|
@local_tag_for_pinned_sha = most_specific_version_tag_for_sha(ref) if pinned_ref_looks_like_commit_sha?
|
154
154
|
end
|
155
155
|
|
156
|
+
def version_for_pinned_sha
|
157
|
+
return unless local_tag_for_pinned_sha && version_class.correct?(local_tag_for_pinned_sha)
|
158
|
+
|
159
|
+
version_class.new(local_tag_for_pinned_sha)
|
160
|
+
end
|
161
|
+
|
156
162
|
def git_repo_reachable?
|
157
163
|
local_upload_pack
|
158
164
|
true
|