dependabot-maven 0.394.0 → 0.396.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '009515ba93dc3e414380b797fe7b3aa17a388d024e5406e74291c901600f1a0c'
4
- data.tar.gz: b511053c1259a770b1f7a2d649cf357bec4abcab55ad3aacb34b96ec40482893
3
+ metadata.gz: f681ccdf35c9bb41f70991513c98aa2c71e0373c848231238cfb3f1fec8d5e66
4
+ data.tar.gz: 8c079e8daf4de93af87c167b0230c5d42c9046ce23359560ef76dcbb5e181130
5
5
  SHA512:
6
- metadata.gz: 36c134e6d66d0d445df02dca60b7ae8afe60dd585e7475e8c4668656b22bc6ca3b8917251110772709075112142cc7ffd109564573f5231fcb130adba9aaa2cf
7
- data.tar.gz: dd730e81dec85d5abb73e201c832087ac4e0f75a5a09284046b87d203a208415f0588e3f9b04c58a588ecf1a55e7c70673551b20a43fd59a3b27bf1a48ea5d7f
6
+ metadata.gz: c7c02de0cb8393690544546664a2f1b2a883850c241ab27b23c649b596db5ec41445c1d6904279de15b8aaec7243b7e90c41265b4e37bdf0d4856bd232c3bca1
7
+ data.tar.gz: b6ea966696ecc770959ec9e187bb3fce67da8cb3ab6186881e60b6cc39826dd6997ecad4722ea7b705efc1b43b953e7e262b92dd9f4e5ff49fb874b22d5a5971
@@ -4,6 +4,7 @@
4
4
  # Parses maven-wrapper.properties and emits Dependency objects for the two
5
5
  # tracked Maven coordinates: org.apache.maven:apache-maven (the maven distribution)
6
6
  # and org.apache.maven.wrapper:maven-wrapper (the wrapper plugin).
7
+ require "uri"
7
8
  require "dependabot/dependency_requirement"
8
9
  require "dependabot/maven/file_parser"
9
10
  require "dependabot/maven/distributions"
@@ -39,7 +40,8 @@ module Dependabot
39
40
  # - wrapperVersion property (>=3.3.1),
40
41
  # - version segment of wrapperUrl JAR filename (<3.3.0), or
41
42
  # - comment in the mvnw script body (3.3.0 only, see MWRAPPER-120 and MWRAPPER-134).
42
- # This field is mandatory and raises if none of the sources yield a version.
43
+ # When none of the sources yield a version, load_properties returns nil and the
44
+ # wrapper is skipped, so this field is only ever set to a resolved version.
43
45
  const :wrapper_version, String
44
46
 
45
47
  # The full JAR URL from the wrapperUrl property
