PMD and Salesforce
PMD is a static code analysis tool, a great way to impose simple coding standards making code reviews more efficient. For instance, how often do we rework our code and forget to remove trailing variables that are no longer referenced, and how often have we pointed out to other developers that the unit test requires assert statements, or the method that they’ve written is too complex, etc… Well, PMD offers these checks along with many more. Thus, by running PMD on our code before it gets to the Peer review/QA, we can ensure that the code under review is of an expected standard, making the process less time-consuming and more efficient.
Here’s how I went about using PMD.
Objective — Run PMD rules on Apex using ANT
In short, I created a new target in the build.xml file that ANT uses. This opens up other possibilities like being able to call this target from Jenkins and running PMD rules as a stage in our deployment process as part of the continuous integration process.
Design
GIT is an optional step in the design, your code doesnt have to be committed to GIT if you want to run PMD locally. The PMD folder in this case, will be stored in the workspace where the build.xml resides.
The following diagram highlights what the end goal, i.e. running PMD rules as part of the release process.
· In my case, PMD static code analysis will be run by Jenkins as part of the CI/CD release process. (done by modifying the Jenkinsfile that defines the stages of a deployment process. The stage for running the PMD rules invokes the ant target for PMD detailed further on in this document)
· The PMD libraries will be downloaded and committed to GIT alongside the source code as well as the Apex Rulesets that PMD will be calling.
· The build.xml will be modified to include a new Ant Target that Jenkins will call in order to run the PMD static code analysis.
Downloading PMD
PMD can be downloaded from https://github.com/pmd/pmd/releases.
The current version is PMD 6.32.0 (27-February-2021). Scroll down to the ‘assets’ section and download the binary distribution, pmd-bin-6.32.0.zip.
Unzip the file and add it to your workspace folder, i.e. the folder containing the sourcecode for Salesforce.
Creating a new ANT target
Modify the build.xml to include a new target for PMD as follows
Check that the target is correctly set up by calling this target via the command line. Navigate to the current folder as you would for a Salesforce deploy. Then enter the following command to invoke PMD on the source code.
>ant pmd
At this point, expect an error saying Ruleset not found.
Defining the Ruleset
Create a new folder called apexrules (or any other meaningful name) in the same folder as the PMD library.
Some rules are available out of the box. These can be downloaded from https://github.com/pmd/pmd/releases. Navigate to the assets section and download pmd-src-6.32.0.zip and unzip this package. Navigate to pmd-src-6.32.0/pmd-apex/src/main/resources/rulesets and copy the xml files into the apexrules folder.
For my investigation I used quickstart.xml as well as created a simple rule file, called basic.xml.
Writing our own rules
Create a new xml file like the one here, basic.xml and paste the following code in it.
<rule ref=”category/apex/bestpractices.xml/UnusedLocalVariable” message=”Unused local variable, please remove!”>
<priority>5</priority>
</rule>
The ref attribute refers to the rules provided by https://pmd.github.io/latest/pmd_rules_apex_bestpractices.html#unusedlocalvariable
Similar rules can be created by extending this file or by creating new xml files.
Priority: Low (5) — The priority has been set to 5 above, but it can be increased in importance by decreasing the number.
Message allows us to provide a customised user friendly/dev friendly message.
To run any set of rules, modify the build.xml target as follows
<target name=”pmd”>
<taskdef name=”pmd” classname=”net.sourceforge.pmd.ant.PMDTask”. classpathref=”pmd.classpath”/><pmd rulesetfiles=”apexrules/basic.xml” failOnRuleViolation=”false”>
<formatter type=”text” toConsole=”true” />
<formatter type=”html” toFile=”pmd_report.html”/>
<fileset dir=”./src/”>
<include name=”**/*.cls”/>
</fileset>
</pmd>
</target>
Run the following command
> ant -v pmd
-v is for a verbose output (optional)
My build.xml has been configured to output the result to an html page, pmd_report.html.
Failing the build
OPTION 1:Fail the build on any violation of a PMD rule.
failOnRuleViolation=”true”
<pmd rulesetfiles=”apexrules/quickstart.xml” failOnRuleViolation=”true”>
<formatter type=”html” toFile=”pmd_report.html” toConsole=”true”/>
<fileset dir=”./src/”>
<include name=”**/*.cls”/>
</fileset>
</pmd>
OPTION 2: Define a threshold for the number of violations allowed before a build fails. This is useful as with the introduction of every PMD rule, the apex code needs to be adjusted accordingly to make it adhere to the new rules imposed.
maxRuleViolations=”100"
<pmd rulesetfiles=”apexrules/quickstart.xml” maxRuleViolations=”100">
<formatter type=”html” toFile=”pmd_report.html” toConsole=”true”/>
<fileset dir=”./src/”>
<include name=”**/*.cls”/>
</fileset>
</pmd>
In this instance, we define that the first 100 errors can be ignored, anything bigger will cause a build failure.