You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by ma...@apache.org on 2021/02/02 07:20:34 UTC
[maven] branch master updated: [MNG-7051] Optionally skip
non-existing profiles and break on missing required profiles.
This is an automated email from the ASF dual-hosted git repository.
martinkanters 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 8defd16 [MNG-7051] Optionally skip non-existing profiles and break on missing required profiles.
8defd16 is described below
commit 8defd169651db30fe0ac3ad3f318e471f0241d02
Author: Maarten Mulders <mt...@apache.org>
AuthorDate: Wed Dec 9 14:43:15 2020 +0100
[MNG-7051] Optionally skip non-existing profiles and break on missing required profiles.
---
.../main/java/org/apache/maven/DefaultMaven.java | 142 ++++++++++++---
.../org/apache/maven/MissingProfilesException.java | 33 ++++
.../execution/DefaultMavenExecutionRequest.java | 36 ++--
.../maven/execution/MavenExecutionRequest.java | 40 ++++
.../apache/maven/execution/ProfileActivation.java | 201 +++++++++++++++++++++
.../main/java/org/apache/maven/cli/MavenCli.java | 72 +++-----
.../java/org/apache/maven/cli/MavenCliTest.java | 37 ++--
.../apache/maven/model/building/ModelProblem.java | 3 +-
.../model/validation/DefaultModelValidator.java | 2 +
.../validation/DefaultModelValidatorTest.java | 10 +
.../poms/validation/invalid-profile-id.xml | 32 ++++
11 files changed, 496 insertions(+), 112 deletions(-)
diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
index 2e1a684..7b758f5 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -19,22 +19,6 @@ package org.apache.maven;
* under the License.
*/
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
import org.apache.maven.artifact.ArtifactUtils;
import org.apache.maven.execution.BuildResumptionAnalyzer;
import org.apache.maven.execution.BuildResumptionDataRepository;
@@ -44,15 +28,19 @@ import org.apache.maven.execution.ExecutionEvent;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionResult;
import org.apache.maven.execution.MavenSession;
+import org.apache.maven.execution.ProfileActivation;
import org.apache.maven.execution.ProjectDependencyGraph;
import org.apache.maven.graph.GraphBuilder;
import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.lifecycle.internal.ExecutionEventCatapult;
import org.apache.maven.lifecycle.internal.LifecycleStarter;
+import org.apache.maven.model.Model;
import org.apache.maven.model.Prerequisites;
+import org.apache.maven.model.Profile;
import org.apache.maven.model.building.ModelProblem;
import org.apache.maven.model.building.Result;
+import org.apache.maven.model.superpom.SuperPomProvider;
import org.apache.maven.plugin.LegacySupport;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuilder;
@@ -66,6 +54,26 @@ import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.repository.WorkspaceReader;
import org.eclipse.aether.util.repository.ChainedWorkspaceReader;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import static java.util.stream.Collectors.toSet;
+
/**
* @author Jason van Zyl
*/
@@ -109,6 +117,9 @@ public class DefaultMaven
@Inject
private BuildResumptionDataRepository buildResumptionDataRepository;
+ @Inject
+ private SuperPomProvider superPomProvider;
+
@Override
public MavenExecutionResult execute( MavenExecutionRequest request )
{
@@ -316,11 +327,17 @@ public class DefaultMaven
validatePrerequisitesForNonMavenPluginProjects( session.getProjects() );
- validateActivatedProfiles( session.getProjects(), request.getActiveProfiles() );
+ validateRequiredProfiles( session, request.getProfileActivation() );
+ if ( session.getResult().hasExceptions() )
+ {
+ return result;
+ }
+
+ validateOptionalProfiles( session, request.getProfileActivation() );
lifecycleStarter.execute( session );
- validateActivatedProfiles( session.getProjects(), request.getActiveProfiles() );
+ validateOptionalProfiles( session, request.getProfileActivation() );
if ( session.getResult().hasExceptions() )
{
@@ -493,22 +510,93 @@ public class DefaultMaven
}
}
- private void validateActivatedProfiles( List<MavenProject> projects, List<String> activeProfileIds )
+ /**
+ * Get all profiles that are detected in the projects, any parent of the projects, or the settings.
+ * @param session The Maven session
+ * @return A {@link Set} of profile identifiers, never {@code null}.
+ */
+ private Set<String> getAllProfiles( MavenSession session )
{
- Collection<String> notActivatedProfileIds = new LinkedHashSet<>( activeProfileIds );
-
- for ( MavenProject project : projects )
+ final Model superPomModel = superPomProvider.getSuperModel( "4.0.0" );
+ final Set<MavenProject> projectsIncludingParents = new HashSet<>();
+ for ( MavenProject project : session.getProjects() )
{
- for ( List<String> profileIds : project.getInjectedProfileIds().values() )
+ boolean isAdded = projectsIncludingParents.add( project );
+ MavenProject parent = project.getParent();
+ while ( isAdded && parent != null )
{
- notActivatedProfileIds.removeAll( profileIds );
+ isAdded = projectsIncludingParents.add( parent );
+ parent = parent.getParent();
}
}
- for ( String notActivatedProfileId : notActivatedProfileIds )
+ final Stream<String> projectProfiles = projectsIncludingParents.stream()
+ .map( MavenProject::getModel )
+ .map( Model::getProfiles )
+ .flatMap( Collection::stream )
+ .map( Profile::getId );
+ final Stream<String> settingsProfiles = session.getSettings().getProfiles().stream()
+ .map( org.apache.maven.settings.Profile::getId );
+ final Stream<String> superPomProfiles = superPomModel.getProfiles().stream()
+ .map( Profile::getId );
+
+ return Stream.of( projectProfiles, settingsProfiles, superPomProfiles )
+ .flatMap( Function.identity() )
+ .collect( toSet() );
+ }
+
+ /**
+ * Check whether the required profiles were found in any of the projects we're building or the settings.
+ * @param session the Maven session.
+ * @param profileActivation the requested optional and required profiles.
+ */
+ private void validateRequiredProfiles( MavenSession session, ProfileActivation profileActivation )
+ {
+ final Set<String> allAvailableProfiles = getAllProfiles( session );
+
+ final Set<String> requiredProfiles = new HashSet<>( );
+ requiredProfiles.addAll( profileActivation.getRequiredActiveProfileIds() );
+ requiredProfiles.addAll( profileActivation.getRequiredInactiveProfileIds() );
+
+ // Check whether the required profiles were found in any of the projects we're building.
+ final Set<String> notFoundRequiredProfiles = requiredProfiles.stream()
+ .filter( rap -> !allAvailableProfiles.contains( rap ) )
+ .collect( toSet() );
+
+ if ( !notFoundRequiredProfiles.isEmpty() )
+ {
+ final String message = String.format(
+ "The requested profiles [%s] could not be activated or deactivated because they do not exist.",
+ String.join( ", ", notFoundRequiredProfiles )
+ );
+ addExceptionToResult( session.getResult(), new MissingProfilesException( message ) );
+ }
+ }
+
+ /**
+ * Check whether any of the requested optional profiles were not activated or deactivated.
+ * @param session the Maven session.
+ * @param profileActivation the requested optional and required profiles.
+ */
+ private void validateOptionalProfiles( MavenSession session, ProfileActivation profileActivation )
+ {
+ final Set<String> allAvailableProfiles = getAllProfiles( session );
+
+ final Set<String> optionalProfiles = new HashSet<>( );
+ optionalProfiles.addAll( profileActivation.getOptionalActiveProfileIds() );
+ optionalProfiles.addAll( profileActivation.getOptionalInactiveProfileIds() );
+
+ final Set<String> notFoundOptionalProfiles = optionalProfiles.stream()
+ .filter( rap -> !allAvailableProfiles.contains( rap ) )
+ .collect( toSet() );
+
+ if ( !notFoundOptionalProfiles.isEmpty() )
{
- logger.warn( "The requested profile \"" + notActivatedProfileId
- + "\" could not be activated because it does not exist." );
+ final String message = String.format(
+ "The requested optional profiles [%s] could not be activated or deactivated because they "
+ + "do not exist.", String.join( ", ", notFoundOptionalProfiles )
+ );
+ logger.warn( message );
}
}
diff --git a/maven-core/src/main/java/org/apache/maven/MissingProfilesException.java b/maven-core/src/main/java/org/apache/maven/MissingProfilesException.java
new file mode 100644
index 0000000..6e9ee76
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/MissingProfilesException.java
@@ -0,0 +1,33 @@
+package org.apache.maven;
+
+/*
+ * 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.
+ */
+
+/**
+ * Signals that the user referenced one or more Maven profiles that could not be located in either the project or the
+ * settings.
+ */
+public class MissingProfilesException
+ extends Exception
+{
+ public MissingProfilesException( String message )
+ {
+ super( message );
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java
index f344359..554928b 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java
@@ -76,6 +76,8 @@ public class DefaultMavenExecutionRequest
private List<Profile> profiles;
+ private final ProfileActivation profileActivation = new ProfileActivation();
+
private List<String> pluginGroups;
private boolean isProjectPresent = true;
@@ -130,10 +132,6 @@ public class DefaultMavenExecutionRequest
private boolean showErrors = false;
- private List<String> activeProfiles;
-
- private List<String> inactiveProfiles;
-
private TransferListener transferListener;
private int loggingLevel = LOGGING_LEVEL_INFO;
@@ -343,11 +341,7 @@ public class DefaultMavenExecutionRequest
{
if ( activeProfiles != null )
{
- this.activeProfiles = new ArrayList<>( activeProfiles );
- }
- else
- {
- this.activeProfiles = null;
+ this.profileActivation.overwriteActiveProfiles( activeProfiles );
}
return this;
@@ -358,17 +352,19 @@ public class DefaultMavenExecutionRequest
{
if ( inactiveProfiles != null )
{
- this.inactiveProfiles = new ArrayList<>( inactiveProfiles );
- }
- else
- {
- this.inactiveProfiles = null;
+ this.profileActivation.overwriteInactiveProfiles( inactiveProfiles );
}
return this;
}
@Override
+ public ProfileActivation getProfileActivation()
+ {
+ return this.profileActivation;
+ }
+
+ @Override
public MavenExecutionRequest setRemoteRepositories( List<ArtifactRepository> remoteRepositories )
{
if ( remoteRepositories != null )
@@ -406,21 +402,13 @@ public class DefaultMavenExecutionRequest
@Override
public List<String> getActiveProfiles()
{
- if ( activeProfiles == null )
- {
- activeProfiles = new ArrayList<>();
- }
- return activeProfiles;
+ return this.profileActivation.getActiveProfiles();
}
@Override
public List<String> getInactiveProfiles()
{
- if ( inactiveProfiles == null )
- {
- inactiveProfiles = new ArrayList<>();
- }
- return inactiveProfiles;
+ return this.profileActivation.getInactiveProfiles();
}
@Override
diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java
index 1ccd7ec..f31e33f 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java
@@ -277,22 +277,62 @@ public interface MavenExecutionRequest
MavenExecutionRequest setProfiles( List<Profile> profiles );
+ /**
+ * @deprecated Use {@link #getProfileActivation()}.
+ */
+ @Deprecated
MavenExecutionRequest addActiveProfile( String profile );
+ /**
+ * @deprecated Use {@link #getProfileActivation()}.
+ */
+ @Deprecated
MavenExecutionRequest addActiveProfiles( List<String> profiles );
+ /**
+ * @deprecated Use {@link #getProfileActivation()}.
+ */
+ @Deprecated
MavenExecutionRequest setActiveProfiles( List<String> profiles );
+ /**
+ * @return The list of profiles that the user wants to activate.
+ * @deprecated Use {@link #getProfileActivation()}.
+ */
+ @Deprecated
List<String> getActiveProfiles();
+ /**
+ * @deprecated Use {@link #getProfileActivation()}.
+ */
+ @Deprecated
MavenExecutionRequest addInactiveProfile( String profile );
+ /**
+ * @deprecated Use {@link #getProfileActivation()}.
+ */
+ @Deprecated
MavenExecutionRequest addInactiveProfiles( List<String> profiles );
+ /**
+ * @deprecated Use {@link #getProfileActivation()}.
+ */
+ @Deprecated
MavenExecutionRequest setInactiveProfiles( List<String> profiles );
+ /**
+ * @return The list of profiles that the user wants to de-activate.
+ * @deprecated Use {@link #getProfileActivation()}.
+ */
+ @Deprecated
List<String> getInactiveProfiles();
+ /**
+ * Return the requested activation(s) of profile(s) in this execution.
+ * @return requested (de-)activation(s) of profile(s) in this execution. Never {@code null}.
+ */
+ ProfileActivation getProfileActivation();
+
// Proxies
List<Proxy> getProxies();
diff --git a/maven-core/src/main/java/org/apache/maven/execution/ProfileActivation.java b/maven-core/src/main/java/org/apache/maven/execution/ProfileActivation.java
new file mode 100644
index 0000000..21530bd
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/execution/ProfileActivation.java
@@ -0,0 +1,201 @@
+package org.apache.maven.execution;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Predicate;
+
+import static java.util.stream.Collectors.toSet;
+
+/**
+ * Container for storing the request from the user to activate or de-activate certain profiles and optionally fail the
+ * build if those profiles do not exist.
+ */
+public class ProfileActivation
+{
+ private enum ActivationSettings
+ {
+ ACTIVATION_OPTIONAL( true, true ),
+ ACTIVATION_REQUIRED( true, false ),
+ DEACTIVATION_OPTIONAL( false, true ),
+ DEACTIVATION_REQUIRED( false, false );
+
+ /** Should the profile be active? */
+ final boolean active;
+ /** Should the build continue if the profile is not present? */
+ final boolean optional;
+
+ ActivationSettings( final boolean active, final boolean optional )
+ {
+ this.active = active;
+ this.optional = optional;
+ }
+
+ static ActivationSettings of( final boolean active, final boolean optional )
+ {
+ if ( optional )
+ {
+ return active ? ACTIVATION_OPTIONAL : DEACTIVATION_OPTIONAL;
+ }
+ else
+ {
+ return active ? ACTIVATION_REQUIRED : DEACTIVATION_REQUIRED;
+ }
+ }
+ }
+
+ private final Map<String, ActivationSettings> activations = new HashMap<>();
+
+ /**
+ * Mimics the pre-Maven 4 "active profiles" list.
+ * @deprecated Use {@link #getRequiredActiveProfileIds()} and {@link #getOptionalActiveProfileIds()} instead.
+ */
+ @Deprecated
+ public List<String> getActiveProfiles()
+ {
+ return new ArrayList<>( getProfileIds( pa -> pa.active ) );
+ }
+
+ /**
+ * Mimics the pre-Maven 4 "inactive profiles" list.
+ * @deprecated Use {@link #getRequiredInactiveProfileIds()} and {@link #getOptionalInactiveProfileIds()} instead.
+ */
+ @Deprecated
+ public List<String> getInactiveProfiles()
+ {
+ return new ArrayList<>( getProfileIds( pa -> !pa.active ) );
+ }
+
+ /**
+ * Overwrites the active profiles based on a pre-Maven 4 "active profiles" list.
+ * @param activeProfileIds A {@link List} of profile IDs that must be activated.
+ * @deprecated Use {@link #activateOptionalProfile(String)} or {@link #activateRequiredProfile(String)} instead.
+ */
+ @Deprecated
+ public void overwriteActiveProfiles( List<String> activeProfileIds )
+ {
+ getActiveProfiles().forEach( this.activations::remove );
+ activeProfileIds.forEach( this::activateOptionalProfile );
+ }
+
+ /**
+ * Overwrites the inactive profiles based on a pre-Maven 4 "inactive profiles" list.
+ * @param inactiveProfileIds A {@link List} of profile IDs that must be deactivated.
+ * @deprecated Use {@link #deactivateOptionalProfile(String)} or {@link #deactivateRequiredProfile(String)} instead.
+ */
+ @Deprecated
+ public void overwriteInactiveProfiles( List<String> inactiveProfileIds )
+ {
+ getInactiveProfiles().forEach( this.activations::remove );
+ inactiveProfileIds.forEach( this::deactivateOptionalProfile );
+ }
+
+ /**
+ * Mark a profile as required and activated.
+ * @param id The identifier of the profile.
+ */
+ public void activateRequiredProfile( String id )
+ {
+ this.activations.put( id, ActivationSettings.ACTIVATION_REQUIRED );
+ }
+
+ /**
+ * Mark a profile as optional and activated.
+ * @param id The identifier of the profile.
+ */
+ public void activateOptionalProfile( String id )
+ {
+ this.activations.put( id, ActivationSettings.ACTIVATION_OPTIONAL );
+ }
+
+ /**
+ * Mark a profile as required and deactivated.
+ * @param id The identifier of the profile.
+ */
+ public void deactivateRequiredProfile( String id )
+ {
+ this.activations.put( id, ActivationSettings.DEACTIVATION_REQUIRED );
+ }
+
+ /**
+ * Mark a profile as optional and deactivated.
+ * @param id The identifier of the profile.
+ */
+ public void deactivateOptionalProfile( String id )
+ {
+ this.activations.put( id, ActivationSettings.DEACTIVATION_OPTIONAL );
+ }
+
+ /**
+ * Adds a profile activation to the request.
+ * @param id The identifier of the profile.
+ * @param active Should the profile be activated?
+ * @param optional Can the build continue if the profile does not exist?
+ */
+ public void addProfileActivation( String id, boolean active, boolean optional )
+ {
+ final ActivationSettings settings = ActivationSettings.of( active, optional );
+ this.activations.put( id, settings );
+ }
+
+ private Set<String> getProfileIds( final Predicate<ActivationSettings> predicate )
+ {
+ return this.activations.entrySet().stream()
+ .filter( e -> predicate.test( e.getValue() ) )
+ .map( e -> e.getKey() )
+ .collect( toSet() );
+ }
+
+ /**
+ * @return Required active profile identifiers, never {@code null}.
+ */
+ public Set<String> getRequiredActiveProfileIds()
+ {
+ 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 Required inactive profile identifiers, never {@code null}.
+ */
+ public Set<String> getRequiredInactiveProfileIds()
+ {
+ 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 );
+ }
+}
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
index 7afe073..792a831 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
@@ -54,6 +54,7 @@ import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionRequestPopulationException;
import org.apache.maven.execution.MavenExecutionRequestPopulator;
import org.apache.maven.execution.MavenExecutionResult;
+import org.apache.maven.execution.ProfileActivation;
import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule;
import org.apache.maven.extension.internal.CoreExports;
import org.apache.maven.extension.internal.CoreExtensionEntry;
@@ -1379,9 +1380,7 @@ public class MavenCli
request.setSelectedProjects( projectActivation.activeProjects );
request.setExcludedProjects( projectActivation.inactiveProjects );
- final ProfileActivation profileActivation = determineProfileActivation( commandLine );
- request.addActiveProfiles( profileActivation.activeProfiles );
- request.addInactiveProfiles( profileActivation.inactiveProfiles );
+ performProfileActivation( commandLine, request.getProfileActivation() );
final String localRepositoryPath = determineLocalRepositoryPath( request );
if ( localRepositoryPath != null )
@@ -1507,41 +1506,41 @@ public class MavenCli
}
// Visible for testing
- static ProfileActivation determineProfileActivation( final CommandLine commandLine )
+ static void performProfileActivation( final CommandLine commandLine,
+ final ProfileActivation profileActivation )
{
- final ProfileActivation result = new ProfileActivation();
-
if ( commandLine.hasOption( CLIManager.ACTIVATE_PROFILES ) )
{
- String[] profileOptionValues = commandLine.getOptionValues( CLIManager.ACTIVATE_PROFILES );
- if ( profileOptionValues != null )
+ final String[] optionValues = commandLine.getOptionValues( CLIManager.ACTIVATE_PROFILES );
+
+ if ( optionValues == null || optionValues.length == 0 )
{
- for ( String profileOptionValue : profileOptionValues )
- {
- StringTokenizer profileTokens = new StringTokenizer( profileOptionValue, "," );
+ return;
+ }
- while ( profileTokens.hasMoreTokens() )
+ for ( final String optionValue : optionValues )
+ {
+ for ( String token : optionValue.split( "," ) )
+ {
+ String profileId = token.trim();
+ boolean active = true;
+ if ( profileId.charAt( 0 ) == '-' || profileId.charAt( 0 ) == '!' )
{
- String profileAction = profileTokens.nextToken().trim();
-
- if ( profileAction.startsWith( "-" ) || profileAction.startsWith( "!" ) )
- {
- result.deactivate( profileAction.substring( 1 ) );
- }
- else if ( profileAction.startsWith( "+" ) )
- {
- result.activate( profileAction.substring( 1 ) );
- }
- else
- {
- result.activate( profileAction );
- }
+ active = false;
+ profileId = profileId.substring( 1 );
+ }
+ else if ( token.charAt( 0 ) == '+' )
+ {
+ profileId = profileId.substring( 1 );
}
+
+ boolean optional = profileId.charAt( 0 ) == '?';
+ profileId = profileId.substring( optional ? 1 : 0 );
+
+ profileActivation.addProfileActivation( profileId, active, optional );
}
}
}
-
- return result;
}
private ExecutionListener determineExecutionListener()
@@ -1797,23 +1796,6 @@ public class MavenCli
}
// Visible for testing
- static class ProfileActivation
- {
- final List<String> activeProfiles = new ArrayList<>();
- final List<String> inactiveProfiles = new ArrayList<>();
-
- public void deactivate( final String profile )
- {
- inactiveProfiles.add( profile );
- }
-
- public void activate( final String profile )
- {
- activeProfiles.add( profile );
- }
- }
-
- // Visible for testing
static class ProjectActivation
{
List<String> activeProjects;
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
index c7a41a5..de7485c 100644
--- a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
@@ -20,7 +20,7 @@ package org.apache.maven.cli;
*/
import static java.util.Arrays.asList;
-import static org.apache.maven.cli.MavenCli.determineProfileActivation;
+import static org.apache.maven.cli.MavenCli.performProfileActivation;
import static org.apache.maven.cli.MavenCli.determineProjectActivation;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
@@ -33,6 +33,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.hamcrest.collection.IsIterableContainingInOrder.contains;
+import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
@@ -46,9 +47,11 @@ import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
+import org.apache.commons.cli.Parser;
import org.apache.maven.Maven;
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.ProfileActivation;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.utils.logging.MessageUtils;
import org.apache.maven.toolchain.building.ToolchainsBuildingRequest;
@@ -88,25 +91,29 @@ public class MavenCliTest
}
@Test
- public void testDetermineProfileActivation() throws ParseException
+ public void testPerformProfileActivation() throws ParseException
{
- MavenCli.ProfileActivation result;
- Options options = new Options();
+ final Parser parser = new GnuParser();
+
+ final Options options = new Options();
options.addOption( Option.builder( Character.toString( CLIManager.ACTIVATE_PROFILES ) ).hasArg().build() );
- result = determineProfileActivation( new GnuParser().parse( options, new String[]{ "-P", "test1,+test2" } ) );
- assertThat( result.activeProfiles.size(), is( 2 ) );
- assertThat( result.activeProfiles, contains( "test1", "test2" ) );
+ ProfileActivation activation;
+
+ activation = new ProfileActivation();
+ performProfileActivation( parser.parse( options, new String[]{ "-P", "test1,+test2,?test3,+?test4" } ), activation );
+ assertThat( activation.getRequiredActiveProfileIds(), containsInAnyOrder( "test1", "test2" ) );
+ assertThat( activation.getOptionalActiveProfileIds(), containsInAnyOrder( "test3", "test4" ) );
- result = determineProfileActivation( new GnuParser().parse( options, new String[]{ "-P", "!test1,-test2" } ) );
- assertThat( result.inactiveProfiles.size(), is( 2 ) );
- assertThat( result.inactiveProfiles, contains( "test1", "test2" ) );
+ activation = new ProfileActivation();
+ performProfileActivation( parser.parse( options, new String[]{ "-P", "!test1,-test2,-?test3,!?test4" } ), activation );
+ assertThat( activation.getRequiredInactiveProfileIds(), containsInAnyOrder( "test1", "test2" ) );
+ assertThat( activation.getOptionalInactiveProfileIds(), containsInAnyOrder( "test3", "test4" ) );
- result = determineProfileActivation( new GnuParser().parse( options, new String[]{ "-P", "-test1,+test2" } ) );
- assertThat( result.activeProfiles.size(), is( 1 ) );
- assertThat( result.activeProfiles, contains( "test2" ) );
- assertThat( result.inactiveProfiles.size(), is( 1 ) );
- assertThat( result.inactiveProfiles, contains( "test1" ) );
+ activation = new ProfileActivation();
+ performProfileActivation( parser.parse( options, new String[]{ "-P", "-test1,+test2" } ), activation );
+ assertThat( activation.getRequiredActiveProfileIds(), containsInAnyOrder( "test2" ) );
+ assertThat( activation.getRequiredInactiveProfileIds(), containsInAnyOrder( "test1" ) );
}
@Test
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblem.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblem.java
index 30b6724..a08b5ef 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblem.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblem.java
@@ -51,7 +51,8 @@ public interface ModelProblem
V20,
V30,
V31,
- V37
+ V37,
+ V40
}
/**
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java b/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java
index a4c3cda..ba812b5 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java
@@ -190,6 +190,8 @@ public class DefaultModelValidator
{
String prefix = "profiles.profile[" + profile.getId() + "].";
+ validateId( prefix, "id", problems, Severity.ERROR, Version.V40, profile.getId(), null, m );
+
if ( !profileIds.add( profile.getId() ) )
{
addViolation( problems, errOn30, Version.V20, "profiles.profile.id", null,
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/validation/DefaultModelValidatorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/validation/DefaultModelValidatorTest.java
index 5f17a8a..d73dcb1 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/validation/DefaultModelValidatorTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/validation/DefaultModelValidatorTest.java
@@ -403,6 +403,16 @@ public class DefaultModelValidatorTest
}
@Test
+ public void testInvalidProfileId()
+ throws Exception
+ {
+ SimpleProblemCollector result = validateRaw( "invalid-profile-id.xml" );
+
+ assertViolations( result, 0, 1, 0 );
+
+ assertTrue( result.getErrors().get( 0 ).contains( "?invalid-id" ) );
+ }
+
public void testDuplicateProfileId()
throws Exception
{
diff --git a/maven-model-builder/src/test/resources/poms/validation/invalid-profile-id.xml b/maven-model-builder/src/test/resources/poms/validation/invalid-profile-id.xml
new file mode 100644
index 0000000..6e96026
--- /dev/null
+++ b/maven-model-builder/src/test/resources/poms/validation/invalid-profile-id.xml
@@ -0,0 +1,32 @@
+<!--
+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>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>aid</artifactId>
+ <groupId>gid</groupId>
+ <version>0.1</version>
+ <packaging>pom</packaging>
+
+ <profiles>
+ <profile>
+ <id>?invalid-id</id>
+ </profile>
+ </profiles>
+</project>