dependabot-swift 0.386.0 → 0.387.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/swift/file_parser/dependency_parser.rb +19 -8
- data/lib/dependabot/swift/file_parser/manifest_parser.rb +1 -1
- data/lib/dependabot/swift/file_parser/package_resolved_parser.rb +29 -15
- data/lib/dependabot/swift/file_parser/pbxproj_parser.rb +9 -9
- data/lib/dependabot/swift/file_parser/xcode_spm_resolver.rb +8 -8
- data/lib/dependabot/swift/file_updater/manifest_updater.rb +26 -8
- data/lib/dependabot/swift/file_updater/requirement_replacer.rb +1 -1
- data/lib/dependabot/swift/file_updater/xcode_lockfile_updater.rb +14 -13
- data/lib/dependabot/swift/native_requirement.rb +9 -3
- data/lib/dependabot/swift/requirement.rb +35 -0
- data/lib/dependabot/swift/update_checker/requirements_updater.rb +2 -2
- data/lib/dependabot/swift/update_checker/xcode_version_resolver.rb +26 -13
- data/lib/dependabot/swift/update_checker.rb +30 -16
- data/lib/dependabot/swift/version.rb +214 -0
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b354cacba27d8bed15800f9406537dfab055c1ddd4f71805b578e8d7a443e1a7
|
|
4
|
+
data.tar.gz: '00208626e381f350b287ca78ac59a30066243f925503454145b3c7cca8c143f1'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9043fdeb9fffbb3fb4473c687a5e7cbb75c3405c767739be645efc8b57cba715e139394f41d1729652c021f14347154f62b288b37bf7feb6e76832269e624682
|
|
7
|
+
data.tar.gz: a7568ae5132652a801a449504187e19e6ce10ad59f8290ed696bf556f6612f52edd1b9435137cf14586fd8984191987266e20e66a89d0059efe949bd4be0c561
|
|
@@ -48,7 +48,7 @@ module Dependabot
|
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
|
|
51
|
-
sig { returns(T::Hash[String,
|
|
51
|
+
sig { returns(T::Hash[String, Object]) }
|
|
52
52
|
def formatted_deps
|
|
53
53
|
deps = SharedHelpers.run_shell_command(
|
|
54
54
|
"swift package show-dependencies --format json",
|
|
@@ -60,30 +60,41 @@ module Dependabot
|
|
|
60
60
|
|
|
61
61
|
sig do
|
|
62
62
|
params(
|
|
63
|
-
data: T::Hash[String,
|
|
63
|
+
data: T::Hash[String, Object],
|
|
64
64
|
level: Integer
|
|
65
65
|
)
|
|
66
66
|
.returns(T::Array[Dependabot::Dependency])
|
|
67
67
|
end
|
|
68
68
|
def subdependencies(data, level: 0)
|
|
69
|
-
data["dependencies"]
|
|
69
|
+
dependencies = data["dependencies"]
|
|
70
|
+
return [] unless dependencies.is_a?(Array)
|
|
71
|
+
|
|
72
|
+
dependencies.flat_map do |root|
|
|
73
|
+
next [] unless root.is_a?(Hash)
|
|
74
|
+
|
|
75
|
+
all_dependencies(root, level: level)
|
|
76
|
+
end
|
|
70
77
|
end
|
|
71
78
|
|
|
72
79
|
sig do
|
|
73
80
|
params(
|
|
74
|
-
data: T::Hash[String,
|
|
81
|
+
data: T::Hash[String, Object],
|
|
75
82
|
level: Integer
|
|
76
83
|
)
|
|
77
84
|
.returns(T::Array[Dependabot::Dependency])
|
|
78
85
|
end
|
|
79
86
|
def all_dependencies(data, level: 0)
|
|
80
87
|
identity = data["identity"]
|
|
81
|
-
|
|
82
|
-
name = UrlHelpers.normalize_name(url)
|
|
88
|
+
url_value = data["url"]
|
|
83
89
|
version = data["version"]
|
|
90
|
+
return subdependencies(data, level: level + 1) unless url_value.is_a?(String)
|
|
91
|
+
|
|
92
|
+
url = SharedHelpers.scp_to_standard(url_value)
|
|
93
|
+
name = UrlHelpers.normalize_name(url)
|
|
94
|
+
version = nil unless version.is_a?(String)
|
|
84
95
|
|
|
85
96
|
source = { type: "git", url: url, ref: version, branch: nil }
|
|
86
|
-
metadata = { identity: identity }
|
|
97
|
+
metadata = { identity: identity.is_a?(String) ? identity : nil }
|
|
87
98
|
args = { name: name, version: version, package_manager: "swift", requirements: [], metadata: metadata }
|
|
88
99
|
|
|
89
100
|
if level.zero?
|
|
@@ -92,7 +103,7 @@ module Dependabot
|
|
|
92
103
|
args[:subdependency_metadata] = [{ source: source }]
|
|
93
104
|
end
|
|
94
105
|
|
|
95
|
-
dep = Dependency.new(**args) if
|
|
106
|
+
dep = Dependency.new(**args) if version != "unspecified"
|
|
96
107
|
|
|
97
108
|
[dep, *subdependencies(data, level: level + 1)].compact
|
|
98
109
|
end
|
|
@@ -27,7 +27,7 @@ module Dependabot
|
|
|
27
27
|
@source = source
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
sig { returns(T::Array[T::Hash[Symbol,
|
|
30
|
+
sig { returns(T::Array[T::Hash[Symbol, Object]]) }
|
|
31
31
|
def requirements
|
|
32
32
|
found = manifest.content&.scan(DEPENDENCY)&.find do |_declaration, url, _requirement|
|
|
33
33
|
SharedHelpers.scp_to_standard(url.to_s) == source[:url]
|
|
@@ -46,7 +46,7 @@ module Dependabot
|
|
|
46
46
|
sig { returns(Dependabot::DependencyFile) }
|
|
47
47
|
attr_reader :resolved_file
|
|
48
48
|
|
|
49
|
-
sig { returns(T::Hash[String,
|
|
49
|
+
sig { returns(T::Hash[String, Object]) }
|
|
50
50
|
def parse_json
|
|
51
51
|
content = resolved_file.content
|
|
52
52
|
unless content
|
|
@@ -64,7 +64,7 @@ module Dependabot
|
|
|
64
64
|
)
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
-
sig { params(parsed: T::Hash[String,
|
|
67
|
+
sig { params(parsed: T::Hash[String, Object]).returns(Integer) }
|
|
68
68
|
def detect_schema_version(parsed)
|
|
69
69
|
version = parsed["version"]
|
|
70
70
|
|
|
@@ -81,13 +81,14 @@ module Dependabot
|
|
|
81
81
|
|
|
82
82
|
sig do
|
|
83
83
|
params(
|
|
84
|
-
parsed: T::Hash[String,
|
|
84
|
+
parsed: T::Hash[String, Object],
|
|
85
85
|
schema_version: Integer
|
|
86
|
-
).returns(T::Array[T::Hash[String,
|
|
86
|
+
).returns(T::Array[T::Hash[String, Object]])
|
|
87
87
|
end
|
|
88
88
|
def extract_pins(parsed, schema_version)
|
|
89
89
|
pins = if schema_version == 1
|
|
90
|
-
parsed
|
|
90
|
+
object = parsed["object"]
|
|
91
|
+
object["pins"] if object.is_a?(Hash)
|
|
91
92
|
else
|
|
92
93
|
# v2 and v3 use the same top-level "pins" key
|
|
93
94
|
parsed["pins"]
|
|
@@ -106,7 +107,7 @@ module Dependabot
|
|
|
106
107
|
|
|
107
108
|
sig do
|
|
108
109
|
params(
|
|
109
|
-
pin: T::Hash[String,
|
|
110
|
+
pin: T::Hash[String, Object],
|
|
110
111
|
schema_version: Integer
|
|
111
112
|
).returns(T.nilable(Dependabot::Dependency))
|
|
112
113
|
end
|
|
@@ -115,21 +116,34 @@ module Dependabot
|
|
|
115
116
|
url = pin[T.must(keys[:url])]
|
|
116
117
|
return nil unless url.is_a?(String) && !url.empty?
|
|
117
118
|
|
|
118
|
-
state = pin
|
|
119
|
-
identity = pin[T.must(keys[:identity])]
|
|
120
|
-
# v1 uses a display name for "package"; normalize to lowercase like v2/v3 "identity".
|
|
121
|
-
# v2/v3 identity is always lowercase per spec, so only v1 needs downcasing.
|
|
122
|
-
identity = identity&.downcase if schema_version == 1
|
|
119
|
+
state = pin_state(pin, T.must(keys[:state]))
|
|
123
120
|
|
|
124
121
|
build_dependency_object(
|
|
125
|
-
identity: identity,
|
|
122
|
+
identity: pin_identity(pin, T.must(keys[:identity]), schema_version),
|
|
126
123
|
url: url,
|
|
127
|
-
version: state["version"],
|
|
128
|
-
revision: state["revision"],
|
|
129
|
-
branch: state["branch"]
|
|
124
|
+
version: string_value(state["version"]),
|
|
125
|
+
revision: string_value(state["revision"]),
|
|
126
|
+
branch: string_value(state["branch"])
|
|
130
127
|
)
|
|
131
128
|
end
|
|
132
129
|
|
|
130
|
+
sig { params(pin: T::Hash[String, Object], state_key: String).returns(T::Hash[String, Object]) }
|
|
131
|
+
def pin_state(pin, state_key)
|
|
132
|
+
state = pin[state_key]
|
|
133
|
+
state.is_a?(Hash) ? state : {}
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
sig { params(pin: T::Hash[String, Object], identity_key: String, schema_version: Integer).returns(T.nilable(String)) }
|
|
137
|
+
def pin_identity(pin, identity_key, schema_version)
|
|
138
|
+
identity = string_value(pin[identity_key])
|
|
139
|
+
schema_version == 1 ? identity&.downcase : identity
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
sig { params(value: T.nilable(Object)).returns(T.nilable(String)) }
|
|
143
|
+
def string_value(value)
|
|
144
|
+
value if value.is_a?(String)
|
|
145
|
+
end
|
|
146
|
+
|
|
133
147
|
sig do
|
|
134
148
|
params(
|
|
135
149
|
identity: T.nilable(String),
|
|
@@ -49,12 +49,12 @@ module Dependabot
|
|
|
49
49
|
# Returns a hash mapping normalized URL to requirement metadata.
|
|
50
50
|
# Each entry includes the Dependabot requirement string and the raw
|
|
51
51
|
# Xcode requirement kind/version info for use in metadata.
|
|
52
|
-
sig { returns(T::Hash[String, T::Hash[Symbol,
|
|
52
|
+
sig { returns(T::Hash[String, T::Hash[Symbol, Object]]) }
|
|
53
53
|
def parse
|
|
54
54
|
content = pbxproj_file.content
|
|
55
55
|
return {} unless content
|
|
56
56
|
|
|
57
|
-
requirements = T.let({}, T::Hash[String, T::Hash[Symbol,
|
|
57
|
+
requirements = T.let({}, T::Hash[String, T::Hash[Symbol, Object]])
|
|
58
58
|
|
|
59
59
|
content.scan(PACKAGE_REF_BLOCK).each do |url, requirement_block|
|
|
60
60
|
url = T.cast(url, String)
|
|
@@ -81,7 +81,7 @@ module Dependabot
|
|
|
81
81
|
|
|
82
82
|
sig do
|
|
83
83
|
params(block: String)
|
|
84
|
-
.returns(T.nilable(T::Hash[Symbol,
|
|
84
|
+
.returns(T.nilable(T::Hash[Symbol, Object]))
|
|
85
85
|
end
|
|
86
86
|
def parse_requirement_block(block)
|
|
87
87
|
kind = block.match(KIND_PATTERN)&.captures&.first
|
|
@@ -103,7 +103,7 @@ module Dependabot
|
|
|
103
103
|
end
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
-
sig { params(block: String).returns(T::Hash[Symbol,
|
|
106
|
+
sig { params(block: String).returns(T::Hash[Symbol, Object]) }
|
|
107
107
|
def build_up_to_next_major(block)
|
|
108
108
|
min_version = extract_version(block, MIN_VERSION_PATTERN)
|
|
109
109
|
requirement_string = "from: \"#{min_version}\""
|
|
@@ -116,7 +116,7 @@ module Dependabot
|
|
|
116
116
|
}
|
|
117
117
|
end
|
|
118
118
|
|
|
119
|
-
sig { params(block: String).returns(T::Hash[Symbol,
|
|
119
|
+
sig { params(block: String).returns(T::Hash[Symbol, Object]) }
|
|
120
120
|
def build_up_to_next_minor(block)
|
|
121
121
|
min_version = extract_version(block, MIN_VERSION_PATTERN)
|
|
122
122
|
requirement_string = ".upToNextMinor(from: \"#{min_version}\")"
|
|
@@ -129,7 +129,7 @@ module Dependabot
|
|
|
129
129
|
}
|
|
130
130
|
end
|
|
131
131
|
|
|
132
|
-
sig { params(block: String).returns(T::Hash[Symbol,
|
|
132
|
+
sig { params(block: String).returns(T::Hash[Symbol, Object]) }
|
|
133
133
|
def build_exact(block)
|
|
134
134
|
version = extract_version(block, MIN_VERSION_PATTERN) || extract_version(block, VERSION_PATTERN)
|
|
135
135
|
requirement_string = "exact: \"#{version}\""
|
|
@@ -142,7 +142,7 @@ module Dependabot
|
|
|
142
142
|
}
|
|
143
143
|
end
|
|
144
144
|
|
|
145
|
-
sig { params(block: String).returns(T::Hash[Symbol,
|
|
145
|
+
sig { params(block: String).returns(T::Hash[Symbol, Object]) }
|
|
146
146
|
def build_range(block)
|
|
147
147
|
min_version = extract_version(block, MIN_VERSION_PATTERN)
|
|
148
148
|
max_version = extract_version(block, MAX_VERSION_PATTERN)
|
|
@@ -156,7 +156,7 @@ module Dependabot
|
|
|
156
156
|
}
|
|
157
157
|
end
|
|
158
158
|
|
|
159
|
-
sig { params(block: String).returns(T::Hash[Symbol,
|
|
159
|
+
sig { params(block: String).returns(T::Hash[Symbol, Object]) }
|
|
160
160
|
def build_branch(block)
|
|
161
161
|
branch = block.match(BRANCH_PATTERN)&.captures&.first
|
|
162
162
|
|
|
@@ -168,7 +168,7 @@ module Dependabot
|
|
|
168
168
|
}
|
|
169
169
|
end
|
|
170
170
|
|
|
171
|
-
sig { params(block: String).returns(T::Hash[Symbol,
|
|
171
|
+
sig { params(block: String).returns(T::Hash[Symbol, Object]) }
|
|
172
172
|
def build_revision(block)
|
|
173
173
|
revision = block.match(REVISION_PATTERN)&.captures&.first
|
|
174
174
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "sorbet-runtime"
|
|
@@ -65,9 +65,9 @@ module Dependabot
|
|
|
65
65
|
# Collects requirement info from all project.pbxproj support files,
|
|
66
66
|
# keyed by Xcode scope directory so each resolved file can be enriched
|
|
67
67
|
# by requirements from its closest matching Xcode scope.
|
|
68
|
-
sig { returns(T::Hash[T.nilable(String), T::Hash[String, T::Hash[Symbol,
|
|
68
|
+
sig { returns(T::Hash[T.nilable(String), T::Hash[String, T::Hash[Symbol, Object]]]) }
|
|
69
69
|
def aggregate_pbxproj_requirements
|
|
70
|
-
scoped = T.let({}, T::Hash[T.nilable(String), T::Hash[String, T::Hash[Symbol,
|
|
70
|
+
scoped = T.let({}, T::Hash[T.nilable(String), T::Hash[String, T::Hash[Symbol, Object]]])
|
|
71
71
|
|
|
72
72
|
pbxproj_files.each do |pbxproj_file|
|
|
73
73
|
xcode_scope_dir = extract_xcode_scope_dir(pbxproj_file.name)
|
|
@@ -83,8 +83,8 @@ module Dependabot
|
|
|
83
83
|
|
|
84
84
|
sig do
|
|
85
85
|
params(
|
|
86
|
-
scoped_requirements: T::Hash[T.nilable(String), T::Hash[String, T::Hash[Symbol,
|
|
87
|
-
).returns(T::Hash[String, T::Hash[Symbol,
|
|
86
|
+
scoped_requirements: T::Hash[T.nilable(String), T::Hash[String, T::Hash[Symbol, Object]]]
|
|
87
|
+
).returns(T::Hash[String, T::Hash[Symbol, Object]])
|
|
88
88
|
end
|
|
89
89
|
def merge_scopes(scoped_requirements)
|
|
90
90
|
scoped_requirements.values.each_with_object({}) do |requirements, merged|
|
|
@@ -94,9 +94,9 @@ module Dependabot
|
|
|
94
94
|
|
|
95
95
|
sig do
|
|
96
96
|
params(
|
|
97
|
-
scoped_requirements: T::Hash[T.nilable(String), T::Hash[String, T::Hash[Symbol,
|
|
97
|
+
scoped_requirements: T::Hash[T.nilable(String), T::Hash[String, T::Hash[Symbol, Object]]],
|
|
98
98
|
resolved_file_name: String
|
|
99
|
-
).returns(T::Hash[String, T::Hash[Symbol,
|
|
99
|
+
).returns(T::Hash[String, T::Hash[Symbol, Object]])
|
|
100
100
|
end
|
|
101
101
|
def requirements_for_resolved_file(scoped_requirements:, resolved_file_name:)
|
|
102
102
|
scope_dir = extract_xcode_scope_dir(resolved_file_name)
|
|
@@ -129,7 +129,7 @@ module Dependabot
|
|
|
129
129
|
sig do
|
|
130
130
|
params(
|
|
131
131
|
dep: Dependabot::Dependency,
|
|
132
|
-
pbxproj_requirements: T::Hash[String, T::Hash[Symbol,
|
|
132
|
+
pbxproj_requirements: T::Hash[String, T::Hash[Symbol, Object]]
|
|
133
133
|
).returns(Dependabot::Dependency)
|
|
134
134
|
end
|
|
135
135
|
def enrich_with_pbxproj_requirements(dep, pbxproj_requirements)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "dependabot/file_updaters/base"
|
|
@@ -14,8 +14,8 @@ module Dependabot
|
|
|
14
14
|
sig do
|
|
15
15
|
params(
|
|
16
16
|
content: String,
|
|
17
|
-
old_requirements: T::Array[T::Hash[Symbol,
|
|
18
|
-
new_requirements: T::Array[T::Hash[Symbol,
|
|
17
|
+
old_requirements: T::Array[T::Hash[Symbol, Object]],
|
|
18
|
+
new_requirements: T::Array[T::Hash[Symbol, Object]]
|
|
19
19
|
)
|
|
20
20
|
.void
|
|
21
21
|
end
|
|
@@ -30,11 +30,13 @@ module Dependabot
|
|
|
30
30
|
updated_content = content
|
|
31
31
|
|
|
32
32
|
old_requirements.zip(new_requirements).each do |old, new|
|
|
33
|
+
old_metadata = metadata(old)
|
|
34
|
+
new_metadata = metadata(T.must(new))
|
|
33
35
|
updated_content = RequirementReplacer.new(
|
|
34
36
|
content: updated_content,
|
|
35
|
-
declaration:
|
|
36
|
-
old_requirement:
|
|
37
|
-
new_requirement:
|
|
37
|
+
declaration: string_value(old_metadata, :declaration_string),
|
|
38
|
+
old_requirement: string_value(old_metadata, :requirement_string),
|
|
39
|
+
new_requirement: string_value(new_metadata, :requirement_string)
|
|
38
40
|
).updated_content
|
|
39
41
|
end
|
|
40
42
|
|
|
@@ -46,11 +48,27 @@ module Dependabot
|
|
|
46
48
|
sig { returns(String) }
|
|
47
49
|
attr_reader :content
|
|
48
50
|
|
|
49
|
-
sig { returns(T::Array[T::Hash[Symbol,
|
|
51
|
+
sig { returns(T::Array[T::Hash[Symbol, Object]]) }
|
|
50
52
|
attr_reader :old_requirements
|
|
51
53
|
|
|
52
|
-
sig { returns(T::Array[T::Hash[Symbol,
|
|
54
|
+
sig { returns(T::Array[T::Hash[Symbol, Object]]) }
|
|
53
55
|
attr_reader :new_requirements
|
|
56
|
+
|
|
57
|
+
sig { params(requirement: T::Hash[Symbol, Object]).returns(T::Hash[Symbol, Object]) }
|
|
58
|
+
def metadata(requirement)
|
|
59
|
+
value = requirement[:metadata]
|
|
60
|
+
raise TypeError, "Expected metadata to be a Hash" unless value.is_a?(Hash)
|
|
61
|
+
|
|
62
|
+
value
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
sig { params(hash: T::Hash[Symbol, Object], key: Symbol).returns(String) }
|
|
66
|
+
def string_value(hash, key)
|
|
67
|
+
value = hash.fetch(key)
|
|
68
|
+
raise TypeError, "Expected #{key} to be a String" unless value.is_a?(String)
|
|
69
|
+
|
|
70
|
+
value
|
|
71
|
+
end
|
|
54
72
|
end
|
|
55
73
|
end
|
|
56
74
|
end
|
|
@@ -26,7 +26,7 @@ module Dependabot
|
|
|
26
26
|
2 => { url: "location", identity: "identity", pins_path: ["pins"] },
|
|
27
27
|
3 => { url: "location", identity: "identity", pins_path: ["pins"] }
|
|
28
28
|
}.freeze,
|
|
29
|
-
T::Hash[Integer, T::Hash[Symbol,
|
|
29
|
+
T::Hash[Integer, T::Hash[Symbol, Object]]
|
|
30
30
|
)
|
|
31
31
|
|
|
32
32
|
sig do
|
|
@@ -87,7 +87,7 @@ module Dependabot
|
|
|
87
87
|
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
|
88
88
|
attr_reader :workspace_files
|
|
89
89
|
|
|
90
|
-
sig { params(content: String).returns(T::Hash[String,
|
|
90
|
+
sig { params(content: String).returns(T::Hash[String, Object]) }
|
|
91
91
|
def parse_json(content)
|
|
92
92
|
JSON.parse(content)
|
|
93
93
|
rescue JSON::ParserError => e
|
|
@@ -97,7 +97,7 @@ module Dependabot
|
|
|
97
97
|
)
|
|
98
98
|
end
|
|
99
99
|
|
|
100
|
-
sig { params(parsed: T::Hash[String,
|
|
100
|
+
sig { params(parsed: T::Hash[String, Object]).returns(Integer) }
|
|
101
101
|
def detect_schema_version(parsed)
|
|
102
102
|
version = parsed["version"]
|
|
103
103
|
|
|
@@ -114,9 +114,9 @@ module Dependabot
|
|
|
114
114
|
|
|
115
115
|
sig do
|
|
116
116
|
params(
|
|
117
|
-
parsed: T::Hash[String,
|
|
117
|
+
parsed: T::Hash[String, Object],
|
|
118
118
|
schema_version: Integer,
|
|
119
|
-
keys: T::Hash[Symbol,
|
|
119
|
+
keys: T::Hash[Symbol, Object]
|
|
120
120
|
).void
|
|
121
121
|
end
|
|
122
122
|
def update_pins(parsed, schema_version, keys)
|
|
@@ -138,14 +138,14 @@ module Dependabot
|
|
|
138
138
|
|
|
139
139
|
sig do
|
|
140
140
|
params(
|
|
141
|
-
parsed: T::Hash[String,
|
|
141
|
+
parsed: T::Hash[String, Object],
|
|
142
142
|
path: T::Array[String]
|
|
143
|
-
).returns(
|
|
143
|
+
).returns(Object)
|
|
144
144
|
end
|
|
145
145
|
def dig_pins(parsed, path)
|
|
146
146
|
# Navigate nested hash using path keys
|
|
147
147
|
# Path is either ["object", "pins"] for v1 or ["pins"] for v2/v3
|
|
148
|
-
current = T.let(parsed,
|
|
148
|
+
current = T.let(parsed, Object)
|
|
149
149
|
path.each do |key|
|
|
150
150
|
break unless current.is_a?(Hash)
|
|
151
151
|
|
|
@@ -156,9 +156,9 @@ module Dependabot
|
|
|
156
156
|
|
|
157
157
|
sig do
|
|
158
158
|
params(
|
|
159
|
-
pins: T::Array[T::Hash[String,
|
|
159
|
+
pins: T::Array[T::Hash[String, Object]],
|
|
160
160
|
dependency: Dependabot::Dependency,
|
|
161
|
-
keys: T::Hash[Symbol,
|
|
161
|
+
keys: T::Hash[Symbol, Object],
|
|
162
162
|
schema_version: Integer
|
|
163
163
|
).void
|
|
164
164
|
end
|
|
@@ -192,11 +192,11 @@ module Dependabot
|
|
|
192
192
|
|
|
193
193
|
sig do
|
|
194
194
|
params(
|
|
195
|
-
pins: T::Array[T::Hash[String,
|
|
195
|
+
pins: T::Array[T::Hash[String, Object]],
|
|
196
196
|
dependency: Dependabot::Dependency,
|
|
197
|
-
keys: T::Hash[Symbol,
|
|
197
|
+
keys: T::Hash[Symbol, Object],
|
|
198
198
|
schema_version: Integer
|
|
199
|
-
).returns(T.nilable(T::Hash[String,
|
|
199
|
+
).returns(T.nilable(T::Hash[String, Object]))
|
|
200
200
|
end
|
|
201
201
|
def find_pin_for_dependency(pins, dependency, keys, schema_version)
|
|
202
202
|
identity_key = T.cast(keys[:identity], String)
|
|
@@ -205,6 +205,7 @@ module Dependabot
|
|
|
205
205
|
|
|
206
206
|
pins.find do |pin|
|
|
207
207
|
pin_identity = pin[identity_key]
|
|
208
|
+
pin_identity = nil unless pin_identity.is_a?(String)
|
|
208
209
|
pin_identity = pin_identity&.downcase if schema_version == 1
|
|
209
210
|
|
|
210
211
|
if identity && pin_identity == identity
|
|
@@ -22,14 +22,20 @@ module Dependabot
|
|
|
22
22
|
sig do
|
|
23
23
|
type_parameters(:T)
|
|
24
24
|
.params(
|
|
25
|
-
requirements: T::Array[T::Hash[Symbol,
|
|
25
|
+
requirements: T::Array[T::Hash[Symbol, Object]],
|
|
26
26
|
_blk: T.proc.params(declaration: NativeRequirement).returns(String)
|
|
27
27
|
)
|
|
28
|
-
.returns(T::Array[T::Hash[Symbol,
|
|
28
|
+
.returns(T::Array[T::Hash[Symbol, Object]])
|
|
29
29
|
end
|
|
30
30
|
def self.map_requirements(requirements, &_blk)
|
|
31
31
|
requirements.map do |requirement|
|
|
32
|
-
|
|
32
|
+
metadata = requirement[:metadata]
|
|
33
|
+
next requirement unless metadata.is_a?(Hash)
|
|
34
|
+
|
|
35
|
+
requirement_string = metadata[:requirement_string]
|
|
36
|
+
next requirement unless requirement_string.is_a?(String)
|
|
37
|
+
|
|
38
|
+
declaration = new(requirement_string)
|
|
33
39
|
|
|
34
40
|
new_declaration = yield(declaration)
|
|
35
41
|
new_requirement = new(new_declaration)
|
|
@@ -5,12 +5,47 @@ require "sorbet-runtime"
|
|
|
5
5
|
|
|
6
6
|
require "dependabot/requirement"
|
|
7
7
|
require "dependabot/utils"
|
|
8
|
+
require "dependabot/swift/version"
|
|
8
9
|
|
|
9
10
|
module Dependabot
|
|
10
11
|
module Swift
|
|
11
12
|
class Requirement < Dependabot::Requirement
|
|
12
13
|
extend T::Sig
|
|
13
14
|
|
|
15
|
+
quoted = OPS.keys.map { |k| Regexp.quote(k) }.join("|")
|
|
16
|
+
# Swift requirement grammar (intentionally not strict SemVer): allows multi-segment numeric
|
|
17
|
+
# cores like "4.2.5.1" for compatibility bounds, but still rejects leading zeros and malformed
|
|
18
|
+
# prerelease/build tails via SemVer-style dot-separated identifiers.
|
|
19
|
+
num = "(?:0|[1-9][0-9]*)"
|
|
20
|
+
pre_id = "(?:0|[1-9][0-9]*|[0-9]*[A-Za-z-][0-9A-Za-z-]*)"
|
|
21
|
+
version_pattern = "#{num}(?:\\.#{num})*" \
|
|
22
|
+
"(?:-#{pre_id}(?:\\.#{pre_id})*)?" \
|
|
23
|
+
'(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?'
|
|
24
|
+
|
|
25
|
+
PATTERN = T.let(/\A\s*(#{quoted})?\s*(#{version_pattern})\s*\z/, Regexp)
|
|
26
|
+
|
|
27
|
+
# Parse each boundary into a Swift::Version so prerelease boundaries use SemVer section 11 ordering.
|
|
28
|
+
sig { override.params(obj: T.any(Gem::Version, String)).returns([String, Gem::Version]) }
|
|
29
|
+
def self.parse(obj)
|
|
30
|
+
# Preserve a Swift::Version; convert other stable Gem::Versions so the boundary stays orderable.
|
|
31
|
+
return ["=", obj] if obj.is_a?(Swift::Version)
|
|
32
|
+
|
|
33
|
+
if obj.is_a?(Gem::Version)
|
|
34
|
+
# Reject prerelease Gem::Versions: #to_s is lossily canonicalized (e.g. "1.0.0-alpha" -> "1.0.0.pre.alpha").
|
|
35
|
+
raise BadRequirementError, "Illformed requirement [#{obj.inspect}]" if obj.prerelease?
|
|
36
|
+
|
|
37
|
+
return ["=", Swift::Version.new(obj.to_s)]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
unless (matches = PATTERN.match(obj.to_s))
|
|
41
|
+
raise BadRequirementError, "Illformed requirement [#{obj.inspect}]"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
return DefaultRequirement if matches[1] == ">=" && matches[2] == "0"
|
|
45
|
+
|
|
46
|
+
[matches[1] || "=", Swift::Version.new(T.must(matches[2]))]
|
|
47
|
+
end
|
|
48
|
+
|
|
14
49
|
# For consistency with other languages, we define a requirements array.
|
|
15
50
|
# Swift doesn't have an `OR` separator for requirements, so it
|
|
16
51
|
# always contains a single element.
|
|
@@ -93,8 +93,8 @@ module Dependabot
|
|
|
93
93
|
|
|
94
94
|
sig do
|
|
95
95
|
params(
|
|
96
|
-
source: T.nilable(T::Hash[T.any(String, Symbol),
|
|
97
|
-
).returns(T.nilable(T::Hash[T.any(String, Symbol),
|
|
96
|
+
source: T.nilable(T::Hash[T.any(String, Symbol), Object])
|
|
97
|
+
).returns(T.nilable(T::Hash[T.any(String, Symbol), Object]))
|
|
98
98
|
end
|
|
99
99
|
def update_source_ref(source)
|
|
100
100
|
return source unless source && target_version
|
|
@@ -38,16 +38,19 @@ module Dependabot
|
|
|
38
38
|
tag = latest_resolvable_version_tag
|
|
39
39
|
return nil unless tag
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
version = tag_version(tag)
|
|
42
|
+
return nil unless version
|
|
43
|
+
|
|
44
|
+
Version.new(version)
|
|
42
45
|
end
|
|
43
46
|
|
|
44
47
|
# Returns the full tag info including commit_sha for the latest resolvable version
|
|
45
48
|
# Memoized to avoid redundant computation when called from UpdateChecker
|
|
46
|
-
sig { returns(T.nilable(T::Hash[Symbol,
|
|
49
|
+
sig { returns(T.nilable(T::Hash[Symbol, Object])) }
|
|
47
50
|
def latest_resolvable_version_tag
|
|
48
51
|
@latest_resolvable_version_tag ||= T.let(
|
|
49
52
|
compute_latest_resolvable_version_tag,
|
|
50
|
-
T.nilable(T::Hash[Symbol,
|
|
53
|
+
T.nilable(T::Hash[Symbol, Object])
|
|
51
54
|
)
|
|
52
55
|
end
|
|
53
56
|
|
|
@@ -56,16 +59,17 @@ module Dependabot
|
|
|
56
59
|
return nil unless version_pinned?
|
|
57
60
|
|
|
58
61
|
tags = git_commit_checker.local_tags_for_allowed_versions
|
|
59
|
-
|
|
60
|
-
tags,
|
|
62
|
+
relevant_versions = Dependabot::UpdateCheckers::VersionFilters.filter_vulnerable_versions(
|
|
63
|
+
tags.filter_map { |tag| tag_version(tag) },
|
|
61
64
|
security_advisories
|
|
62
65
|
)
|
|
66
|
+
relevant_tags = tags.select { |tag| (version = tag_version(tag)) && relevant_versions.include?(version) }
|
|
63
67
|
relevant_tags = filter_lower_tags(relevant_tags)
|
|
64
68
|
|
|
65
|
-
lowest_tag = relevant_tags.min_by { |tag|
|
|
69
|
+
lowest_tag = relevant_tags.min_by { |tag| T.must(tag_version(tag)) }
|
|
66
70
|
return nil unless lowest_tag
|
|
67
71
|
|
|
68
|
-
Version.new(
|
|
72
|
+
Version.new(T.must(tag_version(lowest_tag)))
|
|
69
73
|
end
|
|
70
74
|
|
|
71
75
|
sig { returns(T::Boolean) }
|
|
@@ -86,7 +90,7 @@ module Dependabot
|
|
|
86
90
|
sig { returns(T::Array[Dependabot::SecurityAdvisory]) }
|
|
87
91
|
attr_reader :security_advisories
|
|
88
92
|
|
|
89
|
-
sig { returns(T.nilable(T::Hash[Symbol,
|
|
93
|
+
sig { returns(T.nilable(T::Hash[Symbol, Object])) }
|
|
90
94
|
def compute_latest_resolvable_version_tag
|
|
91
95
|
return nil unless version_pinned?
|
|
92
96
|
|
|
@@ -106,7 +110,7 @@ module Dependabot
|
|
|
106
110
|
# For versionRange requirements, find the highest version that satisfies
|
|
107
111
|
# the explicit upper bound constraint. We don't filter out lower versions here
|
|
108
112
|
# because `can_update?` will decide whether an update is actually needed.
|
|
109
|
-
sig { returns(T.nilable(T::Hash[Symbol,
|
|
113
|
+
sig { returns(T.nilable(T::Hash[Symbol, Object])) }
|
|
110
114
|
def compute_latest_version_in_range
|
|
111
115
|
requirement = dependency_requirement
|
|
112
116
|
return nil unless requirement
|
|
@@ -132,7 +136,7 @@ module Dependabot
|
|
|
132
136
|
dependency.requirements.first&.dig(:metadata, :kind)
|
|
133
137
|
end
|
|
134
138
|
|
|
135
|
-
sig { params(version:
|
|
139
|
+
sig { params(version: Object).returns(T::Boolean) }
|
|
136
140
|
def version_meets_requirements?(version)
|
|
137
141
|
kind = requirement_kind
|
|
138
142
|
|
|
@@ -174,14 +178,23 @@ module Dependabot
|
|
|
174
178
|
|
|
175
179
|
sig do
|
|
176
180
|
params(
|
|
177
|
-
tags: T::Array[T::Hash[Symbol,
|
|
178
|
-
).returns(T::Array[T::Hash[Symbol,
|
|
181
|
+
tags: T::Array[T::Hash[Symbol, Object]]
|
|
182
|
+
).returns(T::Array[T::Hash[Symbol, Object]])
|
|
179
183
|
end
|
|
180
184
|
def filter_lower_tags(tags)
|
|
181
185
|
current = current_version
|
|
182
186
|
return tags unless current
|
|
183
187
|
|
|
184
|
-
tags.select
|
|
188
|
+
tags.select do |tag|
|
|
189
|
+
version = tag_version(tag)
|
|
190
|
+
version && version > current
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
sig { params(tag: T::Hash[Symbol, Object]).returns(T.nilable(Gem::Version)) }
|
|
195
|
+
def tag_version(tag)
|
|
196
|
+
version = tag[:version]
|
|
197
|
+
version if version.is_a?(Gem::Version)
|
|
185
198
|
end
|
|
186
199
|
|
|
187
200
|
sig { returns(T.nilable(Dependabot::Version)) }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "sorbet-runtime"
|
|
@@ -81,7 +81,8 @@ module Dependabot
|
|
|
81
81
|
latest = latest_resolvable_version
|
|
82
82
|
if latest && target == latest
|
|
83
83
|
tag = xcode_version_resolver.latest_resolvable_version_tag
|
|
84
|
-
|
|
84
|
+
tag_commit_sha = tag&.fetch(:commit_sha, nil)
|
|
85
|
+
commit_sha = tag_commit_sha if tag_commit_sha.is_a?(String)
|
|
85
86
|
end
|
|
86
87
|
|
|
87
88
|
RequirementsUpdater.new(
|
|
@@ -111,7 +112,7 @@ module Dependabot
|
|
|
111
112
|
tag = latest_version_tag
|
|
112
113
|
return unless tag
|
|
113
114
|
|
|
114
|
-
tag
|
|
115
|
+
tag_version(tag)
|
|
115
116
|
end
|
|
116
117
|
|
|
117
118
|
sig { returns(T.nilable(Dependabot::Version)) }
|
|
@@ -123,7 +124,7 @@ module Dependabot
|
|
|
123
124
|
tag = latest_version_tag
|
|
124
125
|
return unless tag
|
|
125
126
|
|
|
126
|
-
tag
|
|
127
|
+
tag_version(tag)
|
|
127
128
|
end
|
|
128
129
|
|
|
129
130
|
sig { returns(T.nilable(Dependabot::Version)) }
|
|
@@ -135,7 +136,7 @@ module Dependabot
|
|
|
135
136
|
tag = lowest_security_fix_version_tag
|
|
136
137
|
return unless tag
|
|
137
138
|
|
|
138
|
-
tag
|
|
139
|
+
tag_version(tag)
|
|
139
140
|
end
|
|
140
141
|
|
|
141
142
|
sig { returns(T.nilable(Dependabot::Version)) }
|
|
@@ -170,7 +171,7 @@ module Dependabot
|
|
|
170
171
|
Version.new(lowest_resolvable_security_fix_version)
|
|
171
172
|
end
|
|
172
173
|
|
|
173
|
-
sig { params(requirements: T::Array[T::Hash[Symbol,
|
|
174
|
+
sig { params(requirements: T::Array[T::Hash[Symbol, Object]]).returns(VersionResolver) }
|
|
174
175
|
def version_resolver_for(requirements)
|
|
175
176
|
VersionResolver.new(
|
|
176
177
|
dependency: dependency,
|
|
@@ -181,26 +182,26 @@ module Dependabot
|
|
|
181
182
|
)
|
|
182
183
|
end
|
|
183
184
|
|
|
184
|
-
sig { returns(T.nilable(T::Hash[Symbol,
|
|
185
|
+
sig { returns(T.nilable(T::Hash[Symbol, Object])) }
|
|
185
186
|
def latest_version_tag
|
|
186
187
|
git_commit_checker.local_tag_for_latest_version(update_cooldown)
|
|
187
188
|
end
|
|
188
189
|
|
|
189
|
-
sig { returns(T::Array[T::Hash[Symbol,
|
|
190
|
+
sig { returns(T::Array[T::Hash[Symbol, Object]]) }
|
|
190
191
|
def unlocked_requirements
|
|
191
192
|
NativeRequirement.map_requirements(old_requirements) do |_old_requirement|
|
|
192
193
|
"\"#{dependency.version}\"...\"#{latest_version}\""
|
|
193
194
|
end
|
|
194
195
|
end
|
|
195
196
|
|
|
196
|
-
sig { returns(T::Array[T::Hash[Symbol,
|
|
197
|
+
sig { returns(T::Array[T::Hash[Symbol, Object]]) }
|
|
197
198
|
def force_lowest_security_fix_requirements
|
|
198
199
|
NativeRequirement.map_requirements(old_requirements) do |_old_requirement|
|
|
199
200
|
"\"#{lowest_security_fix_version}\"...\"#{lowest_security_fix_version}\""
|
|
200
201
|
end
|
|
201
202
|
end
|
|
202
203
|
|
|
203
|
-
sig { params(new_requirements: T::Array[T::Hash[Symbol,
|
|
204
|
+
sig { params(new_requirements: T::Array[T::Hash[Symbol, Object]]).returns(Dependabot::DependencyFile) }
|
|
204
205
|
def prepare_manifest_for(new_requirements)
|
|
205
206
|
manifest_file = T.must(manifest)
|
|
206
207
|
|
|
@@ -256,26 +257,39 @@ module Dependabot
|
|
|
256
257
|
)
|
|
257
258
|
end
|
|
258
259
|
|
|
259
|
-
sig { returns(T.nilable(T::Hash[Symbol,
|
|
260
|
+
sig { returns(T.nilable(T::Hash[Symbol, Object])) }
|
|
260
261
|
def lowest_security_fix_version_tag
|
|
261
262
|
tags = git_commit_checker.local_tags_for_allowed_versions
|
|
262
263
|
find_lowest_secure_version(tags)
|
|
263
264
|
end
|
|
264
265
|
|
|
265
|
-
sig { params(tags: T::Array[T::Hash[Symbol,
|
|
266
|
+
sig { params(tags: T::Array[T::Hash[Symbol, Object]]).returns(T.nilable(T::Hash[Symbol, Object])) }
|
|
266
267
|
def find_lowest_secure_version(tags)
|
|
267
|
-
|
|
268
|
+
relevant_versions = Dependabot::UpdateCheckers::VersionFilters.filter_vulnerable_versions(
|
|
269
|
+
tags.filter_map { |tag| tag_version(tag) },
|
|
270
|
+
security_advisories
|
|
271
|
+
)
|
|
272
|
+
relevant_tags = tags.select { |tag| (version = tag_version(tag)) && relevant_versions.include?(version) }
|
|
268
273
|
relevant_tags = filter_lower_tags(relevant_tags)
|
|
269
274
|
|
|
270
|
-
relevant_tags.min_by { |tag|
|
|
275
|
+
relevant_tags.min_by { |tag| T.must(tag_version(tag)) }
|
|
271
276
|
end
|
|
272
277
|
|
|
273
|
-
sig { params(tags_array: T::Array[T::Hash[Symbol,
|
|
278
|
+
sig { params(tags_array: T::Array[T::Hash[Symbol, Object]]).returns(T::Array[T::Hash[Symbol, Object]]) }
|
|
274
279
|
def filter_lower_tags(tags_array)
|
|
275
280
|
return tags_array unless current_version
|
|
276
281
|
|
|
277
282
|
tags_array
|
|
278
|
-
.select
|
|
283
|
+
.select do |tag|
|
|
284
|
+
version = tag_version(tag)
|
|
285
|
+
version && version > current_version
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
sig { params(tag: T::Hash[Symbol, Object]).returns(T.nilable(Dependabot::Version)) }
|
|
290
|
+
def tag_version(tag)
|
|
291
|
+
version = tag[:version]
|
|
292
|
+
Dependabot::Swift::Version.new(version.to_s) if version.is_a?(Gem::Version)
|
|
279
293
|
end
|
|
280
294
|
|
|
281
295
|
sig { returns(XcodeVersionResolver) }
|
|
@@ -1,12 +1,226 @@
|
|
|
1
1
|
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
+
require "sorbet-runtime"
|
|
5
|
+
|
|
4
6
|
require "dependabot/utils"
|
|
5
7
|
require "dependabot/version"
|
|
6
8
|
|
|
7
9
|
module Dependabot
|
|
8
10
|
module Swift
|
|
11
|
+
# Swift uses SemVer: strict validation in .correct?, section 11 pre-release precedence in #<=>.
|
|
12
|
+
# #initialize stays tolerant because GitCommitChecker builds unchecked versions (e.g. "0.0.0.0").
|
|
9
13
|
class Version < Dependabot::Version
|
|
14
|
+
extend T::Sig
|
|
15
|
+
|
|
16
|
+
# SEMVER_REGEX uses ^/$ line anchors; anchor to the whole string to reject multiline.
|
|
17
|
+
SEMVER_ANCHORED = T.let(/\A#{SEMVER_REGEX.source}\z/x, Regexp)
|
|
18
|
+
|
|
19
|
+
sig { override.params(version: VersionParameter).returns(T::Boolean) }
|
|
20
|
+
def self.correct?(version)
|
|
21
|
+
return false if version.nil?
|
|
22
|
+
|
|
23
|
+
# Strict SemVer only: rejects "1.0.0.alpha", "0.0.0.0", "01.2.3" and multiline input.
|
|
24
|
+
version.to_s.delete_prefix("v").match?(SEMVER_ANCHORED)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
sig { override.params(version: VersionParameter).void }
|
|
28
|
+
def initialize(version)
|
|
29
|
+
@version_string = T.let(version.to_s.dup.freeze, String)
|
|
30
|
+
|
|
31
|
+
stripped = version.to_s.delete_prefix("v")
|
|
32
|
+
pre_part, plus, build = stripped.partition("+")
|
|
33
|
+
# Strip only well-formed build metadata (SemVer rule 10 ignores it); a malformed "+…" tail is
|
|
34
|
+
# kept so it stays distinct and sorts below the release instead of canonicalizing to it.
|
|
35
|
+
build_ok = plus.empty? || build.match?(/\A[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*\z/)
|
|
36
|
+
@semver = T.let((build_ok ? pre_part : stripped).freeze, String)
|
|
37
|
+
|
|
38
|
+
base, suffix = pre_part.split("-", 2)
|
|
39
|
+
# Split on "-" only when the core before it is numeric (else the hyphen is part of the tail).
|
|
40
|
+
if suffix && !base.to_s.match?(/\A[0-9]+(?:\.[0-9]+)*\z/)
|
|
41
|
+
base = pre_part
|
|
42
|
+
suffix = nil
|
|
43
|
+
end
|
|
44
|
+
release, inferred = normalize_release(T.must(base))
|
|
45
|
+
suffix ||= inferred
|
|
46
|
+
# Fold a malformed build tail into the pre-release suffix so it stays distinct and orderable.
|
|
47
|
+
suffix = [suffix, "+#{build}"].compact.join(".") unless build_ok
|
|
48
|
+
@prerelease_suffix = T.let(suffix, T.nilable(String))
|
|
49
|
+
@release_core = T.let(Gem::Version.new(release), Gem::Version)
|
|
50
|
+
# Seed the superclass with a strict-SemVer form so tolerant tags never raise, while mixed
|
|
51
|
+
# comparisons still see the pre-release state.
|
|
52
|
+
super(semver_seed(release, @prerelease_suffix))
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
sig { override.returns(String) }
|
|
56
|
+
def to_s
|
|
57
|
+
@version_string
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
sig { override.returns(String) }
|
|
61
|
+
def to_semver
|
|
62
|
+
@semver
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
sig { returns(Gem::Version) }
|
|
66
|
+
def bump
|
|
67
|
+
# Bump the full-precision release core so "~>" bounds ignore the padded 3-segment seed.
|
|
68
|
+
@release_core.bump
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
sig { override.returns(T::Boolean) }
|
|
72
|
+
def prerelease?
|
|
73
|
+
return true unless @prerelease_suffix.nil?
|
|
74
|
+
|
|
75
|
+
super
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Strict-SemVer range with "-0" bounds (earliest prerelease) so the grammar accepts it.
|
|
79
|
+
sig { override.returns(T::Array[String]) }
|
|
80
|
+
def ignored_minor_versions
|
|
81
|
+
parts = to_semver.split(".")
|
|
82
|
+
major = parts[0].to_i
|
|
83
|
+
minor = parts.fetch(1, 0).to_i
|
|
84
|
+
[">= #{major}.#{minor + 1}.0-0, < #{major + 1}.0.0-0"]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Strict-SemVer floor at "-0" (earliest prerelease) so a semver-major ignore covers numeric prereleases too.
|
|
88
|
+
sig { override.returns(T::Array[String]) }
|
|
89
|
+
def ignored_major_versions
|
|
90
|
+
major = T.must(to_semver.split(".").first).to_i
|
|
91
|
+
[">= #{major + 1}.0.0-0"]
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
sig { params(other: Object).returns(T::Boolean) }
|
|
95
|
+
def eql?(other)
|
|
96
|
+
return false unless other.is_a?(Version)
|
|
97
|
+
|
|
98
|
+
to_semver == other.to_semver
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
sig { override.returns(Integer) }
|
|
102
|
+
def hash
|
|
103
|
+
to_semver.hash
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
sig { params(other: Object).returns(T::Boolean) }
|
|
107
|
+
def ==(other)
|
|
108
|
+
cmp = self <=> other
|
|
109
|
+
!cmp.nil? && cmp.zero?
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
sig { params(other: Object).returns(T.nilable(Integer)) }
|
|
113
|
+
def <=>(other)
|
|
114
|
+
return nil if other.nil?
|
|
115
|
+
|
|
116
|
+
resolved = coerce_operand(other)
|
|
117
|
+
return nil if resolved.nil?
|
|
118
|
+
|
|
119
|
+
# Compare release cores directly (not via super, whose seeded state uses RubyGems
|
|
120
|
+
# pre-release ordering) so section 11 governs the pre-release tiebreak.
|
|
121
|
+
release_cmp = release_core <=> resolved.release_core
|
|
122
|
+
return release_cmp unless release_cmp&.zero?
|
|
123
|
+
|
|
124
|
+
compare_semver_prerelease(@prerelease_suffix, resolved.prerelease_suffix)
|
|
125
|
+
rescue ArgumentError
|
|
126
|
+
nil
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
protected
|
|
130
|
+
|
|
131
|
+
sig { returns(T.nilable(String)) }
|
|
132
|
+
attr_reader :prerelease_suffix
|
|
133
|
+
|
|
134
|
+
sig { returns(Gem::Version) }
|
|
135
|
+
attr_reader :release_core
|
|
136
|
+
|
|
137
|
+
private
|
|
138
|
+
|
|
139
|
+
# Coerce an operand to a Swift::Version for section 11 ordering, or nil if not orderable.
|
|
140
|
+
# A raw Gem::Version pre-release is declined (lossy #to_s, divergent RubyGems ordering); any
|
|
141
|
+
# #to_s failure also yields nil to keep comparison safe (never raises).
|
|
142
|
+
sig { params(other: Object).returns(T.nilable(Version)) }
|
|
143
|
+
def coerce_operand(other)
|
|
144
|
+
return other if other.is_a?(Version)
|
|
145
|
+
return nil if other.is_a?(Gem::Version) && other.prerelease?
|
|
146
|
+
|
|
147
|
+
normalized = other.to_s.delete_prefix("v")
|
|
148
|
+
if normalized.include?("+")
|
|
149
|
+
return nil unless Version.correct?(normalized)
|
|
150
|
+
|
|
151
|
+
normalized = T.must(normalized.split("+").first)
|
|
152
|
+
end
|
|
153
|
+
return nil unless Gem::Version.correct?(normalized)
|
|
154
|
+
|
|
155
|
+
T.cast(Version.new(normalized), Version)
|
|
156
|
+
rescue StandardError
|
|
157
|
+
nil
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Returns [release core, inferred pre-release or nil]: a non-SemVer tag is reduced to its
|
|
161
|
+
# numeric core with the non-numeric tail as pre-release ("1.0.0.alpha" -> "alpha").
|
|
162
|
+
sig { params(base: String).returns([String, T.nilable(String)]) }
|
|
163
|
+
def normalize_release(base)
|
|
164
|
+
return [base, nil] if self.class.correct?(base)
|
|
165
|
+
|
|
166
|
+
parts = base.split(".")
|
|
167
|
+
numeric = parts.take_while { |s| s.match?(/\A\d+\z/) }
|
|
168
|
+
raise ArgumentError, "Malformed version number string #{@version_string}" if numeric.empty?
|
|
169
|
+
|
|
170
|
+
tail = parts.drop(numeric.length)
|
|
171
|
+
# Preserve every numeric segment so multi-segment requirement bounds keep full precision.
|
|
172
|
+
release = numeric.map { |s| s.to_i.to_s }.join(".")
|
|
173
|
+
[release, tail.empty? ? nil : tail.join(".")]
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Strict-SemVer seed for the Gem superclass: Gem::Version#initialize validates via
|
|
177
|
+
# self.class.correct? (strict 3-part SemVer here), so the seed is a 3-segment core plus the
|
|
178
|
+
# suffix only when it is valid SemVer, letting tolerant tags (e.g. "0.0.0.0") never raise.
|
|
179
|
+
sig { params(release: String, suffix: T.nilable(String)).returns(String) }
|
|
180
|
+
def semver_seed(release, suffix)
|
|
181
|
+
core = (release.split(".").first(3) + %w(0 0 0)).first(3).join(".")
|
|
182
|
+
return core unless suffix && self.class.correct?("0.0.0-#{suffix}")
|
|
183
|
+
|
|
184
|
+
"#{core}-#{suffix}"
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# SemVer section 11 pre-release precedence: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0.
|
|
188
|
+
sig { params(left: T.nilable(String), right: T.nilable(String)).returns(Integer) }
|
|
189
|
+
def compare_semver_prerelease(left, right)
|
|
190
|
+
return 0 if left.nil? && right.nil?
|
|
191
|
+
return 1 if left.nil?
|
|
192
|
+
return -1 if right.nil?
|
|
193
|
+
|
|
194
|
+
left_ids = left.split(".")
|
|
195
|
+
right_ids = right.split(".")
|
|
196
|
+
|
|
197
|
+
# Compare identifiers pairwise over the common prefix.
|
|
198
|
+
[left_ids.length, right_ids.length].min.times do |i|
|
|
199
|
+
cmp = compare_semver_identifier(T.must(left_ids[i]), T.must(right_ids[i]))
|
|
200
|
+
return cmp unless cmp.zero?
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# All shared identifiers equal: more pre-release fields ranks higher.
|
|
204
|
+
left_ids.length <=> right_ids.length
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
sig { params(left: String, right: String).returns(Integer) }
|
|
208
|
+
def compare_semver_identifier(left, right)
|
|
209
|
+
left_numeric = left.match?(/\A\d+\z/)
|
|
210
|
+
right_numeric = right.match?(/\A\d+\z/)
|
|
211
|
+
|
|
212
|
+
if left_numeric && right_numeric
|
|
213
|
+
cmp = left.to_i <=> right.to_i
|
|
214
|
+
# Tiebreak textually so SemVer-invalid leading-zero ids ("01" vs "1") stay distinct.
|
|
215
|
+
cmp.zero? ? T.must(left <=> right) : cmp
|
|
216
|
+
elsif left_numeric
|
|
217
|
+
-1
|
|
218
|
+
elsif right_numeric
|
|
219
|
+
1
|
|
220
|
+
else
|
|
221
|
+
T.must(left <=> right)
|
|
222
|
+
end
|
|
223
|
+
end
|
|
10
224
|
end
|
|
11
225
|
end
|
|
12
226
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dependabot-swift
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.387.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dependabot
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.387.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.387.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: debug
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -272,7 +272,7 @@ licenses:
|
|
|
272
272
|
- MIT
|
|
273
273
|
metadata:
|
|
274
274
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
275
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
275
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.387.0
|
|
276
276
|
rdoc_options: []
|
|
277
277
|
require_paths:
|
|
278
278
|
- lib
|