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.
- checksums.yaml +4 -4
- data/lib/dependabot/clients/azure.rb +3 -3
- data/lib/dependabot/config/file.rb +32 -9
- data/lib/dependabot/config/file_fetcher.rb +3 -3
- data/lib/dependabot/config/ignore_condition.rb +34 -8
- data/lib/dependabot/config/update_config.rb +42 -6
- data/lib/dependabot/config.rb +1 -1
- data/lib/dependabot/dependency_file.rb +89 -14
- data/lib/dependabot/dependency_group.rb +29 -5
- data/lib/dependabot/errors.rb +101 -13
- data/lib/dependabot/file_fetchers/base.rb +250 -93
- data/lib/dependabot/file_updaters/artifact_updater.rb +37 -10
- data/lib/dependabot/file_updaters/vendor_updater.rb +13 -3
- data/lib/dependabot/logger.rb +7 -2
- data/lib/dependabot/metadata_finders/base/changelog_finder.rb +13 -6
- data/lib/dependabot/pull_request_creator/commit_signer.rb +33 -7
- data/lib/dependabot/pull_request_creator/github.rb +13 -10
- 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 +5 -3
- data/lib/dependabot/pull_request_creator/message_builder.rb +5 -18
- data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +10 -4
- data/lib/dependabot/pull_request_updater/github.rb +2 -2
- 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 +37 -9
@@ -1,6 +1,7 @@
|
|
1
|
-
# typed:
|
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 =
|
35
|
-
|
36
|
-
|
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
|
-
|
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:
|
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
|
-
|
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
|
data/lib/dependabot/logger.rb
CHANGED
@@ -1,13 +1,18 @@
|
|
1
|
-
# typed:
|
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:
|
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,16 +1,40 @@
|
|
1
|
-
# typed:
|
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
|
-
|
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:
|
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:
|
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 ||
|
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:
|
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,
|
@@ -154,7 +156,7 @@ module Dependabot
|
|
154
156
|
msg += body
|
155
157
|
msg + "</details>\n"
|
156
158
|
else
|
157
|
-
"\n
|
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"
|