You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by kh...@apache.org on 2014/03/14 22:03:29 UTC
svn commit: r1577707 - in /maven/enforcer/trunk/enforcer-rules/src:
main/java/org/apache/maven/plugins/enforcer/
main/java/org/apache/maven/plugins/enforcer/utils/ site/apt/
test/java/org/apache/maven/plugins/enforcer/
Author: khmarbaise
Date: Fri Mar 14 21:03:29 2014
New Revision: 1577707
URL: http://svn.apache.org/r1577707
Log:
[MENFORCER-186]
- First working implementation of the RequireSameVersionsReactor
rule.
Added:
maven/enforcer/trunk/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireSameVersionsReactor.java
maven/enforcer/trunk/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/DefaultTestLogger.java
maven/enforcer/trunk/enforcer-rules/src/site/apt/requireSameVersionsReactor.apt.vm
maven/enforcer/trunk/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/RequireSameVersionsReactorTest.java
Added: maven/enforcer/trunk/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireSameVersionsReactor.java
URL: http://svn.apache.org/viewvc/maven/enforcer/trunk/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireSameVersionsReactor.java?rev=1577707&view=auto
==============================================================================
--- maven/enforcer/trunk/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireSameVersionsReactor.java (added)
+++ maven/enforcer/trunk/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/RequireSameVersionsReactor.java Fri Mar 14 21:03:29 2014
@@ -0,0 +1,412 @@
+package org.apache.maven.plugins.enforcer;
+
+/*
+ * 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.Map.Entry;
+
+import org.apache.commons.lang.SystemUtils;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
+
+/**
+ * This rule will check if a multi module build will follow the best practices.
+ *
+ * @author Karl-Heinz Marbaise
+ * @since 1.3.2
+ */
+public class RequireSameVersionsReactor
+ extends AbstractNonCacheableEnforcerRule
+{
+ private Log logger;
+
+ public void execute( EnforcerRuleHelper helper )
+ throws EnforcerRuleException
+ {
+ logger = helper.getLog();
+
+ MavenSession session;
+ try
+ {
+ session = (MavenSession) helper.evaluate( "${session}" );
+ }
+ catch ( ExpressionEvaluationException eee )
+ {
+ throw new EnforcerRuleException( "Unable to retrieve the MavenSession: ", eee );
+ }
+
+ @SuppressWarnings( "unchecked" )
+ List<MavenProject> sortedProjects = session.getSortedProjects();
+ if ( sortedProjects != null && !sortedProjects.isEmpty() )
+ {
+ checkReactor( sortedProjects );
+ checkParentsInReactor( sortedProjects );
+ checkMissingParentsInReactor( sortedProjects );
+ checkParentsPartOfTheReactor( sortedProjects );
+ checkDependenciesWithinReactor( sortedProjects );
+ }
+
+ }
+
+ private void checkParentsPartOfTheReactor( List<MavenProject> sortedProjects )
+ throws EnforcerRuleException
+ {
+ List<MavenProject> parentsWhichAreNotPartOfTheReactor =
+ existParentsWhichAreNotPartOfTheReactor( sortedProjects );
+ if ( !parentsWhichAreNotPartOfTheReactor.isEmpty() )
+ {
+ StringBuilder sb = new StringBuilder().append( SystemUtils.LINE_SEPARATOR );
+ for ( MavenProject mavenProject : parentsWhichAreNotPartOfTheReactor )
+ {
+ sb.append( " module: " );
+ sb.append( mavenProject.getId() );
+ sb.append( SystemUtils.LINE_SEPARATOR );
+ }
+ throw new EnforcerRuleException( "Module parents have been found which could not be found in the reactor."
+ + sb.toString() );
+ }
+ }
+
+ /**
+ * Convenience method to create a user readable message.
+ *
+ * @param sortedProjects The list of reactor projects.
+ * @throws EnforcerRuleException In case of a violation.
+ */
+ private void checkMissingParentsInReactor( List<MavenProject> sortedProjects )
+ throws EnforcerRuleException
+ {
+ List<MavenProject> modulesWithoutParentsInReactory = existModulesWithoutParentsInReactor( sortedProjects );
+ if ( !modulesWithoutParentsInReactory.isEmpty() )
+ {
+ StringBuilder sb = new StringBuilder().append( SystemUtils.LINE_SEPARATOR );
+ for ( MavenProject mavenProject : modulesWithoutParentsInReactory )
+ {
+ sb.append( " module: " );
+ sb.append( mavenProject.getId() );
+ sb.append( SystemUtils.LINE_SEPARATOR );
+ }
+ throw new EnforcerRuleException( "Reactor contains modules without parents." + sb.toString() );
+ }
+ }
+
+ private void checkDependenciesWithinReactor( List<MavenProject> sortedProjects )
+ throws EnforcerRuleException
+ {
+ //TODO: After we are sure having consistent version we can simply use the first one?
+ String reactorVersion = sortedProjects.get( 0 ).getVersion();
+
+ Map<MavenProject, List<Dependency>> areThereDependenciesWhichAreNotPartOfTheReactor =
+ areThereDependenciesWhichAreNotPartOfTheReactor( reactorVersion, sortedProjects );
+ if ( !areThereDependenciesWhichAreNotPartOfTheReactor.isEmpty() )
+ {
+ StringBuilder sb = new StringBuilder().append( SystemUtils.LINE_SEPARATOR );
+ for ( Entry<MavenProject, List<Dependency>> item : areThereDependenciesWhichAreNotPartOfTheReactor.entrySet() )
+ {
+ sb.append( " module: " );
+ sb.append( item.getKey().getId() );
+ sb.append( SystemUtils.LINE_SEPARATOR );
+ for ( Dependency dependency : item.getValue() )
+ {
+ String id =
+ dependency.getGroupId() + ":" + dependency.getArtifactId() + ":" + dependency.getVersion();
+ sb.append( " dependency: " );
+ sb.append( id );
+ sb.append( SystemUtils.LINE_SEPARATOR );
+ }
+ }
+ throw new EnforcerRuleException(
+ "Reactor modules contains dependencies which do not reference the reactor."
+ + sb.toString() );
+ }
+ }
+
+ /**
+ * Convenience method to create a user readable message.
+ *
+ * @param sortedProjects The list of reactor projects.
+ * @throws EnforcerRuleException In case of a violation.
+ */
+ private void checkParentsInReactor( List<MavenProject> sortedProjects )
+ throws EnforcerRuleException
+ {
+ //TODO: After we are sure having consistent version we can simply use the first one?
+ String reactorVersion = sortedProjects.get( 0 ).getVersion();
+
+ List<MavenProject> areParentsFromTheReactor = areParentsFromTheReactor( reactorVersion, sortedProjects );
+ if ( !areParentsFromTheReactor.isEmpty() )
+ {
+ StringBuilder sb = new StringBuilder().append( SystemUtils.LINE_SEPARATOR );
+ for ( MavenProject mavenProject : areParentsFromTheReactor )
+ {
+ sb.append( " --> " );
+ sb.append( mavenProject.getId() + " parent:" + mavenProject.getParent().getId() );
+ sb.append( SystemUtils.LINE_SEPARATOR );
+ }
+ throw new EnforcerRuleException( "Reactor modules have parents which contain a wrong version."
+ + sb.toString() );
+ }
+ }
+
+ /**
+ * Convenience method to create user readable message.
+ *
+ * @param sortedProjects The list of reactor projects.
+ * @throws EnforcerRuleException In case of a violation.
+ */
+ private void checkReactor( List<MavenProject> sortedProjects )
+ throws EnforcerRuleException
+ {
+ List<MavenProject> consistenceCheckResult = isReactorVersionConsistent( sortedProjects );
+ if ( !consistenceCheckResult.isEmpty() )
+ {
+ StringBuilder sb = new StringBuilder().append( SystemUtils.LINE_SEPARATOR );
+ for ( MavenProject mavenProject : consistenceCheckResult )
+ {
+ sb.append( " --> " );
+ sb.append( mavenProject.getId() );
+ sb.append( SystemUtils.LINE_SEPARATOR );
+ }
+ throw new EnforcerRuleException( "The reactor contains different versions." + sb.toString() );
+ }
+ }
+
+ private List<MavenProject> areParentsFromTheReactor( String reactorVersion, List<MavenProject> sortedProjects )
+ {
+ List<MavenProject> result = new ArrayList<MavenProject>();
+
+ for ( MavenProject mavenProject : sortedProjects )
+ {
+ logger.debug( "Project: " + mavenProject.getId() );
+ if ( hasParent( mavenProject ) )
+ {
+ if ( !mavenProject.isExecutionRoot() )
+ {
+ MavenProject parent = mavenProject.getParent();
+ if ( !reactorVersion.equals( parent.getVersion() ) )
+ {
+ logger.debug( "The project: " + mavenProject.getId()
+ + " has a parent which version does not match the other elements in reactor" );
+ result.add( mavenProject );
+ }
+ }
+ }
+ else
+ {
+ //This situation is currently ignored, cause it's handled by existModulesWithoutParentsInReactor()
+ }
+ }
+
+ return result;
+ }
+
+ private List<MavenProject> existParentsWhichAreNotPartOfTheReactor( List<MavenProject> sortedProjects )
+ {
+ List<MavenProject> result = new ArrayList<MavenProject>();
+
+ for ( MavenProject mavenProject : sortedProjects )
+ {
+ logger.debug( "Project: " + mavenProject.getId() );
+ if ( hasParent( mavenProject ) )
+ {
+ if ( !mavenProject.isExecutionRoot() )
+ {
+ MavenProject parent = mavenProject.getParent();
+ if ( !isProjectPartOfTheReactor( parent, sortedProjects ) )
+ {
+ result.add( mavenProject );
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * This will check of the groupId/artifactId can be found in any reactor project. The version will be ignored cause
+ * versions are checked before.
+ *
+ * @param project The project which should be checked if it is contained in the sortedProjects.
+ * @param sortedProjects The list of existing projects.
+ * @return true if the project has been found within the list false otherwise.
+ */
+ private boolean isProjectPartOfTheReactor( MavenProject project, List<MavenProject> sortedProjects )
+ {
+ return isGAPartOfTheReactor( project.getGroupId(), project.getArtifactId(), sortedProjects );
+ }
+
+ private boolean isDependencyPartOfTheReactor( Dependency dependency, List<MavenProject> sortedProjects )
+ {
+ return isGAPartOfTheReactor( dependency.getGroupId(), dependency.getArtifactId(), sortedProjects );
+ }
+
+ private boolean isGAPartOfTheReactor( String groupId, String artifactId, List<MavenProject> sortedProjects )
+ {
+ boolean result = false;
+ for ( MavenProject mavenProject : sortedProjects )
+ {
+ String parentId = groupId + ":" + artifactId;
+ String projectId = mavenProject.getGroupId() + ":" + mavenProject.getArtifactId();
+ if ( parentId.equals( projectId ) )
+ {
+ result = true;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Assume we have a module which is which is a child of a multi module build but this child does not have a parent.
+ * This method will exactly search for such cases.
+ *
+ * @param projectList The sorted list of the reactor modules.
+ * @return The resulting list will contain the modules in the reactor which do not have a parent. The list will
+ * never null. If the list is empty no violation have happened.
+ */
+ private List<MavenProject> existModulesWithoutParentsInReactor( List<MavenProject> sortedProjects )
+ {
+ List<MavenProject> result = new ArrayList<MavenProject>();
+
+ for ( MavenProject mavenProject : sortedProjects )
+ {
+ logger.debug( "Project: " + mavenProject.getId() );
+ if ( !hasParent( mavenProject ) )
+ {
+ if ( mavenProject.isExecutionRoot() )
+ {
+ logger.debug( "The root does not need having a parent." );
+ }
+ else
+ {
+ logger.debug( "The module: " + mavenProject.getId() + " has no parent." );
+ result.add( mavenProject );
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private void addDep( Map<MavenProject, List<Dependency>> result, MavenProject project, Dependency dependency )
+ {
+ if ( result.containsKey( project ) )
+ {
+ List<Dependency> list = result.get( project );
+ if ( list == null )
+ {
+ list = new ArrayList<Dependency>();
+ }
+ list.add( dependency );
+ result.put( project, list );
+ }
+ else
+ {
+ List<Dependency> list = new ArrayList<Dependency>();
+ list.add( dependency );
+ result.put( project, list );
+ }
+ }
+
+ private Map<MavenProject, List<Dependency>> areThereDependenciesWhichAreNotPartOfTheReactor( String reactorVersion,
+ List<MavenProject> sortedProjects )
+ {
+ Map<MavenProject, List<Dependency>> result = new HashMap<MavenProject, List<Dependency>>();
+ for ( MavenProject mavenProject : sortedProjects )
+ {
+ logger.debug( "Project: " + mavenProject.getId() );
+
+ @SuppressWarnings( "unchecked" )
+ List<Dependency> dependencies = mavenProject.getDependencies();
+ if ( hasDependencies( dependencies ) )
+ {
+ for ( Dependency dependency : dependencies )
+ {
+ if ( isDependencyPartOfTheReactor( dependency, sortedProjects ) )
+ {
+ if ( !dependency.getVersion().equals( reactorVersion ) )
+ {
+ addDep( result, mavenProject, dependency );
+ }
+ }
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * This method will check the following situation within a multi-module build.
+ *
+ * <pre>
+ * <parent>
+ * <groupId>...</groupId>
+ * <artifactId>...</artifactId>
+ * <version>1.0-SNAPSHOT</version>
+ * </parent>
+ *
+ * <version>1.1-SNAPSHOT</version>
+ * </pre>
+ *
+ * @param projectList The sorted list of the reactor modules.
+ * @return The resulting list will contain the modules in the reactor which do the thing in the example above. The
+ * list will never null. If the list is empty no violation have happened.
+ */
+ private List<MavenProject> isReactorVersionConsistent( List<MavenProject> projectList )
+ {
+ List<MavenProject> result = new ArrayList<MavenProject>();
+
+ if ( projectList != null && !projectList.isEmpty() )
+ {
+ //TODO: Check if this the right choice ?
+ String version = projectList.get( 0 ).getVersion();
+ logger.debug( "First version:" + version );
+ for ( MavenProject mavenProject : projectList )
+ {
+ logger.debug( " -> checking " + mavenProject.getId() );
+ if ( !version.equals( mavenProject.getVersion() ) )
+ {
+ result.add( mavenProject );
+ }
+ }
+ }
+ return result;
+ }
+
+ private boolean hasDependencies( List<Dependency> dependencies )
+ {
+ return dependencies != null && !dependencies.isEmpty();
+ }
+
+ private boolean hasParent( MavenProject mavenProject )
+ {
+ return mavenProject.getParent() != null;
+ }
+
+}
\ No newline at end of file
Added: maven/enforcer/trunk/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/DefaultTestLogger.java
URL: http://svn.apache.org/viewvc/maven/enforcer/trunk/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/DefaultTestLogger.java?rev=1577707&view=auto
==============================================================================
--- maven/enforcer/trunk/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/DefaultTestLogger.java (added)
+++ maven/enforcer/trunk/enforcer-rules/src/main/java/org/apache/maven/plugins/enforcer/utils/DefaultTestLogger.java Fri Mar 14 21:03:29 2014
@@ -0,0 +1,104 @@
+package org.apache.maven.plugins.enforcer.utils;
+
+import org.apache.maven.plugin.logging.Log;
+
+public class DefaultTestLogger implements Log
+{
+
+ public boolean isDebugEnabled()
+ {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void debug( CharSequence content )
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void debug( CharSequence content, Throwable error )
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void debug( Throwable error )
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean isInfoEnabled()
+ {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void info( CharSequence content )
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void info( CharSequence content, Throwable error )
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void info( Throwable error )
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean isWarnEnabled()
+ {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void warn( CharSequence content )
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void warn( CharSequence content, Throwable error )
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void warn( Throwable error )
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean isErrorEnabled()
+ {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void error( CharSequence content )
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void error( CharSequence content, Throwable error )
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void error( Throwable error )
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+}
Added: maven/enforcer/trunk/enforcer-rules/src/site/apt/requireSameVersionsReactor.apt.vm
URL: http://svn.apache.org/viewvc/maven/enforcer/trunk/enforcer-rules/src/site/apt/requireSameVersionsReactor.apt.vm?rev=1577707&view=auto
==============================================================================
--- maven/enforcer/trunk/enforcer-rules/src/site/apt/requireSameVersionsReactor.apt.vm (added)
+++ maven/enforcer/trunk/enforcer-rules/src/site/apt/requireSameVersionsReactor.apt.vm Fri Mar 14 21:03:29 2014
@@ -0,0 +1,130 @@
+~~ 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.
+
+ ------
+ Require Same Versions Reactor
+ ------
+ Karl-Heinz Marbaise
+ ------
+ March 2014
+ ------
+
+Require Same Versions Reactor
+
+ This rule checks that the versions within the reactor are consistent furthermore
+ it will check that every module within the project contains a parent and that the
+ parent is part of the reactor build. Furthermore it will all given dependencies
+ if they are intermodule dependencies that they using the same versions.
+
+
+ The following parameters are supported by this rule:
+
+ * message - an optional message to the user if the rule fails.
+
+ []
+
+
+ Sample Plugin Configuration:
+
++---+
+<project>
+ [...]
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-enforcer-plugin</artifactId>
+ <version>${project.version}</version>
+ <executions>
+ <execution>
+ <id>enforce-no-snapshots</id>
+ <goals>
+ <goal>enforce</goal>
+ </goals>
+ <configuration>
+ <rules>
+ <requireSameVersionsReactor/>
+ </rules>
+ <fail>true</fail>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ [...]
+</project>
++---+
+
+ There are different situations within a multi module build which can lead to problems
+ (for example not working with maven-release-plugin etc.).
+ This rule is intended to prevent such problems.
+
+ Let us assume we have the following (simple) project structure for a multi module setup.
+
++-----
+ root (pom.xml)
+ +--- module1 (pom.xml)
+ +--- module2 (pom.xml)
++-----
+
+ The root <<pom.xml>> looks like this:
+
++-----
+ <groupId>com.mycompany.project</groupId>
+ <artifactId>parent</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ (..)
++-----
+
+ The best practice in Maven is that all childs inherit the version from their parent
+ and don't define a new version which looks like this:
+
++-----
+ <parent>
+ <groupId>...</groupId>
+ <artifactId>...</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>module1</artifactId>
+ (..)
++-----
+
+ But sometimes people mistaken things or violate the best-practice and
+ this look like this:
+
++-----
+ <parent>
+ <groupId>...</groupId>
+ <artifactId>...</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>module1</artifactId>
+ <version>1.1-SNAPSHOT</version>
++-----
+
+ By using this rule you would get a message during the build if you try to build
+ and example like the above which result in the following output:
+
++-----
+[WARNING] Rule 0: org.apache.maven.plugins.enforcer.RequireSameVersionsReactor failed with message:
+The reactor contains different versions.
+ --> org.apache.enforcer.example:appasm:pom:1.1.0-SNAPSHOT
++-----
+
Added: maven/enforcer/trunk/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/RequireSameVersionsReactorTest.java
URL: http://svn.apache.org/viewvc/maven/enforcer/trunk/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/RequireSameVersionsReactorTest.java?rev=1577707&view=auto
==============================================================================
--- maven/enforcer/trunk/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/RequireSameVersionsReactorTest.java (added)
+++ maven/enforcer/trunk/enforcer-rules/src/test/java/org/apache/maven/plugins/enforcer/RequireSameVersionsReactorTest.java Fri Mar 14 21:03:29 2014
@@ -0,0 +1,341 @@
+package org.apache.maven.plugins.enforcer;
+
+/*
+ * 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 org.apache.maven.enforcer.rule.api.EnforcerRuleException;
+import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Check requireSameVersionsReactor rule.
+ *
+ * @author <a href="mailto:khmarbaise@apache.org">Karl Heinz Marbaise</a>
+ */
+public class RequireSameVersionsReactorTest
+{
+ private MavenProject project;
+
+ private MavenSession session;
+
+ private EnforcerRuleHelper helper;
+
+ private RequireSameVersionsReactor rule;
+
+ @Before
+ public void before()
+ throws ExpressionEvaluationException
+ {
+ project = mock( MavenProject.class );
+ session = mock( MavenSession.class );
+ helper = mock( EnforcerRuleHelper.class );
+ when( helper.evaluate( "${project}" ) ).thenReturn( project );
+ when( helper.evaluate( "${session}" ) ).thenReturn( session );
+ when( helper.getLog() ).thenReturn( mock( Log.class ) );
+
+ rule = new RequireSameVersionsReactor();
+ }
+
+ @Test
+ public void shouldNotFailWithNoProject()
+ throws EnforcerRuleException
+ {
+ when( session.getSortedProjects() ).thenReturn( Collections.<MavenProject> emptyList() );
+
+ rule.execute( helper );
+
+ //intentionally only assertTrue cause we don't expect an exception.
+ assertTrue( true );
+ }
+
+ @Test
+ public void shouldNotFailWithAValidProject()
+ throws EnforcerRuleException, ExpressionEvaluationException
+ {
+ MavenProject mp1 = createProjectParent();
+ MavenProject mp2 = createProjectChild1( mp1 );
+ MavenProject mp3 = createProjectChild2( mp1 );
+
+ assertTrue( mp2.getParent() == mp1 );
+ assertTrue( mp3.getParent() == mp1 );
+
+ List<MavenProject> theList = Arrays.asList( mp1, mp2, mp3 );
+ when( session.getSortedProjects() ).thenReturn( theList );
+
+ rule.execute( helper );
+
+ //intentionally only assertTrue cause we don't expect an exception.
+ assertTrue( true );
+ }
+
+ @Test( expected = EnforcerRuleException.class )
+ public void shouldFailWithWrongVersionInOneChild()
+ throws EnforcerRuleException, ExpressionEvaluationException
+ {
+ MavenProject mp1 = createProjectParent();
+ MavenProject mp2 = createProjectChild1( mp1 );
+ MavenProject mp3 = createProjectChild2WithWrongVersion( mp1 );
+
+ List<MavenProject> theList = Arrays.asList( mp1, mp2, mp3 );
+ when( session.getSortedProjects() ).thenReturn( theList );
+
+ rule.execute( helper );
+
+ //intentionally no assertTrue() cause we expect getting an exception.
+ }
+
+ @Test( expected = EnforcerRuleException.class )
+ public void shouldFailWithWrongParent()
+ throws EnforcerRuleException, ExpressionEvaluationException
+ {
+ MavenProject mp1 = createProjectParent();
+
+ MavenProject wrongParentVerison = mock( MavenProject.class );
+ when( wrongParentVerison.getGroupId() ).thenReturn( "org.apache.enforcer" );
+ when( wrongParentVerison.getArtifactId() ).thenReturn( "m1" );
+ when( wrongParentVerison.getVersion() ).thenReturn( "1.1-SNAPSHOT" );
+ when( wrongParentVerison.getId() ).thenReturn( "org.apache.enforcer:m1:jar:1.1-SNAPSHOT" );
+ when( wrongParentVerison.getDependencies() ).thenReturn( Collections.emptyList() );
+
+ MavenProject mp2 = createProjectChild2( wrongParentVerison );
+ MavenProject mp3 = createProjectChild2( mp1 );
+
+ List<MavenProject> theList = Arrays.asList( mp1, mp2, mp3 );
+ when( session.getSortedProjects() ).thenReturn( theList );
+
+ rule.execute( helper );
+
+ //intentionally no assertTrue() cause we expect getting an exception.
+ }
+
+ @Test
+ public void shouldNotFailWithACompanyParent()
+ throws EnforcerRuleException, ExpressionEvaluationException
+ {
+ MavenProject companyParent = createCompanyParent();
+ MavenProject mp1 = createProjectParent( companyParent );
+
+ MavenProject mp2 = createProjectChild1( mp1 );
+ MavenProject mp3 = createProjectChild2( mp1 );
+
+ List<MavenProject> theList = Arrays.asList( mp1, mp2, mp3 );
+ when( session.getSortedProjects() ).thenReturn( theList );
+
+ rule.execute( helper );
+
+ //intentionally only assertTrue cause we don't expect an exception.
+ assertTrue( true );
+ }
+
+ @Test( expected = EnforcerRuleException.class )
+ public void shouldFailWithMissingParentsInReactory()
+ throws EnforcerRuleException, ExpressionEvaluationException
+ {
+ MavenProject mp1 = createProjectParent();
+ MavenProject mp2 = createProjectChild1( mp1 );
+ MavenProject mp3 = createProjectChild2( null );
+
+ List<MavenProject> theList = Arrays.asList( mp1, mp2, mp3 );
+ when( session.getSortedProjects() ).thenReturn( theList );
+
+ rule.execute( helper );
+
+ //intentionally only assertTrue cause we don't expect an exception.
+ assertTrue( true );
+ }
+
+ @Test( expected = EnforcerRuleException.class )
+ public void shouldFailWithAParentWhichIsNotPartOfTheReactory()
+ throws EnforcerRuleException, ExpressionEvaluationException
+ {
+ MavenProject mp1 = createProjectParent();
+
+ MavenProject wrongParentVerison = mock( MavenProject.class );
+ when( wrongParentVerison.getGroupId() ).thenReturn( "org.apache" );
+ when( wrongParentVerison.getArtifactId() ).thenReturn( "m1" );
+ when( wrongParentVerison.getVersion() ).thenReturn( "1.0-SNAPSHOT" );
+ when( wrongParentVerison.getId() ).thenReturn( "org.apache.enforcer:m1:jar:1.0-SNAPSHOT" );
+ when( wrongParentVerison.getDependencies() ).thenReturn( Collections.emptyList() );
+
+ MavenProject mp2 = createProjectChild2( wrongParentVerison );
+ MavenProject mp3 = createProjectChild2( mp1 );
+
+ List<MavenProject> theList = Arrays.asList( mp1, mp2, mp3 );
+ when( session.getSortedProjects() ).thenReturn( theList );
+
+ rule.execute( helper );
+
+ //intentionally no assertTrue() cause we expect getting an exception.
+ }
+
+ @Test
+ public void shouldNotFailWithDependencyInReactory()
+ throws EnforcerRuleException, ExpressionEvaluationException
+ {
+ MavenProject mp1 = createProjectParent();
+ MavenProject mp2 = createProjectChild1( mp1 );
+
+ Dependency goodDependency = createDependency( "org.junit", "junit", "2.0" );
+ List<Dependency> depListMP2 = Arrays.asList( goodDependency );
+ when( mp2.getDependencies() ).thenReturn( depListMP2 );
+
+ MavenProject mp3 = createProjectChild2( mp1 );
+ Dependency dep1_MP3 = createDependency( "org.apache.commons", "commons-io", "1.0.4" );
+ List<Dependency> depListMP3 = Arrays.asList( dep1_MP3 );
+ when( mp3.getDependencies() ).thenReturn( depListMP3 );
+
+ List<MavenProject> theList = Arrays.asList( mp1, mp2, mp3 );
+ when( session.getSortedProjects() ).thenReturn( theList );
+
+ rule.execute( helper );
+
+ //intentionally no assertTrue() cause we expect getting an exception.
+ assertTrue( true );
+ }
+
+ @Test( expected = EnforcerRuleException.class )
+ public void shouldFailWithWrongDependencyInReactory()
+ throws EnforcerRuleException, ExpressionEvaluationException
+ {
+ MavenProject mp1 = createProjectParent();
+ MavenProject mp2 = createProjectChild1( mp1 );
+
+ Dependency goodDependency = createDependency( "org.junit", "junit", "2.0" );
+
+ Dependency wrongDepFromReactory = createDependency( "org.apache.enforcer", "m2", "1.1-SNAPSHOT" );
+ List<Dependency> depList = Arrays.asList( goodDependency, wrongDepFromReactory );
+ when( mp2.getDependencies() ).thenReturn( depList );
+
+ MavenProject mp3 = createProjectChild2( mp1 );
+
+ List<MavenProject> theList = Arrays.asList( mp1, mp2, mp3 );
+ when( session.getSortedProjects() ).thenReturn( theList );
+
+ rule.execute( helper );
+
+ //intentionally no assertTrue() cause we expect getting an exception.
+ }
+
+ /**
+ * This small setup is equivalent to the following situation:
+ *
+ * <pre>
+ * <parent>
+ * <groupId>...</groupId>
+ * <artifactId>...</artifactId>
+ * <version>1.0-SNAPSHOT</version>
+ * </parent>
+ *
+ * <version>1.1-SNAPSHOT</version>
+ * </pre>
+ *
+ * @param parent
+ * @return Create MavenProject mock.
+ */
+ private MavenProject createProjectChild2WithWrongVersion( MavenProject parent )
+ {
+ MavenProject mp2 = mock( MavenProject.class );
+ when( mp2.getParent() ).thenReturn( parent );
+ when( mp2.getGroupId() ).thenReturn( "org.apache.enforcer" );
+ when( mp2.getArtifactId() ).thenReturn( "m1" );
+ when( mp2.getVersion() ).thenReturn( "1.1-SNAPSHOT" );
+ when( mp2.getId() ).thenReturn( "org.apache.enforcer:m1:jar:1.1-SNAPSHOT" );
+ when( mp2.getDependencies() ).thenReturn( Collections.emptyList() );
+ return mp2;
+ }
+
+ private MavenProject createProjectChild2( MavenProject parent )
+ {
+ MavenProject mp3 = mock( MavenProject.class );
+ when( mp3.getParent() ).thenReturn( parent );
+ when( mp3.getGroupId() ).thenReturn( "org.apache.enforcer" );
+ when( mp3.getArtifactId() ).thenReturn( "m2" );
+ when( mp3.getVersion() ).thenReturn( "1.0-SNAPSHOT" );
+ when( mp3.getId() ).thenReturn( "org.apache.enforcer:m2:jar:1.0-SNAPSHOT" );
+ when( mp3.getDependencies() ).thenReturn( Collections.emptyList() );
+ return mp3;
+ }
+
+ private MavenProject createProjectChild1( MavenProject parent )
+ {
+ MavenProject mp2 = mock( MavenProject.class );
+ when( mp2.getParent() ).thenReturn( parent );
+ when( mp2.getGroupId() ).thenReturn( "org.apache.enforcer" );
+ when( mp2.getArtifactId() ).thenReturn( "m1" );
+ when( mp2.getVersion() ).thenReturn( "1.0-SNAPSHOT" );
+ when( mp2.getId() ).thenReturn( "org.apache.enforcer:m1:jar:1.0-SNAPSHOT" );
+ when( mp2.getDependencies() ).thenReturn( Collections.emptyList() );
+ return mp2;
+ }
+
+ private MavenProject createCompanyParent()
+ {
+ MavenProject nonReactoryParent = mock( MavenProject.class );
+ when( nonReactoryParent.getGroupId() ).thenReturn( "org.apache.enforcer.parent" );
+ when( nonReactoryParent.getArtifactId() ).thenReturn( "parent" );
+ when( nonReactoryParent.getVersion() ).thenReturn( "1.1" );
+ when( nonReactoryParent.getId() ).thenReturn( "org.apache.enforcer.parent:parent:jar:1.1" );
+ when( nonReactoryParent.getDependencies() ).thenReturn( Collections.emptyList() );
+ return nonReactoryParent;
+ }
+
+ private MavenProject createProjectParent( MavenProject nonReactorParent )
+ {
+ MavenProject m = createProjectParent();
+ when( m.isExecutionRoot() ).thenReturn( true );
+ when( m.getParent() ).thenReturn( nonReactorParent );
+ return m;
+ }
+
+ private MavenProject createProjectParent()
+ {
+ MavenProject mp1 = mock( MavenProject.class );
+ when( mp1.isExecutionRoot() ).thenReturn( true );
+ when( mp1.getParent() ).thenReturn( null );
+ when( mp1.getGroupId() ).thenReturn( "org.apache.enforcer" );
+ when( mp1.getArtifactId() ).thenReturn( "parent" );
+ when( mp1.getVersion() ).thenReturn( "1.0-SNAPSHOT" );
+ when( mp1.getId() ).thenReturn( "org.apache.enforcer:parent:pom:1.0-SNAPSHOT" );
+ when( mp1.getDependencies() ).thenReturn( Collections.emptyList() );
+ return mp1;
+ }
+
+ private Dependency createDependency( String groupId, String artifactId, String version )
+ {
+ Dependency dep = mock( Dependency.class );
+ when( dep.getGroupId() ).thenReturn( groupId );
+ when( dep.getArtifactId() ).thenReturn( artifactId );
+ when( dep.getVersion() ).thenReturn( version );
+ return dep;
+ }
+}