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.buildJenkinsWithLatesttruefalse)激活和控制。

当逻辑处于活动状态时,将使用来自项目文件 dependencies-production.gradledependencies-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 设置为truefalse。 应用通用构建脚本(设置属性后!)。

例如在dependencies-jenkins.gradle 使用最新的 2.x.x 版本:

依赖 编译'示例:我的库:2+'

关于如何以动态方式指定版本,请参阅@CantSleepNow 的回答。

并在dependencies-production.gradle 中使用特定版本:

依赖 编译'示例:我的库:2.3.4'

然后在build.gradle 中设置属性并应用通用构建脚本:

... project.ext.buildJenkinsWithLatest = true; 申请自:'../bxgradle/bx-std.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自动发布

jenkins + gradle ,卡在 app:processReleaseAGCPlugin

jenkins node 版本无法使用最新的版本