This is an automated email from the ASF dual-hosted git repository. sjaranowski pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/maven-dependency-plugin.git
The following commit(s) were added to refs/heads/master by this push: new 860d04ba [MDEP-924] Get rid of maven-artifact-transfer from list-classes goal 860d04ba is described below commit 860d04ba3d0c3c33bc587baab84f52ba314c0884 Author: Slawomir Jaranowski <s.jaranow...@gmail.com> AuthorDate: Mon Apr 22 23:26:02 2024 +0200 [MDEP-924] Get rid of maven-artifact-transfer from list-classes goal --- pom.xml | 33 ++- .../maven/plugins/dependency/ListClassesMojo.java | 263 ++++++--------------- .../plugins/dependency/utils/ParamArtifact.java | 91 +++++++ .../plugins/dependency/utils/ResolverUtil.java | 167 ++++++++++++- .../dependency/AbstractDependencyMojoTestCase.java | 9 + .../plugins/dependency/TestListClassesMojo.java | 65 ++--- .../testUtils/stubs/DependencyProjectStub.java | 6 + .../plugins/dependency/utils/ResolverUtilTest.java | 108 +++++++++ 8 files changed, 520 insertions(+), 222 deletions(-) diff --git a/pom.xml b/pom.xml index d4b9dc09..3cf62a9a 100644 --- a/pom.xml +++ b/pom.xml @@ -88,13 +88,16 @@ under the License. <properties> <mavenVersion>3.6.3</mavenVersion> + <javaVersion>8</javaVersion> + <jettyVersion>9.4.54.v20240208</jettyVersion> + <mockito.version>4.11.0</mockito.version> + <plexus-archiver.version>4.9.2</plexus-archiver.version> <pluginTestingVersion>3.3.0</pluginTestingVersion> <resolverVersion>1.4.1</resolverVersion> - <javaVersion>8</javaVersion> - <project.build.outputTimestamp>2023-10-20T21:21:50Z</project.build.outputTimestamp> <slf4j.version>1.7.36</slf4j.version> - <plexus-archiver.version>4.9.2</plexus-archiver.version> + + <project.build.outputTimestamp>2023-10-20T21:21:50Z</project.build.outputTimestamp> </properties> <dependencyManagement> @@ -324,6 +327,22 @@ under the License. <version>${resolverVersion}</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-api</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-params</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <!-- support for JUnit 4 --> + <groupId>org.junit.vintage</groupId> + <artifactId>junit-vintage-engine</artifactId> + <scope>test</scope> + </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> @@ -345,7 +364,13 @@ under the License. <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>4.11.0</version> + <version>${mockito.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-junit-jupiter</artifactId> + <version>${mockito.version}</version> <scope>test</scope> </dependency> diff --git a/src/main/java/org/apache/maven/plugins/dependency/ListClassesMojo.java b/src/main/java/org/apache/maven/plugins/dependency/ListClassesMojo.java index 31ba07a9..1cd29ba2 100644 --- a/src/main/java/org/apache/maven/plugins/dependency/ListClassesMojo.java +++ b/src/main/java/org/apache/maven/plugins/dependency/ListClassesMojo.java @@ -18,132 +18,121 @@ */ package org.apache.maven.plugins.dependency; +import java.io.File; import java.io.IOException; -import java.util.ArrayList; import java.util.Enumeration; import java.util.List; -import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarFile; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.apache.maven.artifact.handler.ArtifactHandler; -import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager; -import org.apache.maven.artifact.repository.ArtifactRepository; -import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy; -import org.apache.maven.artifact.repository.MavenArtifactRepository; -import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout; -import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Component; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.project.DefaultProjectBuildingRequest; -import org.apache.maven.project.ProjectBuildingRequest; -import org.apache.maven.repository.RepositorySystem; -import org.apache.maven.settings.Settings; -import org.apache.maven.shared.transfer.artifact.ArtifactCoordinate; -import org.apache.maven.shared.transfer.artifact.DefaultArtifactCoordinate; -import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolver; -import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResolverException; -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.apache.maven.plugins.dependency.utils.ParamArtifact; +import org.apache.maven.plugins.dependency.utils.ResolverUtil; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.resolution.ArtifactResolutionException; +import org.eclipse.aether.resolution.DependencyResolutionException; /** * Retrieves and lists all classes contained in the specified artifact from the specified remote repositories. + * + * @since 3.1.3 */ @Mojo(name = "list-classes", requiresProject = false, threadSafe = true) public class ListClassesMojo extends AbstractMojo { - private static final Pattern ALT_REPO_SYNTAX_PATTERN = Pattern.compile("(.+)::(.*)::(.+)"); - - @Component - private MavenSession session; - - @Component - private ArtifactResolver artifactResolver; @Component - private DependencyResolver dependencyResolver; + private ResolverUtil resolverUtil; - @Component - private ArtifactHandlerManager artifactHandlerManager; + private ParamArtifact paramArtifact = new ParamArtifact(); /** - * Map that contains the layouts. - */ - @Component(role = ArtifactRepositoryLayout.class) - private Map<String, ArtifactRepositoryLayout> repositoryLayouts; - - /** - * The repository system. - */ - @Component - private RepositorySystem repositorySystem; - - private DefaultDependableCoordinate coordinate = new DefaultDependableCoordinate(); - - /** - * The group ID of the artifact to download. Ignored if {@link #artifact} is used. + * The group ID of the artifact to download. Ignored if {@code artifact} is used. + * + * @since 3.1.3 */ @Parameter(property = "groupId") - private String groupId; + public void setGroupId(String groupId) { + paramArtifact.setGroupId(groupId); + } /** - * The artifact ID of the artifact to download. Ignored if {@link #artifact} is used. + * The artifact ID of the artifact to download. Ignored if {@code artifact} is used. + * + * @since 3.1.3 */ @Parameter(property = "artifactId") - private String artifactId; + public void setArtifactId(String artifactId) { + paramArtifact.setArtifactId(artifactId); + } /** - * The version of the artifact to download. Ignored if {@link #artifact} is used. + * The version of the artifact to download. Ignored if {@code artifact} is used. + * + * @since 3.1.3 */ @Parameter(property = "version") - private String version; + public void setVersion(String version) { + paramArtifact.setVersion(version); + } /** - * The classifier of the artifact to download. Ignored if {@link #artifact} is used. + * The classifier of the artifact to download. Ignored if {@code artifact} is used. * - * @since 2.3 + * @since 3.1.3 */ @Parameter(property = "classifier") - private String classifier; + public void setClassifier(String classifier) { + paramArtifact.setClassifier(classifier); + } /** - * The packaging of the artifact to download. Ignored if {@link #artifact} is used. + * The packaging of the artifact to download. Ignored if {@code artifact} is used. + * + * @since 3.1.3 */ @Parameter(property = "packaging", defaultValue = "jar") - private String packaging = "jar"; + public void setPackaging(String packaging) { + paramArtifact.setPackaging(packaging); + } /** - * Repositories in the format id::[layout]::url or just URLs, separated by comma. That is, - * central::default::https://repo.maven.apache.org/maven2,myrepo::::https://repo.acme.com,https://repo.acme2.com + * A string of the form {@code groupId:artifactId:version[:packaging[:classifier]]}. + * + * @since 3.1.3 */ - @Parameter(property = "remoteRepositories") - private String remoteRepositories; + @Parameter(property = "artifact") + public void setArtifact(String artifact) { + paramArtifact.setArtifact(artifact); + } /** - * A string of the form groupId:artifactId:version[:packaging[:classifier]]. + * Repositories in the format {@code id::[layout::]url} or just URLs. That is, + * <code> + * central::default::https://repo.maven.apache.org/maven2,myrepo::https://repo.acme.com,https://repo.acme2.com + * </code> + * + * @since 3.1.3 */ - @Parameter(property = "artifact") - private String artifact; - - @Parameter(defaultValue = "${project.remoteArtifactRepositories}", readonly = true, required = true) - private List<ArtifactRepository> pomRemoteRepositories; + @Parameter(property = "remoteRepositories") + private List<String> remoteRepositories; /** * Download transitively, retrieving the specified artifact and all of its dependencies. + * + * @since 3.1.3 */ @Parameter(property = "transitive", defaultValue = "false") private boolean transitive = false; /** * Skip plugin execution completely. + * + * @since 3.6.0 */ @Parameter(property = "mdep.skip", defaultValue = "false") private boolean skip; @@ -155,30 +144,35 @@ public class ListClassesMojo extends AbstractMojo { return; } - ProjectBuildingRequest buildingRequest = makeBuildingRequest(); + if (!paramArtifact.isDataSet()) { + throw new MojoExecutionException("You must specify an artifact OR GAV separately, " + + "e.g. -Dartifact=org.apache.maven.plugins:maven-downloader-plugin:1.0 OR " + + "-DgroupId=org.apache.maven.plugins -DartifactId=maven-downloader-plugin -Dversion=1.0"); + } + + Artifact artifact = resolverUtil.createArtifactFromParams(paramArtifact); try { if (transitive) { - Iterable<ArtifactResult> artifacts = - dependencyResolver.resolveDependencies(buildingRequest, coordinate, null); + List<Artifact> artifacts = + resolverUtil.resolveDependencies(artifact, resolverUtil.remoteRepositories(remoteRepositories)); - for (ArtifactResult result : artifacts) { - printClassesFromArtifactResult(result); + for (Artifact a : artifacts) { + printClassesFromArtifactResult(a.getFile()); } } else { - ArtifactResult result = - artifactResolver.resolveArtifact(buildingRequest, toArtifactCoordinate(coordinate)); - - printClassesFromArtifactResult(result); + Artifact a = + resolverUtil.resolveArtifact(artifact, resolverUtil.remoteRepositories(remoteRepositories)); + printClassesFromArtifactResult(a.getFile()); } - } catch (ArtifactResolverException | DependencyResolverException | IOException e) { + } catch (IOException | ArtifactResolutionException | DependencyResolutionException e) { throw new MojoExecutionException("Couldn't download artifact: " + e.getMessage(), e); } } - private void printClassesFromArtifactResult(ArtifactResult result) throws IOException { + private void printClassesFromArtifactResult(File file) throws IOException { // open jar file in try-with-resources statement to guarantee the file closes after use regardless of errors - try (JarFile jarFile = new JarFile(result.getArtifact().getFile())) { + try (JarFile jarFile = new JarFile(file)) { Enumeration<JarEntry> entries = jarFile.entries(); while (entries.hasMoreElements()) { @@ -197,111 +191,4 @@ public class ListClassesMojo extends AbstractMojo { } } } - - boolean hasGAVSpecified() { - return artifact != null || (groupId != null && artifactId != null && version != null); - } - - private ProjectBuildingRequest makeBuildingRequest() throws MojoExecutionException, MojoFailureException { - if (!hasGAVSpecified()) { - throw new MojoFailureException("You must specify an artifact OR GAV separately, " - + "e.g. -Dartifact=org.apache.maven.plugins:maven-downloader-plugin:1.0 OR " - + "-DgroupId=org.apache.maven.plugins -DartifactId=maven-downloader-plugin -Dversion=1.0"); - } - - String[] tokens = artifact != null - ? artifact.split(":") - : classifier != null - ? new String[] {groupId, artifactId, version, packaging, classifier} - : packaging != null - ? new String[] {groupId, artifactId, version, packaging} - : new String[] {groupId, artifactId, version}; - if (tokens.length < 3 || tokens.length > 5) { - throw new MojoFailureException("Invalid artifact, you must specify " - + "groupId:artifactId:version[:packaging[:classifier]] " + artifact); - } - coordinate.setGroupId(tokens[0]); - coordinate.setArtifactId(tokens[1]); - coordinate.setVersion(tokens[2]); - if (tokens.length >= 4) { - coordinate.setType(tokens[3]); - } - if (tokens.length == 5) { - coordinate.setClassifier(tokens[4]); - } - - ArtifactRepositoryPolicy always = new ArtifactRepositoryPolicy( - true, ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS, ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN); - - List<ArtifactRepository> repoList = new ArrayList<>(); - - if (pomRemoteRepositories != null) { - repoList.addAll(pomRemoteRepositories); - } - - if (remoteRepositories != null) { - // Use the same format as in the deploy plugin id::layout::url - String[] repos = remoteRepositories.split(","); - for (String repo : repos) { - repoList.add(parseRepository(repo, always)); - } - } - - ProjectBuildingRequest buildingRequest = new DefaultProjectBuildingRequest(session.getProjectBuildingRequest()); - - Settings settings = session.getSettings(); - repositorySystem.injectMirror(repoList, settings.getMirrors()); - repositorySystem.injectProxy(repoList, settings.getProxies()); - repositorySystem.injectAuthentication(repoList, settings.getServers()); - - buildingRequest.setRemoteRepositories(repoList); - - return buildingRequest; - } - - private ArtifactCoordinate toArtifactCoordinate(DependableCoordinate dependableCoordinate) { - ArtifactHandler artifactHandler = artifactHandlerManager.getArtifactHandler(dependableCoordinate.getType()); - DefaultArtifactCoordinate artifactCoordinate = new DefaultArtifactCoordinate(); - artifactCoordinate.setGroupId(dependableCoordinate.getGroupId()); - artifactCoordinate.setArtifactId(dependableCoordinate.getArtifactId()); - artifactCoordinate.setVersion(dependableCoordinate.getVersion()); - artifactCoordinate.setClassifier(dependableCoordinate.getClassifier()); - artifactCoordinate.setExtension(artifactHandler.getExtension()); - return artifactCoordinate; - } - - protected ArtifactRepository parseRepository(String repo, ArtifactRepositoryPolicy policy) - throws MojoFailureException { - // if it's a simple url - String id = "temp"; - ArtifactRepositoryLayout layout = getLayout("default"); - - // if it's an extended repo URL of the form id::layout::url - if (repo.contains("::")) { - Matcher matcher = ALT_REPO_SYNTAX_PATTERN.matcher(repo); - if (!matcher.matches()) { - throw new MojoFailureException( - repo, - "Invalid syntax for repository: " + repo, - "Invalid syntax for repository. Use \"id::layout::url\" or \"URL\"."); - } - - id = matcher.group(1).trim(); - if (!(matcher.group(2) == null || matcher.group(2).trim().isEmpty())) { - layout = getLayout(matcher.group(2).trim()); - } - repo = matcher.group(3).trim(); - } - return new MavenArtifactRepository(id, repo, layout, policy, policy); - } - - private ArtifactRepositoryLayout getLayout(String id) throws MojoFailureException { - ArtifactRepositoryLayout layout = repositoryLayouts.get(id); - - if (layout == null) { - throw new MojoFailureException(id, "Invalid repository layout", "Invalid repository layout: " + id); - } - - return layout; - } } diff --git a/src/main/java/org/apache/maven/plugins/dependency/utils/ParamArtifact.java b/src/main/java/org/apache/maven/plugins/dependency/utils/ParamArtifact.java new file mode 100644 index 00000000..1727c485 --- /dev/null +++ b/src/main/java/org/apache/maven/plugins/dependency/utils/ParamArtifact.java @@ -0,0 +1,91 @@ +/* + * 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. + */ +package org.apache.maven.plugins.dependency.utils; + +/** + * Represent artifact data collected from Mojo parameters + */ +public class ParamArtifact { + private String groupId; + + private String artifactId; + + private String version; + + private String classifier; + + private String packaging; + + private String artifact; + + public String getGroupId() { + return groupId; + } + + public String getArtifactId() { + return artifactId; + } + + public String getVersion() { + return version; + } + + public String getClassifier() { + return classifier; + } + + public String getPackaging() { + return packaging; + } + + public String getArtifact() { + return artifact; + } + + public void setGroupId(String groupId) { + this.groupId = groupId; + } + + public void setArtifactId(String artifactId) { + this.artifactId = artifactId; + } + + public void setVersion(String version) { + this.version = version; + } + + public void setClassifier(String classifier) { + this.classifier = classifier; + } + + public void setPackaging(String packaging) { + this.packaging = packaging; + } + + public void setArtifact(String artifact) { + this.artifact = artifact; + } + + /** + * Determinate if all needed data is set + */ + public boolean isDataSet() { + return artifact != null || (groupId != null && artifactId != null && version != 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 6138ddd1..d661377f 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 @@ -23,14 +23,31 @@ import javax.inject.Named; import javax.inject.Provider; import javax.inject.Singleton; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; import org.apache.maven.execution.MavenSession; import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.ArtifactType; +import org.eclipse.aether.artifact.ArtifactTypeRegistry; +import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.collection.CollectRequest; import org.eclipse.aether.collection.CollectResult; import org.eclipse.aether.collection.DependencyCollectionException; import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.repository.RepositoryPolicy; +import org.eclipse.aether.resolution.ArtifactRequest; +import org.eclipse.aether.resolution.ArtifactResolutionException; +import org.eclipse.aether.resolution.ArtifactResult; +import org.eclipse.aether.resolution.DependencyRequest; +import org.eclipse.aether.resolution.DependencyResolutionException; +import org.eclipse.aether.resolution.DependencyResult; import org.eclipse.aether.util.graph.visitor.PreorderNodeListGenerator; /** @@ -45,7 +62,7 @@ public class ResolverUtil { private final Provider<MavenSession> mavenSessionProvider; @Inject - private ResolverUtil(RepositorySystem repositorySystem, Provider<MavenSession> mavenSessionProvider) { + public ResolverUtil(RepositorySystem repositorySystem, Provider<MavenSession> mavenSessionProvider) { this.repositorySystem = repositorySystem; this.mavenSessionProvider = mavenSessionProvider; } @@ -68,4 +85,152 @@ public class ResolverUtil { result.getRoot().accept(nodeListGenerator); return nodeListGenerator.getDependencies(true); } + + /** + * Resolve given artifact + * + * @param artifact an artifact to resolve + * @param repositories remote repositories list + * @return resolved artifact + * @throws ArtifactResolutionException If the artifact could not be resolved. + */ + public Artifact resolveArtifact(Artifact artifact, List<RemoteRepository> repositories) + throws ArtifactResolutionException { + MavenSession session = mavenSessionProvider.get(); + ArtifactRequest request = new ArtifactRequest(artifact, repositories, null); + ArtifactResult result = repositorySystem.resolveArtifact(session.getRepositorySession(), request); + return result.getArtifact(); + } + + /** + * Resolve transitive dependencies for artifact. + * + * @param artifact an artifact to resolve + * @param repositories remote repositories list + * @return list of transitive dependencies for artifact + * @throws DependencyResolutionException If the dependency tree could not be built or any dependency artifact could + * not be resolved. + */ + public List<Artifact> resolveDependencies(Artifact artifact, List<RemoteRepository> repositories) + throws DependencyResolutionException { + MavenSession session = mavenSessionProvider.get(); + + CollectRequest collectRequest = new CollectRequest(new Dependency(artifact, null), repositories); + DependencyRequest request = new DependencyRequest(collectRequest, null); + DependencyResult result = repositorySystem.resolveDependencies(session.getRepositorySession(), request); + return result.getArtifactResults().stream() + .map(ArtifactResult::getArtifact) + .collect(Collectors.toList()); + } + + /** + * Prepare a remote repositories list for given descriptions. + * + * @param repositories remote repositories descriptions + * @return a list of remote repositories + */ + public List<RemoteRepository> remoteRepositories(List<String> repositories) { + MavenSession mavenSession = mavenSessionProvider.get(); + List<RemoteRepository> projectRepositories = + mavenSession.getCurrentProject().getRemoteProjectRepositories(); + if (repositories == null || repositories.isEmpty()) { + return projectRepositories; + } + + List<RemoteRepository> repositoriesList = + repositories.stream().map(this::prepareRemoteRepository).collect(Collectors.toList()); + repositoriesList = + repositorySystem.newResolutionRepositories(mavenSession.getRepositorySession(), repositoriesList); + + List<RemoteRepository> result = new ArrayList<>(projectRepositories); + result.addAll(repositoriesList); + return result; + } + + // protected for testing purpose + protected RemoteRepository prepareRemoteRepository(String repository) { + String[] items = Objects.requireNonNull(repository, "repository must be not null") + .split("::"); + String id = "temp"; + String type = null; + String url; + switch (items.length) { + case 3: + id = items[0]; + type = items[1]; + url = items[2]; + break; + case 2: + id = items[0]; + url = items[1]; + break; + case 1: + url = items[0]; + break; + default: + throw new IllegalArgumentException("Invalid repository: " + repository); + } + + if (type == null || type.isEmpty()) { + type = "default"; + } + + MavenSession mavenSession = mavenSessionProvider.get(); + RepositorySystemSession repositorySession = mavenSession.getRepositorySession(); + + String checksumPolicy = repositorySession.getChecksumPolicy(); + if (checksumPolicy == null) { + checksumPolicy = RepositoryPolicy.CHECKSUM_POLICY_WARN; + } + String updatePolicy = + mavenSession.getRequest().isUpdateSnapshots() ? RepositoryPolicy.UPDATE_POLICY_ALWAYS : null; + RepositoryPolicy repositoryPolicy = new RepositoryPolicy(true, updatePolicy, checksumPolicy); + + RemoteRepository.Builder builder = new RemoteRepository.Builder(id, type, url); + builder.setReleasePolicy(repositoryPolicy); + builder.setSnapshotPolicy(repositoryPolicy); + + return builder.build(); + } + + /** + * Create an artifact based on configuration from Mojo. + * + * @param paramArtifact an artifact configuration + * @return new artifact + */ + public Artifact createArtifactFromParams(ParamArtifact paramArtifact) { + Objects.requireNonNull(paramArtifact); + if (paramArtifact.getArtifact() != null) { + return createArtifactFromString(paramArtifact.getArtifact()); + } else { + ArtifactType artifactType = getArtifactType(paramArtifact.getPackaging()); + return new DefaultArtifact( + paramArtifact.getGroupId(), + paramArtifact.getArtifactId(), + paramArtifact.getClassifier(), + artifactType.getExtension(), + paramArtifact.getVersion(), + artifactType); + } + } + + private Artifact createArtifactFromString(String artifact) { + // groupId:artifactId:version[:packaging[:classifier]]. + String[] items = artifact.split(":"); + if (items.length < 3) { + throw new IllegalArgumentException("Invalid artifact format: " + artifact); + } + + ArtifactType artifactType = getArtifactType(items.length > 3 ? items[3] : null); + String classifier = items.length > 4 ? items[4] : null; + + return new DefaultArtifact(items[0], items[1], classifier, artifactType.getExtension(), items[2], artifactType); + } + + private ArtifactType getArtifactType(String packaging) { + ArtifactTypeRegistry artifactTypeRegistry = + mavenSessionProvider.get().getRepositorySession().getArtifactTypeRegistry(); + return artifactTypeRegistry.get(packaging != null ? packaging : "jar"); + } } diff --git a/src/test/java/org/apache/maven/plugins/dependency/AbstractDependencyMojoTestCase.java b/src/test/java/org/apache/maven/plugins/dependency/AbstractDependencyMojoTestCase.java index 64ecd542..0a4d55cc 100644 --- a/src/test/java/org/apache/maven/plugins/dependency/AbstractDependencyMojoTestCase.java +++ b/src/test/java/org/apache/maven/plugins/dependency/AbstractDependencyMojoTestCase.java @@ -29,6 +29,7 @@ import org.apache.maven.plugins.dependency.testUtils.DependencyArtifactStubFacto import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositorySystem; +import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.LocalRepositoryManager; @@ -79,4 +80,12 @@ public abstract class AbstractDependencyMojoTestCase extends AbstractMojoTestCas LocalRepositoryManager manager = system.newLocalRepositoryManager(repoSession, localRepository); repoSession.setLocalRepositoryManager(manager); } + + protected void installLocalRepository(RepositorySystemSession repoSession) throws ComponentLookupException { + RepositorySystem system = lookup(RepositorySystem.class); + String directory = stubFactory.getWorkingDir().toString(); + LocalRepository localRepository = new LocalRepository(directory); + LocalRepositoryManager manager = system.newLocalRepositoryManager(repoSession, localRepository); + ((DefaultRepositorySystemSession) repoSession).setLocalRepositoryManager(manager); + } } diff --git a/src/test/java/org/apache/maven/plugins/dependency/TestListClassesMojo.java b/src/test/java/org/apache/maven/plugins/dependency/TestListClassesMojo.java index 92cf2d68..0d79086f 100644 --- a/src/test/java/org/apache/maven/plugins/dependency/TestListClassesMojo.java +++ b/src/test/java/org/apache/maven/plugins/dependency/TestListClassesMojo.java @@ -22,15 +22,15 @@ import java.io.File; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Arrays; import java.util.List; import org.apache.maven.execution.MavenSession; -import org.apache.maven.plugin.LegacySupport; import org.apache.maven.plugin.logging.Log; import org.apache.maven.plugins.dependency.testUtils.stubs.DependencyProjectStub; +import org.apache.maven.plugins.dependency.utils.ResolverUtil; import org.apache.maven.project.MavenProject; -import org.apache.maven.settings.Server; -import org.apache.maven.settings.Settings; +import org.eclipse.aether.RepositorySystem; import org.junit.Assert; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @@ -45,6 +45,11 @@ public class TestListClassesMojo extends AbstractDependencyMojoTestCase { getContainer().addComponent(project, MavenProject.class.getName()); MavenSession session = newMavenSession(project); + + RepositorySystem repositorySystem = lookup(RepositorySystem.class); + ResolverUtil resolverUtil = new ResolverUtil(repositorySystem, () -> session); + getContainer().addComponent(resolverUtil, ResolverUtil.class.getName()); + getContainer().addComponent(session, MavenSession.class.getName()); File testPom = new File(getBasedir(), "target/test-classes/unit/get-test/plugin-config.xml"); @@ -54,16 +59,7 @@ public class TestListClassesMojo extends AbstractDependencyMojoTestCase { assertNotNull(mojo); - LegacySupport legacySupport = lookup(LegacySupport.class); - Settings settings = session.getSettings(); - Server server = new Server(); - server.setId("myserver"); - server.setUsername("foo"); - server.setPassword("bar"); - settings.addServer(server); - legacySupport.setSession(session); - - installLocalRepository(legacySupport); + installLocalRepository(session.getRepositorySession()); } public void testListClassesNotTransitive() throws Exception { @@ -74,9 +70,11 @@ public class TestListClassesMojo extends AbstractDependencyMojoTestCase { setVariableValueToObject( mojo, "remoteRepositories", - "central::default::https://repo.maven.apache.org/maven2," - + "central::::https://repo.maven.apache.org/maven2," + "https://repo.maven.apache.org/maven2"); - setVariableValueToObject(mojo, "artifact", "org.apache.commons:commons-lang3:3.6"); + Arrays.asList( + "central::default::https://repo.maven.apache.org/maven2", + "central::::https://repo.maven.apache.org/maven2", + "https://repo.maven.apache.org/maven2")); + mojo.setArtifact("org.apache.commons:commons-lang3:3.6"); setVariableValueToObject(mojo, "transitive", Boolean.FALSE); Log log = Mockito.mock(Log.class); @@ -96,11 +94,15 @@ public class TestListClassesMojo extends AbstractDependencyMojoTestCase { setVariableValueToObject( mojo, "remoteRepositories", - "central::default::https://repo.maven.apache.org/maven2," - + "central::::https://repo.maven.apache.org/maven2," + "https://repo.maven.apache.org/maven2"); - setVariableValueToObject(mojo, "groupId", "org.apache.commons"); - setVariableValueToObject(mojo, "artifactId", "commons-lang3"); - setVariableValueToObject(mojo, "version", "3.6"); + Arrays.asList( + "central1::default::https://repo.maven.apache.org/maven2", + "central2::::https://repo.maven.apache.org/maven2", + "https://repo.maven.apache.org/maven2")); + + mojo.setGroupId("org.apache.commons"); + mojo.setArtifactId("commons-lang3"); + mojo.setVersion("3.6"); + setVariableValueToObject(mojo, "transitive", Boolean.FALSE); Log log = Mockito.mock(Log.class); @@ -120,9 +122,12 @@ public class TestListClassesMojo extends AbstractDependencyMojoTestCase { setVariableValueToObject( mojo, "remoteRepositories", - "central::default::https://repo.maven.apache.org/maven2," - + "central::::https://repo.maven.apache.org/maven2," + "https://repo.maven.apache.org/maven2"); - setVariableValueToObject(mojo, "artifact", "org.apache.commons:commons-lang3:3.6"); + Arrays.asList( + "central::default::https://repo.maven.apache.org/maven2", + "central::::https://repo.maven.apache.org/maven2", + "https://repo.maven.apache.org/maven2")); + + mojo.setArtifact("org.apache.commons:commons-lang3:3.6"); setVariableValueToObject(mojo, "transitive", Boolean.TRUE); Log log = Mockito.mock(Log.class); @@ -142,11 +147,13 @@ public class TestListClassesMojo extends AbstractDependencyMojoTestCase { setVariableValueToObject( mojo, "remoteRepositories", - "central::default::https://repo.maven.apache.org/maven2," - + "central::::https://repo.maven.apache.org/maven2," + "https://repo.maven.apache.org/maven2"); - setVariableValueToObject(mojo, "groupId", "org.apache.commons"); - setVariableValueToObject(mojo, "artifactId", "commons-lang3"); - setVariableValueToObject(mojo, "version", "3.6"); + Arrays.asList( + "central::default::https://repo.maven.apache.org/maven2", + "central::::https://repo.maven.apache.org/maven2", + "https://repo.maven.apache.org/maven2")); + mojo.setGroupId("org.apache.commons"); + mojo.setArtifactId("commons-lang3"); + mojo.setVersion("3.6"); setVariableValueToObject(mojo, "transitive", Boolean.TRUE); Log log = Mockito.mock(Log.class); diff --git a/src/test/java/org/apache/maven/plugins/dependency/testUtils/stubs/DependencyProjectStub.java b/src/test/java/org/apache/maven/plugins/dependency/testUtils/stubs/DependencyProjectStub.java index e48df87a..9edcfb35 100644 --- a/src/test/java/org/apache/maven/plugins/dependency/testUtils/stubs/DependencyProjectStub.java +++ b/src/test/java/org/apache/maven/plugins/dependency/testUtils/stubs/DependencyProjectStub.java @@ -59,6 +59,7 @@ import org.apache.maven.plugin.testing.stubs.DefaultArtifactHandlerStub; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.PlexusTestCase; import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.eclipse.aether.repository.RemoteRepository; /** * very simple stub of maven project, going to take a lot of work to make it useful as a stub though @@ -204,6 +205,11 @@ public class DependencyProjectStub extends MavenProject { return Collections.emptyList(); } + @Override + public List<RemoteRepository> getRemoteProjectRepositories() { + return Collections.emptyList(); + } + @Override public boolean hasParent() { return (parent != null); diff --git a/src/test/java/org/apache/maven/plugins/dependency/utils/ResolverUtilTest.java b/src/test/java/org/apache/maven/plugins/dependency/utils/ResolverUtilTest.java new file mode 100644 index 00000000..4359c694 --- /dev/null +++ b/src/test/java/org/apache/maven/plugins/dependency/utils/ResolverUtilTest.java @@ -0,0 +1,108 @@ +/* + * 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. + */ +package org.apache.maven.plugins.dependency.utils; + +import javax.inject.Provider; + +import java.util.stream.Stream; + +import org.apache.maven.execution.MavenExecutionRequest; +import org.apache.maven.execution.MavenSession; +import org.eclipse.aether.RepositorySystemSession; +import org.eclipse.aether.repository.RemoteRepository; +import org.eclipse.aether.repository.RepositoryPolicy; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.junit.jupiter.params.provider.Arguments.of; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class ResolverUtilTest { + + @Mock + private MavenExecutionRequest executionRequest; + + @Mock + private RepositorySystemSession repositorySystemSession; + + @Mock + private MavenSession mavenSession; + + @Mock + private Provider<MavenSession> sessionProvider; + + @InjectMocks + private ResolverUtil resolverUtil; + + public static Stream<Arguments> prepareRepositoryTest() { + + return Stream.of( + of("", "temp", "default", ""), + of("https://repo.maven.apache.org", "temp", "default", "https://repo.maven.apache.org"), + of("central::https://repo.maven.apache.org", "central", "default", "https://repo.maven.apache.org"), + of("central::::https://repo.maven.apache.org", "central", "default", "https://repo.maven.apache.org"), + of( + "central::layout2::https://repo.maven.apache.org", + "central", + "layout2", + "https://repo.maven.apache.org")); + } + + @ParameterizedTest + @MethodSource + void prepareRepositoryTest(String repository, String id, String type, String url) { + when(sessionProvider.get()).thenReturn(mavenSession); + when(mavenSession.getRepositorySession()).thenReturn(repositorySystemSession); + when(mavenSession.getRequest()).thenReturn(executionRequest); + when(executionRequest.isUpdateSnapshots()).thenReturn(true); + + RemoteRepository remoteRepository = resolverUtil.prepareRemoteRepository(repository); + + assertThat(remoteRepository).isNotNull(); + assertThat(remoteRepository.getId()).isEqualTo(id); + assertThat(remoteRepository.getContentType()).isEqualTo(type); + assertThat(remoteRepository.getUrl()).isEqualTo(url); + + RepositoryPolicy snapshotPolicy = remoteRepository.getPolicy(true); + assertThat(snapshotPolicy).isNotNull(); + assertThat(snapshotPolicy.getUpdatePolicy()).isEqualTo(RepositoryPolicy.UPDATE_POLICY_ALWAYS); + assertThat(snapshotPolicy.getChecksumPolicy()).isEqualTo(RepositoryPolicy.CHECKSUM_POLICY_WARN); + + RepositoryPolicy releasePolicy = remoteRepository.getPolicy(true); + assertThat(releasePolicy).isNotNull(); + assertThat(releasePolicy.getUpdatePolicy()).isEqualTo(RepositoryPolicy.UPDATE_POLICY_ALWAYS); + assertThat(releasePolicy.getChecksumPolicy()).isEqualTo(RepositoryPolicy.CHECKSUM_POLICY_WARN); + } + + @Test + void prepareRepositoryWithNull() { + assertThatCode(() -> resolverUtil.prepareRemoteRepository(null)) + .isExactlyInstanceOf(NullPointerException.class) + .hasMessage("repository must be not null"); + } +}