Visitar URL original
Fix glob patterns in exists()/missing() profile conditions on Windows by Dev-next-gen · Pull Request #13160 · apache/maven · GitHub
Skip to content

Fix glob patterns in exists()/missing() profile conditions on Windows - #13160

Merged
gnodet merged 1 commit into
apache:masterfrom
Dev-next-gen:condition-exists-glob-windows
Sep 17, 2026
Merged

gnodet merged 1 commit into
apache:masterfrom
Dev-next-gen:condition-exists-glob-windows

Conversation

@Dev-next-gen

Copy link
Copy Markdown
Contributor

The activation/condition docs in maven.mdo give exists('${project.basedir}/src/**/*.xsd') as the file-existence example. On Windows that condition never matches, and a relative pattern like exists('**/*.xsd') fails the profile with an exception.

DefaultProfileActivationContext.doExists ran the whole pattern through interpolatePath(), which aligns it to the project directory, and only then split it into a fixed directory and a glob. On Windows that goes wrong in two ways:

  • For an absolute pattern, alignment turns every / into \, so the glob becomes **\*.xsd. The JDK glob syntax treats \ as an escape character on Windows too (there, / is what matches the separator), so the pattern looks for a literal * and nothing matches. exists() is always false and missing() always true.
  • For a relative pattern, alignment calls basedir.resolve("**\*.xsd"), which throws InvalidPathException: Illegal char <*> at index 0: **\*.xsd because * is not a valid Windows path character. The condition activator reports it as Error invoking function 'exists'.

The fix splits the interpolated pattern first, on either / or \. It then aligns only the fixed part to the base directory and uses / as the separator in the glob. interpolatePath() keeps its behavior; its interpolation step moves into a private interpolate() so doExists can use it before alignment. On Linux and macOS the result is the same as before, since alignment already turned \ into / there.

testFileWilcards in ConditionProfileActivatorTest covers exactly these patterns but has been @Disabled since the condition activator was added. It passes on Linux as is, so I re-enabled it and added two negative assertions (missing(...) on an existing match, exists(...) on a missing one). To check on Windows 11 (JDK 17), I ran the test class against maven-impl classes built from master and from this branch:

before: 35 tests successful, 1 failed
  testFileWilcards => AssertionFailedError: expected: <true> but was: <false>
after:  36 tests successful, 0 failed

FileProfileActivatorTest passes on both. On Linux (JDK 21), all maven-impl tests pass (709 run, 0 failures) and spotless:check is clean.

  • Your pull request should address just one issue, without pulling in other changes.

  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.

  • Each commit in the pull request should have a meaningful subject line and body.

  • Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied.

  • Run mvn verify to make sure basic checks pass.

  • You have run the Core IT successfully.

  • I hereby declare this contribution to be licenced under the Apache License Version 2.0, January 2004

  • In any other case, please file an Apache Individual Contributor License Agreement.

Found by a defect-hunting pipeline I build and run (Dev-next-gen), using Claude Code with Anthropic's Claude Opus 5.

DefaultProfileActivationContext aligned the whole pattern to the project
directory before splitting it into a fixed directory and a glob. On
Windows this breaks both kinds of pattern:

- an absolute pattern such as '${project.basedir}/src/**/*.xsd' leaves a
  glob with backslash separators ('**\*.xsd'), and the glob syntax reads
  '\' as an escape character, so nothing ever matches: exists() is always
  false and missing() always true;
- a relative pattern such as '**/*.xsd' is resolved with Path.resolve(),
  which throws InvalidPathException because '*' is not a valid Windows
  path character.

Split the interpolated pattern first, align only the fixed part, and use
'/' as the separator in the glob. testFileWilcards, disabled since the
condition activator was added, passes on Linux and Windows now and is
enabled again.

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The fix is mechanically correct: splitting the interpolated pattern on '/' and '\' before calling alignToBaseDirectory prevents the path normalizer from turning **/*.xsd into **\*.xsd on Windows (where \ is an escape character in glob syntax, not a separator). The extraction of interpolate() from interpolatePath() preserves the public contract while giving doExists access to the pre-aligned string.

Two points worth addressing:

1. No JIRA issue linked. Maven PRs are expected to reference a MNG-XXXXXX JIRA ticket in the title and body so the fix is traceable in the release notes. Please file an issue at https://issues.apache.org/jira/projects/MNG and update the PR title to [MNG-XXXXXX] Fix glob patterns in exists()/missing() profile conditions on Windows.

2. The mvn verify and Core-IT checkboxes are unchecked. The PR description includes solid evidence that the tests pass on both Linux and Windows, so this looks like a documentation gap rather than a real skip — but the checklist is part of the contribution process. Please check the boxes (or explain why Core ITs were not run, e.g. infrastructure access).

Everything else looks solid. The edge cases (lastSep < 0 → fixed = "" → alignToBaseDirectory("…", basedir) resolves to basedir; trailing-separator fixed normalized by Path.resolve(...).normalize(); glob.replace('\\', '/') ensuring glob-safe separators) all behave correctly on both platforms.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@Dev-next-gen

Copy link
Copy Markdown
Contributor Author

Thank you for the review — the walk through the edge cases (lastSep < 0, the trailing separator, the final replace('\\', '/')) is exactly what I would have wanted checked.

On the JIRA ticket: I cannot file one. ASF Jira no longer accepts self-registration — the login page ends with "Not a member? To request an account, please contact your Jira administrators." and there is no public signup form behind it. So an outside contributor has no way to obtain an MNG number on their own. I am happy to rename the title to [MNG-XXXXXX] Fix glob patterns in exists()/missing() profile conditions on Windows the moment a number exists.

On the two checkboxes: I have left them unchecked because ticking them would claim more than I did. What I ran is in the description — ConditionProfileActivatorTest and FileProfileActivatorTest against maven-impl built from master and from this branch, on Windows 11 with JDK 17 (35 passing and 1 failing before, 36 passing and 0 failing after), and the full maven-impl test module on Linux with JDK 21 (709 tests, 0 failures). What I did not run is mvn verify over the whole reactor, nor the Core ITs, for which I have no environment. I would rather report that than check a box.

If someone with an account files the ticket, or points me to the right person to ask for one, I will update the title straight away — otherwise this is simply where the PR stands.

Found by a defect-hunting pipeline I build and run (Dev-next-gen), using Claude Code with Anthropic's Claude Opus 5.

(@Dev-next-gen)

@gnodet gnodet added bug Something isn't working backport-to-4.0.x labels Sep 17, 2026
@gnodet gnodet added this to the 4.1.0 milestone Sep 17, 2026
@gnodet
gnodet merged commit faddbd3 into apache:master Sep 17, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants