gnodet commented on code in PR #12744:
URL: https://github.com/apache/maven/pull/12744#discussion_r3841054801


##########
impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java:
##########
@@ -451,6 +459,127 @@ private static void warnNotDowngraded(MavenProject 
project) {
                 + "attribute on the <project> element of your POM.");
     }
 
+    /**
+     * Inlines packaging-activated profiles into the model.
+     * <p>
+     * When a profile is activated by packaging and the packaging matches the 
project's packaging,
+     * the profile's content (dependencies, dependency management, 
repositories) is merged into
+     * the main model and the profile is removed. This ensures consistent 
behavior across all
+     * tools consuming the POM, since packaging activation is a 4.1.0+ feature 
not available
+     * in Maven 3 or other tools like Gradle.
+     * <p>
+     * If the profile has other activation conditions besides packaging, only 
the packaging
+     * part is stripped from the activation; the profile's content is 
<b>not</b> inlined to
+     * preserve AND semantics (the content remains gated by the remaining 
conditions).
+     * <p>
+     * Profiles with a non-matching packaging activation are dropped entirely, 
since they
+     * can never activate for this artifact's fixed packaging and their 
presence would block
+     * model version downgrade to 4.0.0.
+     * <p>
+     * Non-transitive scope dependencies (test, provided, system) from inlined 
profiles are
+     * filtered out to prevent leakage into the consumer POM.
+     *
+     * @param model the model to process
+     * @param packaging the project's packaging type
+     * @return the model with packaging-activated profiles inlined
+     */
+    static Model inlinePackagingActivatedProfiles(Model model, String 
packaging) {
+        List<Profile> remainingProfiles = new ArrayList<>();
+        List<Dependency> additionalDeps = new ArrayList<>();
+        List<Dependency> additionalManagedDeps = new ArrayList<>();
+        List<Repository> additionalRepos = new ArrayList<>();
+
+        for (Profile profile : model.getProfiles()) {
+            Activation activation = profile.getActivation();
+            if (activation != null && activation.getPackaging() != null) {
+                if (Objects.equals(activation.getPackaging(), packaging)) {
+                    Activation strippedActivation = 
stripPackagingActivation(activation);
+                    if (strippedActivation != null) {
+                        // Keep the profile but remove the packaging 
activation part
+                        // Do not inline its contents since it has other 
activation conditions
+                        
remainingProfiles.add(profile.withActivation(strippedActivation));
+                    } else {
+                        // Packaging is the ONLY condition.
+                        // Inline profile content into the model
+                        additionalDeps.addAll(profile.getDependencies());
+                        if (profile.getDependencyManagement() != null) {
+                            additionalManagedDeps.addAll(
+                                    
profile.getDependencyManagement().getDependencies());
+                        }
+                        additionalRepos.addAll(profile.getRepositories());
+                    }
+                } else {
+                    // Packaging does not match — drop the profile entirely
+                }
+            } else {
+                // No packaging activation — keep the profile as-is
+                remainingProfiles.add(profile);
+            }
+        }
+
+        // Merge additional dependencies into the model, deduplicating by key
+        if (!additionalDeps.isEmpty()) {
+            
additionalDeps.removeIf(DefaultConsumerPomBuilder::hasDependencyScope);
+            Map<String, Dependency> mergedDeps = new LinkedHashMap<>();
+            for (Dependency dep : model.getDependencies()) {
+                mergedDeps.put(getDependencyKey(dep), dep);
+            }
+            for (Dependency dep : additionalDeps) {
+                mergedDeps.putIfAbsent(getDependencyKey(dep), dep);
+            }
+            model = model.withDependencies(mergedDeps.values());

Review Comment:
   Minor: managed dependencies inlined from profiles are not filtered for 
`import` scope. In `buildEffectiveModel` (line ~232), managed deps with 
`scope=import` are explicitly filtered out. But 
`inlinePackagingActivatedProfiles` adds profile managed deps via `putIfAbsent` 
without this filter.
   
   Since `transformNonPom` receives the effective model (where import-scoped 
managed deps were already filtered by `buildEffectiveModel`), profiles still 
retain their original declarations, and `putIfAbsent` could re-add 
import-scoped managed deps that were previously filtered. This is an edge case 
(requires BOM imports inside a packaging-activated profile) but represents a 
gap in the filtering logic.



##########
impl/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java:
##########
@@ -135,6 +153,62 @@ void testTrivialConsumer() throws Exception {
         assertNotNull(model.getDependencies());
     }
 
+    @Test
+    void testPackagingActivatedProfiles() throws Exception {
+        setRootDirectory("packaging-profiles");
+        Path file = 
Paths.get("src/test/resources/consumer/packaging-profiles/pom.xml");
+
+        MavenProject project = getEffectiveModel(file);
+
+        Model model = 
DefaultConsumerPomBuilder.transformNonPom(getConsumerModel(file, false), 
project);
+
+        assertNotNull(model);
+
+        assertEquals(1, model.getProfiles().size());
+        org.apache.maven.api.model.Profile mixedProfile = 
model.getProfiles().get(0);
+        assertEquals("mixed-profile", mixedProfile.getId());
+        assertNotNull(mixedProfile.getActivation());
+        assertNull(mixedProfile.getActivation().getPackaging());
+        assertNotNull(mixedProfile.getActivation().getProperty());
+        assertEquals("foo", 
mixedProfile.getActivation().getProperty().getName());
+
+        assertNotNull(model.getDependencies());
+        assertEquals(1, model.getDependencies().size());
+        assertEquals("slf4j-api", 
model.getDependencies().get(0).getArtifactId());
+    }
+
+    @Test
+    void testParentPomPackagingActivatedProfilesArePreserved() throws 
Exception {
+        setRootDirectory("packaging-parent-profiles");

Review Comment:
   Missing test resource file: `testBomPackagingActivatedProfilesArePreserved` 
references `src/test/resources/consumer/packaging-bom-profiles/pom.xml` but 
this file is not included in the PR. Only `packaging-profiles/pom.xml` and 
`packaging-parent-profiles/pom.xml` were added. This test will fail at runtime 
with a file-not-found error.
   
   A BOM-style POM (packaging=pom with dependencyManagement in profiles) needs 
to be created at the referenced path.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to