dependabot-composer 0.310.0 → 0.311.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/composer/file_fetcher.rb +50 -18
- data/lib/dependabot/composer/file_updater/lockfile_updater.rb +138 -49
- data/lib/dependabot/composer/file_updater/manifest_updater.rb +29 -10
- data/lib/dependabot/composer/file_updater.rb +1 -1
- data/lib/dependabot/composer/metadata_finder.rb +18 -1
- data/lib/dependabot/composer/version.rb +8 -2
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b7f9286dece3b3c0c35b5be85a580078a6467edb4dd43b9817601f541b5c2cf
|
4
|
+
data.tar.gz: 4d31a01b968c789451178cee2855a6e507fad696663bac7e01cc89103b6a5c0c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb35c79db05afba4a18eceb83722484488031b68503975dd13df219b3eaba3d98d931bb0850dd74f2c5a3023689441e436083f01e81a188bd1db897840496a86
|
7
|
+
data.tar.gz: d963a5ccdc05bc63e3ee72b6d59bd8e9e8eedd3ac71d3a7da457d803ccd9ff618cf2d68c5da1e6e6707606cbbc1d094664dbc2d386fe3ca22ace4116eaa3a5cd
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "json"
|
@@ -15,14 +15,17 @@ module Dependabot
|
|
15
15
|
require_relative "file_fetcher/path_dependency_builder"
|
16
16
|
require_relative "helpers"
|
17
17
|
|
18
|
+
sig { override.params(filenames: T::Array[String]).returns(T::Boolean) }
|
18
19
|
def self.required_files_in?(filenames)
|
19
20
|
filenames.include?(PackageManager::MANIFEST_FILENAME)
|
20
21
|
end
|
21
22
|
|
23
|
+
sig { override.returns(String) }
|
22
24
|
def self.required_files_message
|
23
25
|
"Repo must contain a #{PackageManager::MANIFEST_FILENAME}."
|
24
26
|
end
|
25
27
|
|
28
|
+
sig { override.returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
26
29
|
def ecosystem_versions
|
27
30
|
{
|
28
31
|
package_managers: {
|
@@ -44,28 +47,35 @@ module Dependabot
|
|
44
47
|
|
45
48
|
private
|
46
49
|
|
50
|
+
sig { returns(Dependabot::DependencyFile) }
|
47
51
|
def composer_json
|
48
|
-
@composer_json ||=
|
52
|
+
@composer_json ||= T.let(
|
53
|
+
fetch_file_from_host(PackageManager::MANIFEST_FILENAME),
|
54
|
+
T.nilable(Dependabot::DependencyFile)
|
55
|
+
)
|
49
56
|
end
|
50
57
|
|
58
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
51
59
|
def composer_lock
|
52
|
-
|
53
|
-
|
54
|
-
|
60
|
+
@composer_lock ||= T.let(
|
61
|
+
fetch_file_if_present(PackageManager::LOCKFILE_FILENAME),
|
62
|
+
T.nilable(Dependabot::DependencyFile)
|
63
|
+
)
|
55
64
|
end
|
56
65
|
|
57
66
|
# NOTE: This is fetched but currently unused
|
67
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
58
68
|
def auth_json
|
59
|
-
|
60
|
-
|
61
|
-
|
69
|
+
@auth_json ||= T.let(
|
70
|
+
fetch_support_file(PackageManager::AUTH_FILENAME),
|
71
|
+
T.nilable(Dependabot::DependencyFile)
|
72
|
+
)
|
62
73
|
end
|
63
74
|
|
75
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
64
76
|
def artifact_dependencies
|
65
|
-
return @artifact_dependencies if defined?(@artifact_dependencies)
|
66
|
-
|
67
77
|
# Find zip files in the artifact sources and download them.
|
68
|
-
@artifact_dependencies
|
78
|
+
@artifact_dependencies ||= T.let(
|
69
79
|
artifact_sources.map do |url|
|
70
80
|
repo_contents(dir: url)
|
71
81
|
.select { |file| file.type == "file" && file.name.end_with?(".zip") }
|
@@ -78,7 +88,9 @@ module Dependabot
|
|
78
88
|
type: "file"
|
79
89
|
)
|
80
90
|
end
|
81
|
-
end.flatten
|
91
|
+
end.flatten,
|
92
|
+
T.nilable(T::Array[Dependabot::DependencyFile])
|
93
|
+
)
|
82
94
|
|
83
95
|
# Add .gitkeep to all directories in case they are empty. Composer isn't ok with empty directories.
|
84
96
|
@artifact_dependencies += artifact_sources.map do |url|
|
@@ -96,8 +108,9 @@ module Dependabot
|
|
96
108
|
@artifact_dependencies
|
97
109
|
end
|
98
110
|
|
111
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
99
112
|
def path_dependencies
|
100
|
-
@path_dependencies ||=
|
113
|
+
@path_dependencies ||= T.let(
|
101
114
|
begin
|
102
115
|
composer_json_files = []
|
103
116
|
unfetchable_deps = []
|
@@ -123,19 +136,24 @@ module Dependabot
|
|
123
136
|
composer_json_files.tap do |files|
|
124
137
|
files.each { |f| f.support_file = true }
|
125
138
|
end
|
126
|
-
end
|
139
|
+
end,
|
140
|
+
T.nilable(T::Array[Dependabot::DependencyFile])
|
141
|
+
)
|
127
142
|
end
|
128
143
|
|
144
|
+
sig { returns(T::Array[String]) }
|
129
145
|
def artifact_sources
|
130
146
|
sources.select { |details| details["type"] == "artifact" }.map { |details| details["url"] }
|
131
147
|
end
|
132
148
|
|
149
|
+
sig { returns(T::Array[String]) }
|
133
150
|
def path_sources
|
134
151
|
sources.select { |details| details["type"] == "path" }.map { |details| details["url"] }
|
135
152
|
end
|
136
153
|
|
154
|
+
sig { returns(T::Array[T::Hash[String, T.untyped]]) }
|
137
155
|
def sources
|
138
|
-
@sources ||=
|
156
|
+
@sources ||= T.let(
|
139
157
|
begin
|
140
158
|
repos = parsed_composer_json.fetch("repositories", [])
|
141
159
|
if repos.is_a?(Hash) || repos.is_a?(Array)
|
@@ -147,9 +165,12 @@ module Dependabot
|
|
147
165
|
else
|
148
166
|
[]
|
149
167
|
end
|
150
|
-
end
|
168
|
+
end,
|
169
|
+
T.nilable(T::Array[T::Hash[String, T.untyped]])
|
170
|
+
)
|
151
171
|
end
|
152
172
|
|
173
|
+
sig { params(unfetchable_deps: T::Array[String]).returns(T::Array[Dependabot::DependencyFile]) }
|
153
174
|
def build_unfetchable_deps(unfetchable_deps)
|
154
175
|
unfetchable_deps.filter_map do |path|
|
155
176
|
PathDependencyBuilder.new(
|
@@ -160,6 +181,7 @@ module Dependabot
|
|
160
181
|
end
|
161
182
|
end
|
162
183
|
|
184
|
+
sig { params(path: String).returns(T::Array[String]) }
|
163
185
|
def expand_path(path)
|
164
186
|
wildcard_depth = 0
|
165
187
|
path = path.gsub(/\*$/, "")
|
@@ -185,6 +207,7 @@ module Dependabot
|
|
185
207
|
.select { |p| p.to_s.start_with?(path.gsub(/\*$/, "")) }
|
186
208
|
end
|
187
209
|
|
210
|
+
sig { returns(T::Array[String]) }
|
188
211
|
def lockfile_path_dependency_paths
|
189
212
|
keys = FileParser::DEPENDENCY_GROUP_KEYS
|
190
213
|
.map { |h| h.fetch(:lockfile) }
|
@@ -198,20 +221,29 @@ module Dependabot
|
|
198
221
|
end
|
199
222
|
end
|
200
223
|
|
224
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
201
225
|
def parsed_composer_json
|
202
|
-
@parsed_composer_json ||=
|
226
|
+
@parsed_composer_json ||= T.let(
|
227
|
+
JSON.parse(T.must(composer_json.content)),
|
228
|
+
T.nilable(T::Hash[String, T.untyped])
|
229
|
+
)
|
203
230
|
rescue JSON::ParserError
|
204
231
|
raise Dependabot::DependencyFileNotParseable, composer_json.path
|
205
232
|
end
|
206
233
|
|
234
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
207
235
|
def parsed_lockfile
|
208
236
|
return {} unless composer_lock
|
209
237
|
|
210
|
-
@parsed_lockfile ||=
|
238
|
+
@parsed_lockfile ||= T.let(
|
239
|
+
JSON.parse(T.must(T.must(composer_lock).content)),
|
240
|
+
T.nilable(T::Hash[String, T.untyped])
|
241
|
+
)
|
211
242
|
rescue JSON::ParserError
|
212
243
|
{}
|
213
244
|
end
|
214
245
|
|
246
|
+
sig { params(filename: String).returns(Dependabot::DependencyFile) }
|
215
247
|
def fetch_file_with_root_fallback(filename)
|
216
248
|
path = Pathname.new(File.join(directory, filename)).cleanpath.to_path
|
217
249
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "dependabot/shared_helpers"
|
@@ -10,19 +10,26 @@ require "dependabot/composer/requirement"
|
|
10
10
|
require "dependabot/composer/native_helpers"
|
11
11
|
require "dependabot/composer/helpers"
|
12
12
|
require "dependabot/composer/update_checker/version_resolver"
|
13
|
+
require "sorbet-runtime"
|
13
14
|
|
14
15
|
# rubocop:disable Metrics/ClassLength
|
15
16
|
module Dependabot
|
16
17
|
module Composer
|
17
18
|
class FileUpdater
|
18
19
|
class LockfileUpdater
|
20
|
+
extend T::Sig
|
21
|
+
|
19
22
|
require_relative "manifest_updater"
|
20
23
|
|
21
24
|
class MissingExtensions < StandardError
|
25
|
+
extend T::Sig
|
26
|
+
|
27
|
+
sig { returns(T::Array[T::Hash[Symbol, String]]) }
|
22
28
|
attr_reader :extensions
|
23
29
|
|
30
|
+
sig { params(extensions: T::Array[T::Hash[Symbol, String]]).void }
|
24
31
|
def initialize(extensions)
|
25
|
-
@extensions = extensions
|
32
|
+
@extensions = T.let(extensions, T::Array[T::Hash[Symbol, String]])
|
26
33
|
super
|
27
34
|
end
|
28
35
|
end
|
@@ -39,15 +46,27 @@ module Dependabot
|
|
39
46
|
}x
|
40
47
|
MISSING_ENV_VAR_REGEX = /Environment variable '(?<env_var>.[^']+)' is not set/
|
41
48
|
|
49
|
+
sig do
|
50
|
+
params(
|
51
|
+
dependencies: T::Array[Dependabot::Dependency],
|
52
|
+
dependency_files: T::Array[Dependabot::DependencyFile],
|
53
|
+
credentials: T::Array[Dependabot::Credential]
|
54
|
+
).void
|
55
|
+
end
|
42
56
|
def initialize(dependencies:, dependency_files:, credentials:)
|
43
57
|
@dependencies = dependencies
|
44
58
|
@dependency_files = dependency_files
|
45
59
|
@credentials = credentials
|
46
|
-
@composer_platform_extensions = initial_platform
|
60
|
+
@composer_platform_extensions = T.let(initial_platform, T::Hash[String, T::Array[String]])
|
61
|
+
@lock_git_deps = T.let(true, T::Boolean)
|
47
62
|
end
|
48
63
|
|
64
|
+
sig { returns(String) }
|
49
65
|
def updated_lockfile_content
|
50
|
-
@updated_lockfile_content ||=
|
66
|
+
@updated_lockfile_content ||= T.let(
|
67
|
+
generate_updated_lockfile_content,
|
68
|
+
T.nilable(String)
|
69
|
+
)
|
51
70
|
rescue MissingExtensions => e
|
52
71
|
previous_extensions = composer_platform_extensions.dup
|
53
72
|
update_required_extensions(e.extensions)
|
@@ -58,13 +77,21 @@ module Dependabot
|
|
58
77
|
|
59
78
|
private
|
60
79
|
|
80
|
+
sig { returns(T::Array[Dependabot::Dependency]) }
|
61
81
|
attr_reader :dependencies
|
82
|
+
|
83
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
62
84
|
attr_reader :dependency_files
|
85
|
+
|
86
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
63
87
|
attr_reader :credentials
|
88
|
+
|
89
|
+
sig { returns(T::Hash[String, T::Array[String]]) }
|
64
90
|
attr_reader :composer_platform_extensions
|
65
91
|
|
92
|
+
sig { returns(String) }
|
66
93
|
def generate_updated_lockfile_content
|
67
|
-
base_directory = dependency_files.first.directory
|
94
|
+
base_directory = T.must(dependency_files.first).directory
|
68
95
|
SharedHelpers.in_a_temporary_directory(base_directory) do
|
69
96
|
write_temporary_dependency_files
|
70
97
|
|
@@ -87,13 +114,15 @@ module Dependabot
|
|
87
114
|
handle_composer_errors(e)
|
88
115
|
end
|
89
116
|
|
117
|
+
sig { returns(Dependabot::Dependency) }
|
90
118
|
def dependency
|
91
119
|
# For now, we'll only ever be updating a single dependency for PHP
|
92
|
-
dependencies.first
|
120
|
+
T.must(dependencies.first)
|
93
121
|
end
|
94
122
|
|
123
|
+
sig { returns(T::Hash[String, String]) }
|
95
124
|
def run_update_helper
|
96
|
-
SharedHelpers.with_git_configured(credentials: credentials) do
|
125
|
+
SharedHelpers.with_git_configured(credentials: T.unsafe(credentials)) do
|
97
126
|
SharedHelpers.run_helper_subprocess(
|
98
127
|
command: "php -d memory_limit=-1 #{php_helper_path}",
|
99
128
|
allow_unsafe_shell_command: true,
|
@@ -110,6 +139,7 @@ module Dependabot
|
|
110
139
|
end
|
111
140
|
end
|
112
141
|
|
142
|
+
sig { returns(String) }
|
113
143
|
def updated_composer_json_content
|
114
144
|
ManifestUpdater.new(
|
115
145
|
dependencies: dependencies,
|
@@ -117,6 +147,7 @@ module Dependabot
|
|
117
147
|
).updated_manifest_content
|
118
148
|
end
|
119
149
|
|
150
|
+
sig { params(error: SharedHelpers::HelperSubprocessFailed).returns(T::Boolean) }
|
120
151
|
def transitory_failure?(error)
|
121
152
|
return true if error.message.include?("404 Not Found")
|
122
153
|
return true if error.message.include?("timed out")
|
@@ -125,6 +156,7 @@ module Dependabot
|
|
125
156
|
error.message.include?("Content-Length mismatch")
|
126
157
|
end
|
127
158
|
|
159
|
+
sig { params(error: SharedHelpers::HelperSubprocessFailed).returns(T::Boolean) }
|
128
160
|
def locked_git_dep_error?(error)
|
129
161
|
error.message.start_with?("Could not authenticate against")
|
130
162
|
end
|
@@ -135,6 +167,7 @@ module Dependabot
|
|
135
167
|
# rubocop:disable Metrics/CyclomaticComplexity
|
136
168
|
# rubocop:disable Metrics/MethodLength
|
137
169
|
# rubocop:disable Metrics/PerceivedComplexity
|
170
|
+
sig { params(error: SharedHelpers::HelperSubprocessFailed).returns(T.noreturn) }
|
138
171
|
def handle_composer_errors(error)
|
139
172
|
if error.message.match?(MISSING_EXPLICIT_PLATFORM_REQ_REGEX)
|
140
173
|
# These errors occur when platform requirements declared explicitly
|
@@ -142,7 +175,7 @@ module Dependabot
|
|
142
175
|
missing_extensions =
|
143
176
|
error.message.scan(MISSING_EXPLICIT_PLATFORM_REQ_REGEX)
|
144
177
|
.map do |extension_string|
|
145
|
-
name, requirement = extension_string.strip.split(" ", 2)
|
178
|
+
name, requirement = T.cast(extension_string, String).strip.split(" ", 2)
|
146
179
|
{ name: name, requirement: requirement }
|
147
180
|
end
|
148
181
|
raise MissingExtensions, missing_extensions
|
@@ -153,7 +186,7 @@ module Dependabot
|
|
153
186
|
missing_extensions =
|
154
187
|
error.message.scan(MISSING_IMPLICIT_PLATFORM_REQ_REGEX)
|
155
188
|
.map do |extension_string|
|
156
|
-
name, requirement = extension_string.strip.split(" ", 2)
|
189
|
+
name, requirement = T.cast(extension_string, String).strip.split(" ", 2)
|
157
190
|
{ name: name, requirement: requirement }
|
158
191
|
end
|
159
192
|
|
@@ -162,10 +195,10 @@ module Dependabot
|
|
162
195
|
version_for_reqs(existing_reqs + [hash[:requirement]])
|
163
196
|
end
|
164
197
|
|
165
|
-
raise MissingExtensions, [
|
198
|
+
raise MissingExtensions, (T.must(missing_extension).then { |ext| [ext] })
|
166
199
|
end
|
167
200
|
|
168
|
-
|
201
|
+
git_dependency_reference_error(error) if error.message.start_with?("Failed to execute git checkout")
|
169
202
|
|
170
203
|
# Special case for Laravel Nova, which will fall back to attempting
|
171
204
|
# to close a private repo if given invalid (or no) credentials
|
@@ -185,9 +218,10 @@ module Dependabot
|
|
185
218
|
|
186
219
|
# NOTE: This matches error output from a composer plugin (private-composer-installer):
|
187
220
|
# https://github.com/ffraenz/private-composer-installer/blob/8655e3da4e8f99203f13ccca33b9ab953ad30a31/src/Exception/MissingEnvException.php#L22
|
188
|
-
|
189
|
-
|
190
|
-
|
221
|
+
match_data = error.message.match(MISSING_ENV_VAR_REGEX)
|
222
|
+
if match_data
|
223
|
+
env_var = match_data.named_captures.fetch("env_var")
|
224
|
+
raise MissingEnvironmentVariable, T.must(env_var)
|
191
225
|
end
|
192
226
|
|
193
227
|
if error.message.start_with?("Unknown downloader type: npm-sign") ||
|
@@ -198,9 +232,9 @@ module Dependabot
|
|
198
232
|
|
199
233
|
raise Dependabot::OutOfMemory if error.message.start_with?("Allowed memory size")
|
200
234
|
|
201
|
-
|
202
|
-
|
203
|
-
|
235
|
+
match_data = error.message.match(%r{https?://(?<source>[^/]+)/})
|
236
|
+
if error.message.include?("403 Forbidden") && match_data
|
237
|
+
source = match_data.named_captures.fetch("source")
|
204
238
|
raise PrivateSourceAuthenticationFailure, source
|
205
239
|
end
|
206
240
|
|
@@ -217,15 +251,17 @@ module Dependabot
|
|
217
251
|
# rubocop:enable Metrics/MethodLength
|
218
252
|
# rubocop:enable Metrics/PerceivedComplexity
|
219
253
|
|
254
|
+
sig { returns(T::Boolean) }
|
220
255
|
def library?
|
221
256
|
parsed_composer_json["type"] == "library"
|
222
257
|
end
|
223
258
|
|
259
|
+
sig { params(message: String).returns(T::Boolean) }
|
224
260
|
def implicit_platform_reqs_satisfiable?(message)
|
225
261
|
missing_extensions =
|
226
262
|
message.scan(MISSING_IMPLICIT_PLATFORM_REQ_REGEX)
|
227
263
|
.map do |extension_string|
|
228
|
-
name, requirement = extension_string.strip.split(" ", 2)
|
264
|
+
name, requirement = T.cast(extension_string, String).strip.split(" ", 2)
|
229
265
|
{ name: name, requirement: requirement }
|
230
266
|
end
|
231
267
|
|
@@ -235,6 +271,7 @@ module Dependabot
|
|
235
271
|
end
|
236
272
|
end
|
237
273
|
|
274
|
+
sig { void }
|
238
275
|
def write_temporary_dependency_files
|
239
276
|
artifact_dependencies.each do |file|
|
240
277
|
path = file.name
|
@@ -250,9 +287,10 @@ module Dependabot
|
|
250
287
|
|
251
288
|
File.write(PackageManager::MANIFEST_FILENAME, locked_composer_json_content)
|
252
289
|
File.write(PackageManager::LOCKFILE_FILENAME, lockfile.content)
|
253
|
-
File.write(PackageManager::AUTH_FILENAME, auth_json.content) if auth_json
|
290
|
+
File.write(PackageManager::AUTH_FILENAME, T.must(auth_json).content) if auth_json
|
254
291
|
end
|
255
292
|
|
293
|
+
sig { returns(String) }
|
256
294
|
def locked_composer_json_content
|
257
295
|
content = updated_composer_json_content
|
258
296
|
content = lock_dependencies_being_updated(content)
|
@@ -261,6 +299,7 @@ module Dependabot
|
|
261
299
|
content
|
262
300
|
end
|
263
301
|
|
302
|
+
sig { params(content: String).returns(String) }
|
264
303
|
def add_temporary_platform_extensions(content)
|
265
304
|
json = JSON.parse(content)
|
266
305
|
|
@@ -274,6 +313,7 @@ module Dependabot
|
|
274
313
|
JSON.dump(json)
|
275
314
|
end
|
276
315
|
|
316
|
+
sig { params(original_content: String).returns(String) }
|
277
317
|
def lock_dependencies_being_updated(original_content)
|
278
318
|
dependencies.reduce(original_content) do |content, dep|
|
279
319
|
updated_req = dep.version
|
@@ -298,6 +338,7 @@ module Dependabot
|
|
298
338
|
end
|
299
339
|
end
|
300
340
|
|
341
|
+
sig { params(content: String).returns(String) }
|
301
342
|
def lock_git_dependencies(content)
|
302
343
|
json = JSON.parse(content)
|
303
344
|
|
@@ -309,7 +350,7 @@ module Dependabot
|
|
309
350
|
next if req.include?("#")
|
310
351
|
|
311
352
|
commit_sha = parsed_lockfile
|
312
|
-
.fetch(keys[:lockfile], [])
|
353
|
+
.fetch(T.must(keys[:lockfile]), [])
|
313
354
|
.find { |d| d["name"] == name }
|
314
355
|
&.dig("source", "reference")
|
315
356
|
updated_req_parts = req.split
|
@@ -321,11 +362,13 @@ module Dependabot
|
|
321
362
|
JSON.dump(json)
|
322
363
|
end
|
323
364
|
|
365
|
+
sig { params(error: SharedHelpers::HelperSubprocessFailed).returns(T.noreturn) }
|
324
366
|
def git_dependency_reference_error(error)
|
325
367
|
ref = error.message.match(/checkout '(?<ref>.*?)'/)
|
326
|
-
|
368
|
+
&.named_captures
|
369
|
+
&.fetch("ref")
|
327
370
|
dependency_name =
|
328
|
-
JSON.parse(lockfile.content)
|
371
|
+
JSON.parse(T.must(lockfile.content))
|
329
372
|
.values_at("packages", "packages-dev").flatten(1)
|
330
373
|
.find { |dep| dep.dig("source", "reference") == ref }
|
331
374
|
&.fetch("name")
|
@@ -335,23 +378,20 @@ module Dependabot
|
|
335
378
|
raise GitDependencyReferenceNotFound, dependency_name
|
336
379
|
end
|
337
380
|
|
338
|
-
|
339
|
-
content = replace_patches(content)
|
340
|
-
content = replace_content_hash(content)
|
341
|
-
replace_platform_overrides(content)
|
342
|
-
end
|
343
|
-
|
381
|
+
sig { params(updated_content: String).returns(String) }
|
344
382
|
def replace_patches(updated_content)
|
345
383
|
content = updated_content
|
346
384
|
%w(packages packages-dev).each do |package_type|
|
347
|
-
JSON.parse(lockfile.content)
|
385
|
+
JSON.parse(T.must(lockfile.content))
|
386
|
+
.fetch(package_type, [])
|
387
|
+
.each do |details|
|
348
388
|
next unless details["extra"].is_a?(Hash)
|
349
389
|
next unless (patches = details.dig("extra", "patches_applied"))
|
350
390
|
|
351
391
|
updated_object = JSON.parse(content)
|
352
392
|
updated_object_package =
|
353
393
|
updated_object
|
354
|
-
.fetch(package_type)
|
394
|
+
.fetch(package_type, [])
|
355
395
|
.find { |d| d["name"] == details["name"] }
|
356
396
|
|
357
397
|
next unless updated_object_package
|
@@ -360,14 +400,18 @@ module Dependabot
|
|
360
400
|
updated_object_package["extra"]["patches_applied"] = patches
|
361
401
|
|
362
402
|
content =
|
363
|
-
|
403
|
+
T.cast(
|
404
|
+
JSON.pretty_generate(updated_object, indent: " ")
|
364
405
|
.gsub(/\[\n\n\s*\]/, "[]")
|
365
|
-
.gsub(/\}\z/, "}\n")
|
406
|
+
.gsub(/\}\z/, "}\n"),
|
407
|
+
String
|
408
|
+
)
|
366
409
|
end
|
367
410
|
end
|
368
411
|
content
|
369
412
|
end
|
370
413
|
|
414
|
+
sig { params(content: String).returns(String) }
|
371
415
|
def replace_content_hash(content)
|
372
416
|
existing_hash = JSON.parse(content).fetch("content-hash")
|
373
417
|
SharedHelpers.in_a_temporary_directory do
|
@@ -385,8 +429,9 @@ module Dependabot
|
|
385
429
|
end
|
386
430
|
end
|
387
431
|
|
432
|
+
sig { params(content: String).returns(String) }
|
388
433
|
def replace_platform_overrides(content)
|
389
|
-
original_object = JSON.parse(lockfile.content)
|
434
|
+
original_object = JSON.parse(T.must(lockfile.content))
|
390
435
|
original_overrides = original_object.fetch("platform-overrides", nil)
|
391
436
|
|
392
437
|
updated_object = JSON.parse(content)
|
@@ -402,6 +447,7 @@ module Dependabot
|
|
402
447
|
.gsub(/\}\z/, "}\n")
|
403
448
|
end
|
404
449
|
|
450
|
+
sig { params(requirements: T::Array[String]).returns(String) }
|
405
451
|
def version_for_reqs(requirements)
|
406
452
|
req_arrays =
|
407
453
|
requirements
|
@@ -426,42 +472,60 @@ module Dependabot
|
|
426
472
|
version.to_s
|
427
473
|
end
|
428
474
|
|
475
|
+
sig { params(additional_extensions: T::Array[T::Hash[Symbol, String]]).void }
|
429
476
|
def update_required_extensions(additional_extensions)
|
430
477
|
additional_extensions.each do |ext|
|
431
478
|
composer_platform_extensions[ext.fetch(:name)] ||= []
|
432
|
-
composer_platform_extensions[ext.fetch(:name)]
|
433
|
-
|
479
|
+
existing_reqs = composer_platform_extensions[ext.fetch(:name)]
|
480
|
+
composer_platform_extensions[ext.fetch(:name)] =
|
481
|
+
T.must(existing_reqs) + [ext.fetch(:requirement)]
|
434
482
|
composer_platform_extensions[ext.fetch(:name)] =
|
435
|
-
composer_platform_extensions[ext.fetch(:name)].uniq
|
483
|
+
T.must(composer_platform_extensions[ext.fetch(:name)]).uniq
|
436
484
|
end
|
437
485
|
end
|
438
486
|
|
487
|
+
sig { returns(String) }
|
439
488
|
def php_helper_path
|
440
489
|
NativeHelpers.composer_helper_path(composer_version: composer_version)
|
441
490
|
end
|
442
491
|
|
492
|
+
sig { params(content: String).returns(String) }
|
493
|
+
def post_process_lockfile(content)
|
494
|
+
content = replace_patches(content)
|
495
|
+
content = replace_content_hash(content)
|
496
|
+
replace_platform_overrides(content)
|
497
|
+
end
|
498
|
+
|
499
|
+
sig { returns(String) }
|
443
500
|
def composer_version
|
444
|
-
@composer_version ||=
|
501
|
+
@composer_version ||= T.let(
|
502
|
+
Helpers.composer_version(parsed_composer_json, parsed_lockfile),
|
503
|
+
T.nilable(String)
|
504
|
+
)
|
445
505
|
end
|
446
506
|
|
507
|
+
sig { returns(T::Hash[String, String]) }
|
447
508
|
def credentials_env
|
448
509
|
credentials
|
449
510
|
.select { |c| c.fetch("type") == "php_environment_variable" }
|
450
|
-
.to_h { |cred| [cred["env-key"], cred.fetch("env-value", "-")] }
|
511
|
+
.to_h { |cred| [T.cast(cred["env-key"], String), cred.fetch("env-value", "-")] }
|
451
512
|
end
|
452
513
|
|
514
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
453
515
|
def git_credentials
|
454
516
|
credentials
|
455
517
|
.select { |cred| cred.fetch("type") == "git_source" }
|
456
518
|
.select { |cred| cred["password"] }
|
457
519
|
end
|
458
520
|
|
521
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
459
522
|
def registry_credentials
|
460
523
|
credentials
|
461
524
|
.select { |cred| cred.fetch("type") == PackageManager::REPOSITORY_KEY }
|
462
525
|
.select { |cred| cred["password"] }
|
463
526
|
end
|
464
527
|
|
528
|
+
sig { returns(T::Hash[String, T::Array[String]]) }
|
465
529
|
def initial_platform
|
466
530
|
platform_php = Helpers.capture_platform_php(parsed_composer_json)
|
467
531
|
|
@@ -480,6 +544,7 @@ module Dependabot
|
|
480
544
|
platform
|
481
545
|
end
|
482
546
|
|
547
|
+
sig { params(req_string: String).returns(T::Boolean) }
|
483
548
|
def requirement_valid?(req_string)
|
484
549
|
Composer::Requirement.requirements_array(req_string)
|
485
550
|
true
|
@@ -487,36 +552,60 @@ module Dependabot
|
|
487
552
|
false
|
488
553
|
end
|
489
554
|
|
555
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
490
556
|
def parsed_composer_json
|
491
|
-
@parsed_composer_json ||=
|
557
|
+
@parsed_composer_json ||= T.let(
|
558
|
+
JSON.parse(T.must(composer_json.content)),
|
559
|
+
T.nilable(T::Hash[String, T.untyped])
|
560
|
+
)
|
492
561
|
end
|
493
562
|
|
563
|
+
sig { returns(T::Hash[String, T.untyped]) }
|
494
564
|
def parsed_lockfile
|
495
|
-
@parsed_lockfile ||=
|
565
|
+
@parsed_lockfile ||= T.let(
|
566
|
+
JSON.parse(T.must(lockfile.content)),
|
567
|
+
T.nilable(T::Hash[String, T.untyped])
|
568
|
+
)
|
496
569
|
end
|
497
570
|
|
571
|
+
sig { returns(Dependabot::DependencyFile) }
|
498
572
|
def composer_json
|
499
|
-
@composer_json ||=
|
500
|
-
dependency_files.find { |f| f.name == PackageManager::MANIFEST_FILENAME }
|
573
|
+
@composer_json ||= T.let(
|
574
|
+
T.must(dependency_files.find { |f| f.name == PackageManager::MANIFEST_FILENAME }),
|
575
|
+
T.nilable(Dependabot::DependencyFile)
|
576
|
+
)
|
501
577
|
end
|
502
578
|
|
579
|
+
sig { returns(Dependabot::DependencyFile) }
|
503
580
|
def lockfile
|
504
|
-
@lockfile ||=
|
505
|
-
dependency_files.find { |f| f.name == PackageManager::LOCKFILE_FILENAME }
|
581
|
+
@lockfile ||= T.let(
|
582
|
+
T.must(dependency_files.find { |f| f.name == PackageManager::LOCKFILE_FILENAME }),
|
583
|
+
T.nilable(Dependabot::DependencyFile)
|
584
|
+
)
|
506
585
|
end
|
507
586
|
|
587
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
508
588
|
def auth_json
|
509
|
-
@auth_json ||=
|
589
|
+
@auth_json ||= T.let(
|
590
|
+
dependency_files.find { |f| f.name == PackageManager::AUTH_FILENAME },
|
591
|
+
T.nilable(Dependabot::DependencyFile)
|
592
|
+
)
|
510
593
|
end
|
511
594
|
|
595
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
512
596
|
def artifact_dependencies
|
513
|
-
@artifact_dependencies ||=
|
514
|
-
dependency_files.select { |f| f.name.end_with?(".zip", ".gitkeep") }
|
597
|
+
@artifact_dependencies ||= T.let(
|
598
|
+
dependency_files.select { |f| f.name.end_with?(".zip", ".gitkeep") },
|
599
|
+
T.nilable(T::Array[Dependabot::DependencyFile])
|
600
|
+
)
|
515
601
|
end
|
516
602
|
|
603
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
517
604
|
def path_dependencies
|
518
|
-
@path_dependencies ||=
|
519
|
-
dependency_files.select { |f| f.name.end_with?("/#{PackageManager::MANIFEST_FILENAME}") }
|
605
|
+
@path_dependencies ||= T.let(
|
606
|
+
dependency_files.select { |f| f.name.end_with?("/#{PackageManager::MANIFEST_FILENAME}") },
|
607
|
+
T.nilable(T::Array[Dependabot::DependencyFile])
|
608
|
+
)
|
520
609
|
end
|
521
610
|
end
|
522
611
|
end
|
@@ -1,22 +1,28 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
4
6
|
require "dependabot/composer/file_updater"
|
5
7
|
|
6
8
|
module Dependabot
|
7
9
|
module Composer
|
8
10
|
class FileUpdater
|
9
11
|
class ManifestUpdater
|
12
|
+
extend T::Sig
|
13
|
+
|
14
|
+
sig { params(dependencies: T::Array[Dependabot::Dependency], manifest: Dependabot::DependencyFile).void }
|
10
15
|
def initialize(dependencies:, manifest:)
|
11
16
|
@dependencies = dependencies
|
12
17
|
@manifest = manifest
|
13
18
|
end
|
14
19
|
|
20
|
+
sig { returns(String) }
|
15
21
|
def updated_manifest_content
|
16
|
-
dependencies.reduce(manifest.content.dup) do |content, dep|
|
22
|
+
T.must(dependencies.reduce(manifest.content.dup) do |content, dep|
|
17
23
|
updated_content = content
|
18
24
|
updated_requirements(dep).each do |new_req|
|
19
|
-
old_req = old_requirement(dep, new_req)
|
25
|
+
old_req = old_requirement(dep, new_req)&.fetch(:requirement)
|
20
26
|
updated_req = new_req.fetch(:requirement)
|
21
27
|
|
22
28
|
regex =
|
@@ -25,7 +31,7 @@ module Dependabot
|
|
25
31
|
"#{Regexp.escape(old_req)}"
|
26
32
|
/x
|
27
33
|
|
28
|
-
updated_content = content
|
34
|
+
updated_content = content&.gsub(regex) do |declaration|
|
29
35
|
declaration.gsub(%("#{old_req}"), %("#{updated_req}"))
|
30
36
|
end
|
31
37
|
|
@@ -33,32 +39,45 @@ module Dependabot
|
|
33
39
|
end
|
34
40
|
|
35
41
|
updated_content
|
36
|
-
end
|
42
|
+
end)
|
37
43
|
end
|
38
44
|
|
39
45
|
private
|
40
46
|
|
47
|
+
sig { returns(T::Array[Dependabot::Dependency]) }
|
41
48
|
attr_reader :dependencies
|
49
|
+
|
50
|
+
sig { returns(Dependabot::DependencyFile) }
|
42
51
|
attr_reader :manifest
|
43
52
|
|
53
|
+
sig { params(dependency: Dependabot::Dependency).returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
44
54
|
def new_requirements(dependency)
|
45
55
|
dependency.requirements.select { |r| r[:file] == manifest.name }
|
46
56
|
end
|
47
57
|
|
58
|
+
sig do
|
59
|
+
params(
|
60
|
+
dependency: Dependabot::Dependency,
|
61
|
+
new_requirement: T::Hash[Symbol, T.untyped]
|
62
|
+
)
|
63
|
+
.returns(T.nilable(T::Hash[Symbol, T.untyped]))
|
64
|
+
end
|
48
65
|
def old_requirement(dependency, new_requirement)
|
49
|
-
dependency.previous_requirements
|
50
|
-
|
51
|
-
|
66
|
+
T.must(dependency.previous_requirements)
|
67
|
+
.select { |r| r[:file] == manifest.name }
|
68
|
+
.find { |r| r[:groups] == new_requirement[:groups] }
|
52
69
|
end
|
53
70
|
|
71
|
+
sig { params(dependency: Dependabot::Dependency).returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
54
72
|
def updated_requirements(dependency)
|
55
73
|
new_requirements(dependency)
|
56
|
-
.reject { |r| dependency.previous_requirements.include?(r) }
|
74
|
+
.reject { |r| T.must(dependency.previous_requirements).include?(r) }
|
57
75
|
end
|
58
76
|
|
77
|
+
sig { params(file: Dependabot::DependencyFile, dependency: Dependabot::Dependency).returns(T::Boolean) }
|
59
78
|
def requirement_changed?(file, dependency)
|
60
79
|
changed_requirements =
|
61
|
-
dependency.requirements - dependency.previous_requirements
|
80
|
+
dependency.requirements - T.must(dependency.previous_requirements)
|
62
81
|
|
63
82
|
changed_requirements.any? { |f| f[:file] == file.name }
|
64
83
|
end
|
@@ -1,7 +1,9 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "excon"
|
5
|
+
require "sorbet-runtime"
|
6
|
+
|
5
7
|
require "dependabot/metadata_finders"
|
6
8
|
require "dependabot/metadata_finders/base"
|
7
9
|
require "dependabot/registry_client"
|
@@ -10,6 +12,21 @@ require "dependabot/composer/version"
|
|
10
12
|
module Dependabot
|
11
13
|
module Composer
|
12
14
|
class MetadataFinder < Dependabot::MetadataFinders::Base
|
15
|
+
extend T::Sig
|
16
|
+
|
17
|
+
sig do
|
18
|
+
override
|
19
|
+
.params(
|
20
|
+
dependency: Dependabot::Dependency,
|
21
|
+
credentials: T::Array[Dependabot::Credential]
|
22
|
+
)
|
23
|
+
.void
|
24
|
+
end
|
25
|
+
def initialize(dependency:, credentials:)
|
26
|
+
@packagist_listing = T.let(nil, T.nilable(T::Hash[String, T.untyped]))
|
27
|
+
super
|
28
|
+
end
|
29
|
+
|
13
30
|
private
|
14
31
|
|
15
32
|
sig { override.returns(T.nilable(Source)) }
|
@@ -1,6 +1,8 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strong
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
4
6
|
require "dependabot/version"
|
5
7
|
require "dependabot/utils"
|
6
8
|
|
@@ -11,11 +13,15 @@ require "dependabot/utils"
|
|
11
13
|
module Dependabot
|
12
14
|
module Composer
|
13
15
|
class Version < Dependabot::Version
|
16
|
+
extend T::Sig
|
17
|
+
|
18
|
+
sig { override.params(version: VersionParameter).void }
|
14
19
|
def initialize(version)
|
15
|
-
@version_string = version.to_s
|
20
|
+
@version_string = T.let(version.to_s, String)
|
16
21
|
super
|
17
22
|
end
|
18
23
|
|
24
|
+
sig { returns(String) }
|
19
25
|
def to_s
|
20
26
|
@version_string
|
21
27
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dependabot-composer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.311.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dependabot
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-05-01 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: dependabot-common
|
@@ -15,14 +15,14 @@ dependencies:
|
|
15
15
|
requirements:
|
16
16
|
- - '='
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: 0.
|
18
|
+
version: 0.311.0
|
19
19
|
type: :runtime
|
20
20
|
prerelease: false
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
22
22
|
requirements:
|
23
23
|
- - '='
|
24
24
|
- !ruby/object:Gem::Version
|
25
|
-
version: 0.
|
25
|
+
version: 0.311.0
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: debug
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
@@ -223,16 +223,16 @@ dependencies:
|
|
223
223
|
name: webrick
|
224
224
|
requirement: !ruby/object:Gem::Requirement
|
225
225
|
requirements:
|
226
|
-
- - "
|
226
|
+
- - "~>"
|
227
227
|
- !ruby/object:Gem::Version
|
228
|
-
version: '1.
|
228
|
+
version: '1.9'
|
229
229
|
type: :development
|
230
230
|
prerelease: false
|
231
231
|
version_requirements: !ruby/object:Gem::Requirement
|
232
232
|
requirements:
|
233
|
-
- - "
|
233
|
+
- - "~>"
|
234
234
|
- !ruby/object:Gem::Version
|
235
|
-
version: '1.
|
235
|
+
version: '1.9'
|
236
236
|
description: Dependabot-Composer provides support for bumping PHP (composer) libraries
|
237
237
|
via Dependabot. If you want support for multiple package managers, you probably
|
238
238
|
want the meta-gem dependabot-omnibus.
|
@@ -279,7 +279,7 @@ licenses:
|
|
279
279
|
- MIT
|
280
280
|
metadata:
|
281
281
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
282
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
282
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.311.0
|
283
283
|
rdoc_options: []
|
284
284
|
require_paths:
|
285
285
|
- lib
|