web-dev-qa-db-ja.com

Jenkinsパイプラインshはシェルコマンドでパイプを尊重していないようです

バージョン2.32.2のパイプラインでJenkinsfileを使用しています。

さまざまな理由で、pomからバージョン文字列を抽出します。私は、mavenヘルププラグインを追加して、evaluateを使用する必要がないことを望んでいました。

パイプを使用し、executorのjenkinsワークスペースのコマンドラインで動作するpomからそれを取得するために、すぐに小さなsed式を思いつきました。

$ 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

Jenkinsfileでパイプされたコマンドを適切に使用する方法に関するガイダンスはありますか?

13
sporkthrower

私はついに考えを入れて、パイプサブシェルがおそらく問題を引き起こしていることに気付きました。私は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}"
}   
7
sporkthrower

環境で許可されている場合、この問題の簡単な解決策は、パイプを含むスクリプトをファイルに配置し、次のように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"
  }
}
4
BnMcG

そのため、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を割り当てるシェルの実行が期待どおりに機能することに注意してください(変数をv2.1.0に割り当てる)。 VERSION_NUMBERを割り当てるために同じことを(単一引用符で)試みると、うまくいきません-パイプがすべてを台無しにします。代わりに、スクリプトを二重引用符で囲みます。

最初のエコーはVERSION_NUMBER: 2.1.0を出力しますが、2番目のエコーはVERSION_NUMBER:を出力します。 VERSION_NUMBERをシェルコマンドで使用できるようにするには、以下に示すように、シェルコマンドの出力を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を出力し、2番目のエコーはVERSION_NUMBER: 2.1.0を出力します。

0
Quinn Vissak

私はジェンキンスパイプライン内でのパイプの使用にも苦労していますが、補足として、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
0
mattvbv

pipeline-utility-steps 現在のプラグインには readMavenPom ステップが含まれており、次のようにバージョンにアクセスできます。

version = readMavenPom.getVersion()
0
StephenKing