Search

Domino Upgrade

VersionSupport end
5.0
6.0
6.5
7.0
8.0
8.5
Upgrade to 9.x now!
(see the full Lotus lifcyle) To make your upgrade a success use the Upgrade Cheat Sheet.
Contemplating to replace Notes? You have to read this! (also available on Slideshare)

Languages

Other languages on request.

Twitter

Useful Tools

Get Firefox
Use OpenDNS
The support for Windows XP has come to an end . Time to consider an alternative to move on.

About Me

I am the "IBM Collaboration & Productivity Advisor" for IBM Asia Pacific. I'm based in Singapore.
Reach out to me via:
Follow notessensei on Twitter
(posts)
Skype
Sametime
IBM
Facebook
LinkedIn
XING
Amazon Store
Amazon Kindle
NotesSensei's Spreadshirt shop
profile for stwissel on Stack Exchange, a network of free, community-driven Q&A sites

« From Blogsphere to a Static Site (Part 5) - Comment front-end | Main| Excel in Continuous Integration »

Static APEX code analysis with PMD

Coding standard are only as good as they are followed. One venerable tool to check source code is PMD. When you, like I did, wonder what acronym PMD represents, you will be disappointed. PMD supports the usual suspects like C, C++, C#, Fortran, Java, JavaScript, Go, Groovy, XML... as well as Apex and Visualforce.

The default ruleset for Apex contains 34 rules and are the ones also used by CodeClimate

PMD is a Java application and you have a number options to run it:

  • As a command line application
  • Using ANT or Maven
  • In your CI platform (using command line, ANT or Maven )
  • Linking your Github (or Gitlab, Bitbucket) repository to a service like CodeClimate

PMD supports a series of output formats like plain, csv, html (different flavours) and XML. When you understand XSLT, the XML format allows you to render whatever report you deem fit

