All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.atlassian.maven.enforcer.BanVersionDeps Maven / Gradle / Ivy

There is a newer version: 1.5.11
Show newest version
package com.atlassian.maven.enforcer;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.enforcer.AbstractBanDependencies;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.artifact.filter.StrictPatternExcludesArtifactFilter;
import org.apache.maven.shared.artifact.filter.StrictPatternIncludesArtifactFilter;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

@SuppressWarnings ("UnusedDeclaration")
public class BanVersionDeps extends AbstractBanDependencies
{
    /**
     * Dependencies with version strings that match are banned
     */
    private String bannedDependencyVersionRegexp;

    /**
     * Will not fail if artifact being built has a version string that matches
     */
    private String noFailReactorVersionRegexp;

    /**
     * Will not fail if artifact being built is a snapshot
     */
    private boolean noFailSnapshots;

    /**
     * Ignore dependencies which have a scope of "test"
     */
    private boolean ignoreTest;

    /**
     * Exclude these dependencies in the check
     */
    private List excludes;

    /**
     * Include only these dependencies in the check
     */
    private List includes;

    Pattern bannedDependencyVersionPattern;

    Pattern noFailReactorVersionPattern;

    boolean failBuild;

    /**
     * Format is "::"
     */
    Set reactorGAVs;

    @Override
    public void execute(final EnforcerRuleHelper helper) throws EnforcerRuleException
    {
        final MavenProject reactorProject = retrieveReactorProject(helper);

        // I know it sucks to use members to store state, but they're valid for the lifetime of this rule
        // the alternative is reimplementing the private bits of {@{@link AbstractBanDependencies}
        bannedDependencyVersionPattern = parseRegexp(bannedDependencyVersionRegexp, "bannedDependencyVersionRegexp", true);
        noFailReactorVersionPattern = parseRegexp(noFailReactorVersionRegexp, "noFailReactorVersionRegexp", false);
        failBuild = shouldFailBuild(reactorProject);
        reactorGAVs = reactorProject.getProjectReferences().keySet();

        decorateMessage();

        super.execute(helper);
    }

    /**
     * Check all resolved dependencies' version string against {@link #bannedDependencyVersionRegexp}. Any that match
     * will be flagged as banned.
     *
     * The enforcer will fail unless the reactor matched noFailReactorVersionRegexp or noFailSnapshots is specified for
     * a snapshot.
     *
     * @param dependencies mandatory
     * @param log mandatory
     * @return possibly empty
     * @throws org.apache.maven.enforcer.rule.api.EnforcerRuleException on invalid or missing regexp
     */
    @Override
    protected Set checkDependencies(final Set dependencies, final Log log)
            throws EnforcerRuleException
    {
        Set bannedArtifacts = new HashSet();

        // check each dependency; transitives will not be included if searchTransitive is false
        for (Artifact dependency : includeExclude(dependencies))
        {
            if (dependency.getVersion() != null)
            {
                // ignore test dependencies if configured
                if (!ignoreTest || !Artifact.SCOPE_TEST.equals(dependency.getScope()))
                {
                    // ban any dependencies which have a resolved version that matches
                    Matcher versionMatcher = bannedDependencyVersionPattern.matcher(dependency.getVersion());
                    if (versionMatcher.matches())
                    {
                        // don't check dependencies that are within this reactor
                        if (!reactorGAVs.contains(dependency.getGroupId() + ":" + dependency.getArtifactId() + ":" + dependency.getVersion()))
                        {
                            bannedArtifacts.add(dependency);
                        }
                    }
                }
            }
        }

        if (failBuild)
        {
            // fail the build by returning the banned list
            return bannedArtifacts;
        }
        else
        {
            // warn about the failures but don't fail the build
            if (!bannedArtifacts.isEmpty())
            {
                StringBuilder buf = new StringBuilder();
                buf.append("\n");
                buf.append(getMessage());
                buf.append("\n");
                for (Artifact artifact : bannedArtifacts)
                {
                    buf.append(getErrorMessage(artifact));
                }
                buf.append("Use 'mvn dependency:tree' to locate the source of the banned dependencies.");
                log.warn(buf.toString());
            }
            return Collections.emptySet();
        }
    }

    /**
     * Filter input based on {@link #includes} and {@link #excludes} if they are present
     *
     * @param dependencies mandatory
     * @return possibly empty
     */
    Set includeExclude(final Set dependencies)
    {
        Set includedExcluded = new HashSet();

        // build a filter with the includes and excldes, but only if they're present
        AndArtifactFilter filter = new AndArtifactFilter();
        if (includes != null)
        {
            filter.add(new StrictPatternIncludesArtifactFilter(includes));
        }
        if (excludes != null)
        {
            filter.add(new StrictPatternExcludesArtifactFilter(excludes));
        }

        // filter the dependencies; this will just pass through if there are no includes/excludes
        for (Artifact dependency : dependencies)
        {
            if (filter.include(dependency))
            {
                includedExcluded.add(dependency);
            }
        }

        return includedExcluded;
    }

