Writing a custom rule
Custom rules are easy to make with the maven-enforcer-rule-api
. These rules can then be invoked with the maven-enforcer-plugin.
Note: The files shown below may be downloaded here: custom-rule.zip
Project with custom Enforcer Rule
First make a new jar project starting with the sample pom below:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>custom-rule</groupId> <artifactId>custom-rule-sample</artifactId> <version>1.0</version> <name>My Custom Rule</name> <description>This is my custom rule.</description> <properties> <api.version>3.3.0</api.version> <mavenVersion>3.2.5</mavenVersion> <!-- use JDK 1.8 or 11 --> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.apache.maven.enforcer</groupId> <artifactId>enforcer-api</artifactId> <version>${api.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-core</artifactId> <version>${mavenVersion}</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <!-- generate index of project components --> <groupId>org.eclipse.sisu</groupId> <artifactId>sisu-maven-plugin</artifactId> <version>0.9.0.M1</version> <executions> <execution> <goals> <goal>main-index</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
Target bytecode version of rule must be 1.8
or 11
- due to MENFORCER-473.
Note that the classloader is shared with the embedding maven-enforcer-plugin
(a regular plugin classloader) and therefore the artifacts org.apache.maven.enforcer:enforcer-api
are always loaded in the same version as the embedding maven-enforcer-plugin
.
Custom rule artifacts should therefore only depend on enforcer-api
and core Maven artifacts with provided
scope (for details refer to MNG-7097).
The classes available from enforcer-rules
must not be used from custom rules, as those are not considered API and may change in backwards-incompatible ways with every maven-enforcer
version (even minor ones).
Other dependencies used by custom rule at run time should have compile
scope.
Implementation of custom Enforcer Rule
The rule must extends the AbstractEnforcerRule and implements execute
method.
Add annotation @Named("yourRuleName")
to your Rule class. Your Rule name must start with lowercase character.
In addition, the rule can provide a setter method or simply field for each parameter allowed to be configured in the pom.xml file (like the parameter shouldIfail
shown example).
Maven component can be injected into Rule by annotation @Inject
on field or constructor.
Entry point for Rule executing is execute
method, tf the rule succeeds, it should just simply return. If the rule fails, it should throw an EnforcerRuleException with a descriptive message telling the user why the rule failed. Enforcer plugin takes decision based on configuration and Enforcer Rule level whether build should pass or fail. In case when you want to brake build immediately, execute
method can throw an EnforcerRuleError.
Here's a sample class:
package org.example.custom.rule; import javax.inject.Inject; import javax.inject.Named; import java.util.List; import org.apache.maven.enforcer.rule.api.AbstractEnforcerRule; import org.apache.maven.enforcer.rule.api.EnforcerRuleException; import org.apache.maven.execution.MavenSession; import org.apache.maven.project.MavenProject; import org.apache.maven.rtinfo.RuntimeInformation; /** * Custom Enforcer Rule - example */ @Named("myCustomRule") // rule name - must start from lowercase character public class MyCustomRule extends AbstractEnforcerRule { /** * Simple param. This rule fails if the value is true. */ private boolean shouldIfail = false; /** * Rule parameter as list of items. */ private List<String> listParameters; // Inject needed Maven components @Inject private MavenProject project; @Inject private MavenSession session; @Inject private RuntimeInformation runtimeInformation; public void execute() throws EnforcerRuleException { getLog().info("Retrieved Target Folder: " + project.getBuild().getDirectory()); getLog().info("Retrieved ArtifactId: " + project.getArtifactId()); getLog().info("Retrieved Project: " + project); getLog().info("Retrieved Maven version: " + runtimeInformation.getMavenVersion()); getLog().info("Retrieved Session: " + session); getLog().warnOrError("Parameter shouldIfail: " + shouldIfail); getLog().info(() -> "Parameter listParameters: " + listParameters); if (this.shouldIfail) { throw new EnforcerRuleException("Failing because my param said so."); } } /** * If your rule is cacheable, you must return a unique id when parameters or conditions * change that would cause the result to be different. Multiple cached results are stored * based on their id. * <p> * The easiest way to do this is to return a hash computed from the values of your parameters. * <p> * If your rule is not cacheable, then you don't need to override this method or return null */ @Override public String getCacheId() { //no hash on boolean...only parameter so no hash is needed. return Boolean.toString(shouldIfail); } /** * A good practice is provided toString method for Enforcer Rule. * <p> * Output is used in verbose Maven logs, can help during investigate problems. * * @return rule description */ @Override public String toString() { return String.format("MyCustomRule[shouldIfail=%b]", shouldIfail); } }
Using custom Rule
- Build and Install or Deploy your custom rule.
- Add your custom-rule artifact as a dependency of the
maven-enforcer-plugin
in your build. - Add your rule to the configuration section of the
maven-enforcer-plugin
, the name used in@Named
annotation of your Rule will be the name of the rule.
That's it. The full plugin config may look like this:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>custom-rule</groupId> <artifactId>maven-enforcer-plugin-sample-usage</artifactId> <version>1</version> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>3.3.0</version> <dependencies> <!-- dependencies to your artifact contains rule implementation --> <dependency> <groupId>custom-rule</groupId> <artifactId>custom-rule-sample</artifactId> <version>1.0</version> </dependency> </dependencies> <executions> <execution> <id>enforce</id> <configuration> <rules> <!-- rule name --> <myCustomRule> <!-- rule parameters --> <shouldIfail>true</shouldIfail> <listParameters> <item>item 1</item> <item>item 2</item> </listParameters> </myCustomRule> </rules> </configuration> <goals> <goal>enforce</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>