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),

Reply via email to