概要
Jenkins-Pipelineについての覚書レベルのものを羅列。
嵩張りそうなら個別のページに切り出す。
個別ページに切り出した項目
pipeline中に使える変数
${jenkinsmachineのURL}/pipeline-syntax/globals
で確認できる。
Jenkinsfileにparameters
を足した時などに一度リロードさせたい
1度実行しないとparameters
は反映されない。
そのため、以下のような下準備を行っておくとよいと思われる。
pipeline {
parameters {
booleanParam(name: 'RELOAD_PIPELINE', defaultValue: false, description: 'Job定義ファイルを再読み込みして即終了(ABORT)する')
}
stages {
stage('Reload') {
when { expression { params.RELOAD_PIPELINE } }
steps { script {
echo 'Reload'
currentBuild.result = 'ABORTED'
error('Reload jenkins files.')
} }
}
}
}
currentBuild.result = 'ABORTED'
しておくことでpost { failure { ... } }
の処理が呼ばれないので便利!
マスターマシンとビルド(スレーブ)マシンが違う場合における処理のShared Libraries(モジュール)化
基本は↓を参照。
- https://www.jenkins.io/doc/book/pipeline/shared-libraries/
- https://www.jenkins.io/doc/pipeline/steps/workflow-cps-global-lib/
ただ、マスターマシンとビルド(スレーブ)マシンが違う場合には上記の処理ではうまく読み込めなかった。(詳しい方アドバイスをいただきたいです)
色々試した結果、以下のようにするとスレーブマシンでもモジュールを読み込めたので記載する。
- 任意のレポジトリの
トップレベルディレクトリ
にvars
という名前のディレクトリを作成 -
vars
内に${some_name}.groovy
というgroovyスクリプトを置く- 中身は
def call() {
から始まるcall関数(パラメータがあってもよい)があれば関数やクラスの宣言があっても問題ない模様- e.g.
TriggerJob.groovy
def call(jobName) { build( job: "${jobName}", wait: false, parameters: [] ) }
- e.g.
- groovyではあるが、Jenkins-Scriptなので
withEnv
やsh
、withCredentials
などsteps
に記述できるものは何でも記述可能である模様(未検証)
- 中身は
- 呼び出し元のJob内で
script { library(identifier: 'lib@master', retriever: legacySCM(scm)) }
を呼び出す。- e.g.
stage('Import') { steps { script { library(identifier: 'lib@master', retriever: legacySCM(scm)) } } }
- identifierは何でもいい模様
- retrieverは
legacySCM(scm)
以外だとうまくいかなかった。(要検証)
- e.g.
- 呼び出したいstepsで
some_name()
と書くだけで呼び出しが可能- e.g.
stage("trigger_job") { steps { TriggerJob("other_job_name") }
- e.g.
groovy変数をsh内で参照する方法
groovy変数をsh内で使用するには以下の方法がある。
-
sh "...${variable}..."
のように"
の中に書く -
sh '...' + variable + '...'
やsh '''...''' + variable + '''...'''
のように一度文字列を終了させて+で連結させる。 - 環境変数化
- withEnvブロックを使う
- e.g.
withEnv(["VARIABLE=" + variable]) { sh '..."${variable}"...' }
- 基本はこれを使用すれば良さそう
- e.g.
- environmentブロックを使う
- e.g.
stage(...) { environment { VARIABLE = "${variable}" } steps {...} }
- groovyとしてわざわざ使う機会はないはず?
- e.g.
-
env.NAME
に代入する- e.g.
env.VARIABLE = variable
- 既に定義済みの環境変数を上書きすることはできない点に注意
- e.g.
- withEnvブロックを使う
変更ログを取得する
変更ログの取得方法は2通りあり、APIを使用する方法とgroovy変数を参照する方法である。
API
以下のURLにアクセスすればよい。
${BUILD_URL}api/xml?xpath=//changeSet//comment/text()&wrapper=changes
解説すると以下のような感じ。
-
api/xml
はXML形式で結果を返すことを指す。- 他に
api/json
やpython/ruby/javaなどもあるらしい。(未検証) - 参考 : https://www.jenkins.io/doc/book/using/remote-access-api/
- 単にjobの実行URLに
api/xml
を付けただけでも様々な内容が返ってくる。
- 他に
-
xpath=//changeSet//comment/text()
-
xpath
はXPathというコマンド?(未調査)と同じ挙動をさせるらしい。 -
//
はいずれかの階層とのこと。changeSetはworkflowRun/changeSet
でもアクセスできるが、//
と書くことにより、任意の階層にマッチできる。- よくあるパス指定での
/**/
みたいなものだと思っている。(未検証)
- よくあるパス指定での
-
text()
は//comment
でも取ってこれるが、text形式のものだけ抽出する(未調査)ことができるので楽っぽい。 -
xpath=//comment/text()
だけでも要件は満たせたが、changeSet
も指定した方が厳密な気がしたので採用している。
-
-
wrapper=changes
は最上位のタグをchanges
にする?(未調査)- とりあえず必要なので付けている。
-
sed
あたりにpipeで渡してあげれば良さそう。
注意点
- ユーザー認証などがある場合はAPI-Tokenの用意などが必要。
groovy変数(currentBuild.changeSets)
以下のコードで動作した。
def getChangeMessages() {
def messages = ""
for (entries in currentBuild.changeSets)
{
for (entry in entries.items)
{
messages += "${entry.msg}\n"
}
}
return messages
}
groovy変数名について
未検証
以下のような機能を作成した際、
def getChanges() {
def changes = ""
for (entries in currentBuild.changeSets)
{
for (entry in entries)
{
changes += "${entry.msg}\n"
}
}
return chages
}
以下のようなエラーが出て困ったことがある。
groovy.lang.MissingPropertyException: No such property: chages for class: groovy.lang.Binding
Possible solutions: class
at groovy.lang.Binding.getVariable(Binding.java:63)
at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onGetProperty(SandboxInterceptor.java:270)
at org.kohsuke.groovy.sandbox.impl.Checker$6.call(Checker.java:291)
at org.kohsuke.groovy.sandbox.impl.Checker.checkedGetProperty(Checker.java:295)
at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.getProperty(SandboxInvoker.java:29)
at com.cloudbees.groovy.cps.impl.PropertyAccessBlock.rawGet(PropertyAccessBlock.java:20)
at MyModule.getChanges(MyModule.groovy:11)
at MyModule.call(MyModule.groovy:16)
散々試した結果、changes
という変数名をmessages
に変更したら大丈夫だった。
MissingPropertyException
を見かけたら名前を変えてみるといいのかも?
API呼び出し結果を検証する
Jenkinsというよりはshの挙動なのだが、CIに関わってくるので記載。
curl -I ${url}
でhttp_codeを取得できるのだが、これはGET
にしか使用できない。
そのため、POST
で使用するには以下のようにする必要がある。(GET
にも応用はできるはず)
curl -w '%{http_code}' -o /dev/null ${post_parameters} ${url}
だが、これだとレスポンスの内容が取得できないので以下のようにする必要がある。
-w
で指定する内容にcontentの内容が含まれていない点に注意。
set -e
response=$(curl -w '\n%{http_code}' ${post_parameters} ${url})
http_code=$(echo "${response}" | tail -n1) # "でエスケープしないと改行が変になるため正常に取得できない
test ${http_code} = "200" # 200以外ならエラー終了
レスポンスの内容も出したいなら↓のようにする。
echo "${response}" | head -n -1
ダウンロード進捗表示
curl ... 2>/dev/null
しなくてもcurl -s ...
で消せる。