Gradle 连续构建行为异常

Gradle continuous build behaves odd

提问人:Janning Vygen 提问时间:11/10/2023 最后编辑:Anish B.Janning Vygen 更新时间:11/22/2023 访问量:107

问:

Gradle 对我来说是一个魔盒。我经常不明白,总是尝试和错误。 我使用 gradle 8.1 和 groovy 脚本。我有这个小任务

import java.time.Instant

tasks.register('continuous-build') {
    dependsOn tasks.compileJava
    onlyIf { !compileJava.state.upToDate }
    logger.lifecycle("Job executed at " + Instant.now())
    doLast {
        def file = new File(projectDir, "build/classes/java/main/.reloadTrigger");
        file.createNewFile();
        file.setLastModified(Instant.now().toEpochMilli())
        logger.lifecycle("This message is never seen")
    }
}

我希望此任务使用 --continuous-build 运行,并在编译完成后触摸文件。

这是我所做的:

运行 ./gradlew continuous-build --continuous

$ ./gradlew continuous-build --continuous
Reload triggered at 2023-11-10T11:48:50.446501720Z   
BUILD SUCCESSFUL in 1s
6 actionable tasks: 1 executed, 5 up-to-date
Waiting for changes to input files... (ctrl-d to exit)

对Main.java进行小改动,编译良好

modified: [...]Main.java
Change detected, executing build...
Reload triggered at 2023-11-10T11:49:02.870526619Z
BUILD SUCCESSFUL in 1s
6 actionable tasks: 1 executed, 2 from cache, 3 up-to-date
Waiting for changes to input files... (ctrl-d to exit)

在此之后,文件时间戳将更改。这就是我想要的。

对Main.java进行小改动,编译时出错

modified: [...]Main.java
Change detected, executing build...   
Reload triggered at 2023-11-10T11:49:09.303034432Z    
> Task :compileJava FAILED
[...]Main.java:22: error: <identifier> expected
    publi static final String ANSWER = "42";
         ^
1 error
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileJava'.
> Compilation failed; see the compiler error output for details.   
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.    
* Get more help at https://help.gradle.org    
BUILD FAILED in 1s
3 actionable tasks: 2 executed, 1 up-to-date    
Waiting for changes to input files... (ctrl-d to exit)

在此之后,文件时间戳不会更改。这就是我想要的,因为它编译时出错了。

对Main.java进行小改动,再次编译良好

modified: [...]Main.java
Change detected, executing build...
Reload triggered at 2023-11-10T11:49:14.192599979Z
BUILD SUCCESSFUL in 1s
6 actionable tasks: 1 executed, 5 up-to-date
Waiting for changes to input files... (ctrl-d to exit)

在此之后,即使编译成功,文件时间戳也不会再更改。如果编译Java成功,我怎样才能实现文件触摸cmd。

为什么从未看到第二条日志记录消息?

PS:我稍微缩短了输出,使其更具可读性

java gradle build.gradle gradle -任务

评论


答:

1赞 Anish B. 11/18/2023 #1

有几点值得一提:

  • doLast是对任务的操作。它在任务结束时运行。

  • 您的 gradle 任务通过此行依赖于任务,这意味着如果任务失败,即 Java 类的编译失败,则不会从您的任务执行任务操作。因此,这就是不创建/更新文件的原因。continuous-buildcompileJavadependsOn tasks.compileJavacompileJavadoLastcontinuous-build

  • gradle 任务中的这一行表示,只有在任务状态发生更改时,才会执行任何任务操作。简单来说,如果您在 Java 类中更改代码,则将从您的任务执行操作,否则将从执行中跳过它。onlyIf { !compileJava.state.upToDate }continuous-buildcompileJavadoLastcontinuous-build

所以,你的行动完全取决于这两条线。doLastdependsOn tasks.compileJavaonlyIf { !compileJava.state.upToDate }

为了演示,我稍微更新了你的 gradle 任务来解释。

import java.time.Instant

tasks.register('continuous-build') {
    dependsOn tasks.compileJava
    onlyIf { !compileJava.state.upToDate }
    logger.lifecycle("Job executed at " + Instant.now())
    doLast {
        def file = new File(projectDir, "build/classes/java/main/.reloadTrigger");
        def created = file.createNewFile();
        logger.lifecycle("File created status :" + created);
        file.setLastModified(Instant.now().toEpochMilli())
        logger.lifecycle("Last modified timestamp of the file: " + file.lastModified());
        logger.lifecycle("This message is never seen")
    }
} 

首次执行:

enter image description here

enter image description here

第二次执行(Java 类没有变化):

doLast任务操作将不会按照点中的说明执行(因为此行)。onlyIf { !compileJava.state.upToDate }

enter image description here

第三次执行(在 Java 类中进行修改):

将执行任务操作,这将触发文件更新而不是创建,尽管这次将更改时间戳。doLast

enter image description here

第四次执行(在 Java 类中修改并出现错误):

由于任务检测到的某个 Java 类中的编译错误,将不会执行任务操作,并且任务依赖于 。doLastcompileJavacontinuous-buildcompileJava

enter image description here

第五次执行(没有错误,即还原更改):在这种情况下,再次重复第三次执行方案

enter image description here

评论

1赞 Janning Vygen 11/22/2023
非常好的解释。所以我把赏金给了你。但我真正想知道的是:当你修复 java 错误时,在第五次执行中会发生什么。我又试了一次,我错过的是:如果我添加一个错误并在之后将其删除,则编译Java是最新的,因为构建缓存正在启动,因为之前编译了完全相同的类。如果我修复错误并向类中添加一些其他随机内容,一切都按预期工作
0赞 Anish B. 11/22/2023
@JanningVygen 如果修复了类中的错误,则将再次重复第三次执行方案。
0赞 Anish B. 11/22/2023
@JanningVygen我也用第五次执行更新了答案。