vlambda博客
学习文章列表

读书笔记《gradle-effective-implementations-guide-second-edition》维护代码质量

Chapter 9. Maintaining Code Quality

在进行项目时,我们希望有某种工具或流程,我们可以使用它们来查看我们的代码是否遵循某些标准;要么我们的代码没有常见的编码问题,要么它计算了代码的复杂度。

我们需要这些工具来编写更好的代码。更好的代码意味着它更容易维护,这降低了维护代码的成本。在项目团队中,我们希望确保代码遵循项目团队定义的相同标准。公司可以定义一组开发人员需要遵循的标准,作为项目启动的条件。

Java 和 Groovy 项目已经有一些工具可以用来分析和检查源代码,例如 CheckstyleJDependPMD FindBugs 和 CodeNarc。 Gradle 为这些工具中的每一个都提供了插件。在本章中,我们将看看以下插件并讨论如何在我们的项目中使用它们:

  • 格纹风格

  • PMD

  • 查找错误

  • 依赖

  • CodeNarc

Using the Checkstyle plugin


如果我们正在处理一个 Java 项目,并且我们将 Java 插件应用到我们的项目中,我们将得到一个名为 check 的空任务。这是 build 任务的依赖任务。这意味着当我们执行 build 任务时, check 任务也会被执行。我们可以编写自己的任务来检查项目中的某些内容,并使其成为 check 任务的依赖任务。所以如果 check任务被执行,我们自己的任务也会被执行。不仅是我们自己编写的任务,插件也可以向check任务添加新的依赖任务。

在本章中,我们将看到大多数插件会将一个或多个任务作为依赖任务添加到 check 任务中。这意味着我们可以将插件应用到我们的项目中,当我们调用 check 或 build 任务时,额外的插件的任务是自动执行的。

此外,check 任务依赖于 test 任务。 Gradle 将始终确保  test 任务在  check 任务之前执行,因此我们知道所有源文件和编译测试源文件,并在检查代码之前运行测试。要将 Checkstyle 分析添加到我们的项目中,我们只需应用 checkstyle 插件,如下所示:

apply plugin: 'java' 
apply plugin: 'checkstyle' 

如果我们从命令行调用 tasks 任务,我们可以看到插件已经添加了新任务:

$ gradle tasks --all
:tasks
------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------
...
Verification tasks
------------------
check - Runs all checks. [classes, test, testClasses]
checkstyleMain - Run Checkstyle analysis for main classes
checkstyleTest - Run Checkstyle analysis for test classes
test - Runs the unit tests. [classes, testClasses]
...
BUILD SUCCESSFUL
Total time: 1.194 secs

checkstyleMain 和 checkstyleTest 任务被添加为 check 的依赖项任务。这些任务对主类和测试类运行 Checkstyle 分析。

我们还不能执行这些任务,因为我们必须在我们的项目中添加一个 Checkstyle 配置文件。此文件包含我们要应用于代码的规则。该插件会在我们项目的config/checkstyle目录中寻找checkstyle.xml文件。这是默认位置和文件名,但我们可以更改它。

让我们创建一个包含以下内容的配置文件:

<?xml version="1.0"?> 
<!DOCTYPE module PUBLIC "-//Puppy Crawl//DTD Check Configuration 1.3//EN" "http://www.puppycrawl.com/dtds/configuration_1_3.dtd"> 
<module name="Checker"> 
    <module name="JavadocPackage"/> 
    <module name="NewlineAtEndOfFile"/> 
    <module name="RegexpSingleline"> 
      <property name="format" value="\s+$"/> 
      <property name="minimum" value="0"/> 
      <property name="maximum" value="0"/> 
      <property name="message" value="Line has trailing spaces."/> 
    </module> 
 
    <module name="TreeWalker"> 
      <module name="IllegalImport"/> 
      <module name="RedundantImport"/> 
      <module name="UnusedImports"/> 
      <module name="AvoidNestedBlocks"/> 
      <module name="EmptyBlock"/> 
      <module name="LeftCurly"/> 
      <module name="NeedBraces"/> 
      <module name="RightCurly"/> 
      <module name="DesignForExtension"/> 
      <module name="FinalClass"/> 
      <module name="HideUtilityClassConstructor"/> 
      <module name="InterfaceIsType"/> 
      <module name="VisibilityModifier"/> 
    </module> 
 
