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