dependabot-common 0.235.0 → 0.237.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 (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"