</module> 

checkstyle 插件不会自动将所需的库依赖项添加到我们的项目中。我们需要在我们的项目中添加一个适当的存储库,以便 checkstyle 插件可以下载所有依赖项。

让我们创建以下示例构建文件并添加存储库定义:

apply plugin: 'java' 
apply plugin: 'checkstyle' 
 
repositories { 
    // Add repository so Checkstyle 
    // dependencies can be downloaded. 
    jcenter() 
} 

现在我们可以运行 check 任务并查看输出:

$ gradle check
:compileJava
:processResources UP-TO-DATE
:classes
:checkstyleMain
[ant:checkstyle] /Projects/gradle-bookChapter9/Code_Files/checkstyle/src/main/java/gradle/sample/JavaSample.java:0: File does not end with a newline.
[ant:checkstyle] /Projects/gradle-bookChapter9/Code_Files/checkstyle/src/main/java/gradle/sample/JavaSample.java:0: Missing package-info.java file.
[ant:checkstyle] /Projects/gradle-bookChapter9/Code_Files/checkstyle/src/main/java/gradle/sample/JavaSample.java:9: Line has trailing spaces.
[ant:checkstyle] /Projects/gradle-bookChapter9/Code_Files/checkstyle/src/main/java/gradle/sample/JavaSample.java:14: Line has trailing spaces.
[ant:checkstyle] /Projects/gradle-bookChapter9/Code_Files/checkstyle/src/main/java/gradle/sample/JavaSample.java:15: Line has trailing spaces.
[ant:checkstyle] /Projects/gradle-bookChapter9/Code_Files/checkstyle/src/main/java/gradle/sample/JavaSample.java:17:5: Method 'setGreeting' is not designed for extension - needs to be abstract, final or empty.
[ant:checkstyle] /Projects/gradle-bookChapter9/Code_Files/checkstyle/src/main/java/gradle/sample/JavaSample.java:21:5: Method 'getGreeting' is not designed for extension - needs to be abstract, final or empty.
[ant:checkstyle] /Projects/gradle-bookChapter9/Code_Files/checkstyle/src/main/java/gradle/sample/JavaSample.java:25:5: Method 'greet' is not designed for extension - needs to be abstract, final or empty.
[ant:checkstyle] /Projects/gradle-bookChapter9/Code_Files/checkstyle/src/main/java/gradle/sample/JavaSample.java:29:5: Method 'equals' is not designed for extension - needs to be abstract, final or empty.
:checkstyleMain FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':checkstyleMain'.
> Checkstyle rule violations were found. See the report at: file:///Projects/gradle-book/Chapter9/Code_Files/checkstyle/build/reports/checkstyle/main.html
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: 1.296 secs

checkstyleMain 任务已执行,但构建失败,因为我们的代码不符合我们的 Checkstyle 规则。在输出中,我们可以看到所有违反规则的行为。 Gradle 还将在 build/reports/checkstyle 目录中创建一个包含违规的 XML 和 HTML 文件。

如果我们不希望构建失败,我们可以使用 checkstyle 任务的 ignoreFailures 属性。检查仍在执行并生成报告文件,但构建不会失败。

我们可以在 Gradle 构建中使用 checkstyle{} 脚本块或 checkstyle 属性配置 checkstyle 插件。脚本块接受配置闭包,我们可以在其中更改属性。在下面的构建文件中,我们将 ignoreFailures属性设置为true,这样Checkstyle发现错误后构建也不会失败:

apply plugin: 'java' 
apply plugin: 'checkstyle' 
 
repositories { 
    jcenter() 
} 
 
// Configuration for Checkstyle. 
checkstyle { 
    // The build will not fail if there 
    // are violations found. 
    ignoreFailures = true 
} 

要更改 Gradle 使用的 Checkstyle 版本,请在 checkstyle{} 配置块中设置 toolVersion 属性。我们可以分配与 Gradle 中默认可用的版本不同的版本。

在以下示例构建文件中,我们将使用 toolVersion 属性来使用 Checkstyle 版本 5.7

apply plugin: 'java' 
apply plugin: 'checkstyle' 
 
repositories { 
    jcenter() 
} 
 
checkstyle { 
    // Use version 5.7 of Checkstyle. 
    toolVersion = '5.7' 
} 

