Skip to content

Commit

Permalink
[MENFORCER-422] Added externalRules rule
Browse files Browse the repository at this point in the history
  • Loading branch information
gastaldi committed Aug 11, 2022
1 parent ae93fa8 commit abc34f5
Show file tree
Hide file tree
Showing 12 changed files with 490 additions and 15 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ target
.svn
*.iml
.checkstyle

.DS_Store
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.apache.maven.plugins.enforcer;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import org.apache.maven.enforcer.rule.api.EnforcerRule;

/**
* An enforcer rules descriptor used by {@link ExternalRules}
*
* @author <a href="mailto:gastaldi@apache.org">George Gastaldi</a>
*/
public class EnforcerDescriptor
{
EnforcerRule[] rules;

public EnforcerRule[] getRules()
{
return rules;
}

public void setRules( EnforcerRule[] rules )
{
this.rules = rules;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package org.apache.maven.plugins.enforcer;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import org.apache.maven.enforcer.rule.api.EnforcerRule;
import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
import org.apache.maven.plugin.MojoExecution;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.codehaus.plexus.component.configurator.ComponentConfigurator;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.configuration.PlexusConfiguration;
import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
import org.codehaus.plexus.util.xml.pull.XmlPullParserException;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;

/**
* An enforcer rule that will invoke rules from an external resource
*
* @author <a href="mailto:gastaldi@apache.org">George Gastaldi</a>
*/
public class ExternalRules extends AbstractNonCacheableEnforcerRule
{
private static final String LOCATION_PREFIX_CLASSPATH = "classpath:";

/**
* The external rules location. If it starts with "classpath:", the resource is read from the classpath
*/
String location;

public ExternalRules()
{
}

public ExternalRules( String location )
{
this.location = location;
}

@Override
public void execute( EnforcerRuleHelper helper ) throws EnforcerRuleException
{
// Find descriptor
EnforcerDescriptor enforcerDescriptor = getEnforcerDescriptor( helper );
for ( EnforcerRule rule : enforcerDescriptor.getRules() )
{
rule.execute( helper );
}
}

/**
* Resolve the {@link EnforcerDescriptor} based on the provided {@link #descriptor} or {@link #descriptorRef}
*
* @param helper used to build the {@link EnforcerDescriptor}
* @return an {@link EnforcerDescriptor} for this rule
* @throws EnforcerRuleException if any failure happens while reading the descriptor
*/
EnforcerDescriptor getEnforcerDescriptor( EnforcerRuleHelper helper )
throws EnforcerRuleException
{
try ( InputStream descriptorStream = resolveDescriptor( helper ) )
{
EnforcerDescriptor descriptor = new EnforcerDescriptor();
// To get configuration from the enforcer-plugin mojo do:
//helper.evaluate(helper.getComponent(MojoExecution.class).getConfiguration().getChild("fail").getValue())
// Configure EnforcerDescriptor from the XML
ComponentConfigurator configurator = helper.getComponent( ComponentConfigurator.class, "basic" );
configurator.configureComponent( descriptor, toPlexusConfiguration( descriptorStream ), helper,
getClassRealm( helper ) );
return descriptor;
}
catch ( EnforcerRuleException e )
{
throw e;
}
catch ( Exception e )
{
throw new EnforcerRuleException( "Error while enforcing rules", e );
}
}

private InputStream resolveDescriptor( EnforcerRuleHelper helper )
throws ComponentLookupException, EnforcerRuleException
{
InputStream descriptorStream;
if ( location != null )
{
if ( location.startsWith( LOCATION_PREFIX_CLASSPATH ) )
{
String classpathLocation = location.substring( LOCATION_PREFIX_CLASSPATH.length() );
ClassLoader classRealm = getClassRealm( helper );
descriptorStream = classRealm.getResourceAsStream( classpathLocation );
if ( descriptorStream == null )
{
throw new EnforcerRuleException( "Location '" + classpathLocation + "' not found in classpath" );
}
}
else
{
File descriptorFile = helper.alignToBaseDirectory( new File( location ) );
try
{
descriptorStream = Files.newInputStream( descriptorFile.toPath() );
}
catch ( IOException e )
{
throw new EnforcerRuleException( "Could not read descriptor in " + descriptorFile, e );
}
}
}
else
{
throw new EnforcerRuleException( "No location provided" );
}
return descriptorStream;
}

private static PlexusConfiguration toPlexusConfiguration( InputStream descriptorStream )
throws XmlPullParserException, IOException
{
return new XmlPlexusConfiguration( Xpp3DomBuilder.build( descriptorStream, "UTF-8" ) );
}

private ClassRealm getClassRealm( EnforcerRuleHelper helper ) throws ComponentLookupException
{
return helper.getComponent( MojoExecution.class ).getMojoDescriptor().getRealm();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,6 @@
* under the License.
*/

import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.util.Arrays;
import java.util.Collections;
import java.util.Properties;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
Expand All @@ -38,17 +30,27 @@
import org.apache.maven.model.Plugin;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.logging.SystemStreamLog;
import org.apache.maven.plugins.enforcer.utils.MockEnforcerExpressionEvaluator;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.ProjectBuildingRequest;
import org.apache.maven.shared.dependency.graph.DependencyCollectorBuilder;
import org.apache.maven.shared.dependency.graph.internal.DefaultDependencyNode;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.classworlds.ClassWorld;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.mockito.Mockito;

import java.util.Arrays;
import java.util.Collections;
import java.util.Properties;

import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

/**
* The Class EnforcerTestUtils.
*
Expand Down Expand Up @@ -114,28 +116,28 @@ public static EnforcerRuleHelper getHelper( MavenProject project )
/**
* Gets the helper.
*
* @param project the project
* @param project the project
* @param mockExpression the mock expression
* @return the helper
*/
public static EnforcerRuleHelper getHelper( MavenProject project, boolean mockExpression )
{
MavenSession session = getMavenSession();
MojoExecution mockExecution = mock( MojoExecution.class );
ExpressionEvaluator eval;
if ( mockExpression )
{
eval = new MockEnforcerExpressionEvaluator( session );
}
else
{
MojoExecution mockExecution = mock( MojoExecution.class );
session.setCurrentProject( project );
eval = new PluginParameterExpressionEvaluator( session, mockExecution );
}
PlexusContainer container = Mockito.mock( PlexusContainer.class );

Artifact artifact =
new DefaultArtifact( "groupId", "artifactId", "version", "compile", "jar", "classifier", null );
new DefaultArtifact( "groupId", "artifactId", "version", "compile", "jar", "classifier", null );
Artifact v1 = new DefaultArtifact( "groupId", "artifact", "1.0.0", "compile", "jar", "", null );
Artifact v2 = new DefaultArtifact( "groupId", "artifact", "2.0.0", "compile", "jar", "", null );
final DefaultDependencyNode node = new DefaultDependencyNode( artifact );
Expand All @@ -154,14 +156,26 @@ public static EnforcerRuleHelper getHelper( MavenProject project, boolean mockEx
{
// test will fail
}
ClassWorld classWorld = new ClassWorld( "test", EnforcerTestUtils.class.getClassLoader() );
MojoDescriptor mojoDescriptor = new MojoDescriptor();
mojoDescriptor.setRealm( classWorld.getClassRealm( "test" ) );
when( mockExecution.getMojoDescriptor() ).thenReturn( mojoDescriptor );
try
{
when( container.lookup( MojoExecution.class ) ).thenReturn( mockExecution );
}
catch ( ComponentLookupException e )
{
// test will fail
}
return new DefaultEnforcementRuleHelper( session, eval, new SystemStreamLog(), container );
}

/**
* Gets the helper.
*
* @param project the project
* @param eval the expression evaluator to use
* @param eval the expression evaluator to use
* @return the helper
*/
public static EnforcerRuleHelper getHelper( MavenProject project, ExpressionEvaluator eval )
Expand All @@ -173,9 +187,9 @@ public static EnforcerRuleHelper getHelper( MavenProject project, ExpressionEval
/**
* New plugin.
*
* @param groupId the group id
* @param groupId the group id
* @param artifactId the artifact id
* @param version the version
* @param version the version
* @return the plugin
*/
public static Plugin newPlugin( String groupId, String artifactId, String version )
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package org.apache.maven.plugins.enforcer;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper;
import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThatExceptionOfType;

public class TestExternalRules
{
@Test
void shouldFailIfNoLocationIsSet()
{
ExternalRules rule = new ExternalRules();
EnforcerRuleHelper helper = EnforcerTestUtils.getHelper();
assertThatExceptionOfType( EnforcerRuleException.class ).isThrownBy( () -> rule.execute( helper ) )
.withMessage( "No location provided" );
}

@Test
void shouldFailIfClasspathLocationIsNotFound()
{
ExternalRules rule = new ExternalRules("classpath:foo");
EnforcerRuleHelper helper = EnforcerTestUtils.getHelper();
assertThatExceptionOfType( EnforcerRuleException.class ).isThrownBy( () -> rule.execute( helper ) )
.withMessage( "Location 'foo' not found in classpath" );
}

@Test
void shouldFailIfFileLocationIsNotFound()
{
ExternalRules rule = new ExternalRules("blah.xml");
EnforcerRuleHelper helper = EnforcerTestUtils.getHelper();
assertThatExceptionOfType( EnforcerRuleException.class ).isThrownBy( () -> rule.execute( helper ) )
.withMessageMatching( "Could not read descriptor in .*blah.xml" );
}
}

0 comments on commit abc34f5

Please sign in to comment.