Jenkins 和 gradle - 使用最新版本的 CI 依赖项构建项目,用于生产的特定版本
Posted
技术标签:
【中文标题】Jenkins 和 gradle - 使用最新版本的 CI 依赖项构建项目,用于生产的特定版本【英文标题】:Jenkins and gradle - build projects with latest versions of dependencies for CI, specific versions for production 【发布时间】:2019-06-29 06:21:47 【问题描述】:我正在使用 Jenkins、Gradle 和我们的 Ivy 存储库。
我们的构建脚本指定要用于构建的依赖项的确切版本。这是生产的良好做法。
对于 CI,如果项目构建使用我们自己的库的最新版本会很有趣,这样我们不仅可以查看库更改是否“破坏了库的构建”,还可以查看它们是否破坏了使用它们的项目.这似乎是“整合”的重点!
我知道 gradle 将采用 "1.+"
而不是 "1.2.3"
所以我可以破解 CI 服务器上项目的 build.gradle 来实现这一点。但也许有一种更简洁的方法来做到这一点(构建脚本识别它处于 CI 模式并使用最新而不是特定版本,也许通过在 build.gradle
上运行 sed 脚本来更改它)。
我在 Jenkins 或 gradle 中遗漏了什么吗?是否有任何 gradle 插件可以实现这一目标,或者您用来实现这一目标的替代方法?
【问题讨论】:
【参考方案1】:类似的东西可能适用于 Jenkins:
if(System.getenv("BUILD_EXPERIMENTAL") == null)
// known to be stable versions
apply from: "dependencies.gradle"
else
// bleeding edge versions
apply from: "experimental.gradle"
这只是需要将同一个项目设置两次,一次使用环境变量BUILD_EXPERIMENTAL
,一次不使用环境变量BUILD_EXPERIMENTAL
,用于控制应用哪个dependencies
块。
如果您希望它被普遍应用,当使用 Jenkins 构建项目时,只需将 BUILD_EXPERIMENTAL
替换为 BUILD_NUMBER
(默认情况下在该环境中设置)。
【讨论】:
这个想法将允许构建脚本在生产和 CI 中通用,这就是我所追求的。如果我们按照@cantSleepNow 在experimental.gradle
文件中的建议使用latest
,那么该文件不需要任何更改即可进行微不足道的更新,并且会在Jenkins 构建中自动获取我们库的新版本,该版本可以启动为构建该库的结果。
@KevinSadler 一个也可以有一个dependencies
块,同时从两个不同的version.properties
文件加载版本号变量。我的意图只是在两个环境之间进行某种严格的分离,因此建议使用两个文件;这也可以与diff
进行比较。 latest
的缺点可能是缺乏控制,而对于静态版本号,IDE 会将过时的版本标记为黄色背景,以确保它可以随时重现 - 并且可以看到要更新的内容。适用于.gradle
而不是.properties
。
甚至可以进一步扩展它,使用两个不同的applicationidSuffix
,只是为了确保生成的包不会那么容易混淆,并且还可以更轻松地在同一设备上进行手动 A/B 测试- 或在本地运行export BUILD_EXPERIMENTAL=1
,以构建实验版本。
我接受了这个答案,因为逻辑和BUILD_NUMBER
提示构成了我自己的解决方案的基础。我自己的答案通过经过测试的示例代码解决了这个问题。谢谢!【参考方案2】:
如果你想拥有最新的,你可以简单地使用latest
,或者如果它更简单,比如[1.0,)
,它将匹配所有大于或等于 1.0 的版本(假设 1.0 是你的“最小版本”)看here 用于其他匹配模式,您也可以与statuses 结合使用。
另一种方法是仅在 jenkins 从属设备上拥有一个本地文件系统 ivy 存储库,其中包含所有最新版本的库,关键是开发人员工作站/笔记本电脑/VM 无法访问此存储库。然后您只需以某种方式在 gradle 设置中使用它(例如,仅在 jenkins 从站上定义环境变量)。这意味着您无需更改build.gradle
【讨论】:
由于我不一定希望生产构建使用latest
或其他非特定选项,因此第一个建议将强制 CI 和生产需要稍微不同的构建脚本。但是,如果这与@Martin Zeitler 的回答中的逻辑相结合 - 并在experimental.gradle
文件中使用latest
,我们可能会有一些东西。【参考方案3】:
我建议利用 Gradle dependency locking 来实现这一点。
在构建中,您将使用 dynamic versions 作为您的依赖项,锁定到一个众所周知的状态。 然后,开发人员和生产版本将解决这些锁定的版本。 在 CI 上,您可以有一个(一组)专用作业运行,updates the lock state 一次用于一个或多个模块。根据该反馈,您甚至可以提交此依赖项升级或至少为其打开拉取请求。【讨论】:
【参考方案4】:这是我自己的答案,灵感来自@Martin Zeitler 的回答。
我们有一个通用的构建脚本,可以应用于所有项目build.gradle
设置常用选项、设置和任务。我们想添加这个逻辑,但是让它成为可选的并且不破坏现有的构建脚本。
该逻辑将由属性project.ext.buildJenkinsWithLatest
(true
或false
)激活和控制。
当逻辑处于活动状态时,将使用来自项目文件 dependencies-production.gradle
或 dependencies-jenkins.gradle
的依赖项。仅当属性为 true 并且通过存在 BUILD_NUMBER
环境变量检测到 CI 环境时,才会使用 Jenkins 依赖项。
通用构建脚本包含以下内容:
如果(project.ext.has('buildJenkinsWithLatest')) println "使用条件依赖管理..." //如果这是 Jenkins 构建,BUILD_NUMBER 不为空 if(project.ext.buildJenkinsWithLatest == true && System.getenv("BUILD_NUMBER") != null) println "--- 使用替代依赖..." 申请自:“dependencies-jenkins.gradle” 别的 println "--- 使用生产依赖..." 申请自:“dependencies-production.gradle” 别的 println "条件依赖管理未激活"现在任何项目的build.gradle
已经应用此脚本将在运行时打印:
Conditional dependency management is not active
要使用该功能,我们需要为我们的项目执行以下操作:
-
为我们要动态选择版本的库创建一个包含
dependencies
子句的dependencies-jenkins.gradle
。
为这些库创建一个 dependencies-production.gradle
,其中包含 dependencies
子句,但指定了特定版本。
从项目build.gradle
中保留的任何dependencies
中删除库。
将属性project.ext.buildJenkinsWithLatest
设置为true
或false
。
应用通用构建脚本(设置属性后!)。
例如在dependencies-jenkins.gradle
使用最新的 2.x.x 版本:
关于如何以动态方式指定版本,请参阅@CantSleepNow 的回答。
并在dependencies-production.gradle
中使用特定版本:
然后在build.gradle
中设置属性并应用通用构建脚本:
现在,当在 Jenkins 上运行构建时,将使用替代依赖项。如果希望在 Jenkins 上使用生产依赖项构建它,请将 project.ext.buildJenkinsWithLatest
设置为 false
。
【讨论】:
以上是关于Jenkins 和 gradle - 使用最新版本的 CI 依赖项构建项目,用于生产的特定版本的主要内容,如果未能解决你的问题,请参考以下文章
如何用jenkins+gradle一次性构建多个java工程
Jenkins Artifactory 插件(gradle)不从 gradle.properties 读取版本
Jenkins+Gradle+Github实现Android自动化打包
Jenkins + Gradle + pgyer + Android自动发布