1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.enforcer.rules;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23
24 import java.util.ArrayList;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Map.Entry;
29 import java.util.Objects;
30
31 import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
32 import org.apache.maven.execution.MavenSession;
33 import org.apache.maven.model.Dependency;
34 import org.apache.maven.project.MavenProject;
35 import org.codehaus.plexus.util.StringUtils;
36
37
38
39
40
41
42
43 @Named("reactorModuleConvergence")
44 public final class ReactorModuleConvergence extends AbstractStandardEnforcerRule {
45 private static final String MODULE_TEXT = " module: ";
46
47 private boolean ignoreModuleDependencies = false;
48
49 private final MavenSession session;
50
51 @Inject
52 public ReactorModuleConvergence(MavenSession session) {
53 this.session = Objects.requireNonNull(session);
54 }
55
56 @Override
57 public void execute() throws EnforcerRuleException {
58
59 List<MavenProject> sortedProjects = session.getProjectDependencyGraph().getSortedProjects();
60 if (sortedProjects != null && !sortedProjects.isEmpty()) {
61 checkReactor(sortedProjects);
62 checkParentsInReactor(sortedProjects);
63 checkMissingParentsInReactor(sortedProjects);
64 checkParentsPartOfTheReactor(sortedProjects);
65 if (!isIgnoreModuleDependencies()) {
66 checkDependenciesWithinReactor(sortedProjects);
67 }
68 }
69 }
70
71 private void checkParentsPartOfTheReactor(List<MavenProject> sortedProjects) throws EnforcerRuleException {
72 List<MavenProject> parentsWhichAreNotPartOfTheReactor = existParentsWhichAreNotPartOfTheReactor(sortedProjects);
73 if (!parentsWhichAreNotPartOfTheReactor.isEmpty()) {
74 StringBuilder sb = new StringBuilder().append(System.lineSeparator());
75 addMessageIfExist(sb);
76 for (MavenProject mavenProject : parentsWhichAreNotPartOfTheReactor) {
77 sb.append(MODULE_TEXT);
78 sb.append(mavenProject.getId());
79 sb.append(System.lineSeparator());
80 }
81 throw new EnforcerRuleException(
82 "Module parents have been found which could not be found in the reactor." + sb);
83 }
84 }
85
86
87
88
89
90
91
92 private void checkMissingParentsInReactor(List<MavenProject> sortedProjects) throws EnforcerRuleException {
93 List<MavenProject> modulesWithoutParentsInReactor = existModulesWithoutParentsInReactor(sortedProjects);
94 if (!modulesWithoutParentsInReactor.isEmpty()) {
95 StringBuilder sb = new StringBuilder().append(System.lineSeparator());
96 addMessageIfExist(sb);
97 for (MavenProject mavenProject : modulesWithoutParentsInReactor) {
98 sb.append(MODULE_TEXT);
99 sb.append(mavenProject.getId());
100 sb.append(System.lineSeparator());
101 }
102 throw new EnforcerRuleException("Reactor contains modules without parents." + sb);
103 }
104 }
105
106 private void checkDependenciesWithinReactor(List<MavenProject> sortedProjects) throws EnforcerRuleException {
107
108 String reactorVersion = sortedProjects.get(0).getVersion();
109
110 Map<MavenProject, List<Dependency>> areThereDependenciesWhichAreNotPartOfTheReactor =
111 areThereDependenciesWhichAreNotPartOfTheReactor(reactorVersion, sortedProjects);
112 if (!areThereDependenciesWhichAreNotPartOfTheReactor.isEmpty()) {
113 StringBuilder sb = new StringBuilder().append(System.lineSeparator());
114 addMessageIfExist(sb);
115
116 for (Entry<MavenProject, List<Dependency>> item :
117 areThereDependenciesWhichAreNotPartOfTheReactor.entrySet()) {
118 sb.append(MODULE_TEXT);
119 sb.append(item.getKey().getId());
120 sb.append(System.lineSeparator());
121 for (Dependency dependency : item.getValue()) {
122 String id =
123 dependency.getGroupId() + ":" + dependency.getArtifactId() + ":" + dependency.getVersion();
124 sb.append(" dependency: ");
125 sb.append(id);
126 sb.append(System.lineSeparator());
127 }
128 }
129 throw new EnforcerRuleException(
130 "Reactor modules contains dependencies which do not reference the reactor." + sb);
131
132 }
133 }
134
135
136
137
138
139
140
141 private void checkParentsInReactor(List<MavenProject> sortedProjects) throws EnforcerRuleException {
142
143 String reactorVersion = sortedProjects.get(0).getVersion();
144
145 List<MavenProject> areParentsFromTheReactor = areParentsFromTheReactor(reactorVersion, sortedProjects);
146 if (!areParentsFromTheReactor.isEmpty()) {
147 StringBuilder sb = new StringBuilder().append(System.lineSeparator());
148 addMessageIfExist(sb);
149 for (MavenProject mavenProject : areParentsFromTheReactor) {
150 sb.append(" --> ");
151 sb.append(mavenProject.getId());
152 sb.append(" parent:");
153 sb.append(mavenProject.getParent().getId());
154 sb.append(System.lineSeparator());
155 }
156 throw new EnforcerRuleException("Reactor modules have parents which contain a wrong version." + sb);
157 }
158 }
159
160
161
162
163
164
165
166 private void checkReactor(List<MavenProject> sortedProjects) throws EnforcerRuleException {
167 List<MavenProject> consistenceCheckResult = isReactorVersionConsistent(sortedProjects);
168 if (!consistenceCheckResult.isEmpty()) {
169 StringBuilder sb = new StringBuilder().append(System.lineSeparator());
170 addMessageIfExist(sb);
171 for (MavenProject mavenProject : consistenceCheckResult) {
172 sb.append(" --> ");
173 sb.append(mavenProject.getId());
174 sb.append(System.lineSeparator());
175 }
176 throw new EnforcerRuleException("The reactor contains different versions." + sb);
177 }
178 }
179
180 private List<MavenProject> areParentsFromTheReactor(String reactorVersion, List<MavenProject> sortedProjects) {
181 List<MavenProject> result = new ArrayList<>();
182
183 for (MavenProject mavenProject : sortedProjects) {
184 getLog().debug("Project: " + mavenProject.getId());
185 if (hasParent(mavenProject)) {
186 if (!mavenProject.isExecutionRoot()) {
187 MavenProject parent = mavenProject.getParent();
188 if (!reactorVersion.equals(parent.getVersion())) {
189 getLog().debug("The project: " + mavenProject.getId()
190 + " has a parent which version does not match the other elements in reactor");
191 result.add(mavenProject);
192 }
193 }
194 } else {
195
196 }
197 }
198
199 return result;
200 }
201
202 private List<MavenProject> existParentsWhichAreNotPartOfTheReactor(List<MavenProject> sortedProjects) {
203 List<MavenProject> result = new ArrayList<>();
204
205 for (MavenProject mavenProject : sortedProjects) {
206 getLog().debug("Project: " + mavenProject.getId());
207 if (hasParent(mavenProject)) {
208 if (!mavenProject.isExecutionRoot()) {
209 MavenProject parent = mavenProject.getParent();
210 if (!isProjectPartOfTheReactor(parent, sortedProjects)) {
211 result.add(mavenProject);
212 }
213 }
214 }
215 }
216
217 return result;
218 }
219
220
221
222
223
224
225
226
227
228 private boolean isProjectPartOfTheReactor(MavenProject project, List<MavenProject> sortedProjects) {
229 return isGAPartOfTheReactor(project.getGroupId(), project.getArtifactId(), sortedProjects);
230 }
231
232 private boolean isDependencyPartOfTheReactor(Dependency dependency, List<MavenProject> sortedProjects) {
233 return isGAPartOfTheReactor(dependency.getGroupId(), dependency.getArtifactId(), sortedProjects);
234 }
235
236
237
238
239
240
241
242
243
244 private boolean isGAPartOfTheReactor(String groupId, String artifactId, List<MavenProject> sortedProjects) {
245 boolean result = false;
246 for (MavenProject mavenProject : sortedProjects) {
247 String parentId = groupId + ":" + artifactId;
248 String projectId = mavenProject.getGroupId() + ":" + mavenProject.getArtifactId();
249 if (parentId.equals(projectId)) {
250 result = true;
251 }
252 }
253 return result;
254 }
255
256
257
258
259
260
261
262
263
264 private List<MavenProject> existModulesWithoutParentsInReactor(List<MavenProject> sortedProjects) {
265 List<MavenProject> result = new ArrayList<>();
266
267 for (MavenProject mavenProject : sortedProjects) {
268 getLog().debug("Project: " + mavenProject.getId());
269 if (!hasParent(mavenProject)) {
270
271 if (mavenProject.isExecutionRoot()) {
272 getLog().debug("The root does not need having a parent.");
273 } else {
274 getLog().debug("The module: " + mavenProject.getId() + " has no parent.");
275 result.add(mavenProject);
276 }
277 }
278 }
279
280 return result;
281 }
282
283
284
285
286
287
288
289
290 private void addDep(Map<MavenProject, List<Dependency>> result, MavenProject project, Dependency dependency) {
291 if (result.containsKey(project)) {
292 List<Dependency> list = result.get(project);
293 if (list == null) {
294 list = new ArrayList<>();
295 }
296 list.add(dependency);
297 result.put(project, list);
298 } else {
299 List<Dependency> list = new ArrayList<>();
300 list.add(dependency);
301 result.put(project, list);
302 }
303 }
304
305
306
307
308
309
310
311
312
313
314
315 private Map<MavenProject, List<Dependency>> areThereDependenciesWhichAreNotPartOfTheReactor(
316 String reactorVersion, List<MavenProject> sortedProjects)
317
318 {
319 Map<MavenProject, List<Dependency>> result = new HashMap<>();
320 for (MavenProject mavenProject : sortedProjects) {
321 getLog().debug("Project: " + mavenProject.getId());
322
323 List<Dependency> dependencies = mavenProject.getDependencies();
324 if (hasDependencies(dependencies)) {
325 for (Dependency dependency : dependencies) {
326 getLog().debug(" -> Dep:" + dependency.getGroupId() + ":" + dependency.getArtifactId() + ":"
327 + dependency.getVersion());
328 if (isDependencyPartOfTheReactor(dependency, sortedProjects)) {
329 if (!dependency.getVersion().equals(reactorVersion)) {
330 addDep(result, mavenProject, dependency);
331 }
332 }
333 }
334 }
335 }
336
337 return result;
338 }
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355 private List<MavenProject> isReactorVersionConsistent(List<MavenProject> projectList) {
356 List<MavenProject> result = new ArrayList<>();
357
358 if (projectList != null && !projectList.isEmpty()) {
359 String version = projectList.get(0).getVersion();
360 getLog().debug("First version:" + version);
361 for (MavenProject mavenProject : projectList) {
362 getLog().debug(" -> checking " + mavenProject.getId());
363 if (!version.equals(mavenProject.getVersion())) {
364 result.add(mavenProject);
365 }
366 }
367 }
368 return result;
369 }
370
371 private boolean hasDependencies(List<Dependency> dependencies) {
372 return dependencies != null && !dependencies.isEmpty();
373 }
374
375 private boolean hasParent(MavenProject mavenProject) {
376 return mavenProject.getParent() != null;
377 }
378
379 public boolean isIgnoreModuleDependencies() {
380 return ignoreModuleDependencies;
381 }
382
383
384
385
386
387
388 private void addMessageIfExist(StringBuilder sb) {
389 if (!StringUtils.isEmpty(getMessage())) {
390 sb.append(getMessage());
391 sb.append(System.lineSeparator());
392 }
393 }
394
395 @Override
396 public String getCacheId() {
397 return String.valueOf(toString().hashCode());
398 }
399
400 @Override
401 public String toString() {
402 return String.format(
403 "ReactorModuleConvergence[message=%s, ignoreModuleDependencies=%b]",
404 getMessage(), ignoreModuleDependencies);
405 }
406 }