Skip to content

Fix #12430: mvnup upgrade strategies and compatibility improvements#12454

Open
gnodet wants to merge 17 commits into
apache:masterfrom
gnodet:add-http-to-https-repository-url-upgrade-to-mvnup
Open

Fix #12430: mvnup upgrade strategies and compatibility improvements#12454
gnodet wants to merge 17 commits into
apache:masterfrom
gnodet:add-http-to-https-repository-url-upgrade-to-mvnup

Conversation

@gnodet

@gnodet gnodet commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Consolidates #12430 and #12443 into a single PR, plus new features:

New strategies

  • RepositoryHttpsUpgradeStrategy — converts HTTP repository URLs to HTTPS (blocked since Maven 3.8.1+), with well-known canonical URL mappings for Maven Central and Apache repositories
  • EnforcerVersionRangeStrategy — widens requireMavenVersion ranges that exclude Maven 4 (e.g., [3.8.8,4)[3.8.8,5))

Quarkus plugin improvements

  • Skip upgrade for Quarkus 2.x — detects the Quarkus platform version from dependencyManagement (quarkus-bom) or well-known properties (quarkus.platform.version, quarkus.version) and skips the quarkus-maven-plugin upgrade when the project uses Quarkus 2.x, preventing NoSuchMethodError build failures
  • Quarkus plugin upgrade support, BOM version decoupling, and version gap warnings (from mvnup: Quarkus plugin upgrade, CLI robustness, and Maven 4 compatibility warnings #12430)

Bug fixes

Other improvements (from #12430)

  • Silently ignore unrecognized CLI options from .mvn/maven.config
  • Warn about property-interpolated module paths
  • Warn about CI-friendly ${revision} missing dependency versions
  • Auto-upgrade gmavenplus-plugin to Maven 4-compatible version
  • Upgrade DomTrip to 1.6.0 (from Fix mvnup comment formatting for override comments #12443)

Supersedes #12430 and #12443 (commits cherry-picked).

Test plan

  • 27 tests for RepositoryHttpsUpgradeStrategy
  • 22 tests for EnforcerVersionRangeStrategy
  • 11 tests for Quarkus platform version detection and 2.x skip behavior
  • 3 tests for last-wins dedup semantics (2 updated + 1 new)
  • Full module test suite passes (554 tests, 0 failures)

🤖 Generated with Claude Code

gnodet and others added 2 commits July 9, 2026 09:00
…o mvnup

Since Maven 3.8.1+, HTTP repositories are blocked by the
maven-default-http-blocker mirror. This adds a RepositoryHttpsUpgradeStrategy
that automatically converts http:// repository URLs to https:// in POM files.

Well-known repositories (Apache snapshots/releases, Maven Central variants)
are mapped to their canonical HTTPS equivalents. All other http:// URLs get
a generic scheme upgrade.

Handles repositories, pluginRepositories, distributionManagement (both
repository and snapshotRepository), and profile-scoped repositories.

Includes 27 tests covering well-known URL normalization, generic http->https
conversion, all POM sections, profile-scoped repos, and edge cases.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… dedup last-wins

Add EnforcerVersionRangeStrategy that widens requireMavenVersion ranges
excluding Maven 4 (e.g. [3.8.8,4) → [3.8.8,5)) in the maven-enforcer-plugin.
Handles top-level and per-execution configurations, pluginManagement, and
profile-scoped declarations.

Fix CompatibilityFixStrategy dependency/plugin deduplication to use last-wins
semantics (matching Maven 3 runtime behavior) instead of first-wins. Update
log messages to include the kept version.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gnodet gnodet changed the title mvnup: Add HTTP-to-HTTPS repository URL upgrade strategy Fix #12430: Add upgrade strategies to mvnup (HTTPS, enforcer, dedup) Jul 9, 2026
@gnodet gnodet added this to the 4.0.0-rc-6 milestone Jul 9, 2026
@gnodet gnodet marked this pull request as ready for review July 9, 2026 13:25
@gnodet gnodet requested a review from cstamas July 9, 2026 13:25
gnodet and others added 11 commits July 9, 2026 13:37
Add PluginUpgrade entries for quarkus-maven-plugin (both io.quarkus
and io.quarkus.platform groupIds) with minimum version 3.26.0.
When the plugin version references the same property as a Quarkus BOM,
the strategy decouples it by introducing a separate quarkus-plugin.version
property. After upgrading, emits a warning if the platform BOM version
is significantly older than the plugin version.

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

mvnup inherits the Maven launcher's argument handling, which appends
options from .mvn/maven.config. That file often contains build flags
like -ntp, -U, or -T that mvnup does not recognize, causing a
ParseException before any upgrades are applied.

Override CLIManager.parse() to catch UnrecognizedOptionException and
retry after removing the offending option, so mvnup works in projects
with a .mvn/maven.config file.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
gmavenplus-plugin (all versions up to 4.1.1) calls mutating methods
on immutable lists returned by the Maven 4 API, causing
UnsupportedOperationException on goals like removeStubs.

Add a warning-only check to CompatibilityFixStrategy that detects
known incompatible plugins and emits a warning with a link to the
upstream issue tracker. The check does not modify the POM.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Maven 4's prefix-based artifact filtering may block resolution from
repositories that do not publish a prefixes.txt file. When Maven 4
auto-generates an incomplete prefix list, legitimate artifacts are
rejected with ArtifactFilteredOutException.

Add a warning for non-Maven-Central repositories detected in POMs,
advising users to check prefix configuration if builds fail.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Maven 4 validates module paths during POM parsing, before property
interpolation occurs. Paths like <module>spark-${spark.version}</module>
are rejected because the literal string (with the unresolved
expression) does not correspond to an existing directory.

Add a warning for module/subproject elements containing ${...}
expressions, both at root level and inside profiles.

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

In CI-friendly projects using ${revision}, ${sha1}, or ${changelist}
as the parent version, child modules with versionless dependencies
may fail with 'dependencies.dependency.version is missing' because
Maven 4 validates dependency completeness before fully resolving the
parent's dependencyManagement chain.

Add a warning that detects this pattern: a parent with a CI-friendly
version expression and dependencies without explicit <version> elements.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Maven 4's prefix filtering defaults to permissive behavior when a
repository has no prefixes.txt — artifacts are allowed through, not
blocked. The warning was based on a misunderstanding of the default
noInputOutcome=true setting. The actual issue is narrower: only
auto-discovered prefix files with incomplete content can cause false
negatives, and Maven already provides per-repository disable options
and helpful hints in ArtifactFilteredOutException messages.

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

- CLI option stripping: also remove trailing argument values for
  options like "-T 4" (two tokens) to prevent the value from being
  treated as a spurious goal.
- BOM property decoupling: skip when the shared property is not
  declared in the current POM (inherited from parent), since we
  cannot resolve its actual value and introducing a new property
  could downgrade an already-sufficient inherited version.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…n version gap warning

- Move gmavenplus-plugin from KNOWN_INCOMPATIBLE_PLUGINS (permanent warning)
  to PluginUpgrade with minimum version 4.2.0. The Maven 4 incompatibility
  was fixed in groovy/GMavenPlus#328 (released in 4.2.0), and the Maven-side
  fix landed in MNG-8662.
- Soften the Quarkus version gap warning: remove the unsubstantiated claim
  about binary incompatibility at 3.32.0 and replace with general version
  alignment advice.
- Fix wrong Quarkus upstream reference in PR description (#46889 → #37627).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When mvnup inserts "Override version inherited from parent" comments
before plugin elements, the comment was placed on the same line as
the preceding </plugin> closing tag, causing POM formatting violations
in projects that enforce XML formatting (e.g. via spotless).

The fix sets precedingWhitespace on the Comment node to match the
plugin element's indentation, ensuring the comment appears on its
own line.

Fixes gnodet/maven4-testing#23134

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the manual precedingWhitespace() workaround with the new
Editor.insertCommentBefore() method added in DomTrip 1.6.0
(maveniverse/domtrip#254), which handles whitespace automatically.

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

Detect the Quarkus platform version before upgrading quarkus-maven-plugin.
Projects using Quarkus 2.x (or 1.x) get their plugin upgrade skipped to
prevent NoSuchMethodError and build failures from the 2.x→3.x jump.

Detection checks dependencyManagement for quarkus-bom (resolving property
references), then falls back to quarkus.platform.version / quarkus.version
/ quarkus-plugin.version properties. When the version cannot be determined,
a warning is emitted.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gnodet gnodet changed the title Fix #12430: Add upgrade strategies to mvnup (HTTPS, enforcer, dedup) Fix #12430: mvnup upgrade strategies and compatibility improvements Jul 9, 2026
gnodet and others added 2 commits July 9, 2026 21:55
…nputException on binary files

Maven 4 strictly decodes filtered resources as UTF-8, causing
MalformedInputException when binary files (.xlsx, .docx, etc.) are
present in resource directories with <filtering>true</filtering>.

This strategy scans all <resource> and <testResource> blocks. When
filtering is enabled and the maven-resources-plugin does not already
declare <nonFilteredFileExtensions>, adds a comprehensive list of 23
binary file extensions (office docs, archives, fonts, executables,
keystores) to pluginManagement. If a partial config exists, merges
the missing extensions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Maven 4 rejects duplicate dependency/plugin declarations that Maven 3
silently accepted. Extract the deduplication logic into a standalone
strategy for clarity and independent control.

The new strategy scans <dependencies>, <dependencyManagement>, and
<plugins>/<pluginManagement> sections (including profiles) and removes
duplicates using last-wins semantics matching Maven 3's runtime
behavior. The key is groupId:artifactId:type:classifier for
dependencies and groupId:artifactId for plugins.

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

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thorough review of this large PR (6900+ lines, 17 files) covering mvnup upgrade strategies and compatibility improvements.

Verified findings (4 confirmed, 2 false positives dropped):

  1. DeduplicateDependenciesStrategy — "last-wins" semantics documentation (medium): The Javadoc on line 59 states "keeping the last declaration (matching Maven 3's last-wins behavior at runtime)", but Maven 3's dependency resolver actually uses first-wins for same-depth conflicts. For plugins, Maven 3 does merge later declarations over earlier ones (effectively last-wins for configuration), so last-wins is correct for plugins but not for dependencies. The old code in CompatibilityFixStrategy used first-wins for dependencies. Consider either updating the Javadoc to document this is an intentional behavior change, or switching to first-wins for dependencies.

  2. CommonsCliUpgradeOptions parse() retry loop (low): When CleanArgument.cleanArgs() strips surrounding quotes, UnrecognizedOptionException.getOption() returns the post-cleaned option name while currentArgs has pre-cleaned strings. For a quoted arg like "-ntp", indexOf("-ntp") would fail to match. The idx < 0 guard correctly throws, so behavior degrades gracefully to an error rather than a silent bug. Very unlikely in practice.

  3. EnforcerVersionRangeStrategy regex scope (low): The regex 4(?:\.\d+)* matches any 4.x upper bound (4.1, 4.2, etc.), not just 4/4.0/4.0.0. The Javadoc examples only show the narrower case. Consider tightening to 4(?:\.0+)* or updating the documentation.

  4. ResourceFilteringStrategy BINARY_EXTENSIONS (low): The list of 23 entries is labeled "comprehensive" but omits common binary types (png, jpg/jpeg, gif, mp3, mp4, sqlite, p12/pfx). Consider expanding the list or softening the "comprehensive" claim.

  5. RepositoryHttpsUpgradeStrategy LinkedHashMap comment (low): Comment claims ordering ensures "longer prefixes are checked before shorter ones", but entries are not actually ordered by length. Ordering doesn't matter for correctness since no key is a prefix of another, but the comment is misleading.

False positives dropped by verifier:

  • Multi-segment version ranges: the regex DOES match union ranges correctly (lazy quantifier handles them)
  • Missing test edge cases: existing test coverage is adequate

Overall: Well-structured PR with clean separation of strategies. No blocking issues — findings are informational comments and minor documentation improvements.

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of Guillaume Nodet

- DeduplicateDependenciesStrategy: clarify last-wins is intentional,
  not matching Maven 3's first-wins dependency resolution
- EnforcerVersionRangeStrategy: document regex matches any 4.x upper
  bound, not just 4/4.0/4.0.0
- ResourceFilteringStrategy: add 10 missing binary extensions (png,
  jpg, jpeg, gif, bmp, tiff, mp3, mp4, p12, pfx) and soften
  "comprehensive" wording to "common"
- RepositoryHttpsUpgradeStrategy: fix misleading LinkedHashMap comment
  about prefix length ordering

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

gnodet commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the review feedback in cbdee27:

  1. DeduplicateDependenciesStrategy Javadoc — Clarified that last-wins is an intentional choice (preserves the most recently added declaration), not a claim to match Maven 3's first-wins dependency resolution. Also noted that last-wins does match Maven 3's plugin configuration merging behavior.

  2. CommonsCliUpgradeOptions parse() retry loop — Acknowledged; no change needed since behavior degrades gracefully to an error.

  3. EnforcerVersionRangeStrategy regex scope — Updated the Javadoc to document that the regex intentionally matches any 4.x upper bound (e.g., 4.1, 4.2.1) since all such bounds should be widened.

  4. ResourceFilteringStrategy BINARY_EXTENSIONS — Added 10 missing extensions (png, jpg, jpeg, gif, bmp, tiff, mp3, mp4, p12, pfx) and softened the wording from "comprehensive" to "common" in both the class Javadoc and the field Javadoc.

  5. RepositoryHttpsUpgradeStrategy LinkedHashMap comment — Fixed the misleading comment about prefix length ordering. Now correctly states the purpose is predictable insertion-order iteration.

gnodet added a commit to gnodet/maven that referenced this pull request Jul 10, 2026
PR apache#12454 received a new commit at 23:24Z after our review at 23:02Z
on the same calendar day. The precondition's date-level granularity
missed this because updatedAt was still within the same day as the
review date. Backdated the review entry so it gets picked up.

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

@gnodet gnodet left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review after commit cbdee27

The new commit addresses four of the five findings from the prior review:

  • ✅ Class-level Javadoc corrected to clarify last-wins is intentional (not matching Maven 3 first-wins)
  • ✅ EnforcerVersionRangeStrategy docs updated to document regex matching
  • ✅ BINARY_EXTENSIONS expanded from 23 to 33 entries with softened wording
  • ✅ LinkedHashMap comment fixed in RepositoryHttpsUpgradeStrategy

Remaining issue

Low — Javadoc inconsistency in DeduplicateDependenciesStrategy

The class-level Javadoc was correctly updated to say:

"Maven 3's dependency resolver uses first-wins for same-depth conflicts; last-wins is chosen here intentionally"

But the method-level Javadoc for fixDuplicateDependenciesInSection (~line 183) still says:

"matching Maven 3's runtime behavior"

These contradict each other. Suggest changing the method Javadoc to just say "last-wins" without referencing Maven 3 behavior.


This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Claude Code on behalf of Guillaume Nodet

gnodet added a commit to gnodet/maven that referenced this pull request Jul 10, 2026
Reviewed 3 PRs: apache#12454 (re-review), apache#11502 (new), apache#11405 (new).
Added 2 new dependabot PRs to skip list.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant