dependabot-common 0.235.0 → 0.237.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/config/file.rb +32 -9
- data/lib/dependabot/config/file_fetcher.rb +3 -3
- data/lib/dependabot/config/ignore_condition.rb +34 -8
- data/lib/dependabot/config/update_config.rb +42 -6
- data/lib/dependabot/config.rb +1 -1
- data/lib/dependabot/dependency_file.rb +89 -14
- data/lib/dependabot/dependency_group.rb +29 -5
- data/lib/dependabot/errors.rb +101 -13
- data/lib/dependabot/file_fetchers/base.rb +250 -93
- data/lib/dependabot/file_updaters/artifact_updater.rb +37 -10
- data/lib/dependabot/file_updaters/vendor_updater.rb +13 -3
- data/lib/dependabot/logger.rb +7 -2
- data/lib/dependabot/metadata_finders/base/changelog_finder.rb +13 -6
- data/lib/dependabot/pull_request_creator/commit_signer.rb +33 -7
- data/lib/dependabot/pull_request_creator/github.rb +13 -10
- 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 +5 -3
- data/lib/dependabot/pull_request_creator/message_builder.rb +5 -18
- data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +10 -4
- data/lib/dependabot/pull_request_updater/github.rb +2 -2
- 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 +37 -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,37 +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 = {}
|
85
|
+
@linked_paths = T.let({}, T::Hash[T.untyped, T.untyped])
|
86
|
+
@submodules = T.let([], T::Array[T.untyped])
|
60
87
|
@options = options
|
61
88
|
end
|
62
89
|
|
90
|
+
sig { returns(String) }
|
63
91
|
def repo
|
64
92
|
source.repo
|
65
93
|
end
|
66
94
|
|
95
|
+
sig { returns(String) }
|
67
96
|
def directory
|
68
97
|
Pathname.new(source.directory || "/").cleanpath.to_path
|
69
98
|
end
|
70
99
|
|
100
|
+
sig { returns(T.nilable(String)) }
|
71
101
|
def target_branch
|
72
102
|
source.branch
|
73
103
|
end
|
74
104
|
|
105
|
+
sig { returns(T::Array[DependencyFile]) }
|
75
106
|
def files
|
76
|
-
@files ||=
|
107
|
+
@files ||= T.let(
|
108
|
+
fetch_files.each { |f| f.job_directory = directory },
|
109
|
+
T.nilable(T::Array[DependencyFile])
|
110
|
+
)
|
77
111
|
end
|
78
112
|
|
113
|
+
sig { abstract.returns(T::Array[DependencyFile]) }
|
114
|
+
def fetch_files; end
|
115
|
+
|
116
|
+
sig { returns(T.nilable(String)) }
|
79
117
|
def commit
|
80
|
-
return cloned_commit if cloned_commit
|
81
|
-
return source.commit if source.commit
|
118
|
+
return T.must(cloned_commit) if cloned_commit
|
119
|
+
return T.must(source.commit) if source.commit
|
82
120
|
|
83
121
|
branch = target_branch || default_branch_for_repo
|
84
122
|
|
85
|
-
@commit ||= client_for_provider.fetch_commit(repo, branch)
|
123
|
+
@commit ||= T.let(T.unsafe(client_for_provider).fetch_commit(repo, branch), T.nilable(String))
|
86
124
|
rescue *CLIENT_NOT_FOUND_ERRORS
|
87
125
|
raise Dependabot::BranchNotFound, branch
|
88
126
|
rescue Octokit::Conflict => e
|
@@ -90,9 +128,12 @@ module Dependabot
|
|
90
128
|
end
|
91
129
|
|
92
130
|
# Returns the path to the cloned repo
|
131
|
+
sig { returns(String) }
|
93
132
|
def clone_repo_contents
|
94
|
-
@clone_repo_contents ||=
|
95
|
-
_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
|
+
)
|
96
137
|
rescue Dependabot::SharedHelpers::HelperSubprocessFailed => e
|
97
138
|
if e.message.include?("fatal: Remote branch #{target_branch} not found in upstream origin")
|
98
139
|
raise Dependabot::BranchNotFound, target_branch
|
@@ -100,19 +141,20 @@ module Dependabot
|
|
100
141
|
raise Dependabot::OutOfDisk
|
101
142
|
end
|
102
143
|
|
103
|
-
raise Dependabot::RepoNotFound,
|
144
|
+
raise Dependabot::RepoNotFound.new(source, e.message)
|
104
145
|
end
|
105
146
|
|
106
|
-
|
107
|
-
|
108
|
-
end
|
147
|
+
sig { overridable.returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
148
|
+
def ecosystem_versions; end
|
109
149
|
|
110
150
|
private
|
111
151
|
|
152
|
+
sig { params(name: String).returns(T.nilable(Dependabot::DependencyFile)) }
|
112
153
|
def fetch_support_file(name)
|
113
154
|
fetch_file_if_present(name)&.tap { |f| f.support_file = true }
|
114
155
|
end
|
115
156
|
|
157
|
+
sig { params(filename: String, fetch_submodules: T::Boolean).returns(T.nilable(DependencyFile)) }
|
116
158
|
def fetch_file_if_present(filename, fetch_submodules: false)
|
117
159
|
unless repo_contents_path.nil?
|
118
160
|
begin
|
@@ -136,6 +178,7 @@ module Dependabot
|
|
136
178
|
nil
|
137
179
|
end
|
138
180
|
|
181
|
+
sig { params(filename: T.any(Pathname, String)).returns(Dependabot::DependencyFile) }
|
139
182
|
def load_cloned_file_if_present(filename)
|
140
183
|
path = Pathname.new(File.join(directory, filename)).cleanpath.to_path
|
141
184
|
repo_path = File.join(clone_repo_contents, path)
|
@@ -154,10 +197,19 @@ module Dependabot
|
|
154
197
|
directory: directory,
|
155
198
|
type: type,
|
156
199
|
content: content,
|
157
|
-
symlink_target: symlink_target
|
200
|
+
symlink_target: symlink_target,
|
201
|
+
support_file: in_submodule?(path)
|
158
202
|
)
|
159
203
|
end
|
160
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
|
161
213
|
def fetch_file_from_host(filename, type: "file", fetch_submodules: false)
|
162
214
|
return load_cloned_file_if_present(filename) unless repo_contents_path.nil?
|
163
215
|
|
@@ -167,7 +219,7 @@ module Dependabot
|
|
167
219
|
|
168
220
|
linked_path = symlinked_subpath(clean_path)
|
169
221
|
type = "symlink" if linked_path
|
170
|
-
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"
|
171
223
|
|
172
224
|
DependencyFile.new(
|
173
225
|
name: Pathname.new(filename).cleanpath.to_path,
|
@@ -181,61 +233,87 @@ module Dependabot
|
|
181
233
|
end
|
182
234
|
|
183
235
|
# Finds the first subpath in path that is a symlink
|
236
|
+
sig { params(path: String).returns(T.nilable(String)) }
|
184
237
|
def symlinked_subpath(path)
|
185
238
|
subpaths(path).find { |subpath| @linked_paths.key?(subpath) }
|
186
239
|
end
|
187
240
|
|
241
|
+
sig { params(path: String).returns(T::Boolean) }
|
242
|
+
def in_submodule?(path)
|
243
|
+
subpaths(path.delete_prefix("/")).any? { |subpath| @submodules.include?(subpath) }
|
244
|
+
end
|
245
|
+
|
188
246
|
# Given a "foo/bar/baz" path, returns ["foo", "foo/bar", "foo/bar/baz"]
|
247
|
+
sig { params(path: String).returns(T::Array[String]) }
|
189
248
|
def subpaths(path)
|
190
249
|
components = path.split("/")
|
191
|
-
components.map { |component| components[0..components.index(component)].join("/") }
|
250
|
+
components.map { |component| T.must(components[0..components.index(component)]).join("/") }
|
192
251
|
end
|
193
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
|
194
262
|
def repo_contents(dir: ".", ignore_base_directory: false,
|
195
263
|
raise_errors: true, fetch_submodules: false)
|
196
264
|
dir = File.join(directory, dir) unless ignore_base_directory
|
197
265
|
path = Pathname.new(dir).cleanpath.to_path.gsub(%r{^/*}, "")
|
198
266
|
|
199
|
-
@repo_contents ||= {}
|
200
|
-
@repo_contents[dir] ||= if repo_contents_path
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
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
|
206
274
|
end
|
207
275
|
|
276
|
+
sig { returns(T.nilable(String)) }
|
208
277
|
def cloned_commit
|
209
278
|
return if repo_contents_path.nil? || !File.directory?(File.join(repo_contents_path, ".git"))
|
210
279
|
|
211
280
|
SharedHelpers.with_git_configured(credentials: credentials) do
|
212
|
-
Dir.chdir(repo_contents_path) do
|
213
|
-
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
|
214
283
|
end
|
215
284
|
end
|
216
285
|
end
|
217
286
|
|
287
|
+
sig { returns(String) }
|
218
288
|
def default_branch_for_repo
|
219
|
-
@default_branch_for_repo ||= client_for_provider
|
220
|
-
.fetch_default_branch(repo)
|
289
|
+
@default_branch_for_repo ||= T.let(T.unsafe(client_for_provider).fetch_default_branch(repo), T.nilable(String))
|
221
290
|
rescue *CLIENT_NOT_FOUND_ERRORS
|
222
291
|
raise Dependabot::RepoNotFound, source
|
223
292
|
end
|
224
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
|
225
303
|
def update_linked_paths(repo, path, commit, github_response)
|
226
|
-
case github_response.type
|
304
|
+
case T.unsafe(github_response).type
|
227
305
|
when "submodule"
|
228
|
-
sub_source = Source.from_url(github_response.submodule_git_url)
|
306
|
+
sub_source = Source.from_url(T.unsafe(github_response).submodule_git_url)
|
229
307
|
return unless sub_source
|
230
308
|
|
231
309
|
@linked_paths[path] = {
|
232
310
|
repo: sub_source.repo,
|
233
311
|
provider: sub_source.provider,
|
234
|
-
commit: github_response.sha,
|
312
|
+
commit: T.unsafe(github_response).sha,
|
235
313
|
path: "/"
|
236
314
|
}
|
237
315
|
when "symlink"
|
238
|
-
updated_path = File.join(File.dirname(path), github_response.target)
|
316
|
+
updated_path = File.join(File.dirname(path), T.unsafe(github_response).target)
|
239
317
|
@linked_paths[path] = {
|
240
318
|
repo: repo,
|
241
319
|
provider: "github",
|
@@ -245,10 +323,22 @@ module Dependabot
|
|
245
323
|
end
|
246
324
|
end
|
247
325
|
|
326
|
+
sig { returns(T::Boolean) }
|
248
327
|
def recurse_submodules_when_cloning?
|
249
328
|
false
|
250
329
|
end
|
251
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
|
252
342
|
def client_for_provider
|
253
343
|
case source.provider
|
254
344
|
when "github" then github_client
|
@@ -260,46 +350,75 @@ module Dependabot
|
|
260
350
|
end
|
261
351
|
end
|
262
352
|
|
353
|
+
sig { returns(Dependabot::Clients::GithubWithRetries) }
|
263
354
|
def github_client
|
264
355
|
@github_client ||=
|
265
|
-
|
266
|
-
|
267
|
-
|
356
|
+
T.let(
|
357
|
+
Dependabot::Clients::GithubWithRetries.for_source(
|
358
|
+
source: source,
|
359
|
+
credentials: credentials
|
360
|
+
),
|
361
|
+
T.nilable(Dependabot::Clients::GithubWithRetries)
|
268
362
|
)
|
269
363
|
end
|
270
364
|
|
365
|
+
sig { returns(Dependabot::Clients::GitlabWithRetries) }
|
271
366
|
def gitlab_client
|
272
367
|
@gitlab_client ||=
|
273
|
-
|
274
|
-
|
275
|
-
|
368
|
+
T.let(
|
369
|
+
Dependabot::Clients::GitlabWithRetries.for_source(
|
370
|
+
source: source,
|
371
|
+
credentials: credentials
|
372
|
+
),
|
373
|
+
T.nilable(Dependabot::Clients::GitlabWithRetries)
|
276
374
|
)
|
277
375
|
end
|
278
376
|
|
377
|
+
sig { returns(Dependabot::Clients::Azure) }
|
279
378
|
def azure_client
|
280
379
|
@azure_client ||=
|
281
|
-
|
282
|
-
|
380
|
+
T.let(
|
381
|
+
Dependabot::Clients::Azure.for_source(
|
382
|
+
source: source,
|
383
|
+
credentials: credentials
|
384
|
+
),
|
385
|
+
T.nilable(Dependabot::Clients::Azure)
|
386
|
+
)
|
283
387
|
end
|
284
388
|
|
389
|
+
sig { returns(Dependabot::Clients::BitbucketWithRetries) }
|
285
390
|
def bitbucket_client
|
286
391
|
# TODO: When self-hosted Bitbucket is supported this should use
|
287
392
|
# `Bitbucket.for_source`
|
288
393
|
@bitbucket_client ||=
|
289
|
-
|
290
|
-
|
394
|
+
T.let(
|
395
|
+
Dependabot::Clients::BitbucketWithRetries.for_bitbucket_dot_org(
|
396
|
+
credentials: credentials
|
397
|
+
),
|
398
|
+
T.nilable(Dependabot::Clients::BitbucketWithRetries)
|
399
|
+
)
|
291
400
|
end
|
292
401
|
|
402
|
+
sig { returns(Dependabot::Clients::CodeCommit) }
|
293
403
|
def codecommit_client
|
294
404
|
@codecommit_client ||=
|
295
|
-
|
296
|
-
|
405
|
+
T.let(
|
406
|
+
Dependabot::Clients::CodeCommit.for_source(
|
407
|
+
source: source,
|
408
|
+
credentials: credentials
|
409
|
+
),
|
410
|
+
T.nilable(Dependabot::Clients::CodeCommit)
|
411
|
+
)
|
297
412
|
end
|
298
413
|
|
299
414
|
#################################################
|
300
415
|
# INTERNAL METHODS (not for use by sub-classes) #
|
301
416
|
#################################################
|
302
417
|
|
418
|
+
sig do
|
419
|
+
params(path: String, fetch_submodules: T::Boolean, raise_errors: T::Boolean)
|
420
|
+
.returns(T::Array[OpenStruct])
|
421
|
+
end
|
303
422
|
def _fetch_repo_contents(path, fetch_submodules: false,
|
304
423
|
raise_errors: true)
|
305
424
|
path = path.gsub(" ", "%20")
|
@@ -331,6 +450,10 @@ module Dependabot
|
|
331
450
|
retry
|
332
451
|
end
|
333
452
|
|
453
|
+
sig do
|
454
|
+
params(provider: String, repo: String, path: String, commit: String)
|
455
|
+
.returns(T::Array[OpenStruct])
|
456
|
+
end
|
334
457
|
def _fetch_repo_contents_fully_specified(provider, repo, path, commit)
|
335
458
|
case provider
|
336
459
|
when "github"
|
@@ -347,9 +470,10 @@ module Dependabot
|
|
347
470
|
end
|
348
471
|
end
|
349
472
|
|
473
|
+
sig { params(repo: String, path: String, commit: String).returns(T::Array[OpenStruct]) }
|
350
474
|
def _github_repo_contents(repo, path, commit)
|
351
475
|
path = path.gsub(" ", "%20")
|
352
|
-
github_response = github_client.contents(repo, path: path, ref: commit)
|
476
|
+
github_response = T.unsafe(github_client).contents(repo, path: path, ref: commit)
|
353
477
|
|
354
478
|
if github_response.respond_to?(:type)
|
355
479
|
update_linked_paths(repo, path, commit, github_response)
|
@@ -359,6 +483,7 @@ module Dependabot
|
|
359
483
|
github_response.map { |f| _build_github_file_struct(f) }
|
360
484
|
end
|
361
485
|
|
486
|
+
sig { params(relative_path: String).returns(T::Array[OpenStruct]) }
|
362
487
|
def _cloned_repo_contents(relative_path)
|
363
488
|
repo_path = File.join(clone_repo_contents, relative_path)
|
364
489
|
return [] unless Dir.exist?(repo_path)
|
@@ -384,37 +509,40 @@ module Dependabot
|
|
384
509
|
end
|
385
510
|
end
|
386
511
|
|
512
|
+
sig { params(file: Sawyer::Resource).returns(OpenStruct) }
|
387
513
|
def _build_github_file_struct(file)
|
388
514
|
OpenStruct.new(
|
389
|
-
name: file.name,
|
390
|
-
path: file.path,
|
391
|
-
type: file.type,
|
392
|
-
sha: file.sha,
|
393
|
-
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
|
394
520
|
)
|
395
521
|
end
|
396
522
|
|
523
|
+
sig { params(repo: String, path: String, commit: String).returns(T::Array[OpenStruct]) }
|
397
524
|
def _gitlab_repo_contents(repo, path, commit)
|
398
|
-
gitlab_client
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
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
|
416
543
|
end
|
417
544
|
|
545
|
+
sig { params(path: String, commit: String).returns(T::Array[OpenStruct]) }
|
418
546
|
def _azure_repo_contents(path, commit)
|
419
547
|
response = azure_client.fetch_repo_contents(commit, path)
|
420
548
|
|
@@ -434,12 +562,14 @@ module Dependabot
|
|
434
562
|
end
|
435
563
|
end
|
436
564
|
|
565
|
+
sig { params(repo: String, path: String, commit: String).returns(T::Array[OpenStruct]) }
|
437
566
|
def _bitbucket_repo_contents(repo, path, commit)
|
438
|
-
response =
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
567
|
+
response = T.unsafe(bitbucket_client)
|
568
|
+
.fetch_repo_contents(
|
569
|
+
repo,
|
570
|
+
commit,
|
571
|
+
path
|
572
|
+
)
|
443
573
|
|
444
574
|
response.map do |file|
|
445
575
|
type = case file.fetch("type")
|
@@ -457,6 +587,7 @@ module Dependabot
|
|
457
587
|
end
|
458
588
|
end
|
459
589
|
|
590
|
+
sig { params(repo: String, path: String, commit: String).returns(T::Array[OpenStruct]) }
|
460
591
|
def _codecommit_repo_contents(repo, path, commit)
|
461
592
|
response = codecommit_client.fetch_repo_contents(
|
462
593
|
repo,
|
@@ -474,11 +605,12 @@ module Dependabot
|
|
474
605
|
end
|
475
606
|
end
|
476
607
|
|
608
|
+
sig { params(path: String, fetch_submodules: T::Boolean).returns(T::Hash[Symbol, T.untyped]) }
|
477
609
|
def _full_specification_for(path, fetch_submodules:)
|
478
610
|
if fetch_submodules && _linked_dir_for(path)
|
479
611
|
linked_dir_details = @linked_paths[_linked_dir_for(path)]
|
480
612
|
sub_path =
|
481
|
-
path.gsub(%r{^#{Regexp.quote(_linked_dir_for(path))}(/|$)}, "")
|
613
|
+
path.gsub(%r{^#{Regexp.quote(T.must(_linked_dir_for(path)))}(/|$)}, "")
|
482
614
|
new_path =
|
483
615
|
Pathname.new(File.join(linked_dir_details.fetch(:path), sub_path))
|
484
616
|
.cleanpath.to_path
|
@@ -499,6 +631,7 @@ module Dependabot
|
|
499
631
|
end
|
500
632
|
end
|
501
633
|
|
634
|
+
sig { params(path: String, fetch_submodules: T::Boolean).returns(String) }
|
502
635
|
def _fetch_file_content(path, fetch_submodules: false)
|
503
636
|
path = path.gsub(%r{^/*}, "")
|
504
637
|
|
@@ -519,17 +652,18 @@ module Dependabot
|
|
519
652
|
retry
|
520
653
|
end
|
521
654
|
|
655
|
+
sig { params(provider: String, repo: String, path: String, commit: String).returns(String) }
|
522
656
|
def _fetch_file_content_fully_specified(provider, repo, path, commit)
|
523
657
|
case provider
|
524
658
|
when "github"
|
525
659
|
_fetch_file_content_from_github(path, repo, commit)
|
526
660
|
when "gitlab"
|
527
|
-
tmp = gitlab_client.get_file(repo, path, commit).content
|
661
|
+
tmp = T.unsafe(gitlab_client).get_file(repo, path, commit).content
|
528
662
|
decode_binary_string(tmp)
|
529
663
|
when "azure"
|
530
664
|
azure_client.fetch_file_contents(commit, path)
|
531
665
|
when "bitbucket"
|
532
|
-
bitbucket_client.fetch_file_contents(repo, commit, path)
|
666
|
+
T.unsafe(bitbucket_client).fetch_file_contents(repo, commit, path)
|
533
667
|
when "codecommit"
|
534
668
|
codecommit_client.fetch_file_contents(repo, commit, path)
|
535
669
|
else raise "Unsupported provider '#{source.provider}'."
|
@@ -537,8 +671,9 @@ module Dependabot
|
|
537
671
|
end
|
538
672
|
|
539
673
|
# rubocop:disable Metrics/AbcSize
|
674
|
+
sig { params(path: String, repo: String, commit: String).returns(String) }
|
540
675
|
def _fetch_file_content_from_github(path, repo, commit)
|
541
|
-
tmp = github_client.contents(repo, path: path, ref: commit)
|
676
|
+
tmp = T.unsafe(github_client).contents(repo, path: path, ref: commit)
|
542
677
|
|
543
678
|
raise Octokit::NotFound if tmp.is_a?(Array)
|
544
679
|
|
@@ -549,7 +684,7 @@ module Dependabot
|
|
549
684
|
commit: commit,
|
550
685
|
path: Pathname.new(tmp.target).cleanpath.to_path
|
551
686
|
}
|
552
|
-
tmp = github_client.contents(
|
687
|
+
tmp = T.unsafe(github_client).contents(
|
553
688
|
repo,
|
554
689
|
path: Pathname.new(tmp.target).cleanpath.to_path,
|
555
690
|
ref: commit
|
@@ -559,7 +694,7 @@ module Dependabot
|
|
559
694
|
if tmp.content == ""
|
560
695
|
# The file may have exceeded the 1MB limit
|
561
696
|
# see https://github.blog/changelog/2022-05-03-increased-file-size-limit-when-retrieving-file-contents-via-rest-api/
|
562
|
-
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")
|
563
698
|
else
|
564
699
|
decode_binary_string(tmp.content)
|
565
700
|
end
|
@@ -573,7 +708,7 @@ module Dependabot
|
|
573
708
|
file_details = repo_contents(dir: dir).find { |f| f.name == basename }
|
574
709
|
raise unless file_details
|
575
710
|
|
576
|
-
tmp = github_client.blob(repo, file_details.sha)
|
711
|
+
tmp = T.unsafe(github_client).blob(repo, file_details.sha)
|
577
712
|
return tmp.content if tmp.encoding == "utf-8"
|
578
713
|
|
579
714
|
decode_binary_string(tmp.content)
|
@@ -583,6 +718,7 @@ module Dependabot
|
|
583
718
|
# Update the @linked_paths hash by exploiting a side-effect of
|
584
719
|
# recursively calling `repo_contents` for each directory up the tree
|
585
720
|
# until a submodule or symlink is found
|
721
|
+
sig { params(path: String).returns(T.nilable(T::Array[T.untyped])) }
|
586
722
|
def _find_linked_dirs(path)
|
587
723
|
path = Pathname.new(path).cleanpath.to_path.gsub(%r{^/*}, "")
|
588
724
|
dir = File.dirname(path)
|
@@ -597,6 +733,7 @@ module Dependabot
|
|
597
733
|
)
|
598
734
|
end
|
599
735
|
|
736
|
+
sig { params(path: String).returns(T.nilable(String)) }
|
600
737
|
def _linked_dir_for(path)
|
601
738
|
linked_dirs = @linked_paths.keys
|
602
739
|
linked_dirs
|
@@ -608,6 +745,7 @@ module Dependabot
|
|
608
745
|
# rubocop:disable Metrics/MethodLength
|
609
746
|
# rubocop:disable Metrics/PerceivedComplexity
|
610
747
|
# rubocop:disable Metrics/BlockLength
|
748
|
+
sig { params(target_directory: T.nilable(String)).returns(String) }
|
611
749
|
def _clone_repo_contents(target_directory:)
|
612
750
|
SharedHelpers.with_git_configured(credentials: credentials) do
|
613
751
|
path = target_directory || File.join("tmp", source.repo)
|
@@ -633,11 +771,13 @@ module Dependabot
|
|
633
771
|
git clone #{clone_options.string} #{source.url} #{path}
|
634
772
|
CMD
|
635
773
|
)
|
774
|
+
|
775
|
+
@submodules = find_submodules(path) if recurse_submodules_when_cloning?
|
636
776
|
rescue SharedHelpers::HelperSubprocessFailed => e
|
637
777
|
raise unless e.message.match(GIT_SUBMODULE_ERROR_REGEX) && e.message.downcase.include?("submodule")
|
638
778
|
|
639
779
|
submodule_cloning_failed = true
|
640
|
-
match = e.message.match(GIT_SUBMODULE_ERROR_REGEX)
|
780
|
+
match = T.must(e.message.match(GIT_SUBMODULE_ERROR_REGEX))
|
641
781
|
url = match.named_captures["url"]
|
642
782
|
code = match.named_captures["code"]
|
643
783
|
|
@@ -680,10 +820,27 @@ module Dependabot
|
|
680
820
|
# rubocop:enable Metrics/PerceivedComplexity
|
681
821
|
# rubocop:enable Metrics/BlockLength
|
682
822
|
|
823
|
+
sig { params(str: String).returns(String) }
|
683
824
|
def decode_binary_string(str)
|
684
825
|
bom = (+"\xEF\xBB\xBF").force_encoding(Encoding::BINARY)
|
685
826
|
Base64.decode64(str).delete_prefix(bom).force_encoding("UTF-8").encode
|
686
827
|
end
|
828
|
+
|
829
|
+
sig { params(path: String).returns(T::Array[String]) }
|
830
|
+
def find_submodules(path)
|
831
|
+
SharedHelpers.run_shell_command(
|
832
|
+
<<~CMD
|
833
|
+
git -C #{path} ls-files --stage
|
834
|
+
CMD
|
835
|
+
).split("\n").filter_map do |line|
|
836
|
+
info = line.split
|
837
|
+
|
838
|
+
type = info.first
|
839
|
+
path = T.must(info.last)
|
840
|
+
|
841
|
+
next path if type == DependencyFile::Mode::SUBMODULE
|
842
|
+
end
|
843
|
+
end
|
687
844
|
end
|
688
845
|
end
|
689
846
|
end
|