dependabot-common 0.392.0 → 0.394.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 +42 -22
- data/lib/dependabot/clients/bitbucket.rb +52 -26
- data/lib/dependabot/clients/bitbucket_with_retries.rb +11 -12
- data/lib/dependabot/clients/codecommit.rb +73 -53
- data/lib/dependabot/clients/github_resource_parser.rb +70 -0
- data/lib/dependabot/clients/github_with_retries.rb +63 -23
- data/lib/dependabot/clients/gitlab_with_retries.rb +19 -17
- data/lib/dependabot/clients/json_response_parser.rb +103 -0
- data/lib/dependabot/command_helpers.rb +79 -11
- data/lib/dependabot/credential.rb +12 -3
- data/lib/dependabot/errors.rb +4 -1
- data/lib/dependabot/file_fetchers/base.rb +199 -151
- data/lib/dependabot/file_filtering.rb +0 -2
- data/lib/dependabot/file_updaters/vendor_updater.rb +8 -2
- data/lib/dependabot/git_tag_details.rb +8 -14
- data/lib/dependabot/metadata_finders/base/changelog_finder.rb +211 -110
- data/lib/dependabot/metadata_finders/base/commit_response_parser.rb +68 -0
- data/lib/dependabot/metadata_finders/base/commits_finder.rb +44 -38
- data/lib/dependabot/package/npm_package_manager_config.rb +72 -0
- data/lib/dependabot/package/npm_registry_package.rb +186 -0
- data/lib/dependabot/pull_request_creator/azure.rb +1 -1
- data/lib/dependabot/pull_request_creator/codecommit.rb +10 -12
- data/lib/dependabot/pull_request_creator/github.rb +55 -35
- data/lib/dependabot/pull_request_creator/gitlab.rb +37 -11
- data/lib/dependabot/pull_request_creator/labeler.rb +65 -15
- data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +179 -78
- data/lib/dependabot/pull_request_updater/azure.rb +63 -11
- data/lib/dependabot/pull_request_updater/github.rb +44 -34
- data/lib/dependabot/pull_request_updater/gitlab.rb +23 -12
- data/lib/dependabot/pull_request_updater.rb +3 -3
- data/lib/dependabot/shared_helpers.rb +77 -32
- data/lib/dependabot/update_checkers/base.rb +9 -5
- data/lib/dependabot/update_checkers/version_filters.rb +5 -0
- data/lib/dependabot/update_checkers/vulnerability_audit.rb +282 -0
- data/lib/dependabot/workspace/git.rb +35 -4
- data/lib/dependabot.rb +1 -1
- metadata +10 -4
|
@@ -83,19 +83,19 @@ module Dependabot
|
|
|
83
83
|
commit: T.nilable(String),
|
|
84
84
|
path: T.nilable(String)
|
|
85
85
|
)
|
|
86
|
-
|
|
87
|
-
# but it not extend Delegator, unblocking until shim or
|
|
88
|
-
# another fix is implemented
|
|
89
|
-
.returns(T.untyped)
|
|
86
|
+
.returns(Seahorse::Client::Response)
|
|
90
87
|
end
|
|
91
88
|
def fetch_repo_contents(repo, commit = nil, path = nil)
|
|
92
89
|
actual_path = path
|
|
93
90
|
actual_path = "/" if path.to_s.empty?
|
|
94
91
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
92
|
+
T.cast(
|
|
93
|
+
cc_client.get_folder(
|
|
94
|
+
repository_name: repo,
|
|
95
|
+
commit_specifier: commit,
|
|
96
|
+
folder_path: actual_path
|
|
97
|
+
),
|
|
98
|
+
Seahorse::Client::Response
|
|
99
99
|
)
|
|
100
100
|
end
|
|
101
101
|
|
|
@@ -121,12 +121,15 @@ module Dependabot
|
|
|
121
121
|
params(
|
|
122
122
|
branch_name: String
|
|
123
123
|
)
|
|
124
|
-
.returns(
|
|
124
|
+
.returns(Seahorse::Client::Response)
|
|
125
125
|
end
|
|
126
126
|
def branch(branch_name)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
T.cast(
|
|
128
|
+
cc_client.get_branch(
|
|
129
|
+
repository_name: source.unscoped_repo,
|
|
130
|
+
branch_name: branch_name
|
|
131
|
+
),
|
|
132
|
+
Seahorse::Client::Response
|
|
130
133
|
)
|
|
131
134
|
end
|
|
132
135
|
|
|
@@ -183,18 +186,24 @@ module Dependabot
|
|
|
183
186
|
repo: String,
|
|
184
187
|
branch_name: String
|
|
185
188
|
)
|
|
186
|
-
.returns(
|
|
189
|
+
.returns(Seahorse::Client::Response)
|
|
187
190
|
end
|
|
188
191
|
def commits(repo, branch_name = T.must(source.branch))
|
|
189
192
|
retrieved_commits = fetch_commits(repo, branch_name, 5)
|
|
190
193
|
|
|
191
|
-
result =
|
|
192
|
-
|
|
193
|
-
|
|
194
|
+
result = T.cast(
|
|
195
|
+
@cc_client.batch_get_commits(
|
|
196
|
+
commit_ids: retrieved_commits,
|
|
197
|
+
repository_name: repo
|
|
198
|
+
),
|
|
199
|
+
Seahorse::Client::Response
|
|
194
200
|
)
|
|
195
201
|
|
|
196
202
|
# sort the results by date
|
|
197
|
-
|
|
203
|
+
output = T.cast(result.data, Aws::CodeCommit::Types::BatchGetCommitsOutput)
|
|
204
|
+
commits = output.commits
|
|
205
|
+
commits&.sort_by! { |commit| commit.author&.date || "" }
|
|
206
|
+
commits&.reverse!
|
|
198
207
|
result
|
|
199
208
|
end
|
|
200
209
|
|
|
@@ -204,7 +213,7 @@ module Dependabot
|
|
|
204
213
|
state: String,
|
|
205
214
|
branch: String
|
|
206
215
|
)
|
|
207
|
-
.returns(T::Array[
|
|
216
|
+
.returns(T::Array[Seahorse::Client::Response])
|
|
208
217
|
end
|
|
209
218
|
def pull_requests(repo, state, branch)
|
|
210
219
|
pull_request_ids = @cc_client.list_pull_requests(
|
|
@@ -212,18 +221,20 @@ module Dependabot
|
|
|
212
221
|
pull_request_status: state
|
|
213
222
|
).pull_request_ids
|
|
214
223
|
|
|
215
|
-
result = []
|
|
224
|
+
result = T.let([], T::Array[Seahorse::Client::Response])
|
|
216
225
|
# list_pull_requests only gets us the pull request id
|
|
217
226
|
# get_pull_request has all the info we need
|
|
218
227
|
pull_request_ids.each do |id|
|
|
219
|
-
pr_hash =
|
|
220
|
-
|
|
228
|
+
pr_hash = T.cast(
|
|
229
|
+
@cc_client.get_pull_request(
|
|
230
|
+
pull_request_id: id
|
|
231
|
+
),
|
|
232
|
+
Seahorse::Client::Response
|
|
221
233
|
)
|
|
234
|
+
output = T.cast(pr_hash.data, Aws::CodeCommit::Types::GetPullRequestOutput)
|
|
222
235
|
# only include PRs from the referenced branch
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
result << pr_hash
|
|
226
|
-
end
|
|
236
|
+
source_reference = T.must(output.pull_request.pull_request_targets[0]).source_reference
|
|
237
|
+
result << pr_hash if source_reference.delete_prefix("refs/heads/") == branch.delete_prefix("refs/heads/")
|
|
227
238
|
end
|
|
228
239
|
result
|
|
229
240
|
end
|
|
@@ -234,13 +245,16 @@ module Dependabot
|
|
|
234
245
|
branch_name: String,
|
|
235
246
|
commit_id: String
|
|
236
247
|
)
|
|
237
|
-
.returns(
|
|
248
|
+
.returns(Seahorse::Client::Response)
|
|
238
249
|
end
|
|
239
250
|
def create_branch(repo, branch_name, commit_id)
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
251
|
+
T.cast(
|
|
252
|
+
cc_client.create_branch(
|
|
253
|
+
repository_name: repo,
|
|
254
|
+
branch_name: branch_name,
|
|
255
|
+
commit_id: commit_id
|
|
256
|
+
),
|
|
257
|
+
Seahorse::Client::Response
|
|
244
258
|
)
|
|
245
259
|
end
|
|
246
260
|
|
|
@@ -252,7 +266,7 @@ module Dependabot
|
|
|
252
266
|
commit_message: String,
|
|
253
267
|
files: T::Array[Dependabot::DependencyFile]
|
|
254
268
|
)
|
|
255
|
-
.returns(
|
|
269
|
+
.returns(Seahorse::Client::Response)
|
|
256
270
|
end
|
|
257
271
|
def create_commit(
|
|
258
272
|
branch_name,
|
|
@@ -261,19 +275,22 @@ module Dependabot
|
|
|
261
275
|
commit_message,
|
|
262
276
|
files
|
|
263
277
|
)
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
278
|
+
T.cast(
|
|
279
|
+
cc_client.create_commit(
|
|
280
|
+
repository_name: source.unscoped_repo,
|
|
281
|
+
branch_name: branch_name,
|
|
282
|
+
parent_commit_id: base_commit,
|
|
283
|
+
author_name: author_name,
|
|
284
|
+
commit_message: commit_message,
|
|
285
|
+
put_files: files.map do |file|
|
|
286
|
+
{
|
|
287
|
+
file_path: file.path,
|
|
288
|
+
file_mode: "NORMAL",
|
|
289
|
+
file_content: file.content
|
|
290
|
+
}
|
|
291
|
+
end
|
|
292
|
+
),
|
|
293
|
+
Seahorse::Client::Response
|
|
277
294
|
)
|
|
278
295
|
end
|
|
279
296
|
|
|
@@ -284,7 +301,7 @@ module Dependabot
|
|
|
284
301
|
source_branch: String,
|
|
285
302
|
pr_description: String
|
|
286
303
|
)
|
|
287
|
-
.returns(
|
|
304
|
+
.returns(Seahorse::Client::Response)
|
|
288
305
|
end
|
|
289
306
|
def create_pull_request(
|
|
290
307
|
pr_name,
|
|
@@ -292,14 +309,17 @@ module Dependabot
|
|
|
292
309
|
source_branch,
|
|
293
310
|
pr_description
|
|
294
311
|
)
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
312
|
+
T.cast(
|
|
313
|
+
cc_client.create_pull_request(
|
|
314
|
+
title: pr_name,
|
|
315
|
+
description: pr_description,
|
|
316
|
+
targets: [
|
|
317
|
+
{ repository_name: source.unscoped_repo,
|
|
318
|
+
source_reference: target_branch,
|
|
319
|
+
destination_reference: source_branch }
|
|
320
|
+
]
|
|
321
|
+
),
|
|
322
|
+
Seahorse::Client::Response
|
|
303
323
|
)
|
|
304
324
|
end
|
|
305
325
|
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# typed: strong
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "dependabot/errors"
|
|
5
|
+
require "sorbet-runtime"
|
|
6
|
+
|
|
7
|
+
module Dependabot
|
|
8
|
+
module Clients
|
|
9
|
+
module GithubResourceParser
|
|
10
|
+
extend T::Sig
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
sig { params(resource: Sawyer::Resource, key: Symbol, context: String).returns(String) }
|
|
15
|
+
def github_string(resource, key, context)
|
|
16
|
+
value = T.cast(resource[key], Object)
|
|
17
|
+
return value if value.is_a?(String)
|
|
18
|
+
|
|
19
|
+
raise_bad_github_response("#{context} #{key} must be a string")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
sig { params(resource: Sawyer::Resource, key: Symbol, context: String).returns(T.nilable(String)) }
|
|
23
|
+
def github_optional_string(resource, key, context)
|
|
24
|
+
value = T.cast(resource[key], Object)
|
|
25
|
+
return if value.nil?
|
|
26
|
+
return value if value.is_a?(String)
|
|
27
|
+
|
|
28
|
+
raise_bad_github_response("#{context} #{key} must be a string or nil")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
sig { params(resource: Sawyer::Resource, key: Symbol, context: String).returns(Integer) }
|
|
32
|
+
def github_integer(resource, key, context)
|
|
33
|
+
value = T.cast(resource[key], Object)
|
|
34
|
+
return value if value.is_a?(Integer)
|
|
35
|
+
|
|
36
|
+
raise_bad_github_response("#{context} #{key} must be an integer")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
sig { params(resource: Sawyer::Resource, key: Symbol, context: String).returns(T::Boolean) }
|
|
40
|
+
def github_boolean(resource, key, context)
|
|
41
|
+
value = T.cast(resource[key], Object)
|
|
42
|
+
return value if value == true
|
|
43
|
+
return false if value.nil? || value == false
|
|
44
|
+
|
|
45
|
+
raise_bad_github_response("#{context} #{key} must be a boolean or nil")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
sig { params(resource: Sawyer::Resource, key: Symbol, context: String).returns(Sawyer::Resource) }
|
|
49
|
+
def github_resource(resource, key, context)
|
|
50
|
+
value = T.cast(resource[key], Object)
|
|
51
|
+
return value if value.is_a?(Sawyer::Resource)
|
|
52
|
+
|
|
53
|
+
raise_bad_github_response("#{context} #{key} must be an object")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
sig { params(message: String).returns(T.noreturn) }
|
|
57
|
+
def raise_bad_github_response(message)
|
|
58
|
+
Kernel.raise Dependabot::PrivateSourceBadResponse.new(
|
|
59
|
+
github_response_source,
|
|
60
|
+
"Malformed GitHub response: #{message}"
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
sig { returns(String) }
|
|
65
|
+
def github_response_source
|
|
66
|
+
Kernel.raise NotImplementedError
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
|
|
4
4
|
require "octokit"
|
|
5
5
|
require "sorbet-runtime"
|
|
6
|
+
require "delegate"
|
|
6
7
|
require "dependabot/credential"
|
|
7
8
|
|
|
8
9
|
module Dependabot
|
|
9
10
|
module Clients
|
|
10
|
-
class GithubWithRetries
|
|
11
|
+
class GithubWithRetries < SimpleDelegator
|
|
11
12
|
extend T::Sig
|
|
12
13
|
|
|
13
14
|
DEFAULT_OPEN_TIMEOUT_IN_SECONDS = 2
|
|
14
15
|
DEFAULT_READ_TIMEOUT_IN_SECONDS = 5
|
|
16
|
+
ClientOptions = T.type_alias { T::Hash[Symbol, Object] }
|
|
15
17
|
|
|
16
18
|
sig { returns(Integer) }
|
|
17
19
|
def self.open_timeout_in_seconds
|
|
@@ -32,7 +34,7 @@ module Dependabot
|
|
|
32
34
|
}
|
|
33
35
|
}
|
|
34
36
|
}.freeze,
|
|
35
|
-
|
|
37
|
+
ClientOptions
|
|
36
38
|
)
|
|
37
39
|
|
|
38
40
|
RETRYABLE_ERRORS = T.let(
|
|
@@ -88,30 +90,35 @@ module Dependabot
|
|
|
88
90
|
|
|
89
91
|
sig { params(repo: String, branch: String).returns(String) }
|
|
90
92
|
def fetch_commit(repo, branch)
|
|
91
|
-
response =
|
|
93
|
+
response = ref(repo, "heads/#{branch}")
|
|
92
94
|
|
|
93
|
-
raise Octokit::NotFound if response.is_a?(Array)
|
|
95
|
+
Kernel.raise Octokit::NotFound if response.is_a?(Array)
|
|
94
96
|
|
|
95
|
-
response
|
|
97
|
+
object = T.cast(response[:object], Sawyer::Resource)
|
|
98
|
+
T.cast(object[:sha], String)
|
|
96
99
|
end
|
|
97
100
|
|
|
98
101
|
sig { params(repo: String).returns(String) }
|
|
99
102
|
def fetch_default_branch(repo)
|
|
100
|
-
T.
|
|
103
|
+
T.cast(repository(repo)[:default_branch], String)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
sig { params(repo: String, path: String, ref: String).returns(String) }
|
|
107
|
+
def raw_contents(repo, path:, ref:)
|
|
108
|
+
T.cast(
|
|
109
|
+
contents(repo, path: path, ref: ref, accept: "application/vnd.github.v3.raw"),
|
|
110
|
+
String
|
|
111
|
+
)
|
|
101
112
|
end
|
|
102
113
|
|
|
103
114
|
############
|
|
104
115
|
# Proxying #
|
|
105
116
|
############
|
|
106
117
|
|
|
107
|
-
sig { params(max_retries: T.nilable(Integer), args:
|
|
118
|
+
sig { params(max_retries: T.nilable(Integer), args: Object).void }
|
|
108
119
|
def initialize(max_retries: 3, **args)
|
|
109
120
|
args = DEFAULT_CLIENT_ARGS.merge(args)
|
|
110
|
-
|
|
111
|
-
access_tokens = args.delete(:access_tokens) || []
|
|
112
|
-
access_tokens << args[:access_token] if args[:access_token]
|
|
113
|
-
access_tokens << nil if access_tokens.empty?
|
|
114
|
-
access_tokens.uniq!
|
|
121
|
+
access_tokens = extract_access_tokens(args)
|
|
115
122
|
|
|
116
123
|
# Explicitly set the proxy if one is set in the environment
|
|
117
124
|
# as Faraday's find_proxy is very slow.
|
|
@@ -135,30 +142,29 @@ module Dependabot
|
|
|
135
142
|
end,
|
|
136
143
|
T::Array[Octokit::Client]
|
|
137
144
|
)
|
|
145
|
+
super(T.must(@clients.last))
|
|
138
146
|
end
|
|
139
147
|
|
|
140
148
|
# TODO: Create all the methods that are called on the client
|
|
141
149
|
sig do
|
|
142
150
|
params(
|
|
143
151
|
method_name: T.any(Symbol, String),
|
|
144
|
-
args:
|
|
145
|
-
block: T.nilable(
|
|
152
|
+
args: Object,
|
|
153
|
+
block: T.nilable(Proc)
|
|
146
154
|
)
|
|
147
|
-
.returns(T.
|
|
155
|
+
.returns(T.anything)
|
|
148
156
|
end
|
|
149
157
|
def method_missing(method_name, *args, &block)
|
|
158
|
+
original_args = args
|
|
150
159
|
untried_clients = @clients.dup
|
|
151
160
|
client = untried_clients.pop
|
|
152
161
|
|
|
153
162
|
begin
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
else
|
|
158
|
-
super
|
|
159
|
-
end
|
|
163
|
+
__setobj__(T.must(client))
|
|
164
|
+
args = original_args.map(&:dup)
|
|
165
|
+
super
|
|
160
166
|
rescue Octokit::NotFound, Octokit::Unauthorized, Octokit::Forbidden
|
|
161
|
-
raise unless (client = untried_clients.pop)
|
|
167
|
+
Kernel.raise unless (client = untried_clients.pop)
|
|
162
168
|
|
|
163
169
|
retry
|
|
164
170
|
end
|
|
@@ -172,7 +178,41 @@ module Dependabot
|
|
|
172
178
|
.returns(T::Boolean)
|
|
173
179
|
end
|
|
174
180
|
def respond_to_missing?(method_name, include_private = false)
|
|
175
|
-
@clients.first.respond_to?(method_name)
|
|
181
|
+
@clients.first.respond_to?(method_name, include_private)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
private
|
|
185
|
+
|
|
186
|
+
sig { params(args: ClientOptions).returns(T::Array[T.nilable(String)]) }
|
|
187
|
+
def extract_access_tokens(args)
|
|
188
|
+
access_tokens = T.let([], T::Array[T.nilable(String)])
|
|
189
|
+
case (raw_access_tokens = args.delete(:access_tokens))
|
|
190
|
+
when nil
|
|
191
|
+
nil
|
|
192
|
+
when Array
|
|
193
|
+
raw_access_tokens.each do |raw_token|
|
|
194
|
+
token = T.cast(raw_token, Object)
|
|
195
|
+
case token
|
|
196
|
+
when nil, String then access_tokens << token
|
|
197
|
+
else Kernel.raise TypeError, "access_tokens must contain only strings or nil"
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
else
|
|
201
|
+
Kernel.raise TypeError, "access_tokens must be an array or nil"
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
access_token = args[:access_token]
|
|
205
|
+
case access_token
|
|
206
|
+
when nil
|
|
207
|
+
nil
|
|
208
|
+
when String
|
|
209
|
+
access_tokens << access_token
|
|
210
|
+
else
|
|
211
|
+
Kernel.raise TypeError, "access_token must be a string or nil"
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
access_tokens << nil if access_tokens.empty?
|
|
215
|
+
access_tokens.uniq
|
|
176
216
|
end
|
|
177
217
|
end
|
|
178
218
|
end
|
|
@@ -3,14 +3,17 @@
|
|
|
3
3
|
|
|
4
4
|
require "gitlab"
|
|
5
5
|
require "sorbet-runtime"
|
|
6
|
+
require "delegate"
|
|
6
7
|
|
|
7
8
|
require "dependabot/credential"
|
|
8
9
|
|
|
9
10
|
module Dependabot
|
|
10
11
|
module Clients
|
|
11
|
-
class GitlabWithRetries
|
|
12
|
+
class GitlabWithRetries < SimpleDelegator
|
|
12
13
|
extend T::Sig
|
|
13
14
|
|
|
15
|
+
ClientOptions = T.type_alias { T::Hash[Symbol, Object] }
|
|
16
|
+
|
|
14
17
|
RETRYABLE_ERRORS = T.let(
|
|
15
18
|
[Gitlab::Error::BadGateway].freeze,
|
|
16
19
|
T::Array[T.class_of(Gitlab::Error::ResponseError)]
|
|
@@ -67,22 +70,24 @@ module Dependabot
|
|
|
67
70
|
|
|
68
71
|
sig { params(repo: String, branch: String).returns(String) }
|
|
69
72
|
def fetch_commit(repo, branch)
|
|
70
|
-
T.
|
|
73
|
+
commit = T.cast(branch(repo, branch)["commit"], Gitlab::ObjectifiedHash)
|
|
74
|
+
T.cast(commit["id"], String)
|
|
71
75
|
end
|
|
72
76
|
|
|
73
77
|
sig { params(repo: String).returns(String) }
|
|
74
78
|
def fetch_default_branch(repo)
|
|
75
|
-
T.
|
|
79
|
+
T.cast(project(repo)["default_branch"], String)
|
|
76
80
|
end
|
|
77
81
|
|
|
78
82
|
############
|
|
79
83
|
# Proxying #
|
|
80
84
|
############
|
|
81
85
|
|
|
82
|
-
sig { params(max_retries: T.nilable(Integer), args:
|
|
86
|
+
sig { params(max_retries: T.nilable(Integer), args: Object).void }
|
|
83
87
|
def initialize(max_retries: 3, **args)
|
|
84
88
|
@max_retries = T.let(max_retries || 3, Integer)
|
|
85
89
|
@client = T.let(::Gitlab::Client.new(args), ::Gitlab::Client)
|
|
90
|
+
super(@client)
|
|
86
91
|
end
|
|
87
92
|
|
|
88
93
|
# Create commit in gitlab repo with correctly mapped file actions
|
|
@@ -99,7 +104,7 @@ module Dependabot
|
|
|
99
104
|
branch_name: String,
|
|
100
105
|
commit_message: String,
|
|
101
106
|
files: T::Array[Dependabot::DependencyFile],
|
|
102
|
-
options:
|
|
107
|
+
options: Object
|
|
103
108
|
)
|
|
104
109
|
.returns(Gitlab::ObjectifiedHash)
|
|
105
110
|
end
|
|
@@ -117,19 +122,16 @@ module Dependabot
|
|
|
117
122
|
sig do
|
|
118
123
|
params(
|
|
119
124
|
method_name: T.any(Symbol, String),
|
|
120
|
-
args:
|
|
121
|
-
block: T.nilable(
|
|
125
|
+
args: Object,
|
|
126
|
+
block: T.nilable(Proc)
|
|
122
127
|
)
|
|
123
|
-
.returns(T.
|
|
128
|
+
.returns(T.anything)
|
|
124
129
|
end
|
|
125
130
|
def method_missing(method_name, *args, &block)
|
|
131
|
+
original_args = args
|
|
126
132
|
retry_connection_failures do
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
T.unsafe(@client).public_send(method_name, *mutatable_args, &block)
|
|
130
|
-
else
|
|
131
|
-
super
|
|
132
|
-
end
|
|
133
|
+
args = original_args.map(&:dup)
|
|
134
|
+
super
|
|
133
135
|
end
|
|
134
136
|
end
|
|
135
137
|
|
|
@@ -141,7 +143,7 @@ module Dependabot
|
|
|
141
143
|
.returns(T::Boolean)
|
|
142
144
|
end
|
|
143
145
|
def respond_to_missing?(method_name, include_private = false)
|
|
144
|
-
@client.respond_to?(method_name)
|
|
146
|
+
@client.respond_to?(method_name, include_private)
|
|
145
147
|
end
|
|
146
148
|
|
|
147
149
|
sig do
|
|
@@ -156,7 +158,7 @@ module Dependabot
|
|
|
156
158
|
yield
|
|
157
159
|
rescue *RETRYABLE_ERRORS
|
|
158
160
|
retry_attempt += 1
|
|
159
|
-
retry_attempt <= @max_retries ? retry : raise
|
|
161
|
+
retry_attempt <= @max_retries ? retry : Kernel.raise
|
|
160
162
|
end
|
|
161
163
|
end
|
|
162
164
|
|
|
@@ -166,7 +168,7 @@ module Dependabot
|
|
|
166
168
|
#
|
|
167
169
|
# @param [Array<Dependabot::DependencyFile>] files
|
|
168
170
|
# @return [Array<Hash>]
|
|
169
|
-
sig { params(files: T::Array[Dependabot::DependencyFile]).returns(T::Array[T::Hash[Symbol,
|
|
171
|
+
sig { params(files: T::Array[Dependabot::DependencyFile]).returns(T::Array[T::Hash[Symbol, Object]]) }
|
|
170
172
|
def file_actions(files)
|
|
171
173
|
files.map do |file|
|
|
172
174
|
{
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# typed: strong
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "json"
|
|
5
|
+
|
|
6
|
+
require "dependabot/errors"
|
|
7
|
+
require "sorbet-runtime"
|
|
8
|
+
|
|
9
|
+
module Dependabot
|
|
10
|
+
module Clients
|
|
11
|
+
module JsonResponseParser
|
|
12
|
+
extend T::Sig
|
|
13
|
+
|
|
14
|
+
JsonObject = T.type_alias { T::Hash[String, Object] }
|
|
15
|
+
JsonObjects = T.type_alias { T::Array[JsonObject] }
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
sig { params(body: String, context: String).returns(JsonObject) }
|
|
20
|
+
def parse_json_object(body, context)
|
|
21
|
+
value = T.cast(JSON.parse(body), Object)
|
|
22
|
+
return T.let(value, JsonObject) if value.is_a?(Hash)
|
|
23
|
+
|
|
24
|
+
raise_bad_response(context, "expected an object")
|
|
25
|
+
rescue JSON::ParserError => e
|
|
26
|
+
raise_bad_response(context, e.message)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
sig { params(object: JsonObject, key: String, context: String).returns(JsonObject) }
|
|
30
|
+
def object_field(object, key, context)
|
|
31
|
+
value = object.fetch(key)
|
|
32
|
+
return T.let(value, JsonObject) if value.is_a?(Hash)
|
|
33
|
+
|
|
34
|
+
raise_bad_response(context, "#{key} must be an object")
|
|
35
|
+
rescue KeyError => e
|
|
36
|
+
raise_bad_response(context, e.message)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
sig { params(object: JsonObject, key: String, context: String).returns(String) }
|
|
40
|
+
def string_field(object, key, context)
|
|
41
|
+
string_value(object.fetch(key), context)
|
|
42
|
+
rescue KeyError => e
|
|
43
|
+
raise_bad_response(context, e.message)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
sig { params(value: Object, context: String).returns(String) }
|
|
47
|
+
def string_value(value, context)
|
|
48
|
+
return value if value.is_a?(String)
|
|
49
|
+
|
|
50
|
+
raise_bad_response(context, "expected a string")
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
sig { params(object: JsonObject, key: String, context: String).returns(JsonObjects) }
|
|
54
|
+
def object_array_field(object, key, context)
|
|
55
|
+
object_array(object.fetch(key), context)
|
|
56
|
+
rescue KeyError => e
|
|
57
|
+
raise_bad_response(context, e.message)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
sig { params(value: Object, context: String).returns(JsonObjects) }
|
|
61
|
+
def object_array(value, context)
|
|
62
|
+
raise_bad_response(context, "expected an array") unless value.is_a?(Array)
|
|
63
|
+
|
|
64
|
+
value.map do |raw_entry|
|
|
65
|
+
entry = T.cast(raw_entry, Object)
|
|
66
|
+
next T.let(entry, JsonObject) if entry.is_a?(Hash)
|
|
67
|
+
|
|
68
|
+
raise_bad_response(context, "array entries must be objects")
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
sig { params(object: JsonObject, key: String, context: String).returns(JsonObject) }
|
|
73
|
+
def first_object_field(object, key, context)
|
|
74
|
+
value = object_array_field(object, key, context).first
|
|
75
|
+
return value if value
|
|
76
|
+
|
|
77
|
+
raise_bad_response(context, "#{key} must contain at least one object")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
sig { params(object: JsonObject, context: String, paths: T::Array[T::Array[String]]).void }
|
|
81
|
+
def validate_string_paths(object, context, paths)
|
|
82
|
+
paths.each do |path|
|
|
83
|
+
current = T.must(path[0...-1]).reduce(object) { |value, key| object_field(value, key, context) }
|
|
84
|
+
string_field(current, T.must(path.last), context)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
sig { params(context: String, message: String).returns(T.noreturn) }
|
|
89
|
+
def raise_bad_response(context, message)
|
|
90
|
+
provider, source = response_identity
|
|
91
|
+
Kernel.raise Dependabot::PrivateSourceBadResponse.new(
|
|
92
|
+
source,
|
|
93
|
+
"Malformed #{provider} response for #{context}: #{message}"
|
|
94
|
+
)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
sig { returns([String, String]) }
|
|
98
|
+
def response_identity
|
|
99
|
+
Kernel.raise NotImplementedError
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|