Jenkins + plenv で、ブランチ毎のテスト実行環境を構築する


# 概要

使用しているJenkinsのバージョンは1.559。

以下、やりたいこととどのような設定が必要かの概要。

■ブランチ毎にテストしたい
-> Jenkinsでパラメータ付きビルドの設定をする。
-> パラメータでブランチ名を受け取り、テスト実行時に処理を分岐させる。

■各ブランチで違うPerlを使したい
-> plenvで各ブランチ用のPerlをインストールする。
-> ブランチ毎にディレクトリを作成し、「plenv local」でブランチ毎のPerlを指定する。

■gitでpushしたタイミングでテストしたい
-> JenkinsのAPI経由からビルドを実行できるように設定する。
-> gitのhookでJenkinsのAPIを叩く。


# Javaのインストール

```shell
$ sudo yum install java-1.6.0-openjdk
$ sudo yum install java-1.6.0-openjdk-devel
```

# Jenkinsのインストール

以下のリンクを参考にしてインストール。
http://pkg.jenkins-ci.org/redhat/

```shell
$ sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
$ sudo rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key
$ sudo yum install jenkins
```

# Jenkinsの起動と起動設定

以下のコマンドでJenkinsを起動。

```shell
$ sudo /etc/init.d/jenkins start
```

以下のコマンドでJenkinsを起動設定する。

```shell
$ sudo chkconfig jenkins on
```


# jenkinsアカウントでログインできるようにする

以下のコマンドで、
/var/lib/jenkinsをjenkinsアカウントのホームディレクトリにする。

```shell
sudo usermod -d /var/lib/jenkins -s /bin/bash jenkins
```

必要ならパスワードも設定する。
root権限からログインするようにしているので今回は設定しなかった。

# Jenkins用のSSHキーを設定

SSHでリモートのgitリポジトリにアクセスする必要があるため、
Jenkins用のSSHキーを設定する。

```shell
$ cd /var/lib/jenkins
$ sudo -u jenkins ssh-keygen
$ sudo -u jenkins vi .ssh/config
$ sudo -u jenkins chmod 600 .ssh/config
```


# gitプラグインをインストール

http://[ドメイン]:8080/ にアクセスし、

[Jenkinsの管理] -> [プラグインの管理] -> [利用可能タブ] -> [git Plugin]

を選択して、インストールする。


# plenvのインストール

以下の手順でjenkinsアカウントになる。

```shell
$ sudo bash -
# su - jenkins
```

以下のページなどを参考にしてplenvをインストールする。
http://qiita.com/uchiko/items/127b91001b45ad0312f0


# テスト実行ディレクトリを作成

ブランチ毎にcloneしたり、テストを実行したりする作業ディレクトリを作る。

```shell
$ cd /var/lib/jenkins
$ mkdir -p .work/myapp/
```

# 新規ジョブ作成

http://[ドメイン]:8080/ にアクセスして、

[新規ジョブ作成]を選択し、
「ジョブ名」を設定し、
「フリースタイル・プロジェクトのビルド」を選択し、
OKボタンを押す。

# ジョブの設定

http://[ドメイン]:8080/ にアクセスして、ジョブ名を選択。

左メニューの「設定」を選択し、以下の項目を設定する。

## ビルドのパラメータ化

ブランチ名を受け取るため、パラメータを作成する。
以下のように「branch_name」を作成する。

