001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.maven.enforcer.rules; 020 021import javax.inject.Inject; 022import javax.inject.Named; 023 024import java.util.ArrayList; 025import java.util.Collection; 026import java.util.Collections; 027import java.util.List; 028import java.util.Objects; 029import java.util.Optional; 030import java.util.function.Function; 031import java.util.stream.Collectors; 032 033import org.apache.maven.enforcer.rule.api.EnforcerRuleException; 034import org.apache.maven.execution.MavenSession; 035import org.apache.maven.model.Model; 036import org.apache.maven.model.Repository; 037import org.apache.maven.project.MavenProject; 038import org.apache.maven.project.ProjectBuildingRequest; 039import org.apache.maven.settings.Profile; 040import org.apache.maven.settings.RepositoryBase; 041import org.codehaus.plexus.util.StringUtils; 042 043/** 044 * This rule checks that this pom or its parents don't define a repository. 045 * 046 * @author <a href="mailto:brianf@apache.org">Brian Fox</a> 047 */ 048@Named("requireNoRepositories") 049public final class RequireNoRepositories extends AbstractStandardEnforcerRule { 050 051 private static final String VERSION = " version:"; 052 053 /** 054 * Whether to ban non-plugin repositories. By default they are banned. 055 * 056 * @see #setBanRepositories(boolean) 057 */ 058 private boolean banRepositories = true; 059 060 /** 061 * Whether to ban plugin repositories. By default they are banned. 062 * 063 * @see #setBanPluginRepositories(boolean) 064 */ 065 private boolean banPluginRepositories = true; 066 067 /** 068 * Specify explicitly allowed non-plugin repositories. This is a list of ids. 069 * 070 * @see #setAllowedRepositories(List) 071 */ 072 private List<String> allowedRepositories; 073 074 /** 075 * Specify explicitly allowed plugin repositories. This is a list of ids. 076 * 077 * @see #setAllowedPluginRepositories(List) 078 */ 079 private List<String> allowedPluginRepositories; 080 081 /** 082 * Whether to allow repositories which only resolve snapshots. By default they are banned. 083 * 084 * @see #setAllowSnapshotRepositories(boolean) 085 */ 086 private boolean allowSnapshotRepositories = false; 087 088 /** 089 * Whether to allow plugin repositories which only resolve snapshots. By default they are banned. 090 * 091 * @see #setAllowSnapshotPluginRepositories(boolean) 092 */ 093 private boolean allowSnapshotPluginRepositories = false; 094 095 private final MavenSession session; 096 097 @Inject 098 public RequireNoRepositories(MavenSession session) { 099 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}