Skip to content

[#12288] Pass settings.xml profile properties to LRM#12291

Closed
ascheman wants to merge 2 commits into
apache:masterfrom
aschemaven:gh-12288-lrm-profile-properties
Closed

[#12288] Pass settings.xml profile properties to LRM#12291
ascheman wants to merge 2 commits into
apache:masterfrom
aschemaven:gh-12288-lrm-profile-properties

Conversation

@ascheman

Copy link
Copy Markdown
Contributor

Fixes #12288.

Profiles activated through settings.xml (<activeProfiles> or
<activation><activeByDefault>true</activeByDefault>) had their
<properties> block dropped before the resolver session was built, so
aether.* configuration declared in such a profile silently failed.
The same <properties> on the same <profile> worked when activated
via CLI -P.

Changes

  1. Two ITs in core-it-suite covering both settings.xml activation
    channels — testActiveByDefaultProfile (red on master) and
    testActiveProfilesList (green on master, regression guard).
  2. DefaultRepositorySystemSessionFactory#getPropertiesFromRequestedProfiles
    extended to also consider request.getActiveProfiles() and
    <activeByDefault>true</activeByDefault> profiles.

Locally verified against the core-it-suite:

  • master + new ITs: 1 of 2 fail (testActiveByDefaultProfile)
  • master + new ITs + fix: 2 of 2 pass

Scope

Only the profile's <properties> block is affected — other profile
content (<plugins>, <dependencies>, <repositories>, …) flows
through its existing channels unchanged.

Limitation: this does not re-implement the full DefaultProfileSelector
semantics (e.g. activeByDefault deactivation when other profiles of
the same source are active). For the property-propagation use case in
scope of #12288 this is sufficient; injecting ProfileSelector here
would be a larger refactor in a session-build hot path and is left to a
follow-up if needed.

Affected versions

Reproduces on Maven 4.x master and on Maven 3.9.16; backport candidate.

Test plan

  • mvn install on apache-maven from the branch builds cleanly
  • mvn verify -Prun-its -DmavenDistro=… -Dit.test=MavenITSettingsProfileAetherPropertiesTest on the patched dist: both ITs green
  • Same command on vanilla master dist: testActiveByDefaultProfile red, testActiveProfilesList green
  • core-it-suite full run (not done locally — CI takes it from here)

ascheman added 2 commits June 17, 2026 12:28
Adds two integration tests asserting that <properties> declared in
a settings.xml <profile> reach the resolver session config before
the LocalRepositoryManager is initialized.

The fixtures use aether.enhancedLocalRepository.{split,localPrefix}
because those have an observable effect on the install path, but the
propagation gap covered by the tests applies to any profile property.
Only the profile's <properties> block is consumed; the profile's
<plugins>, <dependencies>, <repositories>, etc. are not in scope here.

Both settings.xml-only activation channels are covered:
* testActiveByDefaultProfile -- <activation><activeByDefault>true</...
* testActiveProfilesList     -- <activeProfiles><activeProfile>...

On unmodified master, testActiveByDefaultProfile is RED (the bug) and
testActiveProfilesList is GREEN (acts as a regression guard for the
channel that already propagates correctly).
DefaultRepositorySystemSessionFactory#getPropertiesFromRequestedProfiles
previously only considered CLI-activated profile ids (-P). Profiles
activated through settings.xml (<activeProfiles> or <activeByDefault>)
were filtered out, so any <properties> they declared were dropped
before the resolver session was built. aether.* configuration was the
most visible casualty (LRM split/localPrefix etc.), but the gap
affects every property declared in such a profile.

The fix only touches profile <properties>; other profile content
(<plugins>, <dependencies>, <repositories>, ...) is unchanged and
keeps flowing through its existing project/build channels.

Extend the active-profile-id set with request.getActiveProfiles() and
add an isActiveByDefault() branch to the filter.

Note: this does not re-implement the full DefaultProfileSelector
semantics (e.g. activeByDefault deactivation when other profiles of
the same source are active). For the property-propagation use case in
scope of apache#12288 this is sufficient; injecting ProfileSelector here
would be a larger refactor in a session-build hot path and is left to
a follow-up if needed.

@gnodet gnodet 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.

Thank you for this well-documented PR, @ascheman — the bug report and reproducer are thorough, and the fix targets the right method.

Two issues to address, one correctness gap and one redundancy:

  1. Missing deactivation check: The activeByDefault branch doesn't exclude profiles explicitly deactivated via -P !profileId. A user running mvn -P !aether-split-via-settings would expect the profile to be deactivated, but the current code still includes its properties.

  2. Redundant request.getActiveProfiles() call: request.getActiveProfiles() returns the exact union of getRequiredActiveProfileIds() + getOptionalActiveProfileIds() (already collected above). The settings.xml <activeProfiles> list flows via overwriteActiveProfiles()activateOptionalProfile(), so they're already in getOptionalActiveProfileIds(). The real fix is the activeByDefault check — the getActiveProfiles() line adds nothing.

See inline suggestions for concrete fixes.

Note: this review does not replace specialized AI review tools (CodeRabbit, Sourcery) or static analysis (SonarCloud).

Fully automatic review from Claude Code

Comment on lines +436 to +439
// Also include profiles activated via settings.xml <activeProfiles> so that their
// properties (notably aether.* configuration) reach the resolver session config in
// time for LocalRepositoryManager initialization.
activeProfileId.addAll(request.getActiveProfiles());

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.

request.getActiveProfiles() delegates to profileActivation.getActiveProfiles(), which returns all IDs where active() == true — the exact union of getRequiredActiveProfileIds() + getOptionalActiveProfileIds() already collected above. The settings.xml <activeProfiles> list is wired via overwriteActiveProfiles()activateOptionalProfile(), so those IDs are already in getOptionalActiveProfileIds().

This block should instead collect inactive profile IDs, so the activeByDefault filter below can respect explicit deactivation (-P !profileId):

Suggested change
// Also include profiles activated via settings.xml <activeProfiles> so that their
// properties (notably aether.* configuration) reach the resolver session config in
// time for LocalRepositoryManager initialization.
activeProfileId.addAll(request.getActiveProfiles());
// Profiles explicitly deactivated via -P !id must be excluded even if they
// declare activeByDefault=true.
HashSet<String> inactiveProfileId =
new HashSet<>(request.getProfileActivation().getRequiredInactiveProfileIds());
inactiveProfileId.addAll(request.getProfileActivation().getOptionalInactiveProfileIds());

Comment on lines +442 to +444
.filter(profile -> activeProfileId.contains(profile.getId())
|| (profile.getActivation() != null
&& profile.getActivation().isActiveByDefault()))

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 activeByDefault branch should exclude profiles that have been explicitly deactivated:

Suggested change
.filter(profile -> activeProfileId.contains(profile.getId())
|| (profile.getActivation() != null
&& profile.getActivation().isActiveByDefault()))
.filter(profile -> activeProfileId.contains(profile.getId())
|| (!inactiveProfileId.contains(profile.getId())
&& profile.getActivation() != null
&& profile.getActivation().isActiveByDefault()))

* settings.xml activation channels fail, which is what these tests guard
* against.
*/
public class MavenITSettingsProfileAetherPropertiesTest extends AbstractMavenIntegrationTestCase {

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.

Nit: other ITs fixing tracked issues typically follow the MavenITgh<number>...Test pattern (e.g. MavenITgh10210SettingsXmlDecryptTest). Consider renaming to MavenITgh12288SettingsProfileAetherPropertiesTest for consistency and traceability.

@ascheman

Copy link
Copy Markdown
Contributor Author

Superseded by #12297 — closing in favor of @gnodet's reroll. Thanks for picking it up and preserving attribution.

@ascheman ascheman closed this Jun 17, 2026
gnodet added a commit that referenced this pull request Jun 17, 2026
Fixes #12288. Supersedes #12291.

Profiles activated through settings.xml (<activeProfiles> or
<activation><activeByDefault>true</activeByDefault>) had their
<properties> block dropped before the resolver session was built, so
aether.* configuration declared in such a profile silently failed.

Changes:
- Collect activeByDefault profiles for property propagation to LRM
- Respect -P !profileId deactivation for activeByDefault profiles
- Add ITs for both settings.xml activation channels

Co-authored-by: Gerd Aschemann <gerd@aschemann.net>
gnodet added a commit that referenced this pull request Jun 18, 2026
…#12299)

Fixes #12288. Supersedes #12291.

Profiles activated through settings.xml (<activeProfiles> or
<activation><activeByDefault>true</activeByDefault>) had their
<properties> block dropped before the resolver session was built, so
aether.* configuration declared in such a profile silently failed.

Changes:
- Collect activeByDefault profiles for property propagation to LRM
- Respect -P !profileId deactivation for activeByDefault profiles
- Add ITs for both settings.xml activation channels

Co-authored-by: Gerd Aschemann <gerd@aschemann.net>
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.

Profile-level properties from a settings.xml-activated profile are dropped before LRM init

2 participants