Skip to content

Advanced configuration#

The plugin supports a number of advanced behaviours. For example, it can be used to set a baseline of warnings and errors below which the build will not fail, which is very useful for legacy projects.

Table of contents#


Configurable failure thresholds#

Users can define maximum amount of warnings and errors tolerated in a build via the Gradle configuration:

staticAnalysis {
    penalty {
        maxErrors = 10
        maxWarnings = 10
    }
}

Violations are then collected while running all the static analysis tools enabled in the project and split between errors and warnings. Only in the end they are cumulatively evaluated against the thresholds provided in the configuration to decide whether the build should fail or not.

If you don't specify a penalty configuration, the plugin will use the default threshold values, which are to allow any warning, but break the build on any error.

Default penalty profiles#

Besides manually specifying thresholds, the plugin includes a few built-in penalty profiles that can be used as follows:

  • none
    staticAnalysis {
        penalty none
    }
    
    In this case the build won't fail no matter how many violations (warnings or errors) are found.
  • failOnErrors (default policy)
    staticAnalysis {
        penalty failOnErrors
    }
    
    This will break the build if any error is found. Warnings instead are only logged and will not break the build.
  • failFast
    staticAnalysis {
        penalty failFast
    }
    
    This policy will fail the build if any warning or error is found. It is a zero-tolerance policy, useful to keep the codebase clean from any warnings or errors over time.

Improve the report with a base URL#

Build logs will show an overall report of how many violations have been found during the analysis and the links to the relevant HTML reports, for instance:

    > PMD rule violations were found (2 errors, 2 warnings). See the reports at:
    - file:///foo/project/build/reports/pmd/main.html
    - file:///foo/project/build/reports/pmd/main2.html
    - file:///foo/project/build/reports/pmd/main3.html
    - file:///foo/project/build/reports/pmd/main4.html

It's possible to specify a custom renderer for the report urls in the logs via the logs extension. This can be useful in CI environments, where the local paths are not reachable directly. For instance the snippet below will replace the base URL with one mapping to an hypothetical Jenkins workspace:

staticAnalysis {
    ...
    logs {
        reportBaseUrl "http://ci.mycompany.com/job/myproject/ws/app/build/reports"
    }
}

This way, in the CI logs you will see the report URLs printed as:

> Checkstyle rule violations were found (0 errors, 1 warnings). See the reports at:
- http://ci.mycompany.com/job/myproject/ws/app/build/reports/checkstyle/main.html

And that will make them easier to follow them to the respective reports. More info on the topic can be found in the LogsExtension Groovydocs.

Add exclusions with exclude filters#

You can specify custom patterns to exclude specific files from the static analysis. All you have to do is to specify exclude in the configuration of your tool of choice:

staticAnalysis {
    pmd {
        exclude '**/*Test.java' // file pattern
        exclude project.fileTree('src/test/java') // entire folder
        exclude project.file('src/main/java/foo/bar/Constants.java') // specific file
        exclude project.sourceSets.main.java.srcDirs // entire source set
    }
}

Please note that this is not supported for Detekt. To exclude files in Detekt, please refer to the specific tool documentation in the Detekt page.

Add exclusions with Android build variants#

Sometimes using exclude filters could be not enough. When using the plugin in an Android project you may want to consider only one specific variant as part of the analysis. The plugin provides a way of defining which Android variants should be included via the includeVariants method added to each tool extension. E.g.,

staticAnalysis {
    ktlint {
        includeVariants { variant ->
            variant.name == 'debug' // only the debug variant
        }
    }
}

Please note that this is not yet supported for Detekt.

Consume rules from an artifact#

In order to reuse your rules among multiple projects or to easily use an open source rule set, we added support for consuming the rules for all supported tools from a Maven artifact.

Rules artifact#

A rule artifact is just a bundle of files that is published on a Maven repository as artifact. An example of how to do that can be found here. In this case we bundle the files as jar using the java plugin and publish it to a maven repository.

How to define a dependency from a rules artifact#

In order to access the files inside a rule artifact you have to first define an entry in the rules {} extension of the plugin. An entry is defined by a name and Maven coordinate, as follows:

staticAnalysis {
    rules {
        example {
            maven 'com.example:maven-coordinate-to-rules:0.2'
        }
    }
}

Access rules from artifact#

Once you have defined a rule artifact you can access the files inside it by specifying the path of the file inside the bundle, e.g.:

def modules = rules.example['checkstyle-modules.xml']
Note that modules is defined as TextResource, that is a read-only body of text backed by a string, file, archive entry, or other source. Some tools already accept TextResource as value for some of their configuration, while in other cases you have to transform a TextResource into a File or a path. Some examples of using a rule artifact in the supported tools are as below:

Checkstyle#

checkstyle {
    toolVersion '8.8'
    config rules.example['checkstyle-modules.xml']
}

PMD#

pmd {
    toolVersion '6.0.1'
    ruleSetFiles = project.files(rules.example['pmd-rules.xml'].asFile().path)
}

Spotbugs#

spotbugs {
    excludeFilter rules.example['spotbugs-excludes.xml'].asFile()
}

Detekt#

detekt {
    config = files(rules.example['detekt.yml'].asFile())
}

Android Lint#

lintOptions {
    lintConfig = rules.example['lint-config.xml'].asFile()
}