该插件还添加了一个新的依赖配置,名为 checkstyle。我们将使用此配置来添加 Checkstyle 工具所需的依赖项。

要更改 Checkstyle 配置文件,我们可以在 checkstyle{} 配置块中将 configFile 属性设置为不同的值。默认值为 config/checkstyle/checkstyle.xml。例如,我们可以将  sun_checks.xml 配置文件从 Checkstyle 分发版复制到  config/checkstyle 目录。我们将使用这个新文件的值设置 configFile 属性,并使用 sun_checks.xml 配置文件。

以下示例构建文件显示我们引用了另一个 Checkstyle 配置文件:

apply plugin: 'java' 
apply plugin: 'checkstyle' 
 
repositories { 
    jcenter() 
} 
 
// Configuration for Checkstyle. 
checkstyle { 
    // Use a different configuration file. 
    configFile = file('config/checkstyle/sun_checks.xml') 
} 

Checkstyle 配置支持属性扩展。这意味着配置文件具有使用 ${propertyName} 语法的可变属性值。我们可以使用 Checkstyle 配置闭包的 configProperties 属性设置此类属性的值。该属性接受一个映射,其中键是 Checkstyle 配置文件中的属性名称,值是属性值。如果 Checkstyle 配置文件有一个属性,命名为 tabWidth;例如,我们可以使用以下示例构建文件设置值:

apply plugin: 'java' 
apply plugin: 'checkstyle' 
 
repositories { 
    jcenter() 
} 
 
// Configuration for Checkstyle. 
checkstyle { 
    // Define key-value pairs to replace properties 
    // in the configuration file. 
    configProperties = [tabWidth: 10] 
} 

我们使用 checkstyle{} 脚本块来更改项目中所有 checkstyle 任务的属性。但是,我们也可以在构建文件中配置单独的checkstyle 任务。我们有 checkstyleMain 和 checkstyleTest 任务,我们可以像任何其他任务一样更改它们的配置。

让我们创建以下示例构建文件并更改 checkstyleTest 任务的属性,这将覆盖 checkstyle{}脚本块:

apply plugin: 'java' 
apply plugin: 'checkstyle' 
 
repositories { 
    jcenter() 
} 
 
// Set checkstyle options, that are used by 
// all checkstyle tasks. 
checkstyle { 
    configFile = file('config/checkstyle/sun_checks.xml') 
} 
 
// Reconfigure the checkstyleTest task. 
checkstyleTest { 
    configFile = file('config/checkstyle/test.xml') 
    ignoreFailures = true 
} 

如果我们在构建中定义了自定义源集,那么 checkstyle 插件会自动将一个checkstyle<SourceSet> 任务添加到项目。如果我们的源集被命名为 api,那么我们可以调用 checkstyleApi 任务来只检查这个源集。  checkstyleApi 任务也被添加为 check 任务的依赖任务。因此,一旦我们运行 check 任务,Gradle 也会调用 checkstyleApi 任务。

在以下示例构建文件中,我们将创建一个名为 api 的新源集:

apply plugin: 'java' 
apply plugin: 'checkstyle' 
 
repositories { 
    jcenter() 
} 
 
sourceSets { 
    // Add new source set with 
    // the name api. This will 
    // add a task checkstyleApi. 
    api 
} 

如果我们调用 tasks 任务,我们可以在输出中看到添加了一个新创建的任务 checkstyleApi,这是一个 check 任务的依赖任务:

$ gradle tasks --all
:tasks
------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------
...
Verification tasks
------------------
check - Runs all checks. [apiClasses, classes, test, testClasses]
 checkstyleApi - Run Checkstyle analysis for api classes
 checkstyleMain - Run Checkstyle analysis for main classes
 checkstyleTest - Run Checkstyle analysis for test classes
test - Runs the unit tests. [classes, testClasses]
...

生成的报告 XML 文件放置在 build/reports/checkstyle 目录中。文件的名称基于源集名称。因此 checkstyleMain 任务将生成 build/reports/checkstyle/main.xml 报告文件。我们可以在构建文件中配置它。我们可以使用 reportsDir 属性更改包含报告的目录。我们可以使用 destination 属性更改特定 checkstyle 任务的目标文件。我们还可以使用给定任务的 enabled 属性禁用报告生成。