    /**
     * Build will fail on a banned dependency being found unless:
     * noFailSnapshots is set and we are building a snapshot
     * or
     * noFailReactorVersionRegexp matchjes the reactor's version
     */
    boolean shouldFailBuild(final MavenProject reactorProject)
    {
        // snapshots are allowed to pass
        if (noFailSnapshots && reactorProject.getArtifact().isSnapshot())
        {
            return false;
        }

        // user allows certain versions to pass
        if (noFailReactorVersionPattern != null && noFailReactorVersionPattern.matcher(reactorProject.getArtifact().getVersion()).matches())
        {
            return false;
        }

        // default to failing on finding a banned dependency
        return true;
    }

    MavenProject retrieveReactorProject(final EnforcerRuleHelper helper) throws EnforcerRuleException
    {
        try
        {
            return ((MavenProject) helper.evaluate( "${project}" ));
        }
        catch ( ExpressionEvaluationException eee )
        {
            throw new EnforcerRuleException( "Unable to retrieve the MavenProject: ", eee );
        }
    }

    Pattern parseRegexp(final String regexp, final String paramName, final boolean mandatory) throws EnforcerRuleException
    {
        if (mandatory && regexp == null)
        {
            throw new EnforcerRuleException("missing " + paramName);
        }
        if (regexp != null)
        {
            try
            {
                return Pattern.compile(regexp);
            }
            catch (PatternSyntaxException e)
            {
                throw new EnforcerRuleException("invalid " + paramName + ": '" + regexp + "'");
            }
        }
        else
        {
            return null;
        }
    }

    public String getBannedDependencyVersionRegexp()
    {
        return bannedDependencyVersionRegexp;
    }

    public void setBannedDependencyVersionRegexp(final String bannedDependencyVersionRegexp)
    {
        this.bannedDependencyVersionRegexp = bannedDependencyVersionRegexp;
    }

    public String getNoFailReactorVersionRegexp()
    {
        return noFailReactorVersionRegexp;
    }

    public void setNoFailReactorVersionRegexp(final String noFailReactorVersionRegexp)
    {
        this.noFailReactorVersionRegexp = noFailReactorVersionRegexp;
    }

    public boolean isNoFailSnapshots()
    {
        return noFailSnapshots;
    }

    public void setNoFailSnapshots(final boolean noFailSnapshots)
    {
        this.noFailSnapshots = noFailSnapshots;
    }

    public boolean isIgnoreTest()
    {
        return ignoreTest;
    }

    public void setIgnoreTest(final boolean ignoreTest)
    {
        this.ignoreTest = ignoreTest;
    }

    public List getExcludes()
    {
        return excludes;
    }

    public void setExcludes(final List excludes)
    {
        this.excludes = excludes;
    }

    public List getIncludes()
    {
        return includes;
    }

    public void setIncludes(final List includes)
    {
        this.includes = includes;
    }

    private void decorateMessage()
    {
        setMessage("                                   #######\n"
                + "                                 ###########\n"
                + "                               ###############\n"
                + "                             #################\n"
                + "                           #################\n"
                + "                         #################   ##\n"
                + "                       #################   ######\n"
                + "                     #################   ##########\n"
                + "                   #################   ##############\n"
                + "                 #################   ##################\n"
                + "               #################   ######################\n"
                + "             #################   ##########################\n"
                + "           #################   ##############################\n"
                + "         #################   ##################################\n"
                + "       #################   ######################################\n"
                + "      ################   ##########################################\n"
                + "     ###############   #############################     ############\n"
                + "      ############   #########################             ############\n"
                + "        ########   ##########################               #############\n"
                + "          ####   ##############################    ########################\n"
                + "                  ##############################    #########################\n"
                + "                    ############################      #########################\n"
                + "                      #####################           #########################   ####\n"
                + "                        #####################################################   ########\n"
                + "                          #################################################   ###########\n"
                + "                           ##############################################   ##############\n"
                + "                          #############################################   ################\n"
                + "                        #############################################   #################\n"
                + "                      #############################################   #################\n"
                + "                    #############################################   #################\n"
                + "                  #############################################   #################\n"
                + "                ######################  #####################   #################\n"
                + "              ######################      #################   #################\n"
                + "            ######################          #############   #################\n"
                + "         #######################              #########   #################\n"
                + "     #########################                  #####   #################\n"
                + "  ##########################                      #   #################\n"
                + "##########################                          #################\n"
                + "########################                          #################\n"
                + "######################                            ###############\n"
                + "#####################                                ##########\n"
                + " ###################                                  #######\n"
                + "   ################\n"
                + "      ############\n"
                + "        ########\n"
                        + getMessage());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy