JCenter 关闭对 Gradle 构建的影响
2021 年 2 月 3 日,JFrog 宣布他们将关闭 Bintray 和 JCenter。这篇文章告诉您需要了解和做些什么才能避免构建管道中断。
您的构建可能会受到此关闭的多种影响
此外,您还应该注意从一个存储库迁移到另一个存储库时的安全注意事项。
更新:JFrog 决定将 JCenter 作为只读存储库无限期保留。JCenter 不再接受新的包和版本。所有 Bintray 服务已关闭。
背景
JCenter 是一个中央构件存储库,类似于Maven Central。软件项目使用 JCenter 将其软件分发给其他人。JCenter 还可以作为 Maven Central 的镜像,因此 Maven Central 上可用的任何依赖项在 JCenter 上也可用(反之则不行)。
Bintray 是一个管理层,软件项目使用它将包发布到 JCenter 并进行推广。Bintray 还允许用户创建与 JCenter 隔离的公共用户特定存储库。
这两项服务都受到关闭的影响。
对构建的影响
默认情况下,Gradle 不会将构件存储库添加到您的项目中;但是,Gradle 确实提供了一个便捷的 API 用于使用 JCenter 存储库。
Gradle 构建初始化插件 生成使用 JCenter 存储库来解析依赖项的构建模板。在许多代码示例和文档中,JCenter 被用作示例存储库。
您很可能拥有依赖于 JCenter 的构建。我们发现 GitHub 上有超过一百万个 Git 存储库使用 Gradle 使用 JCenter。
为了阻止新项目使用 JCenter,我们将从我们的示例和初始化模板中删除 JCenter。新的默认值将是 Maven Central。Gradle 本身与 JCenter 或 Maven Central 没有内在联系,因此您可以随时切换您选择的任何其他存储库。此更改将在下一个 Gradle 版本(Gradle 7.0)生效。
Gradle 7.0 还将弃用使用 jcenter()
来解析依赖项。您仍然可以使用 JCenter 作为存储库,但 Gradle 将发出弃用警告。 jcenter()
方法将在下一个主要版本中删除。
托管在 JCenter 上的包需要找到一个替代存储库来在 2021 年 3 月 31 日之后提供更新。许多包可能会迁移到 Maven Central,但有些包可能根本不会迁移,而有些包可能只发布新版本。被遗弃的项目可能会更改其坐标,因为其他维护者接管了。这意味着从 JCenter 迁移到另一个存储库将比简单地使用不同的存储库 URL 更困难。
根据当前时间线,使用 JCenter 的构建将能够在 2022 年 2 月 1 日之前无需更改即可解析依赖项。在此日期之后,如果您继续使用 JCenter,则无法保证您能够构建软件。
您该怎么办?
按照以下步骤准备您的构建以应对 JCenter 关闭
- 确定您的构建是否使用 JCenter
- 从您的构建中移除 JCenter 并将其替换为 Maven Central。Gradle 提供了 方便的 API 用于该存储库。
- 运行您的构建管道以查看一切是否仍然有效。
- 如果您的构建成功,您就完成了。
- 如果您的构建失败,您需要 排查哪些依赖项仍然需要 JCenter。
您如何知道是否正在使用 JCenter?
您可以通过几种不同的方式检查是否正在使用 JCenter。
多年来,JCenter 一直是 Android 项目的默认存储库。如果您正在构建 Android 应用程序,您可能正在使用 JCenter。
Gradle 插件门户目前隐式镜像 JCenter。如果您正在使用插件门户(通过 gradlePluginPortal()
或 URL plugins.gradle.org/m2)来解析应用程序的依赖项,您可能依赖于 JCenter。您应该避免将插件门户用作存储库,除了 Gradle 插件项目。
请注意,Bintray 还允许任何用户使用自定义 URL 运行自己的公共存储库。这也受到关闭的影响。您应该检查是否正在使用以 dl.bintray.com 开头的 URL 的存储库。由于这些存储库可以包含任何内容,您需要弄清楚您从这些存储库中使用了哪些依赖项以及它们可能迁移到哪里。
检查您的构建扫描
如果您正在使用 Gradle Enterprise 或公共 构建扫描 服务,您可以检查 用于解析依赖项的存储库
这将帮助您确定哪些依赖项最有可能受到关闭的影响。
检查您的构建文件
如果您在构建脚本中声明存储库,您可以查找 jcenter()
或 URL jcenter.bintray.com。
您正在寻找类似的东西
repositories {
jcenter()
}
或
repositories {
maven {
url = "https://jcenter.bintray.com"
}
}
或
repositories {
maven {
url = "https://dl.bintray.com/<some user name>"
}
}
检查您的插件
任何自定义插件都可以向您的项目添加一个仓库。内置的 Gradle 插件(如 java-library
)不会向您的项目添加仓库。
您正在寻找使用 jcenter()
API 以编程方式将 JCenter 添加为仓库的插件。
与您的团队核实
您可能在构建脚本或插件中找不到任何关于 JCenter 的引用,但您可能仍在使用 JCenter。如果您使用内部镜像或公司代理仓库,则需要检查该仓库是否使用 JCenter。
对付费 JFrog Cloud 客户的影响可能不同,因此请直接联系 JFrog 以了解如果您的内部镜像由 JFrog 提供,您是否可以继续使用 JCenter。
排查来自 JCenter 的依赖项
您可以使用 gradle dependencies
(或构建扫描)来确定哪些依赖项未解析或它们可能如何更改。如果 Gradle 构建无法从任何仓库解析依赖项,则构建也会在解析错误时失败。
在下面的示例中,您可以看到 Gradle 在切换到 Maven Central 后无法解析 trove4j 依赖项。
在控制台中:
在构建扫描中:
此时,如果该包仅在 JCenter 上可用,您的选择是
- 等待维护者迁移到另一个仓库(例如,Maven Central)
- 找到另一个在 Maven Central 上可用的等效包
- 完全删除您对该包的依赖项
- 将该包复制到您自己的内部仓库
如果您的构建可以从另一个仓库解析大多数依赖项,您可以继续使用 JCenter 来获取仅在那里可用的少数几个包。您可以使用 内容过滤器 来阻止仅在 JCenter 上可用的新包被引入您的构建。这将阻止 Gradle 在 JCenter 中查找所有包。
例如,许多 Android 项目依赖于 Trove4J 库,该库在撰写本文时仅在 JCenter 上可用。我们可以使用 内容过滤器来仅允许 org.jetbrains.trove4j
组中的工件 来自 JCenter。我们还将 jcenter()
放在最后,以便首先搜索 Maven Central。
repositories {
mavenCentral()
jcenter {
content {
// org.jetbrains.trove4j is only available in JCenter
includeGroup("org.jetbrains.trove4j")
}
}
}
对 Gradle 插件的影响
在幕后,Gradle 插件门户 使用 JCenter 来解析插件的依赖项。我们将在最终关闭之前将插件门户迁移出 JCenter。在插件门户迁移出 JCenter 时,构建不需要进行更改。
解决现有插件
现有插件将继续以与今天相同的方式解析。您无需对构建进行任何更改。
发布新的或更新的插件
如果您使用 com.gradle.plugin-publish
发布插件,则不受影响。只需仔细检查您的构建是否没有直接使用 JCenter。
如果您将插件发布到 Bintray,则需要使用 com.gradle.plugin-publish
插件 来发布插件的新版本。您越早这样做越好。如果您有任何问题或遇到问题,我们可以提供帮助。
我们将自动迁移所有在 2021 年 3 月 31 日之前发布到 Bintray 的插件。在此日期之后,我们将不再同步发布到 Bintray 的插件。此迁移对于解析依赖项的用户应该是透明的。
对发布到 Bintray 的包的影响
如果您使用 com.jfrog.bintray 插件将构建发布到 Bintray,则需要找到另一个存储库来托管您的包。您可以使用 内置的 maven-publish
发布。
如果您要迁移到 Maven Central,io.github.gradle-nexus.publish-plugin 插件会自动发布到 Nexus 和 Maven Central。
安全注意事项
从 JCenter 迁移到另一个存储库之前,您应该考虑一些安全事项。
正如我们近年来所见,依赖关系混淆 和 命名空间冲突 可能是供应链攻击的严重危险。这些漏洞中的每一个都依赖于使用不受信任的工件来代替受信任的工件。
当您更改用于解析依赖项的存储库列表时,您可能会无意中让自己暴露于这些类型的攻击。
例如,假设您的构建使用 JCenter 和另一个不太流行的存储库(又名 LessPopularCenter)来解析依赖项(按此顺序),并且您的构建依赖于 com.example:foo:1.0
。包 com.example:foo
仅发布到 JCenter,但其他人已设法将 com.example:foo:1.0
的副本放在 LessPopularCenter 上。只要 JCenter 是 Gradle 检查依赖项的首选位置,您的构建就会始终获得官方包。
如果您删除 JCenter 并将其替换为 Maven Central(没有 com.example:foo
的副本),您的构建可能仍然能够解析 com.example:foo
,因为 LessPopularCenter 有它的副本。不幸的是,无法保证 LessPopularCenter 上的副本与官方包相同。
如果您希望强烈保证您现在依赖的工件是相同的或来自同一个可信方,您应该启用依赖项验证。启用后,Gradle 会自动对从存储库解析的所有依赖项执行依赖项验证。这将帮助您检测依赖项工件的意外更改、受损工件或新的不可信工件来源。
依赖项验证需要一些前期设置。您需要指定一个可信密钥列表,用于验证签名工件。对于未签名的工件,您需要为每个工件指定预期的校验和。
依赖项验证失败并不一定意味着发生了恶意行为。依赖项元数据和工件很混乱。有时,同一个版本的包从两个存储库中获取不同的工件是合法的。如果该包分别发布到 JCenter 和 Maven Central,它可能被构建了两次,并生成了行为相同的不同工件。这意味着,即使您从两个存储库中解析了“相同”的版本,当您逐字节比较工件时,您将得到不同的结果。在这种情况下,您可以告诉 Gradle 接受两个校验和作为有效校验和。
反馈
如果您有任何问题,请在我们的论坛或Gradle 社区 Slack上告诉我们。