以下示例构建文件更改了 checkstyleMain 任务的报告目录和目标文件,并禁用了 checkstyleTest 任务的报告生成:

apply plugin: 'java' 
apply plugin: 'checkstyle' 
 
repositories { 
    jcenter() 
} 
 
checkstyle { 
    // Change the output directory. 
    reportsDir = file("${buildDir}/checkstyle-output") 
} 
 
checkstyleTest { 
    // Disable running CheckStyle for the test classes. 
    reports.xml.enabled = false 
} 
 
// Configure the checkstyle task for the main source set. 
checkstyleMain { 
    reports { 
        xml { 
            // Change the destination and filename of the 
            // XML file with results generated by CheckStyle. 
            destination = file("${checkstyle.reportsDir}/checkstyle.xml") 
        } 
    } 
} 

Using the PMD plugin


另一个分析 Java 源代码的工具是 PMD。它会查找未使用的变量、空的 catch 块、不必要的对象创建等。我们可以配置自己的规则集,甚至定义自己的规则。要将 PMD 与 Gradle 一起使用,我们必须将 PMD 插件应用到我们的构建中。添加插件后,我们已经安装了 pmdMain 和 pmdTest 任务。这些任务将为主要和测试源集运行 PMD 规则。如果我们有自定义源集,那么插件也会添加一个 pmd<SourceSet> 任务。这些任务也是 check任务的依赖任务。所以如果我们调用 check任务,所有的 pmd任务也会被执行。

这个插件只定义了一个与 PMD 一起工作的结构,但它不包含实际的 PMD 库依赖项。 Gradle 将在我们第一次调用 pmd 任务时下载 PMD 依赖项。我们必须定义一个包含 PMD 库的存储库,例如 Bintray JCenter 存储库或公司内部网存储库。

在以下构建文件中,我们应用 pmd 插件并定义自定义源集:

apply plugin: 'java' 
apply plugin: 'pmd' 
 
repositories { 
    // We need a repository, so the 
    // PMD dependencies can be downloaded. 
    jcenter() 
} 
 
sourceSets { 
    // New source set with 
    // the name util. 
    util 
} 

当我们调用 check 任务时,如果没有违反规则,我们会得到以下输出:

$ gradle check
:pmdMain
:compileJava
:processResources UP-TO-DATE
:classes
:pmdTest UP-TO-DATE
:pmdUtil
:compileTestJava UP-TO-DATE
:processTestResources UP-TO-DATE
:testClasses UP-TO-DATE
:test UP-TO-DATE
:check
BUILD SUCCESSFUL
Total time: 1.735 secs

注意 pmdMainpmdTest 和  pmdUtil 任务执行。

如果其中一个文件存在违规,则默认情况下构建将失败。我们可以将pmd 任务的ignoreFailures 属性设置为true,这样构建就不会失败。以下示例构建展示了如何将 ignoreFailures 属性设置为 true:

apply plugin: 'java' 
apply plugin: 'pmd' 
 
repositories { 
    jcenter() 
} 
 
sourceSets { 
    util 
} 
 
pmd { 
    // Don't fail the build process when 
    // rule violations are found. 
    ignoreFailures = true 
} 

规则违规将在 build/reports/pmd 目录中的 XML 和 HTML 文件中报告。文件的名称与源集名称相同。我们可以更改报告目录的名称和输出文件名,也可以禁用报告生成。

以下示例构建文件使用 pmd 任务更改报告的几个属性:

apply plugin: 'java' 
apply plugin: 'pmd' 
 
repositories { 
    jcenter() 
} 
 
sourceSets { 
    util 
} 
 
pmd { 
    // Change base reporting dir for PDM reports. 
    reportsDir = file("${reporting.baseDir}/pmd-output") 
} 
 
configure(tasks.withType(Pmd)) { 
    // Disable HTML report generation for all PDM tasks. 
    reports.html.enabled = false 
} 
 
// Special configuration for the pmd task 
// that runs for the source set main. 
pmdMain { 
    reports { 
        xml { 
            // Change output file for XML report. 
            destination = file("${pmd.reportsDir}/pmd.xml") 
      } 
    } 
} 

