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/10/15 07:15:57 UTC
(maven) branch master updated: Fix #10375: activate parent file profiles with the parent's properties
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/master by this push:
new ce26838575 Fix #10375: activate parent file profiles with the parent's properties
ce26838575 is described below
commit ce26838575407bc4a784dee58ebb5d65bcf639f2
Author: Mathias Nicolajsen Kjærgaard <mn...@mnk.dk>
AuthorDate: Thu Oct 15 09:15:50 2026 +0200
Fix #10375: activate parent file profiles with the parent's properties
When reading a parent for a child, ParentModelFrame activated the parent's profiles against a context derived from the child's pre-inheritance model. That model has the right basedir for per-module file checks but lacks the parent's properties, so property placeholders (e.g. ${message.file}) did not interpolate and the profile stayed inactive.
- Activate parent profiles in a fresh recording context (new DefaultProfileActivationContext.start(Map)) whose model properties are those of the assembled parent, keeping the child's basedir, packaging and artifactId
- The recording context also serves as the parent-model cache key, so it is not mutated in place with setModel(parent) to avoid stale cache hits across grandparent records
- Add a new replayRecordIntoContext overload that replays the activation record without model properties, so parent-derived values don't pollute child lookups
- Add DefaultModelBuilderTest case and core IT MavenITmng8710
Fixes https://github.com/apache/maven/issues/10375 (MNG-8710)
---
.../maven/impl/model/DefaultModelBuilder.java | 17 ++++-
.../model/DefaultProfileActivationContext.java | 17 +++++
.../maven/impl/model/DefaultModelBuilderTest.java | 25 +++++++
.../poms/factory/mng-8710/activate.marker | 0
.../poms/factory/mng-8710/child/activate.marker | 0
.../resources/poms/factory/mng-8710/child/pom.xml | 10 +++
.../test/resources/poms/factory/mng-8710/pom.xml | 27 ++++++++
...enITmng8710ParentFileProfileActivationTest.java | 52 +++++++++++++++
.../src/test/resources/mng-8710/my-lib/pom.xml | 30 +++++++++
.../src/test/resources/mng-8710/my-lib/test.txt | 1 +
.../src/test/resources/mng-8710/pom.xml | 78 ++++++++++++++++++++++
.../src/test/resources/mng-8710/test.txt | 1 +
12 files changed, 256 insertions(+), 2 deletions(-)
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java
index 5a8f6fd165..c816d33cd4 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelBuilder.java
@@ -2523,7 +2523,11 @@ ParentFrame advance(Set<ModelSource> activeSources, Set<ResolvedParentKey> activ
phase = ParentModelPhase.MERGE_MIXIN;
return new ParentResolutionFrame(model, mixins.next(), recording, chain, false, false);
}
- List<Profile> profiles = getActiveProfiles(model.getProfiles(), recording);
+ // Evaluate with the parent's properties but the child's basedir (as Maven 3 does);
+ // parent properties are kept out of the cache key since they derive from the source.
+ DefaultProfileActivationContext activation = recording.start(model.getProperties());
+ List<Profile> profiles = getActiveProfiles(model.getProfiles(), activation);
+ replayRecordIntoContext(activation.stop(), recording, false);
model = profileInjector
.injectProfiles(model, profiles, request, ModelBuilderSessionState.this)
.withProfiles(List.of())
@@ -3001,6 +3005,13 @@ boolean isBuildRequestWithActivation() {
*/
private void replayRecordIntoContext(
DefaultProfileActivationContext.Record cachedRecord, DefaultProfileActivationContext targetContext) {
+ replayRecordIntoContext(cachedRecord, targetContext, true);
+ }
+
+ private void replayRecordIntoContext(
+ DefaultProfileActivationContext.Record cachedRecord,
+ DefaultProfileActivationContext targetContext,
+ boolean includeModelProperties) {
if (targetContext.record == null) {
return; // Target context is not recording
}
@@ -3022,7 +3033,9 @@ private void replayRecordIntoContext(
cachedRecord.usedUserProperties.forEach(targetRecord.usedUserProperties::putIfAbsent);
// Replay model properties
- cachedRecord.usedModelProperties.forEach(targetRecord.usedModelProperties::putIfAbsent);
+ if (includeModelProperties) {
+ cachedRecord.usedModelProperties.forEach(targetRecord.usedModelProperties::putIfAbsent);
+ }
// Replay model infos
cachedRecord.usedModelInfos.forEach(targetRecord.usedModelInfos::putIfAbsent);
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 7a4ccd7850..895d0b45b2 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
@@ -226,6 +226,23 @@ DefaultProfileActivationContext start() {
new Record());
}
+ /**
+ * Like {@link #start()}, but overrides the model's properties with the given map.
+ * The model's other attributes (basedir, packaging, artifactId) are preserved
+ * so that file-exists profile conditions resolve against the original project directory.
+ */
+ DefaultProfileActivationContext start(Map<String, String> modelProperties) {
+ return new DefaultProfileActivationContext(
+ rootLocator,
+ interpolator,
+ activeProfileIds,
+ inactiveProfileIds,
+ systemProperties,
+ userProperties,
+ model != null ? model.withProperties(modelProperties) : null,
+ new Record());
+ }
+
Record stop() {
Objects.requireNonNull(record, "start() must be called before stop()");
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 9a5af0e462..ce11369b31 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
@@ -1739,6 +1739,31 @@ void testBomImportWarningFromNonReactorParentIsPreserved() {
}
}
+ @Test
+ void testMng8710ParentFileProfileWithPropertyActivationAppliesToChild() {
+ Path pom = Paths.get("src/test/resources/poms/factory/mng-8710/pom.xml").toAbsolutePath();
+ ModelBuilderResult result = builder.newSession()
+ .build(ModelBuilderRequest.builder()
+ .session(session)
+ .requestType(ModelBuilderRequest.RequestType.BUILD_PROJECT)
+ .recursive(true)
+ .source(Sources.buildSource(pom))
+ .build());
+
+ Model parentModel = result.getEffectiveModel();
+ assertEquals("activated", parentModel.getProperties().get("profile.from.parent"));
+
+ ModelBuilderResult childResult = result.getChildren().stream()
+ .filter(r -> "mng-8710-child".equals(r.getEffectiveModel().getArtifactId()))
+ .findFirst()
+ .orElseThrow(() -> new AssertionError("child result missing: " + result.getChildren()));
+ Model childModel = childResult.getEffectiveModel();
+ assertEquals(
+ "activated",
+ childModel.getProperties().get("profile.from.parent"),
+ "Parent file profile interpolating ${message.file} must inject into child (MNG-8710)");
+ }
+
@Test
void testBomImportWarningFromParentProfileActivatedForChild() {
Path pom = Paths.get("src/test/resources/poms/factory/mng-8450-profile-context/pom.xml")
diff --git a/impl/maven-impl/src/test/resources/poms/factory/mng-8710/activate.marker b/impl/maven-impl/src/test/resources/poms/factory/mng-8710/activate.marker
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/impl/maven-impl/src/test/resources/poms/factory/mng-8710/child/activate.marker b/impl/maven-impl/src/test/resources/poms/factory/mng-8710/child/activate.marker
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/impl/maven-impl/src/test/resources/poms/factory/mng-8710/child/pom.xml b/impl/maven-impl/src/test/resources/poms/factory/mng-8710/child/pom.xml
new file mode 100644
index 0000000000..f3c51cb7a6
--- /dev/null
+++ b/impl/maven-impl/src/test/resources/poms/factory/mng-8710/child/pom.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.maven.test</groupId>
+ <artifactId>mng-8710-parent</artifactId>
+ <version>1.0.0</version>
+ </parent>
+ <artifactId>mng-8710-child</artifactId>
+</project>
diff --git a/impl/maven-impl/src/test/resources/poms/factory/mng-8710/pom.xml b/impl/maven-impl/src/test/resources/poms/factory/mng-8710/pom.xml
new file mode 100644
index 0000000000..c6f6fda833
--- /dev/null
+++ b/impl/maven-impl/src/test/resources/poms/factory/mng-8710/pom.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>org.apache.maven.test</groupId>
+ <artifactId>mng-8710-parent</artifactId>
+ <version>1.0.0</version>
+ <packaging>pom</packaging>
+ <properties>
+ <message.file>activate.marker</message.file>
+ </properties>
+ <modules>
+ <module>child</module>
+ </modules>
+ <profiles>
+ <profile>
+ <id>file-from-parent</id>
+ <activation>
+ <file>
+ <exists>${message.file}</exists>
+ </file>
+ </activation>
+ <properties>
+ <profile.from.parent>activated</profile.from.parent>
+ </properties>
+ </profile>
+ </profiles>
+</project>
diff --git a/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8710ParentFileProfileActivationTest.java b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8710ParentFileProfileActivationTest.java
new file mode 100644
index 0000000000..cf5ab199e0
--- /dev/null
+++ b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITmng8710ParentFileProfileActivationTest.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.it;
+
+import java.nio.file.Path;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * This is a test set for <a href="https://issues.apache.org/jira/browse/MNG-8710">MNG-8710</a>.
+ *
+ * A file-based profile defined in a parent POM that interpolates a parent property in
+ * {@code <exists>} must activate for child modules (using each child's basedir) and inject
+ * the profile's build plugins into the child's effective model.
+ */
+class MavenITmng8710ParentFileProfileActivationTest extends AbstractMavenIntegrationTestCase {
+
+ @Test
+ void testParentFileProfileAppliesToChild() throws Exception {
+ Path testDir = extractResources("mng-8710");
+
+ Verifier verifier = newVerifier(testDir);
+ verifier.setAutoclean(false);
+ verifier.deleteDirectory("target");
+ verifier.deleteDirectory("my-lib/target");
+ verifier.addCliArgument("validate");
+ verifier.execute();
+ verifier.verifyErrorFreeLog();
+
+ verifier.verifyFilePresent("target/profile-activated.txt");
+ verifier.verifyFilePresent("my-lib/target/profile-activated.txt");
+
+ verifier.verifyTextInLog("Profile activated in my-app: Test 1");
+ verifier.verifyTextInLog("Profile activated in my-lib: Test 2");
+ }
+}
diff --git a/its/core-it-suite/src/test/resources/mng-8710/my-lib/pom.xml b/its/core-it-suite/src/test/resources/mng-8710/my-lib/pom.xml
new file mode 100644
index 0000000000..3742ae094a
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-8710/my-lib/pom.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://maven.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.maven.its.mng8710</groupId>
+ <artifactId>my-app</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>my-lib</artifactId>
+</project>
diff --git a/its/core-it-suite/src/test/resources/mng-8710/my-lib/test.txt b/its/core-it-suite/src/test/resources/mng-8710/my-lib/test.txt
new file mode 100644
index 0000000000..110c58e6f3
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-8710/my-lib/test.txt
@@ -0,0 +1 @@
+Test 2
diff --git a/its/core-it-suite/src/test/resources/mng-8710/pom.xml b/its/core-it-suite/src/test/resources/mng-8710/pom.xml
new file mode 100644
index 0000000000..b1f551a16e
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-8710/pom.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.maven.its.mng8710</groupId>
+ <artifactId>my-app</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ <packaging>pom</packaging>
+
+ <name>Maven Integration Test :: MNG-8710 :: Parent</name>
+ <description>Parent file-based profile with property interpolation must apply to children</description>
+
+ <properties>
+ <message.file>test.txt</message.file>
+ </properties>
+
+ <modules>
+ <module>my-lib</module>
+ </modules>
+
+ <profiles>
+ <profile>
+ <id>test</id>
+ <activation>
+ <file>
+ <exists>${message.file}</exists>
+ </file>
+ </activation>
+ <properties>
+ <profile.activated>true</profile.activated>
+ </properties>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <version>3.1.0</version>
+ <executions>
+ <execution>
+ <id>echo-profile</id>
+ <phase>validate</phase>
+ <configuration>
+ <target>
+ <loadfile property="message" srcFile="${message.file}"/>
+ <echo>Profile activated in ${project.artifactId}: ${message}</echo>
+ <mkdir dir="${project.build.directory}"/>
+ <touch file="${project.build.directory}/profile-activated.txt"/>
+ </target>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/its/core-it-suite/src/test/resources/mng-8710/test.txt b/its/core-it-suite/src/test/resources/mng-8710/test.txt
new file mode 100644
index 0000000000..ac5ab8fbdb
--- /dev/null
+++ b/its/core-it-suite/src/test/resources/mng-8710/test.txt
@@ -0,0 +1 @@
+Test 1