この記事はQiitaで公開されていました
ほとんど情報がなかったので調べながら書いたメモ。基本的に、公式情報が最もまとまっている。
また、古い情報らしいけど、現状こちらにしか書かれていない項目もある。
Declarative Pipelineの1.2.8から、ジェネレータが追加されたようです。
基本
現状のJenkinsfileは2通り書き方があって、pipeline
がルートになっている場合はDeclarative Pipelineという。この場合は、Groovyスクリプトを直接書くことができず、Groovyを書きたければscript
ディレクティブを使う必要がある。この記事では主にこちらを扱う。
pipeline
から始まらない場合、Scripted Pipelineといって、この場合は直接Groovyスクリプトも書けるし、node()
やstage()
などの、Pipeline Stepsメソッドも書くことができる。便利そうにみえるけど自由度が高すぎて職人コードになりがち。
Declarative Pipelineの書き方
Jenkinsfileは特定の条件ごとにディレクティブを書いて実装する。ディレクティブの出現順は以下の順番になっている。例えばstages
のすぐ下にagent
を書くことはできない。
pipeline { // 1行コメント /* * 複数行コメント */ agent { ... } environment { ... } options { buildDiscarder(...) checkoutToSubdirectory(...) disableConcurrentBuilds(...) disableResume() newContainerPerStage(...) overrideIndexTriggers(...) preserveStashes(...) quietPeriod(...) retry(...) skipDefaultCheckout(...) skipStagesAfterUnstable(...) timeout(...) timestamps() parallelsAlwaysFailFast(...) } parameters { string(...) booleanParam(...) choice(...) file(...) text(...) password(...) run(...) // ?? } tools { maven '...' jdk '...' gradle '...' } triggers { cron(...) pollSCM(...) } stages { stage { agent { ... } environment { ... } tools { ... } options { skipDefaultCheckout(...) timeout(...) retry(...) timestamps() } when { ... } steps { //Pipeline Steps Reference参照 echo 'help' sh 'ls' script { // 任意のGroovyスクリプト } } } } steps { //Pipeline Steps Reference参照 } post { always { ... } success { ... } failure { ... } ... } }
steps
だけの場合は、直接steps
の中に書くものを記述できる。
echo 'help' sh 'ls'
node()
のようにsteps
ディレクティブの中で子ブロックが現れる場合、そのブロックの中はsteps
ディレクティブと同じものが書ける。
steps { node('slave1'){ sh 'ls' dir('output'){ sh 'ls' } } }
個別の事例
stageの書き方
stage()
を使うと、進捗を分けて表示することができるが、インターネットでは2種類の書き方がある。stage
単体で書かれているものは古く、推奨されない。
stage 'first' sh 'ls' stage 'second' sh 'pwd'
今はブロックを取るようになっていて、こちらが推奨される。
stage('first'){ sh 'ls' } stage('second'){ sh 'pwd' }
ビルドするノードを制限する
agent
ディレクティブでラベルを指定する。
agent {
label 'slave1'
}
または、steps
ディレクティブでnode
ブロックを使う。
steps {
node('slave1'){
}
}
環境変数をセットする
environment
ディレクティブが使える場合はその中で書く。ここでは、定数またはcredentials()
しか使えない。また、credentials()
はSSHユーザ名と秘密鍵を扱えない。
environment { GOPATH = '/home/jenkins/go' // Jenkinsの資格情報に登録されている値を取り出す TOKEN = credentials('credential_id') }
credentials()
で取り出したものは、シークレットテキストの場合はそのまま使える。ユーザ名とパスワードの場合、TOKEN
はユーザ名とパスワードを:で区切った文字列になっている。個別に使いたい場合は、TOKEN_USR
やTOKEN_PSW
のようにサフィックスを付けて扱うと良い。
または、steps
ディレクティブの中でwithEnv
ブロックやwithCredentials
ブロックを使う。withEnv
の中でだけ環境変数が有効になる。
steps { withEnv(["GOPATH=${env.WORKSPACE}"]) { } withCredentials(bindings: [ // シークレットテキスト string(credentialsId: 'credential_id', variable: 'TOKEN'), // ユーザ名とパスワード usernamePassword(credentialsId: 'credential_id', passwordVariable:'PASS', usernameVariable:'USER'), // ファイル file(credentialsId: 'credential_id', variable: 'FILE'), // SSH秘密鍵: passphraseVariable, usernameVariableは省略可 sshUserPrivateKey(credentialsId: 'credential_id', keyFileVariable: 'KEY_FILE', passphraseVariable: '', usernameVariable: '') ]){ } }
withCredentials()
の詳細はCredentials Binding Pluginを読むと良い。
Groovyを使ってもっと細かく制御したい場合。steps
ディレクティブに直接Groovyは書けないのでscript
ディレクティブを使う。
steps {
script {
// ここからGroovy
env.GOPATH = env.WORKSPACE
}
}
ツールをインストールする
Jenkinsの管理メニューにGlobal Tools Configuration があり、そこで事前にMavenやGoコンパイラなどのバージョンと名前を定義しておくと、tools
ディレクティブで、自動でインストールすることができる。
pipeline {
tools {
go 'go1.10'
}
}
Pipeline Syntaxで自動生成したコードはtool name: 'go1.9', type: 'go'
のように出力されるが、このままDeclarative Pipelineとして記述するとエラーになる。$type '$name'
のように置き換えて書く必要がある。
パラメータ付きビルドにする
parameters
に何か書くと、パラメータ付きビルドとして扱われる。params.name
で参照する。
pipeline { parameters { string(name: 'TARGET', defaultValue: 'Tests', description: '説明') choice(name: 'STAGE', choices: 'staging\nproduction', description: '説明') } stages { stage('build'){ sh "./make.bash ${params.TARGET}" } } }
実行条件を設定する
stage()
ブロックでwhen
ディレクティブを使う。以下の例は、ブランチ名がrelease-*にマッチした場合のみstageを実行する。
stage('stage'){ when { branch 'release-*' } }
他にも、環境変数の値を条件としたり、全て一致またはどれかが一致などの条件を作ることができる。
複数行のシェルスクリプトを実行
'''
または"""
で囲むと複数行のテキストを記述できる。
steps { sh ''' date sleep 10 date ''' }
'''
の場合は変数展開などをせずにそのままシェルへ渡す。"""
なら${env.PATH}
のような展開を行う。
GitHub Branch Source Plugin環境でスレーブを使ってビルドする
基本的には何もしなくてもプラグインがcloneするが、デフォルトでは(おそらく)Jenkinsマスターのワークスペースへcloneされる。このため、ビルドノードがマスター以外の場合、ビルドするソースコードがスレーブのワークスペースにない状態となる。
steps
ディレクティブでcheckout
を使うとslaveのワークスペースへcloneが行われる。
steps { checkout scm }
または最初から、agent
ディレクティブでラベルを指定しておくと、対象となったスレーブでcloneされる。
pipeline { agent { label 'slave1' } steps { sh 'ls' } }
特定のディレクトリへcloneする
options
ディレクティブで指定する。
options {
checkoutToSubdirectory 'src/v2'
}
または、dir()
を使うとカレントディレクトリを変更できるので、移動した後でcheckout scm
を実行すればいい。移動するディレクトリが存在しない場合は自動的に作成される。
stage('chekout'){ steps { dir("src/v2"){ checkout scm } } }
GitHub Branch Source Pluginでcheckoutの動作を変更する
How to Customize Checkout for Pipeline Multibranchによると、checkout scm
は、
checkout([ $class: 'GitSCM', branches: scm.branches, extensions: scm.extensions, userRemoteConfigs: scm.userRemoteConfigs ])
の省略形らしい。Shallow cloneとかcloneするディレクトリを変更する場合は、scm.extensions
に配列でオプションを追加する。
checkout([ $class: 'GitSCM', branches: scm.branches, extensions: scm.extensions + [ [ $class: 'CloneOption', noTags: false ], [ $class: 'RelativeTargetDirectory', relativeTargetDir: "src/v2" ], ], userRemoteConfigs: scm.userRemoteConfigs ])
Gitサブモジュールを使う
checkout scm
にSubmoduleOption
をセットします。
checkout([ $class: 'GitSCM', branches: scm.branches, extensions: scm.extensions + [ [ $class: 'SubmoduleOption', disableSubmodules: false, parentCredentials: true, recursiveSubmodules: true, reference: '', trackingSubmodules: false ], ], userRemoteConfigs: scm.userRemoteConfigs ])
ただし、GitHub Branch Source Pluginを使う場合、parentCredentials
はGitHub APIトークンが使われているため、サブモジュールの参照もHTTPで行う必要があります。
checkoutの前にワークスペースをクリアする
checkout scm
の前にdeleteDir
を使う。
stage('clean'){ steps { deleteDir() } } stage('checkout'){ steps { checkout scm } }
Scripts not permitted to use methodエラーで動作しない
Jenkinsfileのコードを実行した時、
RejectedAccessException: Scripts not permitted to use method (メソッド名)
というエラーで停止する場合がある。これは、外部のコードを無条件に実行すると危険なので、Script Security Pluginによってsandbox実行されているため、らしい。
外部のコードを制限するための機能なので、Jenkinsfileで回避できるものではない。エラーが発生した後であれば、Jenkinsの管理画面にエラーとなったメソッドの許可を求めるログが出ているので、そこでApprovalボタンを押せば次からはエラーを回避できる。このファイルは$JENKINS_HOME/scriptApproval.xmlに置かれているので、これをコピーしてもいい。
成果物を保存する
post
セクションでArchive Artifact Pluginを使えばよい。
pipeline { post { success { archiveArtifacts artifacts: bin/*, fingerprint: true } } }
成果物の保存数を制限する
いろいろ書き方はあるが、おそらくoptions
ディレクティブを使うのが簡単。
pipeline { options { buildDiscarder(logRotator(numToKeepStr: '5', daysToKeepStr: '7', artifactNumToKeepStr: '5')) } }
並列ビルドする
steps
でparallel
を使う。
steps { parallel( linux: { sh './make.bash -t linux_amd64' }, windows: { sh './make.bash -t windows_amd64' } ) }
この例では、./make.bash -t linux_amd64
と./make.bash -t windows_amd64
が並列実行される。
他のジョブをビルドする
build
を使う。
引数のパラメータはJenkinsを置いているフォルダまでのパスを渡す。相対パスの場合は呼び出し元ジョブのディレクトリがカレントになり、絶対パスの場合は$JENKINS_HOME/jobsがルートになる。
steps {
build '../jobName1'
}
マルチブランチ構成のプロジェクトを呼び出す場合は、内部の階層がブランチごとに切られているので、ブランチ名も必要。
steps {
build '../jobName1/master'
}
GitHub Branch Sourceが管理しているジョブはマルチブランチに近くて、Organizationの下にジョブが作られるので、次のようになる。
steps {
build '/organizationName/jobs/jobName/master'
}
Jenkinsが管理しているCredentialでssh接続したい
ssh-agentプラグインをインストールするとsshagent
ブロックが利用可能になる。このブロックの中に記述したコマンドは、Jenkinsが管理している秘密鍵が追加されたssh-agent
が動作してる状態で実行される。なのでJenkinsのアカウントでgit push
したい場合は、以下のように書く。
steps { // jenkins_credential_id_strという名前のCredentialを読み込む sshagent(['jenkins_credential_id_str']){ sh 'git push' } }