绝大多数软件项目构建的内容旨在以某种方式被消费。它可以是其他软件项目使用的库,也可以是面向最终用户的应用程序。发布是将构建内容提供给消费者的过程。

在 Gradle 中,这个过程如下所示

  1. 定义要发布的内容

  2. 定义要发布到的位置

  3. 执行发布

这些步骤中的每一个都取决于您想要将 artifacts 发布到的仓库类型。两种最常见的类型是 Maven 兼容仓库和 Ivy 兼容仓库,简称 Maven 仓库和 Ivy 仓库。

从 Gradle 6.0 开始,Gradle 模块元数据将始终与 Ivy XML 或 Maven POM 元数据文件一起发布。

Gradle 通过提供一些预打包的基础设施(即Maven 发布插件Ivy 发布插件)使得发布到这些类型的仓库变得容易。这些插件让您能够以最小的精力配置要发布的内容并执行发布。

publishing process
图 1. 发布过程

让我们更详细地了解这些步骤

要发布的内容

Gradle 需要知道要发布哪些文件和信息,以便消费者可以使用您的项目。这通常是 artifacts 和元数据的组合,Gradle 称之为出版物(publication)。出版物具体包含什么取决于它发布的仓库类型。

例如,要发布到 Maven 仓库的出版物包括

  • 一个或多个 artifacts — 通常由项目构建,

  • Gradle 模块元数据文件,它将描述已发布组件的变体,

  • Maven POM 文件将标识主要 artifact 及其依赖项。主要 artifact 通常是项目的生产 JAR,次要 artifacts 可能包括 "-sources" 和 "-javadoc" JAR。

此外,如果配置了,Gradle 将发布上述所有内容的 checksums,以及签名。从 Gradle 6.0 开始,这包括 SHA256SHA512 checksums。

发布到哪里

Gradle 需要知道将 artifacts 发布到哪里,以便消费者可以获取它们。这通过仓库(repositories)完成,仓库存储并提供各种 artifacts。Gradle 还需要与仓库交互,这就是为什么您必须提供仓库的类型和位置。

如何发布

Gradle 会为出版物和仓库的所有可能组合自动生成发布任务,允许您将任何 artifact 发布到任何仓库。如果您发布到 Maven 仓库,任务类型是 PublishToMavenRepository,而对于 Ivy 仓库,任务类型是 PublishToIvyRepository

以下是一个演示整个发布过程的实际示例。

设置基本发布

发布的第一步,无论您的项目类型如何,都是应用适当的发布插件。正如引言中提到的,Gradle 通过以下插件支持 Maven 和 Ivy 仓库

这些插件提供了配置相应仓库类型发布所需的特定出版物和仓库类。由于 Maven 仓库是最常用的,它们将作为本示例以及本章中其他示例的基础。不用担心,我们将解释如何为 Ivy 仓库调整单个示例。

假设我们正在处理一个简单的 Java 库项目,因此只应用了以下插件

build.gradle.kts
plugins {
    `java-library`
    `maven-publish`
}
build.gradle
plugins {
    id 'java-library'
    id 'maven-publish'
}

一旦应用了适当的插件,您就可以配置出版物和仓库。对于本示例,我们希望将项目的生产 JAR 文件— 由 jar 任务生成的文件— 发布到自定义 Maven 仓库。我们通过以下 publishing {} 块来完成此操作,该块由 PublishingExtension 支持。

build.gradle.kts
group = "org.example"
version = "1.0"

publishing {
    publications {
        create<MavenPublication>("myLibrary") {
            from(components["java"])
        }
    }

    repositories {
        maven {
            name = "myRepo"
            url = uri(layout.buildDirectory.dir("repo"))
        }
    }
}
build.gradle
group = 'org.example'
version = '1.0'

publishing {
    publications {
        myLibrary(MavenPublication) {
            from components.java
        }
    }

    repositories {
        maven {
            name = 'myRepo'
            url = layout.buildDirectory.dir("repo")
        }
    }
}

这定义了一个名为 "myLibrary" 的出版物,由于其类型 MavenPublication,可以发布到 Maven 仓库。此出版物仅包含生产 JAR artifact 及其元数据,这两者组合起来由项目的 java 组件表示。

组件是定义出版物的标准方式。它们由插件提供,通常是语言或平台类型的插件。例如,Java 插件定义了 components.java SoftwareComponent,而 War 插件定义了 components.web

该示例还定义了一个名为 "myRepo" 的基于文件的 Maven 仓库。这样的基于文件的仓库对于示例很方便,但实际项目通常使用基于 HTTPS 的仓库服务器,例如 Maven Central 或公司内部服务器。

您可以定义一个且只有一个没有名称的仓库。对于 Maven 仓库,这会被解释为隐式名称 "Maven",对于 Ivy 仓库,则为 "Ivy"。所有其他仓库定义都必须给定一个显式名称。

结合项目的 groupversion,出版物和仓库定义提供了 Gradle 发布项目生产 JAR 所需的一切。然后,Gradle 将创建一个专门的 publishMyLibraryPublicationToMyRepoRepository 任务来执行此操作。其名称基于模板 publishPubNamePublicationToRepoNameRepository。有关此任务的性质以及可能可用的任何其他任务的更多详细信息,请参阅相应的发布插件文档。

您可以直接执行单个发布任务,也可以执行 publish,它将运行所有可用的发布任务。在此示例中,publish 将只运行 publishMyLibraryPublicationToMavenRepository

发布到 Ivy 仓库的基本过程非常相似:您只需使用 Ivy Publish Plugin,将 MavenPublication 替换为 IvyPublication,并在仓库定义中使用 ivy 代替 maven

这两种仓库类型之间存在差异,特别是在各自支持的额外元数据方面— 例如,Maven 仓库需要 POM 文件,而 Ivy 仓库有自己的元数据格式— 因此请查阅插件章节以获取有关如何为您使用的任何仓库类型配置出版物和仓库的全面信息。

基本用例到此为止。然而,许多项目需要更多地控制发布的内容,因此我们将在以下部分中探讨几种常见场景。

抑制验证错误

Gradle 会对生成的模块元数据执行验证。在某些情况下,验证可能会失败,这表明您很可能需要修复错误,但也可能您是有意为之。如果是这种情况,Gradle 会指示您可以在 GenerateModuleMetadata 任务上禁用的验证错误的名称

build.gradle.kts
tasks.withType<GenerateModuleMetadata> {
    // The value 'enforced-platform' is provided in the validation
    // error message you got
    suppressedValidationErrors.add("enforced-platform")
}
build.gradle
tasks.withType(GenerateModuleMetadata).configureEach {
    // The value 'enforced-platform' is provided in the validation
    // error message you got
    suppressedValidationErrors.add('enforced-platform')
}