![スクリーンショット 2014-05-19 21.42.07.png](https://qiita-image-store.s3.amazonaws.com/0/2278/58aa64d2-d8a7-a815-3707-3a69d06a6245.png "スクリーンショット 2014-05-19 21.42.07.png")


## 「ソースコード管理」の設定

プラグインが無事にインストールされていれば、
「ソースコード管理」に"Git"が選択できるようになっているので、
選択してリモートリポジトリへのパスを設定する。

![スクリーンショット 2014-05-19 21.44.19.png](https://qiita-image-store.s3.amazonaws.com/0/2278/923ffb9c-ed86-60c2-543a-1f6eced740fc.png "スクリーンショット 2014-05-19 21.44.19.png")

## 「ビルド・トリガ」の設定

後に設定するAPIで使用する認証トークンを設定する。

![スクリーンショット 2014-05-19 22.54.24.png](https://qiita-image-store.s3.amazonaws.com/0/2278/411e0fd6-6b41-9756-9989-215f9d37e276.png "スクリーンショット 2014-05-19 22.54.24.png")


「リモートからビルド」という項目がない場合は、
[Jenkinsの管理] -> [グローバルセキュリティの設定]を行うと、項目が出現した。

後述する通り、結局はこの認証トークンを用いなくても実行できた。



## 「ビルド」の設定

「ビルド手順の追加」から「シェルの実行」を選択する。
テキストエリアが表示されるので、
以下の様なシェルスクリプトを記述する。

```shell:test.sh
PERL_VERSION="5.16.3"
HOME=/var/lib/jenkins
SHELL=/bin/bash
WORKDIR=/var/lib/jenkins/.work/myapp/$branch_name
BNAME=`echo $branch_name | sed -e "s/\//_/g"`
RESULT=$HOME/jobs/myapp/workspace/result-$BNAME.xml
PERL_NAME="$PERL_VERSION.$BNAME"
_BRANCH_NAME="for_test_$BNAME"

. $HOME/.bash_profile

# 作業領域存在チェック
if [ ! -d $WORKDIR ]; then
    mkdir -p $WORKDIR
fi

cd $WORKDIR

# git cloneしているか
if [ ! -d .git ]; then
    git clone ssh://xxx.xxx.xxx.xxx/path/to/myapp.git .
if

# ソースを取得
git fetch
git checkout master
git branch -D $_BRANCH_NAME || true
git checkout $branch_name -b $_BRANCH_NAME

# Perlの切替
plenv local system
EXISTS_PERL=''
IFS=$'\n'
for v in `plenv versions`; do
    v=`echo $v | sed -e "s/[ *\n]//g"`
    echo $v
    if [ "$PERL_NAME" = $v ]; then
        EXISTS_PERL="1"
        break
    fi
done
if [ "$EXISTS_PERL" = "" ]; then
    plenv install 5.16.3 --as $PERL_NAME
fi
plenv local $PERL_NAME
plenv install-cpanm

# モジュールインストール
cpanm --installdeps .
cpanm TAP::Formatter::JUnit

# テスト実行
prove -lr --formatter=TAP::Formatter::JUnit t/ > $RESULT || RET=$?

# テストファイル置換(subtestに日本語が入っていると文字化けるため)
perl -i -ple 's/\[\\x([a-f0-9]{2})\]/pack("H*", $1)/egx' $RESULT

# 後処理
git checkout master
git branch -D $_BRANCH_NAME

# テスト結果を返す
exit $RET
```

![スクリーンショット 2014-05-19 22.09.45.png](https://qiita-image-store.s3.amazonaws.com/0/2278/8cb343e0-c3b1-fc53-63cd-5d1665af21e8.png "スクリーンショット 2014-05-19 22.09.45.png")


## 「ビルド後の処理」を設定

「JUnitテスト結果の集計」で「テスト結果XML」のパスを指定する。
ここで指定するパスは、
「/var/lib/jenkins/jobs/myapp/workspace」のディレクトリからの相対パスで指定する。
上記のスクリプトでは、このディレクトリ直下に置くようにしているので、
以下のように設定する。

![スクリーンショット 2014-05-19 21.55.49.png](https://qiita-image-store.s3.amazonaws.com/0/2278/c223707e-7a0e-437f-8c52-0aca6819f3f3.png "スクリーンショット 2014-05-19 21.55.49.png")

# gitのhookを設定

bareリポジトリのあるgitサーバで、
以下のコマンドで、push時に実行するスクリプトファイルを開く。

```shell
$ cd /path/to/myapp.git/hooks
$ mv post-update.sample post-update
$ chmod 755 post-update
$ vi post-update
```

開いたら以下の様なスクリプトを記述する。

```shell:post-update
#!/bin/sh

# pushされたブランチ名を取得
BRANCH=$(git rev-parse --symbolic --abbrev-ref $1)

# jenkinsのAPIを叩く
curl http://[domain]:8080/job/myapp/build -F json='{"parameter": [{"name":"branch_name", "value":"$BRANCH"}]}'
```

先述したとおり、認証トークンを設定しなくとも実行ができた。
これについては、Jankinsのバージョンによって違うのだろうか？


以上で、構築できた。
実際の環境は、
gitサーバがグローバル、Jenkinsのサーバがローカルにそれぞれあって、
色々とごにょごにょとしているものを省いた設定にしているので、
動作確認はあまりとれていない。