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.dependency;
20  
21  import javax.inject.Inject;
22  import javax.inject.Named;
23  
24  import java.util.HashSet;
25  import java.util.Set;
26  
27  import org.apache.maven.artifact.Artifact;
28  import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
29  import org.apache.maven.enforcer.rules.utils.ArtifactUtils;
30  import org.apache.maven.execution.MavenSession;
31  
32  import static java.util.Optional.ofNullable;
33  import static org.apache.maven.enforcer.rules.utils.ArtifactUtils.matchDependencyArtifact;
34  
35  /**
36   * This rule checks that no snapshots are included.
37   *
38   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
39   */
40  @Named("requireReleaseDeps")
41  public final class RequireReleaseDeps extends BannedDependenciesBase {
42  
43      /**
44       * Allows this rule to execute only when this project is a release.
45       */
46      private boolean onlyWhenRelease = false;
47  
48      /**
49       * Allows this rule to fail when the parent is defined as a snapshot.
50       */
51      private boolean failWhenParentIsSnapshot = true;
52  
53      @Inject
54      public RequireReleaseDeps(MavenSession session, ResolverUtil resolverUtil) {
55          super(session, resolverUtil);
56      }
57  
58      // Override parent to allow optional ignore of this rule.
59      @Override
60      public void execute() throws EnforcerRuleException {
61          boolean callSuper;
62          if (onlyWhenRelease) {
63              // only call super if this project is a release
64              callSuper = !getSession().getCurrentProject().getArtifact().isSnapshot();
65          } else {
66              callSuper = true;
67          }
68  
69          if (callSuper) {
70              super.execute();
71              if (failWhenParentIsSnapshot) {
72  
73                  Artifact parentArtifact = getSession().getCurrentProject().getParentArtifact();
74  
75                  if (parentArtifact != null) {
76                      Set<Artifact> singletonArtifact = new HashSet<>();
77                      singletonArtifact.add(parentArtifact);
78                      Set<Artifact> artifacts = filterArtifacts(singletonArtifact);
79                      parentArtifact = ofNullable(artifacts)
80                              .flatMap(s -> s.stream().findFirst())
81                              .orElse(null);
82                  }
83  
84                  if (parentArtifact != null && parentArtifact.isSnapshot()) {
85                      throw new EnforcerRuleException("Parent Cannot be a snapshot: " + parentArtifact.getId());
86                  }
87              }
88          }
89      }
90  
91      @Override
92      protected String getErrorMessage() {
93          return "is not a release dependency";
94      }
95  
96      @Override
97      protected boolean validate(Artifact artifact) {
98          // only check isSnapshot() if the artifact does not match (excludes minus includes)
99          // otherwise true
100         return (matchDependencyArtifact(artifact, getExcludes()) && !matchDependencyArtifact(artifact, getIncludes()))
101                 || !artifact.isSnapshot();
102     }
103 
104     /**
105      * Filter the dependency artifacts according to the includes and excludes
106      * If includes and excludes are both null, the original set is returned.
107      *
108      * @param dependencies the list of dependencies to filter
109      * @return the resulting set of dependencies
110      */
111     private Set<Artifact> filterArtifacts(Set<Artifact> dependencies) throws EnforcerRuleException {
112         if (getIncludes() != null) {
113             dependencies = ArtifactUtils.filterDependencyArtifacts(dependencies, getIncludes());
114         }
115 
116         if (dependencies != null && getExcludes() != null) {
117             ofNullable(ArtifactUtils.filterDependencyArtifacts(dependencies, getExcludes()))
118                     .ifPresent(dependencies::removeAll);
119         }
120 
121         return dependencies;
122     }
123 
124     public void setOnlyWhenRelease(boolean onlyWhenRelease) {
125         this.onlyWhenRelease = onlyWhenRelease;
126     }
127 
128     public void setFailWhenParentIsSnapshot(boolean failWhenParentIsSnapshot) {
129         this.failWhenParentIsSnapshot = failWhenParentIsSnapshot;
130     }
131 
132     @Override
133     public String toString() {
134         return String.format(
135                 "RequireReleaseDeps[message=%s, excludes=%s, includes=%s, searchTransitive=%b, onlyWhenRelease=%b, failWhenParentIsSnapshot=%b]",
136                 getMessage(),
137                 getExcludes(),
138                 getIncludes(),
139                 isSearchTransitive(),
140                 onlyWhenRelease,
141                 failWhenParentIsSnapshot);
142     }
143 }