dependabot-common 0.245.0 → 0.247.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/dependabot/clients/bitbucket.rb +113 -5
  3. data/lib/dependabot/clients/codecommit.rb +107 -12
  4. data/lib/dependabot/clients/github_with_retries.rb +61 -19
  5. data/lib/dependabot/clients/gitlab_with_retries.rb +60 -7
  6. data/lib/dependabot/dependency.rb +1 -1
  7. data/lib/dependabot/errors.rb +20 -2
  8. data/lib/dependabot/file_fetchers/base.rb +8 -19
  9. data/lib/dependabot/file_updaters/base.rb +2 -0
  10. data/lib/dependabot/git_commit_checker.rb +3 -2
  11. data/lib/dependabot/metadata_finders/base/changelog_finder.rb +1 -1
  12. data/lib/dependabot/metadata_finders/base/commits_finder.rb +1 -1
  13. data/lib/dependabot/metadata_finders/base/release_finder.rb +1 -1
  14. data/lib/dependabot/pull_request_creator/azure.rb +80 -9
  15. data/lib/dependabot/pull_request_creator/bitbucket.rb +73 -9
  16. data/lib/dependabot/pull_request_creator/branch_namer/solo_strategy.rb +1 -1
  17. data/lib/dependabot/pull_request_creator/codecommit.rb +96 -25
  18. data/lib/dependabot/pull_request_creator/github.rb +162 -49
  19. data/lib/dependabot/pull_request_creator/gitlab.rb +109 -21
  20. data/lib/dependabot/pull_request_creator/message_builder/issue_linker.rb +13 -4
  21. data/lib/dependabot/pull_request_creator/message_builder.rb +246 -89
  22. data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +11 -9
  23. data/lib/dependabot/pull_request_creator.rb +32 -27
  24. data/lib/dependabot/pull_request_updater/azure.rb +75 -11
  25. data/lib/dependabot/pull_request_updater/github.rb +89 -28
  26. data/lib/dependabot/pull_request_updater/gitlab.rb +61 -12
  27. data/lib/dependabot/pull_request_updater.rb +1 -1
  28. data/lib/dependabot/registry_client.rb +2 -2
  29. data/lib/dependabot/requirements_update_strategy.rb +13 -0
  30. data/lib/dependabot/update_checkers/base.rb +123 -32
  31. data/lib/dependabot/update_checkers/version_filters.rb +15 -5
  32. data/lib/dependabot/version.rb +6 -43
  33. data/lib/dependabot.rb +1 -1
  34. metadata +18 -3
@@ -1,12 +1,20 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "gitlab"
5
+ require "sorbet-runtime"
6
+
7
+ require "dependabot/credential"
5
8
 
6
9
  module Dependabot
7
10
  module Clients
8
11
  class GitlabWithRetries
9
- RETRYABLE_ERRORS = [Gitlab::Error::BadGateway].freeze
12
+ extend T::Sig
13
+
14
+ RETRYABLE_ERRORS = T.let(
15
+ [Gitlab::Error::BadGateway].freeze,
16
+ T::Array[T.class_of(Gitlab::Error::ResponseError)]
17
+ )
10
18
 
11
19
  class ContentEncoding
12
20
  BASE64 = "base64"
@@ -17,6 +25,13 @@ module Dependabot
17
25
  # Constructor methods #
18
26
  #######################
19
27
 
28
+ sig do
29
+ params(
30
+ source: Dependabot::Source,
31
+ credentials: T::Array[Dependabot::Credential]
32
+ )
33
+ .returns(Dependabot::Clients::GitlabWithRetries)
34
+ end
20
35
  def self.for_source(source:, credentials:)
21
36
  access_token =
22
37
  credentials
@@ -31,6 +46,7 @@ module Dependabot
31
46
  )
32
47
  end
33
48
 
49
+ sig { params(credentials: T::Array[Dependabot::Credential]).returns(Dependabot::Clients::GitlabWithRetries) }
34
50
  def self.for_gitlab_dot_com(credentials:)
35
51
  access_token =
36
52
  credentials
@@ -49,10 +65,12 @@ module Dependabot
49
65
  # VCS Interface #
