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.
- checksums.yaml +4 -4
- data/lib/dependabot/clients/azure.rb +3 -3
- data/lib/dependabot/config/file.rb +17 -6
- data/lib/dependabot/config/update_config.rb +23 -5
- data/lib/dependabot/dependency_file.rb +84 -14
- data/lib/dependabot/dependency_group.rb +29 -5
- data/lib/dependabot/errors.rb +101 -13
- data/lib/dependabot/file_fetchers/base.rb +227 -93
- data/lib/dependabot/metadata_finders/base/changelog_finder.rb +13 -6
- data/lib/dependabot/pull_request_creator/github.rb +11 -8
- data/lib/dependabot/pull_request_creator/message.rb +21 -2
- data/lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb +37 -16
- data/lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb +4 -2
- data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +10 -4
- data/lib/dependabot/shared_helpers.rb +117 -33
- data/lib/dependabot/simple_instrumentor.rb +22 -3
- data/lib/dependabot/source.rb +65 -17
- data/lib/dependabot/update_checkers/version_filters.rb +12 -1
- data/lib/dependabot/utils.rb +21 -2
- data/lib/dependabot/workspace/base.rb +42 -7
- data/lib/dependabot/workspace/change_attempt.rb +31 -3
- data/lib/dependabot/workspace/git.rb +34 -4
- data/lib/dependabot/workspace.rb +16 -2
- data/lib/dependabot.rb +1 -1
- metadata +23 -9
@@ -1,7 +1,8 @@
|
|
1
|
-
# typed:
|
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
|
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
|
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
|
-
|
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:
|
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:
|
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
|
-
|
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:
|
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 =
|
26
|
-
GITHUB_PRE_LANG FULL_INFO_STRING
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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:
|
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
|
-
|
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 =
|
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
|
-
|
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
|
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
|