dependabot-common 0.236.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.
@@ -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,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
@@ -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,
@@ -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"
@@ -132,7 +132,7 @@ module Dependabot
132
132
  case last_dependabot_commit_style
133
133
  when :gitmoji then true
134
134
  when :conventional_prefix, :conventional_prefix_with_scope
135
- last_dependabot_commit_message.match?(/: (\[[Ss]ecurity\] )?(B|U)/)
135
+ last_dependabot_commit_title.match?(/: (\[[Ss]ecurity\] )?(B|U)/)
136
136
  else raise "Unknown commit style #{last_dependabot_commit_style}"
137
137
  end
138
138
  end
@@ -152,7 +152,7 @@ module Dependabot
152
152
  end
153
153
 
154
154
  def last_dependabot_commit_style
155
- return unless (msg = last_dependabot_commit_message)
155
+ return unless (msg = last_dependabot_commit_title)
156
156
 
157
157
  return :gitmoji if msg.start_with?("⬆️")
158
158
  return :conventional_prefix if msg.match?(/\A(chore|build|upgrade):/i)
@@ -162,7 +162,7 @@ module Dependabot
162
162
  end
163
163
 
164
164
  def last_dependabot_commit_prefix
165
- last_dependabot_commit_message&.split(/[:(]/)&.first
165
+ last_dependabot_commit_title&.split(/[:(]/)&.first
166
166
  end
167
167
 
168
168
  # rubocop:disable Metrics/PerceivedComplexity
@@ -245,7 +245,7 @@ module Dependabot
245
245
  ANGULAR_PREFIXES.any? { |pre| message.match?(/#{pre}[:(]/i) }
246
246
  end
247
247
 
248
- return last_dependabot_commit_message&.start_with?(/[A-Z]/) if semantic_messages.none?
248
+ return last_dependabot_commit_title&.start_with?(/[A-Z]/) if semantic_messages.none?
249
249
 
250
250
  capitalized_msgs = semantic_messages
251
251
  .select { |m| m.start_with?(/[A-Z]/) }
@@ -329,6 +329,12 @@ module Dependabot
329
329
  .map(&:strip)
330
330
  end
331
331
 
332
+ def last_dependabot_commit_title
333
+ return @last_dependabot_commit_title if defined?(@last_dependabot_commit_title)
334
+
335
+ @last_dependabot_commit_title = last_dependabot_commit_message&.split("\n")&.first
336
+ end
337
+
332
338
  def last_dependabot_commit_message
333
339
  @last_dependabot_commit_message ||=
334
340
  case source.provider