50
66
  #################
51
67
 
68
+ sig { params(repo: String, branch: String).returns(String) }
52
69
  def fetch_commit(repo, branch)
53
70
  T.unsafe(self).branch(repo, branch).commit.id
54
71
  end
55
72
 
73
+ sig { params(repo: String).returns(String) }
56
74
  def fetch_default_branch(repo)
57
75
  T.unsafe(self).project(repo).default_branch
58
76
  end
@@ -61,9 +79,10 @@ module Dependabot
61
79
  # Proxying #
62
80
  ############
63
81
 
82
+ sig { params(max_retries: T.nilable(Integer), args: T.untyped).void }
64
83
  def initialize(max_retries: 3, **args)
65
- @max_retries = max_retries || 3
66
- @client = ::Gitlab::Client.new(args)
84
+ @max_retries = T.let(max_retries || 3, Integer)
85
+ @client = T.let(::Gitlab::Client.new(args), ::Gitlab::Client)
67
86
  end
68
87
 
69
88
  # Create commit in gitlab repo with correctly mapped file actions
@@ -74,32 +93,63 @@ module Dependabot
74
93
  # @param [Array<Dependabot::DependencyFile>] files
75
94
  # @param [Hash] options
76
95
  # @return [Gitlab::ObjectifiedHash]
96
+ sig do
97
+ params(
98
+ repo: String,
99
+ branch_name: String,
100
+ commit_message: String,
101
+ files: T::Array[Dependabot::DependencyFile],
102
+ options: T.untyped
103
+ )
104
+ .returns(Gitlab::ObjectifiedHash)
105
+ end
77
106
  def create_commit(repo, branch_name, commit_message, files, **options)
78
107
  @client.create_commit(
79
108
  repo,
80
109
  branch_name,
81
110
  commit_message,
82
111
  file_actions(files),
83
- **options
112
+ options
84
113
  )
85
114
  end
86
115
 
116
+ # TODO: Create all the methods that are called on the client
117
+ sig do
118
+ params(
119
+ method_name: T.any(Symbol, String),
120
+ args: T.untyped,
121
+ block: T.nilable(T.proc.returns(T.untyped))
122
+ )
123
+ .returns(T.untyped)
124
+ end
87
125
  def method_missing(method_name, *args, &block)
88
126
  retry_connection_failures do
89
127
  if @client.respond_to?(method_name)
90
128
  mutatable_args = args.map(&:dup)
91
- @client.public_send(method_name, *mutatable_args, &block)
129
+ T.unsafe(@client).public_send(method_name, *mutatable_args, &block)
92
130
  else
93
131
  super
94
132
  end
95
133
  end
96
134
  end
97
135
 
136
+ sig do
137
+ params(
138
+ method_name: Symbol,
139
+ include_private: T::Boolean
140
+ )
141
+ .returns(T::Boolean)
142
+ end
98
143
  def respond_to_missing?(method_name, include_private = false)
99
144
  @client.respond_to?(method_name) || super
100
145
  end
101
146
 
102
- def retry_connection_failures
147
+ sig do
148
+ type_parameters(:T)
149
+ .params(_blk: T.proc.returns(T.type_parameter(:T)))
150
+ .returns(T.type_parameter(:T))
151
+ end
152
+ def retry_connection_failures(&_blk)
103
153
  retry_attempt = 0
104
154
 
105
155
  begin
@@ -116,6 +166,7 @@ module Dependabot
116
166
  #
117
167
  # @param [Array<Dependabot::DependencyFile>] files
118
168
  # @return [Array<Hash>]
169
+ sig { params(files: T::Array[Dependabot::DependencyFile]).returns(T::Array[T::Hash[Symbol, T.untyped]]) }
119
170
  def file_actions(files)
120
171
  files.map do |file|