@@ -65,7 +67,21 @@ module Dependabot
65
67
  DIST_URL_VERSION_REGEX = %r{
66
68
  /apache-maven-(?<version>[^/?#]+)-(?:bin|src)\.(?:zip|tar\.gz)(?:[?#].*)?\z
67
69
  }x
68
- class UnparseableDistributionUrl < RuntimeError; end
70
+
71
+ # Apache Maven Wrapper JAR as it appears in a wrapperUrl path. Anchored to the artifact
72
+ # directory, a numeric version directory, and a `maven-wrapper-<version>.jar` filename whose
73
+ # version equals that directory (via the \k<version> backreference), mirroring Maven's
74
+ # mandatory repository layout. This rejects foreign JARs sharing the directory (e.g.
75
+ # .../maven-wrapper/3.3.4/foreign-3.3.4.jar), non-artifact filenames
76
+ # (.../3.3.4/maven-wrapper-foreign.jar) and mismatched coordinates
77
+ # (.../3.3.4/maven-wrapper-9.9.9.jar). Matched on the path only (not the host, query, or
78
+ # fragment) so wrappers proxied through private registries are still recognised, while
79
+ # wrappers from other vendors (e.g. legacy io.takari) are not. Applied in apache_wrapper_url?.
80
+ WRAPPER_COORDINATE_REGEX = %r{
81
+ /org/apache/maven/wrapper/maven-wrapper/ # Apache Maven Wrapper artifact directory
82
+ (?<version>\d+\.\d+(?:\.\d+)?(?:-\w+)*)/ # version directory
83
+ maven-wrapper-\k<version>\.jar\z # artifact JAR named for that same version
84
+ }xi
69
85
 
70
86
  sig do
71
87
  params(
@@ -77,23 +93,11 @@ module Dependabot
77
93
  content = properties_file.content
78
94
  return [] unless content
79
95
 
80
- distribution_url = get_property_value(content, "distributionUrl")
81
- if distribution_url&.include?("mvnd")
82
- Dependabot.logger.warn("Maven daemon (mvnd) distribution is not supported, skipping wrapper update")
83
- return []
84
- end
85
-
86
- begin
87
- props = load_properties(content, script_files: script_files)
88
- rescue UnparseableDistributionUrl => e
89
- Dependabot.logger.warn("#{e.message}, skipping wrapper update")
90
- return []
91
- end
92
-
93
- if props.wrapper_url&.include?("takari")
94
- Dependabot.logger.warn("The Takari distribution is not supported, skipping wrapper update")
95
- return []
96
- end
96
+ # load_properties returns nil for wrappers we cannot safely update (missing
97
+ # mandatory data or an unsupported vendor/distribution). The reason is logged there,
98
+ # and we skip the wrapper without disrupting ordinary POM dependency parsing.
99
+ props = load_properties(content, script_files: script_files)
100
+ return [] unless props
97
101
 
98
102
  file_name = properties_file.name
99
103
  has_debug_scripts = debug_scripts?(script_files)
@@ -252,35 +256,65 @@ module Dependabot
252
256
  script_files.any? { |f| debug_scripts.any? { |s| f.name.end_with?(s) } }
253
257
  end
254
258
 
255
- sig { params(content: String, script_files: T::Array[DependencyFile]).returns(WrapperProperties) }
259
+ sig { params(content: String, script_files: T::Array[DependencyFile]).returns(T.nilable(WrapperProperties)) }
256
260
  def self.load_properties(content, script_files: [])
257
- distribution_url = get_property_value!(content, "distributionUrl")
261
+ distribution_url = get_property_value(content, "distributionUrl")
262
+ return skip_wrapper("distributionUrl property is missing") unless distribution_url
263
+
264
+ return skip_wrapper("Maven daemon (mvnd) distribution is not supported") if distribution_url.include?("mvnd")
265
+
258
266
  distribution_version = extract_distribution_version(distribution_url)
259
- distribution_sha256_sum = get_property_value(content, "distributionSha256Sum")
267
+ return skip_wrapper("could not extract Maven version from distributionUrl") unless distribution_version
268
+
260
269
  wrapper_url = get_property_value(content, "wrapperUrl")
261
- wrapper_sha256_sum = get_property_value(content, "wrapperSha256Sum")
262
- distribution_type = resolve_distribution_type(content, wrapper_url)
270
+ if wrapper_url && !apache_wrapper_url?(wrapper_url)
271
+ return skip_wrapper("wrapperUrl is not an Apache Maven Wrapper")
272
+ end
273
+
263
274
  wrapper_version = resolve_wrapper_version(content, wrapper_url, script_files)
275
+ unless wrapper_version
276
+ return skip_wrapper(
277
+ "could not determine Maven Wrapper version from wrapperVersion, wrapperUrl, or script files"
278
+ )
279
+ end
264
280
 
265
281
  WrapperProperties.new(
266
282
  distribution_url: distribution_url,
267
283
  distribution_version: distribution_version,
268
- distribution_sha256_sum: distribution_sha256_sum,
269
- wrapper_sha256_sum: wrapper_sha256_sum,
284
+ distribution_sha256_sum: get_property_value(content, "distributionSha256Sum"),
285
+ wrapper_sha256_sum: get_property_value(content, "wrapperSha256Sum"),
270
286
  wrapper_version: wrapper_version,
271
287
  wrapper_url: wrapper_url,
272
- distribution_type: distribution_type
288
+ distribution_type: resolve_distribution_type(content, wrapper_url)
273
289
  )
274
290
  end
275
291
 
276
- sig { params(content: String).returns(String) }
292
+ # Signals that the wrapper cannot be updated: logs the reason and returns nil so the
293
+ # caller treats the wrapper as absent rather than aborting the whole Maven parse.
294
+ sig { params(reason: String).returns(NilClass) }
295
+ def self.skip_wrapper(reason)
296
+ Dependabot.logger.warn("#{reason}, skipping Maven Wrapper update")
297
+ nil
298
+ end
299
+
300
+ sig { params(content: String).returns(T.nilable(String)) }
277
301
  def self.extract_distribution_version(content)
278
302
  match = content.match(DIST_URL_VERSION_REGEX)
279
- unless match && match[:version]
280
- raise UnparseableDistributionUrl, "Could not extract Maven version from distributionUrl"
281
- end
303
+ match && match[:version]
304
+ end
282
305
 
283
- T.must(match[:version])
306
+ # True when the wrapperUrl points at the Apache Maven Wrapper artifact. The coordinate is
307
+ # matched against the URL path only (never the query or fragment) so that a non-Apache JAR
308
+ # cannot slip through the allowlist by carrying the coordinate in a `?redirect=...` query.
309
+ # A malformed URL that cannot be parsed is treated as not-Apache.
310
+ sig { params(url: String).returns(T::Boolean) }
311
+ def self.apache_wrapper_url?(url)
312
+ path = URI.parse(url).path
313
+ return false unless path
314
+
315
+ path.match?(WRAPPER_COORDINATE_REGEX)
316
+ rescue URI::InvalidURIError
317
+ false
284
318
  end
285
319
 
286
320
  sig { params(content: String, target_key: String).returns(T.nilable(String)) }
@@ -324,15 +358,6 @@ module Dependabot
324
358
  end
325
359
  end
326
360
 
327
- sig { params(content: String, target_key: String).returns(String) }
328
- def self.get_property_value!(content, target_key)
329
- value = get_property_value(content, target_key)
330
-
331
- raise "Missing mandatory property: #{target_key}" if value.nil?
332
-
333
- value
334
- end
335
-
336
361
  private_class_method :build_distribution_dependency
337
362
  private_class_method :build_wrapper_dependency
338
363
  private_class_method :build_distribution_requirements
@@ -353,7 +378,7 @@ module Dependabot
353
378
  content: String,
354
379
  wrapper_url: T.nilable(String),
355
380
  script_files: T::Array[DependencyFile]
356
- ).returns(String)
381
+ ).returns(T.nilable(String))
357
382
  end
358
383
  def self.resolve_wrapper_version(content, wrapper_url, script_files)
359
384
  version = get_property_value(content, "wrapperVersion")
@@ -367,10 +392,6 @@ module Dependabot
367
392
  version = load_wrapper_version_from_scripts(script_files)
368
393
  end
369
394
 
370
- if version.nil?
371
- raise "Could not determine Maven Wrapper version from wrapperVersion, wrapperUrl, or script files"
372
- end
373
-
374
395
  version
375
396
  end
376
397
 
@@ -401,6 +422,8 @@ module Dependabot
401
422
  private_class_method :resolve_wrapper_version
402
423
  private_class_method :parse_version_from_wrapper_url
403
424
  private_class_method :load_wrapper_version_from_scripts
425
+ private_class_method :skip_wrapper
426
+ private_class_method :apache_wrapper_url?
404
427
  end
405
428
  end
406
429
  end
@@ -17,7 +17,7 @@ require "dependabot/errors"
17
17
  # - http://maven.apache.org/pom.html
18
18
  module Dependabot
19
19
  module Maven
20
- # rubocop:disable Metrics/ClassLength
20
+ # rubocop:disable-next Metrics/ClassLength
21
21
  class FileParser < Dependabot::FileParsers::Base
22
22
  extend T::Sig
23
23
 
@@ -658,7 +658,6 @@ module Dependabot
658
658
  doc.css(PLUGIN_SELECTOR, PLUGIN_ARTIFACT_ITEMS_SELECTOR)
659
659
  end
660
660
  end
661
- # rubocop:enable Metrics/ClassLength
662
661
  end
663
662
  end
664
663
 
@@ -222,6 +222,7 @@ module Dependabot
222
222
  wrapper_plugin_version: wrapper_version,
223
223
  env: build_env,
224
224
  distribution_type: distribution_type,
225
+ registry_base: resolved_registry_base,
225
226
  extra_args: extra_args,
226
227
  cwd: wrapper_dir
227
228
  )
