I recently configured a Jenkins job to execute CPD (copy paste detector) using PMD against an iOS project. For those of you who are not familiar with CPD, it is a tool which can analyze a code base to identify large chunks of code that have been duplicated. CPD is capable of ignoring differences in whitespace and literal values so that you can find similar code and not just identical code. Because of this, CPD is an invaluable ally in the constant battle against bad coding practices.
CPD supports Java, JSP, C, C++, Fortran and PHP out of the box and can be extended by writing language definitions in Java. In order to get the best results for iOS projects, I have compiled a simple Objective-C language definition based on an Objective-C JavaCC grammar which was written by a fellow named Mike Hall.
If you would like to setup CPD execution within your Jenkins iOS builds, you will need to first download CPD from this link: http://sourceforge.net/projects/pmd/files/pmd/4.2.5/
You will also need to download my generated Objective-C CPD language definition from github: https://github.com/jkennedy1980/Objective-C-CPD-Language. NOTE: It is best to download the entire project as a zip file because I have seen issues when downloading the individual release jars from github.
Once you have all the jars extracted from their zip files, you’ll want to copy the PMD and ObjCLanguage-0.0.7-SNAPSHOT jars to a location on your Jenkins box. Next, go into your Jenkins build’s configuration and add a new ‘execute shell’ build step. You’ll need to tailor the actual command to your project, but here is an example of what the command should look like:
java -Xmx512m -classpath pmd-4.2.5.jar:ObjCLanguage-0.0.7-SNAPSHOT.jar net.sourceforge.pmd.cpd.CPD --minimum-tokens 100 --files [Path to XCode project classes] --language ObjectiveC --encoding UTF-8 --format net.sourceforge.pmd.cpd.XMLRenderer > cpd-output.xml
- java – CPD is executed using the java application. Make sure you Jenkins box has a JRE installed.
- -Xmx512m - This parameter tells the JRE to allocate 512 Mb of memory for the JVM. If your project is large and you are getting out of memory or heap errors, you may want to bump this number up.
- –classpath pmd-4.2.5.jar:ObjCLanguage-0.0.7-SNAPSHOT.jar – This puts the PMD jar and the Objective C language definition onto the JVMs classpath. The paths to the 2 jars may need to be absolute paths.
- net.sourceforge.pmd.cpd.CPD — This is the main class (CPD itself) that is executed from inside the PMD jar by the java executable.
- –minimum-tokens 100 – Configures the minimum size for blocks considered to be duplicate
- –files [path] – This parameter tells CPD which files should be scanned for copy paste violations. You can provide more than one –files parameter if needed.
- –language ObjectiveC – This tells CPD to load my custom Objective-C language definition.
- –encoding UTF-8 – This allows you to specify which encoding you would like to use. [optional]
- –format net.sourceforge.pmd.cpd.XMLRenderer – This tells CPD that you would like to output the results as XML. You will need to use XML if you want to publish the results within Jenkins using the plugins mentioned below.
- > cpd-output.xml – This takes all the XML output by CPD and writes it into a file named cpd-output.xml. You can name the output file whatever you want.
Once you have tailored the command above, you can install the Violations or the DRY plugin from the Jenkins update center. I used the Violations plugin which allows you to configure limits that define when the build should be unstable or cloudy within each job’s configuration. You’ll need to be sure that you setup the Violations or DRY plugin’s configuration values so that they can find the output CPD XML file.
Once you have configured everything properly, you should see a Violations section within your job that lets you browse the duplicated code blocks that were found within your code base.
I hope you find this post helpful and that CPD helps you remove all your duplication…or your co-workers’ duplication
If you are receiving parsing errors in your output, you can now( as of version 0.0.5) add ‘-DObjC-CPD-LoggingEnabled=YES’ after java in the CPD command to enable some additional logging. The new logging will print out each file’s name as they are processed and show files names when parsing exceptions are generated. If you are redirecting the output to an XML file as I have shown in this post, you will have to open the XML file to see the logging output. Here is an example with logging enabled:
java -DObjC-CPD-LoggingEnabled=YES -Xmx512m -classpath pmd-4.2.5.jar:ObjCLanguage-0.0.7-SNAPSHOT.jar net.sourceforge.pmd.cpd.CPD --minimum-tokens 100 --files [Path to XCode project classes] --language ObjectiveC --encoding UTF-8 --format net.sourceforge.pmd.cpd.XMLRenderer > cpd-output.xml
WARNING: by enabling logging the XML output will be invalid. Logging should only enabled to assist in troubleshooting.