Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions api/maven-api-core/src/main/java/org/apache/maven/api/Project.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.model.Build;
import org.apache.maven.api.model.Model;
import org.apache.maven.api.model.Profile;

/**
* Interface representing a Maven project which can be created using the
Expand Down Expand Up @@ -237,4 +238,69 @@ default String getId() {
*/
@Nonnull
Optional<Project> getParent();

/**
* Returns all profiles defined in this project.
* <p>
* This method returns only the profiles defined directly in the current project's POM
* and does not include profiles from parent projects.
*
* @return a non-null, possibly empty list of profiles defined in this project
* @see Profile
* @see #getEffectiveProfiles()
*/
@Nonnull
List<Profile> getDeclaredProfiles();

/**
* Returns all profiles defined in this project and all of its parent projects.
* <p>
* This method traverses the parent hierarchy and includes profiles defined in parent POMs.
* The returned list contains profiles from the current project and all of its ancestors in
* the project inheritance chain.
*
* @return a non-null, possibly empty list of all profiles from this project and its parents
* @see Profile
* @see #getDeclaredProfiles()
*/
@Nonnull
List<Profile> getEffectiveProfiles();

/**
* Returns all active profiles for the current project build.
* <p>
* Active profiles are those that have been explicitly activated through one of the following means:
* <ul>
* <li>Command line activation using the -P flag</li>
* <li>Maven settings activation in settings.xml via &lt;activeProfiles&gt;</li>
* <li>Automatic activation via &lt;activation&gt; conditions</li>
* <li>The default active profile (marked with &lt;activeByDefault&gt;true&lt;/activeByDefault&gt;)</li>
* </ul>
* <p>
* The active profiles control various aspects of the build configuration including but not
* limited to dependencies, plugins, properties, and build resources.
*
* @return a non-null, possibly empty list of active profiles for this project
* @see Profile
* @see #getEffectiveActiveProfiles()
*/
@Nonnull
List<Profile> getDeclaredActiveProfiles();

/**
* Returns all active profiles for this project and all of its parent projects.
* <p>
* This method traverses the parent hierarchy and collects all active profiles from
* the current project and its ancestors. Active profiles are those that meet the
* activation criteria through explicit activation or automatic conditions.
* <p>
* The combined set of active profiles from the entire project hierarchy affects
* the effective build configuration.
*
* @return a non-null, possibly empty list of all active profiles from this project and its parents
* @see Profile
* @see #getDeclaredActiveProfiles()
*/
@Nonnull
List<Profile> getEffectiveActiveProfiles();
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;

import org.apache.maven.RepositoryUtils;
import org.apache.maven.api.DependencyCoordinates;
Expand All @@ -38,6 +40,7 @@
import org.apache.maven.api.annotations.Nullable;
import org.apache.maven.api.model.DependencyManagement;
import org.apache.maven.api.model.Model;
import org.apache.maven.api.model.Profile;
import org.apache.maven.impl.MappedCollection;
import org.apache.maven.impl.MappedList;
import org.apache.maven.project.MavenProject;
Expand Down Expand Up @@ -165,6 +168,37 @@ public Optional<Project> getParent() {
return Optional.ofNullable(session.getProject(parent));
}

@Override
@Nonnull
public List<Profile> getDeclaredProfiles() {
return getModel().getProfiles();
}

@Override
@Nonnull
public List<Profile> getEffectiveProfiles() {
return Stream.iterate(this.project, Objects::nonNull, MavenProject::getParent)
.flatMap(project -> project.getModel().getDelegate().getProfiles().stream())
.toList();
}

@Override
@Nonnull
public List<Profile> getDeclaredActiveProfiles() {
return project.getActiveProfiles().stream()
.map(org.apache.maven.model.Profile::getDelegate)
.toList();
}