@@ -288,8 +289,10 @@ module Dependabot
288
289
  end
289
290
 
290
291
  # Builds the environment hash passed to the native wrapper command.
291
- # Sets the proxy host and, for a private/mirror registry, MVNW_REPOURL. Registry auth is
292
- # injected by Dependabot's proxy, so no username/password is set here (core never receives them).
292
+ # Sets only the proxy host. Registry routing is handled by the native
293
+ # helper's generated settings mirror (see `resolved_registry_base`), and
294
+ # registry auth is injected by Dependabot's proxy, so no username/password
295
+ # is set here (core never receives them).
293
296
  sig { returns(T::Hash[String, String]) }
294
297
  def build_env
295
298
  env = T.let({}, T::Hash[String, String])
@@ -299,9 +302,6 @@ module Dependabot
299
302
  env["PROXY_HOST"] = proxy_url.host.to_s
300
303
  end
301
304
 
302
- registry_base, cred = resolve_registry_base_and_credential
303
- env.merge!(build_registry_env(registry_base, cred))
304
-
305
305
  if Dependabot.logger.debug?
306
306
  env["MVNW_VERBOSE"] = "true"
307
307
  Dependabot.logger.debug "build_env result: #{env}"
@@ -310,51 +310,18 @@ module Dependabot
310
310
  env
