ヒトリ歩き

愚痴とかいろいろ書きます

Jenkinsで共有ライブラリを作成してみる

プロジェクトを運用していると複数のバージョンに複数のJenkinsfileが存在するということはないでしょうか?
私が所属するプロジェクトでも、Jenkinsfileが複数あるのですが、処理自体は共通化できるようなものがほとんどです。
同じような処理ばかりになると、メンテナンスがやりにくくなるので、共有化できないか調べてみました。
すると、共有ライブラリというものをJenkinsに設定できるようで、試してみました。

jenkins.io

ディレクトリ構成

共有ライブラリのソースコードをSCMで管理し、Jenkinsに設定することでSCMからソースをチェックアウトして使用することが可能です。
共有ライブラリのディレクトリ構成は以下のようなイメージです。

(root)
+- src                     # Groovy source files
|   +- org
|       +- foo
|           +- Bar.groovy  # for org.foo.Bar class
+- vars
|   +- foo.groovy          # for global 'foo' variable
+- resources               # resource files (external libraries only)
|   +- org
|       +- foo
|           +- bar.json    # static helper data for org.foo.Bar

重要なのは、src、vars、resourcesフォルダになります。

ディレクト 概要
src パイプライン実行時にクラスパスに設定される。クラスを実装する場合、srcフォルダに配置する必要があります
vars パイプラインで変数として扱うことができる。vars/log.groovyというファイルにdef test(message)という関数を定義した場合に、log.test "メッセージ" というような使い方が可能です。
resources groovyファイルではないファイル(jsonファイルなど)を配置する。libraryResourceを使ってロードします。

srcフォルダの共有ライブラリを使ったパターン

Utilltiesクラスを定義して、クラスをJenkinsfileから呼び出すパターンを実装してみました。
オブジェクトを生成する際に、パラメータを渡しておけばオブジェクトでデータを保持でき、メソッド内でも使用可能です。

src/org/foo/Utillities.groovy

package org.foo

class Utilities implements Serializable {
  def steps
  def version
  Utilities(steps, version) {
    this.steps = steps
    this.version = version
  }

  def checkout() {
    this.steps.stage("checkout") {
      this.steps.sh "ls -l"
    }
  }

  def compile() {
    this.steps.stage("compile") {
      this.steps.echo "compile " +  version
    }
  }

  def deploy() {
    this.steps.stage("deploy") {
      this.steps.echo "deploy"
    }
  }

  def test() {
    this.steps.stage("test") {
      this.steps.echo "test"
    }
  }
}

Jenkinsfile

@Library('my-shared-library') import org.file.Utilities
def util = new Utilities(this, "1.0");
node() {
    util.checkout()
    util.compile()
    util.deploy()
    util.test()
}

varsフォルダにおいた共有ライブラリを使ったパターン

クラスとは異なり、関数だけ定義することになります。
こちらはこちらでシンプルではあります。
srcフォルダでは、import文を使ってましたが、varsフォルダのスクリプトを使用する場合は、_ を使います。

var/utilites.groovy

def checkout() {
  stage("checkout") {
    echo "checkout"
  }
}

def compile() {
  stage("compile") {
    echo "compile"
  }
}

def deploy() {
  stage("deploy") {
    echo "deploy"
  }
}
@Library('my-shared-library') _

node() {
    utilites.checkout()
    utilites.compile()
    utilites.deploy()
}

最後に

共有ライブラリを初めて試しましたが、スムーズには設定できませんでした。
特に、Jenkinsfileから共有ライブラリの関数やクラスを呼び出すのに手間取ったので、共有ライブラリを作成する際は、簡単なプログラムを共有ライブラリ化して試してみるのをオススメします。

また、共有ライブラリ化することで、Jenkinsfileの定義も小さくなり、クローンコードも無くなり、保守がやりやすくなるので設定の手間よりメリットの方が大きいと思います。

時間を見つけて、プロジェクトのJenkinsfileを共有ライブラリ化しようと思います。