This is an automated email from the ASF dual-hosted git repository. gnodet pushed a commit to branch gh-11772-dual-consumer-pom in repository https://gitbox.apache.org/repos/asf/maven.git
commit 9a6607fca968fe84d39c80e25e2cceb66bdd50ab Author: Guillaume Nodet <[email protected]> AuthorDate: Tue Mar 10 09:24:35 2026 +0100 [GH-11772] Generate dual consumer POMs for parent POMs with 4.1.0 features When a POM-packaged project uses model version 4.1.0 features (e.g., profile condition activation, subprojects), the consumer POM cannot be downgraded to 4.0.0, breaking Maven 3 and Gradle consumers. This fix generates dual consumer POMs: - Main POM (no classifier): 4.0.0-compatible with 4.1.0 features stripped - Consumer POM (classifier): 4.1.0 full-fidelity with parent classifier Changes: - Add classifier field to Parent in maven.mdo (4.1.0+) - DefaultConsumerPomBuilder: add stripTo400() and dual POM generation - ConsumerPomArtifactTransformer: handle consumer-full artifact lifecycle - DefaultModelResolver: pass parent classifier during resolution - DefaultModelBuilder: skip local parent resolution when classifier set Fixes #11772 --- api/maven-api-model/src/main/mdo/maven.mdo | 10 ++ .../impl/ConsumerPomArtifactTransformer.java | 93 +++++++++++++--- .../impl/DefaultConsumerPomBuilder.java | 105 ++++++++++++++++++ .../internal/transformation/impl/PomBuilder.java | 8 ++ .../maven/impl/model/DefaultModelBuilder.java | 2 +- .../maven/impl/resolver/DefaultModelResolver.java | 2 +- .../it/MavenITgh11772DualConsumerPomTest.java | 122 +++++++++++++++++++++ .../gh-11772-dual-consumer-pom/child/pom.xml | 37 +++++++ .../resources/gh-11772-dual-consumer-pom/pom.xml | 51 +++++++++ 9 files changed, 415 insertions(+), 15 deletions(-) diff --git a/api/maven-api-model/src/main/mdo/maven.mdo b/api/maven-api-model/src/main/mdo/maven.mdo index e7acdd78c8..b6cf928433 100644 --- a/api/maven-api-model/src/main/mdo/maven.mdo +++ b/api/maven-api-model/src/main/mdo/maven.mdo @@ -1814,6 +1814,16 @@ </description> <type>String</type> </field> + <field> + <name>classifier</name> + <version>4.1.0+</version> + <description> + The classifier of the parent POM to resolve from the repository. + This is used by consumer POMs to reference the full-fidelity consumer POM + of the parent project, which is deployed with a classifier (e.g., {@code consumer}). + </description> + <type>String</type> + </field> </fields> <codeSegments> <codeSegment> 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 adaf72c7ba..531f39898c 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 @@ -32,11 +32,12 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet; import org.apache.maven.api.feature.Features; -import org.apache.maven.api.model.Model; import org.apache.maven.api.services.ModelBuilderException; import org.apache.maven.api.services.ModelSource; import org.apache.maven.api.services.Source; @@ -58,11 +59,15 @@ @Singleton @Named class ConsumerPomArtifactTransformer extends TransformerSupport { - private static final String CONSUMER_POM_CLASSIFIER = "consumer"; + static final String CONSUMER_POM_CLASSIFIER = "consumer"; + + private static final String CONSUMER_POM_FULL_CLASSIFIER = "consumer-full"; private static final String BUILD_POM_CLASSIFIER = "build"; private final Set<Path> toDelete = new CopyOnWriteArraySet<>(); + private final Map<Path, byte[]> consumerFullCache = new ConcurrentHashMap<>(); + private final Set<Path> consumerFullPaths = ConcurrentHashMap.newKeySet(); private final PomBuilder builder; @@ -89,7 +94,15 @@ public void injectTransformedArtifacts(RepositorySystemSession session, MavenPro : Files.createTempFile(CONSUMER_POM_CLASSIFIER + "-", ".pom"); deferDeleteFile(consumer); + Path consumerFull = buildDir != null + ? Files.createTempFile(buildDir, CONSUMER_POM_FULL_CLASSIFIER + "-", ".pom") + : Files.createTempFile(CONSUMER_POM_FULL_CLASSIFIER + "-", ".pom"); + deferDeleteFile(consumerFull); + consumerFullPaths.add(consumerFull.toAbsolutePath()); + project.addAttachedArtifact(createConsumerPomArtifact(project, consumer, session)); + project.addAttachedArtifact( + createConsumerPomArtifact(project, consumerFull, session, CONSUMER_POM_FULL_CLASSIFIER)); } 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"); @@ -98,6 +111,11 @@ public void injectTransformedArtifacts(RepositorySystemSession session, MavenPro TransformedArtifact createConsumerPomArtifact( MavenProject project, Path consumer, RepositorySystemSession session) { + return createConsumerPomArtifact(project, consumer, session, CONSUMER_POM_CLASSIFIER); + } + + TransformedArtifact createConsumerPomArtifact( + MavenProject project, Path consumer, RepositorySystemSession session, String classifier) { Path actual = project.getFile().toPath(); Path parent = project.getBaseDirectory(); ModelSource source = new ModelSource() { @@ -133,21 +151,51 @@ public ModelSource resolve(ModelLocator modelLocator, String relative) { } }; return new TransformedArtifact( - this, - project, - consumer, - session, - new ProjectArtifact(project), - () -> source, - CONSUMER_POM_CLASSIFIER, - "pom"); + this, project, consumer, session, new ProjectArtifact(project), () -> source, classifier, "pom"); } @Override public void transform(MavenProject project, RepositorySystemSession session, ModelSource src, Path tgt) throws ModelBuilderException, XMLStreamException, IOException { - Model model = builder.build(session, project, src); - write(model, tgt); + if (consumerFullPaths.contains(tgt.toAbsolutePath())) { + // This is the consumer-full artifact — check if we have cached content + byte[] cached = consumerFullCache.remove(tgt.toAbsolutePath()); + if (cached != null) { + Files.write(tgt, cached); + } + // If no cached content, leave the file empty (will be skipped during deploy) + } else { + // This is the main consumer artifact + PomBuilder.ConsumerPomBuildResult result = builder.buildConsumerPoms(session, project, src); + write(result.main(), tgt); + if (result.consumer() != null) { + // Cache the consumer-full content for later + Path consumerFullPath = findConsumerFullPath(tgt); + if (consumerFullPath != null) { + java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(); + try (java.io.OutputStream os = baos) { + new org.apache.maven.model.v4.MavenStaxWriter().write(os, result.consumer()); + } + consumerFullCache.put(consumerFullPath, baos.toByteArray()); + } + } + } + } + + private Path findConsumerFullPath(Path mainPath) { + // Find the consumer-full path that's in the same directory as the main path + Path dir = mainPath.getParent(); + for (Path p : consumerFullPaths) { + if (p.getParent().equals(dir)) { + return p; + } + } + return null; + } + + boolean hasConsumerFullContent(Path path) { + return consumerFullCache.containsKey(path.toAbsolutePath()) + || (Files.exists(path) && path.toFile().length() > 0); } private void deferDeleteFile(Path generatedFile) { @@ -188,10 +236,13 @@ private boolean consumerPomPresent(Collection<Artifact> artifacts) { private Collection<Artifact> replacePom(Collection<Artifact> artifacts) { List<Artifact> consumers = new ArrayList<>(); + List<Artifact> consumerFulls = new ArrayList<>(); List<Artifact> mains = new ArrayList<>(); for (Artifact artifact : artifacts) { if ("pom".equals(artifact.getExtension()) || artifact.getExtension().startsWith("pom.")) { - if (CONSUMER_POM_CLASSIFIER.equals(artifact.getClassifier())) { + if (CONSUMER_POM_FULL_CLASSIFIER.equals(artifact.getClassifier())) { + consumerFulls.add(artifact); + } else if (CONSUMER_POM_CLASSIFIER.equals(artifact.getClassifier())) { consumers.add(artifact); } else if ("".equals(artifact.getClassifier())) { mains.add(artifact); @@ -200,6 +251,7 @@ private Collection<Artifact> replacePom(Collection<Artifact> artifacts) { } if (!mains.isEmpty() && !consumers.isEmpty()) { ArrayList<Artifact> result = new ArrayList<>(artifacts); + // original POM → build classifier for (Artifact main : mains) { result.remove(main); result.add(new DefaultArtifact( @@ -211,6 +263,7 @@ private Collection<Artifact> replacePom(Collection<Artifact> artifacts) { main.getProperties(), main.getPath())); } + // consumer POM → main (no classifier) for (Artifact consumer : consumers) { result.remove(consumer); result.add(new DefaultArtifact( @@ -222,6 +275,20 @@ private Collection<Artifact> replacePom(Collection<Artifact> artifacts) { consumer.getProperties(), consumer.getPath())); } + // consumer-full POM → consumer classifier (only if it has content) + for (Artifact consumerFull : consumerFulls) { + result.remove(consumerFull); + if (consumerFull.getPath() != null && hasConsumerFullContent(consumerFull.getPath())) { + result.add(new DefaultArtifact( + consumerFull.getGroupId(), + consumerFull.getArtifactId(), + CONSUMER_POM_CLASSIFIER, + consumerFull.getExtension(), + consumerFull.getVersion(), + consumerFull.getProperties(), + consumerFull.getPath())); + } + } artifacts = result; } return artifacts; diff --git a/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java b/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java index da8f1e1401..eafdf553d6 100644 --- a/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java +++ b/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java @@ -33,8 +33,11 @@ import org.apache.maven.api.PathScope; import org.apache.maven.api.SessionData; import org.apache.maven.api.feature.Features; +import org.apache.maven.api.model.Activation; +import org.apache.maven.api.model.Build; import org.apache.maven.api.model.Dependency; import org.apache.maven.api.model.DistributionManagement; +import org.apache.maven.api.model.Extension; import org.apache.maven.api.model.Model; import org.apache.maven.api.model.ModelBase; import org.apache.maven.api.model.Profile; @@ -103,6 +106,47 @@ public Model build(RepositorySystemSession session, MavenProject project, ModelS } } + @Override + public ConsumerPomBuildResult buildConsumerPoms( + RepositorySystemSession session, MavenProject project, ModelSource src) throws ModelBuilderException { + Model model = project.getModel().getDelegate(); + boolean flattenEnabled = Features.consumerPomFlatten(session.getConfigProperties()); + String packaging = model.getPackaging(); + String originalPackaging = project.getOriginalModel().getPackaging(); + + boolean isBom = BOM_PACKAGING.equals(originalPackaging); + + if (!flattenEnabled) { + if (POM_PACKAGING.equals(packaging) && !isBom) { + return buildPomConsumerPoms(session, project, src); + } + } else { + if (POM_PACKAGING.equals(packaging) && !isBom) { + return buildPomConsumerPoms(session, project, src); + } + } + // For non-POM, BOMs, etc., fall back to single POM + return new ConsumerPomBuildResult(build(session, project, src), null); + } + + protected ConsumerPomBuildResult buildPomConsumerPoms( + RepositorySystemSession session, MavenProject project, ModelSource src) throws ModelBuilderException { + ModelBuilderResult result = buildModel(session, src); + Model rawModel = result.getRawModel(); + Model consumerModel = transformPom(rawModel, project); + + String modelVersion = consumerModel.getModelVersion(); + if (ModelBuilder.MODEL_VERSION_4_0_0.equals(modelVersion) || consumerModel.isPreserveModelVersion()) { + return new ConsumerPomBuildResult(consumerModel, null); + } + + // Generate dual consumer POMs: main (4.0.0) + consumer (4.1.0) + Model consumer410 = addConsumerClassifierToParent(consumerModel); + Model main400 = stripTo400(consumerModel); + + return new ConsumerPomBuildResult(main400, consumer410); + } + protected Model buildPom(RepositorySystemSession session, MavenProject project, ModelSource src) throws ModelBuilderException { ModelBuilderResult result = buildModel(session, src); @@ -380,4 +424,65 @@ private static List<Repository> pruneRepositories(List<Repository> repositories) .filter(r -> !org.apache.maven.api.Repository.CENTRAL_ID.equals(r.getId())) .collect(Collectors.toList()); } + + static Model stripTo400(Model model) { + // Strip profile condition and packaging activation (4.1.0 features) + if (!model.getProfiles().isEmpty()) { + List<Profile> strippedProfiles = model.getProfiles().stream() + .map(DefaultConsumerPomBuilder::stripProfileTo400) + .collect(Collectors.toList()); + model = model.withProfiles(strippedProfiles); + } + + // Strip build sources (4.1.0 feature) + if (model.getBuild() != null) { + model = model.withBuild(stripBuildTo400(model.getBuild())); + } + + // Strip subprojects (4.1.0 feature, should already be stripped by transformPom but be safe) + model = model.withSubprojects(null); + + // Force model version to 4.0.0 + model = model.withModelVersion(ModelBuilder.MODEL_VERSION_4_0_0); + model = model.withPreserveModelVersion(false); + model = model.withRoot(false); + + return model; + } + + private static Profile stripProfileTo400(Profile profile) { + if (profile.getActivation() != null) { + Activation activation = profile.getActivation(); + if (activation.getCondition() != null || activation.getPackaging() != null) { + activation = Activation.newBuilder(activation, true) + .condition(null) + .packaging(null) + .build(); + profile = profile.withActivation(activation); + } + } + return profile; + } + + private static Build stripBuildTo400(Build build) { + // Strip sources (4.1.0 feature) + if (!build.getSources().isEmpty()) { + build = build.withSources(null); + } + // Strip extension configuration (4.1.0 feature) + if (!build.getExtensions().isEmpty()) { + List<Extension> strippedExtensions = build.getExtensions().stream() + .map(ext -> ext.getConfiguration() != null ? ext.withConfiguration(null) : ext) + .collect(Collectors.toList()); + build = build.withExtensions(strippedExtensions); + } + return build; + } + + static Model addConsumerClassifierToParent(Model model) { + if (model.getParent() != null) { + model = model.withParent(model.getParent().withClassifier("consumer")); + } + return model; + } } diff --git a/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/PomBuilder.java b/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/PomBuilder.java index 86f9bed73a..3e2f4179f8 100644 --- a/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/PomBuilder.java +++ b/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/PomBuilder.java @@ -35,4 +35,12 @@ interface PomBuilder { Model build(RepositorySystemSession session, MavenProject project, ModelSource src) throws ModelBuilderException, IOException, XMLStreamException; + + default ConsumerPomBuildResult buildConsumerPoms( + RepositorySystemSession session, MavenProject project, ModelSource src) + throws ModelBuilderException, IOException, XMLStreamException { + return new ConsumerPomBuildResult(build(session, project, src), null); + } + + record ConsumerPomBuildResult(Model main, Model consumer) {} } 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 b3356a2208..7fe660a07f 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 @@ -1050,7 +1050,7 @@ private Model resolveParent( Set<String> parentChain) throws ModelBuilderException { Model parentModel = null; - if (isBuildRequest()) { + if (isBuildRequest() && parent.getClassifier() == null) { parentModel = readParentLocally(childModel, parent, profileActivationContext, parentChain); } if (parentModel == null) { diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultModelResolver.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultModelResolver.java index 03973c981e..1fc1c0fc4c 100644 --- a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultModelResolver.java +++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultModelResolver.java @@ -68,7 +68,7 @@ public ModelSource resolveModel( parent.getGroupId(), parent.getArtifactId(), parent.getVersion(), - null), + parent.getClassifier()), parent.getLocation("version"), "parent"); if (result.version() != null) { diff --git a/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh11772DualConsumerPomTest.java b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh11772DualConsumerPomTest.java new file mode 100644 index 0000000000..90d233f435 --- /dev/null +++ b/its/core-it-suite/src/test/java/org/apache/maven/it/MavenITgh11772DualConsumerPomTest.java @@ -0,0 +1,122 @@ +/* + * 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.io.Reader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.apache.maven.api.model.Model; +import org.apache.maven.model.v4.MavenStaxReader; +import org.junit.jupiter.api.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +/** + * Integration test for <a href="https://github.com/apache/maven/issues/11772">GH-11772</a>. + * <p> + * Verifies that when a POM-packaged project (parent) uses model version 4.1.0 features + * (like profile condition activation), Maven generates dual consumer POMs: + * <ul> + * <li>Main POM (no classifier): 4.0.0-compatible, 4.1.0 features stripped</li> + * <li>Consumer classifier POM: 4.1.0 full-fidelity, parent references consumer classifier</li> + * </ul> + */ +class MavenITgh11772DualConsumerPomTest extends AbstractMavenIntegrationTestCase { + + MavenITgh11772DualConsumerPomTest() { + super("[4.0.0-rc-2,)"); + } + + private static final String GROUP_ID = "org.apache.maven.its.gh11772"; + + @Test + void testDualConsumerPomsForParent() throws Exception { + Path basedir = extractResources("/gh-11772-dual-consumer-pom").toPath(); + + Verifier verifier = newVerifier(basedir.toString(), null); + verifier.addCliArguments("install"); + verifier.execute(); + verifier.verifyErrorFreeLog(); + + // Verify parent POM artifacts in project-local-repo + Path parentDir = basedir.resolve(Paths.get( + "target", + "project-local-repo", + "org.apache.maven.its.gh11772", + "parent", + "1.0.0-SNAPSHOT")); + + Path parentMainPom = parentDir.resolve("parent-1.0.0-SNAPSHOT.pom"); + Path parentConsumerPom = parentDir.resolve("parent-1.0.0-SNAPSHOT-consumer.pom"); + Path parentBuildPom = parentDir.resolve("parent-1.0.0-SNAPSHOT-build.pom"); + + assertTrue("Parent main POM should exist", Files.exists(parentMainPom)); + assertTrue("Parent consumer POM should exist", Files.exists(parentConsumerPom)); + assertTrue("Parent build POM should exist", Files.exists(parentBuildPom)); + + // Main POM should be 4.0.0-compatible + Model mainModel; + try (Reader r = Files.newBufferedReader(parentMainPom)) { + mainModel = new MavenStaxReader().read(r); + } + assertEquals("4.0.0", mainModel.getModelVersion()); + + // Main POM should NOT have condition activation (stripped for 4.0.0 compat) + for (var profile : mainModel.getProfiles()) { + if (profile.getActivation() != null) { + assertNull( + "Main POM profiles should not have condition activation", + profile.getActivation().getCondition()); + } + } + + // Consumer POM should be 4.1.0 full-fidelity + Model consumerModel; + try (Reader r = Files.newBufferedReader(parentConsumerPom)) { + consumerModel = new MavenStaxReader().read(r); + } + assertEquals("4.1.0", consumerModel.getModelVersion()); + + // Verify child POM + Path childDir = basedir.resolve(Paths.get( + "target", + "project-local-repo", + "org.apache.maven.its.gh11772", + "child", + "1.0.0-SNAPSHOT")); + Path childMainPom = childDir.resolve("child-1.0.0-SNAPSHOT.pom"); + assertTrue("Child main POM should exist", Files.exists(childMainPom)); + + Model childModel; + try (Reader r = Files.newBufferedReader(childMainPom)) { + childModel = new MavenStaxReader().read(r); + } + assertNotNull("Child POM should have a parent reference", childModel.getParent()); + assertEquals(GROUP_ID, childModel.getParent().getGroupId()); + assertEquals("parent", childModel.getParent().getArtifactId()); + assertNull( + "Child POM parent should not have a classifier", + childModel.getParent().getClassifier()); + } +} diff --git a/its/core-it-suite/src/test/resources/gh-11772-dual-consumer-pom/child/pom.xml b/its/core-it-suite/src/test/resources/gh-11772-dual-consumer-pom/child/pom.xml new file mode 100644 index 0000000000..cf3c44eea2 --- /dev/null +++ b/its/core-it-suite/src/test/resources/gh-11772-dual-consumer-pom/child/pom.xml @@ -0,0 +1,37 @@ +<?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.1.0"> + + <parent> + <groupId>org.apache.maven.its.gh11772</groupId> + <artifactId>parent</artifactId> + <version>1.0.0-SNAPSHOT</version> + </parent> + + <artifactId>child</artifactId> + + <dependencies> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + </dependencies> + +</project> diff --git a/its/core-it-suite/src/test/resources/gh-11772-dual-consumer-pom/pom.xml b/its/core-it-suite/src/test/resources/gh-11772-dual-consumer-pom/pom.xml new file mode 100644 index 0000000000..b227adf992 --- /dev/null +++ b/its/core-it-suite/src/test/resources/gh-11772-dual-consumer-pom/pom.xml @@ -0,0 +1,51 @@ +<?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.1.0" root="true"> + + <groupId>org.apache.maven.its.gh11772</groupId> + <artifactId>parent</artifactId> + <version>1.0.0-SNAPSHOT</version> + <packaging>pom</packaging> + + <subprojects> + <subproject>child</subproject> + </subprojects> + + <dependencyManagement> + <dependencies> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>2.0.9</version> + </dependency> + </dependencies> + </dependencyManagement> + + <profiles> + <profile> + <id>test-profile</id> + <activation> + <!-- 4.1.0 feature: condition-based activation --> + <condition>${project.artifactId} == 'parent'</condition> + </activation> + </profile> + </profiles> + +</project>