@Override
@Nonnull
public List<Profile> getEffectiveActiveProfiles() {
return Stream.iterate(this.project, Objects::nonNull, MavenProject::getParent)
.flatMap(project -> project.getActiveProfiles().stream())
.map(org.apache.maven.model.Profile::getDelegate)
.toList();
}

@Nonnull
private DependencyCoordinates toDependency(org.apache.maven.api.model.Dependency dependency) {
return new DependencyCoordinates() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,26 @@
import java.nio.file.StandardCopyOption;
import java.util.List;

import org.apache.maven.api.model.InputLocation;
import org.apache.maven.api.model.InputSource;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.impl.InternalSession;
import org.apache.maven.internal.impl.DefaultProject;
import org.apache.maven.internal.impl.InternalMavenSession;
import org.apache.maven.model.Profile;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.mockito.Mockito;

import static org.apache.maven.project.ProjectBuildingResultWithProblemMessageMatcher.projectBuildingResultWithProblemMessage;
import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
Expand Down Expand Up @@ -345,6 +351,130 @@ void rereadPom_mng7063() throws Exception {
assertThat(project.getName(), is("PROJECT NAME"));
}

@Test
void testActivatedProfileBySource() throws Exception {
File testPom = getTestFile("src/test/resources/projects/pom-with-profiles/pom.xml");

ProjectBuildingRequest request = newBuildingRequest();
request.setLocalRepository(getLocalRepository());
request.setActiveProfileIds(List.of("profile1"));

MavenProject project = projectBuilder.build(testPom, request).getProject();

assertTrue(project.getInjectedProfileIds().keySet().containsAll(List.of("external", project.getId())));
assertTrue(project.getInjectedProfileIds().get("external").isEmpty());
assertTrue(project.getInjectedProfileIds().get(project.getId()).stream().anyMatch("profile1"::equals));
assertTrue(project.getInjectedProfileIds().get(project.getId()).stream().noneMatch("profile2"::equals));
assertTrue(
project.getInjectedProfileIds().get(project.getId()).stream().noneMatch("active-by-default"::equals));
}

@Test
void testActivatedDefaultProfileBySource() throws Exception {
File testPom = getTestFile("src/test/resources/projects/pom-with-profiles/pom.xml");

ProjectBuildingRequest request = newBuildingRequest();
request.setLocalRepository(getLocalRepository());

MavenProject project = projectBuilder.build(testPom, request).getProject();

assertTrue(project.getInjectedProfileIds().keySet().containsAll(List.of("external", project.getId())));
assertTrue(project.getInjectedProfileIds().get("external").isEmpty());
assertTrue(project.getInjectedProfileIds().get(project.getId()).stream().noneMatch("profile1"::equals));
assertTrue(project.getInjectedProfileIds().get(project.getId()).stream().noneMatch("profile2"::equals));
assertTrue(project.getInjectedProfileIds().get(project.getId()).stream().anyMatch("active-by-default"::equals));

InternalMavenSession session = Mockito.mock(InternalMavenSession.class);
List<org.apache.maven.api.model.Profile> activeProfiles =
new DefaultProject(session, project).getDeclaredActiveProfiles();
assertEquals(1, activeProfiles.size());
org.apache.maven.api.model.Profile profile = activeProfiles.get(0);
assertEquals("active-by-default", profile.getId());
InputLocation location = profile.getLocation("");
assertNotNull(location);
assertThat(location.getLineNumber(), greaterThan(0));
assertThat(location.getColumnNumber(), greaterThan(0));
assertNotNull(location.getSource());
assertThat(location.getSource().getLocation(), containsString("pom-with-profiles/pom.xml"));
}

@Test
void testActivatedExternalProfileBySource() throws Exception {
File testPom = getTestFile("src/test/resources/projects/pom-with-profiles/pom.xml");

ProjectBuildingRequest request = newBuildingRequest();
request.setLocalRepository(getLocalRepository());

final Profile externalProfile = new Profile();
externalProfile.setLocation(
"",
new org.apache.maven.model.InputLocation(
1, 1, new org.apache.maven.model.InputSource(new InputSource(null, "settings.xml", null))));
externalProfile.setId("external-profile");
request.addProfile(externalProfile);
request.setActiveProfileIds(List.of(externalProfile.getId()));

MavenProject project = projectBuilder.build(testPom, request).getProject();

assertTrue(project.getInjectedProfileIds().keySet().containsAll(List.of("external", project.getId())));
assertTrue(project.getInjectedProfileIds().get("external").stream().anyMatch("external-profile"::equals));
assertTrue(project.getInjectedProfileIds().get(project.getId()).stream().noneMatch("profile1"::equals));
assertTrue(project.getInjectedProfileIds().get(project.getId()).stream().noneMatch("profile2"::equals));
assertTrue(project.getInjectedProfileIds().get(project.getId()).stream().anyMatch("active-by-default"::equals));

InternalMavenSession session = Mockito.mock(InternalMavenSession.class);
List<org.apache.maven.api.model.Profile> activeProfiles =
new DefaultProject(session, project).getDeclaredActiveProfiles();
assertEquals(2, activeProfiles.size());
org.apache.maven.api.model.Profile profile = activeProfiles.get(0);
assertEquals("active-by-default", profile.getId());
InputLocation location = profile.getLocation("");
assertNotNull(location);
assertThat(location.getLineNumber(), greaterThan(0));
assertThat(location.getColumnNumber(), greaterThan(0));
assertNotNull(location.getSource());
assertThat(location.getSource().getLocation(), containsString("pom-with-profiles/pom.xml"));
profile = activeProfiles.get(1);
assertEquals("external-profile", profile.getId());
location = profile.getLocation("");
assertNotNull(location);
assertThat(location.getLineNumber(), greaterThan(0));
assertThat(location.getColumnNumber(), greaterThan(0));
assertNotNull(location.getSource());
assertThat(location.getSource().getLocation(), containsString("settings.xml"));
}

@Test
void testActivatedProfileIsResolved() throws Exception {
File testPom = getTestFile("src/test/resources/projects/pom-with-profiles/pom.xml");

ProjectBuildingRequest request = newBuildingRequest();
request.setLocalRepository(getLocalRepository());
request.setActiveProfileIds(List.of("profile1"));

MavenProject project = projectBuilder.build(testPom, request).getProject();

assertEquals(1, project.getActiveProfiles().size());
assertTrue(project.getActiveProfiles().stream().anyMatch(p -> "profile1".equals(p.getId())));
assertTrue(project.getActiveProfiles().stream().noneMatch(p -> "profile2".equals(p.getId())));
assertTrue(project.getActiveProfiles().stream().noneMatch(p -> "active-by-default".equals(p.getId())));
}

@Test
void testActivatedProfileByDefaultIsResolved() throws Exception {
File testPom = getTestFile("src/test/resources/projects/pom-with-profiles/pom.xml");

ProjectBuildingRequest request = newBuildingRequest();
request.setLocalRepository(getLocalRepository());

MavenProject project = projectBuilder.build(testPom, request).getProject();

assertEquals(1, project.getActiveProfiles().size());
assertTrue(project.getActiveProfiles().stream().noneMatch(p -> "profile1".equals(p.getId())));
assertTrue(project.getActiveProfiles().stream().noneMatch(p -> "profile2".equals(p.getId())));
assertTrue(project.getActiveProfiles().stream().anyMatch(p -> "active-by-default".equals(p.getId())));
}

/**
* Tests whether external version range parent references are build correctly.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="ISO-8859-1"?>

<!--
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>maven</groupId>
<artifactId>maven-core</artifactId>
<version>2.0-SNAPSHOT</version>

<name>Maven</name>

<profiles>
<profile>
<id>active-by-default</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>profile1</id>
</profile>
<profile>
<id>profile2</id>
</profile>
</profiles>
</project>
Loading