如何在jenkinsfile中为jenkins管道使用shell正则表达式?

时间:2018-05-16 14:33:13

标签: jenkins sh jenkins-pipeline

我正在尝试更换' /'来自Git分支名称' _'在我的jenkinsfile中,以便我可以用分支名称标记我的docker镜像。在bash中,下面的命令工作正常

echo "${git_branch_name//\//_}"

但是当在jenkinsfile中使用上面的命令时会抛出错误。

    #!/usr/bin/env groovy

    def commit_id
    def imagetag
    def branch_name
    def git_branch_name
    node('Nodename') {

        stage('checkout') {
            checkout (scm).$Branch_Param
            sh "git rev-parse --short HEAD > .git/commit-id"
            commit_id = readFile('.git/commit-id').trim()
            sh "git rev-parse --abbrev-ref HEAD > .git/branch-name"
            git_branch_name = readFile('.git/branch-name').trim()
            branch_name= sh "echo ${git_branch_name//\//_}"
            sh "echo ${commit_id}"
            sh "echo ${branch_name}"
            sh "echo Current branch is ${branch_name}"
        }

    }

WorkflowScript: 15: end of line reached within a simple string 'x' or "x" or /x/;
   solution: for multi-line literals, use triple quotes '''x''' or """x""" or /x/ or $/x/$ @ line 15, column 28.
        sh "branch_name = echo ${git_branch_name//\//_}"

我在这里做错了什么?我应该使用Groovy正则表达式而不是shell吗?为什么shell没有被正确解释?

谢谢

1 个答案:

答案 0 :(得分:1)

问题是您要让Groovy本身解释表达式${git_branch_name//\//_},而不是shell。导致该问题的原因是,您在传递给sh步骤的字符串周围使用双引号。因此,如果您改写以下内容,则第一个错误将消失:

    sh 'echo ${git_branch_name//\\//_}' // <- Note the single-quotes

基本上,除非您特别需要使用 groovy的字符串插值,否则请始终使用单引号(请参阅此答案底部的最后一个echo)。

有趣的是,似乎我在测试时不需要shebang(#!/bin/bash)来指定bash,正如一些评论所建议的那样;此${variable//x/y}替换语法按原样在sh步骤中起作用。我猜它生成的外壳是bash。我不知道是否总是这样,还是我们的Jenkins盒子是专门设置的。

还请注意,您需要转义转义序列('\\/'),因为传递给sh步骤的是groovy代码中的字符串文字。如果不添加额外的反斜杠,则传递给外壳的行将由echo ${git_branch_name////_}解释,这是行不通的。

但是还有其他问题。首先,像您所做的那样将sh步骤的输出分配给branch_name意味着branch_name将始终等于null。要从一行shell代码中获取标准输出,您需要将额外的参数returnStdout: true传递给sh:

branch_name = sh (
    script: 'echo ${git_branch_name//\\//_}',
    returnStdout: true
).trim ()     // You basically always need to use trim, because the
              // stdout will have a newline at the end

要获得奖励积分,我们可以将该sh调用包装在closure中。我发现自己经常使用它来使它成为一个好主意。

// Get it? `sh` out, "shout!"
def shout = { cmd -> sh (script: cmd, returnStdout: true).trim () }

//...

branch_name = shout 'echo ${git_branch_name//\\//_}'

但是,最后,主要的问题是bash(或实际生成的任何shell)都无法访问常规变量。据了解,echo ${git_branch_name}输出一个空字符串,因此echo ${git_branch_name//\//_}也输出一个空字符串。

您有两种选择。您可以跳过.git/branch-name的创建,而只是立即输出git rev-parse的字符串替换结果:

branch_name = shout 'name=$(git rev-parse --abbrev-ref HEAD) && echo ${name//\\//_}'

或者为了进一步简化,您可以使用groovy的字符串替换函数而不是bash语法:

branch_name = shout ('git rev-parse --abbrev-ref HEAD').replace ('/', '_')

就个人而言,我发现后者更具可读性。 YMMV。因此,最后将它们整合在一起:

#!groovy

def shout = { cmd -> sh (script: cmd, returnStdout: true).trim () }

// Note that I'm not declaring any variables up here. They're not needed.
// But you can if you want, just to clearly declare the environment for
// future maintainers.

node ('Nodename') {
    stage ('checkout') {
        checkout (scm).$Branch_Param
        commit_id = shout 'git rev-parse --short HEAD'
        branch_name = shout ('git rev-parse --abbrev-ref HEAD').replace ('/', '_')

        echo commit_id
        echo branch_name
        echo "The most recent commit on branch ${branch_name} was ${commit_id}"
    }
}