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