如果我们不在构建文件中定义任何其他内容,则仅应用 PMD 的基本规则集。要更改应用的规则集,我们可以使用 ruleSets 属性和ruleSets() 方法。使用 ruleSets() 方法,我们可以方便地添加新规则。使用 ruleSets 属性,我们必须定义我们想要用作属性分配的所有规则。

除了配置规则集,我们还可以为 pmd 任务分配规则集文件。规则集文件包含多个规则并允许自定义规则。要添加规则集文件,我们可以使用 ruleSetFiles 属性或 ruleSetFiles() 方法。我们需要引用一个文件来设置属性或将其作为方法参数传递。

以下示例构建文件显示了如何设置规则和规则集文件:

apply plugin: 'java' 
apply plugin: 'pmd' 
 
repositories { 
    jcenter() 
} 
 
pmd { 
    // Add rule sets with the ruleSets method. 
    ruleSets 'design', 'braces' 
 
    // Or use property syntax. 
    // ruleSets = ['design', 'braces'] 
 
    // Set rule set files via the task 
    // property ruleSetFiles. 
    ruleSetFiles = files('config/pmd/customRules.xml') 
 
    // Or use ruleSetFiles method to add new file 
    // to existing collection of files. 
    //ruleSetFiles file('config/pmd/customRules.xml') 
} 

要更改我们要使用的 PMD 版本,我们必须设置 PMD 插件的 toolVersion 属性。在编写本书时,它设置为 5.2.3 版本,但如果需要,我们可以将其更改为其他版本。在以下示例构建文件中,我们将使用 toolVersion 属性将版本简单地更改为 5.2.3:

apply plugin: 'java' 
apply plugin: 'pmd' 
 
repositories { 
    jcenter() 
} 
 
pmd { 
    // Use a different version of PMD. 
    toolVersion = '5.4.1' 
} 

Using the FindBugs plugin


FindBugs 是另一个我们可以用来分析源代码的库。要在我们的 Gradle 构建中使用 FindBugs,我们只需应用 findbugs 插件。我们可以将一个源代码分析插件应用到我们的项目中,也可以应用多个插件。每个工具都有不同的功能。这仅取决于我们要检查的内容或公司政策规定的内容。该插件将添加 findbugsMain 和 findbugsTest 任务来分析主要和测试源集中的源代码。如果我们有自定义源集,那么 findbugs<SourceSet> 任务也会添加到插件中。这些任务都是 check任务的依赖任务。

与其他代码质量插件一样,Gradle 不包含 FindBugs 依赖项,但它们会在我们第一次使用 findbugs 任务时下载。我们必须包含一个存储库定义,使 Gradle 能够找到 FindBugs 依赖项。要更改正在使用的 FindBugs 版本,我们可以设置添加到我们的 findbugs 插件扩展的 toolVersion 属性 findbugs 插件的项目。

在以下构建文件中,我们将应用 findbugs 插件并配置一个额外的源集,名为 webservice

apply plugin: 'java' 
apply plugin: 'findbugs' 
 
repositories { 
    // We need to set a repository where the 
    // Findbugs dependencies can be downloaded from. 
    jcenter() 
} 
 
findbugs { 
    // Default version with Gradle 2.10 is 3.0.1. 
    toolVersion = '3.0.0' 
} 
 
sourceSets { 

    // New source set with the name webservice. 
    webservice 
} 

当我们执行 tasks 任务时,我们会看到 findbugsMainfindbugsTest 和 findbugsWebservice 任务是 check 任务的依赖项:

$ gradle tasks --all
:tasks
------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------
...
Verification tasks
------------------
check - Runs all checks. [classes, test, testClasses, webserviceClasses]
 findbugsMain - Run FindBugs analysis for main classes
 findbugsTest - Run FindBugs analysis for test classes
 findbugsWebservice - Run FindBugs analysis for webservice classes
test - Runs the unit tests. [classes, testClasses]
...

如果 FindBugs 在我们的源代码中发现违反规则,那么构建将失败。我们可以将 ignoreFailures 属性设置为 true,如下面的代码行所示,以确保即使发现违规也能继续构建:

apply plugin: 'java' 
apply plugin: 'findbugs' 
 
repositories { 
    jcenter() 
} 
 
// Global setting for all findbugs tasks. 
findbugs { 
    ignoreFailures = true 
} 
 
// We can change ignoreFailures property also per task. 
findbugsMain { 
    ignoreFailures = false 
} 

