Introduction
In Part 1 of this post I showed how to create an XPath expression that looks for SOQL queries outside of test method or accessor classes via the PMD designer. This in itself was good fun, and there's a definite rush when you finally come up with the appropriate runes, but is of limited value. In this post I'll embed the expression in a custom rule and add it to the Salesforce CLI Scanner.
Rule
A rule needs to be inside a ruleset XML file. The PMD site has excellent documentation on this, so I won't reproduce it here for the sake of padding my post out.
A couple of key aspects of my rule is that it is an XPath expression to evaluate against Apex coded, so I need to add that detail to the definition so that the appropriate class can be instantiated to handle it:
<rule name="SoqlOnlyInTestAndAccessorClasses" language="apex" message="SOQL queries can only appear in test methods and accessor classes" class="net.sourceforge.pmd.lang.apex.rule.ApexXPathRule">
and the XPath expression itself appears in the rule properties, along with the XPath version:
<properties> <property name="version" value="2.0"/> <property name="xpath"> <value> <![CDATA[ //UserClass[not(ends-with(@Image, 'Accessor'))]/Method/ModifierNode[@Test=false()]/..// (SoqlExpression | MethodCallExpression[lower-case(@FullMethodName)='database.query']) ]]> </value> </property> </properties>
Packaging the Rule
The ruleset xml needs to be packaged as a JAR file (Java ARchive) using the tool of the same name. If I'd written a custom Java rule, I'd need to compile the class and include that in the JAR, but as I'm relying on a pre-existing class (net.sourceforge.pmd.lang.apex.rule.ApexXPathRule) I can just package the ruleset xml file.
Per the official Authoring Custom Rules documentation, my ruleset file lives at:
./category/apex/bobbuzzard.xml
so to create my JAR I execute the following command, which gives me plenty of information about what is being added:
$ jar -cvf bobbuzzard.jar ./category added manifest adding: category/(in = 0) (out= 0)(stored 0%) adding: category/apex/(in = 0) (out= 0)(stored 0%) adding: category/apex/bobbuzzard.xml(in = 1105) (out= 545)(deflated 50%)
Installing the Rule
Once I've packaged the rule, I can install it using the scanner:rule:add Salesforce CLI command, specifying the language as Apex and the JAR I just created:
$ sfdx scanner:rule:add -l apex -p bobbuzzard.jar
Successfully added rules for apex. 1 Path(s) added: /Users/kbowden/PMDRULE/bobbuzzard.jar
Per the official docs, I list the commands to ensure it went in correctly (when I was figuring all this out but didn't have my ruleset.xml file set up right, the command would succeed but the rule wouldn't be added, so verifying via the list command is definitely a step worth taking). So that I don't have to wade through a tone of output, I pipe it through grep to exclude any lines that don't contain the characters Buzzard :
$ sfdx scanner:rule:list | grep Buzzard
SoqlOnlyInTestAndAccessorClasses apex Bob Buzzard pmd
so all is well - my rule is all present and correct.
Running the Rule
All that is left is to run my rule against some sample Apex classes. The classes, and the ruleset and JAR re available at the Github repository.
I have:
- ScannerExample.cls - this has a SOQL expression and a Database.query method call, so I expect it to be flagged twice.
- ScannerExampleAccessor.cls - as above, but as it's a class name ending in Accessor I don't expect it to be flagged.
- ScannerExampleTest.cls - a test class with one SOQL expression in a test method and one in a regular method. I expect it to be flagged once regarding the regular method
$ sfdx scanner:run --target './**/*.cls' -c "Bob Buzzard"
LOCATION DESCRIPTION CATEGORY U R L
──────────────────────────────────────────────────────── ─────────────────────────────────────────────────── ─────────── ─────
force-app/main/default/classes/ScannerExample.cls:5 SOQL queries can only appear in test methods and Bob Buzzard
accessor classes
force-app/main/default/classes/ScannerExample.cls:10 SOQL queries can only appear in test methods and Bob Buzzard
accessor classes
force-app/main/default/classes/ScannerExampleTest.cls:19 SOQL queries can only appear in test methods and Bob Buzzard
accessor classes
No comments:
Post a Comment