001package org.apache.maven.plugins.enforcer;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.util.ArrayList;
023import java.util.Collections;
024import java.util.List;
025
026import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
027import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
028import org.apache.maven.execution.MavenSession;
029import org.apache.maven.model.Model;
030import org.apache.maven.model.Repository;
031import org.apache.maven.plugin.logging.Log;
032import org.apache.maven.project.MavenProject;
033import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
034import org.codehaus.plexus.util.StringUtils;
035
036/**
037 * This rule checks that this pom or its parents don't define a repository.
038 *
039 * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
040 */
041public class RequireNoRepositories
042    extends AbstractNonCacheableEnforcerRule
043{
044    private static final String VERSION = " version:";
045
046    /**
047     * Whether to ban non-plugin repositories. By default they are banned.
048     * 
049     * @see #setBanRepositories(boolean)
050     */
051    private boolean banRepositories = true;
052
053    /**
054     * Whether to ban plugin repositories. By default they are banned.
055     * 
056     * @see #setBanPluginRepositories(boolean)
057     */
058    private boolean banPluginRepositories = true;
059
060    /**
061     * Specify explicitly allowed non-plugin repositories. This is a list of ids.
062     * 
063     * @see #setAllowedRepositories(List)
064     */
065    private List<String> allowedRepositories = Collections.emptyList();
066
067    /**
068     * Specify explicitly allowed plugin repositories. This is a list of ids.
069     * 
070     * @see #setAllowedPluginRepositories(List)
071     */
072    private List<String> allowedPluginRepositories = Collections.emptyList();
073
074    /**
075     * Whether to allow repositories which only resolve snapshots. By default they are banned.
076     * 
077     * @see #setAllowSnapshotRepositories(boolean)
078     */
079    private boolean allowSnapshotRepositories = false;
080
081    /**
082     * Whether to allow plugin repositories which only resolve snapshots. By default they are banned.
083     * 
084     * @see {@link #setAllowSnapshotPluginRepositories(boolean)}
085     */
086    private boolean allowSnapshotPluginRepositories = false;
087
088    public final void setBanRepositories( boolean banRepositories )
089    {
090        this.banRepositories = banRepositories;
091    }
092    
093    public final void setBanPluginRepositories( boolean banPluginRepositories )
094    {
095        this.banPluginRepositories = banPluginRepositories;
096    }
097    
098    public final void setAllowedRepositories( List<String> allowedRepositories )
099    {
100        this.allowedRepositories = allowedRepositories;
101    }
102    
103    public final void setAllowedPluginRepositories( List<String> allowedPluginRepositories )
104    {
105        this.allowedPluginRepositories = allowedPluginRepositories;
106    }
107    
108    public final void setAllowSnapshotRepositories( boolean allowSnapshotRepositories )
109    {
110        this.allowSnapshotRepositories = allowSnapshotRepositories;
111    }
112    
113    public final void setAllowSnapshotPluginRepositories( boolean allowSnapshotPluginRepositories )
114    {
115        this.allowSnapshotPluginRepositories = allowSnapshotPluginRepositories;
116    }
117    
118    private Log logger;
119
120    @Override
121    public void execute( EnforcerRuleHelper helper )
122        throws EnforcerRuleException
123    {
124        logger = helper.getLog();
125
126        MavenSession session;
127        try
128        {
129            session = (MavenSession) helper.evaluate( "${session}" );
130
131            List<MavenProject> sortedProjects = session.getProjectDependencyGraph().getSortedProjects();
132
133            List<Model> models = new ArrayList<>();
134            for ( MavenProject mavenProject : sortedProjects )
135            {
136                logger.debug( "Scanning project: " + mavenProject.getGroupId() + ":" + mavenProject.getArtifactId()
137                    + VERSION + mavenProject.getVersion() );
138                models.add( mavenProject.getOriginalModel() );
139            }
140            
141            List<Model> badModels = new ArrayList<>();
142
143            StringBuilder newMsg = new StringBuilder();
144            newMsg.append( "Some poms have repositories defined:" + System.lineSeparator() );
145
146            for ( Model model : models )
147            {
148                if ( banRepositories )
149                {
150                    List<Repository> repos = model.getRepositories();
151                    if ( repos != null && !repos.isEmpty() )
152                    {
153                        List<String> bannedRepos =
154                            findBannedRepositories( repos, allowedRepositories, allowSnapshotRepositories );
155                        if ( !bannedRepos.isEmpty() )
156                        {
157                            badModels.add( model );
158                            newMsg.append(
159                                model.getGroupId() + ":" + model.getArtifactId() + VERSION + model.getVersion()
160                                    + " has repositories " + bannedRepos );
161                        }
162                    }
163                }
164                if ( banPluginRepositories )
165                {
166                    List<Repository> repos = model.getPluginRepositories();
167                    if ( repos != null && !repos.isEmpty() )
168                    {
169                        List<String> bannedRepos =
170                            findBannedRepositories( repos, allowedPluginRepositories, allowSnapshotPluginRepositories );
171                        if ( !bannedRepos.isEmpty() )
172                        {
173                            badModels.add( model );
174                            newMsg.append(
175                                model.getGroupId() + ":" + model.getArtifactId() + VERSION + model.getVersion()
176                                    + " has plugin repositories " + bannedRepos );
177                        }
178                    }
179                }
180            }
181
182            // if anything was found, log it then append the
183            // optional message.
184            if ( !badModels.isEmpty() )
185            {
186                String message = getMessage();
187                if ( StringUtils.isNotEmpty( message ) )
188                {
189                    newMsg.append( message );
190                }
191
192                throw new EnforcerRuleException( newMsg.toString() );
193            }
194
195        }
196        catch ( ExpressionEvaluationException e )
197        {
198            throw new EnforcerRuleException( e.getLocalizedMessage() );
199        }
200    }
201
202    /**
203     * 
204     * @param repos all repositories, never {@code null}
205     * @param allowedRepos allowed repositories, never {@code null}
206     * @param allowSnapshots 
207     * @return List of banned repositoreis.
208     */
209    private static List<String> findBannedRepositories( List<Repository> repos, List<String> allowedRepos,
210                                                        boolean allowSnapshots )
211    {
212        List<String> bannedRepos = new ArrayList<>( allowedRepos.size() );
213        for ( Repository r : repos )
214        {
215            if ( !allowedRepos.contains( r.getId() ) )
216            {
217                if ( !allowSnapshots || r.getReleases() == null || r.getReleases().isEnabled() )
218                {
219                    // if we are not allowing snapshots and this repo is enabled for releases
220                    // it is banned.  We don't care whether it is enabled for snapshots
221                    // if you define a repo and don't enable it for anything, then we have nothing 
222                    // to worry about
223                    bannedRepos.add( r.getId() );
224                }
225            }
226        }
227        return bannedRepos;
228    }
229}