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 <mthmuld...@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>