插件可以通过 Gradle 的问题报告 API 报告问题。这些 API 报告关于构建期间发生的问题的丰富、结构化信息。此信息可用于不同的用户界面,例如 Gradle 的控制台输出、Build Scans 或 IDE,以便以最合适的方式将问题传达给用户。

以下示例展示了一个由插件报告的问题

ProblemReportingPlugin.java
public class ProblemReportingPlugin implements Plugin<Project> {

    public static final ProblemGroup PROBLEM_GROUP = ProblemGroup.create("sample-group", "Sample Group");

    private final ProblemReporter problemReporter;

    interface SomeData extends AdditionalData {
        void setName(String name);
        String getName();
    }

    @Inject
    public ProblemReportingPlugin(Problems problems) { (1)
        this.problemReporter = problems.getReporter(); (2)
    }

    public void apply(Project project) {
        ProblemId problemId = ProblemId.create("adhoc-deprecation", "Plugin 'x' is deprecated", PROBLEM_GROUP);
        this.problemReporter.report(problemId, builder -> builder (3)
            .details("The plugin 'x' is deprecated since version 2.5")
            .solution("Please use plugin 'y'")
            .severity(Severity.WARNING)
            .additionalData(SomeData.class, additionalData -> {
                additionalData.setName("Some name"); (4)
            })
        );
    }
}
1 Problem 服务被注入到插件中。
2 为插件创建了一个问题报告器。虽然命名空间由插件作者决定,但建议使用插件 ID。
3 报告了一个问题。此问题是可恢复的,因此构建将继续。
4 添加了一些附加数据。

有关完整示例,请参阅我们的端到端示例

构建问题

报告问题时,可以提供各种信息。ProblemSpec 描述了可以提供的所有信息。

报告问题

关于报告问题,我们支持两种不同的模式

更多详情,请参阅 ProblemReporter 文档。

问题汇总

报告问题时,Gradle 确保报告简洁,没有不必要的冗余。特别是,一旦达到特定阈值,它会阻止重复报告同一个问题。

  • 在构建期间,问题的最初几次实例被报告为 Problem,提供了该问题的所有可用信息。

  • 在构建结束时,同一问题的后续出现会被分组并汇总为 ProblemSummary。此汇总信息通过 ProblemSummariesEvent 传递,其中提供了出现的总次数。

构建失败

指示构建失败的标准方法是抛出异常。ProblemReporter 通过允许抛出与问题报告关联的异常来增强对此的支持。

FailingTask.java
ProblemId id = ProblemId.create("sample-error", "Sample Error", StandardPlugin.PROBLEM_GROUP);
throw getProblems().getReporter().throwing((new RuntimeException("Message from runtime exception")), id, problemSpec -> {
    problemSpec.contextualLabel("This happened because ProblemReporter.throwing() was called")
        .details("This is a demonstration of how to add\ndetailed information to a build failure")
        .documentedAt("https://example.com/docs")
        .solution("Remove the Problems.throwing() method call from the task action");
});

这确保了构建失败与底层问题明确关联,并且这些问题能正确地传达给各种客户端。当使用 Problems API 报告构建失败时,所有客户端(Tooling API、CLI、Build Scans 等)都将能够访问此关联信息。

命令行界面

CLI 构建失败输出将包含关于问题的详细信息。错误消息和描述直接来源于问题报告。如果问题报告包含解决方案或建议的操作,这些信息将取代通用的解决方法进行显示。

AdditionalData 不包含在 CLI 输出中。

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':sample-project:myFailingTask'.
> Message from runtime exception
    This happened because ProblemReporter.throwing() was called
      This is a demonstration of how to add
      detailed information to a build failure

* Try:
> Remove the Problems.throwing() method call from the task action
> Run with --scan to get full insights.

BUILD FAILED in 0ms

Tooling API 客户端

Tooling API 客户端可以通过根构建操作上的 Failure 对象访问与构建失败相关的详细问题报告。要接收这些报告,客户端必须为 OperationType.ROOT 操作类型注册进度监听器。进度监听器回调应随后检查操作结果是否为 FailureResult 类型,然后可以通过 Failure.getProblems() 访问相关问题。

此外,还有一种更便捷的方式来访问失败详情。如果客户端通过 LongRunningOperation.withFailureDetails() 配置项目连接,Tooling API 会隐式订阅 ROOT 操作类型,并通过 GradleConnectionException.getFailures() 方法提供失败详情。

生成的 HTML 报告

Problems API 生成的问题输出也会在构建结束时提供一个丰富的 HTML 报告。此报告是用户回顾构建期间发生的问题的中心位置。

插件作者可以使用 Problems API 记录特定于其插件的事件,这些事件会添加到 Gradle 生成的事件中。

AdditionalData 不包含在 HTML 报告中。

如果没有报告任何问题,则不会生成报告。此外,如果您不想生成此报告,可以使用 --no-problems-report 标志禁用它。控制台输出提供了此报告的链接,如下所示

[Incubating] Problem report is available at: <project-dir>/build/reports/problems/problems-report.html

BUILD SUCCESSFUL in 1s

渲染后的报告链接将您导向问题的详细 HTML 视图

problems report html