View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
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.Collection;
26  import java.util.HashSet;
27  import java.util.LinkedHashMap;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Objects;
31  import java.util.Set;
32  import java.util.regex.Pattern;
33  
34  import org.apache.maven.artifact.Artifact;
35  import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
36  import org.apache.maven.project.MavenProject;
37  
38  /**
39   * @author Robert Scholte
40   * @since 1.3
41   */
42  @Named("requireSameVersions")
43  public final class RequireSameVersions extends AbstractStandardEnforcerRule {
44      private boolean uniqueVersions;
45  
46      private Set<String> dependencies = new HashSet<>();
47  
48      private Set<String> plugins = new HashSet<>();
49  
50      private Set<String> buildPlugins = new HashSet<>();
51  
52      private Set<String> reportPlugins = new HashSet<>();
53  
54      private final MavenProject project;
55  
56      @Inject
57      public RequireSameVersions(MavenProject project) {
58          this.project = Objects.requireNonNull(project);
59      }
60  
61      @Override
62      public void execute() throws EnforcerRuleException {
63  
64          // consider including profile based artifacts
65          Map<String, List<String>> versionMembers = new LinkedHashMap<>();
66  
67          Set<String> buildPluginSet = new HashSet<>(buildPlugins);
68          buildPluginSet.addAll(plugins);
69          Set<String> reportPluginSet = new HashSet<>(reportPlugins);
70          reportPluginSet.addAll(plugins);
71  
72          // CHECKSTYLE_OFF: LineLength
73          versionMembers.putAll(collectVersionMembers(project.getArtifacts(), dependencies, " (dependency)"));
74          versionMembers.putAll(collectVersionMembers(project.getPluginArtifacts(), buildPlugins, " (buildPlugin)"));
75          versionMembers.putAll(collectVersionMembers(project.getReportArtifacts(), reportPlugins, " (reportPlugin)"));
76          // CHECKSTYLE_ON: LineLength
77  
78          if (versionMembers.size() > 1) {
79              StringBuilder builder = new StringBuilder("Found entries with different versions" + System.lineSeparator());
80              for (Map.Entry<String, List<String>> entry : versionMembers.entrySet()) {
81                  builder.append("Entries with version ").append(entry.getKey()).append(System.lineSeparator());
82                  for (String conflictId : entry.getValue()) {
83                      builder.append("- ").append(conflictId).append(System.lineSeparator());
84                  }
85              }
86              throw new EnforcerRuleException(builder.toString());
87          }
88      }
89  
90      private Map<String, List<String>> collectVersionMembers(
91              Set<Artifact> artifacts, Collection<String> patterns, String source) {
92          Map<String, List<String>> versionMembers = new LinkedHashMap<>();
93  
94          List<Pattern> regExs = new ArrayList<>();
95          for (String pattern : patterns) {
96              String regex = pattern.replace(".", "\\.")
97                      .replace("*", ".*")
98                      .replace(":", "\\:")
99                      .replace('?', '.');
100 
101             // pattern is groupId[:artifactId[:type[:classifier]]]
102             regExs.add(Pattern.compile(regex + "(\\:.+)?"));
103         }
104 
105         for (Artifact artifact : artifacts) {
106             for (Pattern regEx : regExs) {
107                 if (regEx.matcher(artifact.getDependencyConflictId()).matches()) {
108                     String version = uniqueVersions ? artifact.getVersion() : artifact.getBaseVersion();
109                     if (!versionMembers.containsKey(version)) {
110                         versionMembers.put(version, new ArrayList<>());
111                     }
112                     versionMembers.get(version).add(artifact.getDependencyConflictId() + source);
113                 }
114             }
115         }
116         return versionMembers;
117     }
118 
119     @Override
120     public String toString() {
121         return String.format(
122                 "RequireSameVersions[dependencies=%s, buildPlugins=%s, reportPlugins=%s, plugins=%s, uniqueVersions=%b]",
123                 dependencies, buildPlugins, reportPlugins, plugins, uniqueVersions);
124     }
125 }