Jenkins の Declarative Pipeline を触ってみた
Jenkins (ジェンキンス) とは、継続的インテグレーション (CI : Continuous Integration) を実現するためのツール。Git リポジトリへの Push などをトリガーに、自動的にビルドやリリース作業を行ってくれるツールだ。
Jenkins におけるジョブ (ビルド処理だとか、自動的にやらせたいタスク) は、これまでブラウザ上で GUI 操作によって作成していたが、ジョブ定義をバージョン管理できないことなどが欠点だった。
そこで、Jenkins バージョン2から Pipeline (パイプライン) という仕組みが登場し、ジョブを定義した専用のスクリプトファイルを書けるようになった。最初に登場したスクリプトの記法は Scripted Pipeline と呼ばれる。テキストファイルならバージョン管理もしやすい、ということで広まったが、記法が難解だったため、新たに Declarative Pipeline という別の記法が登場した。
2018年現在、Jenkins では Declarative Pipeline v1.2 という記法をベースに、必要があればその中に Scripted Pipeline の記法を混ぜ込んで記述してもらう、という手法を推奨しているようである。もちろん、素の Scripted Pipeline の記法でもまだ書けるし、両者にやれることの違いはそんなにないが、できれば新しい・優れた記法を知っておきたい。
今回はこの Declarative Pipeline を触ってみよう、というワケである。
目次
前提環境
今回は、Windows Server 上に構築済みだった Jenkins を利用している。サーバが Linux ではなく Windows Server だったことにより、後々困る事態になった…。インストールとか環境設定の話は割愛。Pipeline プラグインが導入済みの環境とする。
BitBucket リポジトリとの連携をベースにしているので、GitHub との連携設定は適宜別の設定が必要と思われる。
ネット上でパイプラインの記法をググりづらい
イマイチパイプラインの記法がまとまっているサイトが少なく、記事が書かれた時期によって、どの記法を対象に解説しているのかバラバラだ。記法の種類は大きく以下の3種類ある。
- Scripted Pipeline :
node {}
がトップレベルにある記法 - Declarative Pipeline (v1.2 未満) :
pipeline {}
がトップレベルにある記法 - Declarative Pipeline (v1.2 以降) :
pipeline {}
がトップレベルにあるのは変わらず。parallel
など一部で v1.2 未満の記法と互換性がない。
これら3種類は、いずれも互換性がないので、自分がどの記法で書きたいのか、その記事の情報をそのまま適用できるのか、は逐一確認したい。
Declarative Pipeline でジョブを作ってみる
まずは Declarative Pipeline でジョブを作ってみるとする。
Jenkins の管理画面で「新規ジョブ作成」を選ぶ。ジョブの種類として「Pipeline」を選択し、「OK」ボタンでジョブを作成する。
次に設定画面。
- 「General」
- お好みで「古いビルドの破棄」あたりを入れておけばよいかと。
- 「Build Triggers」
- Git リポジトリからのプッシュ時に自動実行する場合は、「Build when a changes is pushed to ...」と「SCM をポーリング」にチェックを入れる。
- 自分は BitBucket 連携を試したが、GitHub との連携時はまたちょっと違うかも。
- 「Advanced Project Options」
- 特になし。
- 「Pipeline」
- まずは「Pipeline script」を選んでおくと、エディタ領域が表示される。ココに直接 Pipeline スクリプトを記述できる。
- 「Pipeline Syntax」のリンクから、Pipeline を記述するためのスニペットが出力できる。
今回は、Git リポジトリからチェックアウトを行い、npm install
後に npm test
コマンドを流してみようと思う。
// Declarative Pipeline 記法。コメントはスラッシュ2つで単一行
/* これで複数行コメントも可能 */
pipeline {
// ジョブを実行するエージェントを指定 : 特になければ any で
agent any
stages {
stage('Git チェックアウト') {
steps {
// Credentials ID は「Pipeline Syntax」より作成すると自動的に生成してくれる
// master ブランチ以外を指定する際は「branch:」オプションを付けて書く
git credentialsId: '★', url: 'ssh://git@example.com/example.git'
}
}
stage('npm install') {
steps {
// Node.js を使用する際は別途環境定義しておき、それを指定する
// これも「Pipeline Syntax」から生成すると良い
nodejs(configId: '★', nodeJSInstallationName: 'my nodejs') {
// Jenkins を Windows Server に立てている場合、Git Bash を入れてあっても「sh」が上手く動作しなかった
// 仕方がないので「bat」で動かしている
bat 'npm install'
// Linux サーバ上に立てている場合は「sh」で良い
// sh 'npm install'
}
}
}
stage('UT 実行') {
steps {
nodejs(configId: '★', nodeJSInstallationName: 'my nodejs') {
bat 'npm test'
}
}
}
}
}
ざっとこんな感じ。今回はカバレッジレポート生成とかはナシ。★
部分は環境によって変わる ID の類なので、「Pipeline Syntax」より設定して自動生成させるとよろし。
Windows Server 上の Jenkins は sh
が使えない?
Windows Server 上に構築した Jenkins の場合、通常のジョブの中では Git Bash を利用した「sh」スクリプトを書くことができたのに、Declarative Pipeline だと何故か以下のようなエラーが出てしまった。
[C:\Program Files (x86)\Jenkins\workspace\Test] Running shell script
sh: echo 2376 > 'C:\Program Files (x86)\Jenkins\workspace\Test@tmp\durable-e59db720\pid'; jsc=durable-00618ac21868df95957d278393c845d5; JENKINS_SERVER_COOKIE= 'C:/Program Files (x86)/Jenkins/workspace/Test@tmp/durable-e59db720/script.sh' > 'C:\Program Files (x86)\Jenkins\workspace\Test@tmp\durable-e59db720\jenkins-log.txt' 2>&1; echo 0 > 'C:\Program Files (x86)\Jenkins\workspace\Test@tmp\durable-e59db720\jenkins-result.txt': No such file or directory
# 整形してみた
[C:\Program Files (x86)\Jenkins\workspace\Test] Running shell script
sh: echo 2376
> 'C:\Program Files (x86)\Jenkins\workspace\Test@tmp\durable-e59db720\pid';
jsc=durable-00618ac21868df95957d278393c845d5;
JENKINS_SERVER_COOKIE= 'C:/Program Files (x86)/Jenkins/workspace/Test@tmp/durable-e59db720/script.sh'
> 'C:\Program Files (x86)\Jenkins\workspace\Test@tmp\durable-e59db720\jenkins-log.txt' 2>&1;
echo 0
> 'C:\Program Files (x86)\Jenkins\workspace\Test@tmp\durable-e59db720\jenkins-result.txt': No such file or directory
# もしくは以下のようなエラー
[C:\Program Files (x86)\Jenkins\workspace\Test] Running shell script
sh: C:/Program Files (x86)/Jenkins/workspace/Test@tmp/durable-c677b5ca/script.sh: C:\Program: bad interpreter: No such file or directory
「No such file or directory
」とか「bad interpreter
」とか言われる。
どうも、Git Bash 内で、Windows のディレクトリの区切り文字バックスラッシュ「\
」がエスケープ文字と誤解されるらしい。もしくは、Program Files
というディレクトリ名のスペースがコマンドの区切りだと思われたり、セミコロン ;
が Git Bash だと解釈できなかったりするのかな?ともかく、正常に動作しなかった。
仕方なく「bat
」を使うことにした。幸い node
や npm
は OS に依存していないので大丈夫だった。
強引に Git Bash を実行するには
それでも Windows Server 上の Jenkins でにおける Declarative Pipeline で強引に Git Bash を実行するには、以下のようにすれば実行はできた。しかし、結果がコンソール出力されないのでイマイチかと。
bat(returnStdout: true, script: '"C:/Program Files/Git/bin/bash.exe" -xec "ls"')
bat
内で Git Bash のフルパスを指定して引数から ls
コマンドを実行させている。オプションは以下のとおり。
-x
: シェルスクリプト内で処理されたコマンドを表示する-e
: 実行したコマンドが 0 でない終了コードを返した時点でスクリプトがexit
する-c
: 引数のコマンドを実行する
ジョブ名に日本語が含まれていると bat
で止まる
ジョブ名はワークスペースのディレクトリ名として使われる。この兼ね合いで、ジョブ名 = ディレクトリ名に日本語が含まれると、「bat
」コマンドが実行されたままになり、結果を返してくれない。
ジョブ名には日本語を使わないようにするのが簡単な回避策。
ジョブを実行する
BitBucket の場合、リポジトリの「設定」→「フック」→「ポストレシーブ」より、「Bitbucket Server Webhook to Jenkins」を有効化しておく必要がある。GitHub の場合は別の設定が必要だろうか?試していない。
設定ができていれば、Jenkins 管理画面での「ジョブ実行」からの手動実行はもちろんのこと、Git リポジトリへの Push や、プルリクのマージ時などに自動的にジョブが実行される。
これは良い感じ。
- 参考 : Jenkins2のPipelineとJenkinsfileの使い方 | karakaram-blog
- Jenkins 管理画面の操作手順が分かりやすい。Jenkinsfile は Scripted Pipeline 記法。
- 参考 : An example Declarative Pipeline Jenkinsfile for Feb 15 2017 demo · GitHub
- 参考 : Declarative PipelineでJenkinsfileを書いてみた(Checkstyle,Findbugs,PMD,CPDとか) - Qiita
- Declarative Pipeline (v1.2 未満) の記法サンプル集。
- 参考 : jenkins - How to define parallel stages in a declarative Jenkinsfile? - Stack Overflow
- Declarative Pipeline v1.2 以降の記法が混在してエラーに至った例。