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.Collections;
27  import java.util.List;
28  import java.util.Objects;
29  import java.util.Optional;
30  import java.util.function.Function;
31  import java.util.stream.Collectors;
32  
33  import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
34  import org.apache.maven.execution.MavenSession;
35  import org.apache.maven.model.Model;
36  import org.apache.maven.model.Repository;
37  import org.apache.maven.project.MavenProject;
38  import org.apache.maven.project.ProjectBuildingRequest;
39  import org.apache.maven.settings.Profile;
40  import org.apache.maven.settings.RepositoryBase;
41  import org.codehaus.plexus.util.StringUtils;
42  
43  /**
44   * This rule checks that this pom or its parents don't define a repository.
45   *
46   * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
47   */
48  @Named("requireNoRepositories")
49  public final class RequireNoRepositories extends AbstractStandardEnforcerRule {
50  
51      private static final String VERSION = " version:";
52  
53      /**
54       * Whether to ban non-plugin repositories. By default they are banned.
55       *
56       * @see #setBanRepositories(boolean)
57       */
58      private boolean banRepositories = true;
59  
60      /**
61       * Whether to ban plugin repositories. By default they are banned.
62       *
63       * @see #setBanPluginRepositories(boolean)
64       */
65      private boolean banPluginRepositories = true;
66  
67      /**
68       * Specify explicitly allowed non-plugin repositories. This is a list of ids.
69       *
70       * @see #setAllowedRepositories(List)
71       */
72      private List<String> allowedRepositories;
73  
74      /**
75       * Specify explicitly allowed plugin repositories. This is a list of ids.
76       *
77       * @see #setAllowedPluginRepositories(List)
78       */
79      private List<String> allowedPluginRepositories;
80  
81      /**
82       * Whether to allow repositories which only resolve snapshots. By default they are banned.
83       *
84       * @see #setAllowSnapshotRepositories(boolean)
85       */
86      private boolean allowSnapshotRepositories = false;
87  
88      /**
89       * Whether to allow plugin repositories which only resolve snapshots. By default they are banned.
90       *
91       * @see #setAllowSnapshotPluginRepositories(boolean)
92       */
93      private boolean allowSnapshotPluginRepositories = false;
94  
95      private final MavenSession session;
96  
97      @Inject
98      public RequireNoRepositories(MavenSession session) {
99          this.session = Objects.requireNonNull(session);
100     }
101 
102     public void setBanRepositories(boolean banRepositories) {
103         this.banRepositories = banRepositories;
104     }
105 
106     public void setBanPluginRepositories(boolean banPluginRepositories) {
107         this.banPluginRepositories = banPluginRepositories;
108     }
109 
110     public void setAllowedRepositories(List<String> allowedRepositories) {
111         this.allowedRepositories = allowedRepositories;
112     }
113 
114     public void setAllowedPluginRepositories(List<String> allowedPluginRepositories) {
115         this.allowedPluginRepositories = allowedPluginRepositories;
116     }
117 
118     public void setAllowSnapshotRepositories(boolean allowSnapshotRepositories) {
119         this.allowSnapshotRepositories = allowSnapshotRepositories;
120     }
121 
122     public void setAllowSnapshotPluginRepositories(boolean allowSnapshotPluginRepositories) {
123         this.allowSnapshotPluginRepositories = allowSnapshotPluginRepositories;
124     }
125 
126     @Override
127     public void execute() throws EnforcerRuleException {
128 
129         // Maven 4 Model contains repositories defined in settings.xml
130         // As workaround we exclude repositories defined in settings.xml
131         // https://issues.apache.org/jira/browse/MNG-7228
132         if (banRepositories) {
133             Collection<String> reposIdsFromSettings = getRepoIdsFromSettings(Profile::getRepositories);
134             if (!reposIdsFromSettings.isEmpty()) {
135                 getLog().debug(() -> "Allow repositories from settings: " + reposIdsFromSettings);
136             }
137 
138             allowedRepositories = Optional.ofNullable(allowedRepositories).orElseGet(ArrayList::new);
139             allowedRepositories.addAll(reposIdsFromSettings);
140         }
141 
142         if (banPluginRepositories) {
143             Collection<String> reposIdsFromSettings = getRepoIdsFromSettings(Profile::getPluginRepositories);
144             if (!reposIdsFromSettings.isEmpty()) {
145                 getLog().debug(() -> "Allow plugin repositories from settings: " + reposIdsFromSettings);
146             }
147 
148             allowedPluginRepositories =
149                     Optional.ofNullable(allowedPluginRepositories).orElseGet(ArrayList::new);
150             allowedPluginRepositories.addAll(reposIdsFromSettings);
151         }
152 
153         List<MavenProject> sortedProjects = session.getProjectDependencyGraph().getSortedProjects();
154 
155         List<Model> models = new ArrayList<>();
156         for (MavenProject mavenProject : sortedProjects) {
157             getLog().debug("Scanning project: " + mavenProject.getGroupId() + ":" + mavenProject.getArtifactId()
158                     + VERSION + mavenProject.getVersion());
159             models.add(mavenProject.getOriginalModel());
160         }
161 
162         List<Model> badModels = new ArrayList<>();
163 
164         StringBuilder newMsg = new StringBuilder();
165         newMsg.append("Some poms have repositories defined:" + System.lineSeparator());
166 
167         for (Model model : models) {
168             if (banRepositories) {
169                 List<Repository> repos = model.getRepositories();
170                 if (repos != null && !repos.isEmpty()) {
171                     List<String> bannedRepos =
172                             findBannedRepositories(repos, allowedRepositories, allowSnapshotRepositories);
173                     if (!bannedRepos.isEmpty()) {
174                         badModels.add(model);
175                         newMsg.append(model.getGroupId() + ":" + model.getArtifactId() + VERSION + model.getVersion()
176                                 + " has repositories " + bannedRepos);
177                     }
178                 }
179             }
180             if (banPluginRepositories) {
181                 List<Repository> repos = model.getPluginRepositories();
182                 if (repos != null && !repos.isEmpty()) {
183                     List<String> bannedRepos =
184                             findBannedRepositories(repos, allowedPluginRepositories, allowSnapshotPluginRepositories);
185                     if (!bannedRepos.isEmpty()) {
186                         badModels.add(model);
187                         newMsg.append(model.getGroupId() + ":" + model.getArtifactId() + VERSION + model.getVersion()
188                                 + " has plugin repositories " + bannedRepos);
189                     }
190                 }
191             }
192         }
193 
194         // if anything was found, log it then append the
195         // optional message.
196         if (!badModels.isEmpty()) {
197             if (StringUtils.isNotEmpty(getMessage())) {
198                 newMsg.append(getMessage());
199             }
200 
201             throw new EnforcerRuleException(newMsg.toString());
202         }
203     }
204 
205     private Collection<String> getRepoIdsFromSettings(
206             Function<Profile, List<org.apache.maven.settings.Repository>> getRepositoriesFunc) {
207 
208         List<String> activeProfileIds = Optional.ofNullable(session.getProjectBuildingRequest())
209                 .map(ProjectBuildingRequest::getActiveProfileIds)
210                 .orElse(Collections.emptyList());
211 
212         List<String> inactiveProfileIds = Optional.ofNullable(session.getProjectBuildingRequest())
213                 .map(ProjectBuildingRequest::getInactiveProfileIds)
214                 .orElse(Collections.emptyList());
215 
216         return session.getSettings().getProfiles().stream()
217                 .filter(p -> activeProfileIds.contains(p.getId()))
218                 .filter(p -> !inactiveProfileIds.contains(p.getId()))
219                 .map(getRepositoriesFunc)
220                 .flatMap(Collection::stream)
221                 .map(RepositoryBase::getId)
222                 .collect(Collectors.toSet());
223     }
224 
225     /**
226      * @param repos          all repositories, never {@code null}
227      * @param allowedRepos   allowed repositories, never {@code null}
228      * @param allowSnapshots
229      * @return List of banned repositoreis.
230      */
231     private static List<String> findBannedRepositories(
232             List<Repository> repos, List<String> allowedRepos, boolean allowSnapshots) {
233         List<String> bannedRepos = new ArrayList<>(allowedRepos.size());
234         for (Repository r : repos) {
235             if (!allowedRepos.contains(r.getId())) {
236                 if (!allowSnapshots
237                         || r.getReleases() == null
238                         || r.getReleases().isEnabled()) {
239                     // if we are not allowing snapshots and this repo is enabled for releases
240                     // it is banned.  We don't care whether it is enabled for snapshots
241                     // if you define a repo and don't enable it for anything, then we have nothing
242                     // to worry about
243                     bannedRepos.add(r.getId());
244                 }
245             }
246         }
247         return bannedRepos;
248     }
249 
250     @Override
251     public String toString() {
252         return String.format(
253                 "RequireNoRepositories[message=%s, banRepositories=%b, allowSnapshotRepositories=%b, allowedRepositories=%s, "
254                         + "banPluginRepositories=%b, allowSnapshotPluginRepositories=%b, allowedPluginRepositories=%s]",
255                 getMessage(),
256                 banRepositories,
257                 allowSnapshotRepositories,
258                 allowedRepositories,
259                 banPluginRepositories,
260                 allowSnapshotPluginRepositories,
261                 allowedPluginRepositories);
262     }
263 }