web-dev-qa-db-ja.com

Jenkins Pipeline-リストを反復処理する方法

パイプラインのファイルから値を読み取る必要があります。私はsplit()を使用して、それらをArrayに入れています。それらをArraylistに入れる必要があるので、Arrays.asList()を使用しています。私が抱えている問題は、size()またはlength()メソッドを使用できないため、次のようなforループを作成できないことです。

for (ii = 0; ii < var.length; ii++)

または

for (ii = 0; ii < var.size; ii++)

エラーが発生するため:nclassified field Java.util.Arrays $ ArrayList length

したがって、for eachループを使用しようとしましたが、最終ブロックで何らかのアクション(たとえばlsコマンドなど)を実行すると、1回だけ反復されます。しかし、コマンド 'echo'を実行するだけで、想定されているように各要素に対して反復処理が行われます。コマンドを使用するときにリスト内の各要素を反復処理するようにコードを変更する方法に関するアドバイスはありますか?

正しく動作します....

node{
    wrap([$class: 'ConfigFileBuildWrapper', managedFiles: [[fileId: 'dest_hosts.txt', targetLocation: '', variable: 'DEST_Host']]]) {
        Host = Arrays.asList(readFile(env.DEST_Host).split("\\r?\\n"))
        deploy(Host)
    }
}

@NonCPS
def deploy(Host){
    for (String target : Host){
        try {
            echo target
        }
        finally {
           echo target
        }
    }
}

OUTPUT(各要素について繰り返す):

[Pipeline] node
Running on <obfuscated>
[Pipeline] {
[Pipeline] wrap
provisoning config files...
copy managed file [<obfuscated>] to file:/var/lib/jenkins/<obfuscated>
[Pipeline] {
[Pipeline] readFile
[Pipeline] echo
www.testhost.com
[Pipeline] echo
www.testhost.com
[Pipeline] echo
www.testhost2.com
[Pipeline] echo
www.testhost2.com
[Pipeline] }
Deleting 1 temporary files
[Pipeline] // wrap
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS

しかし、'ls -l'などのアクションを実行すると、1回だけ反復されます

node{
    wrap([$class: 'ConfigFileBuildWrapper', managedFiles: [[fileId: 'dest_hosts.txt', targetLocation: '', variable: 'DEST_Host']]]) {
        Host = Arrays.asList(readFile(env.DEST_Host).split("\\r?\\n"))
        deploy(Host)
    }
}

@NonCPS
def deploy(Host){
    for (String target : Host){
        try {
            echo target
        }
        finally {
           sh 'ls -l'
        }
    }
}

出力(1回だけ反復):

[Pipeline] node
Running on <obfuscated>
[Pipeline] {
[Pipeline] wrap
provisoning config files...
copy managed file [<obfuscated>] to file:/var/lib/jenkins/<obfuscated>
[Pipeline] {
[Pipeline] readFile
[Pipeline] echo
www.testhost.com
[Pipeline] sh
[sandbox%2Fpipeline-test-new1] Running Shell script
+ ls -l
total 8
-rw-r--r-- 1 jenkins jenkins 10 Jun 17 16:07 someFile
[Pipeline] }
Deleting 1 temporary files
[Pipeline] // wrap
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
6
mdo123

ArrayList(および一般的にLists)には長さフィールドまたはサイズフィールドがありません。それらにはsize()メソッドがあります。それをforで使用します:

for (ii = 0; ii < var.size(); ii++)
7

このチュートリアルに従って: https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md#serializing-local-variables

...注釈_@NonCPS_...でマークされたメソッドは、パイプラインエンジンによって「ネイティブ」として扱われ、そのローカル変数は保存されません。ただし、パイプラインステップへの呼び出しはnot行うことができます

あなたの場合、sh呼び出しはパイプラインステップ操作であり、明らかに_@NonCPS_アノテーション付きメソッド内からは実行できません。

配列をListに変換することに関しては、Groovyの土地にいるので、配列に対して.toList()メソッドを使用するだけで済みます。

4
Olaf

このソリューション

node('master') {
    stage('Test 1: loop of echo statements') {
        echo_all(abcs)
    }
}

@NonCPS // has to be NonCPS or the build breaks on the call to .each
def echo_all(list) {
    list.each { item ->
        echo "Hello ${item}"
    }
}

宣言型パイプラインを使用する場合は、スクリプトステートメントで呼び出しをラップする必要があります。

stage('master') {
    steps {
        script {
            echo_all(abcs);
        }
    }
1
Matthias M

何時間もグーグルを費やさずにジェンキンスに関する有用な情報を見つける方法を理解していないため、正確な理由を説明することはできませんが、次のように伝えることができます。

しばらくの間、sh 'echo $ line'の後に 'echo line'を追加することで正常に実行できると思っていましたが、それはJenkinsがスクリプトの前のバージョンを実行していることが原因でした...

私はあらゆる種類のことを試しましたが、どれも機能しませんでしたが、私はこれを見つけました:

Jenkinsfileの各ループが最初の反復で停止する理由

Jenkinsパイプラインの既知のバグです!

(既知のバグは JENKINS-26481 です。これは、「少なくとも一部のクロージャーは、ワークフロープラグインによって管理されるGroovy CPS DSLスクリプト内で1回だけ実行されます」)

1
RustyCar