Jenkins管道sh似乎不尊重shell命令中的管道

时间:2017-03-02 23:56:19

标签: jenkins pipe jenkins-pipeline subshell

我在版本2.32.2的管道中使用Jenkins文件。

由于各种原因,我想从pom中提取版本字符串。我希望我不必添加maven帮助插件并使用evaluate。

我很快想出了一个小的sed表达式,将它从使用管道的pom中取出,并在执行程序的jenkins工作区中的命令行上运行。

$ sed -n '/<version>/,/<version/p' pom.xml | head -1 | sed 's/[[:blank:]]*<\/*version>//g' 1.0.0-SNAPSHOT

它可能是优化的,但我想理解为什么管道似乎在管道sh命令失败。我玩过各种字符串格式,目前正在使用一个美元的字符串。

管道步骤如下所示,以便轻松输出命令字符串:

script {
    def ver_script = $/sed -n '/<version>/,/<version/p' pom.xml | head -1 | sed 's/[[:blank:]]*<\/*version>//g'/$
    echo "${ver_script}"
    POM_VERSION = sh(script: "${ver_script}", returnStdout: true)
    echo "${POM_VERSION}"
}

当在jenkins管道中运行时,我得到以下控制台输出,它似乎将管道命令分成单独的命令:

[Pipeline] script
[Pipeline] {
[Pipeline] echo
sed -n '/<version>/,/<version/p' pom.xml | head -1 | sed 's/[[:blank:]]*<\/*version>//g'
[Pipeline] sh
[FRA-198-versioned-artifacts-44SD6DBQOGOI54UEF7NYE4ECARE7RMF7VQYXDPBVFOHS5CMSTFLA] Running shell script
+ sed -n /<version>/,/<version/p pom.xml
+ head -1
+ sed s/[[:blank:]]*<\/*version>//g
sed: couldn't write 89 items to stdout: Broken pipe
[Pipeline] }
[Pipeline] // script

有关如何在jenkins文件中正确使用管道命令的指导吗?

6 个答案:

答案 0 :(得分:5)

我终于考虑了一下,并意识到管子壳可能会导致问题。我知道一些eval的邪恶,但我最终还是把它包裹在一个eval中:

script {
    def ver_script = $/eval "sed -n '/<version>/,/<version/p' pom.xml | head -1 | sed 's/[[:blank:]]*<\/*version>//g'"/$
    echo "${ver_script}"
    POM_VERSION = sh(script: "${ver_script}", returnStdout: true)
    echo "${POM_VERSION}"
}   

答案 1 :(得分:4)

如果您的环境允许,我发现这个问题的一个简单解决方案是将包含管道的脚本放入文件中,然后用sh运行,如下所示:

<强> script.sh

#!/bin/sh
kubectl exec --container bla -i $(kubectl get pods | awk '/foo-/{ print $1 }') -- php /code/dostuff

<强> Jenkinsfile

stage('Run script with pipes') {
  steps {
    sh "./script.sh"
  }
}

答案 2 :(得分:1)

我知道这种较晚的答案,但是无论您需要什么而无需评估的人,都可以使用/bin/bash -c "script"来使管道工作

script {
    POM_VERSION = sh(script: "/bin/bash -c 'sed -n \'/<version>/,/<version/p\' pom.xml | head -1 | sed \'s/[[:blank:]]*<\/*version>//g\'\''", returnStdout: true)
    echo "${POM_VERSION}"
}

此方法唯一的问题是hellish escape,但这样,管道的子壳将由我们的孩子/bin/bash -c

处理

答案 3 :(得分:0)

我也在jenkins管道中使用管道,但作为旁注,如果你想要一个简单的方法来提取maven pom的版本,这里是一个非常干净的我在另一篇文章中发现的那个我我正在使用:

stage('Preparation') {
 version = getVersion()
 print "version : " + version
}
def getVersion() {
  def matcher = readFile('pom.xml') =~ '<version>(.+)</version>'
  matcher ? matcher[0][1] : null
}

给你:

[Pipeline] echo
releaseVersion : 0.1.24
[Pipeline] sh

答案 4 :(得分:0)

pipeline-utility-steps插件现在包含readMavenPom步骤,允许按如下方式访问该版本:

version = readMavenPom.getVersion()

答案 5 :(得分:0)

因此,在Groovy中使用脚本化的Jenkinsfile语法对我来说没有任何上述细节。但是,我能够使它工作。您使用的报价类型很重要。在下面的示例中,我试图从GitHub获取最新的git标签。

...

stage("Get latest git tag") {
  if (env.CHANGE_BRANCH == 'master') {
    sh 'git fetch --tags'
    TAGGED_COMMIT = sh(script: 'git rev-list --branches=master --tags --max-count=1', returnStdout: true).trim()
    LATEST_TAG = sh(script: 'git describe --abbrev=0 --tags ${TAGGED_COMMIT}', returnStdout: true).trim()
    VERSION_NUMBER = sh(script: "echo ${LATEST_TAG} | cut -d 'v' -f 2", returnStdout: true).trim()
    echo "VERSION_NUMBER: ${VERSION_NUMBER}"
    sh 'echo "VERSION_NUMBER: ${VERSION_NUMBER}"'
  }
}
...

请注意,分配LATEST_TAG的shell执行如何按预期方式工作(将变量分配给v2.1.0)。如果我们尝试用相同的东西(用单引号引起来)来分配VERSION_NUMBER,它将无法正常工作-管道将所有内容弄乱了。相反,我们将脚本用双引号引起来。

第一个回显打印VERSION_NUMBER: 2.1.0,但是第二个回显打印VERSION_NUMBER:。如果希望VERSION_NUMBER在shell命令中可用,则必须将shell命令的输出分配给env.VERSION_NUMBER,如下所示:

...

stage("Get latest git tag") {
  if (env.CHANGE_BRANCH == 'master') {
    sh 'git fetch --tags'
    TAGGED_COMMIT = sh(script: 'git rev-list --branches=master --tags --max-count=1', returnStdout: true).trim()
    LATEST_TAG = sh(script: 'git describe --abbrev=0 --tags ${TAGGED_COMMIT}', returnStdout: true).trim()
    env.VERSION_NUMBER = sh(script: "echo ${LATEST_TAG} | cut -d 'v' -f 2", returnStdout: true).trim()
    echo "VERSION_NUMBER: ${VERSION_NUMBER}"
    sh 'echo "VERSION_NUMBER: ${VERSION_NUMBER}"'
  }
}
...

第一个回波打印VERSION_NUMBER: 2.1.0,第二个回波打印VERSION_NUMBER: 2.1.0