Jenkins の Multibranch Pipieline を試した

前回、Jenkins でジョブをスクリプト形式で書ける Declarative Pipeline という記法を試した。

今回は、このスクリプトファイルを複数のブランチに適用しやすくするための Multibranch Pipeline というモノを試してみる。

Multibranch Pipeline とは

通常の Pipeline でブランチごとにジョブを実行したい場合、Pipeline スクリプトファイル内でトリガーの契機となったブランチを判定したりする必要があった。この時、ワークスペースは全部ランチで共有されており、ブランチごとに異なる依存ライブラリを扱ったりしている時に不都合が出やすかった。

マルチブランチ・パイプラインは、Git リポジトリと自動連携して複数ブランチを個別に管理してくれる仕組みだ。スクリプトファイル内でブランチを選択してチェックアウトする必要はなく、Git リポジトリへの Push を検知して自動的に対象ブランチ向けのジョブを実行してくれるのだ。

Multibranch Pipeline を作ってみる

まずは Jenkins 管理画面のメニューから「新規ジョブ作成」を選び、「Multibranch Pipeline」を作る。

設定画面での設定項目は以下のとおり。

ここまで設定できたら、対象のリポジトリのルートディレクトリに Jenkinsfile を作り、以下のように実装してみよう。

pipeline {
  agent any
  stages {
    stage('npm install') {
      steps {
        nodejs(configId: '★', nodeJSInstallationName: 'my nodejs') {
          bat 'npm install'
        }
      }
    }
    stage('UT 実行') {
      steps {
        nodejs(configId: '★', nodeJSInstallationName: 'my nodejs') {
          bat 'npm test'
        }
      }
    }
  }
}

内容は前回の記事で作った「npm install 後に npm test を実行する」というジョブのスクリプトとほぼ同じ。違うのは、「Git チェックアウト」の stage がなくなったこと。ブランチのチェックアウトはジョブが勝手にやってくれるので、Jenkinsfile での指定は不要なのだ。

このファイルを git addgit commit して、git push してみよう。Git リポジトリとの連携ができていれば、Jenkins のジョブが自動的に実行されるはずだ。

試しに、別の名前のブランチを新たに作って git push してみよう。先程のブランチのジョブとは別のワークスペースができ、当該ブランチに対するジョブとして実行される。ブランチ別にサブジョブとして管理されるので、Jenkins の管理画面としても見やすい。例えば「master ブランチはテストをクリアしているが、feat/test1 ブランチはテストが失敗している」といった見極めも容易だ。

特定ブランチのみ異なる Jenkinsfile を実行させる

特定のブランチのみ、同リポジトリ内の Jenkinsfile ではなく、別リポジトリで管理している Jenkinsfile を実行する方法。

実はサブジョブも一つの Pipeline ジョブとして扱うことができ、ブランチごとに個別の設定が可能なのだ。

マルチブランチ・パイプラインの「Branches」から任意のブランチを選択し、「設定の参照」に移動する。すると通常の Pipeline ジョブとほぼ同等の設定画面が現れるはずだ。

ココで最下部にある「Pipeline」のプルダウンにて、「Pipeline from multibranch configuration」から「Pipeline script」を選べばその場にスクリプトが書けるし、「Pipeline script from SCM」を選択して別リポジトリを選択すれば、異なる Jenkinsfile を実行できる。

例えば「develop ブランチまでは UT を実行したいが、master ブランチではイチイチ UT を回す必要はない。master ブランチへの Push 時はリリース作業を行う別のスクリプトを実行させたい」といった場合に利用できるかと思う。

ただし、Multibranch Pipeline の設定に沿わないブランチが出てくるのはあまり管理しやすい状態ではないので、多用は控えたい。

特定のブランチのみ実行する stage を書く

次は、1つの Jenkinsfile 内で、ブランチを判別して特定のブランチのみ処理を行わせる方法。

whenbranch というシンタックスを使って、以下のように書けば良い。

pipeline {
  agent any
  stages {
    stage('master ブランチのみ処理する') {
      when {
        branch 'master'
      }
      steps {
        echo 'master ブランチのみ実行します'
      }
    }
    stage('feat/ 始まりのブランチのみ処理する') {
      when {
        branch 'feat/*'
      }
      steps {
        echo 'feat/ 始まりのブランチのみ実行します'
      }
    }
  }
}

このようなスクリプトにすると、master ブランチで実行された場合は「master ブランチのみ処理する」の stage のみ実行され、「feat/ 始まりのブランチのみ処理する」stage はスキップされる。

branch 'feat/*' のようにワイルドカードも使える。Jenkins 管理画面における「対象ブランチ」「対象外ブランチ」の書き方と同じだ。

not { when { branch という構造にすると、当該ブランチ以外なら実行する、という stage も書ける。

こちらもあまり多用すると、1つの Jenkinsfile に条件分岐が多く登場し、こんがらがるので、最低限に留めたい。

Multibranch Pipeline のジョブの後に別のジョブを実行する

Multibranch Pipeline のジョブの後に、別のジョブを実行するためには、次のように設定する。

後続のジョブの設定にて、「Build Triggers」→「他プロジェクトの後にビルド」を選択し、対象プロジェクトを「【マルチブランチ・パイプライン名】/【ブランチ名】」と指定する。例えば「my-multi/master」といった形だ。

単に「my-multi」とマルチブランチ・パイプラインの名前を指定するだけではダメで、入力補完でもこの時点までは入力エラー扱いになるので指定できないかのように見えるが、スラッシュ / まで入力すると候補が登場する。

コレで、「Multibranch Pipeline を使って全ブランチで UT を実行するが、master ブランチのみはその後に別のリリースジョブを実行する」といった設定が可能になる。

おわり

なかなか Jenkins も奥が深い…。ジョブの構成やスクリプトファイルの管理方法に色々悩むが、あんまり綺麗に構造化しきろうとは思わない方が良いのかも。