dependabot-common 0.242.1 → 0.243.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/lib/dependabot/clients/azure.rb +112 -24
  3. data/lib/dependabot/clients/bitbucket.rb +1 -1
  4. data/lib/dependabot/credential.rb +40 -0
  5. data/lib/dependabot/dependency_group.rb +8 -2
  6. data/lib/dependabot/file_fetchers/base.rb +35 -3
  7. data/lib/dependabot/file_parsers/base.rb +4 -3
  8. data/lib/dependabot/file_updaters/artifact_updater.rb +1 -1
  9. data/lib/dependabot/file_updaters/base.rb +4 -3
  10. data/lib/dependabot/file_updaters/vendor_updater.rb +1 -1
  11. data/lib/dependabot/git_commit_checker.rb +3 -2
  12. data/lib/dependabot/git_metadata_fetcher.rb +3 -2
  13. data/lib/dependabot/metadata_finders/base/changelog_finder.rb +151 -56
  14. data/lib/dependabot/metadata_finders/base/changelog_pruner.rb +45 -14
  15. data/lib/dependabot/metadata_finders/base/commits_finder.rb +123 -53
  16. data/lib/dependabot/metadata_finders/base/release_finder.rb +84 -31
  17. data/lib/dependabot/metadata_finders/base.rb +4 -3
  18. data/lib/dependabot/pull_request_creator/azure.rb +1 -1
  19. data/lib/dependabot/pull_request_creator/branch_namer/solo_strategy.rb +2 -2
  20. data/lib/dependabot/pull_request_creator/labeler.rb +3 -2
  21. data/lib/dependabot/pull_request_creator/message_builder/issue_linker.rb +14 -6
  22. data/lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb +50 -9
  23. data/lib/dependabot/pull_request_creator/message_builder.rb +2 -2
  24. data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +164 -58
  25. data/lib/dependabot/pull_request_creator.rb +6 -5
  26. data/lib/dependabot/pull_request_updater.rb +3 -2
  27. data/lib/dependabot/security_advisory.rb +2 -2
  28. data/lib/dependabot/shared_helpers.rb +3 -2
  29. data/lib/dependabot/utils.rb +1 -13
  30. data/lib/dependabot/workspace/git.rb +1 -1
  31. data/lib/dependabot.rb +1 -1
  32. metadata +4 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6e3dfe956941c85f2831b149fa443058ce3165f68890a9cc2f8a47f171cf76cf
4
- data.tar.gz: 1e02a3d9fbcb515af27fe62656748dcf14394707a71d2d2ca78e2f4c5323142b
3
+ metadata.gz: 4c66b8233da2a6599d23a5c9a0db612e4225e7a1ef54aad500fd8861e9a98273
4
+ data.tar.gz: 682b44c5d4ec337dd4a29a80f029e1e84869b9434aea2619969b5079aecac51c
5
5
  SHA512:
6
- metadata.gz: 1d14e15ab94001ea6a2aa5625b23a0db71b13a3f533aca335d6f4a6035fdb14fb1b1600bd38628b5f41919883a4fc20754ccd329e0167c936a4fc68bc7b1031e
7
- data.tar.gz: d31623ce8db6226701b3a4c8c5a49c2b5805d0c9e8723decdf15d275c87f5d6c519ca2add01ea796a607345ceebe498dbe71f4ad80310e916ef04e394748c8ae
6
+ metadata.gz: 9e5c58e16b97382100d7b9b72dcc85ed38d48b8df82a9a1135d72ecda5deab0182a333a4e4ddbb1840b3d2b73c8cf36d3555c5a89af4bf780b76998fabc36404
7
+ data.tar.gz: 65b24a2eb7ab108af968ccfde8934e74e5a1bf584af8b517df75a369b48a515a3011c2c2e4392ffb57f6848b800d83c2eea82dac6d9820fa1bd45ec4b56af166
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "dependabot/shared_helpers"
@@ -7,6 +7,7 @@ require "sorbet-runtime"
7
7
 
8
8
  module Dependabot
9
9
  module Clients
10
+ # rubocop:disable Metrics/ClassLength
10
11
  class Azure
11
12
  extend T::Sig
