Jenkins Workflow Pluginの使いかた

*※まだ使い始めたばかりなので、今後少しずつ情報追記していきます。*

# Workflow Pluginとは
**Workflow Plugin** はGroovyスクリプトでJenkinsのジョブ設定が記述できるプラグインです。
川口氏が関わっているということで公式プラグインという位置付けでしょうか。

[川口耕介氏，Jenkinsプロジェクトの現状やWorkflow Pluginの特徴を説明 ～Jenkinsユーザカンファレンス2015東京 基調講演](http://gihyo.jp/news/report/2015/01/2001)
> Workflow Pluginが解決しようとしている課題は，Jenkinsで複雑なワークフローを実現する際の手間を減らすことです。従来のJenkinsとプラグインの組み合わせだと，複数のジョブをまたがって設定をする必要があり，見通しが悪くなりがちでした。また，ジョブのループ・並列実行やエラーハンドリングの設定は，非常に煩雑でした。
Workflow Pluginでは，一つのジョブで複雑なワークフローを記述できます。フローは，次のようにGroovyを用いたDSLで記述します。一見しただけで，何をしようとしているか，全体像が把握できます。

　
実際に使用してみた印象もまったく上記の通りで、とてもシンプルなコードで目的のワークフローを実現することができました。
また単純なワークフローでも、UI上で設定するよりコードで書いたほうが見通しが良いので、あらゆるケースに有効なプラグインだと思います。

# 外部プラグインとの連携
ワークフロー内で外部プラグインを使用することも可能です。
Workflow Pluginがリリースされたのがつい最近のため、現時点（2015/6）で対応しているプラグインは少ないですが、人気のあるプラグインはわりとすぐに対応されそうな気がします。
> https://github.com/jenkinsci/workflow-plugin/blob/master/COMPATIBILITY.md

# インストールと使いかた
Jenkinsのプラグインの管理から**「Workflow Plugin」**をインストールして、ジョブ作成時に `Workflow` を選択します。

# 基本的な構文
```groovy
node("master") {
  git branch: "master", credentialsId: "14e75b6a-6225-3678-a31c-31753c06d928", url: "https://user@bitbucket.org/user/repo.git"
  sh "gradle clean test"
}

node("slave") {
  ...
}
```

`node("ノード名") { ... }` の形式で記述します。

# Tips
## 別のジョブを実行
```groovy
build job: "hoge"
```

### パラメータを指定してジョブを実行
```groovy
def params = [new StringParameterValue("ENV", "staging")]
build job: "hoge", parameters: params
```

### パラメータを変えてジョブを複数回実行するサンプル
```groovy
def params = ["develop", "staging", "production"]
def tasks = [:]

for (i = 0; i < params.size; i++) {
  def param = params[i]
  tasks[param] = {
    param: {
      build job: "hoge", parameters: [new StringParameterValue("ENV", param)]
    }
  }
}

parallel tasks
```

Groovyなので本当は `each` で書きたいところですが、それだと何故か配列の先頭の値しか実行されず。
ならば `for in` で！と思いきや `java.io.NotSerializableException: java.util.ArrayList$Itr` が発生...。

## 並列実行
```groovy
parallel(
  "task-1": {
    build job: "build"
  }, 
  "task-2": {
    build job: "test"
  }, 
  "task-3": {
    build job: "deploy"
  }
)
```

`task-n` の部分はただのラベル（コンソールログやRunning Stepsに表示される）です。

## 失敗してもリトライ
```groovy
retry(3) {
  build job: "hoge"
}
```

引数の値はリトライ数ではなく初回の実行も合わせた最大実行数です。

## ジョブの実行が失敗しても後続処理を実行するサンプル
```groovy
def failure = false

try {
  build job: "hoge"
} catch (e) {
  // 失敗したらフラグを立てて処理を継続
  failure = true
}

// 後続処理
// ...

// ワークフローのビルドステータスを"FAILURE"にする
if (failure) currentBuild.result = "FAILURE"
```

ワークフロー内で実行したジョブが失敗した場合、単純に `try..catch` しただけだとワークフロー自体のビルドステータスが **SUCCESS** になってしまうので、最後にステータスを **FAILURE** に変更します。

## 成果物を保存
```groovy
archive 'build/test-results/*.xml'
```

## JUnitテスト結果の集計
```groovy
step([$class: 'JUnitResultArchiver', testResults: 'build/test-results/*.xml'])
```

## 他プロジェクトから成果物をコピー
```groovy
step ([$class: 'CopyArtifact',
  projectName: "hoge",  // プロジェクト
  filter: "**/*",  // コピーする成果物
  selector: [$class: 'SpecificBuildSelector', buildNumber: "3"], // ビルド（特定のビルド）
  optional: true  // オプション
])
```

CopyArtifact Pluginを使う場合のサンプルです。
UIから設定できることとひと通り同じことができそうです。
> https://github.com/jenkinsci/copyartifact-plugin/blob/master/src/main/java/hudson/plugins/copyartifact/CopyArtifact.java


# おまけ
ジョブ設定をGroovyスクリプトで記述するということで、直接ジョブのインスタンスを取得して操作するなんてことも簡単にできます。自由度が高くてワクワクしますね。

```groovy:指定したジョブの最後のビルド番号を取得
job = hudson.model.Hudson.instance.getItem("hoge")
def lastBuildNum = job.getLastBuild().number
```

> http://hudson-ci.org/javadoc/hudson/model/Job.html

※ジョブのインスタンスを取得したあとにbuildコマンドを実行すると、なぜか以下のエラーが発生します。

```groovy
java.io.NotSerializableException: org.jenkinsci.plugins.workflow.job.WorkflowJob
```

とりあえずbuildコマンド前に `job = null` すれば回避できるのですが、バグなのか仕様なのか謎です。