dependabot-common 0.245.0 → 0.246.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/bitbucket.rb +113 -5
- data/lib/dependabot/clients/codecommit.rb +107 -12
- data/lib/dependabot/clients/github_with_retries.rb +61 -19
- data/lib/dependabot/clients/gitlab_with_retries.rb +60 -7
- data/lib/dependabot/dependency.rb +1 -1
- data/lib/dependabot/errors.rb +8 -2
- data/lib/dependabot/git_commit_checker.rb +3 -2
- data/lib/dependabot/metadata_finders/base/changelog_finder.rb +1 -1
- data/lib/dependabot/metadata_finders/base/commits_finder.rb +1 -1
- data/lib/dependabot/metadata_finders/base/release_finder.rb +1 -1
- data/lib/dependabot/pull_request_creator/azure.rb +80 -9
- data/lib/dependabot/pull_request_creator/bitbucket.rb +73 -9
- data/lib/dependabot/pull_request_creator/codecommit.rb +96 -25
- data/lib/dependabot/pull_request_creator/github.rb +162 -49
- data/lib/dependabot/pull_request_creator/gitlab.rb +109 -21
- data/lib/dependabot/pull_request_creator/message_builder.rb +239 -89
- data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +11 -9
- data/lib/dependabot/pull_request_creator.rb +32 -27
- data/lib/dependabot/pull_request_updater/azure.rb +75 -11
- data/lib/dependabot/pull_request_updater/github.rb +89 -28
- data/lib/dependabot/pull_request_updater/gitlab.rb +61 -12
- data/lib/dependabot/pull_request_updater.rb +1 -1
- data/lib/dependabot/update_checkers/base.rb +121 -31
- data/lib/dependabot.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: afa14b1e2f804f1713004ae03cf9ba9ac2ed546794d736bbeedef24d18f8be7b
|
4
|
+
data.tar.gz: 012a72964c4ae5f6140ab6a81d101f227bd84445a2e04b77395252ae66771bc8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 367510a477d1b7a1d362f69a8a4a8bdcfb1d89f355f442291d3640c247391e924612b51bbe3393b146dcfb621d1faf53ab7dc364bf4eba134c17389a781d4ba0
|
7
|
+
data.tar.gz: ae0d0af76bbea879c4cf4faec7c1be85067cec9918c1c7ad2818b60c160d5da93bcb11a5c3bd9287d4b9f11256de46eb0758f56db98ef2586ec2c3d4e514ed17
|
@@ -1,12 +1,16 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "dependabot/shared_helpers"
|
5
4
|
require "excon"
|
5
|
+
require "sorbet-runtime"
|
6
|
+
|
7
|
+
require "dependabot/shared_helpers"
|
6
8
|
|
7
9
|
module Dependabot
|
8
10
|
module Clients
|
9
11
|
class Bitbucket
|
12
|
+
extend T::Sig
|
13
|
+
|
10
14
|
class NotFound < StandardError; end
|
11
15
|
|
12
16
|
class Unauthorized < StandardError; end
|
@@ -19,6 +23,13 @@ module Dependabot
|
|
19
23
|
# Constructor methods #
|
20
24
|
#######################
|
21
25
|
|
26
|
+
sig do
|
27
|
+
params(
|
28
|
+
source: Dependabot::Source,
|
29
|
+
credentials: T::Array[Dependabot::Credential]
|
30
|
+
)
|
31
|
+
.returns(Dependabot::Clients::Bitbucket)
|
32
|
+
end
|
22
33
|
def self.for_source(source:, credentials:)
|
23
34
|
credential =
|
24
35
|
credentials
|
@@ -32,11 +43,13 @@ module Dependabot
|
|
32
43
|
# Client #
|
33
44
|
##########
|
34
45
|
|
46
|
+
sig { params(credentials: T.nilable(Dependabot::Credential)).void }
|
35
47
|
def initialize(credentials:)
|
36
48
|
@credentials = credentials
|
37
|
-
@auth_header = auth_header_for(credentials&.fetch("token", nil))
|
49
|
+
@auth_header = T.let(auth_header_for(credentials&.fetch("token", nil)), T::Hash[String, String])
|
38
50
|
end
|
39
51
|
|
52
|
+
sig { params(repo: String, branch: String).returns(String) }
|
40
53
|
def fetch_commit(repo, branch)
|
41
54
|
path = "#{repo}/refs/branches/#{branch}"
|
42
55
|
response = get(base_url + path)
|
@@ -44,12 +57,21 @@ module Dependabot
|
|
44
57
|
JSON.parse(response.body).fetch("target").fetch("hash")
|
45
58
|
end
|
46
59
|
|
60
|
+
sig { params(repo: String).returns(String) }
|
47
61
|
def fetch_default_branch(repo)
|
48
62
|
response = get(base_url + repo)
|
49
63
|
|
50
64
|
JSON.parse(response.body).fetch("mainbranch").fetch("name")
|
51
65
|
end
|
52
66
|
|
67
|
+
sig do
|
68
|
+
params(
|
69
|
+
repo: String,
|
70
|
+
commit: T.nilable(String),
|
71
|
+
path: T.nilable(String)
|
72
|
+
)
|
73
|
+
.returns(T::Array[T::Hash[String, T.untyped]])
|
74
|
+
end
|
53
75
|
def fetch_repo_contents(repo, commit = nil, path = nil)
|
54
76
|
raise "Commit is required if path provided!" if commit.nil? && path
|
55
77
|
|
@@ -62,6 +84,14 @@ module Dependabot
|
|
62
84
|
JSON.parse(response.body).fetch("values")
|
63
85
|
end
|
64
86
|
|
87
|
+
sig do
|
88
|
+
params(
|
89
|
+
repo: String,
|
90
|
+
commit: String,
|
91
|
+
path: String
|
92
|
+
)
|
93
|
+
.returns(String)
|
94
|
+
end
|
65
95
|
def fetch_file_contents(repo, commit, path)
|
66
96
|
path = "#{repo}/src/#{commit}/#{path.gsub(%r{/+$}, '')}"
|
67
97
|
response = get(base_url + path)
|
@@ -69,12 +99,26 @@ module Dependabot
|
|
69
99
|
response.body
|
70
100
|
end
|
71
101
|
|
102
|
+
sig do
|
103
|
+
params(
|
104
|
+
repo: String,
|
105
|
+
branch_name: T.nilable(String)
|
106
|
+
)
|
107
|
+
.returns(T::Enumerator[T::Hash[String, T.untyped]])
|
108
|
+
end
|
72
109
|
def commits(repo, branch_name = nil)
|
73
110
|
commits_path = "#{repo}/commits/#{branch_name}?pagelen=100"
|
74
111
|
next_page_url = base_url + commits_path
|
75
112
|
paginate({ "next" => next_page_url })
|
76
113
|
end
|
77
114
|
|
115
|
+
sig do
|
116
|
+
params(
|
117
|
+
repo: String,
|
118
|
+
branch_name: String
|
119
|
+
)
|
120
|
+
.returns(T::Hash[String, T.untyped])
|
121
|
+
end
|
78
122
|
def branch(repo, branch_name)
|
79
123
|
branch_path = "#{repo}/refs/branches/#{branch_name}"
|
80
124
|
response = get(base_url + branch_path)
|
@@ -82,6 +126,15 @@ module Dependabot
|
|
82
126
|
JSON.parse(response.body)
|
83
127
|
end
|
84
128
|
|
129
|
+
sig do
|
130
|
+
params(
|
131
|
+
repo: String,
|
132
|
+
source_branch: T.nilable(String),
|
133
|
+
target_branch: T.nilable(String),
|
134
|
+
status: T::Array[String]
|
135
|
+
)
|
136
|
+
.returns(T::Array[T::Hash[String, T.untyped]])
|
137
|
+
end
|
85
138
|
def pull_requests(repo, source_branch, target_branch, status = %w(OPEN MERGED DECLINED SUPERSEDED))
|
86
139
|
pr_path = "#{repo}/pullrequests?"
|
87
140
|
# Get pull requests with given status
|
@@ -104,6 +157,17 @@ module Dependabot
|
|
104
157
|
end
|
105
158
|
|
106
159
|
# rubocop:disable Metrics/ParameterLists
|
160
|
+
sig do
|
161
|
+
params(
|
162
|
+
repo: String,
|
163
|
+
branch_name: String,
|
164
|
+
base_commit: String,
|
165
|
+
commit_message: String,
|
166
|
+
files: T::Array[Dependabot::DependencyFile],
|
167
|
+
author_details: T::Hash[Symbol, String]
|
168
|
+
)
|
169
|
+
.void
|
170
|
+
end
|
107
171
|
def create_commit(repo, branch_name, base_commit, commit_message, files,
|
108
172
|
author_details)
|
109
173
|
parameters = {
|
@@ -125,6 +189,18 @@ module Dependabot
|
|
125
189
|
# rubocop:enable Metrics/ParameterLists
|
126
190
|
|
127
191
|
# rubocop:disable Metrics/ParameterLists
|
192
|
+
sig do
|
193
|
+
params(
|
194
|
+
repo: String,
|
195
|
+
pr_name: String,
|
196
|
+
source_branch: String,
|
197
|
+
target_branch: String,
|
198
|
+
pr_description: String,
|
199
|
+
_labels: T.nilable(T::Array[String]),
|
200
|
+
_work_item: T.nilable(Integer)
|
201
|
+
)
|
202
|
+
.void
|
203
|
+
end
|
128
204
|
def create_pull_request(repo, pr_name, source_branch, target_branch,
|
129
205
|
pr_description, _labels, _work_item = nil)
|
130
206
|
reviewers = default_reviewers(repo)
|
@@ -151,6 +227,7 @@ module Dependabot
|
|
151
227
|
end
|
152
228
|
# rubocop:enable Metrics/ParameterLists
|
153
229
|
|
230
|
+
sig { params(repo: String, pr_id: Integer, comment: T.nilable(String)).void }
|
154
231
|
def decline_pull_request(repo, pr_id, comment = nil)
|
155
232
|
# https://developer.atlassian.com/cloud/bitbucket/rest/api-group-pullrequests/
|
156
233
|
decline_path = "#{repo}/pullrequests/#{pr_id}/decline"
|
@@ -168,14 +245,16 @@ module Dependabot
|
|
168
245
|
post(base_url + comment_path, content.to_json)
|
169
246
|
end
|
170
247
|
|
248
|
+
sig { returns(T.nilable(String)) }
|
171
249
|
def current_user
|
172
250
|
base_url = "https://api.bitbucket.org/2.0/user?fields=uuid"
|
173
251
|
response = get(base_url)
|
174
252
|
JSON.parse(response.body).fetch("uuid")
|
175
253
|
rescue Unauthorized
|
176
|
-
|
254
|
+
nil
|
177
255
|
end
|
178
256
|
|
257
|
+
sig { params(repo: String).returns(T::Array[T::Hash[String, String]]) }
|
179
258
|
def default_reviewers(repo)
|
180
259
|
current_uuid = current_user
|
181
260
|
path = "#{repo}/default-reviewers?pagelen=100&fields=values.uuid,next"
|
@@ -192,6 +271,7 @@ module Dependabot
|
|
192
271
|
reviewer_data
|
193
272
|
end
|
194
273
|
|
274
|
+
sig { params(repo: String).returns(T::Array[T::Hash[String, String]]) }
|
195
275
|
def tags(repo)
|
196
276
|
path = "#{repo}/refs/tags?pagelen=100"
|
197
277
|
response = get(base_url + path)
|
@@ -199,6 +279,14 @@ module Dependabot
|
|
199
279
|
JSON.parse(response.body).fetch("values")
|
200
280
|
end
|
201
281
|
|
282
|
+
sig do
|
283
|
+
params(
|
284
|
+
repo: String,
|
285
|
+
previous_tag: String,
|
286
|
+
new_tag: String
|
287
|
+
)
|
288
|
+
.returns(T::Array[T::Hash[String, T.untyped]])
|
289
|
+
end
|
202
290
|
def compare(repo, previous_tag, new_tag)
|
203
291
|
path = "#{repo}/commits/?include=#{new_tag}&exclude=#{previous_tag}"
|
204
292
|
response = get(base_url + path)
|
@@ -206,6 +294,7 @@ module Dependabot
|
|
206
294
|
JSON.parse(response.body).fetch("values")
|
207
295
|
end
|
208
296
|
|
297
|
+
sig { params(url: String).returns(Excon::Response) }
|
209
298
|
def get(url)
|
210
299
|
response = Excon.get(
|
211
300
|
URI::DEFAULT_PARSER.escape(url),
|
@@ -230,6 +319,14 @@ module Dependabot
|
|
230
319
|
response
|
231
320
|
end
|
232
321
|
|
322
|
+
sig do
|
323
|
+
params(
|
324
|
+
url: String,
|
325
|
+
body: String,
|
326
|
+
content_type: String
|
327
|
+
)
|
328
|
+
.returns(Excon::Response)
|
329
|
+
end
|
233
330
|
def post(url, body, content_type = "application/json")
|
234
331
|
headers = auth_header
|
235
332
|
|
@@ -259,12 +356,14 @@ module Dependabot
|
|
259
356
|
|
260
357
|
private
|
261
358
|
|
359
|
+
sig { params(token: T.nilable(String)).returns(T::Hash[String, String]) }
|
262
360
|
def auth_header_for(token)
|
263
361
|
return {} unless token
|
264
362
|
|
265
363
|
{ "Authorization" => "Bearer #{token}" }
|
266
364
|
end
|
267
365
|
|
366
|
+
sig { params(parameters: T::Hash[String, String]).returns(String) }
|
268
367
|
def encode_form_parameters(parameters)
|
269
368
|
parameters.map do |key, value|
|
270
369
|
URI.encode_www_form_component(key.to_s) + "=" + URI.encode_www_form_component(value.to_s)
|
@@ -284,6 +383,11 @@ module Dependabot
|
|
284
383
|
# response = post(url, body)
|
285
384
|
# first_page = JSON.parse(response.body)
|
286
385
|
# paginate(first_page)
|
386
|
+
sig do
|
387
|
+
type_parameters(:T)
|
388
|
+
.params(page: T.all(T.type_parameter(:T), T::Hash[String, T.untyped]))
|
389
|
+
.returns(T::Enumerator[T.type_parameter(:T)])
|
390
|
+
end
|
287
391
|
def paginate(page)
|
288
392
|
Enumerator.new do |yielder|
|
289
393
|
loop do
|
@@ -291,14 +395,18 @@ module Dependabot
|
|
291
395
|
break unless page.key?("next")
|
292
396
|
|
293
397
|
next_page_url = page.fetch("next")
|
294
|
-
page = JSON.parse(get(next_page_url).body)
|
398
|
+
page = T.cast(JSON.parse(get(next_page_url).body), T.all(T::Hash[String, T.untyped], T.type_parameter(:T)))
|
295
399
|
end
|
296
400
|
end
|
297
401
|
end
|
298
402
|
|
403
|
+
sig { returns(T::Hash[String, String]) }
|
299
404
|
attr_reader :auth_header
|
405
|
+
|
406
|
+
sig { returns(T.nilable(Dependabot::Credential)) }
|
300
407
|
attr_reader :credentials
|
301
408
|
|
409
|
+
sig { returns(String) }
|
302
410
|
def base_url
|
303
411
|
# TODO: Make this configurable when we support enterprise Bitbucket
|
304
412
|
"https://api.bitbucket.org/2.0/repositories/"
|
@@ -1,7 +1,9 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "aws-sdk-codecommit"
|
5
|
+
require "sorbet-runtime"
|
6
|
+
|
5
7
|
require "dependabot/shared_helpers"
|
6
8
|
|
7
9
|
module Dependabot
|
@@ -15,6 +17,13 @@ module Dependabot
|
|
15
17
|
# Constructor methods #
|
16
18
|
#######################
|
17
19
|
|
20
|
+
sig do
|
21
|
+
params(
|
22
|
+
source: Dependabot::Source,
|
23
|
+
credentials: T::Array[Dependabot::Credential]
|
24
|
+
)
|
25
|
+
.returns(Dependabot::Clients::CodeCommit)
|
26
|
+
end
|
18
27
|
def self.for_source(source:, credentials:)
|
19
28
|
credential =
|
20
29
|
credentials
|
@@ -28,20 +37,32 @@ module Dependabot
|
|
28
37
|
# Client #
|
29
38
|
##########
|
30
39
|
|
40
|
+
sig do
|
41
|
+
params(
|
42
|
+
source: Dependabot::Source,
|
43
|
+
credentials: T.nilable(Dependabot::Credential)
|
44
|
+
)
|
45
|
+
.void
|
46
|
+
end
|
31
47
|
def initialize(source, credentials)
|
32
48
|
@source = source
|
33
49
|
@cc_client =
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
50
|
+
T.let(
|
51
|
+
if credentials
|
52
|
+
Aws::CodeCommit::Client.new(
|
53
|
+
access_key_id: credentials.fetch("username"),
|
54
|
+
secret_access_key: credentials.fetch("password"),
|
55
|
+
region: credentials.fetch("region")
|
56
|
+
)
|
57
|
+
else
|
58
|
+
Aws::CodeCommit::Client.new
|
59
|
+
end,
|
60
|
+
Aws::CodeCommit::Client
|
61
|
+
)
|
43
62
|
end
|
44
63
|
|
64
|
+
# TODO: Should repo be required?
|
65
|
+
sig { params(repo: T.nilable(String), branch: String).returns(String) }
|
45
66
|
def fetch_commit(repo, branch)
|
46
67
|
cc_client.get_branch(
|
47
68
|
branch_name: branch,
|
@@ -49,12 +70,20 @@ module Dependabot
|
|
49
70
|
).branch.commit_id
|
50
71
|
end
|
51
72
|
|
73
|
+
sig { params(repo: String).returns(String) }
|
52
74
|
def fetch_default_branch(repo)
|
53
75
|
cc_client.get_repository(
|
54
76
|
repository_name: repo
|
55
77
|
).repository_metadata.default_branch
|
56
78
|
end
|
57
79
|
|
80
|
+
sig do
|
81
|
+
params(
|
82
|
+
repo: String, commit: T.nilable(String),
|
83
|
+
path: T.nilable(String)
|
84
|
+
)
|
85
|
+
.returns(Aws::CodeCommit::Types::GetFolderOutput)
|
86
|
+
end
|
58
87
|
def fetch_repo_contents(repo, commit = nil, path = nil)
|
59
88
|
actual_path = path
|
60
89
|
actual_path = "/" if path.to_s.empty?
|
@@ -66,6 +95,14 @@ module Dependabot
|
|
66
95
|
)
|
67
96
|
end
|
68
97
|
|
98
|
+
sig do
|
99
|
+
params(
|
100
|
+
repo: String,
|
101
|
+
commit: String,
|
102
|
+
path: String
|
103
|
+
)
|
104
|
+
.returns(String)
|
105
|
+
end
|
69
106
|
def fetch_file_contents(repo, commit, path)
|
70
107
|
cc_client.get_file(
|
71
108
|
repository_name: repo,
|
@@ -76,6 +113,12 @@ module Dependabot
|
|
76
113
|
raise NotFound
|
77
114
|
end
|
78
115
|
|
116
|
+
sig do
|
117
|
+
params(
|
118
|
+
branch_name: String
|
119
|
+
)
|
120
|
+
.returns(String)
|
121
|
+
end
|
79
122
|
def branch(branch_name)
|
80
123
|
cc_client.get_branch(
|
81
124
|
repository_name: source.unscoped_repo,
|
@@ -84,6 +127,14 @@ module Dependabot
|
|
84
127
|
end
|
85
128
|
|
86
129
|
# work around b/c codecommit doesn't have a 'get all commits' api..
|
130
|
+
sig do
|
131
|
+
params(
|
132
|
+
repo: String,
|
133
|
+
branch_name: String,
|
134
|
+
result_count: Integer
|
135
|
+
)
|
136
|
+
.returns(T::Array[String])
|
137
|
+
end
|
87
138
|
def fetch_commits(repo, branch_name, result_count)
|
88
139
|
top_commit = fetch_commit(repo, branch_name)
|
89
140
|
retrieved_commits = []
|
@@ -123,7 +174,14 @@ module Dependabot
|
|
123
174
|
result
|
124
175
|
end
|
125
176
|
|
126
|
-
|
177
|
+
sig do
|
178
|
+
params(
|
179
|
+
repo: String,
|
180
|
+
branch_name: String
|
181
|
+
)
|
182
|
+
.returns(Aws::CodeCommit::Types::Commit)
|
183
|
+
end
|
184
|
+
def commits(repo, branch_name = T.must(source.branch))
|
127
185
|
retrieved_commits = fetch_commits(repo, branch_name, 5)
|
128
186
|
|
129
187
|
result = @cc_client.batch_get_commits(
|
@@ -136,6 +194,14 @@ module Dependabot
|
|
136
194
|
result
|
137
195
|
end
|
138
196
|
|
197
|
+
sig do
|
198
|
+
params(
|
199
|
+
repo: String,
|
200
|
+
state: String,
|
201
|
+
branch: String
|
202
|
+
)
|
203
|
+
.returns(T::Array[Aws::CodeCommit::Types::PullRequest])
|
204
|
+
end
|
139
205
|
def pull_requests(repo, state, branch)
|
140
206
|
pull_request_ids = @cc_client.list_pull_requests(
|
141
207
|
repository_name: repo,
|
@@ -158,6 +224,14 @@ module Dependabot
|
|
158
224
|
result
|
159
225
|
end
|
160
226
|
|
227
|
+
sig do
|
228
|
+
params(
|
229
|
+
repo: String,
|
230
|
+
branch_name: String,
|
231
|
+
commit_id: String
|
232
|
+
)
|
233
|
+
.returns(Aws::CodeCommit::Types::BranchInfo)
|
234
|
+
end
|
161
235
|
def create_branch(repo, branch_name, commit_id)
|
162
236
|
cc_client.create_branch(
|
163
237
|
repository_name: repo,
|
@@ -166,6 +240,16 @@ module Dependabot
|
|
166
240
|
)
|
167
241
|
end
|
168
242
|
|
243
|
+
sig do
|
244
|
+
params(
|
245
|
+
branch_name: String,
|
246
|
+
author_name: String,
|
247
|
+
base_commit: String,
|
248
|
+
commit_message: String,
|
249
|
+
files: T::Array[Dependabot::DependencyFile]
|
250
|
+
)
|
251
|
+
.returns(Aws::CodeCommit::Types::CreateCommitOutput)
|
252
|
+
end
|
169
253
|
def create_commit(branch_name, author_name, base_commit, commit_message,
|
170
254
|
files)
|
171
255
|
cc_client.create_commit(
|
@@ -184,6 +268,15 @@ module Dependabot
|
|
184
268
|
)
|
185
269
|
end
|
186
270
|
|
271
|
+
sig do
|
272
|
+
params(
|
273
|
+
pr_name: String,
|
274
|
+
target_branch: String,
|
275
|
+
source_branch: String,
|
276
|
+
pr_description: String
|
277
|
+
)
|
278
|
+
.returns(T.nilable(Aws::CodeCommit::Types::CreatePullRequestOutput))
|
279
|
+
end
|
187
280
|
def create_pull_request(pr_name, target_branch, source_branch,
|
188
281
|
pr_description)
|
189
282
|
cc_client.create_pull_request(
|
@@ -199,8 +292,10 @@ module Dependabot
|
|
199
292
|
|
200
293
|
private
|
201
294
|
|
202
|
-
|
295
|
+
sig { returns(Dependabot::Source) }
|
203
296
|
attr_reader :source
|
297
|
+
|
298
|
+
sig { returns(Aws::CodeCommit::Client) }
|
204
299
|
attr_reader :cc_client
|
205
300
|
end
|
206
301
|
end
|
@@ -1,42 +1,61 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "octokit"
|
5
|
+
require "sorbet-runtime"
|
6
|
+
require "dependabot/credential"
|
5
7
|
|
6
8
|
module Dependabot
|
7
9
|
module Clients
|
8
10
|
class GithubWithRetries
|
11
|
+
extend T::Sig
|
12
|
+
|
9
13
|
DEFAULT_OPEN_TIMEOUT_IN_SECONDS = 2
|
10
14
|
DEFAULT_READ_TIMEOUT_IN_SECONDS = 5
|
11
15
|
|
16
|
+
sig { returns(Integer) }
|
12
17
|
def self.open_timeout_in_seconds
|
13
18
|
ENV.fetch("DEPENDABOT_OPEN_TIMEOUT_IN_SECONDS", DEFAULT_OPEN_TIMEOUT_IN_SECONDS).to_i
|
14
19
|
end
|
15
20
|
|
21
|
+
sig { returns(Integer) }
|
16
22
|
def self.read_timeout_in_seconds
|
17
23
|
ENV.fetch("DEPENDABOT_READ_TIMEOUT_IN_SECONDS", DEFAULT_READ_TIMEOUT_IN_SECONDS).to_i
|
18
24
|
end
|
19
25
|
|
20
|
-
DEFAULT_CLIENT_ARGS =
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
26
|
+
DEFAULT_CLIENT_ARGS = T.let(
|
27
|
+
{
|
28
|
+
connection_options: {
|
29
|
+
request: {
|
30
|
+
open_timeout: open_timeout_in_seconds,
|
31
|
+
timeout: read_timeout_in_seconds
|
32
|
+
}
|
25
33
|
}
|
26
|
-
}
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
34
|
+
}.freeze,
|
35
|
+
T::Hash[Symbol, T.untyped]
|
36
|
+
)
|
37
|
+
|
38
|
+
RETRYABLE_ERRORS = T.let(
|
39
|
+
[
|
40
|
+
Faraday::ConnectionFailed,
|
41
|
+
Faraday::TimeoutError,
|
42
|
+
Octokit::InternalServerError,
|
43
|
+
Octokit::BadGateway
|
44
|
+
].freeze,
|
45
|
+
T::Array[T.class_of(StandardError)]
|
46
|
+
)
|
35
47
|
|
36
48
|
#######################
|
37
49
|
# Constructor methods #
|
38
50
|
#######################
|
39
51
|
|
52
|
+
sig do
|
53
|
+
params(
|
54
|
+
source: Dependabot::Source,
|
55
|
+
credentials: T::Array[Dependabot::Credential]
|
56
|
+
)
|
57
|
+
.returns(Dependabot::Clients::GithubWithRetries)
|
58
|
+
end
|
40
59
|
def self.for_source(source:, credentials:)
|
41
60
|
access_tokens =
|
42
61
|
credentials
|
@@ -51,6 +70,7 @@ module Dependabot
|
|
51
70
|
)
|
52
71
|
end
|
53
72
|
|
73
|
+
sig { params(credentials: T::Array[Dependabot::Credential]).returns(Dependabot::Clients::GithubWithRetries) }
|
54
74
|
def self.for_github_dot_com(credentials:)
|
55
75
|
access_tokens =
|
56
76
|
credentials
|
@@ -66,6 +86,7 @@ module Dependabot
|
|
66
86
|
# VCS Interface #
|
67
87
|
#################
|
68
88
|
|
89
|
+
sig { params(repo: String, branch: String).returns(String) }
|
69
90
|
def fetch_commit(repo, branch)
|
70
91
|
response = T.unsafe(self).ref(repo, "heads/#{branch}")
|
71
92
|
|
@@ -74,6 +95,7 @@ module Dependabot
|
|
74
95
|
response.object.sha
|
75
96
|
end
|
76
97
|
|
98
|
+
sig { params(repo: String).returns(String) }
|
77
99
|
def fetch_default_branch(repo)
|
78
100
|
T.unsafe(self).repository(repo).default_branch
|
79
101
|
end
|
@@ -82,6 +104,7 @@ module Dependabot
|
|
82
104
|
# Proxying #
|
83
105
|
############
|
84
106
|
|
107
|
+
sig { params(max_retries: T.nilable(Integer), args: T.untyped).void }
|
85
108
|
def initialize(max_retries: 3, **args)
|
86
109
|
args = DEFAULT_CLIENT_ARGS.merge(args)
|
87
110
|
|
@@ -106,11 +129,23 @@ module Dependabot
|
|
106
129
|
end
|
107
130
|
end
|
108
131
|
|
109
|
-
@clients =
|
110
|
-
|
111
|
-
|
132
|
+
@clients = T.let(
|
133
|
+
access_tokens.map do |token|
|
134
|
+
Octokit::Client.new(args.merge(access_token: token))
|
135
|
+
end,
|
136
|
+
T::Array[Octokit::Client]
|
137
|
+
)
|
112
138
|
end
|
113
139
|
|
140
|
+
# TODO: Create all the methods that are called on the client
|
141
|
+
sig do
|
142
|
+
params(
|
143
|
+
method_name: T.any(Symbol, String),
|
144
|
+
args: T.untyped,
|
145
|
+
block: T.nilable(T.proc.returns(T.untyped))
|
146
|
+
)
|
147
|
+
.returns(T.untyped)
|
148
|
+
end
|
114
149
|
def method_missing(method_name, *args, &block)
|
115
150
|
untried_clients = @clients.dup
|
116
151
|
client = untried_clients.pop
|
@@ -118,7 +153,7 @@ module Dependabot
|
|
118
153
|
begin
|
119
154
|
if client.respond_to?(method_name)
|
120
155
|
mutatable_args = args.map(&:dup)
|
121
|
-
client.public_send(method_name, *mutatable_args, &block)
|
156
|
+
T.unsafe(client).public_send(method_name, *mutatable_args, &block)
|
122
157
|
else
|
123
158
|
super
|
124
159
|
end
|
@@ -129,6 +164,13 @@ module Dependabot
|
|
129
164
|
end
|
130
165
|
end
|
131
166
|
|
167
|
+
sig do
|
168
|
+
params(
|
169
|
+
method_name: Symbol,
|
170
|
+
include_private: T::Boolean
|
171
|
+
)
|
172
|
+
.returns(T::Boolean)
|
173
|
+
end
|
132
174
|
def respond_to_missing?(method_name, include_private = false)
|
133
175
|
@clients.first.respond_to?(method_name) || super
|
134
176
|
end
|