diff --git a/pom.xml b/pom.xml index 7520bd07c..f7e8e98a2 100644 --- a/pom.xml +++ b/pom.xml @@ -99,6 +99,9 @@ under the License. 4.10.1 3.3.0 + + 3.9.1 + true 2024-10-18T18:16:14Z diff --git a/src/it/projects/go-offline/pom.xml b/src/it/projects/go-offline/pom.xml index fc59fc1e6..b185dc590 100644 --- a/src/it/projects/go-offline/pom.xml +++ b/src/it/projects/go-offline/pom.xml @@ -36,12 +36,24 @@ UTF-8 + org.apache.maven - maven-project - 2.0.6 + maven-core + 3.9.11 + + + + + org.apache.maven.plugins + maven-clean-plugin + 3.5.0 + + + + diff --git a/src/it/projects/go-offline/test.properties b/src/it/projects/go-offline/test.properties deleted file mode 100644 index 2a312e22e..000000000 --- a/src/it/projects/go-offline/test.properties +++ /dev/null @@ -1,18 +0,0 @@ -# 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. - -outputFile = target/tree.txt diff --git a/src/it/projects/go-offline/verify.groovy b/src/it/projects/go-offline/verify.groovy new file mode 100644 index 000000000..550cc2caf --- /dev/null +++ b/src/it/projects/go-offline/verify.groovy @@ -0,0 +1,34 @@ +/* + * 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. + */ + +File file = new File(basedir, 'build.log') +assert file.exists() + +String buildLog = file.getText("UTF-8") + +assert buildLog.contains('[INFO] Resolved plugin: maven-clean-plugin-3.5.0.jar') +assert buildLog.contains('[INFO] Resolved plugin dependency:') +assert buildLog.contains('[INFO] maven-clean-plugin-3.5.0.jar') +assert buildLog.contains('[INFO] plexus-utils-4.0.2.jar') + +assert buildLog.contains('[INFO] Resolved dependency: maven-core-3.9.11.jar') +assert buildLog.contains('[INFO] Resolved dependency: maven-model-3.9.11.jar') +assert buildLog.contains('[INFO] Resolved dependency: maven-settings-3.9.11.jar') + + 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 index b796f761c..ef82569fa 100644 --- a/src/main/java/org/apache/maven/plugins/dependency/resolvers/ExcludeReactorProjectsDependencyFilter.java +++ b/src/main/java/org/apache/maven/plugins/dependency/resolvers/ExcludeReactorProjectsDependencyFilter.java @@ -20,57 +20,39 @@ import java.util.List; import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collectors; 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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - * {@link TransformableFilter} implementation that excludes artifacts found in the Reactor. + * Filter implementation that excludes artifacts found in the Reactor. * * @author Maarten Mulders */ -public class ExcludeReactorProjectsDependencyFilter extends AbstractFilter { - private final Log log; +public class ExcludeReactorProjectsDependencyFilter implements Predicate { + private final Logger log = LoggerFactory.getLogger(ExcludeReactorProjectsDependencyFilter.class); private final Set reactorArtifactKeys; - public ExcludeReactorProjectsDependencyFilter(final List reactorProjects, final Log log) { - this.log = log; + public ExcludeReactorProjectsDependencyFilter(final List reactorProjects) { this.reactorArtifactKeys = reactorProjects.stream() .map(project -> ArtifactUtils.key(project.getArtifact())) .collect(Collectors.toSet()); } @Override - public boolean accept(final Node node, final List 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"); + public boolean test(Dependency dependency) { + String key = ArtifactUtils.key(dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion()); + if (reactorArtifactKeys.contains(key)) { + if (log.isDebugEnabled()) { + log.debug("Skipped dependency {} because it is present in the reactor", key); } - - return !result; + return false; } 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 9f8c4ea84..e86d0f832 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 @@ -22,6 +22,7 @@ import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -33,9 +34,9 @@ import org.apache.maven.artifact.DefaultArtifact; import org.apache.maven.artifact.handler.DefaultArtifactHandler; import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager; -import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.Dependency; +import org.apache.maven.model.DependencyManagement; import org.apache.maven.model.Plugin; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Mojo; @@ -43,10 +44,8 @@ import org.apache.maven.plugins.dependency.fromDependencies.AbstractDependencyFilterMojo; import org.apache.maven.plugins.dependency.utils.DependencyUtil; import org.apache.maven.plugins.dependency.utils.ResolverUtil; -import org.apache.maven.project.DefaultProjectBuildingRequest; import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectBuilder; -import org.apache.maven.project.ProjectBuildingRequest; import org.apache.maven.shared.artifact.filter.collection.ArtifactFilterException; import org.apache.maven.shared.artifact.filter.collection.ArtifactIdFilter; import org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter; @@ -55,16 +54,13 @@ import org.apache.maven.shared.artifact.filter.collection.GroupIdFilter; import org.apache.maven.shared.artifact.filter.collection.ScopeFilter; import org.apache.maven.shared.artifact.filter.collection.TypeFilter; -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.DependencyResolver; -import org.apache.maven.shared.transfer.dependencies.resolve.DependencyResolverException; +import org.eclipse.aether.artifact.ArtifactTypeRegistry; import org.eclipse.aether.resolution.ArtifactResolutionException; import org.eclipse.aether.resolution.DependencyResolutionException; import org.sonatype.plexus.build.incremental.BuildContext; +import static java.util.Optional.ofNullable; + /** * Goal that resolves all project dependencies, including plugins and reports and their dependencies. * @@ -76,12 +72,6 @@ @Mojo(name = "go-offline", threadSafe = true) public class GoOfflineMojo extends AbstractDependencyFilterMojo { - /** - * Remote repositories which will be searched for artifacts. - */ - @Parameter(defaultValue = "${project.remoteArtifactRepositories}", readonly = true, required = true) - private List remoteRepositories; - /** * Don't resolve plugins and artifacts that are in the current reactor. * @@ -90,8 +80,6 @@ public class GoOfflineMojo extends AbstractDependencyFilterMojo { @Parameter(property = "excludeReactor", defaultValue = "true") protected boolean excludeReactor; - private final DependencyResolver dependencyResolver; - @Inject // CHECKSTYLE_OFF: ParameterNumber public GoOfflineMojo( @@ -99,11 +87,9 @@ public GoOfflineMojo( BuildContext buildContext, MavenProject project, ResolverUtil resolverUtil, - DependencyResolver dependencyResolver, ProjectBuilder projectBuilder, ArtifactHandlerManager artifactHandlerManager) { super(session, buildContext, project, resolverUtil, projectBuilder, artifactHandlerManager); - this.dependencyResolver = dependencyResolver; } // CHECKSTYLE_ON: ParameterNumber @@ -136,16 +122,14 @@ protected void doExecute() throws MojoExecutionException { } } - final Set dependencies = resolveDependencyArtifacts(); + final List dependencies = resolveDependencyArtifacts(); - for (Artifact artifact : dependencies) { - logMessage("Resolved dependency: " + DependencyUtil.getFormattedFileName(artifact, false)); + for (org.eclipse.aether.artifact.Artifact artifact : dependencies) { + logMessage("Resolved dependency: " + + DependencyUtil.getFormattedFileName(RepositoryUtils.toArtifact(artifact), false)); } - } catch (DependencyResolverException - | ArtifactFilterException - | ArtifactResolutionException - | DependencyResolutionException e) { + } catch (ArtifactFilterException | ArtifactResolutionException | DependencyResolutionException e) { throw new MojoExecutionException(e.getMessage(), e); } } @@ -161,56 +145,43 @@ private void logMessage(String message) { /** * This method resolves the dependency artifacts from the project. * - * @return set of resolved dependency artifacts - * @throws ArtifactFilterException - * @throws DependencyResolverException in case of an error while resolving the artifacts + * @return lis of resolved dependency artifacts + * @throws ArtifactFilterException in case of an error while filtering the artifacts + * @throws DependencyResolutionException in case of an error while resolving the artifacts */ - protected Set resolveDependencyArtifacts() throws DependencyResolverException, ArtifactFilterException { + protected List resolveDependencyArtifacts() + throws ArtifactFilterException, DependencyResolutionException { Collection dependencies = getProject().getDependencies(); dependencies = filterDependencies(dependencies); - Set dependableCoordinates = dependencies.stream() - .map(this::createDependendableCoordinateFromDependency) - .collect(Collectors.toSet()); - - ProjectBuildingRequest buildingRequest = newResolveArtifactProjectBuildingRequest(); - - return resolveDependableCoordinate(buildingRequest, dependableCoordinates, "dependencies"); - } - - private Set resolveDependableCoordinate( - final ProjectBuildingRequest buildingRequest, - final Collection dependableCoordinates, - final String type) - throws DependencyResolverException { - final TransformableFilter filter = getTransformableFilter(); - - this.getLog().debug("Resolving '" + type + "' with following repositories:"); - for (ArtifactRepository repo : buildingRequest.getRemoteRepositories()) { - getLog().debug(repo.getId() + " (" + repo.getUrl() + ")"); - } - - final Set results = new HashSet<>(); - - for (DependableCoordinate dependableCoordinate : dependableCoordinates) { - final Iterable artifactResults = - dependencyResolver.resolveDependencies(buildingRequest, dependableCoordinate, filter); - - for (final ArtifactResult artifactResult : artifactResults) { - results.add(artifactResult.getArtifact()); - } - } - - return results; - } - - private TransformableFilter getTransformableFilter() { + Predicate excludeReactorProjectsDependencyFilter = d -> true; if (this.excludeReactor) { - return new ExcludeReactorProjectsDependencyFilter(this.reactorProjects, getLog()); - } else { - return null; + excludeReactorProjectsDependencyFilter = new ExcludeReactorProjectsDependencyFilter(this.reactorProjects); } + + ArtifactTypeRegistry artifactTypeRegistry = + session.getRepositorySession().getArtifactTypeRegistry(); + + List dependableCoordinates = dependencies.stream() + .filter(excludeReactorProjectsDependencyFilter) + .map(d -> RepositoryUtils.toDependency(d, artifactTypeRegistry)) + .collect(Collectors.toList()); + + List managedDependencies = ofNullable( + getProject().getDependencyManagement()) + .map(DependencyManagement::getDependencies) + .map(list -> list.stream() + .map(d -> RepositoryUtils.toDependency(d, artifactTypeRegistry)) + .collect(Collectors.toList())) + .orElse(null); + + return getResolverUtil() + .resolveDependenciesForArtifact( + RepositoryUtils.toArtifact(getProject().getArtifact()), + dependableCoordinates, + managedDependencies, + getProject().getRemoteProjectRepositories()); } /** @@ -237,6 +208,9 @@ private Set getProjectPlugins() { } private List toList(String list) { + if (list == null || list.isEmpty()) { + return Collections.emptyList(); + } return Arrays.asList(DependencyUtil.cleanToBeTokenizedString(list).split(",")); } @@ -250,17 +224,6 @@ private Collection filterDependencies(Collection deps) t return createDependencySetFromArtifacts(artifacts); } - 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()); - result.setClassifier(dependency.getClassifier()); - - return result; - } - private Set createArtifactSetFromDependencies(Collection deps) { Set artifacts = new HashSet<>(); for (Dependency dep : deps) { @@ -297,6 +260,7 @@ private Collection createDependencySetFromArtifacts(Set ar /** * @return {@link FilterArtifacts} */ + // TODO: refactor this to use Resolver API filters protected FilterArtifacts getArtifactsFilter() { final FilterArtifacts filter = new FilterArtifacts(); @@ -327,22 +291,6 @@ protected FilterArtifacts getArtifactsFilter() { return filter; } - /** - * @return returns a new ProjectBuildingRequest populated from the current session and the current project remote - * repositories, used to resolve artifacts - */ - public ProjectBuildingRequest newResolveArtifactProjectBuildingRequest() { - return newProjectBuildingRequest(remoteRepositories); - } - - private ProjectBuildingRequest newProjectBuildingRequest(List repositories) { - ProjectBuildingRequest buildingRequest = new DefaultProjectBuildingRequest(session.getProjectBuildingRequest()); - - buildingRequest.setRemoteRepositories(repositories); - - return buildingRequest; - } - @Override protected ArtifactsFilter getMarkedArtifactFilter() { return null; diff --git a/src/main/java/org/apache/maven/plugins/dependency/utils/ResolverUtil.java b/src/main/java/org/apache/maven/plugins/dependency/utils/ResolverUtil.java index 43fc7e5a2..3976abaa3 100644 --- a/src/main/java/org/apache/maven/plugins/dependency/utils/ResolverUtil.java +++ b/src/main/java/org/apache/maven/plugins/dependency/utils/ResolverUtil.java @@ -163,6 +163,35 @@ public List resolveDependencies( .collect(Collectors.toList()); } + /** + * Resolve transitive dependencies for artifact with managed dependencies. + * + * @param rootArtifact a root artifact to resolve + * @param dependencies a list of dependencies for artifact + * @param managedDependencies a list of managed dependencies for artifact + * @param remoteProjectRepositories remote repositories list + * @return Resolved dependencies + * @throws DependencyResolutionException if the dependency tree could not be built or any dependency artifact could + * not be resolved + */ + public List resolveDependenciesForArtifact( + Artifact rootArtifact, + List dependencies, + List managedDependencies, + List remoteProjectRepositories) + throws DependencyResolutionException { + MavenSession session = mavenSessionProvider.get(); + + CollectRequest collectRequest = + new CollectRequest(dependencies, managedDependencies, remoteProjectRepositories); + collectRequest.setRootArtifact(rootArtifact); + DependencyRequest request = new DependencyRequest(collectRequest, null); + DependencyResult result = repositorySystem.resolveDependencies(session.getRepositorySession(), request); + return result.getArtifactResults().stream() + .map(ArtifactResult::getArtifact) + .collect(Collectors.toList()); + } + /** * Resolve transitive dependencies for plugin. * 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 index 26034f6dd..e1460e317 100644 --- a/src/test/java/org/apache/maven/plugins/dependency/resolvers/ExcludeReactorProjectsDependencyFilterTest.java +++ b/src/test/java/org/apache/maven/plugins/dependency/resolvers/ExcludeReactorProjectsDependencyFilterTest.java @@ -18,22 +18,14 @@ */ package org.apache.maven.plugins.dependency.resolvers; -import java.util.Collections; - 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 static java.util.Collections.singletonList; -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() { @@ -50,56 +42,15 @@ public void testReject() { MavenProject project = new MavenProjectStub(); project.setArtifact(artifact1); - Log log = mock(Log.class); - when(log.isDebugEnabled()).thenReturn(false); - ExcludeReactorProjectsDependencyFilter filter = - new ExcludeReactorProjectsDependencyFilter(singletonList(project), log); + new ExcludeReactorProjectsDependencyFilter(singletonList(project)); - Node node = () -> { - final Dependency result = new Dependency(); - result.setGroupId(artifact1.getGroupId()); - result.setArtifactId(artifact1.getArtifactId()); - result.setVersion(artifact1.getVersion()); - return result; - }; + Dependency dependency = new Dependency(); + dependency.setGroupId(artifact1.getGroupId()); + dependency.setArtifactId(artifact1.getArtifactId()); + dependency.setVersion(artifact1.getVersion()); - assertFalse(filter.accept(node, Collections.emptyList())); - } - - 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"); - - 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 = () -> { - final Dependency result = new Dependency(); - result.setGroupId(artifact1.getGroupId()); - result.setArtifactId(artifact1.getArtifactId()); - result.setVersion(artifact1.getVersion()); - return result; - }; - - filter.accept(node, Collections.emptyList()); - - ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); - verify(log).debug(captor.capture()); - assertTrue(captor.getValue().contains("Skipped dependency")); + assertFalse(filter.test(dependency)); } public void testAccept() { @@ -116,20 +67,14 @@ public void testAccept() { MavenProject project = new MavenProjectStub(); project.setArtifact(artifact1); - Log log = mock(Log.class); - when(log.isDebugEnabled()).thenReturn(false); - ExcludeReactorProjectsDependencyFilter filter = - new ExcludeReactorProjectsDependencyFilter(singletonList(project), log); + new ExcludeReactorProjectsDependencyFilter(singletonList(project)); - Node node = () -> { - final Dependency result = new Dependency(); - result.setGroupId("something-else"); - result.setArtifactId(artifact1.getArtifactId()); - result.setVersion(artifact1.getVersion()); - return result; - }; + Dependency dependency = new Dependency(); + dependency.setGroupId("something-else"); + dependency.setArtifactId(artifact1.getArtifactId()); + dependency.setVersion(artifact1.getVersion()); - assertTrue(filter.accept(node, Collections.emptyList())); + assertTrue(filter.test(dependency)); } }