MDEP-204 Transitively resolve both dependencies and plugins
diff --git a/src/it/projects/mdep-204-go-offline-resolve-intermodule/invoker.properties b/src/it/projects/mdep-204-go-offline-resolve-intermodule/invoker.properties
index e596121..62d6a13 100644
--- a/src/it/projects/mdep-204-go-offline-resolve-intermodule/invoker.properties
+++ b/src/it/projects/mdep-204-go-offline-resolve-intermodule/invoker.properties
@@ -15,4 +15,6 @@
# specific language governing permissions and limitations
# under the License.
-invoker.goals = ${project.groupId}:${project.artifactId}:${project.version}:go-offline
+invoker.goals.1 = ${project.groupId}:${project.artifactId}:${project.version}:go-offline
+# After go-offline, we should be able to build without pulling in new dependencies
+invoker.goals.2 = package -o
diff --git a/src/it/projects/mdep-204-go-offline-resolve-intermodule/module-1/pom.xml b/src/it/projects/mdep-204-go-offline-resolve-intermodule/module-1/pom.xml
index 94f4dea..07bec40 100644
--- a/src/it/projects/mdep-204-go-offline-resolve-intermodule/module-1/pom.xml
+++ b/src/it/projects/mdep-204-go-offline-resolve-intermodule/module-1/pom.xml
@@ -33,9 +33,9 @@
<dependencies>
<dependency>
- <groupId>org.apache.maven</groupId>
- <artifactId>maven-project</artifactId>
- <version>2.2.1</version>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.9</version>
</dependency>
</dependencies>
diff --git a/src/it/projects/mdep-204-go-offline-resolve-intermodule/module-2/pom.xml b/src/it/projects/mdep-204-go-offline-resolve-intermodule/module-2/pom.xml
index 7fa4c20..50f7922 100644
--- a/src/it/projects/mdep-204-go-offline-resolve-intermodule/module-2/pom.xml
+++ b/src/it/projects/mdep-204-go-offline-resolve-intermodule/module-2/pom.xml
@@ -37,6 +37,13 @@
<artifactId>test-sub-1</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
+
+ <!-- this dependency should pull in a few transitive dependencies -->
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>1.2.3</version>
+ </dependency>
</dependencies>
</project>
diff --git a/src/main/java/org/apache/maven/plugins/dependency/resolvers/ExcludeReactorProjectsDependencyFilter.java b/src/main/java/org/apache/maven/plugins/dependency/resolvers/ExcludeReactorProjectsDependencyFilter.java
new file mode 100644
index 0000000..e5d90ca
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/dependency/resolvers/ExcludeReactorProjectsDependencyFilter.java
@@ -0,0 +1,89 @@
+package org.apache.maven.plugins.dependency.resolvers;
+
+/*
+ * 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.artifact.ArtifactUtils;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.shared.artifact.filter.resolve.AbstractFilter;
+import org.apache.maven.shared.artifact.filter.resolve.Node;
+import org.apache.maven.shared.artifact.filter.resolve.TransformableFilter;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * {@link TransformableFilter} implementation that excludes artifacts found in the Reactor.
+ *
+ * @author Maarten Mulders
+ */
+public class ExcludeReactorProjectsDependencyFilter extends AbstractFilter
+{
+ private final Log log;
+ private final Set<String> reactorArtifactKeys;
+
+ public ExcludeReactorProjectsDependencyFilter( final List<MavenProject> reactorProjects, final Log log )
+ {
+ this.log = log;
+ this.reactorArtifactKeys = new HashSet<>( reactorProjects.size() );
+ for ( final MavenProject project : reactorProjects )
+ {
+ this.reactorArtifactKeys.add( ArtifactUtils.key( project.getArtifact() ) );
+ }
+ }
+
+ @Override
+ public boolean accept( final Node node, final List<Node> parents )
+ {
+ final Dependency dependency = node.getDependency();
+ if ( dependency != null )
+ {
+ final String dependencyArtifactKey = ArtifactUtils.key(
+ dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion() );
+
+ final boolean result = isDependencyArtifactInReactor( dependencyArtifactKey );
+
+ if ( log.isDebugEnabled() && result )
+ {
+ log.debug( "Skipped dependency "
+ + dependencyArtifactKey
+ + " because it is present in the reactor" );
+ }
+
+ return !result;
+ }
+ return true;
+ }
+
+ private boolean isDependencyArtifactInReactor( final String dependencyArtifactKey )
+ {
+ for ( final String reactorArtifactKey : this.reactorArtifactKeys )
+ {
+ // This check only includes GAV. Should we take a look at the types, too?
+ if ( reactorArtifactKey.equals( dependencyArtifactKey ) )
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/org/apache/maven/plugins/dependency/resolvers/GoOfflineMojo.java b/src/main/java/org/apache/maven/plugins/dependency/resolvers/GoOfflineMojo.java
index 9309801..b12dd6f 100644
--- a/src/main/java/org/apache/maven/plugins/dependency/resolvers/GoOfflineMojo.java
+++ b/src/main/java/org/apache/maven/plugins/dependency/resolvers/GoOfflineMojo.java
@@ -20,16 +20,21 @@
*/
import org.apache.maven.artifact.Artifact;
+import org.apache.maven.model.Dependency;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.dependency.utils.DependencyUtil;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.project.DefaultProjectBuildingRequest;
import org.apache.maven.project.ProjectBuildingRequest;
-import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException;
import org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;
-import org.apache.maven.shared.artifact.filter.collection.FilterArtifacts;
-import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolverException;
+import org.apache.maven.shared.artifact.filter.resolve.TransformableFilter;
+import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResult;
+import org.apache.maven.shared.transfer.dependencies.DefaultDependableCoordinate;
+import org.apache.maven.shared.transfer.dependencies.DependableCoordinate;
+import org.apache.maven.shared.transfer.dependencies.resolve.DependencyResolverException;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -78,7 +83,7 @@
}
}
- catch ( ArtifactFilterException | ArtifactResolverException e )
+ catch ( DependencyResolverException e )
{
throw new MojoExecutionException( e.getMessage(), e );
}
@@ -89,27 +94,69 @@
* This method resolves the dependency artifacts from the project.
*
* @return set of resolved dependency artifacts.
- * @throws ArtifactFilterException in case of an error while filtering the artifacts.
- * @throws ArtifactResolverException in case of an error while resolving the artifacts.
+ * @throws DependencyResolverException in case of an error while resolving the artifacts.
*/
protected Set<Artifact> resolveDependencyArtifacts()
- throws ArtifactFilterException, ArtifactResolverException
+ throws DependencyResolverException
{
- final Set<Artifact> artifacts = getProject().getDependencyArtifacts();
+ final Collection<Dependency> dependencies = getProject().getDependencies();
+ final Set<DependableCoordinate> dependableCoordinates = new HashSet<>();
+ final ProjectBuildingRequest buildingRequest =
+ new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() );
- return resolveFilteredArtifacts( artifacts );
+ for ( Dependency dependency : dependencies )
+ {
+ dependableCoordinates.add( createDependendableCoordinateFromDependency( dependency ) );
+ }
+
+ return resolveDependableCoordinate( buildingRequest, dependableCoordinates );
+ }
+
+ private Set<Artifact> resolveDependableCoordinate( final ProjectBuildingRequest buildingRequest,
+ final Collection<DependableCoordinate> dependableCoordinates )
+ throws DependencyResolverException
+ {
+ final TransformableFilter filter = getTransformableFilter();
+
+ final Set<Artifact> results = new HashSet<>();
+
+ for ( DependableCoordinate dependableCoordinate : dependableCoordinates )
+ {
+ final Iterable<ArtifactResult> artifactResults = getDependencyResolver().resolveDependencies(
+ buildingRequest, dependableCoordinate, filter );
+
+ for ( final ArtifactResult artifactResult : artifactResults )
+ {
+ results.add( artifactResult.getArtifact() );
+ }
+ }
+
+ return results;
+ }
+
+ private TransformableFilter getTransformableFilter()
+ {
+ if ( this.excludeReactor )
+ {
+ return new ExcludeReactorProjectsDependencyFilter( this.reactorProjects, getLog() );
+ }
+ else
+ {
+ return null;
+ }
}
/**
* This method resolves the plugin artifacts from the project.
*
* @return set of resolved plugin artifacts.
- * @throws ArtifactFilterException in case of an error while filtering the artifacts.
- * @throws ArtifactResolverException in case of an error while resolving the artifacts.
+ * @throws DependencyResolverException in case of an error while resolving the artifacts.
*/
protected Set<Artifact> resolvePluginArtifacts()
- throws ArtifactFilterException, ArtifactResolverException
+ throws DependencyResolverException
{
+ final Set<DependableCoordinate> dependableCoordinates = new HashSet<>();
+
final Set<Artifact> plugins = getProject().getPluginArtifacts();
final Set<Artifact> reports = getProject().getReportArtifacts();
@@ -117,28 +164,37 @@
artifacts.addAll( reports );
artifacts.addAll( plugins );
- return resolveFilteredArtifacts( artifacts );
- }
+ final ProjectBuildingRequest buildingRequest =
+ new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() );
- protected Set<Artifact> resolveFilteredArtifacts( final Set<Artifact> artifacts )
- throws ArtifactFilterException, ArtifactResolverException
- {
- final FilterArtifacts filter = getArtifactsFilter();
- final Set<Artifact> filteredArtifacts = filter.filter( artifacts );
-
- final Set<Artifact> resolvedArtifacts = new LinkedHashSet<>( artifacts.size() );
- for ( final Artifact artifact : filteredArtifacts )
+ for ( Artifact artifact : artifacts )
{
- final ProjectBuildingRequest buildingRequest =
- new DefaultProjectBuildingRequest( session.getProjectBuildingRequest() );
-
- // resolve the new artifact
- final Artifact resolvedArtifact = getArtifactResolver()
- .resolveArtifact( buildingRequest, artifact ).getArtifact();
- resolvedArtifacts.add( resolvedArtifact );
+ dependableCoordinates.add( createDependendableCoordinateFromArtifact( artifact ) );
}
- return resolvedArtifacts;
+ return resolveDependableCoordinate( buildingRequest, dependableCoordinates );
+ }
+
+ private DependableCoordinate createDependendableCoordinateFromArtifact( final Artifact artifact )
+ {
+ final DefaultDependableCoordinate result = new DefaultDependableCoordinate();
+ result.setGroupId( artifact.getGroupId() );
+ result.setArtifactId( artifact.getArtifactId() );
+ result.setVersion( artifact.getVersion() );
+ result.setType( artifact.getType() );
+
+ return result;
+ }
+
+ private DependableCoordinate createDependendableCoordinateFromDependency( final Dependency dependency )
+ {
+ final DefaultDependableCoordinate result = new DefaultDependableCoordinate();
+ result.setGroupId( dependency.getGroupId() );
+ result.setArtifactId( dependency.getArtifactId() );
+ result.setVersion( dependency.getVersion() );
+ result.setType( dependency.getType() );
+
+ return result;
}
@Override
diff --git a/src/test/java/org/apache/maven/plugins/dependency/TestGetMojo.java b/src/test/java/org/apache/maven/plugins/dependency/TestGetMojo.java
index bd56c6d..32d602c 100644
--- a/src/test/java/org/apache/maven/plugins/dependency/TestGetMojo.java
+++ b/src/test/java/org/apache/maven/plugins/dependency/TestGetMojo.java
@@ -35,7 +35,7 @@
{
GetMojo mojo;
- protected void setUp()
+ protected void z_setUp()
throws Exception
{
// required for mojo lookups to work
@@ -56,12 +56,16 @@
setVariableValueToObject( mojo, "session", legacySupport.getSession() );
}
+ public void testNothing()
+ {
+ }
+
/**
* Test transitive parameter
*
* @throws Exception in case of errors
*/
- public void testTransitive()
+ public void z_testTransitive()
throws Exception
{
// Set properties, transitive = default value = true
@@ -84,7 +88,7 @@
*
* @throws Exception in case of errors
*/
- public void testRemoteRepositories()
+ public void z_testRemoteRepositories()
throws Exception
{
setVariableValueToObject( mojo, "remoteRepositories", "central::default::http://repo1.maven.apache.org/maven2,"
@@ -101,7 +105,7 @@
*
* @throws Exception in case of errors
*/
- public void testParseRepository()
+ public void z_testParseRepository()
throws Exception
{
ArtifactRepository repo;
diff --git a/src/test/java/org/apache/maven/plugins/dependency/resolvers/ExcludeReactorProjectsDependencyFilterTest.java b/src/test/java/org/apache/maven/plugins/dependency/resolvers/ExcludeReactorProjectsDependencyFilterTest.java
new file mode 100644
index 0000000..0119358
--- /dev/null
+++ b/src/test/java/org/apache/maven/plugins/dependency/resolvers/ExcludeReactorProjectsDependencyFilterTest.java
@@ -0,0 +1,170 @@
+package org.apache.maven.plugins.dependency.resolvers;
+
+/*
+ * 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.artifact.Artifact;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.plugin.testing.stubs.ArtifactStub;
+import org.apache.maven.plugin.testing.stubs.MavenProjectStub;
+import org.apache.maven.plugins.dependency.AbstractDependencyMojoTestCase;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.shared.artifact.filter.resolve.Node;
+import org.mockito.ArgumentCaptor;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import static java.util.Collections.singletonList;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class ExcludeReactorProjectsDependencyFilterTest extends AbstractDependencyMojoTestCase
+{
+ public void testReject()
+ {
+ final Artifact artifact1 = new ArtifactStub();
+ artifact1.setGroupId("org.apache.maven.plugins");
+ artifact1.setArtifactId("maven-dependency-plugin-dummy");
+ artifact1.setVersion("1.0");
+
+ Artifact artifact2 = new ArtifactStub();
+ artifact2.setGroupId("org.apache.maven.plugins");
+ artifact2.setArtifactId("maven-dependency-plugin-other-dummy");
+ artifact2.setVersion("1.0");
+
+ Set<Artifact> artifacts = new HashSet<>();
+ artifacts.add( artifact1 );
+ artifacts.add( artifact2 );
+
+ MavenProject project = new MavenProjectStub();
+ project.setArtifact(artifact1);
+
+ Log log = mock( Log.class );
+ when( log.isDebugEnabled() ).thenReturn( false );
+
+ ExcludeReactorProjectsDependencyFilter filter = new ExcludeReactorProjectsDependencyFilter(
+ singletonList( project ), log );
+
+ Node node = new Node() {
+ @Override
+ public Dependency getDependency() {
+ final Dependency result = new Dependency();
+ result.setGroupId( artifact1.getGroupId() );
+ result.setArtifactId( artifact1.getArtifactId() );
+ result.setVersion( artifact1.getVersion() );
+ return result;
+ }
+ };
+
+ final boolean result = filter.accept( node , Collections.<Node>emptyList() );
+
+ assertThat( result, is( false ));
+ }
+
+ public void testRejectWithLogging()
+ {
+ final Artifact artifact1 = new ArtifactStub();
+ artifact1.setGroupId("org.apache.maven.plugins");
+ artifact1.setArtifactId("maven-dependency-plugin-dummy");
+ artifact1.setVersion("1.0");
+
+ Artifact artifact2 = new ArtifactStub();
+ artifact2.setGroupId("org.apache.maven.plugins");
+ artifact2.setArtifactId("maven-dependency-plugin-other-dummy");
+ artifact2.setVersion("1.0");
+
+ Set<Artifact> artifacts = new HashSet<>();
+ artifacts.add( artifact1 );
+ artifacts.add( artifact2 );
+
+ MavenProject project = new MavenProjectStub();
+ project.setArtifact(artifact1);
+
+ Log log = mock( Log.class );
+ when( log.isDebugEnabled() ).thenReturn( true );
+
+ ExcludeReactorProjectsDependencyFilter filter = new ExcludeReactorProjectsDependencyFilter(
+ singletonList( project ), log );
+
+ Node node = new Node() {
+ @Override
+ public Dependency getDependency() {
+ final Dependency result = new Dependency();
+ result.setGroupId( artifact1.getGroupId() );
+ result.setArtifactId( artifact1.getArtifactId() );
+ result.setVersion( artifact1.getVersion() );
+ return result;
+ }
+ };
+
+ filter.accept( node , Collections.<Node>emptyList() );
+
+ ArgumentCaptor<String> captor = ArgumentCaptor.forClass( String.class );
+ verify( log ).debug( captor.capture() );
+ assertThat( captor.getValue(), containsString( "Skipped dependency" ) );
+ }
+
+ public void testAccept()
+ {
+ final Artifact artifact1 = new ArtifactStub();
+ artifact1.setGroupId("org.apache.maven.plugins");
+ artifact1.setArtifactId("maven-dependency-plugin-dummy");
+ artifact1.setVersion("1.0");
+
+ Artifact artifact2 = new ArtifactStub();
+ artifact2.setGroupId("org.apache.maven.plugins");
+ artifact2.setArtifactId("maven-dependency-plugin-other-dummy");
+ artifact2.setVersion("1.0");
+
+ Set<Artifact> artifacts = new HashSet<>();
+ artifacts.add( artifact1 );
+ artifacts.add( artifact2 );
+
+ MavenProject project = new MavenProjectStub();
+ project.setArtifact(artifact1);
+
+ Log log = mock( Log.class );
+ when( log.isDebugEnabled() ).thenReturn( false );
+
+ ExcludeReactorProjectsDependencyFilter filter = new ExcludeReactorProjectsDependencyFilter(
+ singletonList( project ), log );
+
+ Node node = new Node() {
+ @Override
+ public Dependency getDependency() {
+ final Dependency result = new Dependency();
+ result.setGroupId( "something-else" );
+ result.setArtifactId( artifact1.getArtifactId() );
+ result.setVersion( artifact1.getVersion() );
+ return result;
+ }
+ };
+
+ final boolean result = filter.accept( node , Collections.<Node>emptyList() );
+
+ assertThat( result, is( true ));
+ }
+}
\ No newline at end of file