121
172
  {
@@ -131,6 +182,7 @@ module Dependabot
131
182
  #
132
183
  # @param [Dependabot::DependencyFile] file
133
184
  # @return [String]
185
+ sig { params(file: Dependabot::DependencyFile).returns(String) }
134
186
  def file_action(file)
135
187
  if file.operation == Dependabot::DependencyFile::Operation::DELETE
136
188
  "delete"
@@ -145,6 +197,7 @@ module Dependabot
145
197
  #
146
198
  # @param [Dependabot::DependencyFile] file
147
199
  # @return [String]
200
+ sig { params(file: Dependabot::DependencyFile).returns(String) }
148
201
  def file_encoding(file)
149
202
  return ContentEncoding::BASE64 if file.content_encoding == Dependabot::DependencyFile::ContentEncoding::BASE64
150
203
 
@@ -93,7 +93,7 @@ module Dependabot
93
93
  # TODO: Make version a Dependabot::Version everywhere
94
94
  version: T.nilable(T.any(String, Dependabot::Version)),
95
95
  previous_version: T.nilable(String),
96
- previous_requirements: T.nilable(T::Array[T::Hash[String, String]]),
96
+ previous_requirements: T.nilable(T::Array[T::Hash[T.any(Symbol, String), T.untyped]]),
97
97
  subdependency_metadata: T.nilable(T::Array[T::Hash[T.any(Symbol, String), String]]),
98
98
  removed: T::Boolean,
99
99
  metadata: T.nilable(T::Hash[T.any(Symbol, String), String])
@@ -7,6 +7,18 @@ require "dependabot/utils"
7
7
  module Dependabot
8
8
  extend T::Sig
9
9
 
10
+ module ErrorAttributes
11
+ BACKTRACE = "error-backtrace"
12
+ CLASS = "error-class"
13
+ DETAILS = "error-details"
14
+ FINGERPRINT = "fingerprint"
15
+ MESSAGE = "error-message"
16
+ DEPENDENCIES = "job-dependencies"
17
+ DEPENDENCY_GROUPS = "job-dependency-groups"
18
+ JOB_ID = "job-id"
19
+ PACKAGE_MANAGER = "package-manager"
20
+ end
21
+
10
22
  # rubocop:disable Metrics/MethodLength
11
23
  sig { params(error: StandardError).returns(T.nilable(T::Hash[Symbol, T.untyped])) }
12
24
  def self.fetcher_error_details(error)
@@ -48,7 +60,10 @@ module Dependabot
48
60
  when Dependabot::DependencyFileNotFound
49
61
  {
50
62
  "error-type": "dependency_file_not_found",
51
- "error-detail": { "file-path": error.file_path }
63
+ "error-detail": {
64
+ message: error.message,
65
+ "file-path": error.file_path
66
+ }
52
67
  }
53
68
  when Dependabot::OutOfDisk
54
69
  {
@@ -108,7 +123,10 @@ module Dependabot
108
123
  when Dependabot::DependencyFileNotFound
109
124
  {
110
125
  "error-type": "dependency_file_not_found",
111
- "error-detail": { "file-path": error.file_path }
126
+ "error-detail": {
127
+ message: error.message,
128
+ "file-path": error.file_path
129
+ }
112
130
  }
113
131
  when Dependabot::PathDependenciesNotReachable
114
132
  {
@@ -354,11 +354,6 @@ module Dependabot
354
354
  end
355
355
  end
356
356
 
357
- sig { returns(T::Boolean) }
358
- def recurse_submodules_when_cloning?
359
- false
360
- end
361
-
362
357
  sig do
363
358
  returns(
364
359
  T.any(
@@ -776,7 +771,6 @@ module Dependabot
776
771
  # rubocop:disable Metrics/MethodLength
777
772
  # rubocop:disable Metrics/PerceivedComplexity
778
773
  # rubocop:disable Metrics/BlockLength
779
- # rubocop:disable Metrics/CyclomaticComplexity
780
774
  sig { params(target_directory: T.nilable(String)).returns(String) }
781
775
  def _clone_repo_contents(target_directory:)
782
776
  SharedHelpers.with_git_configured(credentials: credentials) do
@@ -789,11 +783,7 @@ module Dependabot
789
783
 
790
784
  clone_options = StringIO.new
791
785
  clone_options << "--no-tags --depth 1"
792
- clone_options << if recurse_submodules_when_cloning?
793
- " --recurse-submodules --shallow-submodules"
794
- else
795
- " --no-recurse-submodules"
796
- end
786
+ clone_options << " --recurse-submodules --shallow-submodules"
797
787
  clone_options << " --branch #{source.branch} --single-branch" if source.branch
798
788
 
799
789
  submodule_cloning_failed = false
@@ -805,7 +795,7 @@ module Dependabot
805
795
  CMD
806
796
  )
807
797
 
808
- @submodules = find_submodules(path) if recurse_submodules_when_cloning?
798
+ @submodules = find_submodules(path)
809
799
  rescue SharedHelpers::HelperSubprocessFailed => e
810
800
  if GIT_RETRYABLE_ERRORS.any? { |error| error.match?(e.message) } && retries < 5
811
801
  retries += 1
@@ -835,20 +825,20 @@ module Dependabot
835
825
  Dir.chdir(path) do
836
826
  fetch_options = StringIO.new
837
827
  fetch_options << "--depth 1"
838
- fetch_options << if recurse_submodules_when_cloning? && !submodule_cloning_failed
839
- " --recurse-submodules=on-demand"
840
- else
828
+ fetch_options << if submodule_cloning_failed
841
829
  " --no-recurse-submodules"
830
+ else
831
+ " --recurse-submodules=on-demand"
842
832
  end
843
833
  # Need to fetch the commit due to the --depth 1 above.
844
834
  SharedHelpers.run_shell_command("git fetch #{fetch_options.string} origin #{source.commit}")
845
835
 
846
836
  reset_options = StringIO.new
847
837
  reset_options << "--hard"
848
- reset_options << if recurse_submodules_when_cloning? && !submodule_cloning_failed
849
- " --recurse-submodules"
850
- else
838
+ reset_options << if submodule_cloning_failed
851
839
  " --no-recurse-submodules"
840
+ else
841
+ " --recurse-submodules"
852
842
  end
853
843
  # Set HEAD to this commit so later calls so git reset HEAD will work.
854
844
  SharedHelpers.run_shell_command("git reset #{reset_options.string} #{source.commit}")
@@ -862,7 +852,6 @@ module Dependabot
862
852
  # rubocop:enable Metrics/MethodLength
863
853
  # rubocop:enable Metrics/PerceivedComplexity
864
854
  # rubocop:enable Metrics/BlockLength
865
- # rubocop:enable Metrics/CyclomaticComplexity
866
855
 
867
856
  sig { params(str: String).returns(String) }
868
857
  def decode_binary_string(str)
@@ -2,6 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "sorbet-runtime"
5
+
5
6
  require "dependabot/credential"
6
7
 
7
8
  module Dependabot
@@ -9,6 +10,7 @@ module Dependabot
9
10
  class Base
10
11
  extend T::Sig
11
12
  extend T::Helpers
13
+
12
14
  abstract!
13
15
 
14
16
  sig { returns(T::Array[Dependabot::Dependency]) }
@@ -367,7 +367,8 @@ module Dependabot
367
367
  client = Clients::GithubWithRetries
368
368
  .for_github_dot_com(credentials: credentials)
369
369
 
370
- client.compare(listing_source_repo, ref1, ref2).status
370
+ # TODO: create this method instead of relying on method_missing
371
+ T.unsafe(client).compare(listing_source_repo, ref1, ref2).status
371
372
  end
372
373
 
373
374
  sig { params(ref1: String, ref2: String).returns(String) }
@@ -375,7 +376,7 @@ module Dependabot
375
376
  client = Clients::GitlabWithRetries
376
377
  .for_gitlab_dot_com(credentials: credentials)
377
378
 
378
- comparison = client.compare(listing_source_repo, ref1, ref2)
379
+ comparison = T.unsafe(client).compare(listing_source_repo, ref1, ref2)
379
380
 
380
381
  if comparison.commits.none? then "behind"
381
382
  elsif comparison.compare_same_ref then "identical"
@@ -460,7 +460,7 @@ module Dependabot
460
460
  def github_client
461
461
  @github_client ||=
462
462
  T.let(
463
- Dependabot::Clients::GithubWithRetries.for_source(source: source, credentials: credentials),
463
+ Dependabot::Clients::GithubWithRetries.for_source(source: T.must(source), credentials: credentials),
464
464
  T.nilable(Dependabot::Clients::GithubWithRetries)
465
465
  )
466
466
  end
@@ -373,7 +373,7 @@ module Dependabot
373
373
  def github_client
374
374
  @github_client ||=
375
375
  T.let(
376
- Dependabot::Clients::GithubWithRetries.for_source(source: source, credentials: credentials),
376
+ Dependabot::Clients::GithubWithRetries.for_source(source: T.must(source), credentials: credentials),
377
377
  T.nilable(Dependabot::Clients::GithubWithRetries)
378
378
  )
379
379
  end
@@ -359,7 +359,7 @@ module Dependabot
359
359
  def github_client
360
360
  @github_client ||=
361
361
  T.let(
362
- Dependabot::Clients::GithubWithRetries.for_source(source: source, credentials: credentials),
362
+ Dependabot::Clients::GithubWithRetries.for_source(source: T.must(source), credentials: credentials),
363
363
  T.nilable(Dependabot::Clients::GithubWithRetries)
364
364
  )
365
365
  end
@@ -1,21 +1,79 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "sorbet-runtime"
5
+
6
+ require "dependabot/credential"
4
7
  require "dependabot/clients/azure"
5
8
  require "dependabot/pull_request_creator"
6
9
 
7
10
  module Dependabot
8
11
  class PullRequestCreator
9
12
  class Azure
10
- attr_reader :source, :branch_name, :base_commit, :credentials,
11
- :files, :commit_message, :pr_description, :pr_name,
12
- :author_details, :labeler, :reviewers, :assignees, :work_item
13
+ extend T::Sig
14
+
15
+ sig { returns(Dependabot::Source) }
16
+ attr_reader :source
17
+
18
+ sig { returns(String) }
19
+ attr_reader :branch_name
20
+
21
+ sig { returns(String) }
22
+ attr_reader :base_commit
23
+
24
+ sig { returns(T::Array[Dependabot::Credential]) }
25
+ attr_reader :credentials
26
+
27
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
28
+ attr_reader :files
29
+
30
+ sig { returns(String) }
31
+ attr_reader :commit_message
32
+
33
+ sig { returns(String) }
34
+ attr_reader :pr_description
35
+
36
+ sig { returns(String) }
37
+ attr_reader :pr_name
38
+
39
+ sig { returns(T.nilable(T::Hash[Symbol, String])) }
40
+ attr_reader :author_details
41
+
42
+ sig { returns(Dependabot::PullRequestCreator::Labeler) }
43
+ attr_reader :labeler
44
+
45
+ sig { returns(T.nilable(T::Array[String])) }
46
+ attr_reader :reviewers
47
+
48
+ sig { returns(T.nilable(T::Array[String])) }
49
+ attr_reader :assignees
50
+
51
+ sig { returns(T.nilable(Integer)) }
52
+ attr_reader :work_item
13
53
 
14
54
  # Azure DevOps limits PR descriptions to a max of 4,000 characters in UTF-16 encoding:
15
55
  # https://developercommunity.visualstudio.com/content/problem/608770/remove-4000-character-limit-on-pull-request-descri.html
16
56
  PR_DESCRIPTION_MAX_LENGTH = 3_999 # 0 based count
17
57
  PR_DESCRIPTION_ENCODING = Encoding::UTF_16
18
58
 
59
+ sig do
60
+ params(
61
+ source: Dependabot::Source,
62
+ branch_name: String,
63
+ base_commit: String,
64
+ credentials: T::Array[Dependabot::Credential],
65
+ files: T::Array[Dependabot::DependencyFile],
66
+ commit_message: String,
67
+ pr_description: String,
68
+ pr_name: String,
69
+ author_details: T.nilable(T::Hash[Symbol, String]),
70
+ labeler: Dependabot::PullRequestCreator::Labeler,
71
+ reviewers: T.nilable(T::Array[String]),
72
+ assignees: T.nilable(T::Array[String]),
73
+ work_item: T.nilable(Integer)
74
+ )
75
+ .void
76
+ end
19
77
  def initialize(source:, branch_name:, base_commit:, credentials:,
20
78
  files:, commit_message:, pr_description:, pr_name:,
21
79
  author_details:, labeler:, reviewers: nil, assignees: nil, work_item: nil)
@@ -34,6 +92,7 @@ module Dependabot
34
92
  @work_item = work_item
35
93
  end
36
94
 
95
+ sig { returns(T.nilable(Excon::Response)) }
37
96
  def create
38
97
  return if branch_exists? && pull_request_exists?
39
98
 
@@ -46,20 +105,26 @@ module Dependabot
46
105
 
47
106
  private
48
107
 
108
+ sig { returns(Dependabot::Clients::Azure) }
49
109
  def azure_client_for_source
50
110
  @azure_client_for_source ||=
51
- Dependabot::Clients::Azure.for_source(
52
- source: source,
53
- credentials: credentials
111
+ T.let(
112
+ Dependabot::Clients::Azure.for_source(
113
+ source: source,
114
+ credentials: credentials
115
+ ),
116
+ T.nilable(Dependabot::Clients::Azure)
54
117
  )
55
118
  end
56
119
 
120
+ sig { returns(T::Boolean) }
57
121
  def branch_exists?
58
- azure_client_for_source.branch(branch_name)
122
+ !azure_client_for_source.branch(branch_name).nil?
59
123
  rescue ::Dependabot::Clients::Azure::NotFound
60
124
  false
61
125
  end
62
126
 
127
+ sig { returns(T::Boolean) }
63
128
  def pull_request_exists?
64
129
  azure_client_for_source.pull_requests(
65
130
  branch_name,
@@ -67,6 +132,7 @@ module Dependabot
67
132
  ).any?
68
133
  end
69
134
 
135
+ sig { void }
70
136
  def create_commit
71
137
  author = author_details&.slice(:name, :email, :date)
72
138
  author = nil unless author&.any?
@@ -80,6 +146,7 @@ module Dependabot
80
146
  )
81
147
  end
82
148
 
149
+ sig { returns(Excon::Response) }
83
150
  def create_pull_request
84
151
  azure_client_for_source.create_pull_request(
85
152
  pr_name,
@@ -93,9 +160,13 @@ module Dependabot
93
160
  )
94
161
  end
95
162
 
163
+ sig { returns(String) }
96
164
  def default_branch
97
165
  @default_branch ||=
98
- azure_client_for_source.fetch_default_branch(source.repo)
166
+ T.let(
167
+ azure_client_for_source.fetch_default_branch(source.repo),
168
+ T.nilable(String)
169
+ )
99
170
  end
100
171
  end
101
172
  end
@@ -1,19 +1,70 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "sorbet-runtime"
5
+
4
6
  require "dependabot/clients/bitbucket"
7
+ require "dependabot/credential"
8
+ require "dependabot/dependency_file"
5
9
  require "dependabot/pull_request_creator"
6
10
 
7
11
  module Dependabot
8
12
  class PullRequestCreator
9
13
  class Bitbucket
10
- attr_reader :source, :branch_name, :base_commit, :credentials,
11
- :files, :commit_message, :pr_description, :pr_name,
12
- :author_details, :labeler, :work_item
14
+ extend T::Sig
15
+
16
+ sig { returns(Dependabot::Source) }
17
+ attr_reader :source
18
+
19
+ sig { returns(String) }
20
+ attr_reader :branch_name
21
+
22
+ sig { returns(String) }
23
+ attr_reader :base_commit
24
+
25
+ sig { returns(T::Array[Dependabot::Credential]) }
26
+ attr_reader :credentials
27
+
28
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
29
+ attr_reader :files
30
+
31
+ sig { returns(String) }
32
+ attr_reader :commit_message
33
+
34
+ sig { returns(String) }
35
+ attr_reader :pr_description
36
+
37
+ sig { returns(String) }
38
+ attr_reader :pr_name
39
+
40
+ sig { returns(T.nilable(T::Hash[Symbol, String])) }
41
+ attr_reader :author_details
42
+
43
+ sig { returns(T.nilable(Dependabot::PullRequestCreator::Labeler)) }
44
+ attr_reader :labeler
45
+
46
+ sig { returns(T.nilable(Integer)) }
47
+ attr_reader :work_item
13
48
 
14
49
  # BitBucket Cloud accepts > 1MB characters, but they display poorly in the UI, so limiting to 4x 65,536
15
50
  PR_DESCRIPTION_MAX_LENGTH = 262_143 # 0 based count
16
51
 
52
+ sig do
53
+ params(
54
+ source: Dependabot::Source,
55
+ branch_name: String,
56
+ base_commit: String,
57
+ credentials: T::Array[Dependabot::Credential],
58
+ files: T::Array[Dependabot::DependencyFile],
59
+ commit_message: String,
60
+ pr_description: String,
61
+ pr_name: String,
62
+ author_details: T.nilable(T::Hash[Symbol, String]),
63
+ labeler: T.nilable(Dependabot::PullRequestCreator::Labeler),
64
+ work_item: T.nilable(Integer)
65
+ )
66
+ .void
67
+ end
17
68
  def initialize(source:, branch_name:, base_commit:, credentials:,
18
69
  files:, commit_message:, pr_description:, pr_name:,
19
70
  author_details:, labeler: nil, work_item: nil)
@@ -30,6 +81,7 @@ module Dependabot
30
81
  @work_item = work_item
31
82
  end
32
83
 
84
+ sig { void }
33
85
  def create
34
86
  return if branch_exists? && pull_request_exists?
35
87
 
@@ -43,20 +95,26 @@ module Dependabot
43
95
 
44
96
  private
45
97
 
98
+ sig { returns(Dependabot::Clients::Bitbucket) }
46
99
  def bitbucket_client_for_source
47
100
  @bitbucket_client_for_source ||=
48
- Dependabot::Clients::Bitbucket.for_source(
49
- source: source,
50
- credentials: credentials
101
+ T.let(
102
+ Dependabot::Clients::Bitbucket.for_source(
103
+ source: source,
104
+ credentials: credentials
105
+ ),
106
+ T.nilable(Dependabot::Clients::Bitbucket)
51
107
  )
52
108
  end
53
109
 
110
+ sig { returns(T::Boolean) }
54
111
  def branch_exists?
55
- bitbucket_client_for_source.branch(source.repo, branch_name)
112
+ !bitbucket_client_for_source.branch(source.repo, branch_name).nil?
56
113
  rescue Clients::Bitbucket::NotFound
57
114
  false
58
115
  end
59
116
 
117
+ sig { returns(T::Boolean) }
60
118
  def pull_request_exists?
61
119
  bitbucket_client_for_source.pull_requests(
62
120
  source.repo,
@@ -65,6 +123,7 @@ module Dependabot
65
123
  ).any?
66
124
  end
67
125
 
126
+ sig { void }
68
127
  def create_commit
69
128
  author = author_details&.slice(:name, :email)
70
129
  author = nil unless author&.any?
@@ -79,6 +138,7 @@ module Dependabot
79
138
  )
80
139
  end
81
140
 
141
+ sig { void }
82
142
  def create_pull_request
83
143
  bitbucket_client_for_source.create_pull_request(
84
144
  source.repo,
@@ -91,9 +151,13 @@ module Dependabot
91
151
  )
92
152
  end
93
153
 
154
+ sig { returns(String) }
94
155
  def default_branch
95
156
  @default_branch ||=
96
- bitbucket_client_for_source.fetch_default_branch(source.repo)
157
+ T.let(
158
+ bitbucket_client_for_source.fetch_default_branch(source.repo),
159
+ T.nilable(String)
160
+ )
97
161
  end
98
162
  end
99
163
  end
@@ -46,7 +46,7 @@ module Dependabot
46
46
  [
47
47
  prefix,
48
48
  package_manager,
49
- T.must(files.first).directory.tr(" ", "-"),
49
+ files.first&.directory&.tr(" ", "-"),
50
50
  target_branch
51
51
  ].compact
52
52
  end