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/30 18:41:17 UTC

(maven) 01/01: Fix #12774: skip consumer POM re-attachment on repeated task segments (#12916)

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

gnodet pushed a commit to branch fix/12774-forward-port
in repository https://gitbox.apache.org/repos/asf/maven.git

commit fcca7d6d0abba82226d5c906c6a6f3e466ebe3c3
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Sun Aug 30 20:39:19 2026 +0200

    Fix #12774: skip consumer POM re-attachment on repeated task segments (#12916)
    
    * Fix #12774: skip consumer POM re-attachment on repeated task segments
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
    
    * Hoist alreadyAttached check before temp file creation
    
    Avoid unnecessary I/O on repeated invocations by checking whether
    the consumer POM is already attached before creating a temp file
    and registering it for deferred deletion.
    
    Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
    
    ---------
    
    Co-authored-by: Claude Opus 4.6 <no...@anthropic.com>
---
 .../impl/ConsumerPomArtifactTransformer.java       | 25 ++++++++-----
 .../impl/ConsumerPomArtifactTransformerTest.java   | 43 ++++++++++++++++++++++
 2 files changed, 58 insertions(+), 10 deletions(-)

diff --git a/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformer.java b/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformer.java
index f32c962886..bfb69d22df 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformer.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformer.java
@@ -79,17 +79,22 @@ public void injectTransformedArtifacts(RepositorySystemSession session, MavenPro
             return;
         }
         if (Features.consumerPom(session.getConfigProperties())) {
-            Path buildDir =
-                    project.getBuild() != null ? Paths.get(project.getBuild().getDirectory()) : null;
-            if (buildDir != null) {
-                Files.createDirectories(buildDir);
-            }
-            Path consumer = buildDir != null
-                    ? Files.createTempFile(buildDir, CONSUMER_POM_CLASSIFIER + "-", ".pom")
-                    : Files.createTempFile(CONSUMER_POM_CLASSIFIER + "-", ".pom");
-            deferDeleteFile(consumer);
+            boolean alreadyAttached = project.getAttachedArtifacts().stream()
+                    .anyMatch(a -> CONSUMER_POM_CLASSIFIER.equals(a.getClassifier()) && "pom".equals(a.getType()));
+            if (!alreadyAttached) {
+                Path buildDir = project.getBuild() != null
+                        ? Paths.get(project.getBuild().getDirectory())
+                        : null;
+                if (buildDir != null) {
+                    Files.createDirectories(buildDir);
+                }
+                Path consumer = buildDir != null
+                        ? Files.createTempFile(buildDir, CONSUMER_POM_CLASSIFIER + "-", ".pom")
+                        : Files.createTempFile(CONSUMER_POM_CLASSIFIER + "-", ".pom");
+                deferDeleteFile(consumer);
 
-            project.addAttachedArtifact(createConsumerPomArtifact(project, consumer, session));
+                project.addAttachedArtifact(createConsumerPomArtifact(project, consumer, session));
+            }
         } else if (project.getModel().getDelegate().isRoot()) {
             throw new IllegalStateException(
                     "The use of the root attribute on the model requires the buildconsumer feature to be active");
diff --git a/impl/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformerTest.java b/impl/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformerTest.java
index 81870abd0f..5efc02883a 100644
--- a/impl/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformerTest.java
+++ b/impl/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformerTest.java
@@ -29,6 +29,7 @@
 
 import org.apache.maven.api.Constants;
 import org.apache.maven.api.services.Sources;
+import org.apache.maven.model.Build;
 import org.apache.maven.model.Model;
 import org.apache.maven.model.v4.MavenStaxReader;
 import org.apache.maven.project.MavenProject;
@@ -39,6 +40,7 @@
 import org.eclipse.aether.deployment.DeployRequest;
 import org.eclipse.aether.installation.InstallRequest;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
 import org.mockito.Mockito;
 import org.xmlunit.builder.DiffBuilder;
 import org.xmlunit.diff.Diff;
@@ -279,4 +281,45 @@ private DeployRequest createDeployRequestWithoutConsumerPom() {
         request.setArtifacts(artifacts);
         return request;
     }
+
+    @Test
+    void injectTransformedArtifactsTwiceShouldNotDuplicate(@TempDir Path tempDir) throws IOException {
+        // Set up a minimal POM file
+        Path pomFile = tempDir.resolve("pom.xml");
+        Files.writeString(
+                pomFile,
+                "<project><modelVersion>4.0.0</modelVersion>"
+                        + "<groupId>test</groupId><artifactId>test</artifactId>"
+                        + "<version>1.0</version></project>");
+
+        // Create project with the POM file and a build directory
+        Model model = new Model();
+        model.setGroupId("test");
+        model.setArtifactId("test");
+        model.setVersion("1.0");
+        Build build = new Build();
+        build.setDirectory(tempDir.resolve("target").toString());
+        model.setBuild(build);
+        MavenProject project = new MavenProject(model);
+        project.setFile(pomFile.toFile());
+
+        // Mock session with consumer POM feature enabled (default for Maven 4)
+        RepositorySystemSession session = Mockito.mock(RepositorySystemSession.class);
+        SessionData sessionData = Mockito.mock(SessionData.class);
+        when(session.getData()).thenReturn(sessionData);
+        when(session.getConfigProperties()).thenReturn(Map.of());
+
+        ConsumerPomArtifactTransformer transformer =
+                new ConsumerPomArtifactTransformer((s, p, src) -> p.getModel().getDelegate());
+
+        // First invocation should attach the consumer POM
+        transformer.injectTransformedArtifacts(session, project);
+        assertEquals(1, project.getAttachedArtifacts().size());
+        assertEquals("consumer", project.getAttachedArtifacts().get(0).getClassifier());
+        assertEquals("pom", project.getAttachedArtifacts().get(0).getType());
+
+        // Second invocation should be a no-op (not duplicate the artifact)
+        transformer.injectTransformedArtifacts(session, project);
+        assertEquals(1, project.getAttachedArtifacts().size());
+    }
 }