dependabot-common 0.235.0 → 0.237.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/azure.rb +3 -3
  3. data/lib/dependabot/config/file.rb +32 -9
  4. data/lib/dependabot/config/file_fetcher.rb +3 -3
  5. data/lib/dependabot/config/ignore_condition.rb +34 -8
  6. data/lib/dependabot/config/update_config.rb +42 -6
  7. data/lib/dependabot/config.rb +1 -1
  8. data/lib/dependabot/dependency_file.rb +89 -14
  9. data/lib/dependabot/dependency_group.rb +29 -5
  10. data/lib/dependabot/errors.rb +101 -13
  11. data/lib/dependabot/file_fetchers/base.rb +250 -93
  12. data/lib/dependabot/file_updaters/artifact_updater.rb +37 -10
  13. data/lib/dependabot/file_updaters/vendor_updater.rb +13 -3
  14. data/lib/dependabot/logger.rb +7 -2
  15. data/lib/dependabot/metadata_finders/base/changelog_finder.rb +13 -6
  16. data/lib/dependabot/pull_request_creator/commit_signer.rb +33 -7
  17. data/lib/dependabot/pull_request_creator/github.rb +13 -10
  18. data/lib/dependabot/pull_request_creator/message.rb +21 -2
  19. data/lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb +37 -16
  20. data/lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb +5 -3
  21. data/lib/dependabot/pull_request_creator/message_builder.rb +5 -18
  22. data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +10 -4
  23. data/lib/dependabot/pull_request_updater/github.rb +2 -2
  24. data/lib/dependabot/shared_helpers.rb +117 -33
  25. data/lib/dependabot/simple_instrumentor.rb +22 -3
  26. data/lib/dependabot/source.rb +65 -17
  27. data/lib/dependabot/update_checkers/version_filters.rb +12 -1
  28. data/lib/dependabot/utils.rb +21 -2
  29. data/lib/dependabot/workspace/base.rb +42 -7
  30. data/lib/dependabot/workspace/change_attempt.rb +31 -3
  31. data/lib/dependabot/workspace/git.rb +34 -4
  32. data/lib/dependabot/workspace.rb +16 -2
  33. data/lib/dependabot.rb +1 -1
  34. metadata +37 -9
@@ -1,6 +1,7 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "sorbet-runtime"
4
5
  require "dependabot/dependency_file"
5
6
 
6
7
  # This class provides a utility to check for arbitary modified files within a
@@ -9,8 +10,12 @@ require "dependabot/dependency_file"
9
10
  module Dependabot
10
11
  module FileUpdaters
11
12
  class ArtifactUpdater
13
+ extend T::Sig
14
+ extend T::Helpers
15
+
12
16
  # @param repo_contents_path [String, nil] the path we cloned the repository into
13
17
  # @param target_directory [String, nil] the path within a project directory we should inspect for changes
18
+ sig { params(repo_contents_path: T.nilable(String), target_directory: T.nilable(String)).void }
14
19
  def initialize(repo_contents_path:, target_directory:)
15
20
  @repo_contents_path = repo_contents_path
16
21
  @target_directory = target_directory
@@ -23,17 +28,24 @@ module Dependabot
23
28
  # @param only_paths [Array<String>, nil] An optional list of specific paths to check, if this is nil we will
24
29
  # return every change we find within the `base_directory`
25
30
  # @return [Array<Dependabot::DependencyFile>]
31
+ sig do
32
+ params(base_directory: String, only_paths: T.nilable(T::Array[String]))
33
+ .returns(T::Array[Dependabot::DependencyFile])
34
+ end
26
35
  def updated_files(base_directory:, only_paths: nil)
27
36
  return [] unless repo_contents_path && target_directory
28
37
 
29
- Dir.chdir(repo_contents_path) do
38
+ Dir.chdir(T.must(repo_contents_path)) do
30
39
  # rubocop:disable Performance/DeletePrefix
31
- relative_dir = Pathname.new(base_directory).sub(%r{\A/}, "").join(target_directory)
40
+ relative_dir = Pathname.new(base_directory).sub(%r{\A/}, "").join(T.must(target_directory))
32
41
  # rubocop:enable Performance/DeletePrefix
33
42
 