12
13
 
@@ -24,12 +25,16 @@ module Dependabot
24
25
 
25
26
  class TagsCreationForbidden < StandardError; end
26
27
 
27
- RETRYABLE_ERRORS = [InternalServerError, BadGateway, ServiceNotAvailable].freeze
28
+ RETRYABLE_ERRORS = T.let(
29
+ [InternalServerError, BadGateway, ServiceNotAvailable].freeze,
30
+ T::Array[T.class_of(StandardError)]
31
+ )
28
32
 
29
33
  #######################
30
34
  # Constructor methods #
31
35
  #######################
32
36
 
37
+ sig { params(source: Dependabot::Source, credentials: T::Array[Dependabot::Credential]).returns(Azure) }
33
38
  def self.for_source(source:, credentials:)
34
39
  credential =
35
40
  credentials
@@ -43,15 +48,24 @@ module Dependabot
43
48
  # Client #
44
49
  ##########
45
50
 
51
+ sig do
52
+ params(
53
+ source: Dependabot::Source,
54
+ credentials: T.nilable(Dependabot::Credential),
55
+ max_retries: T.nilable(Integer)
56
+ )
57
+ .void
58
+ end
46
59
  def initialize(source, credentials, max_retries: 3)
47
60
  @source = source
48
61
  @credentials = credentials
49
- @auth_header = auth_header_for(credentials&.fetch("token", nil))
50
- @max_retries = max_retries || 3
62
+ @auth_header = T.let(auth_header_for(credentials&.fetch("token", nil)), T::Hash[String, String])
63
+ @max_retries = T.let(max_retries || 3, Integer)
51
64
  end
52
65
 
66
+ sig { params(_repo: T.nilable(String), branch: String).returns(String) }
53
67
  def fetch_commit(_repo, branch)
