JenkinsCI:多分支构建
jenkins允许用户开发插件,扩展功能,因此你可以在社区找到丰富的插件,但是插件质量参差不齐,想让多个插件协作,需要非常复杂的配置。
现代的CI/CD
如gitlab CI、travis CI
均摒弃了这样的插件思路
比如,一个普遍遇到的问题就是,如何支持构建不同的分支?这几乎大部分CI
支持、用户以为理所当然的功能,在jenkins里是件比较麻烦的事情
前提
除非是非常简单的项目,大多数项目会使用jenkins pipeline
来计划构建、部署任务
有两个方式定义Pipeline
复杂一点的Pipeline会采用第二种方式,因为可以帮助我们追踪Pipeline的变更。 但是这会引发我们今天要讨论的问题:
问题:Pipeline过早初始化
采用Pipeline from SCM
的项目,随便打开任意构建 console output,会看到类似这样的日志:

我们可以看到,Pipeline是在拉取代码之前就被确定、初始化的。
而Pipeline是存放在SCN
(代码仓库)里, 因此我们需要在配置里面指定拉取的分支:

如果我们想要构建不同的分支,不同分支上的Pipeline有些不一样,怎么办?
解决方法 1:环境变量
我们可以用参数化构建中的环境变量
代替手写的分支名:

BRANCH
是参数化构建中的一个参数
CI/CD ?
问题似乎解决了,但是我们不可能每次构建都要打开jenkins手动点击触发,这样就不叫CI/CD
了。我们要支持trigger
,比如gitlab hook
,由git push
触发构建任务
你需要安装gitlab-plugin
这样,分支可能来自trigger
注入的环境变量,可能来自参数化构建的参数。
很容易想到,我们可以使用同样的名字来隐藏两者的区别,比如gitlab hook
注入的变量gitlabBranch
,那我们也以同样的名字作为参数化构建中的一个参数名

因此,不管gitlabBranch
是来自哪里,我们的Pipeline文件都是最新的。
如果需要更复杂的逻辑,而不是简单的合并,也许你需要EnvInject插件
解决方案 2:动态加载 Pipeline
问题的本质在于Pipeline是在拉取代码之前被确定的,那么,我们可不可以反过来,在拉取代码之后再去「初始化Pipeline」,像其他CI
那样?
利用loadAPI,我们可以做到这一点。
load
可以动态加载一个Groovy
文件(假设名为Main.groovy
),我们可以把主要的任务逻辑放在Main.groovy
.
而我们的Pipeline文件只是一个启动入口,本身不定义任务,只做一件事情——git checkout
,之后就加载Main.groovy
。 如下:
deploy/
├── Jenkinsfile
└── Main.groovy
// Jenkinsfile// 1. checkoutdefrepo=checkout([$class:GitSCM,branches:[[name:"${gitlabBranch}"]],doGenerateSubmoduleConfigurations:false,extensions:[],gitTool:Default,submoduleCfg:[],userRemoteConfigs:scm.userRemoteConfigs])// 2. load main pipelineload"deploy/Main.groovy"
由于Main.groovy
永远是当前分支的,所以整个Pipeline
也是当前分支的,除非Jenkinsfile
发生变更
为什么不使用Multibranch Pipeline
Multibranch Pipeline为项目的每一个分支单独创建一个对应的job
,看起来不错,但是这种方式不支持tag push
、merge request
等。 在实际工作中,也很少看到项目使用这样的方式。
总结
大家可以看到仅仅是多分支,jenkins就需要你花时间去 google,阅读各种不同风格的 plugin 文档,学习 groovy API,不断尝试。
虽然这篇是关于Jenkins Pipeline,但是我不推荐使用jenkins,除非像我一样万不得已(团队内部原因)
如果公司代码托管使用的是gitlab
,明显可以选择gitlab ci。