gradle任务执行结果需通过aftertask监听获取state.outcome枚举值判断,而非日志解析;5种outcome包括no_source、up_to_date、from_cache、executed、failed,各自对应明确执行路径。

Gradle插件中验证任务执行结果,核心不是“手动检查日志”,而是通过 TaskOutcome 类型和构建状态的可观测机制来判断——真正执行了、跳过了、复用了缓存,还是根本没跑,Gradle 都会明确标记。
怎么拿到 Task 的执行结果(Outcome)
在插件或自定义逻辑中,不能靠解析控制台输出,而应监听 TaskExecutionListener 或使用 Task.getOutputs().getPreviousOutputFiles() 等 API 获取状态快照。最常用且可靠的方式是注册监听:
-
project.gradle.taskGraph.afterTask { task, state -> }是唯一能稳定捕获最终 Outcome 的钩子,state是TaskState实例,其getOutcome()返回枚举值 - 注意:这个回调只对已调度并完成的 Task 触发;如果 Task 被跳过(比如
onlyIf返回false),state.outcome是SKIPPED,但不会进入doLast - 不要在
doFirst/doLast里查outcome—— 此时它还没被赋值,永远是null
常见的 Outcome 值及对应含义
TaskOutcome 枚举有 5 种取值,每种都对应明确的执行路径,不是凭感觉猜:
-
NO_SOURCE:Task 声明了 inputs 但没找到任何输入文件(例如空 test 目录),不执行 action -
UP_TO_DATE:inputs/outputs 没变,且 outputs 存在且完整,直接跳过执行(非缓存,是本地 up-to-date 判定) -
FROM_CACHE:build cache 命中,从远程或本地缓存加载 outputs,不运行 action -
EXECUTED:真正执行了所有doLast和doFirst动作 -
FAILED:action 中抛出未捕获异常(注意:StopExecutionException不算失败,它触发的是SKIPPED)
为什么直接看 gradle tasks --all 或日志不可靠
命令行输出里的 UP-TO-DATE 或 FROM-CACHE 是终端渲染结果,不是 Task 运行时的真实 outcome:
-
gradle tasks --all只显示注册状态,不反映执行结果 - 控制台里看到
:myTask UP-TO-DATE,可能是UP_TO_DATE,也可能是NO_SOURCE—— 它们终端都显示为UP-TO-DATE,但语义完全不同 - build scan 或
--console=verbose会多打一行 “Task ':myTask' is not up-to-date because...”,但依然不是编程可读的 outcome - 唯一可信来源是
afterTask回调中的state.outcome枚举值
插件中做结果校验的典型场景
比如你写了个发布插件,需要确保 publishToMavenLocal 真正执行了才继续下一步:
- 不能写
tasks.named("publishToMavenLocal").configure { finalizedBy("verifyPublished") }——finalizedBy无论 outcome 都会触发 - 正确做法是用
afterTask拦截,判断task.name == "publishToMavenLocal" && state.outcome == TaskOutcome.EXECUTED后再触发验证逻辑 - 如果依赖缓存行为,要区分
FROM_CACHE和EXECUTED:前者可能跳过签名步骤,后者才真正生成 artifacts - 注意
enabled = false或onlyIf { false }导致的SKIPPED不会进afterTask,得提前在配置阶段检查
Outcome 是 Gradle 执行模型的底层契约,不是日志副产品。依赖字符串匹配或终端输出做判断,会在 CI 环境、build cache 开启、parallel 构建等场景下失效。真正可靠的验证,必须落在 afterTask + state.outcome 这个组合上。











