1 package org.apache.maven.plugin.dependency.analyze;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.HashSet;
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.model.Dependency;
31 import org.apache.maven.model.DependencyManagement;
32 import org.apache.maven.model.Exclusion;
33 import org.apache.maven.plugin.AbstractMojo;
34 import org.apache.maven.plugin.MojoExecutionException;
35 import org.apache.maven.plugin.MojoFailureException;
36 import org.apache.maven.plugins.annotations.Mojo;
37 import org.apache.maven.plugins.annotations.Parameter;
38 import org.apache.maven.plugins.annotations.ResolutionScope;
39 import org.apache.maven.project.MavenProject;
40 import org.codehaus.plexus.util.StringUtils;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 @Mojo( name = "analyze-dep-mgt", requiresDependencyResolution = ResolutionScope.TEST, threadSafe = true )
57 public class AnalyzeDepMgt
58 extends AbstractMojo
59 {
60
61
62
63
64
65 @Parameter( defaultValue = "${project}", readonly = true, required = true )
66 private MavenProject project;
67
68
69
70
71 @Parameter( property = "mdep.analyze.failBuild", defaultValue = "false" )
72 private boolean failBuild = false;
73
74
75
76
77 @Parameter( property = "mdep.analyze.ignore.direct", defaultValue = "true" )
78 private boolean ignoreDirect = true;
79
80
81
82
83
84
85 @Parameter( property = "mdep.analyze.skip", defaultValue = "false" )
86 private boolean skip;
87
88
89
90
91
92
93 public void execute()
94 throws MojoExecutionException, MojoFailureException
95 {
96 if ( isSkip() )
97 {
98 getLog().info( "Skipping plugin execution" );
99 return;
100 }
101
102 boolean result = checkDependencyManagement();
103 if ( result )
104 {
105 if ( this.failBuild )
106
107 {
108 throw new MojoExecutionException( "Found Dependency errors." );
109 }
110 else
111 {
112 getLog().warn( "Potential problems found in Dependency Management " );
113 }
114 }
115 }
116
117
118
119
120
121
122
123 private boolean checkDependencyManagement()
124 throws MojoExecutionException
125 {
126 boolean foundError = false;
127
128 getLog().info( "Found Resolved Dependency / DependencyManagement mismatches:" );
129
130 List<Dependency> depMgtDependencies = null;
131
132 DependencyManagement depMgt = project.getDependencyManagement();
133 if ( depMgt != null )
134 {
135 depMgtDependencies = depMgt.getDependencies();
136 }
137
138 if ( depMgtDependencies != null && !depMgtDependencies.isEmpty() )
139 {
140
141 Map<String, Dependency> depMgtMap = new HashMap<String, Dependency>();
142 Map<String, Exclusion> exclusions = new HashMap<String, Exclusion>();
143 for ( Dependency depMgtDependency : depMgtDependencies )
144 {
145 depMgtMap.put( depMgtDependency.getManagementKey(), depMgtDependency );
146
147
148 exclusions.putAll( addExclusions( depMgtDependency.getExclusions() ) );
149 }
150
151
152 @SuppressWarnings( "unchecked" ) Set<Artifact> allDependencyArtifacts =
153 new HashSet<Artifact>( project.getArtifacts() );
154
155
156
157 if ( this.ignoreDirect )
158 {
159 getLog().info( "\tIgnoring Direct Dependencies." );
160 @SuppressWarnings( "unchecked" ) Set<Artifact> directDependencies = project.getDependencyArtifacts();
161 allDependencyArtifacts.removeAll( directDependencies );
162 }
163
164
165 List<Artifact> exclusionErrors = getExclusionErrors( exclusions, allDependencyArtifacts );
166 for ( Artifact exclusion : exclusionErrors )
167 {
168 getLog().info( StringUtils.stripEnd( getArtifactManagementKey( exclusion ), ":" )
169 + " was excluded in DepMgt, but version " + exclusion.getVersion()
170 + " has been found in the dependency tree." );
171 foundError = true;
172 }
173
174
175 Map<Artifact, Dependency> mismatch = getMismatch( depMgtMap, allDependencyArtifacts );
176 for ( Map.Entry<Artifact, Dependency> entry : mismatch.entrySet() )
177 {
178 logMismatch( entry.getKey(), entry.getValue() );
179 foundError = true;
180 }
181 if ( !foundError )
182 {
183 getLog().info( " None" );
184 }
185 }
186 else
187 {
188 getLog().info( " Nothing in DepMgt." );
189 }
190
191 return foundError;
192 }
193
194
195
196
197
198
199
200
201
202 public Map<String, Exclusion> addExclusions( List<Exclusion> exclusionList )
203 {
204 Map<String, Exclusion> exclusions = new HashMap<String, Exclusion>();
205 if ( exclusionList != null )
206 {
207 for ( Exclusion exclusion : exclusionList )
208 {
209 exclusions.put( getExclusionKey( exclusion ), exclusion );
210 }
211 }
212 return exclusions;
213 }
214
215
216
217
218
219
220
221
222
223
224 public List<Artifact> getExclusionErrors( Map<String, Exclusion> exclusions, Set<Artifact> allDependencyArtifacts )
225 {
226 List<Artifact> list = new ArrayList<Artifact>();
227
228 for ( Artifact artifact : allDependencyArtifacts )
229 {
230 if ( exclusions.containsKey( getExclusionKey( artifact ) ) )
231 {
232 list.add( artifact );
233 }
234 }
235
236 return list;
237 }
238
239 public String getExclusionKey( Artifact artifact )
240 {
241 return artifact.getGroupId() + ":" + artifact.getArtifactId();
242 }
243
244 public String getExclusionKey( Exclusion ex )
245 {
246 return ex.getGroupId() + ":" + ex.getArtifactId();
247 }
248
249
250
251
252
253
254
255
256
257
258
259 public Map<Artifact, Dependency> getMismatch( Map<String, Dependency> depMgtMap,
260 Set<Artifact> allDependencyArtifacts )
261 {
262 Map<Artifact, Dependency> mismatchMap = new HashMap<Artifact, Dependency>();
263
264 for ( Artifact dependencyArtifact : allDependencyArtifacts )
265 {
266 Dependency depFromDepMgt = depMgtMap.get( getArtifactManagementKey( dependencyArtifact ) );
267 if ( depFromDepMgt != null )
268 {
269
270 dependencyArtifact.isSnapshot();
271
272 if ( !depFromDepMgt.getVersion().equals( dependencyArtifact.getBaseVersion() ) )
273 {
274 mismatchMap.put( dependencyArtifact, depFromDepMgt );
275 }
276 }
277 }
278 return mismatchMap;
279 }
280
281
282
283
284
285
286
287
288
289 public void logMismatch( Artifact dependencyArtifact, Dependency dependencyFromDepMgt )
290 throws MojoExecutionException
291 {
292 if ( dependencyArtifact == null || dependencyFromDepMgt == null )
293 {
294 throw new MojoExecutionException(
295 "Invalid params: Artifact:" + dependencyArtifact + " Dependency:" + dependencyFromDepMgt );
296 }
297
298 getLog().info( "\tDependency: " + StringUtils.stripEnd( dependencyFromDepMgt.getManagementKey(), ":" ) );
299 getLog().info( "\t\tDepMgt : " + dependencyFromDepMgt.getVersion() );
300 getLog().info( "\t\tResolved: " + dependencyArtifact.getBaseVersion() );
301 }
302
303
304
305
306
307
308
309 public String getArtifactManagementKey( Artifact artifact )
310 {
311 return artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getType() + ( (
312 artifact.getClassifier() != null ) ? ":" + artifact.getClassifier() : "" );
313 }
314
315
316
317
318 public boolean isFailBuild()
319 {
320 return this.failBuild;
321 }
322
323
324
325
326 public void setFailBuild( boolean theFailBuild )
327 {
328 this.failBuild = theFailBuild;
329 }
330
331
332
333
334 public MavenProject getProject()
335 {
336 return this.project;
337 }
338
339
340
341
342 public void setProject( MavenProject theProject )
343 {
344 this.project = theProject;
345 }
346
347
348
349
350 public boolean isIgnoreDirect()
351 {
352 return this.ignoreDirect;
353 }
354
355
356
357
358 public void setIgnoreDirect( boolean theIgnoreDirect )
359 {
360 this.ignoreDirect = theIgnoreDirect;
361 }
362
363 public boolean isSkip()
364 {
365 return skip;
366 }
367
368 public void setSkip( boolean skip )
369 {
370 this.skip = skip;
371 }
372 }