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,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "digest"
|
@@ -8,6 +8,7 @@ require "fileutils"
|
|
8
8
|
require "json"
|
9
9
|
require "open3"
|
10
10
|
require "shellwords"
|
11
|
+
require "sorbet-runtime"
|
11
12
|
require "tmpdir"
|
12
13
|
|
13
14
|
require "dependabot/simple_instrumentor"
|
@@ -18,20 +19,34 @@ require "dependabot"
|
|
18
19
|
|
19
20
|
module Dependabot
|
20
21
|
module SharedHelpers
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
extend T::Sig
|
23
|
+
|
24
|
+
GIT_CONFIG_GLOBAL_PATH = T.let(File.expand_path(".gitconfig", Utils::BUMP_TMP_DIR_PATH), String)
|
25
|
+
USER_AGENT = T.let(
|
26
|
+
"dependabot-core/#{Dependabot::VERSION} " \
|
27
|
+
"#{Excon::USER_AGENT} ruby/#{RUBY_VERSION} " \
|
28
|
+
"(#{RUBY_PLATFORM}) " \
|
29
|
+
"(+https://github.com/dependabot/dependabot-core)".freeze,
|
30
|
+
String
|
31
|
+
)
|
26
32
|
SIGKILL = 9
|
27
33
|
|
34
|
+
sig do
|
35
|
+
type_parameters(:T)
|
36
|
+
.params(
|
37
|
+
directory: String,
|
38
|
+
repo_contents_path: T.nilable(String),
|
39
|
+
block: T.proc.params(arg0: T.any(Pathname, String)).returns(T.type_parameter(:T))
|
40
|
+
)
|
41
|
+
.returns(T.type_parameter(:T))
|
42
|
+
end
|
28
43
|
def self.in_a_temporary_repo_directory(directory = "/", repo_contents_path = nil, &block)
|
29
44
|
if repo_contents_path
|
30
45
|
# If a workspace has been defined to allow orcestration of the git repo
|
31
46
|
# by the runtime we should defer to it, otherwise we prepare the folder
|
32
47
|
# for direct use and yield.
|
33
48
|
if Dependabot::Workspace.active_workspace
|
34
|
-
Dependabot::Workspace.active_workspace.change(&block)
|
49
|
+
T.must(Dependabot::Workspace.active_workspace).change(&block)
|
35
50
|
else
|
36
51
|
path = Pathname.new(File.join(repo_contents_path, directory)).expand_path
|
37
52
|
reset_git_repo(repo_contents_path)
|
@@ -46,9 +61,18 @@ module Dependabot
|
|
46
61
|
end
|
47
62
|
end
|
48
63
|
|
49
|
-
|
64
|
+
sig do
|
65
|
+
type_parameters(:T)
|
66
|
+
.params(
|
67
|
+
directory: String,
|
68
|
+
_block: T.proc.params(arg0: T.any(Pathname, String)).returns(T.type_parameter(:T))
|
69
|
+
)
|
70
|
+
.returns(T.type_parameter(:T))
|
71
|
+
end
|
72
|
+
def self.in_a_temporary_directory(directory = "/", &_block)
|
50
73
|
FileUtils.mkdir_p(Utils::BUMP_TMP_DIR_PATH)
|
51
74
|
tmp_dir = Dir.mktmpdir(Utils::BUMP_TMP_FILE_PREFIX, Utils::BUMP_TMP_DIR_PATH)
|
75
|
+
path = Pathname.new(File.join(tmp_dir, directory)).expand_path
|
52
76
|
|
53
77
|
begin
|
54
78
|
path = Pathname.new(File.join(tmp_dir, directory)).expand_path
|
@@ -60,28 +84,59 @@ module Dependabot
|
|
60
84
|
end
|
61
85
|
|
62
86
|
class HelperSubprocessFailed < Dependabot::DependabotError
|
63
|
-
|
87
|
+
extend T::Sig
|
88
|
+
|
89
|
+
sig { returns(String) }
|
90
|
+
attr_reader :error_class
|
91
|
+
|
92
|
+
sig { returns(T::Hash[Symbol, String]) }
|
93
|
+
attr_reader :error_context
|
94
|
+
|
95
|
+
sig { returns(T.nilable(T::Array[String])) }
|
96
|
+
attr_reader :trace
|
64
97
|
|
98
|
+
sig do
|
99
|
+
params(
|
100
|
+
message: String,
|
101
|
+
error_context: T::Hash[Symbol, String],
|
102
|
+
error_class: T.nilable(String),
|
103
|
+
trace: T.nilable(T::Array[String])
|
104
|
+
).void
|
105
|
+
end
|
65
106
|
def initialize(message:, error_context:, error_class: nil, trace: nil)
|
66
107
|
super(message)
|
67
|
-
@error_class = error_class || "HelperSubprocessFailed"
|
108
|
+
@error_class = T.let(error_class || "HelperSubprocessFailed", String)
|
68
109
|
@error_context = error_context
|
69
|
-
@fingerprint = error_context[:fingerprint] || error_context[:command]
|
110
|
+
@fingerprint = T.let(error_context[:fingerprint] || error_context[:command], T.nilable(String))
|
70
111
|
@trace = trace
|
71
112
|
end
|
72
113
|
|
114
|
+
sig { returns(T::Hash[Symbol, T.untyped]) }
|
73
115
|
def raven_context
|
74
116
|
{ fingerprint: [@fingerprint], extra: @error_context.except(:stderr_output, :fingerprint) }
|
75
117
|
end
|
76
118
|
end
|
77
119
|
|
78
120
|
# Escapes all special characters, e.g. = & | <>
|
121
|
+
sig { params(command: String).returns(String) }
|
79
122
|
def self.escape_command(command)
|
80
123
|
command_parts = command.split.map(&:strip).reject(&:empty?)
|
81
124
|
Shellwords.join(command_parts)
|
82
125
|
end
|
83
126
|
|
84
127
|
# rubocop:disable Metrics/MethodLength
|
128
|
+
# rubocop:disable Metrics/AbcSize
|
129
|
+
sig do
|
130
|
+
params(
|
131
|
+
command: String,
|
132
|
+
function: String,
|
133
|
+
args: T.any(T::Array[String], T::Hash[Symbol, String]),
|
134
|
+
env: T.nilable(T::Hash[String, String]),
|
135
|
+
stderr_to_stdout: T::Boolean,
|
136
|
+
allow_unsafe_shell_command: T::Boolean
|
137
|
+
)
|
138
|
+
.returns(T.nilable(T.any(String, T::Hash[String, T.untyped], T::Array[T::Hash[String, T.untyped]])))
|
139
|
+
end
|
85
140
|
def self.run_helper_subprocess(command:, function:, args:, env: nil,
|
86
141
|
stderr_to_stdout: false,
|
87
142
|
allow_unsafe_shell_command: false)
|
@@ -95,11 +150,11 @@ module Dependabot
|
|
95
150
|
if ENV["DEBUG_FUNCTION"] == function
|
96
151
|
puts helper_subprocess_bash_command(stdin_data: stdin_data, command: cmd, env: env)
|
97
152
|
# Pause execution so we can run helpers inside the temporary directory
|
98
|
-
debugger
|
153
|
+
T.unsafe(self).debugger
|
99
154
|
end
|
100
155
|
|
101
156
|
env_cmd = [env, cmd].compact
|
102
|
-
stdout, stderr, process = Open3.capture3(*env_cmd, stdin_data: stdin_data)
|
157
|
+
stdout, stderr, process = T.unsafe(Open3).capture3(*env_cmd, stdin_data: stdin_data)
|
103
158
|
time_taken = Time.now - start
|
104
159
|
|
105
160
|
if ENV["DEBUG_HELPERS"] == "true"
|
@@ -126,24 +181,27 @@ module Dependabot
|
|
126
181
|
|
127
182
|
check_out_of_memory_error(stderr, error_context)
|
128
183
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
184
|
+
begin
|
185
|
+
response = JSON.parse(stdout)
|
186
|
+
return response["result"] if process.success?
|
187
|
+
|
188
|
+
raise HelperSubprocessFailed.new(
|
189
|
+
message: response["error"],
|
190
|
+
error_class: response["error_class"],
|
191
|
+
error_context: error_context,
|
192
|
+
trace: response["trace"]
|
193
|
+
)
|
194
|
+
rescue JSON::ParserError
|
195
|
+
raise HelperSubprocessFailed.new(
|
196
|
+
message: stdout || "No output from command",
|
197
|
+
error_class: "JSON::ParserError",
|
198
|
+
error_context: error_context
|
199
|
+
)
|
200
|
+
end
|
144
201
|
end
|
145
202
|
|
146
203
|
# rubocop:enable Metrics/MethodLength
|
204
|
+
sig { params(stderr: T.nilable(String), error_context: T::Hash[Symbol, String]).void }
|
147
205
|
def self.check_out_of_memory_error(stderr, error_context)
|
148
206
|
return unless stderr&.include?("JavaScript heap out of memory")
|
149
207
|
|
@@ -154,12 +212,14 @@ module Dependabot
|
|
154
212
|
)
|
155
213
|
end
|
156
214
|
|
215
|
+
sig { returns(T::Array[T.class_of(Excon::Middleware::Base)]) }
|
157
216
|
def self.excon_middleware
|
158
|
-
Excon.defaults[:middlewares] +
|
217
|
+
T.must(T.cast(Excon.defaults, T::Hash[Symbol, T::Array[T.class_of(Excon::Middleware::Base)]])[:middlewares]) +
|
159
218
|
[Excon::Middleware::Decompress] +
|
160
219
|
[Excon::Middleware::RedirectFollower]
|
161
220
|
end
|
162
221
|
|
222
|
+
sig { params(headers: T.nilable(T::Hash[String, String])).returns(T::Hash[String, String]) }
|
163
223
|
def self.excon_headers(headers = nil)
|
164
224
|
headers ||= {}
|
165
225
|
{
|
@@ -167,9 +227,10 @@ module Dependabot
|
|
167
227
|
}.merge(headers)
|
168
228
|
end
|
169
229
|
|
230
|
+
sig { params(options: T.nilable(T::Hash[Symbol, T.untyped])).returns(T::Hash[Symbol, T.untyped]) }
|
170
231
|
def self.excon_defaults(options = nil)
|
171
232
|
options ||= {}
|
172
|
-
headers = options.delete(:headers)
|
233
|
+
headers = T.cast(options.delete(:headers), T.nilable(T::Hash[String, String]))
|
173
234
|
{
|
174
235
|
instrumentor: Dependabot::SimpleInstrumentor,
|
175
236
|
connect_timeout: 5,
|
@@ -182,7 +243,15 @@ module Dependabot
|
|
182
243
|
}.merge(options)
|
183
244
|
end
|
184
245
|
|
185
|
-
|
246
|
+
sig do
|
247
|
+
type_parameters(:T)
|
248
|
+
.params(
|
249
|
+
credentials: T::Array[T::Hash[String, String]],
|
250
|
+
_block: T.proc.returns(T.type_parameter(:T))
|
251
|
+
)
|
252
|
+
.returns(T.type_parameter(:T))
|
253
|
+
end
|
254
|
+
def self.with_git_configured(credentials:, &_block)
|
186
255
|
safe_directories = find_safe_directories
|
187
256
|
|
188
257
|
FileUtils.mkdir_p(Utils::BUMP_TMP_DIR_PATH)
|
@@ -203,18 +272,20 @@ module Dependabot
|
|
203
272
|
end
|
204
273
|
|
205
274
|
# Handle SCP-style git URIs
|
275
|
+
sig { params(uri: String).returns(String) }
|
206
276
|
def self.scp_to_standard(uri)
|
207
277
|
return uri unless uri.start_with?("git@")
|
208
278
|
|
209
|
-
"https://#{uri.split('git@').last.sub(%r{:/?}, '/')}"
|
279
|
+
"https://#{T.must(uri.split('git@').last).sub(%r{:/?}, '/')}"
|
210
280
|
end
|
211
281
|
|
282
|
+
sig { returns(String) }
|
212
283
|
def self.credential_helper_path
|
213
284
|
File.join(__dir__, "../../bin/git-credential-store-immutable")
|
214
285
|
end
|
215
286
|
|
216
|
-
# rubocop:disable Metrics/AbcSize
|
217
287
|
# rubocop:disable Metrics/PerceivedComplexity
|
288
|
+
sig { params(credentials: T::Array[T::Hash[String, String]], safe_directories: T::Array[String]).void }
|
218
289
|
def self.configure_git_to_use_https_with_credentials(credentials, safe_directories)
|
219
290
|
File.open(GIT_CONFIG_GLOBAL_PATH, "w") do |file|
|
220
291
|
file << "# Generated by dependabot/dependabot-core"
|
@@ -274,6 +345,7 @@ module Dependabot
|
|
274
345
|
# rubocop:enable Metrics/AbcSize
|
275
346
|
# rubocop:enable Metrics/PerceivedComplexity
|
276
347
|
|
348
|
+
sig { params(host: String).void }
|
277
349
|
def self.configure_git_to_use_https(host)
|
278
350
|
# NOTE: we use --global here (rather than --system) so that Dependabot
|
279
351
|
# can be run without privileged access
|
@@ -299,6 +371,7 @@ module Dependabot
|
|
299
371
|
)
|
300
372
|
end
|
301
373
|
|
374
|
+
sig { params(path: String).void }
|
302
375
|
def self.reset_git_repo(path)
|
303
376
|
Dir.chdir(path) do
|
304
377
|
run_shell_command("git reset HEAD --hard")
|
@@ -306,6 +379,7 @@ module Dependabot
|
|
306
379
|
end
|
307
380
|
end
|
308
381
|
|
382
|
+
sig { returns(T::Array[String]) }
|
309
383
|
def self.find_safe_directories
|
310
384
|
# to preserve safe directories from global .gitconfig
|
311
385
|
output, process = Open3.capture2("git config --global --get-all safe.directory")
|
@@ -314,6 +388,15 @@ module Dependabot
|
|
314
388
|
safe_directories
|
315
389
|
end
|
316
390
|
|
391
|
+
sig do
|
392
|
+
params(
|
393
|
+
command: String,
|
394
|
+
allow_unsafe_shell_command: T::Boolean,
|
395
|
+
env: T.nilable(T::Hash[String, String]),
|
396
|
+
fingerprint: T.nilable(String),
|
397
|
+
stderr_to_stdout: T::Boolean
|
398
|
+
).returns(String)
|
399
|
+
end
|
317
400
|
def self.run_shell_command(command,
|
318
401
|
allow_unsafe_shell_command: false,
|
319
402
|
env: {},
|
@@ -347,6 +430,7 @@ module Dependabot
|
|
347
430
|
)
|
348
431
|
end
|
349
432
|
|
433
|
+
sig { params(command: String, stdin_data: String, env: T.nilable(T::Hash[String, String])).returns(String) }
|
350
434
|
def self.helper_subprocess_bash_command(command:, stdin_data:, env:)
|
351
435
|
escaped_stdin_data = stdin_data.gsub("\"", "\\\"")
|
352
436
|
env_keys = env ? env.compact.map { |k, v| "#{k}=#{v}" }.join(" ") + " " : ""
|
@@ -1,16 +1,35 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strong
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
4
6
|
module Dependabot
|
5
7
|
module SimpleInstrumentor
|
6
8
|
class << self
|
7
|
-
|
9
|
+
extend T::Sig
|
10
|
+
extend T::Generic
|
11
|
+
|
12
|
+
sig { returns(T.nilable(T::Array[T.proc.params(name: String, params: T::Hash[Symbol, T.untyped]).void])) }
|
13
|
+
attr_accessor :subscribers
|
8
14
|
|
15
|
+
sig { params(block: T.proc.params(name: String, params: T::Hash[Symbol, T.untyped]).void).void }
|
9
16
|
def subscribe(&block)
|
10
|
-
@subscribers ||=
|
17
|
+
@subscribers ||= T.let(
|
18
|
+
[],
|
19
|
+
T.nilable(T::Array[T.proc.params(name: String, params: T::Hash[Symbol, T.untyped]).void])
|
20
|
+
)
|
11
21
|
@subscribers << block
|
12
22
|
end
|
13
23
|
|
24
|
+
sig do
|
25
|
+
type_parameters(:T)
|
26
|
+
.params(
|
27
|
+
name: String,
|
28
|
+
params: T::Hash[Symbol, T.untyped],
|
29
|
+
block: T.proc.returns(T.type_parameter(:T))
|
30
|
+
)
|
31
|
+
.returns(T.nilable(T.type_parameter(:T)))
|
32
|
+
end
|
14
33
|
def instrument(name, params = {}, &block)
|
15
34
|
@subscribers&.each { |s| s.call(name, params) }
|
16
35
|
yield if block
|
data/lib/dependabot/source.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
4
6
|
module Dependabot
|
5
7
|
class Source
|
8
|
+
extend T::Sig
|
9
|
+
|
6
10
|
GITHUB_SOURCE = %r{
|
7
11
|
(?<provider>github)
|
8
12
|
(?:\.com)[/:]
|
@@ -59,24 +63,48 @@ module Dependabot
|
|
59
63
|
(?:#{CODECOMMIT_SOURCE})
|
60
64
|
/x
|
61
65
|
|
62
|
-
IGNORED_PROVIDER_HOSTS = %w(gitbox.apache.org svn.apache.org fuchsia.googlesource.com).freeze
|
66
|
+
IGNORED_PROVIDER_HOSTS = T.let(%w(gitbox.apache.org svn.apache.org fuchsia.googlesource.com).freeze,
|
67
|
+
T::Array[String])
|
68
|
+
|
69
|
+
sig { returns(String) }
|
70
|
+
attr_accessor :provider
|
71
|
+
|
72
|
+
sig { returns(String) }
|
73
|
+
attr_accessor :repo
|
74
|
+
|
75
|
+
sig { returns(T.nilable(String)) }
|
76
|
+
attr_accessor :directory
|
63
77
|
|
64
|
-
|
65
|
-
|
78
|
+
sig { returns(T.nilable(T::Array[String])) }
|
79
|
+
attr_accessor :directories
|
66
80
|
|
81
|
+
sig { returns(T.nilable(String)) }
|
82
|
+
attr_accessor :branch
|
83
|
+
|
84
|
+
sig { returns(T.nilable(String)) }
|
85
|
+
attr_accessor :commit
|
86
|
+
|
87
|
+
sig { returns(String) }
|
88
|
+
attr_accessor :hostname
|
89
|
+
|
90
|
+
sig { returns(T.nilable(String)) }
|
91
|
+
attr_accessor :api_endpoint
|
92
|
+
|
93
|
+
sig { params(url_string: T.nilable(String)).returns(T.nilable(Source)) }
|
67
94
|
def self.from_url(url_string)
|
68
95
|
return github_enterprise_from_url(url_string) unless url_string&.match?(SOURCE_REGEX)
|
69
96
|
|
70
|
-
captures = url_string.match(SOURCE_REGEX).named_captures
|
97
|
+
captures = T.must(url_string.match(SOURCE_REGEX)).named_captures
|
71
98
|
|
72
99
|
new(
|
73
|
-
provider: captures.fetch("provider"),
|
74
|
-
repo: captures.fetch("repo").delete_suffix(".git").delete_suffix("."),
|
100
|
+
provider: T.must(captures.fetch("provider")),
|
101
|
+
repo: T.must(captures.fetch("repo")).delete_suffix(".git").delete_suffix("."),
|
75
102
|
directory: captures.fetch("directory"),
|
76
103
|
branch: captures.fetch("branch")
|
77
104
|
)
|
78
105
|
end
|
79
106
|
|
107
|
+
sig { params(url_string: T.nilable(String)).returns(T.nilable(Source)) }
|
80
108
|
def self.github_enterprise_from_url(url_string)
|
81
109
|
captures = url_string&.match(GITHUB_ENTERPRISE_SOURCE)&.named_captures
|
82
110
|
return unless captures
|
@@ -88,7 +116,7 @@ module Dependabot
|
|
88
116
|
|
89
117
|
new(
|
90
118
|
provider: "github",
|
91
|
-
repo: captures.fetch("repo").delete_suffix(".git").delete_suffix("."),
|
119
|
+
repo: T.must(captures.fetch("repo")).delete_suffix(".git").delete_suffix("."),
|
92
120
|
directory: captures.fetch("directory"),
|
93
121
|
branch: captures.fetch("branch"),
|
94
122
|
hostname: captures.fetch("host"),
|
@@ -96,18 +124,30 @@ module Dependabot
|
|
96
124
|
)
|
97
125
|
end
|
98
126
|
|
127
|
+
sig { params(base_url: String).returns(T::Boolean) }
|
99
128
|
def self.github_enterprise?(base_url)
|
100
129
|
resp = Excon.get(File.join(base_url, "status"))
|
101
130
|
resp.status == 200 &&
|
102
131
|
# Alternatively: resp.headers["Server"] == "GitHub.com", but this
|
103
132
|
# currently doesn't work with development environments
|
104
|
-
resp.headers["X-GitHub-Request-Id"] &&
|
105
|
-
!resp.headers["X-GitHub-Request-Id"].empty?
|
133
|
+
((resp.headers["X-GitHub-Request-Id"] && !resp.headers["X-GitHub-Request-Id"]&.empty?) || false)
|
106
134
|
rescue StandardError
|
107
135
|
false
|
108
136
|
end
|
109
137
|
|
110
|
-
|
138
|
+
sig do
|
139
|
+
params(
|
140
|
+
provider: String,
|
141
|
+
repo: String,
|
142
|
+
directory: T.nilable(String),
|
143
|
+
directories: T.nilable(T::Array[String]),
|
144
|
+
branch: T.nilable(String),
|
145
|
+
commit: T.nilable(String),
|
146
|
+
hostname: T.nilable(String),
|
147
|
+
api_endpoint: T.nilable(String)
|
148
|
+
).void
|
149
|
+
end
|
150
|
+
def initialize(provider:, repo:, directory: nil, directories: nil, branch: nil, commit: nil,
|
111
151
|
hostname: nil, api_endpoint: nil)
|
112
152
|
if (hostname.nil? ^ api_endpoint.nil?) && (provider != "codecommit")
|
113
153
|
msg = "Both hostname and api_endpoint must be specified if either " \
|
@@ -119,16 +159,19 @@ module Dependabot
|
|
119
159
|
@provider = provider
|
120
160
|
@repo = repo
|
121
161
|
@directory = directory
|
162
|
+
@directories = directories
|
122
163
|
@branch = branch
|
123
164
|
@commit = commit
|
124
|
-
@hostname = hostname || default_hostname(provider)
|
125
|
-
@api_endpoint = api_endpoint || default_api_endpoint(provider)
|
165
|
+
@hostname = T.let(hostname || default_hostname(provider), String)
|
166
|
+
@api_endpoint = T.let(api_endpoint || default_api_endpoint(provider), T.nilable(String))
|
126
167
|
end
|
127
168
|
|
169
|
+
sig { returns(String) }
|
128
170
|
def url
|
129
171
|
"https://" + hostname + "/" + repo
|
130
172
|
end
|
131
173
|
|
174
|
+
sig { returns(String) }
|
132
175
|
def url_with_directory
|
133
176
|
return url if [nil, ".", "/"].include?(directory)
|
134
177
|
|
@@ -149,25 +192,29 @@ module Dependabot
|
|
149
192
|
end
|
150
193
|
end
|
151
194
|
|
195
|
+
sig { returns(String) }
|
152
196
|
def organization
|
153
|
-
repo.split("/").first
|
197
|
+
T.must(repo.split("/").first)
|
154
198
|
end
|
155
199
|
|
200
|
+
sig { returns(String) }
|
156
201
|
def project
|
157
202
|
raise "Project is an Azure DevOps concept only" unless provider == "azure"
|
158
203
|
|
159
204
|
parts = repo.split("/_git/")
|
160
|
-
return parts.first.split("/").last if parts.first
|
205
|
+
return T.must(T.must(parts.first).split("/").last) if parts.first&.split("/")&.count == 2
|
161
206
|
|
162
|
-
parts.last
|
207
|
+
T.must(parts.last)
|
163
208
|
end
|
164
209
|
|
210
|
+
sig { returns(String) }
|
165
211
|
def unscoped_repo
|
166
|
-
repo.split("/").last
|
212
|
+
T.must(repo.split("/").last)
|
167
213
|
end
|
168
214
|
|
169
215
|
private
|
170
216
|
|
217
|
+
sig { params(provider: String).returns(String) }
|
171
218
|
def default_hostname(provider)
|
172
219
|
case provider
|
173
220
|
when "github" then "github.com"
|
@@ -179,6 +226,7 @@ module Dependabot
|
|
179
226
|
end
|
180
227
|
end
|
181
228
|
|
229
|
+
sig { params(provider: String).returns(T.nilable(String)) }
|
182
230
|
def default_api_endpoint(provider)
|
183
231
|
case provider
|
184
232
|
when "github" then "https://api.github.com/"
|
@@ -1,9 +1,20 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strong
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
4
6
|
module Dependabot
|
5
7
|
module UpdateCheckers
|
6
8
|
module VersionFilters
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
sig do
|
12
|
+
params(
|
13
|
+
versions_array: T::Array[T.any(Gem::Version, T::Hash[Symbol, String])],
|
14
|
+
security_advisories: T::Array[SecurityAdvisory]
|
15
|
+
)
|
16
|
+
.returns(T::Array[T.any(Gem::Version, T::Hash[Symbol, String])])
|
17
|
+
end
|
7
18
|
def self.filter_vulnerable_versions(versions_array, security_advisories)
|
8
19
|
versions_array.reject do |v|
|
9
20
|
security_advisories.any? do |a|
|
data/lib/dependabot/utils.rb
CHANGED
@@ -5,6 +5,7 @@ require "tmpdir"
|
|
5
5
|
require "set"
|
6
6
|
require "sorbet-runtime"
|
7
7
|
require "dependabot/version"
|
8
|
+
require "dependabot/config/file"
|
8
9
|
|
9
10
|
# TODO: in due course, these "registries" should live in a wrapper gem, not
|
10
11
|
# dependabot-core.
|
@@ -22,11 +23,13 @@ module Dependabot
|
|
22
23
|
version_class = @version_classes[package_manager]
|
23
24
|
return version_class if version_class
|
24
25
|
|
25
|
-
raise "
|
26
|
+
raise "Unregistered package_manager #{package_manager}"
|
26
27
|
end
|
27
28
|
|
28
29
|
sig { params(package_manager: String, version_class: T.class_of(Dependabot::Version)).void }
|
29
30
|
def self.register_version_class(package_manager, version_class)
|
31
|
+
validate_package_manager!(package_manager)
|
32
|
+
|
30
33
|
@version_classes[package_manager] = version_class
|
31
34
|
end
|
32
35
|
|
@@ -37,11 +40,13 @@ module Dependabot
|
|
37
40
|
requirement_class = @requirement_classes[package_manager]
|
38
41
|
return requirement_class if requirement_class
|
39
42
|
|
40
|
-
raise "
|
43
|
+
raise "Unregistered package_manager #{package_manager}"
|
41
44
|
end
|
42
45
|
|
43
46
|
sig { params(package_manager: String, requirement_class: T.class_of(Gem::Requirement)).void }
|
44
47
|
def self.register_requirement_class(package_manager, requirement_class)
|
48
|
+
validate_package_manager!(package_manager)
|
49
|
+
|
45
50
|
@requirement_classes[package_manager] = requirement_class
|
46
51
|
end
|
47
52
|
|
@@ -54,7 +59,21 @@ module Dependabot
|
|
54
59
|
|
55
60
|
sig { params(package_manager: String).void }
|
56
61
|
def self.register_always_clone(package_manager)
|
62
|
+
validate_package_manager!(package_manager)
|
63
|
+
|
57
64
|
@cloning_package_managers << package_manager
|
58
65
|
end
|
66
|
+
|
67
|
+
sig { params(package_manager: String).void }
|
68
|
+
def self.validate_package_manager!(package_manager)
|
69
|
+
# Official package manager
|
70
|
+
return if Config::File::PACKAGE_MANAGER_LOOKUP.invert.key?(package_manager)
|
71
|
+
|
72
|
+
# Used by specs
|
73
|
+
return if package_manager == "dummy"
|
74
|
+
|
75
|
+
raise "Unsupported package_manager #{package_manager}"
|
76
|
+
end
|
77
|
+
private_class_method :validate_package_manager!
|
59
78
|
end
|
60
79
|
end
|
@@ -1,29 +1,53 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
4
6
|
module Dependabot
|
5
7
|
module Workspace
|
6
8
|
class Base
|
7
|
-
|
9
|
+
extend T::Sig
|
10
|
+
extend T::Helpers
|
11
|
+
extend T::Generic
|
12
|
+
|
13
|
+
abstract!
|
14
|
+
|
15
|
+
sig { returns(T::Array[Dependabot::Workspace::ChangeAttempt]) }
|
16
|
+
attr_reader :change_attempts
|
8
17
|
|
18
|
+
sig { returns(T.any(Pathname, String)) }
|
19
|
+
attr_reader :path
|
20
|
+
|
21
|
+
sig { params(path: T.any(Pathname, String)).void }
|
9
22
|
def initialize(path)
|
10
23
|
@path = path
|
11
|
-
@change_attempts = []
|
24
|
+
@change_attempts = T.let([], T::Array[Dependabot::Workspace::ChangeAttempt])
|
12
25
|
end
|
13
26
|
|
27
|
+
sig { returns(T::Boolean) }
|
14
28
|
def changed?
|
15
29
|
changes.any?
|
16
30
|
end
|
17
31
|
|
32
|
+
sig { returns(T::Array[Dependabot::Workspace::ChangeAttempt]) }
|
18
33
|
def changes
|
19
34
|
change_attempts.select(&:success?)
|
20
35
|
end
|
21
36
|
|
37
|
+
sig { returns(T::Array[Dependabot::Workspace::ChangeAttempt]) }
|
22
38
|
def failed_change_attempts
|
23
39
|
change_attempts.select(&:error?)
|
24
40
|
end
|
25
41
|
|
26
|
-
|
42
|
+
sig do
|
43
|
+
type_parameters(:T)
|
44
|
+
.params(
|
45
|
+
memo: T.nilable(String),
|
46
|
+
_blk: T.proc.params(arg0: T.any(Pathname, String)).returns(T.type_parameter(:T))
|
47
|
+
)
|
48
|
+
.returns(T.type_parameter(:T))
|
49
|
+
end
|
50
|
+
def change(memo = nil, &_blk)
|
27
51
|
Dir.chdir(path) { yield(path) }
|
28
52
|
rescue StandardError => e
|
29
53
|
capture_failed_change_attempt(memo, e)
|
@@ -31,17 +55,28 @@ module Dependabot
|
|
31
55
|
raise e
|
32
56
|
end
|
33
57
|
|
58
|
+
sig do
|
59
|
+
abstract.params(memo: T.nilable(String)).returns(T.nilable(T::Array[Dependabot::Workspace::ChangeAttempt]))
|
60
|
+
end
|
34
61
|
def store_change(memo = nil); end
|
35
62
|
|
36
|
-
|
37
|
-
|
38
|
-
end
|
63
|
+
sig { abstract.returns(String) }
|
64
|
+
def to_patch; end
|
39
65
|
|
66
|
+
sig { abstract.returns(NilClass) }
|
40
67
|
def reset!; end
|
41
68
|
|
42
69
|
protected
|
43
70
|
|
71
|
+
sig do
|
72
|
+
abstract
|
73
|
+
.params(memo: T.nilable(String), error: T.nilable(StandardError))
|
74
|
+
.returns(T.nilable(T::Array[Dependabot::Workspace::ChangeAttempt]))
|
75
|
+
end
|
44
76
|
def capture_failed_change_attempt(memo = nil, error = nil); end
|
77
|
+
|
78
|
+
sig { abstract.returns(String) }
|
79
|
+
def clean; end
|
45
80
|
end
|
46
81
|
end
|
47
82
|
end
|