54
- response = get(source.api_endpoint +
68
+ response = get(T.must(source.api_endpoint) +
55
69
  source.organization + "/" + source.project +
56
70
  "/_apis/git/repositories/" + source.unscoped_repo +
57
71
  "/stats/branches?name=" + branch)
@@ -61,18 +75,26 @@ module Dependabot
61
75
  JSON.parse(response.body).fetch("commit").fetch("commitId")
62
76
  end
63
77
 
78
+ sig { params(_repo: String).returns(String) }
64
79
  def fetch_default_branch(_repo)
65
- response = get(source.api_endpoint +
80
+ response = get(T.must(source.api_endpoint) +
66
81
  source.organization + "/" + source.project +
67
82
  "/_apis/git/repositories/" + source.unscoped_repo)
68
83
 
69
84
  JSON.parse(response.body).fetch("defaultBranch").gsub("refs/heads/", "")
70
85
  end
71
86
 
87
+ sig do
88
+ params(
89
+ commit: T.nilable(String),
90
+ path: T.nilable(String)
91
+ )
92
+ .returns(T::Array[T::Hash[String, T.untyped]])
93
+ end
72
94
  def fetch_repo_contents(commit = nil, path = nil)
73
95
  tree = fetch_repo_contents_treeroot(commit, path)
74
96
 
75
- response = get(source.api_endpoint +
97
+ response = get(T.must(source.api_endpoint) +
76
98
  source.organization + "/" + source.project +
77
99
  "/_apis/git/repositories/" + source.unscoped_repo +
78
100
  "/trees/" + tree + "?recursive=false")
@@ -80,18 +102,19 @@ module Dependabot
80
102
  JSON.parse(response.body).fetch("treeEntries")
81
103
  end
82
104
 
105
+ sig { params(commit: T.nilable(String), path: T.nilable(String)).returns(String) }
83
106
  def fetch_repo_contents_treeroot(commit = nil, path = nil)
84
107
  actual_path = path
85
108
  actual_path = "/" if path.to_s.empty?
86
109
 
87
- tree_url = source.api_endpoint +
110
+ tree_url = T.must(source.api_endpoint) +
88
111
  source.organization + "/" + source.project +
89
112
  "/_apis/git/repositories/" + source.unscoped_repo +
90
- "/items?path=" + actual_path
113
+ "/items?path=" + T.must(actual_path)
91
114
 
92
115
  unless commit.to_s.empty?
93
116
  tree_url += "&versionDescriptor.versionType=commit" \
94
- "&versionDescriptor.version=" + commit
117
+ "&versionDescriptor.version=" + T.must(commit)
95
118
  end
96
119
 
97
120
  tree_response = get(tree_url)
@@ -99,8 +122,9 @@ module Dependabot
99
122
  JSON.parse(tree_response.body).fetch("objectId")
100
123
  end
101
124
 
125
+ sig { params(commit: String, path: String).returns(String) }
102
126
  def fetch_file_contents(commit, path)
103
- response = get(source.api_endpoint +
127
+ response = get(T.must(source.api_endpoint) +
104
128
  source.organization + "/" + source.project +
105
129
  "/_apis/git/repositories/" + source.unscoped_repo +
106
130
  "/items?path=" + path +
@@ -110,21 +134,23 @@ module Dependabot
110
134
  response.body
111
135
  end
112
136
 
137
+ sig { params(branch_name: T.nilable(String)).returns(T::Array[T::Hash[String, T.untyped]]) }
113
138
  def commits(branch_name = nil)
114
- commits_url = source.api_endpoint +
139
+ commits_url = T.must(source.api_endpoint) +
115
140
  source.organization + "/" + source.project +
116
141
  "/_apis/git/repositories/" + source.unscoped_repo +
117
142
  "/commits"
118
143
 
119
- commits_url += "?searchCriteria.itemVersion.version=" + branch_name unless branch_name.to_s.empty?
144
+ commits_url += "?searchCriteria.itemVersion.version=" + T.must(branch_name) unless branch_name.to_s.empty?
120
145
 
121
146
  response = get(commits_url)
122
147
 
123
148
  JSON.parse(response.body).fetch("value")
124
149
  end
125
150
 
151
+ sig { params(branch_name: String).returns(T.nilable(T::Hash[String, T.untyped])) }
126
152
  def branch(branch_name)
127
- response = get(source.api_endpoint +
153
+ response = get(T.must(source.api_endpoint) +
128
154
  source.organization + "/" + source.project +
129
155
  "/_apis/git/repositories/" + source.unscoped_repo +
130
156
  "/refs?filter=heads/" + branch_name)
@@ -132,8 +158,9 @@ module Dependabot
132
158
  JSON.parse(response.body).fetch("value").first
133
159
  end
134
160
 
161
+ sig { params(source_branch: String, target_branch: String).returns(T::Array[T::Hash[String, T.untyped]]) }
135
162
  def pull_requests(source_branch, target_branch)
136
- response = get(source.api_endpoint +
163
+ response = get(T.must(source.api_endpoint) +
137
164
  source.organization + "/" + source.project +
138
165
  "/_apis/git/repositories/" + source.unscoped_repo +
139
166
  "/pullrequests?searchCriteria.status=all" \
@@ -143,6 +170,16 @@ module Dependabot
143
170
  JSON.parse(response.body).fetch("value")
144
171
  end
145
172
 
173
+ sig do
174
+ params(
175
+ branch_name: String,
176
+ base_commit: String,
177
+ commit_message: String,
178
+ files: T::Array[Dependabot::DependencyFile],
179
+ author_details: T.nilable(T::Hash[String, String])
180
+ )
181
+ .returns(T.untyped)
182
+ end
146
183
  def create_commit(branch_name, base_commit, commit_message, files,
147
184
  author_details)
148
185
  content = {
@@ -158,7 +195,7 @@ module Dependabot
158
195
  changeType: "edit",
159
196
  item: { path: file.path },
160
197
  newContent: {
161
- content: Base64.encode64(file.content),
198
+ content: Base64.encode64(T.must(file.content)),
162
199
  contentType: "base64encoded"
163
200
  }
164
201
  }
@@ -167,12 +204,25 @@ module Dependabot
167
204
  ]
168
205
  }
169
206
 
170
- post(source.api_endpoint + source.organization + "/" + source.project +
207
+ post(T.must(source.api_endpoint) + source.organization + "/" + source.project +
171
208
  "/_apis/git/repositories/" + source.unscoped_repo +
172
209
  "/pushes?api-version=5.0", content.to_json)
173
210
  end
174
211
 
175
212
  # rubocop:disable Metrics/ParameterLists
213
+ sig do
214
+ params(
215
+ pr_name: String,
216
+ source_branch: String,
217
+ target_branch: String,
218
+ pr_description: String,
219
+ labels: T::Array[String],
220
+ reviewers: T.nilable(T::Array[String]),
221
+ assignees: T.nilable(T::Array[String]),
222
+ work_item: T.nilable(Integer)
223
+ )
224
+ .returns(T.untyped)
225
+ end
176
226
  def create_pull_request(pr_name, source_branch, target_branch,
177
227
  pr_description, labels,
178
228
  reviewers = nil, assignees = nil, work_item = nil)
@@ -187,12 +237,25 @@ module Dependabot
187
237
  workItemRefs: [{ id: work_item }]
188
238
  }
189
239
 
190
- post(source.api_endpoint +
240
+ post(T.must(source.api_endpoint) +
191
241
  source.organization + "/" + source.project +
192
242
  "/_apis/git/repositories/" + source.unscoped_repo +
193
243
  "/pullrequests?api-version=5.0", content.to_json)
194
244
  end
195
245
 
246
+ sig do
247
+ params(
248
+ pull_request_id: Integer,
249
+ auto_complete_set_by: String,
250
+ merge_commit_message: String,
251
+ delete_source_branch: T::Boolean,
252
+ squash_merge: T::Boolean,
253
+ merge_strategy: String,
254
+ trans_work_items: T::Boolean,
255
+ ignore_config_ids: T::Array[String]
256
+ )
257
+ .returns(T.untyped)
258
+ end
196
259
  def autocomplete_pull_request(pull_request_id, auto_complete_set_by, merge_commit_message,
197
260
  delete_source_branch = true, squash_merge = true, merge_strategy = "squash",
198
261
  trans_work_items = true, ignore_config_ids = [])
@@ -211,7 +274,7 @@ module Dependabot
211
274
  }
212
275
  }
213
276
 
214
- response = patch(source.api_endpoint +
277
+ response = patch(T.must(source.api_endpoint) +
215
278
  source.organization + "/" + source.project +
216
279
  "/_apis/git/repositories/" + source.unscoped_repo +
217
280
  "/pullrequests/" + pull_request_id.to_s + "?api-version=5.1", content.to_json)
@@ -219,14 +282,16 @@ module Dependabot
219
282
  JSON.parse(response.body)
220
283
  end
221
284
 
285
+ sig { params(pull_request_id: String).returns(T::Hash[String, T.untyped]) }
222
286
  def pull_request(pull_request_id)
223
- response = get(source.api_endpoint +
287
+ response = get(T.must(source.api_endpoint) +
224
288
  source.organization + "/" + source.project +
225
289
  "/_apis/git/pullrequests/" + pull_request_id)
226
290
 
227
291
  JSON.parse(response.body)
228
292
  end
229
293
 
294
+ sig { params(branch_name: String, old_commit: String, new_commit: String).returns(T::Hash[String, T.untyped]) }
230
295
  def update_ref(branch_name, old_commit, new_commit)
231
296
  content = [
232
297
  {
@@ -236,7 +301,7 @@ module Dependabot
236
301
  }
237
302
  ]
238
303
 
239
- response = post(source.api_endpoint + source.organization + "/" + source.project +
304
+ response = post(T.must(source.api_endpoint) + source.organization + "/" + source.project +
240
305
  "/_apis/git/repositories/" + source.unscoped_repo +
241
306
  "/refs?api-version=5.0", content.to_json)
242
307
 
@@ -244,8 +309,15 @@ module Dependabot
244
309
  end
245
310
  # rubocop:enable Metrics/ParameterLists
246
311
 
312
+ sig do
313
+ params(
314
+ previous_tag: T.nilable(String), new_tag: T.nilable(String),
315
+ type: String
316
+ )
317
+ .returns(T::Array[T::Hash[String, T.untyped]])
318
+ end
247
319
  def compare(previous_tag, new_tag, type)
248
- response = get(source.api_endpoint +
320
+ response = get(T.must(source.api_endpoint) +
249
321
  source.organization + "/" + source.project +
250
322
  "/_apis/git/repositories/" + source.unscoped_repo +
251
323
  "/commits?searchCriteria.itemVersion.versionType=#{type}" \
@@ -311,7 +383,7 @@ module Dependabot
311
383
  raise Unauthorized if response&.status == 401
312
384
 
313
385
  if response&.status == 403
314
- raise TagsCreationForbidden if tags_creation_forbidden?(response)
386
+ raise TagsCreationForbidden if tags_creation_forbidden?(T.must(response))
315
387
 
316
388
  raise Forbidden
317
389
  end
@@ -354,7 +426,8 @@ module Dependabot
354
426
 
355
427
  private
356
428
 
357
- def retry_connection_failures
429
+ sig { params(blk: T.proc.void).void }
430
+ def retry_connection_failures(&blk) # rubocop:disable Lint/UnusedMethodArgument
358
431
  retry_attempt = 0
359
432
 
360
433
  begin
@@ -365,6 +438,7 @@ module Dependabot
365
438
  end
366
439
  end
367
440
 
441
+ sig { params(token: T.nilable(String)).returns(T::Hash[String, String]) }
368
442
  def auth_header_for(token)
369
443
  return {} unless token
370
444
 
@@ -379,6 +453,7 @@ module Dependabot
379
453
  end
380
454
  end
381
455
 
456
+ sig { params(response: Excon::Response).returns(T::Boolean) }
382
457
  def tags_creation_forbidden?(response)
383
458
  return false if response.body.empty?
384
459
 
@@ -386,6 +461,13 @@ module Dependabot
386
461
  message&.include?("TF401289")
387
462
  end
388
463
 
464
+ sig do
465
+ params(
466
+ reviewers: T.nilable(T::Array[String]),
467
+ assignees: T.nilable(T::Array[String])
468
+ )
469
+ .returns(T::Array[T::Hash[Symbol, T.untyped]])
470
+ end
389
471
  def pr_reviewers(reviewers, assignees)
390
472
  return [] unless reviewers || assignees
391
473
 
@@ -393,9 +475,15 @@ module Dependabot
393
475
  pr_reviewers + (assignees&.map { |r_id| { id: r_id, isRequired: false } } || [])
394
476
  end
395
477
 
478
+ sig { returns(T::Hash[String, String]) }
396
479
  attr_reader :auth_header
480
+
481
+ sig { returns(T.nilable(Dependabot::Credential)) }
397
482
  attr_reader :credentials
483
+
484
+ sig { returns(Dependabot::Source) }
398
485
  attr_reader :source
399
486
  end
487
+ # rubocop:enable Metrics/ClassLength
400
488
  end
401
489
  end
@@ -282,7 +282,7 @@ module Dependabot
282
282
  #
283
283
  # With POST (for endpoints that provide POST methods for long query parameters)
284
284
  # response = post(url, body)
285
- # first_page = JSON.parse(repsonse.body)
285
+ # first_page = JSON.parse(response.body)
286
286
  # paginate(first_page)
287
287
  def paginate(page)
288
288
  Enumerator.new do |yielder|
@@ -0,0 +1,40 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Dependabot
7
+ class Credential
8
+ extend T::Sig
9
+ extend Forwardable
10
+
11
+ def_delegators :@credential, :fetch, :keys, :[]=, :delete, :slice, :values, :entries
12
+
13
+ sig { params(credential: T::Hash[String, T.any(T::Boolean, String)]).void }
14
+ def initialize(credential)
15
+ @replaces_base = T.let(credential["replaces-base"] == true, T::Boolean)
16
+ credential.delete("replaces-base")
17
+ @credential = T.let(T.unsafe(credential), T::Hash[String, String])
18
+ end
19
+
20
+ sig { returns(T::Boolean) }
21
+ def replaces_base?
22
+ @replaces_base
23
+ end
24
+
25
+ sig { params(key: String).returns(T.nilable(String)) }
26
+ def [](key)
27
+ @credential[key]
28
+ end
29
+
30
+ sig { params(other: Credential).returns(Credential) }
31
+ def merge(other)
32
+ Credential.new(@credential.merge(other.to_h))
33
+ end
34
+
35
+ sig { returns(T::Hash[String, String]) }
36
+ def to_h
37
+ @credential
38
+ end
39
+ end
40
+ end
@@ -22,15 +22,21 @@ module Dependabot
22
22
  sig { returns(T::Array[Dependabot::Dependency]) }
23
23
  attr_reader :dependencies
24
24
 
25
+ sig { returns(String) }
26
+ attr_reader :applies_to
27
+
25
28
  sig do
26
29
  params(
27
30
  name: String,
28
- rules: T::Hash[String, T.untyped]
31
+ rules: T::Hash[String, T.untyped],
32
+ applies_to: T.nilable(String)
29
33
  )
30
34
  .void
31
35
  end
32
- def initialize(name:, rules:)
36
+ def initialize(name:, rules:, applies_to: "version-updates")
33
37
  @name = name
38
+ # For backwards compatibility, if no applies_to is provided, default to "version-updates"
39
+ @applies_to = T.let(applies_to || "version-updates", String)
34
40
  @rules = rules
35
41
  @dependencies = T.let([], T::Array[Dependabot::Dependency])
36
42
  end
@@ -7,6 +7,7 @@ require "dependabot/config"
7
7
  require "dependabot/dependency_file"
8
8
  require "dependabot/source"
9
9
  require "dependabot/errors"
10
+ require "dependabot/credential"
10
11
  require "dependabot/clients/azure"
11
12
  require "dependabot/clients/codecommit"
12
13
  require "dependabot/clients/github_with_retries"
@@ -26,7 +27,7 @@ module Dependabot
26
27
  sig { returns(Dependabot::Source) }
27
28
  attr_reader :source
28
29
 
29
- sig { returns(T::Array[T::Hash[String, String]]) }
30
+ sig { returns(T::Array[Dependabot::Credential]) }
30
31
  attr_reader :credentials
31
32
 
32
33
  sig { returns(T.nilable(String)) }
@@ -51,6 +52,24 @@ module Dependabot
51
52
  GIT_SUBMODULE_CLONE_ERROR =
52
53
  /^fatal: clone of '(?<url>.*)' into submodule path '.*' failed$/
53
54
  GIT_SUBMODULE_ERROR_REGEX = /(#{GIT_SUBMODULE_INACCESSIBLE_ERROR})|(#{GIT_SUBMODULE_CLONE_ERROR})/
55
+ GIT_RETRYABLE_ERRORS =
56
+ T.let(
57
+ [
58
+ /remote error: Internal Server Error/,
59
+ /fatal: Couldn\'t find remote ref/,
60
+ %r{git fetch_pack: expected ACK/NAK, got},
61
+ /protocol error: bad pack header/,
62
+ /The remote end hung up unexpectedly/,
63
+ /TLS packet with unexpected length was received/,
64
+ /RPC failed; result=\d+, HTTP code = \d+/,
65
+ /Connection timed out/,
66
+ /Connection reset by peer/,
67
+ /Unable to look up/,
68
+ /Couldn\'t resolve host/,
69
+ /The requested URL returned error: (429|5\d{2})/
70
+ ].freeze,
71
+ T::Array[Regexp]
72
+ )
54
73
 
55
74
  sig { overridable.params(filenames: T::Array[String]).returns(T::Boolean) }
56
75
  def self.required_files_in?(filenames)
@@ -76,7 +95,7 @@ module Dependabot
76
95
  sig do
77
96
  params(
78
97
  source: Dependabot::Source,
79
- credentials: T::Array[T::Hash[String, String]],
98
+ credentials: T::Array[Dependabot::Credential],
80
99
  repo_contents_path: T.nilable(String),
81
100
  options: T::Hash[String, String]
82
101
  )
@@ -500,7 +519,7 @@ module Dependabot
500
519
  repo_path = File.join(clone_repo_contents, relative_path)
501
520
  return [] unless Dir.exist?(repo_path)
502
521
 
503
- Dir.entries(repo_path).filter_map do |name|
522
+ Dir.entries(repo_path).sort.filter_map do |name|
504
523
  next if name == "." || name == ".."
505
524
 
506
525
  absolute_path = File.join(repo_path, name)
@@ -757,6 +776,7 @@ module Dependabot
757
776
  # rubocop:disable Metrics/MethodLength
758
777
  # rubocop:disable Metrics/PerceivedComplexity
759
778
  # rubocop:disable Metrics/BlockLength
779
+ # rubocop:disable Metrics/CyclomaticComplexity
760
780
  sig { params(target_directory: T.nilable(String)).returns(String) }
761
781
  def _clone_repo_contents(target_directory:)
762
782
  SharedHelpers.with_git_configured(credentials: credentials) do
@@ -777,6 +797,7 @@ module Dependabot
777
797
  clone_options << " --branch #{source.branch} --single-branch" if source.branch
778
798
 
779
799
  submodule_cloning_failed = false
800
+ retries = 0
780
801
  begin
781
802
  SharedHelpers.run_shell_command(
782
803
  <<~CMD
@@ -786,6 +807,16 @@ module Dependabot
786
807
 
787
808
  @submodules = find_submodules(path) if recurse_submodules_when_cloning?
788
809
  rescue SharedHelpers::HelperSubprocessFailed => e
810
+ if GIT_RETRYABLE_ERRORS.any? { |error| error.match?(e.message) } && retries < 5
811
+ retries += 1
812
+ # 3, 6, 12, 24, 48, ...
813
+ sleep_seconds = (2 ^ (retries - 1)) * 3
814
+ Dependabot.logger.warn(
815
+ "Failed to clone repo #{source.url} due to #{e.message}. Retrying in #{sleep_seconds} seconds..."
816
+ )
817
+ sleep(sleep_seconds)
818
+ retry
819
+ end
789
820
  raise unless e.message.match(GIT_SUBMODULE_ERROR_REGEX) && e.message.downcase.include?("submodule")
790
821
 
791
822
  submodule_cloning_failed = true
@@ -831,6 +862,7 @@ module Dependabot
831
862
  # rubocop:enable Metrics/MethodLength
832
863
  # rubocop:enable Metrics/PerceivedComplexity
833
864
  # rubocop:enable Metrics/BlockLength
865
+ # rubocop:enable Metrics/CyclomaticComplexity
834
866
 
835
867
  sig { params(str: String).returns(String) }
836
868
  def decode_binary_string(str)
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "sorbet-runtime"
5
+ require "dependabot/credential"
5
6
 
6
7
  module Dependabot
7
8
  module FileParsers
@@ -17,7 +18,7 @@ module Dependabot
17
18
  sig { returns(T.nilable(String)) }
18
19
  attr_reader :repo_contents_path
19
20
 
20
- sig { returns(T::Array[T::Hash[String, String]]) }
21
+ sig { returns(T::Array[Dependabot::Credential]) }
21
22
  attr_reader :credentials
22
23
 
23
24
  sig { returns(T.nilable(Dependabot::Source)) }
@@ -31,7 +32,7 @@ module Dependabot
31
32
  dependency_files: T::Array[Dependabot::DependencyFile],
32
33
  source: T.nilable(Dependabot::Source),
33
34
  repo_contents_path: T.nilable(String),
34
- credentials: T::Array[T::Hash[String, String]],
35
+ credentials: T::Array[Dependabot::Credential],
35
36
  reject_external_code: T::Boolean,
36
37
  options: T::Hash[Symbol, T.untyped]
37
38
  )
@@ -49,7 +50,7 @@ module Dependabot
49
50
  check_required_files
50
51
  end
51
52
 
52
- sig { abstract.returns(Dependabot::DependencyFile) }
53
+ sig { abstract.returns(T::Array[Dependabot::Dependency]) }
53
54
  def parse; end
54
55
 
55
56
  private
@@ -4,7 +4,7 @@
4
4
  require "sorbet-runtime"
5
5
  require "dependabot/dependency_file"
6
6
 
7
- # This class provides a utility to check for arbitary modified files within a
7
+ # This class provides a utility to check for arbitrary modified files within a
8
8
  # git directory that need to be wrapped as Dependabot::DependencyFile object
9
9
  # and returned as along with anything managed by the FileUpdater itself.
10
10
  module Dependabot
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "sorbet-runtime"
5
+ require "dependabot/credential"
5
6
 
6
7
  module Dependabot
7
8
  module FileUpdaters
@@ -19,13 +20,13 @@ module Dependabot
19
20
  sig { returns(T.nilable(String)) }
20
21
  attr_reader :repo_contents_path
21
22
 
22
- sig { returns(T::Array[T::Hash[String, String]]) }
23
+ sig { returns(T::Array[Dependabot::Credential]) }
23
24
  attr_reader :credentials
24
25
 
25
26
  sig { returns(T::Hash[Symbol, T.untyped]) }
26
27
  attr_reader :options
27
28
 
28
- sig { overridable.returns(String) }
29
+ sig { overridable.returns(T::Array[Regexp]) }
29
30
  def self.updated_files_regex
30
31
  raise NotImplementedError
31
32
  end
@@ -34,7 +35,7 @@ module Dependabot
34
35
  params(
35
36
  dependencies: T::Array[Dependabot::Dependency],
36
37
  dependency_files: T::Array[Dependabot::DependencyFile],
37
- credentials: T::Array[T::Hash[String, String]],
38
+ credentials: T::Array[Dependabot::Credential],
38
39
  repo_contents_path: T.nilable(String),
39
40
  options: T::Hash[Symbol, T.untyped]
40
41
  ).void
@@ -17,7 +17,7 @@ module Dependabot
17
17
  extend T::Sig
18
18
  extend T::Helpers
19
19
 
20
- # This provides backwards compatability for anyone who used this class
20
+ # This provides backwards compatibility for anyone who used this class
21
21
  # before the base ArtifactUpdater class was introduced and aligns the
22
22
  # method's public signatures with it's special-case domain.
23
23
  sig { params(repo_contents_path: T.nilable(String), vendor_dir: T.nilable(String)).void }
@@ -12,6 +12,7 @@ require "dependabot/errors"
12
12
  require "dependabot/utils"
13
13
  require "dependabot/source"
14
14
  require "dependabot/dependency"
15
+ require "dependabot/credential"
15
16
  require "dependabot/git_metadata_fetcher"
16
17
  module Dependabot
17
18
  # rubocop:disable Metrics/ClassLength
@@ -29,7 +30,7 @@ module Dependabot
29
30
  sig do
30
31
  params(
31
32
  dependency: Dependabot::Dependency,
32
- credentials: T::Array[T::Hash[String, String]],
33
+ credentials: T::Array[Dependabot::Credential],
33
34
  ignored_versions: T::Array[String],
34
35
  raise_on_ignored: T::Boolean,
35
36
  consider_version_branches_pinned: T::Boolean,
@@ -226,7 +227,7 @@ module Dependabot
226
227
  sig { returns(Dependabot::Dependency) }
227
228
  attr_reader :dependency
228
229
 
229
- sig { returns(T::Array[T::Hash[String, String]]) }
230
+ sig { returns(T::Array[Dependabot::Credential]) }
230
231
  attr_reader :credentials
231
232
 
232
233
  sig { returns(T::Array[String]) }
@@ -7,6 +7,7 @@ require "sorbet-runtime"
7
7
 
8
8
  require "dependabot/errors"
9
9
  require "dependabot/git_ref"
10
+ require "dependabot/credential"
10
11
 
11
12
  module Dependabot
12
13
  class GitMetadataFetcher
@@ -17,7 +18,7 @@ module Dependabot
17
18
  sig do
18
19
  params(
19
20
  url: String,
20
- credentials: T::Array[T::Hash[String, String]]
21
+ credentials: T::Array[Dependabot::Credential]
21
22
  )
22
23
  .void
23
24
  end
@@ -97,7 +98,7 @@ module Dependabot
97
98
  sig { returns(String) }
98
99
  attr_reader :url
99
100
 
100
- sig { returns(T::Array[T::Hash[String, String]]) }
101
+ sig { returns(T::Array[Dependabot::Credential]) }
101
102
  attr_reader :credentials
102
103
 
103
104
  sig { params(uri: String).returns(String) }