Search code examples
javagradlestatic-analysisgradle-pluginpmd

How to add custom java pmd rules to gradle project using gradle-pmd-plugin?


During working on project arch4u-pmd we made several java-based pmd rules, configured them in XML-based ruleset our-rules.xml, and published it as a plain java lib/artifact (io.github.abc:my-pmd-rules:0.1.0) to our artifacts repository. The artifact structure looks like this:

> unzip -l my-pmd-rules-0.1.0.jar   
Archive:  my-pmd-rules-0.1.0.jar   
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  02-15-2022 00:24   META-INF/
      139  02-15-2022 00:24   META-INF/MANIFEST.MF
        0  02-15-2022 00:24   io/
        0  02-15-2022 00:24   io/github/
        0  02-15-2022 00:24   io/github/rules/
        ...
     4781  02-15-2022 00:24   io/github/rules/MissingMandatoryAnnotation.class
     ...
     1138  02-15-2022 00:24   io/github/rules/our-rules.xml
     ...

How we can add them to the Gradle project using pmd plugin?

We have to process the following materials/questions/answers:

  1. https://stackoverflow.com/search?page=2&tab=Relevance&q=pmd%20classpath
  2. ClassNotFoundException: Using custom java rule for PMD ruleset
  3. Gradle's PMD plugin: what are acceptable arguments?
  4. Adding a ruleset to PMD?
  5. Adding custom rules in PMD - class not found issue
  6. https://discuss.gradle.org/t/pmd-ruleset-not-available-in-classpath/7201
  7. https://discuss.gradle.org/t/custom-rules-with-pmd-plugin/5859/4
  8. How to configure PMD Auxiliary classpath in Sonar
  9. https://docs.gradle.org/current/userguide/pmd_plugin.html
  10. https://github.com/gradle/gradle/blob/master/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/PmdPlugin.java
  11. Custom PMD rule with Gradle also don't work
    tasks.withType(Pmd) {
       pmdClasspath += file("path/to/rules.jar")
    }
    

Solution

  • In official docs for Gradle pmd plugin there is a dependency section that explains this aspect on high-level without a real example:

    1. pmd - The PMD libraries to use
    2. pmdAux - The additional libraries that are available for type resolution during analysis. This might be useful if PMD complains about missing classes.

    In order to add the custom java rules to your project

    1. Using Gradle plugin

      apply plugin: 'pmd'
      
      repositories {
         mavenCentral() // if your rules in Maven Central
         mavenLocal()   // if your rules is in .m2 folder 
         maven {
            // if your rules are in some custom/self-hosted artifacts repository like Nexus
         }
      }
      
      dependencies {
         ...
         pmd "io.github.abc:my-pmd-rules:0.1.0" 
         pmd "commons-io:commons-io:2.11.0"     // required dependency by pmd engine
         ...
      }
      
      pmd {
         consoleOutput = true
         ruleSetFiles = files("io/github/rules/our-rules.xml")    // exactly path as in your lib classpath
         ruleSets = []                                            // Keep it as is, workaround for pmd
      }
      
    2. Using Maven plugin

      ...
      <build>
       <plugins>
         ...
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-pmd-plugin</artifactId>
           <version>3.15.0</version>
           <executions>
             <execution>
               <phase>test</phase>
               <goals>
                 <goal>check</goal>
               </goals>
             </execution>
           </executions>
           <configuration>
             <printFailingErrors>true</printFailingErrors>
             <rulesets>
               ...
               <ruleset>io/github/rules/our-rules.xml</ruleset> <!-- exactly path as in your lib classpath -->
               ...
             </rulesets>
             <excludeRoots>
               <excludeRoot>target/generated-sources/</excludeRoot>
             </excludeRoots>
           </configuration>
           <dependencies>
             <!-- your custom rules -->
             <dependency>
               <groupId>io.github.abc</groupId>
               <artifactId>my-pmd-rules</artifactId>
               <version>0.1.0</version>
             </dependency>
           </dependencies>
         </plugin>
         ...
       </plugins>
      </build>
       ...
      
    3. In case if you already have a ruleset and you just want to include the custom Java rule (that came from the library) you may define it directly in your ruleset xml as is:

        <!-- Define a rule -->
        <rule name="TheRuleName"
              language="java"
              externalInfoUrl="https://link.to.your.rule.official.docs.com"
              message="The violation message regarding your rule"
              class="io.github.rules.MissingMandatoryAnnotation">
          <priority>3</priority>
          <properties>
             ...
          </properties>
        </rule>