首页
Jenkins 多分支项目过滤及 when 的高级用法

需求

前段时间在研究 Jenkins 的自动化构建时,写了一篇文章:使用 Generic Webhook Trigger 触发 Jenkins 多分支流水线自动化构建

Generic Webhook Trigger 的使用过程中,有一个问题一直困扰着我,就是多分支流水线每次触发构建时所有的分支都会去构建一遍。之前也没怎么去关心,因为在Jenkinsfile里我用when做了条件匹配。这周发现分支越来越多,而且团队合并代码变频繁之后,虽然那些分支只是做了一下pull代码的操作,但是各种排队加起来的时间也会导致整个构建的时间越来越长,而且会产生各种不必要的构建日志等等。

之前的思路一直是Generic Webhook Trigger里是不是有一个配置可以做到只触发特定的分支,google 了一些文章发现无果。而且类似的触发器插件都是只能做到根据过滤条件去触发这个Job。所以后来换了个思路去思考这个问题。

首先想到的是,既然是一个多分支的流水线,那么对于这种流水线本身是不是可以去过滤一些特定的分支呢?比如我们项目里只需要构建sprintmaster分支,平时的feature分支还有其它的等等都是不需要构建的。然后就按这种想法去 google 了一下,还真的找到了答案。

Jenkins Multibranch Config: How to Filter branches based on variable string?

多分支流水线过滤

进入流水线的配置界面,在Branch Sources里找到了Behaviours选项,可以添加很多行为,这里面有两个我们需要的:

  • Filter by name(with regular expression)
  • Fliter by name(with wildcards)

使用正则表达式或通配符来过滤

image_1ee5r0l491m466aalatqap1cdp9.png-123.1kB

点击?图标会有一些说明,比如正则表达式的语法使用的是Java的。这也是我想吐槽的一点,同样一个正则表达式,在不同的地方写法各不相同,折腾死人。

image_1ee5r8jko1sbq7t14pnq43a9om.png-24.5kB

保存之后,流水线里就只保留了过滤之后的分支

image_1ee5rcdr71gc1rdjn81vei1n1v13.png-26.6kB

这一步可以把开发时的各种分支都过滤掉,只保留需要构建的分支。但是还有另一个问题,我们Jenkinsfilebuild阶段,会去做一些前端的代码打包工作,比较耗时。这个阶段配置的是mastersprint分支都会去执行。

但我们开发的时候,当代码合并到sprint分支后,我只想触发sprint分支去执行build阶段的命令。master只需要手动去触发。这就需要用到whentriggeredBy属性

when 的 triggeredBy 属性

我们现在需要完成的目标是,当使用Generic Webhook Trigger触发构建的,master分支各个stage都不执行。

官网的说明就这些。对于Generic Webhook Trigger来说,这些都没用。
image_1ee5rr1a3c1s1a5r1tgctg1fgv20.png-31.9kB

然后试了下when { triggeredBy 'GenericTrigger'}也不行,generic-webhook-trigger-plugin有人专门提了一个Issues去问这个问题,但是被关闭了,也没有解决办法。

后面就去搜怎么在Jenkins中获取构建的原因,居然还找到了很多这方面的资料。可以通过currentBuild.getRawBuild().getCauses()去获取。但是出于安全考虑,Jenkins脚本中直接使用系统的方法是被禁止的,需要手动去添加一下。参考了Jenkins CI Pipeline Scripts not permitted to use method groovy.lang.GroovyObject这个问题的回答搞定了这个问题。

最后写了一个测试的脚本,如下:

stage('TEST'){
    steps{
        script{
            env.buildCauses = currentBuild.getRawBuild().getCauses()
        }
        echo "Causes by: ${env.buildCauses}"
    }
}

打印的结果如下:

image_1ee5t31bn1fh71jq58fm55q1ja32d.png-9.6kB

本来想根据返回的这个结果去自己写匹配语句,但感觉很麻烦干脆就试一下when { triggeredBy 'GenericCause'}。天哪,居然可以了,简直不敢相信。

最终的Jenkinsfile脚本如下:

stage('Build'){
    //构建条件:如果是feature分支,任何条件下都构建;如果是master分支,取消自动化构建
    when{
        anyOf{
           expression { BRANCH_NAME ==~ /features\/sprint\d*/ }
           allOf{
                branch 'master'
                not {
                    triggeredBy 'GenericCause'
                }
            }
        }
    }
    steps{
        sh '''
        '''
    }
}

这次虽然解决了这个棘手的问题,但是并没有非常开心。其实这些问题,文档写明白一点就不用去折腾这么久了。对于开源产品来说,一个清晰的文档真的很重要。