dependabot-composer 0.310.0 → 0.312.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/helpers.rb +1 -1
- data/lib/dependabot/composer/metadata_finder.rb +18 -1
- data/lib/dependabot/composer/update_checker/latest_version_finder.rb +66 -14
- data/lib/dependabot/composer/update_checker/requirements_updater.rb +64 -30
- data/lib/dependabot/composer/update_checker/version_resolver.rb +146 -47
- data/lib/dependabot/composer/update_checker.rb +10 -10
- data/lib/dependabot/composer/version.rb +8 -2
- metadata +27 -27
@@ -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
|
@@ -174,7 +174,7 @@ module Dependabot
|
|
174
174
|
|
175
175
|
sig { params(dependency_url: String).returns(String) }
|
176
176
|
def self.clean_dependency_url(dependency_url)
|
177
|
-
return dependency_url unless URI::
|
177
|
+
return dependency_url unless URI::RFC2396_PARSER.regexp[:ABS_URI].match?(dependency_url)
|
178
178
|
|
179
179
|
url = URI.parse(dependency_url)
|
180
180
|
url.user = nil
|
@@ -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,8 +1,9 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "excon"
|
5
5
|
require "json"
|
6
|
+
require "sorbet-runtime"
|
6
7
|
|
7
8
|
require "dependabot/composer/update_checker"
|
8
9
|
require "dependabot/update_checkers/version_filters"
|
@@ -13,9 +14,20 @@ module Dependabot
|
|
13
14
|
module Composer
|
14
15
|
class UpdateChecker
|
15
16
|
class LatestVersionFinder
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
extend T::Sig
|
18
|
+
|
19
|
+
sig do
|
20
|
+
params(
|
21
|
+
dependency: Dependabot::Dependency,
|
22
|
+
dependency_files: T::Array[Dependabot::DependencyFile],
|
23
|
+
credentials: T::Array[Dependabot::Credential],
|
24
|
+
ignored_versions: T::Array[String],
|
25
|
+
security_advisories: T::Array[Dependabot::SecurityAdvisory],
|
26
|
+
raise_on_ignored: T::Boolean
|
27
|
+
).void
|
28
|
+
end
|
29
|
+
def initialize(dependency:, dependency_files:, credentials:, ignored_versions:, security_advisories:,
|
30
|
+
raise_on_ignored: false)
|
19
31
|
@dependency = dependency
|
20
32
|
@dependency_files = dependency_files
|
21
33
|
@credentials = credentials
|
@@ -24,22 +36,40 @@ module Dependabot
|
|
24
36
|
@security_advisories = security_advisories
|
25
37
|
end
|
26
38
|
|
39
|
+
sig { returns(T.nilable(Dependabot::Version)) }
|
27
40
|
def latest_version
|
28
|
-
@latest_version ||=
|
41
|
+
@latest_version ||= T.let(
|
42
|
+
fetch_latest_version,
|
43
|
+
T.nilable(Dependabot::Version)
|
44
|
+
)
|
29
45
|
end
|
30
46
|
|
47
|
+
sig { returns(T.nilable(Dependabot::Version)) }
|
31
48
|
def lowest_security_fix_version
|
32
|
-
@lowest_security_fix_version ||=
|
49
|
+
@lowest_security_fix_version ||= T.let(
|
50
|
+
fetch_lowest_security_fix_version,
|
51
|
+
T.nilable(Dependabot::Version)
|
52
|
+
)
|
33
53
|
end
|
34
54
|
|
35
55
|
private
|
36
56
|
|
57
|
+
sig { returns(Dependabot::Dependency) }
|
37
58
|
attr_reader :dependency
|
59
|
+
|
60
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
38
61
|
attr_reader :dependency_files
|
62
|
+
|
63
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
39
64
|
attr_reader :credentials
|
65
|
+
|
66
|
+
sig { returns(T::Array[String]) }
|
40
67
|
attr_reader :ignored_versions
|
68
|
+
|
69
|
+
sig { returns(T::Array[Dependabot::SecurityAdvisory]) }
|
41
70
|
attr_reader :security_advisories
|
42
71
|
|
72
|
+
sig { returns(T.nilable(Dependabot::Version)) }
|
43
73
|
def fetch_latest_version
|
44
74
|
versions = available_versions
|
45
75
|
versions = filter_prerelease_versions(versions)
|
@@ -47,6 +77,7 @@ module Dependabot
|
|
47
77
|
versions.max
|
48
78
|
end
|
49
79
|
|
80
|
+
sig { returns(T.nilable(Dependabot::Version)) }
|
50
81
|
def fetch_lowest_security_fix_version
|
51
82
|
versions = available_versions
|
52
83
|
versions = filter_prerelease_versions(versions)
|
@@ -58,12 +89,14 @@ module Dependabot
|
|
58
89
|
versions.min
|
59
90
|
end
|
60
91
|
|
92
|
+
sig { params(versions_array: T::Array[Dependabot::Version]).returns(T::Array[Dependabot::Version]) }
|
61
93
|
def filter_prerelease_versions(versions_array)
|
62
94
|
return versions_array if wants_prerelease?
|
63
95
|
|
64
96
|
versions_array.reject(&:prerelease?)
|
65
97
|
end
|
66
98
|
|
99
|
+
sig { params(versions_array: T::Array[Dependabot::Version]).returns(T::Array[Dependabot::Version]) }
|
67
100
|
def filter_ignored_versions(versions_array)
|
68
101
|
filtered =
|
69
102
|
versions_array
|
@@ -76,6 +109,7 @@ module Dependabot
|
|
76
109
|
filtered
|
77
110
|
end
|
78
111
|
|
112
|
+
sig { params(versions_array: T::Array[Dependabot::Version]).returns(T::Array[Dependabot::Version]) }
|
79
113
|
def filter_lower_versions(versions_array)
|
80
114
|
return versions_array unless dependency.numeric_version
|
81
115
|
|
@@ -83,6 +117,7 @@ module Dependabot
|
|
83
117
|
.select { |version| version > dependency.numeric_version }
|
84
118
|
end
|
85
119
|
|
120
|
+
sig { returns(T::Boolean) }
|
86
121
|
def wants_prerelease?
|
87
122
|
current_version = dependency.numeric_version
|
88
123
|
return true if current_version&.prerelease?
|
@@ -92,17 +127,19 @@ module Dependabot
|
|
92
127
|
end
|
93
128
|
end
|
94
129
|
|
130
|
+
sig { returns(T::Array[Dependabot::Version]) }
|
95
131
|
def available_versions
|
96
132
|
registry_version_details
|
97
133
|
.select { |version| version_class.correct?(version.gsub(/^v/, "")) }
|
98
134
|
.map { |version| version_class.new(version.gsub(/^v/, "")) }
|
99
135
|
end
|
100
136
|
|
137
|
+
sig { returns(T::Array[String]) }
|
101
138
|
def registry_version_details
|
102
139
|
return @registry_version_details unless @registry_version_details.nil?
|
103
140
|
|
104
141
|
repositories =
|
105
|
-
JSON.parse(composer_file.content)
|
142
|
+
JSON.parse(T.must(composer_file.content))
|
106
143
|
.fetch("repositories", [])
|
107
144
|
.select { |r| r.is_a?(Hash) }
|
108
145
|
|
@@ -115,16 +152,19 @@ module Dependabot
|
|
115
152
|
urls << "https://repo.packagist.org/p2/#{dependency.name.downcase}.json"
|
116
153
|
end
|
117
154
|
|
118
|
-
@registry_version_details
|
155
|
+
@registry_version_details ||= T.let([], T.nilable(T::Array[String]))
|
119
156
|
urls.each do |url|
|
120
157
|
@registry_version_details += fetch_registry_versions_from_url(url)
|
121
158
|
end
|
122
159
|
@registry_version_details.uniq
|
123
160
|
end
|
124
161
|
|
162
|
+
sig { params(url: String).returns(T::Array[String]) }
|
125
163
|
def fetch_registry_versions_from_url(url)
|
126
164
|
url_host = URI(url).host
|
127
|
-
cred = registry_credentials.find
|
165
|
+
cred = registry_credentials.find do |c|
|
166
|
+
url_host == c["registry"] || url_host == URI(T.must(c["registry"])).host
|
167
|
+
end
|
128
168
|
|
129
169
|
response = Dependabot::RegistryClient.get(
|
130
170
|
url: url,
|
@@ -139,6 +179,7 @@ module Dependabot
|
|
139
179
|
[]
|
140
180
|
end
|
141
181
|
|
182
|
+
sig { params(response: T.untyped, url: String).returns(T::Array[String]) }
|
142
183
|
def parse_registry_response(response, url)
|
143
184
|
return [] unless response.status == 200
|
144
185
|
|
@@ -154,6 +195,7 @@ module Dependabot
|
|
154
195
|
raise DependencyFileNotResolvable, msg
|
155
196
|
end
|
156
197
|
|
198
|
+
sig { params(listing: T::Hash[String, T.untyped]).returns(T::Array[String]) }
|
157
199
|
def extract_versions(listing)
|
158
200
|
# Packagist's Metadata API format:
|
159
201
|
# v1: "packages": {<package name>: {<version_number>: {hash of metadata for a particular release version}}}
|
@@ -174,26 +216,32 @@ module Dependabot
|
|
174
216
|
end
|
175
217
|
end
|
176
218
|
|
219
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
177
220
|
def registry_credentials
|
178
221
|
credentials.select { |cred| cred["type"] == PackageManager::REPOSITORY_KEY } +
|
179
222
|
auth_json_credentials
|
180
223
|
end
|
181
224
|
|
225
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
182
226
|
def auth_json_credentials
|
183
|
-
|
227
|
+
json = auth_json
|
228
|
+
return [] unless json
|
184
229
|
|
185
|
-
parsed_auth_json = JSON.parse(
|
230
|
+
parsed_auth_json = JSON.parse(T.must(json.content))
|
186
231
|
parsed_auth_json.fetch("http-basic", {}).map do |reg, details|
|
187
|
-
{
|
232
|
+
Dependabot::Credential.new({
|
188
233
|
"registry" => reg,
|
189
234
|
"username" => details["username"],
|
190
235
|
"password" => details["password"]
|
191
|
-
}
|
236
|
+
})
|
192
237
|
end
|
193
238
|
rescue JSON::ParserError
|
194
|
-
raise Dependabot::DependencyFileNotParseable,
|
239
|
+
raise Dependabot::DependencyFileNotParseable, json.path if json
|
240
|
+
|
241
|
+
raise Dependabot::DependencyFileNotParseable, "Unknown path"
|
195
242
|
end
|
196
243
|
|
244
|
+
sig { returns(Dependabot::DependencyFile) }
|
197
245
|
def composer_file
|
198
246
|
composer_file =
|
199
247
|
dependency_files.find do |f|
|
@@ -204,18 +252,22 @@ module Dependabot
|
|
204
252
|
composer_file
|
205
253
|
end
|
206
254
|
|
255
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
207
256
|
def auth_json
|
208
257
|
dependency_files.find { |f| f.name == PackageManager::AUTH_FILENAME }
|
209
258
|
end
|
210
259
|
|
260
|
+
sig { returns(T::Array[Dependabot::Requirement]) }
|
211
261
|
def ignore_requirements
|
212
262
|
ignored_versions.map { |req| requirement_class.new(req.split(",")) }
|
213
263
|
end
|
214
264
|
|
265
|
+
sig { returns(T.class_of(Dependabot::Version)) }
|
215
266
|
def version_class
|
216
267
|
dependency.version_class
|
217
268
|
end
|
218
269
|
|
270
|
+
sig { returns(T.class_of(Dependabot::Requirement)) }
|
219
271
|
def requirement_class
|
220
272
|
dependency.requirement_class
|
221
273
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
################################################################################
|
@@ -34,6 +34,13 @@ module Dependabot
|
|
34
34
|
T::Array[Dependabot::RequirementsUpdateStrategy]
|
35
35
|
)
|
36
36
|
|
37
|
+
sig do
|
38
|
+
params(
|
39
|
+
requirements: T::Array[T::Hash[Symbol, String]],
|
40
|
+
update_strategy: Dependabot::RequirementsUpdateStrategy,
|
41
|
+
latest_resolvable_version: T.nilable(T.any(String, Composer::Version))
|
42
|
+
).void
|
43
|
+
end
|
37
44
|
def initialize(requirements:, update_strategy:,
|
38
45
|
latest_resolvable_version:)
|
39
46
|
@requirements = requirements
|
@@ -43,10 +50,13 @@ module Dependabot
|
|
43
50
|
|
44
51
|
return unless latest_resolvable_version
|
45
52
|
|
46
|
-
@latest_resolvable_version =
|
47
|
-
version_class.new(latest_resolvable_version)
|
53
|
+
@latest_resolvable_version = T.let(
|
54
|
+
version_class.new(latest_resolvable_version),
|
55
|
+
Dependabot::Version
|
56
|
+
)
|
48
57
|
end
|
49
58
|
|
59
|
+
sig { returns(T::Array[T::Hash[Symbol, String]]) }
|
50
60
|
def updated_requirements
|
51
61
|
return requirements if update_strategy.lockfile_only?
|
52
62
|
return requirements unless latest_resolvable_version
|
@@ -56,10 +66,16 @@ module Dependabot
|
|
56
66
|
|
57
67
|
private
|
58
68
|
|
69
|
+
sig { returns(T::Array[T::Hash[Symbol, String]]) }
|
59
70
|
attr_reader :requirements
|
71
|
+
|
72
|
+
sig { returns(Dependabot::RequirementsUpdateStrategy) }
|
60
73
|
attr_reader :update_strategy
|
74
|
+
|
75
|
+
sig { returns(T.nilable(Dependabot::Version)) }
|
61
76
|
attr_reader :latest_resolvable_version
|
62
77
|
|
78
|
+
sig { void }
|
63
79
|
def check_update_strategy
|
64
80
|
return if ALLOWED_UPDATE_STRATEGIES.include?(update_strategy)
|
65
81
|
|
@@ -67,8 +83,9 @@ module Dependabot
|
|
67
83
|
end
|
68
84
|
|
69
85
|
# rubocop:disable Metrics/PerceivedComplexity
|
86
|
+
sig { params(req: T::Hash[Symbol, String]).returns(T::Hash[Symbol, String]) }
|
70
87
|
def updated_requirement(req)
|
71
|
-
req_string = req[:requirement].strip
|
88
|
+
req_string = T.must(req[:requirement]).strip
|
72
89
|
or_string_reqs = req_string.split(OR_SEPARATOR)
|
73
90
|
or_separator = req_string.match(OR_SEPARATOR)&.to_s || " || "
|
74
91
|
numeric_or_string_reqs = or_string_reqs
|
@@ -90,28 +107,33 @@ module Dependabot
|
|
90
107
|
update_requirement_version(req, or_separator)
|
91
108
|
end
|
92
109
|
|
110
|
+
# Add a T.must for new_req as it's defined in the case statement with multiple options
|
111
|
+
new_req = T.must(new_req)
|
93
112
|
new_req_string =
|
94
113
|
[new_req[:requirement], *branch_or_string_reqs].join(or_separator)
|
95
114
|
new_req.merge(requirement: new_req_string)
|
96
115
|
end
|
97
116
|
# rubocop:enable Metrics/PerceivedComplexity
|
98
117
|
|
118
|
+
sig { params(req: T::Hash[Symbol, String]).returns(T::Hash[Symbol, String]) }
|
99
119
|
def updated_alias(req)
|
100
|
-
req_string = req[:requirement]
|
101
|
-
|
120
|
+
req_string = T.must(req[:requirement])
|
121
|
+
parts = req_string.split(/\sas\s/)
|
122
|
+
real_version = T.must(parts.first).strip
|
102
123
|
|
103
124
|
# If the version we're aliasing isn't a version then we don't know
|
104
125
|
# how to update it, so we just return the existing requirement.
|
105
126
|
return req unless version_class.correct?(real_version)
|
106
127
|
|
107
|
-
new_version_string = latest_resolvable_version.to_s
|
128
|
+
new_version_string = T.must(latest_resolvable_version).to_s
|
108
129
|
new_req = req_string.sub(real_version, new_version_string)
|
109
130
|
req.merge(requirement: new_req)
|
110
131
|
end
|
111
132
|
|
112
133
|
# rubocop:disable Metrics/PerceivedComplexity
|
134
|
+
sig { params(req: T::Hash[Symbol, String], or_separator: String).returns(T::Hash[Symbol, String]) }
|
113
135
|
def widen_requirement(req, or_separator)
|
114
|
-
current_requirement = req[:requirement]
|
136
|
+
current_requirement = T.must(req[:requirement])
|
115
137
|
reqs = current_requirement.strip.split(SEPARATOR).map(&:strip)
|
116
138
|
|
117
139
|
updated_requirement =
|
@@ -131,13 +153,14 @@ module Dependabot
|
|
131
153
|
end
|
132
154
|
# rubocop:enable Metrics/PerceivedComplexity
|
133
155
|
|
156
|
+
sig { params(req: T::Hash[Symbol, String], or_separator: String).returns(T::Hash[Symbol, String]) }
|
134
157
|
def update_requirement_version(req, or_separator)
|
135
|
-
current_requirement = req[:requirement]
|
158
|
+
current_requirement = T.must(req[:requirement])
|
136
159
|
reqs = current_requirement.strip.split(SEPARATOR).map(&:strip)
|
137
160
|
|
138
161
|
updated_requirement =
|
139
162
|
if reqs.count > 1
|
140
|
-
"^#{latest_resolvable_version}"
|
163
|
+
"^#{T.must(latest_resolvable_version)}"
|
141
164
|
elsif reqs.any? { |r| r.match?(/<|(\s+-\s+)/) }
|
142
165
|
update_range_requirement(current_requirement, or_separator)
|
143
166
|
elsif reqs.any? { |r| r.match?(/>[^=]/) }
|
@@ -149,38 +172,42 @@ module Dependabot
|
|
149
172
|
req.merge(requirement: updated_requirement)
|
150
173
|
end
|
151
174
|
|
175
|
+
sig { params(requirement_string: String).returns(T::Boolean) }
|
152
176
|
def req_satisfied_by_latest_resolvable?(requirement_string)
|
153
177
|
ruby_requirements(requirement_string)
|
154
|
-
.any? { |r| r.satisfied_by?(latest_resolvable_version) }
|
178
|
+
.any? { |r| r.satisfied_by?(T.must(latest_resolvable_version)) }
|
155
179
|
end
|
156
180
|
|
181
|
+
sig { params(req_string: String).returns(String) }
|
157
182
|
def update_version_string(req_string)
|
158
183
|
req_string
|
159
184
|
.sub(VERSION_REGEX) do |old_version|
|
160
|
-
next latest_resolvable_version.to_s unless req_string.match?(/[~*\^]/)
|
185
|
+
next T.must(latest_resolvable_version).to_s unless req_string.match?(/[~*\^]/)
|
161
186
|
|
162
187
|
old_parts = old_version.split(".")
|
163
|
-
new_parts = latest_resolvable_version.to_s.split(".")
|
164
|
-
|
188
|
+
new_parts = T.must(latest_resolvable_version).to_s.split(".")
|
189
|
+
.first(old_parts.count)
|
165
190
|
new_parts.map.with_index do |part, i|
|
166
191
|
old_parts[i] == "*" ? "*" : part
|
167
192
|
end.join(".")
|
168
193
|
end
|
169
194
|
end
|
170
195
|
|
196
|
+
sig { params(requirement_string: String).returns(T::Array[Composer::Requirement]) }
|
171
197
|
def ruby_requirements(requirement_string)
|
172
198
|
Composer::Requirement.requirements_array(requirement_string)
|
173
199
|
end
|
174
200
|
|
201
|
+
sig { params(req_string: String, or_separator: String).returns(String) }
|
175
202
|
def update_caret_requirement(req_string, or_separator)
|
176
203
|
caret_requirements =
|
177
204
|
req_string.split(SEPARATOR).select { |r| r.strip.start_with?("^") }
|
178
|
-
version_parts = latest_resolvable_version.segments
|
205
|
+
version_parts = T.must(latest_resolvable_version).segments
|
179
206
|
|
180
207
|
min_existing_precision =
|
181
|
-
caret_requirements.map { |r| r.split(".").count }.min
|
208
|
+
caret_requirements.map { |r| r.split(".").count }.min || 0
|
182
209
|
first_non_zero_index =
|
183
|
-
version_parts.count.times.find { |i| version_parts[i] != 0 }
|
210
|
+
version_parts.count.times.find { |i| version_parts[i] != 0 } || 0
|
184
211
|
|
185
212
|
precision = [min_existing_precision, first_non_zero_index + 1].max
|
186
213
|
version = version_parts.first(precision).map.with_index do |part, i|
|
@@ -190,71 +217,78 @@ module Dependabot
|
|
190
217
|
req_string + "#{or_separator}^#{version}"
|
191
218
|
end
|
192
219
|
|
220
|
+
sig { params(req_string: String, or_separator: String).returns(String) }
|
193
221
|
def update_tilda_requirement(req_string, or_separator)
|
194
222
|
tilda_requirements =
|
195
223
|
req_string.split(SEPARATOR).select { |r| r.strip.start_with?("~") }
|
196
|
-
precision = tilda_requirements.map { |r| r.split(".").count }.min
|
224
|
+
precision = tilda_requirements.map { |r| r.split(".").count }.min || 0
|
197
225
|
|
198
|
-
version_parts = latest_resolvable_version.segments.first(precision)
|
199
|
-
version_parts[-1] = 0
|
226
|
+
version_parts = T.must(latest_resolvable_version).segments.first(precision)
|
227
|
+
version_parts[-1] = 0 if version_parts.any?
|
200
228
|
version = version_parts.join(".")
|
201
229
|
|
202
230
|
req_string + "#{or_separator}~#{version}"
|
203
231
|
end
|
204
232
|
|
233
|
+
sig { params(req_string: String, or_separator: String).returns(String) }
|
205
234
|
def update_wildcard_requirement(req_string, or_separator)
|
206
235
|
wildcard_requirements =
|
207
236
|
req_string.split(SEPARATOR).select { |r| r.include?("*") }
|
208
237
|
precision = wildcard_requirements.map do |r|
|
209
238
|
r.split(".").reject { |s| s == "*" }.count
|
210
|
-
end.min
|
239
|
+
end.min || 0
|
211
240
|
wildcard_count = wildcard_requirements.map do |r|
|
212
241
|
r.split(".").select { |s| s == "*" }.count
|
213
|
-
end.min
|
242
|
+
end.min || 0
|
214
243
|
|
215
|
-
version_parts = latest_resolvable_version.segments.first(precision)
|
244
|
+
version_parts = T.must(latest_resolvable_version).segments.first(precision)
|
216
245
|
version = version_parts.join(".")
|
217
246
|
|
218
247
|
req_string + "#{or_separator}#{version}#{'.*' * wildcard_count}"
|
219
248
|
end
|
220
249
|
|
250
|
+
sig { params(req_string: String, or_separator: String).returns(String) }
|
221
251
|
def update_range_requirement(req_string, or_separator)
|
222
252
|
range_requirements =
|
223
253
|
req_string.split(SEPARATOR).select { |r| r.match?(/<|(\s+-\s+)/) }
|
224
254
|
|
225
255
|
if range_requirements.count == 1
|
226
|
-
range_requirement = range_requirements.first
|
256
|
+
range_requirement = T.must(range_requirements.first)
|
227
257
|
versions = range_requirement.scan(VERSION_REGEX)
|
228
|
-
|
258
|
+
# Convert version strings to Version objects and find the maximum
|
259
|
+
upper_bounds = versions.map { |v| version_class.new(T.cast(v, String)) }
|
260
|
+
upper_bound = T.cast(upper_bounds.max, Dependabot::Version)
|
229
261
|
new_upper_bound = update_greatest_version(
|
230
262
|
upper_bound,
|
231
|
-
latest_resolvable_version
|
263
|
+
T.must(latest_resolvable_version)
|
232
264
|
)
|
233
265
|
|
234
|
-
req_string.sub(upper_bound.to_s, new_upper_bound
|
266
|
+
req_string.sub(upper_bound.to_s, new_upper_bound)
|
235
267
|
else
|
236
|
-
req_string + "#{or_separator}^#{latest_resolvable_version}"
|
268
|
+
req_string + "#{or_separator}^#{T.must(latest_resolvable_version)}"
|
237
269
|
end
|
238
270
|
end
|
239
271
|
|
272
|
+
sig { params(old_version: Dependabot::Version, version_to_be_permitted: Dependabot::Version).returns(String) }
|
240
273
|
def update_greatest_version(old_version, version_to_be_permitted)
|
241
274
|
version = version_class.new(old_version)
|
242
275
|
version = version.release if version.prerelease?
|
243
276
|
|
244
277
|
index_to_update =
|
245
|
-
version.segments.map.with_index { |seg, i| seg.zero? ? 0 : i }.max
|
278
|
+
version.segments.map.with_index { |seg, i| seg.to_i.zero? ? 0 : i }.max || 0
|
246
279
|
|
247
280
|
version.segments.map.with_index do |_, index|
|
248
281
|
if index < index_to_update
|
249
282
|
version_to_be_permitted.segments[index]
|
250
283
|
elsif index == index_to_update
|
251
|
-
version_to_be_permitted.segments[index] + 1
|
284
|
+
version_to_be_permitted.segments[index].to_i + 1
|
252
285
|
else
|
253
286
|
0
|
254
287
|
end
|
255
288
|
end.join(".")
|
256
289
|
end
|
257
290
|
|
291
|
+
sig { returns(T.class_of(Dependabot::Composer::Version)) }
|
258
292
|
def version_class
|
259
293
|
Composer::Version
|
260
294
|
end
|