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