dependabot-gradle 0.351.0 → 0.353.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/gradle/file_fetcher.rb +1 -0
- data/lib/dependabot/gradle/file_updater/wrapper_updater.rb +91 -23
- data/lib/dependabot/gradle/file_updater.rb +21 -14
- data/lib/dependabot/gradle/package/package_details_fetcher.rb +15 -33
- data/lib/dependabot/gradle/package/release_date_extractor.rb +166 -0
- metadata +7 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4df97c3857297707a0ee0c2bf06c540d06e93fc7038e38fbe557b7944d810a00
|
|
4
|
+
data.tar.gz: af7e7cd25247eff9b1f23a31e40bbdd8650d4a1e393800ed0eaab7d8bbc837d8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d582940602b75462d8c3510624dd691176132bfa0503b9a40f9eb7af13b16c4232afde4b1173e1f188be7c5b296e01870d14266dc567f188a27c642ad1954091
|
|
7
|
+
data.tar.gz: 89efef686fd6a6b22b75f81706adbaf192264ad8968656583de0eaa53bcb43a97c24bebb926d3c17e5f5c7abfc162eb20ed8f8ad98ee9c3aa5864f7c58f97982
|
|
@@ -192,6 +192,7 @@ module Dependabot
|
|
|
192
192
|
file.content = Base64.encode64(T.must(file.content)) if file.content
|
|
193
193
|
file.content_encoding = DependencyFile::ContentEncoding::BASE64
|
|
194
194
|
end
|
|
195
|
+
file.mode = DependencyFile::Mode::EXECUTABLE if file.name.end_with?("gradlew", "gradlew.bat")
|
|
195
196
|
file
|
|
196
197
|
rescue Dependabot::DependencyFileNotFound
|
|
197
198
|
# Gradle itself doesn't worry about missing subprojects, so we don't
|
|
@@ -37,6 +37,9 @@ module Dependabot
|
|
|
37
37
|
)
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
# rubocop:disable Metrics/AbcSize
|
|
41
|
+
# rubocop:disable Metrics/MethodLength
|
|
42
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
|
40
43
|
sig { params(build_file: Dependabot::DependencyFile).returns(T::Array[Dependabot::DependencyFile]) }
|
|
41
44
|
def update_files(build_file)
|
|
42
45
|
# We only run this updater if it's a distribution dependency
|
|
@@ -49,29 +52,57 @@ module Dependabot
|
|
|
49
52
|
# If we don't have any files in the build files don't generate one
|
|
50
53
|
return [] unless local_files.any?
|
|
51
54
|
|
|
55
|
+
# we only run this updater if the build file has a requirement for this dependency
|
|
56
|
+
target_requirements = dependency.requirements.select do |req|
|
|
57
|
+
T.let(req[:file], String) == build_file.name
|
|
58
|
+
end
|
|
59
|
+
return [] unless target_requirements.any?
|
|
60
|
+
|
|
52
61
|
updated_files = dependency_files.dup
|
|
53
62
|
SharedHelpers.in_a_temporary_directory do |temp_dir|
|
|
54
63
|
populate_temp_directory(temp_dir)
|
|
55
64
|
cwd = File.join(temp_dir, base_path(build_file))
|
|
56
65
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
write_properties_file(properties_filename)
|
|
61
|
-
|
|
62
|
-
command_parts = %w(gradle --no-daemon --stacktrace) + command_args
|
|
63
|
-
command = Shellwords.join(command_parts)
|
|
66
|
+
has_local_script = File.exist?(File.join(cwd, "./gradlew"))
|
|
67
|
+
command_parts = %w(--no-daemon --stacktrace) + command_args(target_requirements)
|
|
68
|
+
command = Shellwords.join([has_local_script ? "./gradlew" : "gradle"] + command_parts)
|
|
64
69
|
|
|
65
70
|
Dir.chdir(cwd) do
|
|
66
|
-
|
|
71
|
+
FileUtils.chmod("+x", "./gradlew") if has_local_script
|
|
72
|
+
|
|
73
|
+
properties_file = File.join(cwd, "gradle/wrapper/gradle-wrapper.properties")
|
|
74
|
+
validate_option = get_validate_distribution_url_option(properties_file)
|
|
75
|
+
env = { "JAVA_OPTS" => proxy_args.join(" ") } # set proxy for gradle execution
|
|
76
|
+
|
|
77
|
+
begin
|
|
78
|
+
# first attempt: run the wrapper task via the local gradle wrapper (if present)
|
|
79
|
+
# `gradle-wrapper.jar` might be too old to run on host's Java version
|
|
80
|
+
SharedHelpers.run_shell_command(command, cwd: cwd, env: env)
|
|
81
|
+
rescue SharedHelpers::HelperSubprocessFailed => e
|
|
82
|
+
raise e unless has_local_script # already field with system one, there is no point to retry
|
|
83
|
+
|
|
84
|
+
Dependabot.logger.warn("Running #{command} failed, retrying first with system Gradle: #{e.message}")
|
|
85
|
+
|
|
86
|
+
# second attempt: run the wrapper task via system gradle and then retry via local wrapper
|
|
87
|
+
system_command = Shellwords.join(["gradle"] + command_parts)
|
|
88
|
+
SharedHelpers.run_shell_command(system_command, cwd: cwd, env: env) # run via system gradle
|
|
89
|
+
SharedHelpers.run_shell_command(command, cwd: cwd, env: env) # retry via local wrapper
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Restore previous validateDistributionUrl option if it existed
|
|
93
|
+
override_validate_distribution_url_option(properties_file, validate_option)
|
|
94
|
+
|
|
67
95
|
update_files_content(temp_dir, local_files, updated_files)
|
|
68
96
|
rescue SharedHelpers::HelperSubprocessFailed => e
|
|
69
|
-
|
|
97
|
+
Dependabot.logger.error("Failed to update files: #{e.message}")
|
|
70
98
|
return updated_files
|
|
71
99
|
end
|
|
72
100
|
end
|
|
73
101
|
updated_files
|
|
74
102
|
end
|
|
103
|
+
# rubocop:enable Metrics/AbcSize
|
|
104
|
+
# rubocop:enable Metrics/MethodLength
|
|
105
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
|
75
106
|
|
|
76
107
|
private
|
|
77
108
|
|
|
@@ -80,12 +111,20 @@ module Dependabot
|
|
|
80
111
|
@target_files.any? { |r| "/#{file.name}".end_with?(r) }
|
|
81
112
|
end
|
|
82
113
|
|
|
83
|
-
sig { returns(T::Array[String]) }
|
|
84
|
-
def command_args
|
|
85
|
-
version = T.let(
|
|
86
|
-
checksum = T.let(
|
|
87
|
-
|
|
88
|
-
|
|
114
|
+
sig { params(requirements: T::Array[T::Hash[Symbol, T.untyped]]).returns(T::Array[String]) }
|
|
115
|
+
def command_args(requirements)
|
|
116
|
+
version = T.let(requirements[0]&.[](:requirement), String)
|
|
117
|
+
checksum = T.let(requirements[1]&.[](:requirement), String) if dependency.requirements.size > 1
|
|
118
|
+
distribution_url = T.let(requirements[0]&.[](:source), T::Hash[Symbol, String])[:url]
|
|
119
|
+
distribution_type = distribution_url&.match(/\b(bin|all)\b/)&.captures&.first
|
|
120
|
+
|
|
121
|
+
# --no-validate-url is required to bypass HTTP proxy issues when running ./gradlew
|
|
122
|
+
# This prevents validation failures during the wrapper update process
|
|
123
|
+
# Note: This temporarily sets validateDistributionUrl=false in gradle-wrapper.properties
|
|
124
|
+
# The original value is restored after the wrapper task completes
|
|
125
|
+
# see method `get_validate_distribution_url_option` for more details
|
|
126
|
+
args = %W(wrapper --gradle-version #{version} --no-validate-url) # see
|
|
127
|
+
args += %W(--distribution-type #{distribution_type}) if distribution_type
|
|
89
128
|
args += %W(--gradle-distribution-sha256-sum #{checksum}) if checksum
|
|
90
129
|
args
|
|
91
130
|
end
|
|
@@ -135,8 +174,35 @@ module Dependabot
|
|
|
135
174
|
end
|
|
136
175
|
end
|
|
137
176
|
|
|
138
|
-
|
|
139
|
-
|
|
177
|
+
# This is a consequence of the lack of proper proxy support in Gradle Wrapper
|
|
178
|
+
# During the update process, Gradle Wrapper logic will try to validate the distribution URL
|
|
179
|
+
# by performing an HTTP request. If the environment requires a proxy, this validation will fail
|
|
180
|
+
# We need to add the `--no-validate-url` the commandline args to disable this validation
|
|
181
|
+
# However, this change is persistent in the `gradle-wrapper.properties` file
|
|
182
|
+
# To avoid side effects, we read the existing value before the update and restore it afterward
|
|
183
|
+
sig { params(properties_file: T.any(Pathname, String)).returns(T.nilable(String)) }
|
|
184
|
+
def get_validate_distribution_url_option(properties_file)
|
|
185
|
+
return nil unless File.exist?(properties_file)
|
|
186
|
+
|
|
187
|
+
properties_content = File.read(properties_file)
|
|
188
|
+
properties_content.match(/^validateDistributionUrl=(.*)$/)&.captures&.first
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
sig { params(properties_file: T.any(Pathname, String), value: T.nilable(String)).void }
|
|
192
|
+
def override_validate_distribution_url_option(properties_file, value)
|
|
193
|
+
return unless File.exist?(properties_file)
|
|
194
|
+
|
|
195
|
+
properties_content = File.read(properties_file)
|
|
196
|
+
updated_content = properties_content.gsub(
|
|
197
|
+
/^validateDistributionUrl=(.*)\n/,
|
|
198
|
+
value ? "validateDistributionUrl=#{value}\n" : ""
|
|
199
|
+
)
|
|
200
|
+
File.write(properties_file, updated_content)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
|
204
|
+
sig { returns(T::Array[String]) }
|
|
205
|
+
def proxy_args
|
|
140
206
|
http_proxy = ENV.fetch("HTTP_PROXY", nil)
|
|
141
207
|
https_proxy = ENV.fetch("HTTPS_PROXY", nil)
|
|
142
208
|
http_split = http_proxy&.split(":")
|
|
@@ -145,13 +211,15 @@ module Dependabot
|
|
|
145
211
|
https_proxy_host = https_split&.fetch(1, nil)&.gsub("//", "") || "host.docker.internal"
|
|
146
212
|
http_proxy_port = http_split&.fetch(2) || "1080"
|
|
147
213
|
https_proxy_port = https_split&.fetch(2) || "1080"
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
214
|
+
|
|
215
|
+
args = []
|
|
216
|
+
args += %W(-Dhttp.proxyHost=#{http_proxy_host}) if http_proxy_host
|
|
217
|
+
args += %W(-Dhttp.proxyPort=#{http_proxy_port}) if http_proxy_port
|
|
218
|
+
args += %W(-Dhttps.proxyHost=#{https_proxy_host}) if https_proxy_host
|
|
219
|
+
args += %W(-Dhttps.proxyPort=#{https_proxy_port}) if https_proxy_port
|
|
220
|
+
args
|
|
154
221
|
end
|
|
222
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
|
155
223
|
|
|
156
224
|
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
|
157
225
|
attr_reader :dependency_files
|
|
@@ -56,9 +56,7 @@ module Dependabot
|
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
# rubocop:disable Metrics/AbcSize
|
|
59
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
|
60
59
|
# rubocop:disable Metrics/PerceivedComplexity
|
|
61
|
-
# rubocop:disable Metrics/MethodLength
|
|
62
60
|
sig do
|
|
63
61
|
params(buildfiles: T::Array[Dependabot::DependencyFile], dependency: Dependabot::Dependency)
|
|
64
62
|
.returns(T::Array[Dependabot::DependencyFile])
|
|
@@ -103,33 +101,42 @@ module Dependabot
|
|
|
103
101
|
end
|
|
104
102
|
|
|
105
103
|
# runs native updaters (e.g. wrapper, lockfile) on relevant build files updated
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if Dependabot::Experiments.enabled?(:gradle_wrapper_updater)
|
|
104
|
+
if Dependabot::Experiments.enabled?(:gradle_wrapper_updater)
|
|
105
|
+
buildfiles_processed.each_value do |buildfile|
|
|
109
106
|
wrapper_updater = WrapperUpdater.new(dependency_files: files, dependency: dependency)
|
|
110
|
-
updated_files
|
|
107
|
+
updated_files = wrapper_updater.update_files(buildfile)
|
|
108
|
+
replace_updated_files(files, updated_files)
|
|
111
109
|
end
|
|
112
|
-
|
|
110
|
+
end
|
|
111
|
+
if Dependabot::Experiments.enabled?(:gradle_lockfile_updater)
|
|
112
|
+
buildfiles_processed.each_value do |buildfile|
|
|
113
113
|
lockfile_updater = LockfileUpdater.new(dependency_files: files)
|
|
114
|
-
updated_files
|
|
114
|
+
updated_files = lockfile_updater.update_lockfiles(buildfile)
|
|
115
|
+
replace_updated_files(files, updated_files)
|
|
115
116
|
end
|
|
116
117
|
end
|
|
117
118
|
|
|
119
|
+
files
|
|
120
|
+
end
|
|
121
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
|
122
|
+
# rubocop:enable Metrics/AbcSize
|
|
123
|
+
sig do
|
|
124
|
+
params(
|
|
125
|
+
files: T::Array[Dependabot::DependencyFile],
|
|
126
|
+
updated_files: T::Array[Dependabot::DependencyFile]
|
|
127
|
+
).returns(T::Array[Dependabot::DependencyFile])
|
|
128
|
+
end
|
|
129
|
+
def replace_updated_files(files, updated_files)
|
|
118
130
|
updated_files.each do |file|
|
|
119
|
-
existing_file = files.find { |f| f.name == file.name
|
|
131
|
+
existing_file = files.find { |f| f.name == file.name }
|
|
120
132
|
if existing_file.nil?
|
|
121
133
|
files << file
|
|
122
134
|
else
|
|
123
135
|
files[T.must(files.index(existing_file))] = file
|
|
124
136
|
end
|
|
125
137
|
end
|
|
126
|
-
|
|
127
138
|
files
|
|
128
139
|
end
|
|
129
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
|
130
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
|
131
|
-
# rubocop:enable Metrics/AbcSize
|
|
132
|
-
# rubocop:enable Metrics/MethodLength
|
|
133
140
|
|
|
134
141
|
sig do
|
|
135
142
|
params(
|
|
@@ -12,6 +12,7 @@ require "dependabot/gradle/distributions"
|
|
|
12
12
|
require "dependabot/maven/utils/auth_headers_finder"
|
|
13
13
|
require "sorbet-runtime"
|
|
14
14
|
require "dependabot/gradle/metadata_finder"
|
|
15
|
+
require "dependabot/gradle/package/release_date_extractor"
|
|
15
16
|
|
|
16
17
|
module Dependabot
|
|
17
18
|
module Gradle
|
|
@@ -101,37 +102,16 @@ module Dependabot
|
|
|
101
102
|
|
|
102
103
|
sig { returns(T::Hash[String, T::Hash[Symbol, T.untyped]]) }
|
|
103
104
|
def release_details
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
url = repository_details.fetch("url")
|
|
109
|
-
next unless url == Gradle::FileParser::RepositoriesFinder::CENTRAL_REPO_URL
|
|
110
|
-
|
|
111
|
-
release_info_metadata(repository_details).css("a[title]").each do |link|
|
|
112
|
-
version_string = link["title"]
|
|
113
|
-
version = version_string.gsub(%r{/$}, "")
|
|
114
|
-
raw_date_text = link.next.text.strip.split("\n").last.strip
|
|
115
|
-
|
|
116
|
-
release_date = begin
|
|
117
|
-
Time.parse(raw_date_text)
|
|
118
|
-
rescue StandardError
|
|
119
|
-
nil
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
next unless version && version_class.correct?(version)
|
|
123
|
-
|
|
124
|
-
release_date_info[version] = {
|
|
125
|
-
release_date: release_date
|
|
126
|
-
}
|
|
127
|
-
end
|
|
128
|
-
end
|
|
105
|
+
extractor = ReleaseDateExtractor.new(
|
|
106
|
+
dependency_name: dependency.name,
|
|
107
|
+
version_class: version_class
|
|
108
|
+
)
|
|
129
109
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
{}
|
|
134
|
-
|
|
110
|
+
extractor.extract(
|
|
111
|
+
repositories: repositories,
|
|
112
|
+
dependency_metadata_fetcher: ->(repo) { dependency_metadata(repo) },
|
|
113
|
+
release_info_metadata_fetcher: ->(repo) { release_info_metadata(repo) }
|
|
114
|
+
)
|
|
135
115
|
end
|
|
136
116
|
|
|
137
117
|
sig { returns(T::Array[T::Hash[String, T.untyped]]) }
|
|
@@ -226,6 +206,8 @@ module Dependabot
|
|
|
226
206
|
end
|
|
227
207
|
end
|
|
228
208
|
|
|
209
|
+
# Fetches HTML directory listing from Maven-compatible repositories.
|
|
210
|
+
# Uses CSS selector "a[title]" to extract versions and dates. Caches results per repository.
|
|
229
211
|
sig { params(repository_details: T::Hash[T.untyped, T.untyped]).returns(T.untyped) }
|
|
230
212
|
def release_info_metadata(repository_details)
|
|
231
213
|
@release_info_metadata ||= T.let({}, T.nilable(T::Hash[Integer, T.untyped]))
|
|
@@ -237,14 +219,14 @@ module Dependabot
|
|
|
237
219
|
)
|
|
238
220
|
|
|
239
221
|
check_response(response, repository_details.fetch("url"))
|
|
240
|
-
Nokogiri::
|
|
222
|
+
Nokogiri::HTML(response.body)
|
|
241
223
|
rescue URI::InvalidURIError
|
|
242
|
-
Nokogiri::
|
|
224
|
+
Nokogiri::HTML("")
|
|
243
225
|
rescue Excon::Error::Socket, Excon::Error::Timeout,
|
|
244
226
|
Excon::Error::TooManyRedirects
|
|
245
227
|
raise if central_repo_urls.include?(repository_details["url"])
|
|
246
228
|
|
|
247
|
-
Nokogiri::
|
|
229
|
+
Nokogiri::HTML("")
|
|
248
230
|
end
|
|
249
231
|
end
|
|
250
232
|
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "nokogiri"
|
|
5
|
+
require "time"
|
|
6
|
+
require "sorbet-runtime"
|
|
7
|
+
require "dependabot/logger"
|
|
8
|
+
|
|
9
|
+
module Dependabot
|
|
10
|
+
module Gradle
|
|
11
|
+
module Package
|
|
12
|
+
# Extracts release dates from repository metadata to support the cooldown feature.
|
|
13
|
+
# Handles multiple repository formats (Maven Central HTML listings, Gradle Plugin Portal XML).
|
|
14
|
+
class ReleaseDateExtractor
|
|
15
|
+
extend T::Sig
|
|
16
|
+
|
|
17
|
+
sig do
|
|
18
|
+
params(
|
|
19
|
+
dependency_name: String,
|
|
20
|
+
version_class: T.class_of(Dependabot::Version)
|
|
21
|
+
).void
|
|
22
|
+
end
|
|
23
|
+
def initialize(dependency_name:, version_class:)
|
|
24
|
+
@dependency_name = dependency_name
|
|
25
|
+
@version_class = version_class
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Extracts release dates from all repositories.
|
|
29
|
+
# Attempts both parsing strategies for all repositories:
|
|
30
|
+
# 1. Gradle Plugin Portal style: maven-metadata.xml with lastUpdated timestamp (latest version only)
|
|
31
|
+
# 2. Maven repository style: HTML directory listings with per-version dates
|
|
32
|
+
# This supports mirrors/proxies of both Maven Central and Gradle Plugin Portal.
|
|
33
|
+
sig do
|
|
34
|
+
params(
|
|
35
|
+
repositories: T::Array[T::Hash[String, T.untyped]],
|
|
36
|
+
dependency_metadata_fetcher: T.proc.params(
|
|
37
|
+
repo: T::Hash[String, T.untyped]
|
|
38
|
+
).returns(Nokogiri::XML::Document),
|
|
39
|
+
release_info_metadata_fetcher: T.proc.params(
|
|
40
|
+
repo: T::Hash[String, T.untyped]
|
|
41
|
+
).returns(Nokogiri::HTML::Document)
|
|
42
|
+
).returns(T::Hash[String, T::Hash[Symbol, T.untyped]])
|
|
43
|
+
end
|
|
44
|
+
def extract(repositories:, dependency_metadata_fetcher:, release_info_metadata_fetcher:)
|
|
45
|
+
release_date_info = T.let({}, T::Hash[String, T::Hash[Symbol, T.untyped]])
|
|
46
|
+
|
|
47
|
+
begin
|
|
48
|
+
repositories.each do |repository_details|
|
|
49
|
+
parse_gradle_plugin_portal_release(
|
|
50
|
+
repository_details,
|
|
51
|
+
release_date_info,
|
|
52
|
+
dependency_metadata_fetcher
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
parse_maven_central_releases(
|
|
56
|
+
repository_details,
|
|
57
|
+
release_date_info,
|
|
58
|
+
release_info_metadata_fetcher
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
release_date_info
|
|
63
|
+
rescue StandardError => e
|
|
64
|
+
Dependabot.logger.error(
|
|
65
|
+
"Failed to get release date for #{@dependency_name}: #{e.class} - #{e.message}"
|
|
66
|
+
)
|
|
67
|
+
Dependabot.logger.error(e.backtrace&.join("\n") || "No backtrace available")
|
|
68
|
+
{}
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
sig { returns(String) }
|
|
75
|
+
attr_reader :dependency_name
|
|
76
|
+
|
|
77
|
+
sig { returns(T.class_of(Dependabot::Version)) }
|
|
78
|
+
attr_reader :version_class
|
|
79
|
+
|
|
80
|
+
# Parses Maven-style HTML directory listings to extract release dates.
|
|
81
|
+
sig do
|
|
82
|
+
params(
|
|
83
|
+
repository_details: T::Hash[String, T.untyped],
|
|
84
|
+
release_date_info: T::Hash[String, T::Hash[Symbol, T.untyped]],
|
|
85
|
+
metadata_fetcher: T.proc.params(
|
|
86
|
+
repo: T::Hash[String, T.untyped]
|
|
87
|
+
).returns(Nokogiri::HTML::Document)
|
|
88
|
+
).void
|
|
89
|
+
end
|
|
90
|
+
def parse_maven_central_releases(repository_details, release_date_info, metadata_fetcher)
|
|
91
|
+
metadata_fetcher.call(repository_details).css("a[title]").each do |link|
|
|
92
|
+
title = link["title"]
|
|
93
|
+
next unless title
|
|
94
|
+
|
|
95
|
+
version = title.gsub(%r{/$}, "")
|
|
96
|
+
next unless version_class.correct?(version)
|
|
97
|
+
next if release_date_info.key?(version)
|
|
98
|
+
|
|
99
|
+
release_date = extract_release_date_from_link(link, version)
|
|
100
|
+
release_date_info[version] = { release_date: release_date }
|
|
101
|
+
end
|
|
102
|
+
rescue StandardError => e
|
|
103
|
+
Dependabot.logger.debug(
|
|
104
|
+
"Could not parse Maven-style release dates from #{repository_details.fetch('url')} " \
|
|
105
|
+
"for #{dependency_name}: #{e.message}"
|
|
106
|
+
)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Parses Gradle Plugin Portal maven-metadata.xml for release dates.
|
|
110
|
+
sig do
|
|
111
|
+
params(
|
|
112
|
+
repository_details: T::Hash[String, T.untyped],
|
|
113
|
+
release_date_info: T::Hash[String, T::Hash[Symbol, T.untyped]],
|
|
114
|
+
metadata_fetcher: T.proc.params(
|
|
115
|
+
repo: T::Hash[String, T.untyped]
|
|
116
|
+
).returns(Nokogiri::XML::Document)
|
|
117
|
+
).void
|
|
118
|
+
end
|
|
119
|
+
def parse_gradle_plugin_portal_release(repository_details, release_date_info, metadata_fetcher)
|
|
120
|
+
metadata_xml = metadata_fetcher.call(repository_details)
|
|
121
|
+
last_updated = metadata_xml.at_xpath("//metadata/versioning/lastUpdated")&.text&.strip
|
|
122
|
+
latest_version = metadata_xml.at_xpath("//metadata/versioning/latest")&.text&.strip
|
|
123
|
+
|
|
124
|
+
return unless latest_version && version_class.correct?(latest_version)
|
|
125
|
+
return if release_date_info.key?(latest_version)
|
|
126
|
+
|
|
127
|
+
release_date = parse_gradle_timestamp(last_updated)
|
|
128
|
+
Dependabot.logger.info(
|
|
129
|
+
"Parsed Gradle Plugin Portal release for #{dependency_name}: #{latest_version} at #{release_date}"
|
|
130
|
+
)
|
|
131
|
+
release_date_info[latest_version] = { release_date: release_date }
|
|
132
|
+
rescue StandardError => e
|
|
133
|
+
Dependabot.logger.debug(
|
|
134
|
+
"Could not parse Gradle Plugin Portal metadata from #{repository_details.fetch('url')} " \
|
|
135
|
+
"for #{dependency_name}: #{e.message}"
|
|
136
|
+
)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Extracts release date from HTML link element's adjacent text.
|
|
140
|
+
sig { params(link: Nokogiri::XML::Element, version: String).returns(T.nilable(Time)) }
|
|
141
|
+
def extract_release_date_from_link(link, version)
|
|
142
|
+
raw_date_text = link.next.text.strip.split("\n").last.strip
|
|
143
|
+
Time.parse(raw_date_text)
|
|
144
|
+
rescue StandardError => e
|
|
145
|
+
Dependabot.logger.debug(
|
|
146
|
+
"Failed to parse release date for #{dependency_name} version #{version}: #{e.message}"
|
|
147
|
+
)
|
|
148
|
+
nil
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Parses Gradle Plugin Portal timestamp format (YYYYMMDDHHmmss).
|
|
152
|
+
sig { params(timestamp: T.nilable(String)).returns(T.nilable(Time)) }
|
|
153
|
+
def parse_gradle_timestamp(timestamp)
|
|
154
|
+
return nil if timestamp.nil? || timestamp.empty?
|
|
155
|
+
|
|
156
|
+
Time.strptime(timestamp, "%Y%m%d%H%M%S")
|
|
157
|
+
rescue ArgumentError => e
|
|
158
|
+
Dependabot.logger.warn(
|
|
159
|
+
"Failed to parse Gradle timestamp for #{dependency_name}: '#{timestamp}' - #{e.message}"
|
|
160
|
+
)
|
|
161
|
+
nil
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dependabot-gradle
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.353.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dependabot
|
|
@@ -15,28 +15,28 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.353.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.353.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: dependabot-maven
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
30
|
- - '='
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 0.
|
|
32
|
+
version: 0.353.0
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - '='
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 0.
|
|
39
|
+
version: 0.353.0
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: debug
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -272,6 +272,7 @@ files:
|
|
|
272
272
|
- lib/dependabot/gradle/metadata_finder.rb
|
|
273
273
|
- lib/dependabot/gradle/package/distributions_fetcher.rb
|
|
274
274
|
- lib/dependabot/gradle/package/package_details_fetcher.rb
|
|
275
|
+
- lib/dependabot/gradle/package/release_date_extractor.rb
|
|
275
276
|
- lib/dependabot/gradle/package_manager.rb
|
|
276
277
|
- lib/dependabot/gradle/requirement.rb
|
|
277
278
|
- lib/dependabot/gradle/update_checker.rb
|
|
@@ -284,7 +285,7 @@ licenses:
|
|
|
284
285
|
- MIT
|
|
285
286
|
metadata:
|
|
286
287
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
287
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
288
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.353.0
|
|
288
289
|
rdoc_options: []
|
|
289
290
|
require_paths:
|
|
290
291
|
- lib
|