311
311
  end
312
312
 
313
- sig do
314
- returns([T.nilable(String), T.nilable(Dependabot::Credential)])
315
- end
316
- def resolve_registry_base_and_credential
317
- properties = wrapper_properties_file&.content.to_s
318
- dist_url = effective_distribution_url(properties)
319
- Dependabot.logger.debug "Effective distribution URL: #{dist_url}"
320
-
321
- registry_base_regex = %r{^(https?://[^/]+(?:/[^/]+)*)/org/apache/maven/apache-maven/}
322
- registry_base = dist_url&.match(registry_base_regex)&.captures&.first
323
- Dependabot.logger.debug "Extracted registry base: #{registry_base || '(none)'}"
324
-
325
- cred = maven_registry_credential(registry_base)
326
- Dependabot.logger.debug "Matched credential: #{cred ? "url=#{cred.fetch('url', '(none)')}" : '(none)'}"
327
-
328
- [registry_base, cred]
329
- end
330
-
331
- sig do
332
- params(registry_base: T.nilable(String), cred: T.nilable(Dependabot::Credential))
333
- .returns(T::Hash[String, String])
334
- end
335
- def build_registry_env(registry_base, cred)
336
- if registry_base
337
- { "MVNW_REPOURL" => registry_base }
338
- elsif cred&.replaces_base?
339
- { "MVNW_REPOURL" => cred.fetch("url").chomp("/") }
340
- else
341
- {}
342
- end
343
- end
344
-
345
- sig { params(registry_base: T.nilable(String)).returns(T.nilable(Dependabot::Credential)) }
346
- def maven_registry_credential(registry_base)
347
- maven_creds = @credentials.select { |c| c["type"] == "maven_repository" }
348
-
349
- if registry_base
350
- url_matches = maven_creds.select do |c|
351
- cred_url = c.fetch("url", "").chomp("/")
352
- !cred_url.empty? && registry_base.start_with?(cred_url)
353
- end
354
- return url_matches.max_by { |c| c.fetch("url", "").length } if url_matches.any?
355
- end
356
-
357
- maven_creds.find(&:replaces_base?)
313
+ # The registry that actually served the release we're updating to. `source_url` on the
314
+ # resolved requirement is `release.url` from version resolution
315
+ # (base_version_finder: `{ version: release.version, source_url: release.url }`), so it is
316
+ # the one place `mvn` is guaranteed to find this version. The native regeneration mirrors
317
+ # plugin/distribution resolution there instead of falling back to Central and hanging behind
318
+ # a no-egress registry. Nil only when no version resolved, leaving the Central default.
319
+ #
320
+ # A trailing slash is stripped so Maven appends the artifact path to a canonical base
321
+ # (`base/org/...`, not `base//org/...`) and registries don't 301-redirect every request.
322
+ sig { returns(T.nilable(String)) }
323
+ def resolved_registry_base
324
+ dependency.requirements.filter_map { |req| req.metadata_string("source_url") }.first&.chomp("/")
358
325
  end
359
326
 
360
327
  sig { params(buildfile: DependencyFile).returns(String) }
@@ -3,10 +3,12 @@
3
3
 
4
4
  require "fileutils"
5
5
  require "open3"
6
+ require "tempfile"
6
7
  require "uri"
7
8
  require "sorbet-runtime"
8
9
  require "nokogiri"
9
10
  require "dependabot/errors"
11
+ require "dependabot/command_helpers"
10
12
  require "dependabot/shared_helpers"
11
13
 
12
14
  module Dependabot
@@ -33,6 +35,11 @@ module Dependabot
33
35
  # codes; we strip these so classification and the surfaced summary see plain text.
34
36
  ANSI_ESCAPE_REGEX = %r{\e\[[0-9;?]*[ -/]*[@-~]}
35
37
 
38
+ # Bounded inactivity timeout for the wrapper download. `run_shell_command`'s watchdog
39
+ # resets on output, and with transfer progress restored a healthy download keeps it
40
+ # alive, so this only trips on genuine silence — well below the 900s DEFAULT.
41
+ WRAPPER_DOWNLOAD_TIMEOUT = CommandHelpers::TIMEOUTS::LONG_RUNNING
42
+
36
43
  pom_path = File.join(__dir__, "pom.xml")
37
44
 
38
45
  version = File.open(pom_path) do |f|
@@ -86,21 +93,32 @@ module Dependabot
86
93
  wrapper_plugin_version: String,
87
94
  env: T::Hash[String, String],
88
95
  distribution_type: String,
96
+ registry_base: T.nilable(String),
89
97
  extra_args: T::Array[String],
90
98
  cwd: T.nilable(String)
91
99
  ).void
92
100
  end
93
- def self.run_mvnw_wrapper(version:, wrapper_plugin_version:, env:, distribution_type:, extra_args: [], cwd: nil)
101
+ def self.run_mvnw_wrapper(
102
+ version:,
103
+ wrapper_plugin_version:,
104
+ env:,
105
+ distribution_type:,
106
+ registry_base: nil,
107
+ extra_args: [],
108
+ cwd: nil
109
+ )
94
110
  # Use the fully-qualified plugin goal so the exact plugin version is
95
111
  # invoked regardless of the project's plugin group configuration.
96
112
  plugin_goal = "org.apache.maven.plugins:maven-wrapper-plugin:" \
97
113
  "#{wrapper_plugin_version}:wrapper"
98
114
 
115
+ # Do NOT add `--no-transfer-progress`: Maven's transfer progress is the liveness signal
116
+ # that keeps `run_shell_command`'s inactivity watchdog alive during a large download.
117
+ # Suppressing it made a healthy-but-slow fetch look hung and get killed at the timeout.
99
118
  standard_args = [
100
119
  plugin_goal,
101
120
  "-Dmaven=#{version}",
102
- "-Dtype=#{distribution_type}",
103
- "--no-transfer-progress"
121
+ "-Dtype=#{distribution_type}"
104
122
  ] + extra_args
105
123
 
106
124
  # Pass the argument vector directly instead of a pre-joined shell string.
@@ -111,7 +129,22 @@ module Dependabot
111
129
  cmd = ["mvn"] + standard_args
112
130
  run_cwd = cwd && cwd != "." ? cwd : nil
113
131
 
114
- output = SharedHelpers.run_shell_command(cmd, env: env, cwd: run_cwd)
132
+ # Route the native `mvn`'s plugin/distribution resolution to the registry that served the
133
+ # resolved version via a generated settings mirror; without it `mvn` falls back to Central
134
+ # and hangs behind a no-egress registry. Absent when no version resolved, leaving the baked
135
+ # Central default. The bounded timeout is explained on WRAPPER_DOWNLOAD_TIMEOUT.
136
+ settings_file = registry_base && wrapper_settings_file(registry_base)
137
+ settings_args = settings_file ? ["-s", T.must(settings_file.path)] : []
138
+ begin
139
+ output = SharedHelpers.run_shell_command(
140
+ cmd + settings_args,
141
+ env: env,
142
+ cwd: run_cwd,
143
+ timeout: WRAPPER_DOWNLOAD_TIMEOUT
144
+ )
145
+ ensure
146
+ settings_file&.close! # deletes the temp file
147
+ end
115
148
  Dependabot.logger.info("mvn wrapper output: STDOUT:#{output}")
116
149
  output
117
150
  rescue SharedHelpers::HelperSubprocessFailed => e
@@ -124,6 +157,46 @@ module Dependabot
124
157
  handle_wrapper_error(e)
125
158
  end
126
159
 
160
+ # Writes a temporary Maven settings file that keeps the proxy block and adds a
161
+ # mirror pointing every external repository at the resolved base. Registry
162
+ # auth still flows through the Dependabot proxy; no credentials are written here.
163
+ # The caller is responsible for deleting the returned file (via `close!`).
164
+ sig { params(registry_base: String).returns(Tempfile) }
165
+ def self.wrapper_settings_file(registry_base)
166
+ file = Tempfile.new(["dependabot-mvn-wrapper-settings", ".xml"])
167
+ file.write(wrapper_settings_xml(registry_base))
168
+ file.close
169
+ file
170
+ end
171
+
172
+ # Builds the settings XML used for the wrapper invocation: the same proxy block as
173
+ # the baked settings (auth is injected by the proxy) plus a `mirrorOf=external:*`
174
+ # mirror so plugin, transitive POM, and distribution resolution all route through
175
+ # the resolved base instead of Central.
176
+ sig { params(registry_base: String).returns(String) }
177
+ def self.wrapper_settings_xml(registry_base)
178
+ <<~XML
179
+ <settings>
180
+ <proxies>
181
+ <proxy>
182
+ <id>dependabot-proxy</id>
183
+ <active>true</active>
184
+ <protocol>http</protocol>
185
+ <host>${env.PROXY_HOST}</host>
186
+ <port>1080</port>
187
+ </proxy>
188
+ </proxies>
189
+ <mirrors>
190
+ <mirror>
191
+ <id>dependabot-wrapper-mirror</id>
192
+ <mirrorOf>external:*</mirrorOf>
193
+ <url>#{registry_base.encode(xml: :text)}</url>
194
+ </mirror>
195
+ </mirrors>
196
+ </settings>
197
+ XML
198
+ end
199
+
127
200
  # Classifies a failed Maven Wrapper invocation into an actionable Dependabot
128
201
  # error. Known auth and plugin-resolution failures are mapped to their specific
129
202
  # error types, and genuine Maven diagnostics are surfaced via MisconfiguredTooling.
@@ -80,15 +80,19 @@ module Dependabot
80
80
  return possible_releases_reverse.find { |r| released?(r.version) } unless cooldown_options
81
81
 
82
82
  cooldown_filtered_releases = 0
83
- latest_release = possible_releases_reverse.find do |release|
84
- if in_cooldown_period?(release)
85
- Dependabot.logger.info("Filtered out (cooldown) : #{release}")
86
- cooldown_filtered_releases += 1
87
- next false
83
+ latest_releases = cooldown_tracker.filter_prefiltered do
84
+ latest_release = possible_releases_reverse.find do |release|
85
+ if in_cooldown_period?(release)
86
+ Dependabot.logger.info("Filtered out (cooldown) : #{release}")
87
+ cooldown_filtered_releases += 1
88
+ next false
89
+ end
90
+
91
+ released?(release.version)
88
92
  end
89
-
90
- released?(release.version)
93
+ latest_release ? [latest_release] : []
91
94
  end
95
+ latest_release = latest_releases.first
92
96
 
93
97
  if cooldown_filtered_releases.positive?
94
98
  Dependabot.logger.info(
@@ -134,9 +134,7 @@ module Dependabot
134
134
  sig { returns(String) }
135
135
  def property_name
136
136
  @property_name ||= T.let(
137
- dependency.requirements
138
- .find { |r| r.metadata_string("property_name") }
139
- &.metadata_string("property_name"),
137
+ property_requirement.metadata_string("property_name"),
140
138
  T.nilable(String)
141
139
  )
142
140
 
@@ -148,13 +146,33 @@ module Dependabot
148
146
  sig { returns(T.nilable(String)) }
149
147
  def property_source
150
148
  @property_source ||= T.let(
151
- dependency.requirements
152
- .find { |r| r.metadata_string("property_name") == property_name }
153
- &.metadata_string("property_source"),
149
+ property_requirement.metadata_string("property_source"),
154
150
  T.nilable(String)
155
151
  )
156
152
  end
157
153
 
154
+ sig { returns(Dependabot::DependencyRequirement) }
155
+ def property_requirement
156
+ property_requirements = dependency.requirements.select { |r| r.metadata_string("property_name") }
157
+ matching_requirement = property_requirements.find do |requirement|
158
+ normalized_requirement_version(requirement) == dependency.version
159
+ end
160
+ requirement = matching_requirement || property_requirements.first
161
+
162
+ raise "No requirement with a property name!" unless requirement
163
+
164
+ requirement
165
+ end
166
+
167
+ sig { params(requirement: Dependabot::DependencyRequirement).returns(T.nilable(String)) }
168
+ def normalized_requirement_version(requirement)
169
+ requirement_string = requirement.requirement_string
170
+ return unless requirement_string
171
+ return if requirement_string.include?(",")
172
+
173
+ requirement_string.gsub(/[\(\)\[\]]/, "").strip
174
+ end
175
+
158
176
  sig { params(string: String).returns(T::Boolean) }
159
177
  def includes_property_reference?(string)
160
178
  string.match?(Maven::FileParser::PROPERTY_REGEX)
@@ -86,13 +86,13 @@ module Dependabot
86
86
  sig { returns(T::Array[Dependabot::DependencyRequirement]) }
87
87
  attr_reader :requirements
88
88
 
89
- # Bumps a wrapper (maven-wrapper.properties) requirement. As well as the requirement
90
- # string, it updates the fields the FileUpdater actually reads so a real update regenerates
91
- # the *new* release rather than the old one:
92
- # - distributionUrl -> metadata[:distribution_version] and the versioned source url
93
- # - wrapperVersion -> metadata[:wrapper_version]
94
- # The wrapperUrl tag-along requirement (present only on the distribution dependency) is left
95
- # otherwise untouched, since bumping the distribution does not change the wrapper JAR.
89
+ # Bumps a wrapper (maven-wrapper.properties) requirement to the resolved version, keeping the
90
+ # fields the FileUpdater reads in sync so it regenerates the *new* release, not the old one:
91
+ # - distributionUrl -> metadata[:distribution_version] + the versioned source url
92
+ # - wrapperVersion -> metadata[:wrapper_version]
93
+ # - both -> metadata[:source_url] (registry that served the version, so the
94
+ # FileUpdater can mirror the native `mvn` there)
95
+ # - wrapperUrl -> left untouched (tag-along; bumping the distribution doesn't move it)
96
96
  sig do
97
97
  params(req: Dependabot::DependencyRequirement)
98
98
  .returns(Dependabot::DependencyRequirement)
@@ -105,15 +105,32 @@ module Dependabot
105
105
  when "distributionUrl"
106
106
  updated = Dependabot::DependencyRequirement.create(req.merge(requirement: new_version))
107
107
  updated = merge_metadata_version(updated, :distribution_version, new_version)
108
- merge_source_url(updated, old_version, new_version)
108
+ updated = merge_source_url(updated, old_version, new_version)
109
+ merge_registry_source_url(updated)
109
110
  when "wrapperVersion"
110
111
  updated = Dependabot::DependencyRequirement.create(req.merge(requirement: new_version))
111
- merge_metadata_version(updated, :wrapper_version, new_version)
112
+ updated = merge_metadata_version(updated, :wrapper_version, new_version)
113
+ merge_registry_source_url(updated)
112
114
  else
113
115
  req
114
116
  end
115
117
  end
116
118
 
119
+ # Stamps the registry that served the resolved version (source_url = release.url) onto the
120
+ # wrapper requirement metadata, so the FileUpdater can mirror the native `mvn` regeneration
121
+ # to the same registry the version was resolved and vetted against. Nil when no version
122
+ # resolved (no key added), leaving the wrapper's Central default.
123
+ sig do
124
+ params(req: Dependabot::DependencyRequirement).returns(Dependabot::DependencyRequirement)
125
+ end
126
+ def merge_registry_source_url(req)
127
+ base = source_url
128
+ return req unless base
129
+
130
+ metadata = req.metadata || {}
131
+ Dependabot::DependencyRequirement.create(req.merge(metadata: metadata.merge(source_url: base)))
132
+ end
133
+
117
134
  sig do
118
135
  params(req: Dependabot::DependencyRequirement, key: Symbol, new_version: String)
119
136
  .returns(Dependabot::DependencyRequirement)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-maven
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.394.0
4
+ version: 0.396.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.394.0
18
+ version: 0.396.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.394.0
25
+ version: 0.396.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: rexml
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -192,19 +192,19 @@ dependencies:
192
192
  - !ruby/object:Gem::Version
193
193
  version: '1.1'
194
194
  - !ruby/object:Gem::Dependency
195
- name: turbo_tests
195
+ name: turbo_tests2
196
196
  requirement: !ruby/object:Gem::Requirement
197
197
  requirements:
198
198
  - - "~>"
199
199
  - !ruby/object:Gem::Version
200
- version: 2.2.5
200
+ version: 3.2.7
201
201
  type: :development
202
202
  prerelease: false
203
203
  version_requirements: !ruby/object:Gem::Requirement
204
204
  requirements:
205
205
  - - "~>"
206
206
  - !ruby/object:Gem::Version
207
- version: 2.2.5
207
+ version: 3.2.7
208
208
  - !ruby/object:Gem::Dependency
209
209
  name: vcr
210
210
  requirement: !ruby/object:Gem::Requirement
@@ -296,7 +296,7 @@ licenses:
296
296
  - MIT
297
297
  metadata:
298
298
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
299
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.394.0
299
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.396.0
300
300
  rdoc_options: []
301
301
  require_paths:
302
302
  - lib