This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git
The following commit(s) were added to refs/heads/master by this push:
new 08bcf21a20 [MNG-8567] Fix resumption to not recurse into subprojects
(#2102)
08bcf21a20 is described below
commit 08bcf21a20e38481806f8d405029f24432c8bf99
Author: Guillaume Nodet <[email protected]>
AuthorDate: Tue Feb 11 17:38:19 2025 +0100
[MNG-8567] Fix resumption to not recurse into subprojects (#2102)
---
.../apache/maven/execution/ActivationSettings.java | 46 +++++++++--------
.../DefaultBuildResumptionDataRepository.java | 4 +-
.../apache/maven/execution/ProfileActivation.java | 20 ++++----
.../apache/maven/execution/ProjectActivation.java | 60 ++++++++++++----------
.../apache/maven/graph/DefaultGraphBuilder.java | 13 +++--
.../org/apache/maven/graph/ProjectSelector.java | 53 +++++++++++++++++++
.../maven/graph/DefaultGraphBuilderTest.java | 2 +-
7 files changed, 130 insertions(+), 68 deletions(-)
diff --git
a/impl/maven-core/src/main/java/org/apache/maven/execution/ActivationSettings.java
b/impl/maven-core/src/main/java/org/apache/maven/execution/ActivationSettings.java
index a56b1f72f3..30c92ed679 100644
---
a/impl/maven-core/src/main/java/org/apache/maven/execution/ActivationSettings.java
+++
b/impl/maven-core/src/main/java/org/apache/maven/execution/ActivationSettings.java
@@ -20,32 +20,34 @@
/**
* Describes whether a target should be activated or not, and if that is
required or optional.
+ *
+ * @param active Should the target be active?
+ * @param optional Should the build continue if the target is not present?
+ * @param recurse Should the target be activated and its children be activated?
*/
-enum ActivationSettings {
- ACTIVATION_OPTIONAL(true, true),
- ACTIVATION_REQUIRED(true, false),
- DEACTIVATION_OPTIONAL(false, true),
- DEACTIVATION_REQUIRED(false, false);
+public record ActivationSettings(boolean active, boolean optional, boolean
recurse) {
- /**
- * Should the target be active?
- */
- final boolean active;
- /**
- * Should the build continue if the target is not present?
- */
- final boolean optional;
+ static ActivationSettings of(final boolean active, final boolean optional)
{
+ return of(active, optional, true);
+ }
- ActivationSettings(final boolean active, final boolean optional) {
- this.active = active;
- this.optional = optional;
+ static ActivationSettings of(final boolean active, final boolean optional,
final boolean recursive) {
+ return new ActivationSettings(active, optional, recursive);
}
- static ActivationSettings of(final boolean active, final boolean optional)
{
- if (optional) {
- return active ? ACTIVATION_OPTIONAL : DEACTIVATION_OPTIONAL;
- } else {
- return active ? ACTIVATION_REQUIRED : DEACTIVATION_REQUIRED;
- }
+ static ActivationSettings activated() {
+ return new ActivationSettings(true, false, true);
+ }
+
+ static ActivationSettings activatedOpt() {
+ return new ActivationSettings(true, true, true);
+ }
+
+ static ActivationSettings deactivated() {
+ return new ActivationSettings(false, false, false);
+ }
+
+ static ActivationSettings deactivatedOpt() {
+ return new ActivationSettings(false, true, false);
}
}
diff --git
a/impl/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
b/impl/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
index 8a4ded84fb..f19ca25fc5 100644
---
a/impl/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
+++
b/impl/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
@@ -112,8 +112,8 @@ void applyResumptionProperties(MavenExecutionRequest
request, Properties propert
if (properties.containsKey(REMAINING_PROJECTS) && !(str1 != null &&
!str1.isEmpty())) {
String propertyValue = properties.getProperty(REMAINING_PROJECTS);
Stream.of(propertyValue.split(PROPERTY_DELIMITER))
- .filter(str -> str != null && !str.isEmpty())
-
.forEach(request.getProjectActivation()::activateOptionalProject);
+ .filter(str -> !str.isEmpty())
+
.forEach(request.getProjectActivation()::activateOptionalProjectNonRecursive);
LOGGER.info("Resuming from {} due to the --resume / -r feature.",
propertyValue);
}
}
diff --git
a/impl/maven-core/src/main/java/org/apache/maven/execution/ProfileActivation.java
b/impl/maven-core/src/main/java/org/apache/maven/execution/ProfileActivation.java
index cc6aecb3c2..218c3444b2 100644
---
a/impl/maven-core/src/main/java/org/apache/maven/execution/ProfileActivation.java
+++
b/impl/maven-core/src/main/java/org/apache/maven/execution/ProfileActivation.java
@@ -41,7 +41,7 @@ public class ProfileActivation {
*/
@Deprecated
public List<String> getActiveProfiles() {
- return Collections.unmodifiableList(new ArrayList<>(getProfileIds(pa
-> pa.active)));
+ return Collections.unmodifiableList(new ArrayList<>(getProfileIds(pa
-> pa.active())));
}
/**
@@ -50,7 +50,7 @@ public List<String> getActiveProfiles() {
*/
@Deprecated
public List<String> getInactiveProfiles() {
- return Collections.unmodifiableList(new ArrayList<>(getProfileIds(pa
-> !pa.active)));
+ return Collections.unmodifiableList(new ArrayList<>(getProfileIds(pa
-> !pa.active())));
}
/**
@@ -80,7 +80,7 @@ public void overwriteInactiveProfiles(List<String>
inactiveProfileIds) {
* @param id The identifier of the profile.
*/
public void activateRequiredProfile(String id) {
- this.activations.put(id, ActivationSettings.ACTIVATION_REQUIRED);
+ this.activations.put(id, ActivationSettings.activated());
}
/**
@@ -88,7 +88,7 @@ public void activateRequiredProfile(String id) {
* @param id The identifier of the profile.
*/
public void activateOptionalProfile(String id) {
- this.activations.put(id, ActivationSettings.ACTIVATION_OPTIONAL);
+ this.activations.put(id, ActivationSettings.activatedOpt());
}
/**
@@ -96,7 +96,7 @@ public void activateOptionalProfile(String id) {
* @param id The identifier of the profile.
*/
public void deactivateRequiredProfile(String id) {
- this.activations.put(id, ActivationSettings.DEACTIVATION_REQUIRED);
+ this.activations.put(id, ActivationSettings.deactivated());
}
/**
@@ -104,7 +104,7 @@ public void deactivateRequiredProfile(String id) {
* @param id The identifier of the profile.
*/
public void deactivateOptionalProfile(String id) {
- this.activations.put(id, ActivationSettings.DEACTIVATION_OPTIONAL);
+ this.activations.put(id, ActivationSettings.deactivatedOpt());
}
/**
@@ -129,27 +129,27 @@ private Set<String> getProfileIds(final
Predicate<ActivationSettings> predicate)
* @return Required active profile identifiers, never {@code null}.
*/
public Set<String> getRequiredActiveProfileIds() {
- return getProfileIds(pa -> !pa.optional && pa.active);
+ return getProfileIds(pa -> !pa.optional() && pa.active());
}
/**
* @return Optional active profile identifiers, never {@code null}.
*/
public Set<String> getOptionalActiveProfileIds() {
- return getProfileIds(pa -> pa.optional && pa.active);
+ return getProfileIds(pa -> pa.optional() && pa.active());
}
/**
* @return Required inactive profile identifiers, never {@code null}.
*/
public Set<String> getRequiredInactiveProfileIds() {
- return getProfileIds(pa -> !pa.optional && !pa.active);
+ return getProfileIds(pa -> !pa.optional() && !pa.active());
}
/**
* @return Optional inactive profile identifiers, never {@code null}.
*/
public Set<String> getOptionalInactiveProfileIds() {
- return getProfileIds(pa -> pa.optional && !pa.active);
+ return getProfileIds(pa -> pa.optional() && !pa.active());
}
}
diff --git
a/impl/maven-core/src/main/java/org/apache/maven/execution/ProjectActivation.java
b/impl/maven-core/src/main/java/org/apache/maven/execution/ProjectActivation.java
index f5f91a4e43..df02be82d2 100644
---
a/impl/maven-core/src/main/java/org/apache/maven/execution/ProjectActivation.java
+++
b/impl/maven-core/src/main/java/org/apache/maven/execution/ProjectActivation.java
@@ -23,7 +23,6 @@
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toSet;
@@ -33,28 +32,23 @@
* build if those projects do not exist.
*/
public class ProjectActivation {
- private static class ProjectActivationSettings {
- /**
- * The selector of a project. This can be the project directory,
[groupId]:[artifactId] or :[artifactId].
- */
- final String selector;
- /**
- * This describes how/when to active or deactivate the project.
- */
- final ActivationSettings activationSettings;
-
- ProjectActivationSettings(String selector, ActivationSettings
activationSettings) {
- this.selector = selector;
- this.activationSettings = activationSettings;
- }
- }
+ /**
+ * ProjectActivationSettings
+ * @param selector the selector of a project, which can be the project
directory, [groupId]:[artifactId] or :[artifactId]
+ * @param activationSettings describes how/when to active or deactivate
the project
+ */
+ public record ProjectActivationSettings(String selector,
ActivationSettings activationSettings) {}
/**
* List of activated and deactivated projects.
*/
private final List<ProjectActivationSettings> activations = new
ArrayList<>();
+ public List<ProjectActivationSettings> getActivations() {
+ return Collections.unmodifiableList(activations);
+ }
+
/**
* Adds a project activation to the request.
* @param selector The selector of the project.
@@ -78,28 +72,28 @@ private Set<String> getProjectSelectors(final
Predicate<ActivationSettings> pred
* @return Required active project selectors, never {@code null}.
*/
public Set<String> getRequiredActiveProjectSelectors() {
- return getProjectSelectors(pa -> !pa.optional && pa.active);
+ return getProjectSelectors(pa -> !pa.optional() && pa.active());
}
/**
* @return Optional active project selectors, never {@code null}.
*/
public Set<String> getOptionalActiveProjectSelectors() {
- return getProjectSelectors(pa -> pa.optional && pa.active);
+ return getProjectSelectors(pa -> pa.optional() && pa.active());
}
/**
* @return Required inactive project selectors, never {@code null}.
*/
public Set<String> getRequiredInactiveProjectSelectors() {
- return getProjectSelectors(pa -> !pa.optional && !pa.active);
+ return getProjectSelectors(pa -> !pa.optional() && !pa.active());
}
/**
* @return Optional inactive project selectors, never {@code null}.
*/
public Set<String> getOptionalInactiveProjectSelectors() {
- return getProjectSelectors(pa -> pa.optional && !pa.active);
+ return getProjectSelectors(pa -> pa.optional() && !pa.active());
}
/**
@@ -109,7 +103,7 @@ public Set<String> getOptionalInactiveProjectSelectors() {
*/
@Deprecated
public List<String> getSelectedProjects() {
- return Collections.unmodifiableList(new
ArrayList<>(getProjectSelectors(pa -> pa.active)));
+ return Collections.unmodifiableList(new
ArrayList<>(getProjectSelectors(pa -> pa.active())));
}
/**
@@ -119,7 +113,7 @@ public List<String> getSelectedProjects() {
*/
@Deprecated
public List<String> getExcludedProjects() {
- return Collections.unmodifiableList(new
ArrayList<>(getProjectSelectors(pa -> !pa.active)));
+ return Collections.unmodifiableList(new
ArrayList<>(getProjectSelectors(pa -> !pa.active())));
}
/**
@@ -129,7 +123,8 @@ public List<String> getExcludedProjects() {
*/
@Deprecated
public void overwriteActiveProjects(List<String> activeProjectSelectors) {
- List<ProjectActivationSettings> projects = getProjects(pa ->
pa.active).collect(Collectors.toList());
+ List<ProjectActivationSettings> projects =
+ getProjects(pa -> pa.active()).toList();
this.activations.removeAll(projects);
activeProjectSelectors.forEach(this::activateOptionalProject);
}
@@ -141,7 +136,8 @@ public void overwriteActiveProjects(List<String>
activeProjectSelectors) {
*/
@Deprecated
public void overwriteInactiveProjects(List<String>
inactiveProjectSelectors) {
- List<ProjectActivationSettings> projects = getProjects(pa ->
!pa.active).collect(Collectors.toList());
+ List<ProjectActivationSettings> projects =
+ getProjects(pa -> !pa.active()).toList();
this.activations.removeAll(projects);
inactiveProjectSelectors.forEach(this::deactivateOptionalProject);
}
@@ -151,7 +147,7 @@ public void overwriteInactiveProjects(List<String>
inactiveProjectSelectors) {
* @param selector The selector of the project.
*/
public void activateRequiredProject(String selector) {
- this.activations.add(new ProjectActivationSettings(selector,
ActivationSettings.ACTIVATION_REQUIRED));
+ this.activations.add(new ProjectActivationSettings(selector,
ActivationSettings.activated()));
}
/**
@@ -159,7 +155,15 @@ public void activateRequiredProject(String selector) {
* @param selector The selector of the project.
*/
public void activateOptionalProject(String selector) {
- this.activations.add(new ProjectActivationSettings(selector,
ActivationSettings.ACTIVATION_OPTIONAL));
+ this.activations.add(new ProjectActivationSettings(selector,
ActivationSettings.activatedOpt()));
+ }
+
+ /**
+ * Mark a project as optional and activated.
+ * @param selector The selector of the project.
+ */
+ public void activateOptionalProjectNonRecursive(String selector) {
+ this.activations.add(new ProjectActivationSettings(selector,
ActivationSettings.of(true, true, false)));
}
/**
@@ -167,7 +171,7 @@ public void activateOptionalProject(String selector) {
* @param selector The selector of the project.
*/
public void deactivateRequiredProject(String selector) {
- this.activations.add(new ProjectActivationSettings(selector,
ActivationSettings.DEACTIVATION_REQUIRED));
+ this.activations.add(new ProjectActivationSettings(selector,
ActivationSettings.deactivated()));
}
/**
@@ -175,7 +179,7 @@ public void deactivateRequiredProject(String selector) {
* @param selector The selector of the project.
*/
public void deactivateOptionalProject(String selector) {
- this.activations.add(new ProjectActivationSettings(selector,
ActivationSettings.DEACTIVATION_OPTIONAL));
+ this.activations.add(new ProjectActivationSettings(selector,
ActivationSettings.deactivatedOpt()));
}
public boolean isEmpty() {
diff --git
a/impl/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
b/impl/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
index 93c81d830d..5f20f38e59 100644
---
a/impl/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
+++
b/impl/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
@@ -175,14 +175,12 @@ private List<MavenProject> trimSelectedProjects(
List<MavenProject> result = projects;
ProjectActivation projectActivation = request.getProjectActivation();
+
Set<String> requiredSelectors =
projectActivation.getRequiredActiveProjectSelectors();
Set<String> optionalSelectors =
projectActivation.getOptionalActiveProjectSelectors();
if (!requiredSelectors.isEmpty() || !optionalSelectors.isEmpty()) {
- Set<MavenProject> selectedProjects = new
HashSet<>(requiredSelectors.size() + optionalSelectors.size());
- selectedProjects.addAll(
- projectSelector.getRequiredProjectsBySelectors(request,
allSortedProjects, requiredSelectors));
- selectedProjects.addAll(
- projectSelector.getOptionalProjectsBySelectors(request,
allSortedProjects, optionalSelectors));
+ Set<MavenProject> selectedProjects =
+ projectSelector.getActiveProjects(request,
allSortedProjects, projectActivation.getActivations());
// it can be empty when an optional project is missing from the
reactor, fallback to returning all projects
if (!selectedProjects.isEmpty()) {
@@ -231,6 +229,11 @@ private List<MavenProject> trimExcludedProjects(
List<MavenProject> result = projects;
ProjectActivation projectActivation = request.getProjectActivation();
+
+ projectActivation.getActivations().stream()
+ .filter(pa -> pa.activationSettings().active())
+ .forEach(pas -> {});
+
Set<String> requiredSelectors =
projectActivation.getRequiredInactiveProjectSelectors();
Set<String> optionalSelectors =
projectActivation.getOptionalInactiveProjectSelectors();
if (!requiredSelectors.isEmpty() || !optionalSelectors.isEmpty()) {
diff --git
a/impl/maven-core/src/main/java/org/apache/maven/graph/ProjectSelector.java
b/impl/maven-core/src/main/java/org/apache/maven/graph/ProjectSelector.java
index f2ee85f738..25b9adae02 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/graph/ProjectSelector.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/graph/ProjectSelector.java
@@ -25,9 +25,11 @@
import java.util.List;
import java.util.Optional;
import java.util.Set;
+import java.util.stream.Collectors;
import org.apache.maven.MavenExecutionException;
import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.ProjectActivation;
import org.apache.maven.project.MavenProject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -39,6 +41,53 @@
public final class ProjectSelector {
private static final Logger LOGGER =
LoggerFactory.getLogger(ProjectSelector.class);
+ public Set<MavenProject> getActiveProjects(
+ MavenExecutionRequest request,
+ List<MavenProject> projects,
+ List<ProjectActivation.ProjectActivationSettings> projectSelectors)
+ throws MavenExecutionException {
+
+ Set<MavenProject> resolvedOptionalProjects = new LinkedHashSet<>();
+ Set<ProjectActivation.ProjectActivationSettings> unresolvedSelectors =
new HashSet<>();
+ File baseDirectory = getBaseDirectoryFromRequest(request);
+ for (ProjectActivation.ProjectActivationSettings activation :
projectSelectors) {
+ if (activation.activationSettings().active()) {
+ String selector = activation.selector();
+ Optional<MavenProject> optSelectedProject =
+ findOptionalProjectBySelector(projects, baseDirectory,
selector);
+ if (optSelectedProject.isPresent()) {
+ resolvedOptionalProjects.add(optSelectedProject.get());
+ if (activation.activationSettings().recurse()) {
+
resolvedOptionalProjects.addAll(getChildProjects(optSelectedProject.get(),
request));
+ }
+ } else {
+ unresolvedSelectors.add(activation);
+ }
+ }
+ }
+ if (!unresolvedSelectors.isEmpty()) {
+ String requiredSelectors = unresolvedSelectors.stream()
+ .filter(pas -> !pas.activationSettings().optional())
+ .map(ProjectActivation.ProjectActivationSettings::selector)
+ .collect(Collectors.joining(", "));
+ if (!requiredSelectors.isEmpty()) {
+ throw new MavenExecutionException(
+ "The requested required projects " + requiredSelectors
+ " do not exist.", request.getPom());
+ } else {
+ String optionalSelectors = unresolvedSelectors.stream()
+
.map(ProjectActivation.ProjectActivationSettings::selector)
+ .collect(Collectors.joining(", "));
+ LOGGER.info("The requested optional projects {} do not
exist.", optionalSelectors);
+ }
+ }
+
+ return resolvedOptionalProjects;
+ }
+
+ /**
+ * @deprecated use {@link #getActiveProjects(MavenExecutionRequest, List,
List)}
+ */
+ @Deprecated(since = "4.0.0")
public Set<MavenProject> getRequiredProjectsBySelectors(
MavenExecutionRequest request, List<MavenProject> projects,
Set<String> projectSelectors)
throws MavenExecutionException {
@@ -61,6 +110,10 @@ public Set<MavenProject> getRequiredProjectsBySelectors(
return selectedProjects;
}
+ /**
+ * @deprecated use {@link #getActiveProjects(MavenExecutionRequest, List,
List)}
+ */
+ @Deprecated(since = "4.0.0")
public Set<MavenProject> getOptionalProjectsBySelectors(
MavenExecutionRequest request, List<MavenProject> projects,
Set<String> projectSelectors) {
Set<MavenProject> resolvedOptionalProjects = new LinkedHashSet<>();
diff --git
a/impl/maven-core/src/test/java/org/apache/maven/graph/DefaultGraphBuilderTest.java
b/impl/maven-core/src/test/java/org/apache/maven/graph/DefaultGraphBuilderTest.java
index a612235510..1bf6de9c51 100644
---
a/impl/maven-core/src/test/java/org/apache/maven/graph/DefaultGraphBuilderTest.java
+++
b/impl/maven-core/src/test/java/org/apache/maven/graph/DefaultGraphBuilderTest.java
@@ -192,7 +192,7 @@ public static Stream<Arguments> parameters() {
scenario("Selected missing project as required and as
optional")
.activeRequiredProjects("non-existing-module")
.activeOptionalProjects("non-existing-module")
- .expectResult(MavenExecutionException.class, "not find
the selected project"),
+ .expectResult(MavenExecutionException.class, "do not
exist"),
scenario("Resuming from project")
.resumeFrom(MODULE_B)
.expectResult(MODULE_B, MODULE_C_2,
INDEPENDENT_MODULE),