JenkinsでDeclarative Pipelineを使ったアレコレ（2019/3現在）

周りがCircleCIでマイクロサービスしている中、JenkinsおじさんとしてJenkinsfileを書き始めた。
せっかくなので？、2年前からあるけど割と情報少なめのDeclarative Pipelineという書き方で。

実際に書いてみると、情報がなくてハマったところとか、プラグイン事情が変わったりしてたところがあったので、
レシピ的にいくつか残しておく。

## stages内にstageは複数書けるが、stepsは複数書けない
stageとstepsは、stageはプロジェクトのダッシュボードに出てくるけど、stepsは出てこない。
なので、パイプラインの内容をあまり知らない人にザッと伝えるためにstageの構成は重要。
で、stageを細かくしすぎると理解しづらいので、stepsを細かく分けたいと思ったところで、この結論に…。

具体的には、

```groovy
stages {
  stage("Aをする") {
  }
  stage("Bをする") {
  }
}
```

は大丈夫だけど、

```groovy
stages {
  stage("Aをする") {
    steps {
    }
    steps {
    }
  }
}
```

は書けない。
仕様っぽいので仕方ないということで、一層stageの分割はちゃんと考えたいと思った次第。

## CheckstyleやFindBugs(SpotBugs)の結果集計はwarnings-ng-pluginを使う
Jenkins公式ドキュメントの [Pipeline Steps Reference](https://jenkins.io/doc/pipeline/steps/) を見ると、
Checkstyleのプラグインがある。ただし、 **Deprecated** になってる。ついでにFindBugsも。

で見つけたのが、Jenkins公式で開発されている [warnings-ng-plugin](https://github.com/jenkinsci/warnings-ng-plugin) 。
プラグインの **ng** はNext Generationなので、今後はこっちを開発していく方針っぽい。
このプラグインは、静的解析ツールが出した警告や問題を収集して視覚化してくれる。

CheckstyleやFindBugs(SpotBugs)に対応しているのはもちろん、Android LintやCCM、PMDなどにも対応している。
今回は、CheckstyleとFindBugsの結果を収集してみた。
※SpotBugsじゃないのは、プロジェクトのGradleバージョンが低くて導入できなかったから…

以下の書き方で、Gradleでテストして、JUnit形式のテスト結果やJaCoCoのカバレッジ、Checkstyle、FindBugsの結果を収集できる。
できないと思ってて、いまいちだなと思っているのが、Gradleの実行がシェルスクリプト形式なこと。
これ、プラグインで対応しててほしいとこ。

本題のwarnings-ng-pluginを使っているのは、 **recordIssues** を使っているところ。
warnings-ng-pluginには [公式のドキュメント](https://github.com/jenkinsci/warnings-ng-plugin/blob/master/doc/Documentation.md) があるので、詳しくはそっちを見ると良い。


```groovy
stage('Gradleビルドの準備、テスト') {
  environment {
    resultPath = "build/test-results/**/TEST-*.xml"
    jacocoReportDir = "build/jacoco"
    checkstyleReport = "build/checkstyle/*.xml"
    findbugsReport = "build/findbugs/*.xml"
  }
  steps {
    sh "./gradlew clean test checkstyleMain findbugsMain"
  }
  post {
    success {
      junit resultPath
      jacoco execPattern: "${jacocoReportDir}/*.exec", exclusionPattern: '**/*Test.class'
      recordIssues tool: checkStyle(pattern: checkstyleReport)
      recordIssues tool: findBugs(pattern: findbugsReport)
    }
  }
}
```

## パラメータ付きビルドはparametersブロックを使う
文字通り、パラメータ付きビルドにしたい時は、parametersブロック。
例えば、以下のように書くと、選択肢のパラメータAとテキストのパラメータBを設定できて、
Pipeline内でも **params.A** や **params.B** で参照できるようになる。

```groovy
parameters
  choice(name: "A", choices: ["選択肢1", "選択肢2"], description: "Aを選択してください")
  text(name: "B", defaultValue: "hoge", description: "Bを入力してください")
}
```

## 環境変数を設定したい時はwithEnv
ビルド中だけ設定したい環境変数を **sh** 使ってexportしても良いんだけど、withEnvを使った方がスコープを狭められて良い。
注意するのは、PATHに追加したい時。この時だけは、以下の例のように **PATH+EXTRA** を左辺にする。

```groovy
steps {
  withEnv([
    "HOGE=/usr/local/hoge",
    "PATH+EXTRA=/hoge/bin"
  ]) {
    // 何かやること
  }
}
```

## 悩み：Dockerコンテナを脇で動かす方法がいまいち
今回のビルド、SMTPサーバをビルドの横で動かしたいけど、SMTPサーバに届いたメールは捨てたかった。
そんな時の書き方が分からず、shで済ましてしまったのが悩み。

当初は、 **withDockerContainer** を使おうと思ってたんだけど、これは指定したコンテナ内でジョブを動かす時用なので、
今回の用途とちょっと違う。

こんな書き方で一応動いているけど、他に良い書き方はないだろうか？？？
そもそもDockerの理解が薄い中なのが、さらに悩みを深くしている気はしてる。

```groovy
stage("hoge") {
  environment {
    containerName = "smtp4jenkins"
  }
  steps {
    sh script: "docker rm ${containerName}", returnStatus: true
    sh "docker run -d -p 1080:1080 -p 25:1025 --name ${containerName} pocari/mailcatcher"
    // ここで何かやる
    sh "docker stop ${containerName}"
  }
}
```

---

このDeclarative Pipeline周りは、公式のドキュメントが結構充実しているので、それらを参照しながら書くと効率良かった。
しばらくは、これを使って楽しくJenkinsおじさんするぞ。

- [Declarative Pipelineの構文](https://jenkins.io/doc/book/pipeline/syntax/)
- [プラグインリファレンス](https://jenkins.io/doc/pipeline/steps/)