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.
- 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"
|