Gradle shouldRunAfter 不可用于任务

2024-01-24

我创建这个仓库 https://github.com/hotmeatballsoup/idea-scala-hate-each-other准确地重现我所看到的。我正在使用 Gradle 构建一个项目。我想配置我的 Gradle 构建以便运行:

./gradlew build

与运行效果完全相同:

./gradlew clean build scalafmt shadowJar fizzbuzz

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

  1. clean
  2. build(编译并运行单元测试)
  3. scalafmt(运行一个工具,将我的代码格式化为样式指南)
  4. shadowJar(创建一个独立的可执行“fat”jar)
  5. fizzbuzz(在控制台打印出“Fizzbuzz!”)

根据有关排序任务的 Gradle 文档 https://docs.gradle.org/3.3/userguide/more_about_tasks.html#sec:ordering_tasks,看来我可以用shouldRunAfter指定所有任务的顺序...

如果您克隆上面的我的存储库然后运行./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

所以尽管我specify fizzbuzz最后运行...它首先运行!我的其余配置有(显然)错误。我不知道如何“挂钩”clean这样即使我跑步时./gradlew build它首先运行clean.

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


Update

我做了一些改变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

所以即使考虑到我最近的更改,顺序仍然是错误的......


正如奥利弗已经说过的,你需要将控制台输出到doFirst or doLast闭包,否则它将在定义任务时执行(期间配置阶段).

该异常是由于扩展属性和任务都添加到了范围中而引起的Project https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html对象,但如果扩展属性和任务具有相同的名称(scalafmt在这种情况下)存在,将访问扩展属性。正如错误消息告诉您的那样,您正在尝试访问shouldRunAfter类型对象上的方法PluginExtension,它不存在的地方。您需要确保访问该任务:

tasks['scalafmt'].shouldRunAfter build

Update

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

首先,两者shouldRunAfter and mustRunAfter实际上并不导致任务被执行,它们仅定义顺序if这两个任务都被执行(由命令行或任务依赖性引起)。这就是任务的原因clean, scalafmt, shadowJar乃至fizzbuzz如果您调用,则不会执行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通过命令行并仍然执行一些任务after实际上build任务,你可以在你的任务中使用一个小技巧settings.gradle file:

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

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

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

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

task fizzbuzz {
    doFirst {
        println "Fizzbuzz!"
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Gradle shouldRunAfter 不可用于任务 的相关文章

随机推荐