Gradle shouldRunAfter不可用于任务

时间:2017-07-22 10:36:57

标签: gradle

我创建了this repo来准确再现我所看到的内容。我有一个项目,我正在使用Gradle构建。我想配置我的Gradle构建,以便运行:

./gradlew build

与跑步完全相同:

./gradlew clean build scalafmt shadowJar fizzbuzz

含义Gradle按以下顺序调用任务:

  1. clean
  2. build(编译和运行单元测试)
  3. scalafmt(运行将我的代码格式化为样式指南的工具)
  4. shadowJar(创建一个自包含的可执行文件“fat”jar)
  5. fizzbuzz(打印出“Fizzbuzz!”到控制台)
  6. 根据Gradle docs on ordering tasks,似乎我可以使用shouldRunAfter指定所有任务的排序......

    如果你克隆我上面的repo,然后运行./gradlew build,你将获得以下输出:

    ./gradlew build
    Fizzbuzz!
    
    FAILURE: Build failed with an exception.
    
    * Where:
    Build file '/Users/myUser/thelab/idea-scala-hate-each-other/build.gradle' line: 65
    
    * What went wrong:
    A problem occurred evaluating root project 'idea-scala-hate-each-other'.
    > Could not find method shouldRunAfter() for arguments [task ':build'] on cz.alenkacz.gradle.scalafmt.PluginExtension_Decorated@6b24ddd7.
    
    * 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: 10.983 secs
    

    即使我指定 fizzbuzz来运行最后......它首先运行!我的配置的其余部分(显然)存在错误。而且我不确定如何“挂钩”clean,以便即使我运行./gradlew build它也会首先运行clean

    我可以使用一个解决方案,要求我编写自己的“包装器任务”以实现我想要的顺序,然后通过./gradlew buildMyApp等调用它。只是不确定如何实现我想要的。

    更新

    我对build.gradle进行了一些更改,现在看到了:

    ./gradlew fullBuild
    :compileJava UP-TO-DATE
    :compileScala
    :processResources UP-TO-DATE
    :classes
    :jar
    :startScripts
    :distTar
    :distZip
    :assemble
    :compileTestJava UP-TO-DATE
    :compileTestScala UP-TO-DATE
    :processTestResources UP-TO-DATE
    :testClasses UP-TO-DATE
    :test UP-TO-DATE
    :check UP-TO-DATE
    :build
    :clean
    :fizzbuzz
    Fizzbuzz!
    :scalafmt
    :shadowJar
    :fullBuild
    

    所以当我运行./gradlew fullBuild时,任务执行似乎是:

    1. build(通过compileJava调用check
    2. clean
    3. fizzbuzz
    4. scalafmt
    5. shadowJar
    6. 所以即使考虑到我最近的变化,排序仍然是错误的......

2 个答案:

答案 0 :(得分:2)

正如Oliver已经说过的那样,您需要将控制台输出置于doFirstdoLast闭包,否则将在定义任务时执行(在配置阶段)。

异常是由于扩展属性和任务都添加到Project对象的范围,但是如果扩展属性和具有相同名称的任务(scalafmt in这种情况)存在,将访问扩展属性。正如错误消息所示,您正在尝试访问shouldRunAfter类型的对象上的PluginExtension方法,该对象不存在。您需要确保访问该任务:

tasks['scalafmt'].shouldRunAfter build

更新

实际上,我认为您只需要解决两个具体问题,但已经有了基本Gradle结构的解决方案。

首先,shouldRunAftermustRunAfter实际上并不会导致执行任务,它们只定义如果两个任务的执行顺序(由命令引起)行或任务依赖)。这就是为什么如果您致电clean,任务scalafmtshadowJarfizzbuzz甚至gradle build都不会执行的原因。因此,要解决您的第一个问题,您可以让明确调用的build任务依赖于它们:

build.dependsOn 'clean', 'scalafmt', 'shadowJar', 'fizzbuzz'

但是任务依赖项将始终在父任务之前运行,因此所有任务都将在build任务之前执行。这应该不是问题,因为build任务只是为所有必需的构建步骤收集任务依赖性。您还需要定义不仅在您的任务依赖关系之间的顺序,例如, clean和父任务build,但主要在现有任务依赖关系之间,例如compileJava。否则clean可以在compileJava之后运行,这将删除已编译的文件。

另一个选择是定义一个新任务,然后该任务依赖于您要执行的所有任务:

task fullBuild {
    dependsOn 'clean', 'build', 'scalafmt', 'shadowJar', 'fizzbuzz'
}

这仍然需要定义任务与现有任务依赖关系之间的顺序,例如

compileJava.mustRunAfter 'clean'
[...]

请注意,现在您必须从命令行调用gradle fullBuild。如果您确实只需要通过命令行调用gradle build并仍然执行实际build任务后的某些任务,那么您可以在settings.gradle中使用一个小技巧文件:

startParameter.with {
    if (taskNames == ['build']) {
        taskNames = ['clean', 'build', 'scalafmt', 'shadowJar', 'fizzbuzz']
    }
}

这段代码检查您通过命令行输入的任务名称输入并替换它,如果它只包含build任务。这样您就不必为任务顺序而烦恼,因为命令行任务是连续执行的。

但是,这不是一个干净的解决方案。一个好的解决方案包括为真正相互依赖的所有任务定义任务依赖关系,以及通过命令行调用多个任务(您希望避免)。特别是cleanbuild任务之间的硬连接绕过了Gradle平台的许多有用功能,例如:增量构建。

关于更新中的第二点,fizzbuzz任务首先运行是错误的。它根本没有运行。配置任务时将打印命令行输出。请将println来电转移到doFirst / doLast关闭:

task fizzbuzz {
    doFirst {
        println "Fizzbuzz!"
    }
}

答案 1 :(得分:0)

该错误的可能原因之一可能是因为 Gradle 无法编译方法 taskshouldRunAftermustRunAfter

当存在与方法 taskshouldRunAftermustRunAfter 同名的其他类型实体(不是任务)时,也可能发生这种情况。在这种情况下,您可以使用语法 tasks['task1_name'].shouldRunAfter tasks['task2_name']tasks['task1_name'].mustRunAfter tasks['task2_name'] 来确保 Gradle 引用 task 类型的实体。