该插件在 build/reports/findbugs 目录中生成带有 FindBugs 分析结果的 XML 报告。 XML 文件的名称与所分析的源集的名称相同。我们还可以配置插件,以便生成 HTML 报告。在以下构建文件中,我们将在 findbugs插件中配置报告:

apply plugin: 'java' 
apply plugin: 'findbugs' 
 
repositories { 
    jcenter() 
} 
 
findbugs { 
    // Change base directory for FindBugs reports. 
    reportsDir = file("${reporting.baseDir}/findbugs-output") 
} 
 
// Configure the findbugs task for the main source set. 
findbugsMain { 
    reports { 
        html { 
            enabled = true 
 
            // Change output file name. 
            destination = "${findbugs.reportsDir}/findbugs.html" 
        } 
 
        // Only one report (xml or html) can be active. 
        xml { 
            enabled = !html.enabled 
        } 
    } 
} 

如果我们想使用 findbugs 插件,我们可以将它们定义为依赖项。  findbugs 插件添加了一个 findbugs 依赖配置。我们可以为这个配置分配插件依赖, findbugs 任务会使用这些插件来分析代码。

Using the JDepend plugin


要获得代码库的质量指标,我们可以使用 JDepend。 JDepend 遍历我们项目中生成的类文件,并生成设计质量指标。要使用 JDepend,我们只需在项目中应用 jdepend 插件。这将添加 jdependMain 和 jdependTest 任务。对于我们项目中的每个额外源集,都会添加一个 jdepend<SourceSet> 任务。这些任务都是 check任务的依赖任务。

我们必须配置一个存储库,以便 Gradle 可以获取 JDepend 依赖项。 Gradle 在 Gradle 发行版中不提供 JDepend 库。这意味着我们可以轻松地使用另一个版本的 JDepend,独立于我们正在使用的 Gradle 版本。我们在其他代码质量插件中也看到了这种行为。要更改版本号,我们只需设置 jdepend 插件扩展的 toolVersion 属性。

在以下示例构建文件中,我们将应用 jdepend 插件并创建一个额外的源集:

apply plugin: 'java' 
apply plugin: 'jdepend' 
 
repositories { 
    // Repository is need to the JDepend dependencies 
    // can be downloaded. 
    jcenter() 
} 
 
// We can change the version of JDepend to be used. 
jdepend{ 
    // Default version with Gradle 2.10 is JDepend 2.9.1 
    toolVersion = '2.9.1' 
} 
 
// Custom source set so jdependRestApi task is created. 
sourceSets { 
    restApi 
} 

当我们调用 tasks 任务时,我们会看到创建了三个 jdepend 任务作为 检查 任务:

$ gradle tasks --all
:tasks
------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------
...
Verification tasks
------------------
check - Runs all checks. [classes, restApiClasses, test, testClasses]
 jdependMain - Run JDepend analysis for main classes
 jdependRestApi - Run JDepend analysis for restApi classes
 jdependTest - Run JDepend analysis for test classes
test - Runs the unit tests. [classes, testClasses]
...

jdepend 任务创建关于我们代码的统计信息。结果存储在 build/reports/jdepend 目录中的 XML 文件中。我们可以配置 jdepend 插件,以便我们存储报告的目录不同于默认目录。对于每个jdepend 任务,我们还可以更改输出格式。我们可以生成一个包含代码统计信息的文本文件,而不是 XML。我们必须在 XML 和文本之间做出选择;我们不能为单个 jdepend 任务选择两个报告输出。

以下示例构建文件显示了有关如何使用有关我们的源代码的信息更改报告的几个选项:

apply plugin: 'java' 
apply plugin: 'jdepend' 
 
repositories { 
    // Repository is need to the JDepend dependencies 
    // can be downloaded. 
    jcenter() 
} 
 
// We can change the version of JDepend to be used. 
jdepend{ 
    reportsDir = file("${reporting.baseDir}/jdepend-output") 
} 
 
// Configure JDepend for the main source set. 
jdependMain { 
    reports { 
        // Configure text output. 
        text { 
            enabled = true 
 
            // Set destination file. 
            destination = file("${jdepend.reportsDir}/jdepend.txt") 
        } 
        xml { 
            // Only text or XML output can be enabled. 
            enabled = !text.enabled 
        } 
    } 
} 

