dependabot-common 0.242.1 → 0.243.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.
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) }