dependabot-common 0.235.0 → 0.237.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|