Skip to content

Fix #12507: preserve unresolved ${...} in CLI -D values (Maven 3 semantics)#12523

Merged
gnodet merged 3 commits into
masterfrom
bugfix/cli-param-nested-interpolation
Jul 24, 2026
Merged

Fix #12507: preserve unresolved ${...} in CLI -D values (Maven 3 semantics)#12523
gnodet merged 3 commits into
masterfrom
bugfix/cli-param-nested-interpolation

Conversation

@gnodet

@gnodet gnodet commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #12507. Supersedes #12515 (adds the missing test update that unblocks CI).

BaseParser.populateUserProperties() interpolates user-specified -D values at CLI parse time against a callback that only knows session.topDirectory / session.rootDirectory. Every other expression — ${project.build.directory}, ${user.dir}, etc. — was silently replaced with "" because the Interpolator.interpolate(Map, UnaryOperator) convenience overload defaults to defaultsToEmpty=true.

This broke common CI patterns like -DaltDeploymentRepository=id::file://${project.build.directory}/deploy (URL becomes file:///deploy → wrong path, no error).

Root cause

PR #2480 added early interpolation of -D values to support ${session.topDirectory}, but the defaultsToEmpty=true API default was not appropriate for this call site — it wiped all expressions the early callback couldn't resolve. Maven 3 left them literal for later evaluation at mojo configuration time.

Changes

  • BaseParser.java: Pass defaultsToEmpty=false so unresolved placeholders stay literal for later evaluation by the plugin parameter expression evaluator. The ${session.topDirectory} / ${session.rootDirectory} support from User properties are not interpolated for paths #2480 is unaffected.
  • MavenITgh11978PlaceholderInCliArgTest: Update assertion to expect Maven 3 semantics — unknown ${...} preserved as literal, not emptied. The emptying was an unintended side effect of User properties are not interpolated for paths #2480, not a deliberate behavior. The test's primary purpose (launcher doesn't crash on ${...}) is unchanged.
  • New IT MavenITgh12507CliParamNestedInterpolationTest: Two cases (${user.dir} and ${project.build.directory} in CLI-supplied plugin parameters) — red on current master, green with the fix.

Credits

Original fix and IT by @ascheman in #12515. This PR adds the MavenITgh11978PlaceholderInCliArgTest update and rebases onto current master to unblock CI.

🤖 Generated with Claude Code

Gerd Aschemann and others added 3 commits July 23, 2026 18:03
MavenITgh12507CliParamNestedInterpolationTest shows that ${user.dir}
and ${project.build.directory} inside a -D-supplied plugin parameter
value are replaced with the empty string at CLI parse time
(BaseParser.populateUserProperties interpolates user-specified
properties with defaultsToEmpty=true against a paths-only callback),
while Maven 3 resolves such expressions at mojo configuration time.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BaseParser.populateUserProperties interpolated user-specified
properties with defaultsToEmpty=true against a paths-only callback,
silently replacing every expression it could not resolve (system
properties, project.* references) with the empty string. Pass
defaultsToEmpty=false so unresolved placeholders stay literal and are
evaluated later with full session/project context by the plugin
parameter expression evaluator -- restoring Maven 3 semantics for
values like -DaltDeploymentRepository=id::file://${project.build.directory}/x.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The previous assertion expected unknown ${...} in CLI -D values to be
emptied, but that was an unintended side effect of #2480 (which only
meant to add session.topDirectory interpolation). Maven 3 leaves
unknown placeholders literal — update the assertion to match.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ascheman

Copy link
Copy Markdown
Contributor

Thanks @gnodet — the direction reads right to me. Treating the gh-11978 empty-for-unknown expectation as the anomaly (rather than scoping the parse-time interpolation) restores Maven 3's literal-for-unknown behaviour uniformly, which is what the cross-version repro showed 3.9.16 and 3.10.0-rc-1 both do. Preserving unresolved ${...} at CLI parse time and letting PluginParameterExpressionEvaluator resolve project/session context later at mojo time is exactly the semantics -DaltDeploymentRepository=…file://${project.build.directory}/… needs.

CI is green here including the ITs. I've gone ahead and set the bug label and the 4.0.0-rc-6 milestone on this PR (matching #12507) so it's on the rc-6 radar — revert if you'd rather it not carry those. Happy to help with a maven-4.0.x backport once this lands on master; the fix applied cleanly to both lines when I tested it. Thanks again for carrying it over the line.

@ascheman ascheman removed this from the 4.0.0-rc-6 milestone Jul 23, 2026
@ascheman

Copy link
Copy Markdown
Contributor

Correction on my milestone note above: since this PR targets master and rc-6 ships from the maven-4.0.x branch, the 4.0.0-rc-6 milestone was misleading here — a master merge alone won't be in rc-6. I've removed it and added backport-to-4.0.x instead, which captures what actually needs to happen for the fix to reach rc-6. As offered, I'm happy to prepare that 4.0.x backport once this lands on master (it applied cleanly to both lines in my earlier testing).

@gnodet gnodet added this to the 4.1.0 milestone Jul 24, 2026
@gnodet
gnodet merged commit 828e528 into master Jul 24, 2026
42 of 44 checks passed
@gnodet
gnodet deleted the bugfix/cli-param-nested-interpolation branch July 24, 2026 06:54
gnodet added a commit that referenced this pull request Jul 24, 2026
…#12524)

* Add failing IT for #12507 (CLI ${...} param wipe)

MavenITgh12507CliParamNestedInterpolationTest shows that ${user.dir}
and ${project.build.directory} inside a -D-supplied plugin parameter
value are replaced with the empty string at CLI parse time
(BaseParser.populateUserProperties interpolates user-specified
properties with defaultsToEmpty=true against a paths-only callback),
while Maven 3 resolves such expressions at mojo configuration time.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Fix #12507: dont wipe unresolved ${...} in -D values

BaseParser.populateUserProperties interpolated user-specified
properties with defaultsToEmpty=true against a paths-only callback,
silently replacing every expression it could not resolve (system
properties, project.* references) with the empty string. Pass
defaultsToEmpty=false so unresolved placeholders stay literal and are
evaluated later with full session/project context by the plugin
parameter expression evaluator -- restoring Maven 3 semantics for
values like -DaltDeploymentRepository=id::file://${project.build.directory}/x.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Update gh-11978 IT to expect Maven 3 semantics for unknown placeholders

The previous assertion expected unknown ${...} in CLI -D values to be
emptied, but that was an unintended side effect of #2480 (which only
meant to add session.topDirectory interpolation). Maven 3 leaves
unknown placeholders literal — update the assertion to match.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Port gh-12507 IT to the 4.0.x test-harness API

The IT was written against master's newer test harness (Path-based
Verifier, no-arg AbstractMavenIntegrationTestCase). On maven-4.0.x
that API is File/String-based and requires a version-range super()
call, so the cherry-picked test did not compile.

- Add version gate super("[4.0.0-rc-6,)") — the fix ships in rc-6;
  the built 4.0.0-SNAPSHOT satisfies the range so the body runs.
- extractResources now returns File: use leading "/" +
  getAbsoluteFile().toPath().
- newVerifier(String) instead of newVerifier(Path).

Verified locally against the 4.0.x dist: gh-12507 2/2 + gh-11978
1/1, all run (not skipped).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Gerd Aschemann <ascheman@apache.org>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Guillaume Nodet <gnodet@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-to-4.0.x bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

${...} expressions in CLI-supplied plugin parameter values are wiped to empty at CLI parse time (Maven 3 resolves them at mojo configuration)

3 participants