action/setup-java 5.4和5.5 新功能:签名验证、Kona JDK与更佳Maven体验
actions/setup-java 5.5.0 新特性
如果你在 GitHub Actions 上构建 Java,actions/setup-java 几乎可以说是你工作流程中的第一步。它安装 JDK,配置 JAVA_HOME 和 PATH,设置 Maven 的 settings.xml,配置依赖缓存,并注册 Maven 工具链——这一切都在你的构建开始之前完成。
最近的两个版本 v5.4.0 和 v5.5.0 悄然成为一段时间以来最有趣的更新之一。v5.5.0 尤其带来了 Java 开发者多年来在 CI 上一直期盼的功能:对你下载的 JDK 进行加密验证。此外,还有一个全新的发行版、更智能的版本文件处理,以及一系列 Maven 质量改进,使你的日志更干净,工具链文件更合理。
v5.4.0 发布时没有专门的更新日志,因此本文一次性涵盖了两个版本的亮点。
让我们深入了解一下。
验证下载的 JDK 签名
关于大多数 CI 流水线,有一个令人不安的事实:编译和运行代码的 JDK 是通过网络下载的,长期以来唯一的完整性保障是 TLS。这通常没问题——直到出问题。JDK 成为流水线其余部分信任的 java 二进制文件,它可以访问你的密钥、签名凭据和部署凭证。工具链本身的供应链完整性至关重要。
v5.5.0 为下载的 JDK 归档添加了分离的 GPG 签名验证:
当 verify-signature: true 时,该操作会下载发行版与归档一起发布的分离 GPG 签名,并在安装之前验证 JDK。如果签名不匹配,步骤将失败——损坏的 JDK 永远不会进入运行器。
一些重要细节:
- 当前支持的发行版:
temurin和microsoft。该操作捆绑了这些发行版的受信任公钥。 - 快速失败,而非静默: 如果你对尚不支持该功能的发行版设置了
verify-signature: true,操作将失败,而不是假装验证成功。不会产生虚假的安全感。 - 自带密钥: 如果你内部镜像 JDK 或希望固定到特定的受信任密钥,可以使用
verify-signature-public-key提供你自己的密钥:
密钥以 ASCII-armored GPG 公钥的形式传递,并会覆盖所选发行版的默认捆绑密钥。
如果你关心可重现且供应链安全的构建,这就是你需要的标志。预计受支持的发行版列表会随着时间的推移而增长。
Tencent Kona JDK
actions/setup-java 现在原生支持 Tencent Kona JDK:
Tencent Kona JDK 是一个基于 OpenJDK 的生产级发行版,腾讯大规模运行,并为 LTS 版本提供构建。如果你的组织标准化了 Kona——或者你只是想针对它进行测试——你不再需要自定义的下载和解压步骤。它现在是一个一流的 distribution 值,也可以通过版本文件工作(更多内容见下文)。
这使得受支持的发行版列表扩展到了一个健康的集合:Temurin、Zulu、Adopt (Hotspot/OpenJ9)、Liberica、Microsoft、Corretto、Semeru、Oracle、Dragonwell、SapMachine、GraalVM、GraalVM Community,现在又加入了 Kona。
安装 JDK 而不使其成为默认
默认情况下,每次调用 setup-java 都会设置 JAVA_HOME 并更新 PATH,因此最后安装的 JDK“胜出”并成为作业其余部分的 java。这通常是你要的——但并非总是如此。
有时你需要一个特定的 JDK 仅用于一个步骤(例如,必须在 Java 17 上运行的工具),而不干扰构建使用的主要 Java 版本。set-default: false 登场:
使用 set-default: false,该操作:
- 不修改
JAVA_HOME和PATH,因此 Java 21 仍为默认。 - 仍然导出
JAVA_HOME_<版本>_<架构>(例如JAVA_HOME_17_X64),因此额外的 JDK 可被发现。 - 仍然在 Maven 工具链文件中注册该 JDK,因此构建可以通过工具链选择它。
这使得单个作业可以干净地处理多个 JDK,而无需“最后安装你想要的”这种排序游戏。
注意:如果你通过多行
java-version在一个步骤中安装多个 JDK,set-default: false适用于所有 JDK——没有一个成为默认,但每个都可通过其JAVA_HOME_<版本>_<架构>变量被发现。
更智能的版本文件:自动检测发行版
setup-java 可以从文件中读取你的 Java 版本,而不是在工作流中硬编码。它支持 .java-version、.tool-versions (asdf) 和 .sdkmanrc (SDKMAN)。最近的版本教会了它从这些文件中推断发行版,因此你可以停止重复自己。
从 .sdkmanrc
SDKMAN 标识符带有供应商后缀——-tem 表示 Temurin,-zulu 表示 Zulu,等等。该操作现在自动将该后缀映射到发行版:
这个 -tem 就足够了——不需要 distribution 输入。实际上,当你的 .sdkmanrc 使用可识别的后缀时,distribution 现在是可选的。
更好的 Maven 体验
这些版本中的几个更改直接针对最常见的 Java 构建工具之一。
默认更安静的日志
Maven 喜欢为每一个下载的工件打印一行。在冷缓存上,这是数百行嘈杂的输出,掩盖了你真正关心的内容。setup-java 现在默认在 MAVEN_ARGS 环境变量中设置 --no-transfer-progress (-ntp):
值得知道的细节:
- 适用于 Maven 3.9.0+ 和 Maven Wrapper (
mvnw),它们都尊重MAVEN_ARGS。旧版 Maven 会忽略它——你可以在命令行传递--no-transfer-progress。 - 任何现有的
MAVEN_ARGS值都会保留,不会被覆盖。 - 想要进度信息?设置
show-download-progress: true。
非交互式 settings.xml
生成的 settings.xml 现在禁用了 Maven 的交互模式。换句话说:Maven 永远不会在 CI 运行中阻塞,等待一个没有人会回答的提示。
阻止工具链失控增长
这是一个真正的错误修复,会让一些人非常高兴。如果你在作业中多次调用 setup-java,每次调用都会追加到 toolchains.xml——包括重复条目。在几次安装后,你会得到一个充满重复的工具链文件。
生成的 toolchains.xml 现在按工具链类型和 id 去重。而且关键的是,它保留了你现有的根属性和任何非 JDK 的工具链。因此,你可以在多个步骤中安装任意数量的 JDK,最终得到一个干净、正确的工具链文件。
不要忘记这些 v5.4.0 的补充
该版本还有三件事值得一提:
-
免费的 GraalVM Community 发行版 (
graalvm-community):直接安装 GraalVM Community Edition 构建(稳定 JDK 17+),无需许可证操作。$ config -
javac问题匹配器: 该操作在安装 JDK 后注册了一个问题匹配器,将javac错误和警告转化为你拉取请求和运行摘要中的内联注释。编译器失败直接显示在有问题的行上,而不是被埋没在日志中。(如果你更喜欢,可以禁用它——请参阅高级用法文档。) -
Maven Wrapper 缓存: 使用
cache: maven,该操作现在还缓存 Maven Wrapper,从而缩短使用./mvnw的作业的时间。
综合起来
以下是一个工作流,同时使用了其中几个功能——签名验证的 Temurin 作为默认、用于工具的辅助 JDK、由 .sdkmanrc 驱动的版本、Maven 缓存,以及开箱即用的干净日志:
关于固定版本的建议
维护者反复推荐,也是任何第三方操作的良好实践:固定版本。为了可重现且供应链安全的构建,请引用确切的发布标签 v5.5.0(现在这些标签是不可变的),或者为了最强保证,引用完整的提交 SHA:
浮动的主要标签 v5 虽然方便但会随着时间移动。固定到 SHA 意味着你审计的字节就是运行的字节。结合新的 verify-signature 支持,你现在可以信任操作本身以及它安装的 JDK。
获取详细信息请参阅高级用法指南和 v5.5.0 发布说明。一如既往,欢迎在 actions/setup-java 仓库中提供反馈和报告问题。
祝你构建愉快(且验证安全)。
本文最初发表于 foojay。