1 package org.apache.maven.plugin.surefire;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.Collection;
23 import java.util.Iterator;
24 import java.util.LinkedHashSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28
29 import org.apache.maven.artifact.Artifact;
30 import org.apache.maven.artifact.repository.ArtifactRepository;
31 import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
32 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
33 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
34 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
35 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
36 import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
37 import org.apache.maven.artifact.versioning.VersionRange;
38 import org.apache.maven.model.Dependency;
39 import org.apache.maven.plugin.MojoExecutionException;
40 import org.apache.maven.plugin.surefire.log.api.ConsoleLogger;
41 import org.apache.maven.project.ProjectBuildingRequest;
42 import org.apache.maven.repository.RepositorySystem;
43 import org.apache.maven.shared.artifact.filter.resolve.ScopeFilter;
44 import org.apache.maven.shared.transfer.artifact.resolve.ArtifactResult;
45 import org.apache.maven.shared.transfer.dependencies.resolve.DependencyResolver;
46 import org.apache.maven.shared.transfer.dependencies.resolve.DependencyResolverException;
47
48 import javax.annotation.Nonnull;
49 import javax.annotation.Nullable;
50
51 import static java.util.Arrays.asList;
52 import static org.apache.maven.artifact.Artifact.SCOPE_COMPILE;
53 import static org.apache.maven.artifact.Artifact.SCOPE_COMPILE_PLUS_RUNTIME;
54 import static org.apache.maven.artifact.Artifact.SCOPE_RUNTIME;
55 import static org.apache.maven.artifact.ArtifactUtils.artifactMapByVersionlessId;
56 import static org.apache.maven.artifact.versioning.VersionRange.createFromVersionSpec;
57
58
59
60
61
62
63
64 final class SurefireDependencyResolver
65 {
66 static final String PROVIDER_GROUP_ID = "org.apache.maven.surefire";
67
68 private static final String[] PROVIDER_CLASSPATH_ORDER = {
69 "surefire-junit3",
70 "surefire-junit4",
71 "surefire-junit47",
72 "surefire-testng",
73 "surefire-junit-platform",
74 "surefire-api",
75 "surefire-logger-api",
76 "common-java5",
77 "common-junit3",
78 "common-junit4",
79 "common-junit48",
80 "common-testng-utils"
81 };
82
83 private final RepositorySystem repositorySystem;
84
85 private final ConsoleLogger log;
86
87 private final ArtifactRepository localRepository;
88
89 private final List<ArtifactRepository> pluginRemoteRepositories;
90
91 private final List<ArtifactRepository> projectRemoteRepositories;
92
93 private final String pluginName;
94
95 private final DependencyResolver depencencyResolver;
96
97 SurefireDependencyResolver( RepositorySystem repositorySystem, ConsoleLogger log,
98 ArtifactRepository localRepository,
99 List<ArtifactRepository> pluginRemoteRepositories,
100 List<ArtifactRepository> projectRemoteRepositories, String pluginName,
101 DependencyResolver depencencyResolver )
102 {
103 this.repositorySystem = repositorySystem;
104 this.log = log;
105 this.localRepository = localRepository;
106 this.pluginRemoteRepositories = pluginRemoteRepositories;
107 this.projectRemoteRepositories = projectRemoteRepositories;
108 this.pluginName = pluginName;
109 this.depencencyResolver = depencencyResolver;
110 }
111
112 static boolean isWithinVersionSpec( @Nullable Artifact artifact, @Nonnull String versionSpec )
113 {
114 if ( artifact == null )
115 {
116 return false;
117 }
118 try
119 {
120 VersionRange range = createFromVersionSpec( versionSpec );
121 try
122 {
123 return range.containsVersion( artifact.getSelectedVersion() );
124 }
125 catch ( NullPointerException e )
126 {
127 return range.containsVersion( new DefaultArtifactVersion( artifact.getBaseVersion() ) );
128 }
129 }
130 catch ( InvalidVersionSpecificationException | OverConstrainedVersionException e )
131 {
132 throw new RuntimeException( "Bug in plugin. Please report with stacktrace" );
133 }
134 }
135
136 Set<Artifact> resolvePluginDependencies( ProjectBuildingRequest request, Collection<Dependency> pluginDependencies )
137 throws MojoExecutionException
138 {
139 try
140 {
141 Iterable<ArtifactResult> resolvedPluginDependencies = depencencyResolver.resolveDependencies( request,
142 pluginDependencies, null, ScopeFilter.including( SCOPE_COMPILE, SCOPE_RUNTIME ) );
143
144 Set<Artifact> resolved = new LinkedHashSet<>();
145 for ( ArtifactResult resolvedPluginDependency : resolvedPluginDependencies )
146 {
147 resolved.add( resolvedPluginDependency.getArtifact() );
148 }
149 return resolved;
150 }
151 catch ( DependencyResolverException e )
152 {
153 throw new MojoExecutionException( e.getLocalizedMessage(), e );
154 }
155 }
156
157 ArtifactResolutionResult resolvePluginArtifact( Artifact artifact )
158 {
159 return resolveArtifact( artifact, pluginRemoteRepositories );
160 }
161
162 ArtifactResolutionResult resolveProjectArtifact( Artifact artifact )
163 {
164 return resolveArtifact( artifact, projectRemoteRepositories );
165 }
166
167 private ArtifactResolutionResult resolveArtifact( Artifact artifact, List<ArtifactRepository> repositories )
168 {
169 ArtifactResolutionRequest request = new ArtifactResolutionRequest()
170 .setArtifact( artifact )
171 .setLocalRepository( localRepository )
172 .setResolveTransitively( true )
173 .setCollectionFilter( new RuntimeArtifactFilter() )
174 .setRemoteRepositories( repositories );
175
176 return repositorySystem.resolve( request );
177 }
178
179 @Nonnull
180 Set<Artifact> getProviderClasspath( String providerArtifactId, String providerVersion )
181 {
182 Dependency provider = toProviderDependency( providerArtifactId, providerVersion );
183
184 Artifact providerArtifact = repositorySystem.createDependencyArtifact( provider );
185
186 ArtifactResolutionResult result = resolvePluginArtifact( providerArtifact );
187
188 if ( log.isDebugEnabled() )
189 {
190 for ( Artifact artifact : result.getArtifacts() )
191 {
192 String artifactPath = artifact.getFile().getAbsolutePath();
193 String scope = artifact.getScope();
194 log.debug( "Adding to " + pluginName + " test classpath: " + artifactPath + " Scope: " + scope );
195 }
196 }
197
198 return orderProviderArtifacts( result.getArtifacts() );
199 }
200
201 @Nonnull
202 Map<String, Artifact> getProviderClasspathAsMap( String providerArtifactId, String providerVersion )
203 {
204 return artifactMapByVersionlessId( getProviderClasspath( providerArtifactId, providerVersion ) );
205 }
206
207 Set<Artifact> addProviderToClasspath( Map<String, Artifact> pluginArtifactMap, Artifact mojoPluginArtifact,
208 Artifact surefireApi, Artifact surefireLoggerApi )
209 {
210 Set<Artifact> providerArtifacts = new LinkedHashSet<>();
211 ArtifactResolutionResult artifactResolutionResult = resolvePluginArtifact( mojoPluginArtifact );
212 for ( Artifact artifact : pluginArtifactMap.values() )
213 {
214 if ( !artifactResolutionResult.getArtifacts().contains( artifact ) )
215 {
216 providerArtifacts.add( artifact );
217 for ( Artifact dependency : resolvePluginArtifact( artifact ).getArtifacts() )
218 {
219 String groupId = dependency.getGroupId();
220 String artifactId = dependency.getArtifactId();
221 if ( groupId.equals( surefireApi.getGroupId() )
222 && artifactId.equals( surefireApi.getArtifactId() ) )
223 {
224 providerArtifacts.add( surefireApi );
225 }
226 else if ( groupId.equals( surefireLoggerApi.getGroupId() )
227 && artifactId.equals( surefireLoggerApi.getArtifactId() ) )
228 {
229 providerArtifacts.add( surefireLoggerApi );
230 }
231 }
232 }
233 }
234 return orderProviderArtifacts( providerArtifacts );
235 }
236
237 private static Set<Artifact> orderProviderArtifacts( Set<Artifact> providerArtifacts )
238 {
239 Set<Artifact> orderedProviderArtifacts = new LinkedHashSet<>();
240 for ( String order : PROVIDER_CLASSPATH_ORDER )
241 {
242 Iterator<Artifact> providerArtifactsIt = providerArtifacts.iterator();
243 while ( providerArtifactsIt.hasNext() )
244 {
245 Artifact providerArtifact = providerArtifactsIt.next();
246 if ( providerArtifact.getArtifactId().equals( order ) )
247 {
248 orderedProviderArtifacts.add( providerArtifact );
249 providerArtifactsIt.remove();
250 }
251 }
252 }
253 orderedProviderArtifacts.addAll( providerArtifacts );
254 return orderedProviderArtifacts;
255 }
256
257 private static Dependency toProviderDependency( String providerArtifactId, String providerVersion )
258 {
259 Dependency dependency = new Dependency();
260 dependency.setGroupId( PROVIDER_GROUP_ID );
261 dependency.setArtifactId( providerArtifactId );
262 dependency.setVersion( providerVersion );
263 dependency.setType( "jar" );
264 return dependency;
265 }
266
267 static class RuntimeArtifactFilter implements ArtifactFilter
268 {
269 private static final Collection<String> SCOPES =
270 asList( SCOPE_COMPILE, SCOPE_COMPILE_PLUS_RUNTIME, SCOPE_RUNTIME );
271
272 @Override
273 public boolean include( Artifact artifact )
274 {
275 String scope = artifact.getScope();
276 return !artifact.isOptional() && ( scope == null || SCOPES.contains( scope ) );
277 }
278 }
279 }