That is what I did. My XSLT stylesheet first shows the summary (one could render that as a dashboard), then the list of rules applied in the run, grouped by domains, then the findings by rule and finally the findings per file. Here you go:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="2.0">

    <xsl:output method="html"/>

    <xsl:template match="/">
        <html xmlns="http://www.w3.org/1999/xhtml">
            <head>
                <title>
                    <xsl:value-of select="/pmd/@timestamp"/>
                </title>
                <style type="text/css">
                    html,
                    body,
                    td{
                        font-family: Verdana, Arial, Sans-serif;
                        font-size: small
                    }
                    .filename{
                        font-weight: bold
                    }
                    .lineno{
                        color: #999999
                    }
                    h1, h2 { border-bottom: 1px solid gray; text-align: center; background-color: #CCCCCC}
                    h3 {border-left: 5px solid red; padding-left: 5px;}
                    span.rule { font-weight: bold; padding: 0; margin: 0; display: block}
                    li.rule { border-top: 1px solid gray; margin-top: 15px; }
                    a {text-decoration : none}
                    a:hover {text-decoration : underline}
                </style>
            </head>
            <body>
                <a name="top"></a><h1>Apex PMD report</h1>
                <p style="text-align: right;"><xsl:value-of select="/pmd/@timestamp"/> - v<xsl:value-of select="/pmd/@version"/></p>
                <h3>Table of content</h3>
                <ol>
                    <li><a href="#summary">Summary</a></li>
                    <li><a href="#rules">Checked rules</a></li>
                    <li><a href="#domain">Finding by rule</a></li>
                    <li><a href="#files">Finding by file</a></li>
                </ol>
                <a name="summary"></a><h2>1. Summary</h2>
                <xsl:apply-templates select="/pmd" mode="summary"/>
                <a href="#top">back to top</a>
                <a name="rules"></a><h2>2. Rules checked</h2>
                <xsl:apply-templates select="/pmd" mode="rules"/>
                <a href="#top">back to top</a>
                <a name="domain"></a><h2>3. Details by Domain</h2>
                <xsl:apply-templates select="/pmd" mode="domain"/>
                <a href="#top">back to top</a>
                <a name="files"></a><h2>4. Details by file</h2>
                <ol>
                    <xsl:apply-templates select="/pmd/file"/>
                </ol>
                <a href="#top">back to top</a>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="file">
        <li>
            <xsl:variable name="filename" select="tokenize(@name, '/')[last()]" />
            <xsl:element name="a">
            <xsl:attribute name="class">filename</xsl:attribute>
            <xsl:attribute name="name" select="$filename" />
                <xsl:value-of select="$filename"/>
            </xsl:element>
            <ol>
                <xsl:apply-templates select="violation"/>
            </ol>
        </li>
    </xsl:template>

    <xsl:template match="violation">
        <li>
            <xsl:value-of select="."/>
            <span class="lineno">(lines <xsl:value-of select="@beginline"/>-<xsl:value-of
                    select="@endline"/>)</span>
        </li>
    </xsl:template>

    <xsl:template match="pmd" mode="summary">
        <ul class="summary">
            <li>Rules checked: <xsl:value-of select="count(distinct-values(file/violation/@rule))" /></li>
            <li>Domains: <xsl:value-of select="distinct-values(file/violation/@ruleset)"/></li>
            <li>Apex files with issues: <xsl:value-of select="count(file)"/></li>
            <li>Number of finding: <xsl:value-of select="count(file/violation)" /></li>
            <xsl:for-each-group select="file/violation" group-by="@ruleset">
                <li> findings in domain <xsl:value-of select="current-grouping-key()"/>:
                    <xsl:value-of select="count(current-group())"/>
                </li>
            </xsl:for-each-group>
        </ul>
    </xsl:template>

    <xsl:template match="pmd" mode="domain">
        <xsl:for-each-group select="file/violation" group-by="@ruleset">
            <xsl:variable name="key" select="current-grouping-key()" />
            <h3><xsl:value-of select="$key"/></h3>
            <ol>
            <xsl:for-each-group select="current-group()" group-by="@rule">
                <xsl:variable name="keytwo" select="current-grouping-key()" />
                <li class="rule"><xsl:value-of select="$keytwo"/>: <xsl:value-of select="count(current-group())"/>
                    <p class="rule">like: <xsl:value-of select="current-group()[position()=1]"/></p>
                    <ol>
                        <xsl:for-each select="current-group()">
                            <xsl:variable name="sibcount" select="count(parent::node()/violation[@rule=$keytwo])" />
                            <xsl:if test="count(preceding-sibling::node()[@rule=$keytwo]) eq 0">
                                <xsl:variable name="filename" select="tokenize(../@name, '/')[last()]" />
                               <li>
                                    <xsl:element name="a">
                                        <xsl:attribute name="href">#<xsl:value-of select="$filename" /></xsl:attribute>
                                    <xsl:value-of select="$filename" />
                                    </xsl:element>
                                    : <xsl:value-of select="$sibcount" /> finding(s)
                                </li>
                            </xsl:if>
                        </xsl:for-each>
                    </ol>
                </li>
            </xsl:for-each-group>
            </ol>
        </xsl:for-each-group>
    </xsl:template>

    <xsl:template match="pmd" mode="rules">
        <xsl:for-each-group select="file/violation" group-by="@ruleset">
            <h3><xsl:value-of select="current-grouping-key()"/></h3>
            <ol>
                <xsl:for-each-group select="current-group()" group-by="@rule">
                    <li><xsl:value-of select="current-grouping-key()"/></li>
                </xsl:for-each-group>
            </ol>
        </xsl:for-each-group>
    </xsl:template>

</xsl:stylesheet>

As usual YMMV!

Comments

Disclaimer

This site is in no way affiliated, endorsed, sanctioned, supported, nor enlightened by Lotus Software nor IBM Corporation. I may be an employee, but the opinions, theories, facts, etc. presented here are my own and are in now way given in any official capacity. In short, these are my words and this is my site, not IBM's - and don't even begin to think otherwise. (Disclaimer shamelessly plugged from Rocky Oliver)
© 2003 - 2017 Stephan H. Wissel - some rights reserved as listed here: Creative Commons License
Unless otherwise labeled by its originating author, the content found on this site is made available under the terms of an Attribution/NonCommercial/ShareAlike Creative Commons License, with the exception that no rights are granted -- since they are not mine to grant -- in any logo, graphic design, trademarks or trade names of any type. Code samples and code downloads on this site are, unless otherwise labeled, made available under an Apache 2.0 license. Other license models are available on written request and written confirmation.