绝大多数软件项目构建的东西旨在以某种方式被使用。它可能是一个供其他软件项目使用的库,也可能是一个供最终用户使用的应用程序。发布是将正在构建的东西提供给使用者的过程。

在 Gradle 中,该过程如下所示

  1. 定义什么要发布

  2. 定义在哪里发布它

  3. 执行发布

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

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

Gradle 通过提供一些预打包的基础设施,以 Maven 发布插件Ivy 发布插件 的形式,可以轻松地发布到这些类型的仓库。这些插件允许你配置要发布的内容,并以最小的努力执行发布。

publishing process
图 1. 发布过程

让我们更详细地看一下这些步骤

发布什么

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

例如,目标为 Maven 仓库的发布物包括

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

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

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

此外,Gradle 将为以上所有内容发布校验和,并在配置为这样做时发布签名。从 Gradle 6.0 开始,这包括 SHA256SHA512 校验和。

发布到哪里

Gradle 需要知道将工件发布到哪里,以便使用者可以获取它们。这是通过仓库完成的,仓库存储并使其可用各种工件。Gradle 还需要与仓库交互,这就是为什么你必须提供仓库的类型及其位置。

如何发布

Gradle 为发布物和仓库的所有可能组合自动生成发布任务,允许你将任何工件发布到任何仓库。如果你要发布到 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 工件及其元数据,它们组合起来由项目的 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 发布插件,将 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')
}