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.
- Configurable failure thresholds
- Improve the report with a base URL
- Add exclusions with
exclude
filters - Add exclusions with Android build variants
- Consume rules from an artifact
- Custom violations evaluator (incubating)
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.
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.
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.
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 {
findbugs {
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.
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 {
findbugs {
includeVariants { variant ->
variant.name == 'debug' // only the debug variant
}
}
}
Please note that this is not yet supported for Detekt.
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.
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 be found here. In this case we bundle the files as jar using the using the java plugin and publish it using our bintray-release plugin.
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 a Maven coordinate, as follows:
staticAnalysis {
rules {
novoda {
maven 'com.novoda:static-analysis-rules:0.2'
}
}
}
Once you have defined a rule artifact you can access the files inside it specifying the path of the file inside the bundle, e.g.:
def modules = rules.novoda['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 of the 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 is provided below:
checkstyle {
toolVersion '8.8'
config rules.novoda['checkstyle-modules.xml']
}
pmd {
toolVersion '6.0.1'
ruleSetFiles = project.files(rules.novoda['pmd-rules.xml'].asFile().path)
}
findbugs {
excludeFilter rules.novoda['findbugs-excludes.xml'].asFile()
}
detekt {
profile('main') {
config = rules.novoda['detekt.yml'].asFile().path
}
}
lintOptions {
lintConfig = rules.novoda['lint-config.xml'].asFile()
}