当今的软件开发需要使用许多不同的工具和技术来确保代码质量和稳定性。PMD是一个流行的静态代码分析工具,可以帮助开发者在编译代码之前发现潜在的问题。在本文中,我们将讨论如何在Gradle中使用PMD,并介绍一些最佳实践。
什么是PMD?
PMD是一个用于Java代码的静态代码分析工具。它可以帮助开发者找出潜在的问题,如代码重复、未使用的变量、错误的异常处理等。PMD支持多种规则,可以根据具体项目的需要进行配置。其工作原理参考How PMD Works。
PMD支持通过命令行界面(CLI, Command Line Interface for batch scripting)和其他多种集成方式,比如Maven、Gradle、Java API等等。
PMD在Gradle中配置和使用
Gradle中自带了PMD插件,插件的默认版本可以通过源码DEFAULT_PMD_VERSION知道。使用和配置可以参考The PMD Plugin,页面左上角可以选择Gradle版本,确保查看的版本和你使用的Gradle版本一致,因为很多PMD的配置属性或者功能不一定在每个版本都有。
通过页面左上角选了其他版本后跳转的地址是Gradle文档的首页,而不是PMD插件的文档页。我们可以通过修改The PMD Plugin链接中的8.0.2
为其他版本号即可跳转到对应Gradle版本包含的PMD插件文档的页面。比如:
当前最新版:https://docs.gradle.org/current/userguide/pmd_plugin.html
7.3.3版本:https://docs.gradle.org/7.3.3/userguide/pmd_plugin.html
在项目build.gradle文件中增加以下内容应用插件和扩展PMD,参考Usage和Configuration,更多的配置属性可以参考PmdExtension。
plugins {
id 'pmd'
}
pmd {
// 是否将 PMD 结果输出到终端
consoleOutput = true
// 要使用的PMD版本
toolVersion = "6.21.0"
// 规则优先级阈值,低于这个优先级则会被忽略
rulesMinimumPriority = 5
// 使用的规则集配置文件路径
ruleSets = ["category/java/errorprone.xml", "category/java/bestpractices.xml"]
}
插件会生成两个主要的PMD TaskpmdMain和pmdTest分别对main和test两个项目源文件目录使用PMD进行代码检查。
找到IDEA Gradle窗口 > Tasks > other
,双击生成的Task;或者在项目根目录运行./gradlew pmdMain
都可以运行PMD。检查结果将输出到终端中(前提是配置了consoleOutput = true
),违反了PMD规则的类会给出完整的跳转路径以及规则提示信息。
最后还会给出一个报告的地址,内容包含了输出到终端的信息。Problem列出了规则的提示,点击可以跳转到PMD规则描述文档对应的位置。
Gradle PMD Plugin扩展属性
在这里我们将PMD插件的扩展属性作用进行说明,参考PmdExtension,这个文档详细说明了各个属性的作用、默认值和配置示例。如果文档描述的不是很清楚也可以参考PMD CLI options的对应描述。
consoleOutput
是否将结果输出到终端(System.out
)允许值为true|false
。
ignoreFailures
如果出现了警告,是否允许继续构建,允许值为true|false
。
配置为否(false),在执行build的时候(build任务中默认包含了pmdMain和pmdTest),如果发现了代码有违反规则,将会中断构建过程;配置为是(true),将不会中断构建,只是输出报告信息。
maxFailures
停止构建前允许的最大失败次数。
incrementalAnalysis
是否开启增量分析,允许值为true|false
。在pmd docs Incremental Analysis中详细描述了增量分析的相关信息。简单来说,开启了增量分析,PMD会缓存分析数据和结果,后续分析仅查看那些新的/已更改的文件,以此显著减少分析的时间,在Gradle中,这个功能使用PMD6.0.0
及以上版本才有。
但是有一些情况会导致增量分析的缓存失效:使用PMD的版本发生了变化;使用的规则集已更改;被分析的代码的类路径已更改;被分析代码依赖的库的类路径已更改。具体参考When is the cache invalidated?
在以上前提下,即使切换分支缓存也是有效的,甚至还支持在不同的机器重复使用缓存文件。参考Can I reuse a cache created on branch A for analyzing my project on branch B? 和Can I reuse a cache file across different machines?
reportsDir
报告生成的路径。
ruleSetFiles
要使用的自定义规则集文件路径,可以在files()
中填多个路径。
ruleSetFiles = files("config/pmd/myRuleSet.xml")
ruleSetConfig
跟ruleSetFiles
的作用一样,不过只能填一个文件路径。
ruleSetConfig = resources.text.fromFile("config/pmd/myRuleSet.xml")
ruleSets
指定使用的规则集,默认值为["category/java/errorprone.xml"]。
建议如果配置了ruleSetFiles
或者ruleSetConfig
,就将ruleSets
配置为空(ruleSets = []
),以免互相干扰,官方文档Custom ruleset给出的例子也是如此。
ruleSets = ["category/java/errorprone.xml", "category/java/bestpractices.xml"]
rulesMinimumPriority
每个规则都有个优先级,是从 1 到 5 的整数,其中 1 是最高优先级,参考[Message and priority overriding,每个规则的优先级参考Java Rules。rulesMinimumPriority
的作用是配置报告的最低优先级,低于这个优先级的规则将被忽略。比如配置rulesMinimumPriority = 4
,优先级为 5 的规则将被忽略。
sourceSets
作为 check
和 build
任务的一部分进行分析的源代码集合,配置方式参考SourceSet。
targetJdk
PMD使用的JDK版本。有些规则可能会要求JDK的最低或者最高版本,具体要求参考Java Rules。
threads
PMD 运行时使用的线程数。
toolVersion
要使用的PMD的版本。