dependabot-common 0.245.0 → 0.246.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fbc9b9fbba7549f6bdbb7dafec2f3d3111bd2e8263e966b3eaf1bfce19be3a01
4
- data.tar.gz: 2e396338454b56410104329634792a20076533cadf2418f15e74d591612969eb
3
+ metadata.gz: afa14b1e2f804f1713004ae03cf9ba9ac2ed546794d736bbeedef24d18f8be7b
4
+ data.tar.gz: 012a72964c4ae5f6140ab6a81d101f227bd84445a2e04b77395252ae66771bc8
5
5
  SHA512:
6
- metadata.gz: 2cc3166e278f88f679a7d177b74d77ba9d8cd48ac22694db65a61a36bf5386efb7fd459e430f971cad2e21f33253e67f1e264137fcfc48b57d3d41480c71f9f9
7
- data.tar.gz: fc85175d8dfe6020bc3737fec46342fe529371e984d0f1d806195c697124ff6c63418edc7a1135a30c1c2ceff6caf28be2a715463c466c6bfa3267b5b0249b8a
6
+ metadata.gz: 367510a477d1b7a1d362f69a8a4a8bdcfb1d89f355f442291d3640c247391e924612b51bbe3393b146dcfb621d1faf53ab7dc364bf4eba134c17389a781d4ba0
7
+ data.tar.gz: ae0d0af76bbea879c4cf4faec7c1be85067cec9918c1c7ad2818b60c160d5da93bcb11a5c3bd9287d4b9f11256de46eb0758f56db98ef2586ec2c3d4e514ed17
@@ -1,12 +1,16 @@
1
- # typed: true
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
- [nil]
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: true
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
- if credentials
35
- Aws::CodeCommit::Client.new(
36
- access_key_id: credentials.fetch("username"),
37
- secret_access_key: credentials.fetch("password"),
38
- region: credentials.fetch("region")
39
- )
40
- else
41
- Aws::CodeCommit::Client.new
42
- end
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
- def commits(repo, branch_name = source.branch)
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
- attr_reader :credentials
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: true
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
- connection_options: {
22
- request: {
23
- open_timeout: open_timeout_in_seconds,
24
- timeout: read_timeout_in_seconds
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
- }.freeze
28
-
29
- RETRYABLE_ERRORS = [
30
- Faraday::ConnectionFailed,
31
- Faraday::TimeoutError,
32
- Octokit::InternalServerError,
33
- Octokit::BadGateway
34
- ].freeze
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 = access_tokens.map do |token|
110
- Octokit::Client.new(args.merge(access_token: token))
111
- end
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