34
- status = SharedHelpers.run_shell_command(
35
- "git status --untracked-files all --porcelain v1 #{relative_dir}",
36
- fingerprint: "git status --untracked-files all --porcelain v1 <relative_dir>"
43
+ status = T.let(
44
+ SharedHelpers.run_shell_command(
45
+ "git status --untracked-files all --porcelain v1 #{relative_dir}",
46
+ fingerprint: "git status --untracked-files all --porcelain v1 <relative_dir>"
47
+ ),
48
+ String
37
49
  )
38
50
  changed_paths = status.split("\n").map(&:split)
39
51
  changed_paths.filter_map do |type, path|
@@ -51,7 +63,7 @@ module Dependabot
51
63
  operation = Dependabot::DependencyFile::Operation::DELETE if type == "D"
52
64
  operation = Dependabot::DependencyFile::Operation::CREATE if type == "??"
53
65
 
54
- encoded_content, encoding = get_encoded_file_contents(path, operation)
66
+ encoded_content, encoding = get_encoded_file_contents(T.must(path), operation)
55
67
 
56
68
  create_dependency_file(
57
69
  name: file_path.to_s,
@@ -66,10 +78,19 @@ module Dependabot
66
78
 
67
79
  private
68
80
 
69
- TEXT_ENCODINGS = %w(us-ascii utf-8).freeze
81
+ TEXT_ENCODINGS = T.let(%w(us-ascii utf-8).freeze, T::Array[String])
70
82
 
71
- attr_reader :repo_contents_path, :target_directory
83
+ sig { returns(T.nilable(String)) }
84
+ attr_reader :repo_contents_path
85
+ sig { returns(T.nilable(String)) }
86
+ attr_reader :target_directory
72
87
 
88
+ sig do
89
+ params(
90
+ path: String,
91
+ operation: String
92
+ ).returns([T.nilable(String), String])
93
+ end
73
94
  def get_encoded_file_contents(path, operation)
74
95
  encoded_content = nil
75
96
  encoding = ""
@@ -86,6 +107,7 @@ module Dependabot
86
107
  [encoded_content, encoding]
87
108
  end
88
109
 
110
+ sig { params(path: String).returns(T::Boolean) }
89
111
  def binary_file?(path)
90
112
  return false unless File.exist?(path)
91
113
 
@@ -95,8 +117,13 @@ module Dependabot
95
117
  !TEXT_ENCODINGS.include?(encoding)
96
118
  end
97
119
 
120
+ sig do
121
+ overridable
122
+ .params(parameters: T::Hash[Symbol, T.untyped])
123
+ .returns(Dependabot::DependencyFile)
124
+ end
98
125
  def create_dependency_file(parameters)
99
- Dependabot::DependencyFile.new(**parameters)
126
+ Dependabot::DependencyFile.new(**T.unsafe(parameters))
100
127
  end
101
128
  end
102
129
  end
@@ -1,6 +1,7 @@
1
- # typed: false
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "sorbet-runtime"
4
5
  require "dependabot/dependency_file"
5
6
  require "dependabot/file_updaters/artifact_updater"
6
7
 
@@ -13,21 +14,30 @@ require "dependabot/file_updaters/artifact_updater"
13
14
  module Dependabot
14
15
  module FileUpdaters
15
16
  class VendorUpdater < ArtifactUpdater
17
+ extend T::Sig
18
+ extend T::Helpers
19
+
16
20
  # This provides backwards compatability for anyone who used this class
17
21
  # before the base ArtifactUpdater class was introduced and aligns the
18
22
  # method's public signatures with it's special-case domain.
23
+ sig { params(repo_contents_path: T.nilable(String), vendor_dir: T.nilable(String)).void }
19
24
  def initialize(repo_contents_path:, vendor_dir:)
20
25
  @repo_contents_path = repo_contents_path
21
26
  @vendor_dir = vendor_dir
22
27
  super(repo_contents_path: @repo_contents_path, target_directory: @vendor_dir)
23
28
  end
24
29
 
25
- alias updated_vendor_cache_files updated_files
30
+ T.unsafe(self).alias_method :updated_vendor_cache_files, :updated_files
26
31
 
27
32
  private
28
33
 
34
+ sig do
35
+ override
36
+ .params(parameters: T::Hash[Symbol, T.untyped])
37
+ .returns(Dependabot::DependencyFile)
38
+ end
29
39
  def create_dependency_file(parameters)
30
- Dependabot::DependencyFile.new(**parameters.merge({ vendored_file: true }))
40
+ Dependabot::DependencyFile.new(**T.unsafe({ **parameters.merge({ vendored_file: true }) }))
31
41
  end
32
42
  end
33
43
  end
@@ -1,13 +1,18 @@
1
- # typed: true
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "logger"
5
+ require "sorbet-runtime"
5
6
 
6
7
  module Dependabot
8
+ extend T::Sig
9
+
10
+ sig { returns(::Logger) }
7
11
  def self.logger
8
- @logger ||= Logger.new(nil)
12
+ @logger ||= T.let(::Logger.new(nil), T.nilable(::Logger))
9
13
  end
10
14
 
15
+ sig { params(logger: ::Logger).void }
11
16
  def self.logger=(logger)
12
17
  @logger = logger
13
18
  end
@@ -1,7 +1,8 @@
1
- # typed: false
1
+ # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "excon"
5
+ require "sorbet-runtime"
5
6
 
6
7
  require "dependabot/clients/github_with_retries"
7
8
  require "dependabot/clients/gitlab_with_retries"
@@ -12,6 +13,8 @@ module Dependabot
12
13
  module MetadataFinders
13
14
  class Base
14
15
  class ChangelogFinder
16
+ extend T::Sig
17
+
15
18
  require_relative "changelog_pruner"
16
19
  require_relative "commits_finder"
17
20
 
@@ -86,9 +89,9 @@ module Dependabot
86
89
  suggested_source = Source.from_url(suggested_changelog_url)
87
90
  return unless suggested_source&.provider == "github"
88
91
 
89
- opts = { path: suggested_source.directory, ref: suggested_source.branch }.compact
92
+ opts = { path: suggested_source&.directory, ref: suggested_source&.branch }.compact
90
93
  suggested_source_client = github_client_for_source(suggested_source)
91
- tmp_files = suggested_source_client.contents(suggested_source.repo, opts)
94
+ tmp_files = suggested_source_client.contents(suggested_source&.repo, opts)
92
95
 
93
96
  filename = suggested_changelog_url.split("/").last.split("#").first
94
97
  @changelog_from_suggested_url =
@@ -128,7 +131,10 @@ module Dependabot
128
131
  file = candidates.first if candidates.one?
129
132
  file ||=
130
133
  candidates.find do |f|
131
- candidates -= [f] && next if fetch_file_text(f).nil?
134
+ if fetch_file_text(f).nil?
135
+ candidates -= [f]
136
+ next
137
+ end
132
138
  pruner = ChangelogPruner.new(
133
139
  dependency: dependency,
134
140
  changelog_text: fetch_file_text(f)
@@ -159,11 +165,12 @@ module Dependabot
159
165
  fetch_file_text(changelog)
160
166
  end
161
167
 
168
+ sig { params(file: T.untyped).returns(T.nilable(String)) }
162
169
  def fetch_file_text(file)
163
170
  @file_text ||= {}
164
171
 
165
172
  unless @file_text.key?(file.download_url)
166
- file_source = Source.from_url(file.html_url)
173
+ file_source = T.must(Source.from_url(file.html_url))
167
174
  @file_text[file.download_url] =
168
175
  case file_source.provider
169
176
  when "github" then fetch_github_file(file_source, file)
@@ -171,7 +178,7 @@ module Dependabot
171
178
  when "bitbucket" then fetch_bitbucket_file(file)
172
179
  when "azure" then fetch_azure_file(file)
173
180
  when "codecommit" then nil # TODO: git file from codecommit
174
- else raise "Unsupported provider '#{provider}'"
181
+ else raise "Unsupported provider '#{file_source.provider}'"
175
182
  end
176
183
  end
177
184
 
@@ -1,16 +1,40 @@
1
- # typed: false
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "time"
5
5
  require "tmpdir"
6
+ require "sorbet-runtime"
6
7
  require "dependabot/pull_request_creator"
7
8
 
8
9
  module Dependabot
9
10
  class PullRequestCreator
10
11
  class CommitSigner
11
- attr_reader :author_details, :commit_message, :tree_sha, :parent_sha,
12
- :signature_key
12
+ extend T::Sig
13
13
 
14
+ sig { returns(T::Hash[Symbol, String]) }
15
+ attr_reader :author_details
16
+
17
+ sig { returns(String) }
18
+ attr_reader :commit_message
19
+
20
+ sig { returns(String) }
21
+ attr_reader :tree_sha
22
+
23
+ sig { returns(String) }
24
+ attr_reader :parent_sha
25
+
26
+ sig { returns(String) }
27
+ attr_reader :signature_key
28
+
29
+ sig do
30
+ params(
31
+ author_details: T::Hash[Symbol, String],
32
+ commit_message: String,
33
+ tree_sha: String,
34
+ parent_sha: String,
35
+ signature_key: String
36
+ ).void
37
+ end
14
38
  def initialize(author_details:, commit_message:, tree_sha:, parent_sha:,
15
39
  signature_key:)
16
40
  @author_details = author_details
@@ -20,6 +44,7 @@ module Dependabot
20
44
  @signature_key = signature_key
21
45
  end
22
46
 
47
+ sig { returns(String) }
23
48
  def signature
24
49
  begin
25
50
  require "gpgme"
@@ -39,20 +64,21 @@ module Dependabot
39
64
  opts = { mode: GPGME::SIG_MODE_DETACH, signer: email }
40
65
  crypto.sign(commit_object, opts).to_s
41
66
  rescue Errno::ENOTEMPTY
42
- FileUtils.remove_entry(dir, true)
67
+ FileUtils.remove_entry(T.must(dir), true)
43
68
  # This appears to be a Ruby bug which occurs very rarely
44
69
  raise if @retrying
45
70
 
46
- @retrying = true
71
+ @retrying = T.let(true, T.nilable(T::Boolean))
47
72
  retry
48
73
  ensure
49
- FileUtils.remove_entry(dir, true)
74
+ FileUtils.remove_entry(T.must(dir), true)
50
75
  end
51
76
 
52
77
  private
53
78
 
79
+ sig { returns(String) }
54
80
  def commit_object
55
- time_str = Time.parse(author_details[:date]).strftime("%s %z")
81
+ time_str = Time.parse(T.must(author_details[:date])).strftime("%s %z")
56
82
  name = author_details[:name]
57
83
  email = author_details[:email]
58
84
 
@@ -1,8 +1,9 @@
1
- # typed: false
1
+ # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "octokit"
5
5
  require "securerandom"
6
+ require "sorbet-runtime"
6
7
  require "dependabot/clients/github_with_retries"
7
8
  require "dependabot/pull_request_creator"
8
9
  require "dependabot/pull_request_creator/commit_signer"
@@ -10,6 +11,8 @@ module Dependabot
10
11
  class PullRequestCreator
11
12
  # rubocop:disable Metrics/ClassLength
12
13
  class Github
14
+ extend T::Sig
15
+
13
16
  # GitHub limits PR descriptions to a max of 65,536 characters:
14
17
  # https://github.com/orgs/community/discussions/27190#discussioncomment-3726017
15
18
  PR_DESCRIPTION_MAX_LENGTH = 65_535 # 0 based count
@@ -65,11 +68,11 @@ module Dependabot
65
68
  def branch_exists?(name)
66
69
  git_metadata_fetcher.ref_names.include?(name)
67
70
  rescue Dependabot::GitDependenciesNotReachable => e
68
- raise e.cause if e.cause&.message&.include?("is disabled")
69
- raise e.cause if e.cause.is_a?(Octokit::Unauthorized)
71
+ raise T.must(e.cause) if e.cause&.message&.include?("is disabled")
72
+ raise T.must(e.cause) if e.cause.is_a?(Octokit::Unauthorized)
70
73
  raise(RepoNotFound, source.url) unless repo_exists?
71
74
 
72
- retrying ||= false
75
+ retrying ||= T.let(false, T::Boolean)
73
76
 
74
77
  msg = "Unexpected git error!\n\n#{e.cause&.class}: #{e.cause&.message}"
75
78
  raise msg if retrying
@@ -189,7 +192,7 @@ module Dependabot
189
192
  if file.type == "submodule"
190
193
  {
191
194
  path: file.path.sub(%r{^/}, ""),
192
- mode: "160000",
195
+ mode: Dependabot::DependencyFile::Mode::SUBMODULE,
193
196
  type: "commit",
194
197
  sha: file.content
195
198
  }
@@ -207,7 +210,7 @@ module Dependabot
207
210
 
208
211
  {
209
212
  path: file.realpath,
210
- mode: (file.mode || "100644"),
213
+ mode: (file.mode || Dependabot::DependencyFile::Mode::FILE),
211
214
  type: "blob"
212
215
  }.merge(content)
213
216
  end
@@ -249,14 +252,14 @@ module Dependabot
249
252
  rescue Octokit::UnprocessableEntity => e
250
253
  raise if e.message.match?(/Reference already exists/i)
251
254
 
252
- retrying_branch_creation ||= false
255
+ retrying_branch_creation ||= T.let(false, T::Boolean)
253
256
  raise if retrying_branch_creation
254
257
 
255
258
  retrying_branch_creation = true
256
259
 
257
260
  # Branch creation will fail if a branch called `dependabot` already
258
261
  # exists, since git won't be able to create a dir with the same name
259
- ref = "refs/heads/#{SecureRandom.hex[0..3] + branch_name}"
262
+ ref = "refs/heads/#{T.must(SecureRandom.hex[0..3]) + branch_name}"
260
263
  retry
261
264
  end
262
265
  end
@@ -320,7 +323,7 @@ module Dependabot
320
323
  "`@#{reviewers.first}`"
321
324
  else
322
325
  names = reviewers.map { |rv| "`@#{rv}`" }
323
- "#{names[0..-2].join(', ')} and #{names[-1]}"
326
+ "#{T.must(names[0..-2]).join(', ')} and #{names[-1]}"
324
327
  end
325
328
 
326
329
  msg = "Dependabot tried to add #{reviewers_string} as "
@@ -371,7 +374,7 @@ module Dependabot
371
374
  # Sometimes PR creation fails with no details (presumably because the
372
375
  # details are internal). It doesn't hurt to retry in these cases, in
373
376
  # case the cause is a race.
374
- retrying_pr_creation ||= false
377
+ retrying_pr_creation ||= T.let(false, T::Boolean)
375
378
  raise if retrying_pr_creation
376
379
 
377
380
  retrying_pr_creation = true
@@ -1,12 +1,31 @@
1
- # typed: true
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "sorbet-runtime"
5
+
4
6
  module Dependabot
5
7
  class PullRequestCreator
6
8
  # Message is a static alternative to MessageBuilder
7
9
  class Message
8
- attr_reader :commit_message, :pr_name, :pr_message
10
+ extend T::Sig
11
+
12
+ sig { returns(T.nilable(String)) }
13
+ attr_reader :commit_message
14
+
15
+ sig { returns(T.nilable(String)) }
16
+ attr_reader :pr_name
9
17
 
18
+ sig { returns(T.nilable(String)) }
19
+ attr_reader :pr_message
20
+
21
+ sig do
22
+ params(
23
+ commit_message: T.nilable(String),
24
+ pr_name: T.nilable(String),
25
+ pr_message: T.nilable(String)
26
+ )
27
+ .void
28
+ end
10
29
  def initialize(commit_message: nil, pr_name: nil, pr_message: nil)
11
30
  @commit_message = commit_message
12
31
  @pr_name = pr_name
@@ -1,7 +1,8 @@
1
- # typed: false
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "commonmarker"
5
+ require "sorbet-runtime"
5
6
  require "strscan"
6
7
  require "dependabot/pull_request_creator/message_builder"
7
8
 
@@ -9,6 +10,8 @@ module Dependabot
9
10
  class PullRequestCreator
10
11
  class MessageBuilder
11
12
  class LinkAndMentionSanitizer
13
+ extend T::Sig
14
+
12
15
  GITHUB_USERNAME = /[a-z0-9]+(-[a-z0-9]+)*/i
13
16
  GITHUB_REF_REGEX = %r{
14
17
  (?:https?://)?
@@ -22,19 +25,24 @@ module Dependabot
22
25
  TEAM_MENTION_REGEX = %r{(?<![A-Za-z0-9`~])@(?<org>#{GITHUB_USERNAME})/(?<team>#{GITHUB_USERNAME})/?}
23
26
  # End of string
24
27
  EOS_REGEX = /\z/
25
- COMMONMARKER_OPTIONS = %i(
26
- GITHUB_PRE_LANG FULL_INFO_STRING
27
- ).freeze
28
- COMMONMARKER_EXTENSIONS = %i(
29
- table tasklist strikethrough autolink tagfilter
30
- ).freeze
31
-
28
+ COMMONMARKER_OPTIONS = T.let(
29
+ %i(GITHUB_PRE_LANG FULL_INFO_STRING).freeze,
30
+ T::Array[Symbol]
31
+ )
32
+ COMMONMARKER_EXTENSIONS = T.let(
33
+ %i(table tasklist strikethrough autolink tagfilter).freeze,
34
+ T::Array[Symbol]
35
+ )
36
+
37
+ sig { returns(T.nilable(String)) }
32
38
  attr_reader :github_redirection_service
33
39
 
40
+ sig { params(github_redirection_service: T.nilable(String)).void }
34
41
  def initialize(github_redirection_service:)
35
42
  @github_redirection_service = github_redirection_service
36
43
  end
37
44
 
45
+ sig { params(text: String, unsafe: T::Boolean, format_html: T::Boolean).returns(String) }
38
46
  def sanitize_links_and_mentions(text:, unsafe: false, format_html: true)
39
47
  doc = CommonMarker.render_doc(
40
48
  text, :LIBERAL_HTML_TAG, COMMONMARKER_EXTENSIONS
@@ -53,6 +61,7 @@ module Dependabot
53
61
 
54
62
  private
55
63
 
64
+ sig { params(doc: CommonMarker::Node).void }
56
65
  def sanitize_mentions(doc)
57
66
  doc.walk do |node|
58
67
  if node.type == :text &&
@@ -77,6 +86,7 @@ module Dependabot
77
86
  # This is because there are ecosystems that have packages that follow the same pattern
78
87
  # (e.g. @angular/angular-cli), and we don't want to create an invalid link, since
79
88
  # team mentions link to `https://github.com/org/:organization_name/teams/:team_name`.
89
+ sig { params(doc: CommonMarker::Node).void }
80
90
  def sanitize_team_mentions(doc)
81
91
  doc.walk do |node|
82
92
  if node.type == :text &&
@@ -92,6 +102,7 @@ module Dependabot
92
102
  end
93
103
  end
94
104
 
105
+ sig { params(doc: CommonMarker::Node).void }
95
106
  def sanitize_links(doc)
96
107
  doc.walk do |node|
97
108
  if node.type == :link && node.url.match?(GITHUB_REF_REGEX)
@@ -101,7 +112,7 @@ module Dependabot
101
112
  next
102
113
  end
103
114
 
104
- last_match = subnode.string_content.match(GITHUB_REF_REGEX)
115
+ last_match = T.must(subnode.string_content.match(GITHUB_REF_REGEX))
105
116
  number = last_match.named_captures.fetch("number")
106
117
  repo = last_match.named_captures.fetch("repo")
107
118
  subnode.string_content = "#{repo}##{number}"
@@ -115,6 +126,7 @@ module Dependabot
115
126
  end
116
127
  end
117
128
 
129
+ sig { params(doc: CommonMarker::Node).void }
118
130
  def sanitize_nwo_text(doc)
119
131
  doc.walk do |node|
120
132
  if node.type == :text &&
@@ -125,8 +137,9 @@ module Dependabot
125
137
  end
126
138
  end
127
139
 
140
+ sig { params(node: CommonMarker::Node).void }
128
141
  def replace_nwo_node(node)
129
- match = node.string_content.match(GITHUB_NWO_REGEX)
142
+ match = T.must(node.string_content.match(GITHUB_NWO_REGEX))
130
143
  repo = match.named_captures.fetch("repo")
131
144
  number = match.named_captures.fetch("number")
132
145
  new_node = build_nwo_text_node("#{repo}##{number}")
@@ -134,22 +147,24 @@ module Dependabot
134
147
  node.delete
135
148
  end
136
149
 
150
+ sig { params(text: String).returns(String) }
137
151
  def replace_github_host(text)
138
- return text if !github_redirection_service.nil? && text.include?(github_redirection_service)
152
+ return text if !github_redirection_service.nil? && text.include?(T.must(github_redirection_service))
139
153
 
140
154
  text.gsub(
141
155
  /(www\.)?github.com/, github_redirection_service || "github.com"
142
156
  )
143
157
  end
144
158
 
159
+ sig { params(text: String).returns(T::Array[CommonMarker::Node]) }
145
160
  def build_mention_nodes(text)
146
- nodes = []
161
+ nodes = T.let([], T::Array[CommonMarker::Node])
147
162
  scan = StringScanner.new(text)
148
163
 
149
164
  until scan.eos?
150
165
  line = scan.scan_until(MENTION_REGEX) ||
151
166
  scan.scan_until(EOS_REGEX)
152
- line_match = line.match(MENTION_REGEX)
167
+ line_match = T.must(line).match(MENTION_REGEX)
153
168
  mention = line_match&.to_s
154
169
  text_node = CommonMarker::Node.new(:text)
155
170
 
@@ -168,14 +183,15 @@ module Dependabot
168
183
  nodes
169
184
  end
170
185
 
186
+ sig { params(text: String).returns(T::Array[CommonMarker::Node]) }
171
187
  def build_team_mention_nodes(text)
172
- nodes = []
188
+ nodes = T.let([], T::Array[CommonMarker::Node])
173
189
 
174
190
  scan = StringScanner.new(text)
175
191
  until scan.eos?
176
192
  line = scan.scan_until(TEAM_MENTION_REGEX) ||
177
193
  scan.scan_until(EOS_REGEX)
178
- line_match = line.match(TEAM_MENTION_REGEX)
194
+ line_match = T.must(line).match(TEAM_MENTION_REGEX)
179
195
  mention = line_match&.to_s
180
196
  text_node = CommonMarker::Node.new(:text)
181
197
 
@@ -192,18 +208,21 @@ module Dependabot
192
208
  nodes
193
209
  end
194
210
 
211
+ sig { params(text: String).returns(T::Array[CommonMarker::Node]) }
195
212
  def build_mention_link_text_nodes(text)
196
213
  code_node = CommonMarker::Node.new(:code)
197
214
  code_node.string_content = insert_zero_width_space_in_mention(text)
198
215
  [code_node]
199
216
  end
200
217
 
218
+ sig { params(text: String).returns(CommonMarker::Node) }
201
219
  def build_nwo_text_node(text)
202
220
  code_node = CommonMarker::Node.new(:code)
203
221
  code_node.string_content = text
204
222
  code_node
205
223
  end
206
224
 
225
+ sig { params(url: String, text: String).returns(CommonMarker::Node) }
207
226
  def create_link_node(url, text)
208
227
  link_node = CommonMarker::Node.new(:link)
209
228
  code_node = CommonMarker::Node.new(:code)
@@ -217,12 +236,14 @@ module Dependabot
217
236
  # email replies on dependabot pull requests triggering notifications to
218
237
  # users who've been mentioned in changelogs etc. PR email replies parse
219
238
  # the content of the pull request body in plain text.
239
+ sig { params(mention: String).returns(String) }
220
240
  def insert_zero_width_space_in_mention(mention)
221
241
  mention.sub("@", "@\u200B").encode("utf-8")
222
242
  end
223
243
 
244
+ sig { params(node: CommonMarker::Node).returns(T::Boolean) }
224
245
  def parent_node_link?(node)
225
- node.type == :link || (node.parent && parent_node_link?(node.parent))
246
+ node.type == :link || (!node.parent.nil? && parent_node_link?(T.must(node.parent)))
226
247
  end
227
248
  end
228
249
  end
@@ -1,12 +1,14 @@
1
- # typed: false
1
+ # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "sorbet-runtime"
4
5
  require "dependabot/pull_request_creator/message_builder"
5
6
 
6
7
  module Dependabot
7
8
  class PullRequestCreator
8
9
  class MessageBuilder
9
10
  class MetadataPresenter
11
+ extend T::Sig
10
12
  extend Forwardable
11
13
 
12
14
  attr_reader :dependency, :source, :metadata_finder,
@@ -154,7 +156,7 @@ module Dependabot
154
156
  msg += body
155
157
  msg + "</details>\n"
156
158
  else
157
- "\n##{summary}\n\n#{body}"
159
+ "\n# #{summary}\n\n#{body}"
158
160
  end
159
161
  end
160
162
 
@@ -192,7 +194,7 @@ module Dependabot
192
194
  unaffected_versions
193
195
  affected_versions
194
196
  ).each do |tp|
195
- type = tp.split("_").first.capitalize
197
+ type = T.must(tp.split("_").first).capitalize
196
198
  next unless details[tp]
197
199
 
198
200
  versions_string = details[tp].any? ? details[tp].join("; ") : "none"