From 3665afc30ac68606725e9c373c7247eba45b5b55 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Sat, 29 Aug 2026 15:19:22 +0200 Subject: [PATCH 1/2] Fix #12774: skip consumer POM re-attachment on repeated task segments Co-Authored-By: Claude Opus 4.6 --- .../impl/ConsumerPomArtifactTransformer.java | 6 ++- .../ConsumerPomArtifactTransformerTest.java | 44 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) 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 9d96e800eaf0..26194588d287 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 @@ -89,7 +89,11 @@ public void injectTransformedArtifacts(RepositorySystemSession session, MavenPro : Files.createTempFile(CONSUMER_POM_CLASSIFIER + "-", ".pom"); deferDeleteFile(consumer); - project.addAttachedArtifact(createConsumerPomArtifact(project, consumer, session)); + boolean alreadyAttached = project.getAttachedArtifacts().stream() + .anyMatch(a -> CONSUMER_POM_CLASSIFIER.equals(a.getClassifier()) && "pom".equals(a.getType())); + if (!alreadyAttached) { + 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 4bdc242e01c9..102909a39564 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 @@ -23,14 +23,17 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Collections; 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; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.SessionData; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import org.mockito.Mockito; import org.xmlunit.assertj.XmlAssert; @@ -106,4 +109,45 @@ void injectTransformedArtifactsWithoutPomShouldNotInjectAnyArtifacts() throws IO assertThat(emptyProject.getAttachedArtifacts()).isEmpty(); } + + @Test + void injectTransformedArtifactsTwiceShouldNotDuplicate(@TempDir Path tempDir) throws IOException { + // Set up a minimal POM file + Path pomFile = tempDir.resolve("pom.xml"); + Files.writeString( + pomFile, + "4.0.0" + + "testtest" + + "1.0"); + + // 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(Collections.emptyMap()); + + ConsumerPomArtifactTransformer transformer = + new ConsumerPomArtifactTransformer((s, p, src) -> p.getModel().getDelegate()); + + // First invocation should attach the consumer POM + transformer.injectTransformedArtifacts(session, project); + assertThat(project.getAttachedArtifacts()).hasSize(1); + assertThat(project.getAttachedArtifacts().get(0).getClassifier()).isEqualTo("consumer"); + assertThat(project.getAttachedArtifacts().get(0).getType()).isEqualTo("pom"); + + // Second invocation should be a no-op (not duplicate the artifact) + transformer.injectTransformedArtifacts(session, project); + assertThat(project.getAttachedArtifacts()).hasSize(1); + } } From 9515783100d08ea3c04683dd8d21d8b7fdfcda87 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Sun, 30 Aug 2026 16:46:03 +0200 Subject: [PATCH 2/2] 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 --- .../impl/ConsumerPomArtifactTransformer.java | 21 ++++++++++--------- 1 file changed, 11 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 26194588d287..1ef72c58f3fe 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,19 +79,20 @@ 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)); } } else if (project.getModel().getDelegate().isRoot()) {