Static code analysis for Java and Groovy projects using Checkstyle, PMD, FindBugs and CodeNarc. Plugin implements unified console output for all quality plugins which greatly simplifies developer workflow: only console is required for working with violations and makes it feel the same as java compiler errors.
Features:
- Adds extra javac lint options to see more warnings
- Complete console output for all quality plugins
- Html and xml reports for all plugins (custom xsl used for findbugs html report because it can't generate both xml and html reports)
- Zero configuration by default: provided opinionated configs will make it work out of the box
- Task to copy default configs for customization
- Grouping tasks to run registered quality plugins for exact source set (e.g. checkQualityMain)
Releases are published to bintray jcenter, maven central and gradle plugins portal.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'ru.vyarus:gradle-quality-plugin:2.2.0'
}
}
apply plugin: 'ru.vyarus.quality'
OR
plugins {
id 'ru.vyarus.quality' version '2.2.0'
}
Plugin must be applied after java
or groovy
plugins. Otherwise it will do nothing.
IMPORTANT Plugin is compiled for java 6, but pmd 5.5 requires java 7 and checkstyle 7 requires java 8. So, by default, you will need java 8.
If you are using lower java versions either use previous plugin release (1.3.0) or manually specify lower checkstyle and pmd (if required java 6)
versions using checkstyleVersion = '6.19'
and pmdVersion = '5.4.2'
properties (note that you may need to customize provided default rules configurations to disable rules not yet available in your tool versions).
Plugin will activate Checkstyle, PMD and FindBugs plugins for java project. Java is detected by enabled java plugin and physical presence of java sources. This is required because groovy plugin is also java plugin and these tools are not required for groovy. If groovy plugin available and groovy sources exists, CodeNarc will be enabled.
For example, if groovy plugin active and there is no directory 'src/main/groovy' - CodeNarc will not be registered (suppose default plugins sources config to main only). This is common when groovy used only for tests.
If you have both java and groovy sources, then FindBugs, Checkstyle and PMD will check java sources and CodeNarc will be used for groovy.
By default, checks applied only to main sources and avoid test sources checking.
Default configs are opinionated: not all possible checks are enabled, just the sane majority of them. Also, some defaults were changed. Anyway, all disabled checks are commented in config files, so it would be clear what was disabled.
Any violation leads to build failure (strict mode) - this is the only way to keep quality and I strongly suggest not to disable it. Otherwise you'll either spent days fixing violations (someday after) or never fix them.
Of course, default behaviour could be changed
In order to execute all quality checks do:
$ gradlew check
Or use special tasks (added by plugin) to run quality checks by source:
$ gradlew checkQualityMain
In contrast to check
, this task run only quality tasks registered for Main source set without running tests.
It's better to fix all quality issues before commit.
Here are the samples of console error messages. Note that sometimes (really rare) tool could be wrong or your situation could require violation break. In this case violation could be suppressed.
Note that class line usually looks like sample.(Sample.java:0)
. This syntax allows idea (probably eclipse too)
to put direct link to source from console.
8 Checkstyle rule violations were found in 2 files
[Misc | NewlineAtEndOfFile] sample.(Sample.java:0)
File does not end with a newline.
http://checkstyle.sourceforge.net/config_misc.html#NewlineAtEndOfFile
@SuppressWarnings("NewlineAtEndOfFile")
Or with prefix (but require lower cased name):
@SuppressWarnings("checkstyle:newlineatendoffile")
To suppress all violations:
@SuppressWarnings("all")
Or using comments:
// CHECKSTYLE:OFF
..anything..
// CHECKSTYLE:ON
23 PMD rule violations were found in 2 files
[Comments | CommentRequired] sample.(Sample.java:3)
headerCommentRequirement Required
https://pmd.github.io/pmd-5.4.0/pmd-java/rules/java/comments.html#CommentRequired
@SuppressWarnings("PMD.CommentRequired")
To suppress all violations:
@SuppressWarnings("PMD")
2 (0 / 2 / 0) FindBugs violations were found in 2 files
[Performance | URF_UNREAD_FIELD] sample.(Sample.java:8) [priority 2]
>> Unread field: sample.Sample.sample
This field is never read. Consider removing it from the class.
Counts in braces show priorities (p1/p2/p3).
Note: there is no link to findbugs site, because report already contains everything from there.
To suppress violations you can use filter file. In this case you need to override default filter file (see below).
Or you can use annotations. FindBugs use custom annotations and so you need to add
com.google.code.findbugs:annotations:3.0.0
dependency (with provided scope if possible) and use:
@SuppressFBWarnings("URF_UNREAD_FIELD")
You may add additional findbugs checks by declaring findbugs plugins in findbugsPlugins
dependency configuration.
But, as findbugs plugin applied after configuration read, there are two options:
Either use afterEvaluate:
afterEvaluate {
dependencies {
findbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:6.4.1'
}
}
Or declare findbugs plugin manually (it will be configured by quality plugin):
plugins {
id 'findbugs'
}
dependencies {
findbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:6.4.1'
}
findbugsPlugins 'com.h3xstream.findsecbugs:findsecbugs-plugin:1.4.4'
fb-contrib: A FindBugs auxiliary detector plugin
findbugsPlugins 'com.mebigfatguy.fb-contrib:fb-contrib:6.6.0'
You may use jsr305 annotations to guide findbugs.
Add com.google.code.findbugs:jsr305:3.0.0
dependency (with provided scope if possible).
In some cases you will have to use it. For example, you may face issues with guava functions or predicates:
[NP_PARAMETER_MUST_BE_NONNULL_BUT_MARKED_AS_NULLABLE] input must be nonnull but is marked as nullable
The reason for this is that guava use @Nullable
annotation, which is @Inherited
, so
even if you not set annotation on your own function or predicate it will still be visible.
The simplest workaround is to set @Nonnull
annotaion (jsr305) on your function or predicate:
public boolean apply(@Nonnull final Object input) {
24 (0 / 10 / 14) CodeNarc violations were found in 2 files
[Formatting | ClassJavadoc] sample.(GSample.groovy:3) [priority 2]
>> class GSample {
Class sample.GSample missing Javadoc
Makes sure each class and interface definition is preceded by javadoc. Enum definitions are not checked, due to strange behavior in the Groovy AST.
http://codenarc.sourceforge.net/codenarc-rules-formatting.html#ClassJavadoc
Counts in braces show priorities (p1/p2/p3).
@SuppressWarnings("ClassJavadoc")
If ru.vyarus.animalsniffer applied then it will be configured the same way as other quality plugins:
animalsniffer {
toolVersion = extension.animalsnifferVersion
ignoreFailures = !extension.strict
sourceSets = extension.sourceSets
}
All quality tasks are based on SourceTask which allows excluding sources using ant patterns.
To apply exclusion to all plugins at once use:
quality {
exclude '**/sample/**'
}
This will not affect animalsniffer plugin, because it checks different thing (binary compatibility) and use it's own configuration to configure exclusions.
Findbugs task does not support exclusions on task level, so plugin manually resolve all excluded classes and add them to findbugs excludes filter xml file (default or custom user file). As a result, exclusion works the same way for all plugins.
Please note that exclusion patterns are resolved on relative paths (relative to source dir), so absolute file path matching will not work. Your pattern must match just "package" and file name parts. See example of how to overcome this in direct files exclusion chapter below.
All of the following configurations are allowed:
quality {
exclude '**/Sample.java', 'com/foo/**'
}
quality {
exclude '**/Sample.java'
exclude 'com/foo/**'
}
quality {
exclude = ['**/Sample.java', 'com/foo/**']
}
When you need to exclude sources from check, you should consider:
- Extract such sources into it's own source set and exclude this set from check. (generated classes case)
- Use pattern excludes (above) to exclude sources based on package and (or) file name
If non of the above works for you, then you did sources configuration not according to best practices. Anyway, there is last resort option for such cases (when it could not be done the right way).
Suppose we have generated sources, added to main source set:
sourceSets.main {
java {
srcDir 'build/generated/java'
}
}
Here we have two source dirs for java sources: src/main/java
and build/generated/java
.
We want to exclude them from quality check, so we try:
quality {
exclude '**/generated/**'
}
which WILL NOT WORK because gradle applies patterns relatively to build/generated/java
directory
and so our patter will never match.
Instead, specify ignored files directly, using rich gradle files api:
quality {
excludeSources = fileTree('build/generated')
}
This will exclude all files in 'generated' directory from quality tools checks.
As with patterns exclude, this will not affect animalsniffer. For findbugs, plugin will add excluded classes to exclude filter.
Another example, just to show how flexible it could be configured:
quality {
excludeSources = fileTree('build/generated').matching {
include '**/sample/**/*.java'
}
}
Exclude all java sources in sample package (in generated directory).
Include pattern here will work relatively to build/generated
directory.
You can use even single files:
quality {
excludeSources = files('build/generated/java/com/mypkg/Bad.java')
}
Exclude options could be used together (exclude files and patterns).
Each quality plugin (checkstyle, pmd, findbugs etc) registers separate quality task for each source set.
For example, checkstyleMain
and checkstyleTest
.
Then plugins looks to affected source sets (quality.sourceSets) and applies tasks only for affected source sets to check
task.
For example, by default, only main source set is configured, so only checkstyleMain
assigned to check
.
Anyway, checkstyleTest
task is registered and may be called directly (even if it's not used for project validation).
By analogy, quality plugin register grouping task for each available source set: checkQualityMain
, checkQualityTest
etc.
These tasks simply calls all quality tasks relative to source set.
For example, if we have java quality plugins registered (for example, automatically) then calling checkQualityMain
will call
checkstyleMain
, pmdMain
and findbugsMain
.
This is just a handy shortcut to run quality check tasks for exact source set without running tests (like main check
).
Generally usable to periodically check code violations.
Use quality
closure to configure plugin.
Defaults:
quality {
// Tools versions
checkstyleVersion = '7.6'
pmdVersion = '5.5.4'
findbugsVersion = '3.0.1'
codenarcVersion = '0.27.0'
animalsnifferVersion
/**
* When disabled, quality plugins will not be registered automatically (according to sources).
* Only manualy registered quality plugins will be configured.
*/
boolean autoRegistration = true
// Enable/disable tools (when auto registration disabled control configuration appliance)
checkstyle = true
pmd = true
findbugs = true
codenarc = true
/**
* The analysis effort level. The value specified should be one of min, default, or max.
* Higher levels increase precision and find more bugs at the expense of running time and
* memory consumption. Default is 'max'.
*/
findbugsEffort = 'max'
/**
* The priority threshold for reporting bugs. If set to low, all bugs are reported.
* If set to medium, medium and high priority bugs are reported.
* If set to high, only high priority bugs are reported. Default is 'medium'.
*/
findbugsLevel = 'medium'
/**
* Javac lint options to show compiler warnings, not visible by default.
* Applies to all CompileJava tasks.
* Options will be added as -Xlint:option
* Full list of options: http://docs.oracle.com/javase/8/docs/technotes/tools/windows/javac.html#BHCJCABJ
*/
lintOptions = ['deprecation', 'unchecked']
/**
* Strict quality leads to build fail on any violation found. If disabled, all violation
* are just printed to console.
*/
strict = true
/**
* When false, disables quality tasks execution. Allows disabling tasks without removing plugins.
* Quality tasks are still registered, but skip execution, except when task called directly or through
* checkQualityMain (or other source set) grouping task.
*/
boolean enabled = true
/**
* When false, disables reporting quality issues to console. Only gradle general error messages will
* remain in logs. This may be useful in cases when project contains too many warnings.
* Also, console reporting require xml reports parsing, which could be time consuming in case of too
* many errors (large xml reports).
* True by default.
*/
boolean consoleReporting = true
/**
* Source sets to apply checks on.
* Default is [sourceSets.main] to apply only for project sources, excluding tests.
*/
sourceSets = [project.sourceSets.main]
/**
* Source patterns (relative to source dir) to exclude from checks. Simply sets exclusions to quality tasks.
*
* Animalsniffer is not affected because
* it's a different kind of check (and, also, it operates on classes so source patterns may not comply).
*
* Findbugs does not support exclusion directly, but plugin will resolve excluded classes and apply
* them to xml exclude file (default one or provided by user).
*
* By default nothing is excluded.
*
* IMPORTANT: Patterns are checked relatively to source set dirs (not including them). So you can only
* match source files and packages, but not absolute file path (this is gradle specific, not plugin).
*
* @see org.gradle.api.tasks.SourceTask#exclude(java.lang.Iterable) (base class for all quality tasks)
*/
Collection<String> exclude = []
/**
* Direct sources to exclude from checks (except animalsniffer).
* This is useful as last resort, when extension or package is not enough for filtering.
* Use {@link Project#files(java.lang.Object)} or {@link Project#fileTree(java.lang.Object)}
* to create initial collections and apply filter on it (using
* {@link org.gradle.api.file.FileTree#matching(groovy.lang.Closure)}).
*
* Plugin will include files into findbugs exclusion filter xml (default one or provided by user).
*
* Note: this must be used when excluded classes can't be extracted to different source set and
* filter by package and filename is not sufficient.
*/
FileCollection excludeSources
/**
* User configuration files directory. Files in this directory will be used instead of default (bundled) configs.
*/
configDir = 'gradle/config/'
}
If you register any quality plugin manually it will be configured even if it's not supposed to be registered by project sources.
For example, project contains only java sources (/src/main/java
) and codenarc plugin registered manually:
plugins {
id 'groovy'
id 'codenarc'
id 'ru.vyarus.quality'
}
Then quality plugin will register checkstyle, pmd and findbugs plugins and configure codenarc plugin (which is not supposed to be used according to current sources).
To prevent manually registered plugin configuration use referenced quality option. For example, to prevent codenarc plugin configuration in example above:
quality {
codenarc = false
}
You can disable automatic quality plugins registration (guided by source detection) and register required plugins manually:
plugins {
id 'groovy'
id 'checkstyle'
id 'pmd'
}
quality {
autoRegistration = false
}
Here checkstyle and pmd plugins will be configured and no other plugins will be registered.
In some cases it may not be desired to see errors in console. For example, when quality control applied on existing project and you have thousands of warnings.
quality {
consoleReporting = false
}
But don't turn off console warnings in other cases: people tend to ignore problems they didn't see (practice shows that normally almost no one looks html reports of quality tools). You must see warnings for each build to finally fix them all someday (or fix them as they appear).
Console reporting use xml reports, produced by quality plugins. In case of too many errors, xml parsing could slow down build. You may use reporting disabling to speed up build a bit. In most cases (when you don't have thousands of errors) console reporting will be fast.
If you want to disable quality checks in some cases or opposite - enable quality checks for some build types, you can use:
quality {
enabled = false
}
This will disable all quality tasks (by setting task.enabled = false for each). Quality tasks will still be visible, but marked as SKIPPED on execution.
Note that enable state will not affect tasks called directly. For example, you set quality.enabled = false
and call checkstyleMain
- it will be executed.
Motivation is simple - if you call task directly then you want it to work.
Also, enabled state not affects quality tasks when quality grouping tasks called. For example, if you call checkQualityMain
- all quality plugins will be executed,
even if disabled in configuration. Motivation is the same as with direct call - you obviously want to perform quality checks.
NOTE: if quality grouping task called as dependency of other task, quality plugins will be skipped. Exceptions applies only to direct cases when expected behaviour is obvious.
It is still possible to configure plugins, but direct configuration closures will not work:
checkstyle { // will not work, because plugin will override it
...
}
But will work like this:
afterEvaluation {
checkstyle { // will be applied after plugin and override configuration
...
}
}
For plugins configuration options look:
Plugin contains predefined configurations for all plugins.
During execution default files are copied into $buildDir/quality-configs
(if no custom user configs provided).
If you want to customize them there is a task to copy everything into project:
$ gradlew initQualityConfig
It will copy all configs into configured (quality.configDir
) folder (will not override existing configs).
gradle\
config\
checkstyle\
checkstyle.xml
codenarc\
codenarc.xml
findbugs\
exclude.xml
html-report-style.xsl
pmd\
pmd.xml
Task copies all configs, but you may remove all files you don't want to customize (plugin will use default versions for them). File names are important: if you rename files plugin will not find them and use defaults.
Configuration files contain all possible rules. Not used rules are commented.
Gradle profile report (--profile
option)
shows quality tools tasks time (checkstyleMain, pmdMain etc),
which includes both tool execution time and console reporting (performed by quality plugin).
If you need to know exact console reporting time use --info
option. Plugin writes reporting execution time as info log
(see log messages starting with [plugin:quality]
just after quality tools logs).
Alternatively, you can disable console reporting and run quality tasks with --profile
again to see "pure" quality plugins time.
Checkstyle, pmd, codenarc plugins will produce both xml and html reports. Findbugs plugin could produce only xml or html report, but xml report is required for console reporting. So quality plugin have to manually generate findbugs html report using custom xsl.
You may be sure that all html reports are generated, even when console reporting is disabled. (of course, if you don't disable findbugs plugin configuration with quality.findbugs = false).
All plugins will put link to html report in general error message, except findbugs which will have to put link to xml report. Link to findbugs html report is printed to console manually after errors reporting. If console reporting disabled, findbugs html report path is not printed, because it should be shown only when errors found, but quality plugin can't know it without parsing xml report (which is useless without console reporting).
- pom-plugin - improves pom generation
- java-lib-plugin - avoid boilerplate for java or groovy library project
- github-info-plugin - pre-configure common plugins with github related info
- animalsniffer-plugin - java compatibility checks
- java-library generator - java library project generator