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