dependabot-julia 0.398.0 → 0.399.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/julia/file_fetcher.rb +31 -3
- data/lib/dependabot/julia/file_parser.rb +47 -15
- data/lib/dependabot/julia/file_updater.rb +45 -68
- data/lib/dependabot/julia/package/package_details_fetcher.rb +17 -20
- data/lib/dependabot/julia/registry_client/result.rb +11 -1
- data/lib/dependabot/julia/registry_client.rb +4 -2
- data/lib/dependabot/julia/requirement.rb +16 -1
- data/lib/dependabot/julia/update_checker/latest_version_finder.rb +41 -14
- data/lib/dependabot/julia/update_checker/requirements_updater.rb +24 -7
- data/lib/dependabot/julia/update_checker.rb +21 -2
- data/lib/dependabot/julia/version.rb +8 -0
- data/lib/dependabot/julia.rb +9 -2
- 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: 6c3e654c12908a919461515b6c592e15e2382f106f203b0def25ed45bc68205b
|
|
4
|
+
data.tar.gz: b9c55d333c085e4cd51fd74d88e33fd98c8d379ea41be890fcf83c561f4c06ba
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3a1cdb18bb53b82740729fd4ce2c8276457dd0ac796f38263844fc5ec6e20a36c84d9d2882f04d0834d006080136b5f5b457eed630ad9434625912a174362baf
|
|
7
|
+
data.tar.gz: a74b876e844080eb47dad827cef47cef9c861e999e8afcc013da8d12206a6a8e2131fc5810af4e82260f38c179b053d3dae0b64c2badb8bfb3ba3af3c9950f19
|
|
@@ -34,19 +34,47 @@ module Dependabot
|
|
|
34
34
|
def fetch_files_using_julia_helper(temp_dir)
|
|
35
35
|
workspace_info = registry_client.find_workspace_project_files(temp_dir.to_s)
|
|
36
36
|
if workspace_info.is_a?(Dependabot::Julia::RegistryClient::Result::Failure)
|
|
37
|
-
|
|
37
|
+
raise_workspace_failure(workspace_info, temp_dir.to_s)
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
project_files = workspace_info.project_files
|
|
41
|
-
|
|
41
|
+
manifest_paths = workspace_info.manifest_files
|
|
42
|
+
manifest_paths = [workspace_info.manifest_file] if manifest_paths.empty?
|
|
42
43
|
|
|
43
44
|
fetched_files = fetch_all_project_files(project_files, temp_dir.to_s)
|
|
44
45
|
raise Dependabot::DependencyFileNotFound, "No Project.toml or JuliaProject.toml found." if fetched_files.empty?
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
manifest_paths.each do |manifest_path|
|
|
48
|
+
fetch_manifest_file(fetched_files, manifest_path, project_files, temp_dir.to_s)
|
|
49
|
+
end
|
|
47
50
|
fetched_files
|
|
48
51
|
end
|
|
49
52
|
|
|
53
|
+
# Pkg refuses a project it cannot read (a [compat] entry for a package
|
|
54
|
+
# in no dependency section, say), so report its reason against the
|
|
55
|
+
# project file rather than claiming there is none
|
|
56
|
+
sig do
|
|
57
|
+
params(failure: Dependabot::Julia::RegistryClient::Result::Failure, temp_dir: String).returns(T.noreturn)
|
|
58
|
+
end
|
|
59
|
+
def raise_workspace_failure(failure, temp_dir)
|
|
60
|
+
project_name = %w(JuliaProject.toml Project.toml).find { |name| File.exist?(File.join(temp_dir, name)) }
|
|
61
|
+
raise Dependabot::DependencyFileNotFound, "No Project.toml or JuliaProject.toml found." unless project_name
|
|
62
|
+
|
|
63
|
+
raise Dependabot::DependencyFileNotParseable.new(
|
|
64
|
+
File.join(directory, project_name),
|
|
65
|
+
relative_to(failure.message, temp_dir)
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Pkg may report the temporary directory by its realpath
|
|
70
|
+
# ("/private/tmp/..." on macOS); strip that first so the shorter form
|
|
71
|
+
# cannot match inside it
|
|
72
|
+
sig { params(message: String, dir: String).returns(String) }
|
|
73
|
+
def relative_to(message, dir)
|
|
74
|
+
prefixes = [File.exist?(dir) ? File.realpath(dir) : dir, dir].uniq.map { |prefix| File.join(prefix, "") }
|
|
75
|
+
prefixes.reduce(message) { |text, prefix| text.gsub(prefix, "") }
|
|
76
|
+
end
|
|
77
|
+
|
|
50
78
|
sig { params(project_files: T::Array[String], base_dir: String).returns(T::Array[Dependabot::DependencyFile]) }
|
|
51
79
|
def fetch_all_project_files(project_files, base_dir)
|
|
52
80
|
project_files.filter_map do |project_path|
|
|
@@ -130,6 +130,14 @@ module Dependabot
|
|
|
130
130
|
dependencies_map,
|
|
131
131
|
workspace_package_uuids
|
|
132
132
|
)
|
|
133
|
+
|
|
134
|
+
merge_dependencies_from_list(
|
|
135
|
+
result.extra_dependencies,
|
|
136
|
+
["extras"],
|
|
137
|
+
proj_file.name,
|
|
138
|
+
dependencies_map,
|
|
139
|
+
workspace_package_uuids
|
|
140
|
+
)
|
|
133
141
|
end
|
|
134
142
|
|
|
135
143
|
apply_manifest_versions(dependencies_map)
|
|
@@ -150,6 +158,12 @@ module Dependabot
|
|
|
150
158
|
# entry is maintained
|
|
151
159
|
next dep if dep.metadata.key?(:julia_stdlib_versions)
|
|
152
160
|
|
|
161
|
+
# A weakdep or extra found in the manifest is there as an indirect
|
|
162
|
+
# dependency of something else; the helper only bumps [deps]
|
|
163
|
+
# entries, so a version would announce a manifest update that never
|
|
164
|
+
# happens. It gets compat updates only.
|
|
165
|
+
next dep unless direct_dependency?(dep)
|
|
166
|
+
|
|
153
167
|
uuid = T.cast(dep.metadata[:julia_uuid], T.nilable(String))
|
|
154
168
|
version = uuid && versions[uuid]
|
|
155
169
|
next dep unless version
|
|
@@ -164,22 +178,34 @@ module Dependabot
|
|
|
164
178
|
end
|
|
165
179
|
end
|
|
166
180
|
|
|
181
|
+
sig { params(dep: Dependabot::Dependency).returns(T::Boolean) }
|
|
182
|
+
def direct_dependency?(dep)
|
|
183
|
+
dep.requirements.any? { |req| req.groups&.include?("deps") }
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# An environment can have a manifest per Julia release (Manifest-v1.12.toml
|
|
187
|
+
# beside Manifest.toml). The oldest version across them is the current one,
|
|
188
|
+
# so a manifest that lags behind the others still gets updated.
|
|
167
189
|
sig { returns(T::Hash[String, String]) }
|
|
168
190
|
def manifest_versions_by_uuid
|
|
169
|
-
manifest
|
|
170
|
-
|
|
191
|
+
manifest_files.each_with_object(T.let({}, T::Hash[String, String])) do |manifest, map|
|
|
192
|
+
result = parse_manifest_content(T.must(manifest.content))
|
|
171
193
|
|
|
172
|
-
|
|
194
|
+
if result.is_a?(Dependabot::Julia::RegistryClient::Result::Failure)
|
|
195
|
+
Dependabot.logger.warn("Failed to parse Julia manifest #{manifest.name}: #{result.message}")
|
|
196
|
+
next
|
|
197
|
+
end
|
|
173
198
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
return {}
|
|
177
|
-
end
|
|
199
|
+
result.dependencies.each do |dependency|
|
|
200
|
+
next if dependency.version.empty?
|
|
178
201
|
|
|
179
|
-
|
|
180
|
-
|
|
202
|
+
current = map[dependency.uuid]
|
|
203
|
+
if current && Dependabot::Julia::Version.new(current) <= Dependabot::Julia::Version.new(dependency.version)
|
|
204
|
+
next
|
|
205
|
+
end
|
|
181
206
|
|
|
182
|
-
|
|
207
|
+
map[dependency.uuid] = dependency.version
|
|
208
|
+
end
|
|
183
209
|
end
|
|
184
210
|
end
|
|
185
211
|
|
|
@@ -201,9 +227,9 @@ module Dependabot
|
|
|
201
227
|
end
|
|
202
228
|
end
|
|
203
229
|
|
|
204
|
-
sig { returns(T
|
|
205
|
-
def
|
|
206
|
-
dependency_files.
|
|
230
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
|
231
|
+
def manifest_files
|
|
232
|
+
dependency_files.select do |f|
|
|
207
233
|
File.basename(f.name).match?(/^(Julia)?Manifest(?:-v[\d.]+)?\.toml$/i)
|
|
208
234
|
end
|
|
209
235
|
end
|
|
@@ -250,7 +276,7 @@ module Dependabot
|
|
|
250
276
|
uuid = dependency.uuid
|
|
251
277
|
requirement_string = dependency.requirement
|
|
252
278
|
|
|
253
|
-
next if skip_dependency?(dependency, file_name, workspace_package_uuids)
|
|
279
|
+
next if skip_dependency?(dependency, groups, file_name, workspace_package_uuids)
|
|
254
280
|
|
|
255
281
|
new_requirement = {
|
|
256
282
|
requirement: requirement_string,
|
|
@@ -330,13 +356,19 @@ module Dependabot
|
|
|
330
356
|
sig do
|
|
331
357
|
params(
|
|
332
358
|
dependency: Dependabot::Julia::RegistryClient::Result::ProjectDependency,
|
|
359
|
+
groups: T::Array[String],
|
|
333
360
|
file_name: String,
|
|
334
361
|
workspace_package_uuids: T::Array[String]
|
|
335
362
|
).returns(T::Boolean)
|
|
336
363
|
end
|
|
337
|
-
def skip_dependency?(dependency, file_name, workspace_package_uuids)
|
|
364
|
+
def skip_dependency?(dependency, groups, file_name, workspace_package_uuids)
|
|
338
365
|
return true if workspace_package_uuids.include?(dependency.uuid)
|
|
339
366
|
|
|
367
|
+
# A test dependency under [extras] is only maintained once the project
|
|
368
|
+
# has given it a compat entry, as CompatHelper does by default
|
|
369
|
+
# (IfExistingCompatExtras); nothing is synthesized for the rest.
|
|
370
|
+
return true if dependency.requirement.nil? && groups.include?("extras")
|
|
371
|
+
|
|
340
372
|
# Pkg pins a standard library to the version bundled with Julia, so
|
|
341
373
|
# a compat entry tracking its registry releases (a legacy bridge for
|
|
342
374
|
# older Julia, or an "upgradable" stdlib release) can make the
|
|
@@ -58,23 +58,25 @@ module Dependabot
|
|
|
58
58
|
SharedHelpers.in_a_temporary_repo_directory(T.must(dependency_files.first).directory, repo_contents_path) do
|
|
59
59
|
# Update all project files (main + workspace members)
|
|
60
60
|
updated_project_files = update_all_project_files
|
|
61
|
-
|
|
61
|
+
manifests = find_manifest_files
|
|
62
62
|
|
|
63
|
-
return all_projects_only_update(updated_project_files) if
|
|
63
|
+
return all_projects_only_update(updated_project_files) if manifests.empty?
|
|
64
64
|
|
|
65
65
|
# Requirement-only updates (no target versions) have nothing to tell
|
|
66
66
|
# Pkg; ship the Project.toml changes on their own.
|
|
67
67
|
return all_projects_only_update(updated_project_files) if build_updates_hash.empty?
|
|
68
68
|
|
|
69
69
|
# Write all updated project files to disk for Julia's Pkg
|
|
70
|
-
write_all_temporary_files(updated_project_files,
|
|
71
|
-
|
|
70
|
+
write_all_temporary_files(updated_project_files, manifests)
|
|
71
|
+
updated_files.concat(all_projects_only_update(updated_project_files))
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
# Each manifest is resolved separately, by the Julia release that uses it
|
|
74
|
+
manifests.each do |manifest|
|
|
75
|
+
updated_manifest = updated_manifest_file(manifest)
|
|
76
|
+
updated_files << updated_manifest if updated_manifest
|
|
75
77
|
end
|
|
76
|
-
|
|
77
|
-
|
|
78
|
+
# A manifest that could not be resolved is reported in a notice instead
|
|
79
|
+
return updated_files if updated_files.empty? && notices.any?
|
|
78
80
|
end
|
|
79
81
|
|
|
80
82
|
raise "No files changed!" if updated_files.empty?
|
|
@@ -129,10 +131,10 @@ module Dependabot
|
|
|
129
131
|
sig do
|
|
130
132
|
params(
|
|
131
133
|
updated_project_files: T::Array[T::Hash[Symbol, T.untyped]],
|
|
132
|
-
|
|
134
|
+
manifests: T::Array[Dependabot::DependencyFile]
|
|
133
135
|
).void
|
|
134
136
|
end
|
|
135
|
-
def write_all_temporary_files(updated_project_files,
|
|
137
|
+
def write_all_temporary_files(updated_project_files, manifests)
|
|
136
138
|
# Write all updated project files
|
|
137
139
|
updated_project_files.each do |update_info|
|
|
138
140
|
file = T.cast(update_info[:file], Dependabot::DependencyFile)
|
|
@@ -143,45 +145,41 @@ module Dependabot
|
|
|
143
145
|
File.write(file_path, content)
|
|
144
146
|
end
|
|
145
147
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
148
|
+
manifests.each do |manifest|
|
|
149
|
+
FileUtils.mkdir_p(File.dirname(manifest.name)) if manifest.name.include?("/")
|
|
150
|
+
File.write(manifest.name, manifest.content)
|
|
151
|
+
end
|
|
150
152
|
end
|
|
151
153
|
|
|
152
|
-
sig
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
Dependabot::Julia::RegistryClient::Result::ManifestUpdate,
|
|
156
|
-
Dependabot::Julia::RegistryClient::Result::Failure
|
|
157
|
-
)
|
|
158
|
-
)
|
|
159
|
-
end
|
|
160
|
-
def call_julia_helper
|
|
161
|
-
registry_client.update_manifest(
|
|
154
|
+
sig { params(manifest: Dependabot::DependencyFile).returns(T.nilable(Dependabot::DependencyFile)) }
|
|
155
|
+
def updated_manifest_file(manifest)
|
|
156
|
+
result = registry_client.update_manifest(
|
|
162
157
|
project_path: Dir.pwd,
|
|
158
|
+
manifest_path: File.expand_path(manifest.name),
|
|
163
159
|
updates: build_updates_hash
|
|
164
160
|
)
|
|
161
|
+
|
|
162
|
+
if result.is_a?(Dependabot::Julia::RegistryClient::Result::Failure)
|
|
163
|
+
handle_julia_helper_error(result, manifest)
|
|
164
|
+
return nil
|
|
165
|
+
end
|
|
166
|
+
return nil if result.manifest_content == manifest.content
|
|
167
|
+
|
|
168
|
+
updated_file(file: manifest_file_for_path(result.manifest_path), content: result.manifest_content)
|
|
165
169
|
end
|
|
166
170
|
|
|
167
171
|
sig do
|
|
168
172
|
params(
|
|
169
173
|
result: Dependabot::Julia::RegistryClient::Result::Failure,
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
).returns(T::Array[Dependabot::DependencyFile])
|
|
174
|
+
manifest: Dependabot::DependencyFile
|
|
175
|
+
).void
|
|
173
176
|
end
|
|
174
|
-
def
|
|
177
|
+
def handle_julia_helper_error(result, manifest)
|
|
175
178
|
error_message = result.message
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
is_resolver_error = resolver_error?(error_message)
|
|
179
|
-
raise error_message unless is_resolver_error
|
|
180
|
-
|
|
181
|
-
add_manifest_update_notice(manifest_path, error_message)
|
|
179
|
+
raise error_message unless resolver_error?(error_message)
|
|
182
180
|
|
|
183
|
-
#
|
|
184
|
-
|
|
181
|
+
# The Project.toml changes still go out without this manifest
|
|
182
|
+
add_manifest_update_notice(manifest.name, error_message)
|
|
185
183
|
end
|
|
186
184
|
|
|
187
185
|
sig { params(error_message: String).returns(T::Boolean) }
|
|
@@ -216,31 +214,6 @@ module Dependabot
|
|
|
216
214
|
)
|
|
217
215
|
end
|
|
218
216
|
|
|
219
|
-
sig do
|
|
220
|
-
params(
|
|
221
|
-
updated_files: T::Array[Dependabot::DependencyFile],
|
|
222
|
-
updated_project_files: T::Array[T::Hash[Symbol, T.untyped]],
|
|
223
|
-
actual_manifest: Dependabot::DependencyFile,
|
|
224
|
-
result: Dependabot::Julia::RegistryClient::Result::ManifestUpdate
|
|
225
|
-
).void
|
|
226
|
-
end
|
|
227
|
-
def build_updated_files_multi(updated_files, updated_project_files, actual_manifest, result)
|
|
228
|
-
# Add all updated project files
|
|
229
|
-
updated_project_files.each do |update_info|
|
|
230
|
-
file = T.cast(update_info[:file], Dependabot::DependencyFile)
|
|
231
|
-
content = T.cast(update_info[:content], String)
|
|
232
|
-
next if content == file.content
|
|
233
|
-
|
|
234
|
-
updated_files << updated_file(file: file, content: content)
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
updated_manifest_content = result.manifest_content
|
|
238
|
-
return unless updated_manifest_content != actual_manifest.content
|
|
239
|
-
|
|
240
|
-
manifest_for_update = manifest_file_for_path(result.manifest_path)
|
|
241
|
-
updated_files << updated_file(file: manifest_for_update, content: updated_manifest_content)
|
|
242
|
-
end
|
|
243
|
-
|
|
244
217
|
private
|
|
245
218
|
|
|
246
219
|
sig { returns(T::Hash[String, T::Hash[String, String]]) }
|
|
@@ -251,6 +224,10 @@ module Dependabot
|
|
|
251
224
|
dependencies.each do |dependency|
|
|
252
225
|
version = dependency.version
|
|
253
226
|
next unless version
|
|
227
|
+
# Only a [deps] entry has a manifest entry of its own to bump;
|
|
228
|
+
# the helper leaves weakdeps and extras alone, so their updates
|
|
229
|
+
# are compat-only and need no Pkg run
|
|
230
|
+
next unless dependency.requirements.any? { |req| req.groups&.include?("deps") }
|
|
254
231
|
|
|
255
232
|
uuid = dependency.metadata[:julia_uuid]
|
|
256
233
|
unless uuid.is_a?(String)
|
|
@@ -294,15 +271,15 @@ module Dependabot
|
|
|
294
271
|
)
|
|
295
272
|
end
|
|
296
273
|
|
|
297
|
-
sig { returns(T
|
|
298
|
-
def
|
|
299
|
-
# The file fetcher has already identified the
|
|
300
|
-
# For regular packages:
|
|
301
|
-
# For workspace packages:
|
|
302
|
-
# We just need to find
|
|
274
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
|
275
|
+
def find_manifest_files
|
|
276
|
+
# The file fetcher has already identified the environment's manifests
|
|
277
|
+
# For regular packages: manifests in same directory
|
|
278
|
+
# For workspace packages: manifests in parent directory
|
|
279
|
+
# We just need to find them in dependency_files
|
|
303
280
|
project_dir = T.must(project_file).directory
|
|
304
281
|
|
|
305
|
-
dependency_files.
|
|
282
|
+
dependency_files.select do |f|
|
|
306
283
|
# Use basename to get just the filename, not the full path with ../
|
|
307
284
|
is_manifest = File.basename(f.name).match?(/^(Julia)?Manifest(?:-v[\d.]+)?\.toml$/i)
|
|
308
285
|
is_manifest && (f.directory == project_dir || parent_directory_of?(f.directory, project_dir))
|
|
@@ -14,6 +14,7 @@ module Dependabot
|
|
|
14
14
|
extend T::Sig
|
|
15
15
|
|
|
16
16
|
PACKAGE_LANGUAGE = "julia"
|
|
17
|
+
RELEASE_DATE_PENDING = "release_date_pending"
|
|
17
18
|
|
|
18
19
|
sig do
|
|
19
20
|
params(
|
|
@@ -73,9 +74,14 @@ module Dependabot
|
|
|
73
74
|
|
|
74
75
|
available_versions.map do |version_string|
|
|
75
76
|
version = Julia::Version.new(version_string)
|
|
76
|
-
|
|
77
|
+
date_result = release_dates[version_string]
|
|
78
|
+
date_result = nil if date_result.is_a?(RegistryClient::Result::Failure)
|
|
77
79
|
|
|
78
|
-
create_package_release(
|
|
80
|
+
create_package_release(
|
|
81
|
+
version,
|
|
82
|
+
convert_single_date(date_result&.release_date),
|
|
83
|
+
release_date_pending: date_result&.pending || false
|
|
84
|
+
)
|
|
79
85
|
end
|
|
80
86
|
end
|
|
81
87
|
|
|
@@ -84,7 +90,9 @@ module Dependabot
|
|
|
84
90
|
registry_client: RegistryClient,
|
|
85
91
|
available_versions: T::Array[String],
|
|
86
92
|
uuid: T.nilable(String)
|
|
87
|
-
).returns(
|
|
93
|
+
).returns(
|
|
94
|
+
T::Hash[String, T.any(RegistryClient::Result::ReleaseDate, RegistryClient::Result::Failure)]
|
|
95
|
+
)
|
|
88
96
|
end
|
|
89
97
|
def fetch_release_dates_batch(registry_client, available_versions, uuid)
|
|
90
98
|
return {} if available_versions.empty?
|
|
@@ -103,20 +111,7 @@ module Dependabot
|
|
|
103
111
|
dates_for_package = result.packages[dependency.name]
|
|
104
112
|
return {} unless dates_for_package.is_a?(RegistryClient::Result::ReleaseDates)
|
|
105
113
|
|
|
106
|
-
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
sig do
|
|
110
|
-
params(
|
|
111
|
-
release_dates: RegistryClient::Result::ReleaseDates
|
|
112
|
-
).returns(T::Hash[String, T.nilable(Time)])
|
|
113
|
-
end
|
|
114
|
-
def convert_dates_to_time_objects(release_dates)
|
|
115
|
-
release_dates.dates.transform_values do |result|
|
|
116
|
-
next if result.is_a?(RegistryClient::Result::Failure)
|
|
117
|
-
|
|
118
|
-
convert_single_date(result.release_date)
|
|
119
|
-
end
|
|
114
|
+
dates_for_package.dates
|
|
120
115
|
end
|
|
121
116
|
|
|
122
117
|
sig { params(date_value: T.nilable(String)).returns(T.nilable(Time)) }
|
|
@@ -131,16 +126,18 @@ module Dependabot
|
|
|
131
126
|
sig do
|
|
132
127
|
params(
|
|
133
128
|
version: Julia::Version,
|
|
134
|
-
release_date: T.nilable(Time)
|
|
129
|
+
release_date: T.nilable(Time),
|
|
130
|
+
release_date_pending: T::Boolean
|
|
135
131
|
).returns(Dependabot::Package::PackageRelease)
|
|
136
132
|
end
|
|
137
|
-
def create_package_release(version, release_date)
|
|
133
|
+
def create_package_release(version, release_date, release_date_pending:)
|
|
138
134
|
Dependabot::Package::PackageRelease.new(
|
|
139
135
|
version: version,
|
|
140
136
|
released_at: release_date,
|
|
141
137
|
latest: false, # Will be determined later
|
|
142
138
|
yanked: false, # Yanked versions are filtered out by the Julia registry helper
|
|
143
|
-
language: Dependabot::Package::PackageLanguage.new(name: PACKAGE_LANGUAGE)
|
|
139
|
+
language: Dependabot::Package::PackageLanguage.new(name: PACKAGE_LANGUAGE),
|
|
140
|
+
details: release_date_pending ? { RELEASE_DATE_PENDING => true } : {}
|
|
144
141
|
)
|
|
145
142
|
end
|
|
146
143
|
|
|
@@ -214,6 +214,7 @@ module Dependabot
|
|
|
214
214
|
const :julia_version, String
|
|
215
215
|
const :dependencies, T::Array[ProjectDependency]
|
|
216
216
|
const :weak_dependencies, T::Array[ProjectDependency]
|
|
217
|
+
const :extra_dependencies, T::Array[ProjectDependency]
|
|
217
218
|
const :project_path, String
|
|
218
219
|
|
|
219
220
|
sig { params(value: Object).returns(T.any(Project, Failure)) }
|
|
@@ -230,6 +231,7 @@ module Dependabot
|
|
|
230
231
|
julia_version: ValueParser.string(hash, "julia_version", context),
|
|
231
232
|
dependencies: parse_dependencies(hash, "dependencies", context),
|
|
232
233
|
weak_dependencies: parse_dependencies(hash, "weak_dependencies", context),
|
|
234
|
+
extra_dependencies: parse_dependencies(hash, "extra_dependencies", context),
|
|
233
235
|
project_path: ValueParser.string(hash, "project_path", context)
|
|
234
236
|
)
|
|
235
237
|
end
|
|
@@ -336,6 +338,8 @@ module Dependabot
|
|
|
336
338
|
|
|
337
339
|
const :project_files, T::Array[String]
|
|
338
340
|
const :manifest_file, String
|
|
341
|
+
# Every manifest of the environment, including version-specific ones
|
|
342
|
+
const :manifest_files, T::Array[String], default: []
|
|
339
343
|
const :workspace_root, String
|
|
340
344
|
|
|
341
345
|
sig { params(value: Object).returns(T.any(WorkspaceFiles, Failure)) }
|
|
@@ -351,6 +355,7 @@ module Dependabot
|
|
|
351
355
|
"#{context} project_files"
|
|
352
356
|
),
|
|
353
357
|
manifest_file: ValueParser.string(hash, "manifest_file", context),
|
|
358
|
+
manifest_files: ValueParser.optional_string_array(hash, "manifest_files", context),
|
|
354
359
|
workspace_root: ValueParser.string(hash, "workspace_root", context)
|
|
355
360
|
)
|
|
356
361
|
end
|
|
@@ -429,6 +434,8 @@ module Dependabot
|
|
|
429
434
|
extend T::Sig
|
|
430
435
|
|
|
431
436
|
const :release_date, T.nilable(String)
|
|
437
|
+
# Registered in General after the last GeneralMetadata.jl build, so no date is published yet
|
|
438
|
+
const :pending, T::Boolean, default: false
|
|
432
439
|
|
|
433
440
|
sig { params(value: Object, context: String).returns(T.any(ReleaseDate, Failure)) }
|
|
434
441
|
def self.from_object(value, context:)
|
|
@@ -436,7 +443,10 @@ module Dependabot
|
|
|
436
443
|
failure = Result.failure_from(hash, context)
|
|
437
444
|
return failure if failure
|
|
438
445
|
|
|
439
|
-
new(
|
|
446
|
+
new(
|
|
447
|
+
release_date: ValueParser.nilable_string(hash, "release_date", context),
|
|
448
|
+
pending: ValueParser.optional_boolean(hash, "release_date_pending", context)
|
|
449
|
+
)
|
|
440
450
|
end
|
|
441
451
|
|
|
442
452
|
sig { params(value: Object, context: String).returns(T.any(ReleaseDate, Failure)) }
|
|
@@ -178,15 +178,17 @@ module Dependabot
|
|
|
178
178
|
sig do
|
|
179
179
|
params(
|
|
180
180
|
project_path: String,
|
|
181
|
-
updates: T::Hash[String, T::Hash[String, String]]
|
|
181
|
+
updates: T::Hash[String, T::Hash[String, String]],
|
|
182
|
+
manifest_path: T.nilable(String)
|
|
182
183
|
).returns(T.any(Result::ManifestUpdate, Result::Failure))
|
|
183
184
|
end
|
|
184
|
-
def update_manifest(project_path:, updates:)
|
|
185
|
+
def update_manifest(project_path:, updates:, manifest_path: nil)
|
|
185
186
|
Result::ManifestUpdate.from_object(
|
|
186
187
|
call_julia_helper(
|
|
187
188
|
function: "update_manifest",
|
|
188
189
|
args: {
|
|
189
190
|
project_path: project_path,
|
|
191
|
+
manifest_path: manifest_path,
|
|
190
192
|
updates: updates
|
|
191
193
|
}
|
|
192
194
|
)
|
|
@@ -41,8 +41,11 @@ module Dependabot
|
|
|
41
41
|
# intersection semantics for operator-style lists anyway because this
|
|
42
42
|
# method also parses Dependabot ignore conditions (e.g. ">= 2.a, < 3"),
|
|
43
43
|
# which are always intersections; treating those as unions would make
|
|
44
|
-
# every ignore condition match all versions.
|
|
44
|
+
# every ignore condition match all versions. A list of equalities only
|
|
45
|
+
# ("=0.5.4, =0.5.5") would admit nothing as an intersection, so it is
|
|
46
|
+
# read as the union Pkg takes.
|
|
45
47
|
return false if constraints.length <= 1
|
|
48
|
+
return false if constraints.all? { |c| c.start_with?("=") }
|
|
46
49
|
|
|
47
50
|
constraints.all? { |c| c.match?(/^[<>=]/) }
|
|
48
51
|
end
|
|
@@ -65,6 +68,18 @@ module Dependabot
|
|
|
65
68
|
requirements_array(requirement_string)
|
|
66
69
|
end
|
|
67
70
|
|
|
71
|
+
# Whether a compat entry admits the version. Pkg compares a bound
|
|
72
|
+
# against major.minor.patch only, so a JLL rebuild ("0.0.43+1") is
|
|
73
|
+
# admitted by "=0.0.43" or "0.0.42 - 0.0.43" exactly as the version it
|
|
74
|
+
# rebuilds is, and a prerelease exactly as its release ("1" rejects
|
|
75
|
+
# "2.0.0-rc1"). Ignore conditions go through satisfied_by? instead and
|
|
76
|
+
# keep the ordering between builds ("> 1.6.10" ignores "1.6.10+1").
|
|
77
|
+
sig { params(version: T.any(Gem::Version, String)).returns(T::Boolean) }
|
|
78
|
+
def admits?(version)
|
|
79
|
+
release = Dependabot::Julia::Version.new(version.to_s).compat_version_string
|
|
80
|
+
T.cast(satisfied_by?(Dependabot::Julia::Version.new(release)), T::Boolean)
|
|
81
|
+
end
|
|
82
|
+
|
|
68
83
|
sig { params(version: String).returns(String) }
|
|
69
84
|
def self.normalize_version(version)
|
|
70
85
|
# Remove 'v' prefix if present (common in Julia)
|
|
@@ -55,6 +55,13 @@ module Dependabot
|
|
|
55
55
|
@available_versions ||= T.let(fetch_available_versions, T.nilable(T::Array[Gem::Version]))
|
|
56
56
|
end
|
|
57
57
|
|
|
58
|
+
# Lowest non-vulnerable version above the current one. Like
|
|
59
|
+
# Package::PackageLatestVersionFinder, security fixes skip the cooldown.
|
|
60
|
+
sig { returns(T.nilable(Gem::Version)) }
|
|
61
|
+
def lowest_security_fix_version
|
|
62
|
+
@lowest_security_fix_version ||= T.let(fetch_lowest_security_fix_version, T.nilable(Gem::Version))
|
|
63
|
+
end
|
|
64
|
+
|
|
58
65
|
private
|
|
59
66
|
|
|
60
67
|
sig { returns(Dependabot::Dependency) }
|
|
@@ -81,16 +88,29 @@ module Dependabot
|
|
|
81
88
|
sig { returns(T::Array[T::Hash[Symbol, String]]) }
|
|
82
89
|
attr_reader :custom_registries
|
|
83
90
|
|
|
84
|
-
sig { returns(T::Array[
|
|
85
|
-
def
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
+
sig { returns(T::Array[Dependabot::Package::PackageRelease]) }
|
|
92
|
+
def package_releases
|
|
93
|
+
@package_releases ||= T.let(
|
|
94
|
+
Julia::Package::PackageDetailsFetcher.new(
|
|
95
|
+
dependency: dependency,
|
|
96
|
+
credentials: credentials,
|
|
97
|
+
custom_registries: custom_registries
|
|
98
|
+
).fetch_package_releases,
|
|
99
|
+
T.nilable(T::Array[Dependabot::Package::PackageRelease])
|
|
91
100
|
)
|
|
101
|
+
end
|
|
92
102
|
|
|
93
|
-
|
|
103
|
+
sig { returns(T.nilable(Gem::Version)) }
|
|
104
|
+
def fetch_lowest_security_fix_version
|
|
105
|
+
versions = filter_prerelease_versions(package_releases.map(&:version).sort)
|
|
106
|
+
versions = filter_ignored_versions(versions)
|
|
107
|
+
versions = filter_lower_versions(versions)
|
|
108
|
+
Dependabot::UpdateCheckers::VersionFilters.filter_vulnerable_versions(versions, security_advisories).min
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
sig { returns(T::Array[Gem::Version]) }
|
|
112
|
+
def fetch_available_versions
|
|
113
|
+
releases = package_releases
|
|
94
114
|
return [] if releases.empty?
|
|
95
115
|
|
|
96
116
|
# Filter releases based on cooldown
|
|
@@ -110,8 +130,10 @@ module Dependabot
|
|
|
110
130
|
versions = filter_ignored_versions(versions)
|
|
111
131
|
return [] if versions.empty?
|
|
112
132
|
|
|
113
|
-
# Filter out lower versions
|
|
114
|
-
|
|
133
|
+
# Filter out lower versions, keeping the current release so that an
|
|
134
|
+
# up-to-date dependency reports it as the latest: the base class takes
|
|
135
|
+
# a nil latest_version as out of date and goes on to look for unlocks
|
|
136
|
+
versions = filter_lower_versions(versions, keep_current: true)
|
|
115
137
|
return [] if versions.empty?
|
|
116
138
|
|
|
117
139
|
# Filter out vulnerable versions
|
|
@@ -168,12 +190,12 @@ module Dependabot
|
|
|
168
190
|
filtered
|
|
169
191
|
end
|
|
170
192
|
|
|
171
|
-
sig { params(versions: T::Array[Gem::Version]).returns(T::Array[Gem::Version]) }
|
|
172
|
-
def filter_lower_versions(versions)
|
|
193
|
+
sig { params(versions: T::Array[Gem::Version], keep_current: T::Boolean).returns(T::Array[Gem::Version]) }
|
|
194
|
+
def filter_lower_versions(versions, keep_current: false)
|
|
173
195
|
return versions unless dependency.version
|
|
174
196
|
|
|
175
197
|
current_version = Dependabot::Julia::Version.new(dependency.version)
|
|
176
|
-
versions.select { |v| v > current_version }
|
|
198
|
+
versions.select { |v| v > current_version || (keep_current && v == current_version) }
|
|
177
199
|
end
|
|
178
200
|
|
|
179
201
|
sig { returns(T::Array[Dependabot::Requirement]) }
|
|
@@ -187,6 +209,8 @@ module Dependabot
|
|
|
187
209
|
def cooldown_active_for_release?(release)
|
|
188
210
|
cooldown_days = determine_cooldown_days(release.version)
|
|
189
211
|
return false unless cooldown_days&.positive?
|
|
212
|
+
# A General release too new to have a published date is at most about a day old
|
|
213
|
+
return true if release.details[Julia::Package::PackageDetailsFetcher::RELEASE_DATE_PENDING]
|
|
190
214
|
return false unless release.released_at
|
|
191
215
|
|
|
192
216
|
# Check if enough time has passed since release
|
|
@@ -225,7 +249,10 @@ module Dependabot
|
|
|
225
249
|
return nil unless cooldown_config
|
|
226
250
|
|
|
227
251
|
current_version = dependency.version ? Dependabot::Julia::Version.new(dependency.version) : nil
|
|
228
|
-
|
|
252
|
+
# Without a Manifest there is no version to measure a bump from; like
|
|
253
|
+
# CooldownCalculation.cooldown_days_for, fall back to default_days
|
|
254
|
+
# rather than skipping the cooldown
|
|
255
|
+
return cooldown_days_for_bump_type(:default) unless current_version
|
|
229
256
|
|
|
230
257
|
version_bump_type = determine_version_bump_type(version, current_version)
|
|
231
258
|
cooldown_days_for_bump_type(version_bump_type)
|
|
@@ -90,7 +90,7 @@ module Dependabot
|
|
|
90
90
|
sig { params(requirement_string: String, versions: T::Array[Dependabot::Julia::Version]).returns(String) }
|
|
91
91
|
def widened_stdlib_requirement(requirement_string, versions)
|
|
92
92
|
reqs = Dependabot::Julia::Requirement.requirements_array(requirement_string)
|
|
93
|
-
missing = versions.reject { |version| reqs.any? { |req| req.
|
|
93
|
+
missing = versions.reject { |version| reqs.any? { |req| req.admits?(version) } }
|
|
94
94
|
|
|
95
95
|
missing.reduce(requirement_string) do |entry, version|
|
|
96
96
|
append_spec_string(entry, stdlib_version_spec(version))
|
|
@@ -106,7 +106,7 @@ module Dependabot
|
|
|
106
106
|
minor = (version.segments[1] || 0).to_i
|
|
107
107
|
patch = (version.segments[2] || 0).to_i
|
|
108
108
|
|
|
109
|
-
return "<
|
|
109
|
+
return "<0.0.1" if major.zero? && minor.zero? && patch.zero?
|
|
110
110
|
return major.to_s if major.positive? && minor.zero?
|
|
111
111
|
|
|
112
112
|
simplified_version_spec(version)
|
|
@@ -121,9 +121,11 @@ module Dependabot
|
|
|
121
121
|
def update_requirement(requirement, target_version)
|
|
122
122
|
current_requirement = requirement.requirement_string
|
|
123
123
|
|
|
124
|
-
# If requirement is nil (no compat entry), use target version
|
|
124
|
+
# If requirement is nil (no compat entry), use target version. A JLL's
|
|
125
|
+
# "1.6.10+0" has to be written as "1.6.10": Pkg rejects the build
|
|
126
|
+
# number in a compat entry, and the bound admits every build anyway.
|
|
125
127
|
new_requirement = if current_requirement.nil?
|
|
126
|
-
target_version.
|
|
128
|
+
target_version.compat_version_string
|
|
127
129
|
else
|
|
128
130
|
updated_version_requirement(current_requirement, target_version)
|
|
129
131
|
end
|
|
@@ -141,7 +143,7 @@ module Dependabot
|
|
|
141
143
|
|
|
142
144
|
# Check if any requirement is satisfied by the target version
|
|
143
145
|
# Note: This uses the implicit caret semantics from the Requirement class
|
|
144
|
-
satisfied = reqs.any? { |req| req.
|
|
146
|
+
satisfied = reqs.any? { |req| req.admits?(target_version) }
|
|
145
147
|
|
|
146
148
|
case update_strategy
|
|
147
149
|
when :bump_versions
|
|
@@ -163,11 +165,26 @@ module Dependabot
|
|
|
163
165
|
|
|
164
166
|
sig { params(requirement_string: String, new_spec: String).returns(String) }
|
|
165
167
|
def append_spec_string(requirement_string, new_spec)
|
|
166
|
-
#
|
|
168
|
+
# Add the new spec to the existing requirement (CompatHelper KeepEntry behavior)
|
|
167
169
|
# Detect whether the existing requirement uses spaces after commas and preserve that format
|
|
168
170
|
# and default to ", " if no commas found
|
|
169
171
|
separator = requirement_string.include?(",") && !requirement_string.include?(", ") ? "," : ", "
|
|
170
|
-
|
|
172
|
+
# Keep the entry in ascending order ("<0.0.1, 1", not "1, <0.0.1"):
|
|
173
|
+
# the new spec goes before the first one that starts above it
|
|
174
|
+
specs = requirement_string.split(",").map(&:strip)
|
|
175
|
+
index = specs.index { |spec| spec_lower_bound(spec) > spec_lower_bound(new_spec) }
|
|
176
|
+
return "#{requirement_string}#{separator}#{new_spec}" unless index
|
|
177
|
+
|
|
178
|
+
specs.insert(index, new_spec).join(separator)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# The lowest version a single spec in an entry admits, for ordering; an
|
|
182
|
+
# upper bound alone ("<0.0.1") starts at zero
|
|
183
|
+
sig { params(spec: String).returns(Dependabot::Julia::Version) }
|
|
184
|
+
def spec_lower_bound(spec)
|
|
185
|
+
return Dependabot::Julia::Version.new("0") if spec.start_with?("<", "≤")
|
|
186
|
+
|
|
187
|
+
Dependabot::Julia::Version.new(spec[/\d+(?:\.\d+)*/] || "0")
|
|
171
188
|
end
|
|
172
189
|
|
|
173
190
|
sig { params(target_version: Dependabot::Julia::Version).returns(String) }
|
|
@@ -79,6 +79,19 @@ module Dependabot
|
|
|
79
79
|
@latest_resolvable_version ||= T.let(latest_version, T.nilable(Gem::Version))
|
|
80
80
|
end
|
|
81
81
|
|
|
82
|
+
sig { override.returns(T.nilable(Gem::Version)) }
|
|
83
|
+
def lowest_security_fix_version
|
|
84
|
+
return nil if stdlib?
|
|
85
|
+
|
|
86
|
+
latest_version_finder.lowest_security_fix_version
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
sig { override.returns(T.nilable(Gem::Version)) }
|
|
90
|
+
def lowest_resolvable_security_fix_version
|
|
91
|
+
# Resolvability is not checked, as for latest_resolvable_version
|
|
92
|
+
lowest_security_fix_version
|
|
93
|
+
end
|
|
94
|
+
|
|
82
95
|
sig { override.returns(T.nilable(T.any(Dependabot::Version, String))) }
|
|
83
96
|
def latest_resolvable_version_with_no_unlock
|
|
84
97
|
return nil if stdlib?
|
|
@@ -96,7 +109,7 @@ module Dependabot
|
|
|
96
109
|
candidates.max
|
|
97
110
|
else
|
|
98
111
|
reqs = requirement_class.requirements_array(current_requirement)
|
|
99
|
-
candidates.select { |version| reqs.any? { |req| req.
|
|
112
|
+
candidates.select { |version| reqs.any? { |req| req.admits?(version) } }.max
|
|
100
113
|
end
|
|
101
114
|
return nil unless best
|
|
102
115
|
|
|
@@ -107,7 +120,7 @@ module Dependabot
|
|
|
107
120
|
def updated_requirements
|
|
108
121
|
Dependabot::Julia::RequirementsUpdater.new(
|
|
109
122
|
requirements: dependency.requirements,
|
|
110
|
-
target_version:
|
|
123
|
+
target_version: preferred_resolvable_version&.to_s,
|
|
111
124
|
update_strategy: requirements_update_strategy&.to_s&.to_sym,
|
|
112
125
|
stdlib_versions: stdlib_versions
|
|
113
126
|
).updated_requirements
|
|
@@ -115,6 +128,12 @@ module Dependabot
|
|
|
115
128
|
|
|
116
129
|
private
|
|
117
130
|
|
|
131
|
+
sig { override.returns(T::Boolean) }
|
|
132
|
+
def latest_version_resolvable_with_full_unlock?
|
|
133
|
+
# Full unlock checks aren't implemented for Julia (yet)
|
|
134
|
+
false
|
|
135
|
+
end
|
|
136
|
+
|
|
118
137
|
# Versions a stdlib's compat entry has to admit, by project file; set by
|
|
119
138
|
# the file parser for packages that ship with any Julia release the
|
|
120
139
|
# project supports
|
|
@@ -59,6 +59,14 @@ module Dependabot
|
|
|
59
59
|
@version_string
|
|
60
60
|
end
|
|
61
61
|
|
|
62
|
+
# The "major.minor.patch" part, which is all a [compat] entry can carry:
|
|
63
|
+
# Pkg rejects "1.6.10+0" or "1.6.10-rc1" as a specifier, and its bounds
|
|
64
|
+
# compare major, minor and patch only, so "1.6.10" admits both.
|
|
65
|
+
sig { returns(String) }
|
|
66
|
+
def compat_version_string
|
|
67
|
+
T.must(@version_string[/\A\d+(?:\.\d+){0,2}/])
|
|
68
|
+
end
|
|
69
|
+
|
|
62
70
|
sig { override.returns(String) }
|
|
63
71
|
def to_semver
|
|
64
72
|
@version_string
|
data/lib/dependabot/julia.rb
CHANGED
|
@@ -69,5 +69,12 @@ Dependabot::PullRequestCreator::Labeler
|
|
|
69
69
|
.register_label_details("julia", name: "julia", colour: "a270ba")
|
|
70
70
|
|
|
71
71
|
require "dependabot/dependency"
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
# [extras] hold test-only packages; weakdeps are loaded on demand by
|
|
73
|
+
# extensions and count as runtime, like [deps]
|
|
74
|
+
Dependabot::Dependency.register_production_check(
|
|
75
|
+
"julia",
|
|
76
|
+
lambda do |groups|
|
|
77
|
+
groups = T.cast(groups, T::Array[String])
|
|
78
|
+
groups.empty? || groups.any? { |group| group != "extras" }
|
|
79
|
+
end
|
|
80
|
+
)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dependabot-julia
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.399.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.399.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.399.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: debug
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -262,7 +262,7 @@ licenses:
|
|
|
262
262
|
- MIT
|
|
263
263
|
metadata:
|
|
264
264
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
265
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
265
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.399.0
|
|
266
266
|
rdoc_options: []
|
|
267
267
|
require_paths:
|
|
268
268
|
- lib
|