Using the CodeNarc plugin


要检查用 Groovy 语言编写的代码,我们可以使用 CodeNarc。 CodeNarc 有几个规则可以对 Groovy 代码进行静态分析。 Gradle 有一个 codenarc 插件,因此我们可以将 CodeNarc 中的规则应用到我们的 Groovy 代码库中。如果我们应用插件,我们会自动获得一个 codenarcMain 和 codenarcTest 目标。此外,对于每个自定义源集,我们都会获得一个新的 codenarc<SourceSet> 任务。所有这些任务都是 check任务的依赖任务。

Gradle 中不包含 CodeNarc 库。我们需要在包含 CodeNarc 的构建文件中定义一个存储库。如果我们调用 codenarc 任务,则 Gradle 会设置 CodeNarc 依赖项。我们可以通过设置插件扩展的 codenarc属性的 toolVersion来更改我们想要使用的CodeNarc版本。

该插件定义我们在config/codenarc目录下提供一个名为codenarc.xml的CodeNarc配置文件。我们可以使用插件扩展的 configFile 属性更改对配置文件的引用。

让我们创建以下示例构建文件并为 Groovy 项目应用 codenarc 插件。我们将 CodeNarc 的版本更改为我们想要使用的版本。我们还将CodeNarc配置文件的位置重新定义为 config/codenarc/custom.xml

apply plugin: 'groovy' 
apply plugin: 'codenarc' 
 
repositories { 
    // Define repository for downloading 
    // Codenarc dependencies. 
    jcenter() 
} 
 
codenarc { 
    // Change version of CodeNarc. 
    toolVersion = '0.24.1' 
 
    // Change name of configuration file. Default value 
    // is file('config/codenarc/codenarc.xml') 
    configFile = file('config/codenarc/rules.groovy') 
} 

当我们运行检查任务并且我们的 Groovy 代码库开始违反配置的 CodeNarc 规则时,构建将失败。如果我们不希望构建因违规而失败,我们可以将 ignoreFailures 属性设置为 true。我们可以使用 codenarc.ignoreFailures 属性为所有 codenarc 任务设置此项。我们还可以为单个codenarc 任务设置此属性。

以下构建文件显示我们可以为所有 codenarc 任务设置 ignoreFailures 属性:

apply plugin: 'groovy' 
apply plugin: 'codenarc' 
 
repositories { 
    jcenter() 
} 
 
codenarc { 
    // Keep running the build even 
    // if there are violations. We can 
    // check the reports for violations. 
    ignoreFailures = true 
} 

codenarc 任务使用找到的结果创建一个 HTML 报告,并将其放置在 build/reports/codenarc 目录中。文件的名称由为其执行任务的源集名称定义。我们还可以选择不同的输出格式。我们可以将输出设置为 XML 或文本文件格式。我们可以使用 codenarc 任务的 reports() 方法更改报告的格式。要更改输出目录,我们可以在项目中设置 codenarc.reportsDir属性,如下:

apply plugin: 'groovy' 
apply plugin: 'codenarc' 
 
repositories { 
    jcenter() 
} 
 
codenarc { 
    configFile = file('config/codenarc/rules.groovy') 
 
    // Change output directory for reports. 
    reportsDir = file("${reporting.baseDir}/codenarc-output") 
} 
 
tasks.withType(CodeNarc) { task -> 
    reports { 
        // Enable text format. 
        text { 
            enabled = true 
        } 
 
        // Configure XML output. 
        xml { 
            enabled = true 
 
            // Change destination file. 
            destination = file("${codenarc.reportsDir}/${task.name}.xml") 
        } 
    } 
} 

Summary


在本章中,我们讨论了如何在 Gradle 项目中轻松使用代码分析工具。我们可以在 Java 项目中使用 Checkstyle、PMD、JDepend 和 FindBugs。对于 Groovy 项目,我们可以使用 CodeNarc。这些工具的所有插件都为我们的项目添加了新任务,以便为每个源集进行分析。这些任务中的每一个都是检查任务的依赖任务。因此,当我们在正常构建中应用插件时,将进行代码分析。我们还讨论了每个插件的用法和语法基本相同。

在下一章中,我们将看看如何编写我们自己的自定义任务和插件。我们还将讨论如何使其在其他 Gradle 构建中可重用。