You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2026/08/24 06:18:48 UTC

(maven) branch maven-4.0.x updated: [backport maven-4.0.x] Fix parent profile cache matching across activation contexts

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch maven-4.0.x
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/maven-4.0.x by this push:
     new d208ca5be4 [backport maven-4.0.x] Fix parent profile cache matching across activation contexts
d208ca5be4 is described below

commit d208ca5be40e947ac8d0455f0ec71bac310f9c51
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Mon Aug 24 08:18:42 2026 +0200

    [backport maven-4.0.x] Fix parent profile cache matching across activation contexts
    
    Keep every explicitly consulted profile state in
    DefaultProfileActivationContext.Record, including values that evaluate
    to false. This prevents an assembled parent model from being reused
    when a later module has a different -Pprofile or -!profile context.
    
    Add focused regression tests for both active-profile and
    inactive-profile cache matching.
    
    Backport of #12762.
    Original author: @ulofiai
    
    Closes #12801
---
 .../model/DefaultProfileActivationContext.java     |  3 --
 .../maven/impl/model/DefaultModelBuilderTest.java  | 43 ++++++++++++++++++++++
 2 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultProfileActivationContext.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultProfileActivationContext.java
index 9d9ba94546..0fa7765d14 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultProfileActivationContext.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultProfileActivationContext.java
@@ -237,10 +237,7 @@ DefaultProfileActivationContext start() {
     }
 
     Record stop() {
-        // only keep keys for which the value is `true`
         Objects.requireNonNull(record, "start() must be called before stop()");
-        record.usedActiveProfiles.values().removeIf(value -> !value);
-        record.usedInactiveProfiles.values().removeIf(value -> !value);
         return new Record(record); // Return immutable copy for thread-safe caching
     }
 
diff --git a/impl/maven-impl/src/test/java/org/apache/maven/impl/model/DefaultModelBuilderTest.java b/impl/maven-impl/src/test/java/org/apache/maven/impl/model/DefaultModelBuilderTest.java
index 29689184c8..65c8887ee2 100644
--- a/impl/maven-impl/src/test/java/org/apache/maven/impl/model/DefaultModelBuilderTest.java
+++ b/impl/maven-impl/src/test/java/org/apache/maven/impl/model/DefaultModelBuilderTest.java
@@ -42,6 +42,7 @@
 
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -61,6 +62,34 @@ void setup() {
         assertNotNull(builder);
     }
 
+    @Test
+    public void testParentProfileCacheDistinguishesActiveProfileContexts() {
+        DefaultProfileActivationContext.Record withoutRelease = recordActiveProfile(List.of(), "release");
+        DefaultProfileActivationContext.Record withRelease = recordActiveProfile(List.of("release"), "release");
+
+        assertFalse(
+                withoutRelease.matches(newProfileActivationContext(List.of("release"), List.of())),
+                "a parent assembled without -Prelease must not be reused for a module built with -Prelease");
+        assertFalse(
+                withRelease.matches(newProfileActivationContext(List.of(), List.of())),
+                "a parent assembled with -Prelease must not be reused for a module built without it");
+        assertTrue(withoutRelease.matches(newProfileActivationContext(List.of(), List.of())));
+        assertTrue(withRelease.matches(newProfileActivationContext(List.of("release"), List.of())));
+    }
+
+    @Test
+    public void testParentProfileCacheDistinguishesInactiveProfileContexts() {
+        DefaultProfileActivationContext recording =
+                newProfileActivationContext(List.of(), List.of()).start();
+        recording.isProfileInactive("release");
+        DefaultProfileActivationContext.Record withoutSuppression = recording.stop();
+
+        assertFalse(
+                withoutSuppression.matches(newProfileActivationContext(List.of(), List.of("release"))),
+                "a parent assembled without -!release must not be reused for a module built with -!release");
+        assertTrue(withoutSuppression.matches(newProfileActivationContext(List.of(), List.of())));
+    }
+
     @Test
     public void testPropertiesAndProfiles() {
         ModelBuilderRequest request = ModelBuilderRequest.builder()
@@ -518,6 +547,20 @@ public void testBomDependencyManagementVersionInference() {
                 "1.0-SNAPSHOT", managedDep.getVersion(), "Version should be inferred from the reactor sibling module");
     }
 
+    private static DefaultProfileActivationContext.Record recordActiveProfile(
+            List<String> activeIds, String profileId) {
+        DefaultProfileActivationContext recording =
+                newProfileActivationContext(activeIds, List.of()).start();
+        recording.isProfileActive(profileId);
+        return recording.stop();
+    }
+
+    private static DefaultProfileActivationContext newProfileActivationContext(
+            List<String> activeIds, List<String> inactiveIds) {
+        return new DefaultProfileActivationContext(
+                null, null, null, activeIds, inactiveIds, Map.of(), Map.of(), Model.newInstance());
+    }
+
     private Path getPom(String name) {
         return Paths.get("src/test/resources/poms/factory/" + name + ".xml").toAbsolutePath();
     }