LoginSignup
2
1

More than 3 years have passed since last update.

Jenkins Pipelineのpipeline {...}の"pipeline"と"{...}"は何か(Groovy初心者向け、他言語経験者向け)

Last updated at Posted at 2020-02-20

背景

お仕事でJenkins Pipelineを書くことになりました。早速サンプルをコピーし、Hello Worldが表示されてうれしい一方、こんな疑問が。

この、pipeline{...}とは何なのか?どういう文法規則なのか?

Jenkinsfile
pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'echo "Hello World"'
            }
        }
    }
}

Jenkinsfile自体は単なるデータ構造(JSONやYAMLの仲間)に見えます。ということは何か規則があるはずです。しかしそれが書かれているページが見つからない。
職場のつよつよエンジニアに聞いたところ、JenkinsfileはGroovyのプログラムということが分かりました。

その後自分で調べたことと、他の言語との対比を書いておきます。

"pipeline"と"{...}"は何かの答え

pipelineメソッド名
{...}クロージャ

pipeline {...}は、pipelineメソッドに、{...}というクロージャを引数として渡す、という構文です。

pipelineはメソッドなので、Jenkinsfileの実行時に

def pipeline(Closure cl) {
    // 前処理
    // クロージャを呼び出す
    cl();
    // 後処理
}

のように定義されたメソッドが(どこかから)読み込まれています。(上記コードは正確には少し違います。補足を参照してください)

もっと詳しく

groovyのメソッド呼び出し

上記のpipelineの呼び出しを冗長に書くと、

pipeline({ ->
    // 処理
})

です。
groovyのクロージャは{x, y -> x + y}のように、{引数 -> 処理}のように書きます。引数がない場合は、引数 ->の部分は省略可能です1。引数を省略すると、

pipeline({
    // 処理
})

の形になります。
また、メソッド呼び出しのカッコは、引数がある場合は省略可能なので、

pipeline {
    // 処理
}

になります。Jenkinsfileと同じ形になりました。

クロージャ

クロージャとは、メソッドの呼び出し側で動いているような振る舞いをする無名関数です。
こちらの説明が分かりやすいです。
クロージャ - Apache Groovyチュートリアル

他の言語で書いてみると

Groovyのクロージャを他の言語と対比します。(ここに書ききれない言語につきましてはコメントで補足お願いします)

Ruby

Groovyの

pipeline {
    // 処理
}

という記法は、Rubyの

pipeline {
  # 処理
}

という記法と対応します。見た目は同じですね。GroovyはRubyに強い影響を受けていることがわかります。
Rubyのブロックを、Groovyではクロージャと言います。ブロックとクロージャの違いは、こちらのページが分かりやすいです。
Rubyist のための他言語探訪 【第 5 回】 Groovy

JavaScript

Groovyの

pipeline {
    // 処理
}

という記法は、JavaScriptの

pipeline(() => {
    // 処理
})

という記法に対応します。JavaScriptではメソッド呼び出しのカッコは省略できず、引数がない場合も引数を囲むカッコを省略できないですが、Groovyでは省略が可能です。

Java

Groovyの

pipeline {
    // 処理
}

という記法は、Javaの

pipeline(() -> {
    // 処理
})

に対応します。JavaScriptと同様Javaでもメソッド呼び出しのカッコと、引数がない場合は引数を囲むカッコを省略できません。Groovyではこの2つは省略可能です。

Python

Groovyの

pipeline {
    // 処理
}

という記法は、Pythonで対応する記法がないのですが、あえて書くとしたら

pipeline(lambda: 処理)

です。Pythonの場合、lambda式は複数行にまたがることができませんが、Groovyでは可能です。

補足

上で、pipelineメソッドは

def pipeline(Closure cl) {
    // 前処理
    // クロージャを呼び出す
    cl();
    // 後処理
}

のようになっていると書きましたが、正確にいうと少し違います。クロージャ内で使用できる関数を制限するため、delegate(移譲)を行なっています。pipelineメソッドのソースが見つからなかったのですが、より実情に沿ったコードは以下です。

def pipeline(@DelegatesTo(PipelineSpec) Closure cl) {
    def pipelineSpec = new PipelineSpec()
    def code = cl.rehydrate(pipelineSpec, this, this)
    code.resolveStrategy = Closure.DELEGATE_ONLY
    code()
}

本文中では分かりやすさを優先するため、クロージャをそのまま呼び出す書き方にしています。

参考資料

あとがき

Jenkinsfileを作成している最中、「コピペで動いてはいる、ただ、なんで動いているのか分からない」という状態でしたが、Groovyのプログラムということを理解し、実態がつかめました。
Jenkins Pipelineの記事がまだまだ少ないので、分かったことを今後も書けたらと思います。


  1. 正確に言うと、{-> 処理}{ 処理 }では挙動が変わります。 

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1