開発者（個人）のためのJenkins - Git Plugin編

# はじめに
「開発者（個人）のための」としているのは、別に自分でやっても良いんだけど Jenkins に任せられるなら任せたい、くらいのモチベーションを表現したつもりです。

# 環境
* Ubuntu 14.04 LTS
* Jenkins 1.573
    * Bootstrap になって雰囲気が変わりましたね

# 初期設定
## Jenkins  初期設定
### Plugin のインストール

* [Git Plugin](https://wiki.jenkins-ci.org/display/JENKINS/Git+Plugin)

依存しているPluginも自動的にインストールされます。

Git Parameter Plugin は、ビルド時に Extended Choice Parameter plugin の Single Select ようなパラメータ形式で、リビジョンやタグを選択できるプラグインです。

## Git 初期設定
### Git Install

Git がインストールされていないなら、apt や yum でインストールしておいて良いでしょう。

一応、Jenkins にインストールして貰うことも可能です。
この場合、使用する Git のバージョンを自由に選べるので、最新版を使うこともできるのですが、sudo 権限が必要です。

![Jenkins-Git-Install.png](https://qiita-image-store.s3.amazonaws.com/0/27201/c27ff84d-6b4a-cd84-f422-f1fdf3317616.png)

とはいえ、Git に必要な native library もろもろをインストールするためにも、yum や apt でインストールしておいた無難で楽です。

tar.gz を展開してパスを通すだけで済むなら、Jenkins が勝手にやってくれるのですが、ソースコードからコンパイルする用の tar.gz しか見つからず...

### Credential 設定

Jenkins は認証に関する情報をGUI上で設定できます。

[Credential Plugin](https://wiki.jenkins-ci.org/display/JENKINS/Credentials+Plugin)

設定できる情報

* User/Password
* SSH鍵
* 証明書

Scope に Global と System とありますが、
System で設定した場合、ジョブの中で使用できません。
Git Pull/Push などで使用する認証は、Global で作成しましょう。

![Jenkins-Credential-Setting.png](https://qiita-image-store.s3.amazonaws.com/0/27201/5152483d-32c7-e4ea-f245-8df207804956.png)

もっとも、github から checkout するだけなら認証は必要ありません。

# ブランチの設定
## あらゆるブランチを対象とする

Branch Specifier を空白にしておけば、全ブランチが checkout の対象となります。
Polling と組み合わせれば、あらゆる commit に対して処理を実行できますね。

## 特定のブランチを対象とする

Branch Specifier に「master」などと書けば済みますが、パラメータを使っておくと、後で違うブランチをちょっと試したい時に便利です。

![Jenkins-Git-Specific-Branch-Param.png](https://qiita-image-store.s3.amazonaws.com/0/27201/f63852dd-7d5b-2a29-f781-4e86b2c19f02.png)

![Jenkins-Git-Specific-Branch-Setting.png](https://qiita-image-store.s3.amazonaws.com/0/27201/d0fbcf1f-4407-574e-e139-4486c0178df6.png)

↓のように、develop ブランチを試したい時にはそう書いてしまえばよいです。

![Jenkins-Git-Specific-Branch-Overwrite.png](https://qiita-image-store.s3.amazonaws.com/0/27201/4373c4f9-a693-e28c-d113-512844f5500f.png)

Branch Specifier は、Tag や Revision でも指定できます。

ちなみに、変数名を GIT_BRANCH としてしまうと、Git Plugin が生成する環境変数と被るので、避けた方が良いでしょう。

## commit があれば自動的にビルドする

手っ取り早いのは Polling です。
最近の Jenkins は、Polling の次実行予想時刻を教えてくれます。
cron 記法がよく分からなくても確かめながら設定できますね。

![Jenkins-Git-Polling.png](https://qiita-image-store.s3.amazonaws.com/0/27201/52cbe57b-cf67-a5c4-34dc-8cd8a17c80db.png)

ちなみに、本当は commit した瞬間にビルドされて欲しいのですが、このままでは、最短でも指定した間隔ごとにしかビルドされません。↑の場合は15分です。
とはいえ、そう頻繁にビルドされてもいちいち Jenkins チェックするの面倒だしなぁ、と個人的に思っているのでこれで良しとしています。
Polling しているジョブが増えて負荷になるようだったら考えます。

なお、hook や api を使って対処している先人たちが大勢いらっしゃいます。

# push 前にビルドしたい

Repository URL に指定するのは、要するに、git clone できれば何でも良いので、ファイルパスを指定してしまう手があります。

![Jenkins-Git-Local-Path.png](https://qiita-image-store.s3.amazonaws.com/0/27201/72b5a209-cbd6-e060-ce4c-e0cb34624b81.png)

こうすれば、リモートに Push せずともビルドして色々試せます。

# commit 前にビルドしたい

commit 前にビルドしたい場合もあるでしょう。

カスタムワークスペースを使うと意図したことができるかもしれません。

![Jenkins-Custom-ws.png](https://qiita-image-store.s3.amazonaws.com/0/27201/fb3ebb82-e1e1-f3ff-15df-4be141ee5d7c.png)

この場合 jenkins がアクセスできるディレクトリでなければなりませんが、そのためにわざわざ権限の設定をせずとも、開発で使用しているアカウント or マシンに slave を作ってしまえばなんとでもなります。

# commit してもらう

ジョブの中で、commit をしてもらう手もあります。
↑の commit 前にビルドしたい、と組み合わせて、commit の自動化ができます。
私は、jenkins の設定ファイルの backup をする際に活用しています。

git commit 時に、「あなたはだあれ？」と聞かれたら
　　＃ Please tell me who you are. のこと
Custom user name/e-mail address を設定します。
Jenkins の設定で、グローバルな user name/e-mail address を設定できるので、ジョブが複数あって面倒ならこちらを。

# merge を試して欲しい

Travis CI が、Pull Request を検知して勝手にマージを試してくれるのと似たようなイメージです。

Git Plugin の Merge before build が手っ取り早いです。

![Jenkins-Git-Before-Merge.png](https://qiita-image-store.s3.amazonaws.com/0/27201/f475f66d-2d8b-df3f-1a6a-7cda8f22fcbf.png)

その名の通り、ビルド前（git checkout 直後）に Merge を実行します。
Name of repository には通常、origin を指定すれば良いでしょう。
Repository name は、Repositories の高度な設定で自由に指定できますが、特に指定しなければ origin となります。Jenkins ビルド結果の、コンソール出力 や Get Build Data で確認できるでしょう。

ここでの merge は、次のようなコマンドを実行しているようです。

```bash
 > git rev-parse origin/master^{commit} # timeout=10
 > git config core.sparsecheckout # timeout=10
 > git checkout -f origin/master
 > git merge 7357f49924b765627ccd36e0362081875933bdad # timeout=10
 > git config core.sparsecheckout # timeout=10
 > git checkout -f 7357f49924b765627ccd36e0362081875933bdad
```

conflict が発生するような merge は失敗します。
merge が成功しない限り、ビルド処理は実行されません。

後述する、Git publisher と組み合わせるといい感じです。

例えば ci とか jenkins というブランチを用意しておくとします。
このブランチは、時間のかかるUTや、コードの静的解析、外部サービスの連携などに使用しているとします。
そこで、Merge before build を使って自動的に merge を試し、
時間の掛かる処理を行い、
うまくいったら Git publisher で push 、
とすれば、常に ci ブランチには何らかの処理がなされたファイルが push されるようになります。

よりTravis CIっぽい、Github Pull Request との連携は、[GitHub pull request builder plugin](https://wiki.jenkins-ci.org/display/JENKINS/GitHub+pull+request+builder+plugin) でできるようです。まだ私は試したことが無いので割愛します。個人ではあまり使わないですしね。

代わりに参考になる先人方のページを貼っておきます。

http://d.hatena.ne.jp/oovu70/20130118/p1
http://please-sleep.cou929.nu/jenkins-github-pull-request-builder-plugin.html

# push を代わりにして欲しい

先にちらりと紹介しましたが、Git publisher が便利です。
もちろん、シェルの実行で git push としても良いですが、Git publisher を使えば、先の「Credential 設定」で作成した認証を使えます。

![Jenkins-Git-Publisher-Setting.png](https://qiita-image-store.s3.amazonaws.com/0/27201/ca0c4318-94db-8948-5f98-d9b1a727d742.png)

Push Only If Build Succeeds は選択しておくべきです。
ビルドに失敗したものを Push する意味はありません。

Merge Results は、あまり効果を理解していません...
つけてもつけなくても、特に変わりがなかったです。

## Tag

![Jenkins-Git-Publisher-Setting-Tag.png](https://qiita-image-store.s3.amazonaws.com/0/27201/df2f0f62-6417-b5e6-3d07-2883598299da.png)

Create new tag をチェックしないと、Tagを作ってくれません。
また、すでに存在する Tag 名を指定すると、エラーになります。
Update new tag をチェックすれば更新してくれそうですが、私の環境ではうまく動作しませんでした。

(2015/11/03 追記)
@mechamogera さんの[コメント](http://qiita.com/yasuhiroki/items/61a2be613fc7dcfc8682#comment-f2f56d3b6c442b18014f) から、 Force Push をチェックすれば、Update new tag が成功することが分かりました！

![Jenkins-Git-Publisher-Setting-Tag-force.png](https://qiita-image-store.s3.amazonaws.com/0/27201/20f9c69d-1e8c-1d9c-8308-17a885923676.png)

`git push -f` の `-f` に該当する設定をしておく必要があったのですね。

### 失敗時のログ

```
 > git tag -a -f -m Jenkins Git plugin tagging with NewTag NewTag # timeout=10
Pushing tag NewTag to repo origin
 > git push /var/lib/jenkins/GitJenkinsSample NewTag
ERROR: Failed to push tag NewTag to origin
hudson.plugins.git.GitException: Command "git push /var/lib/jenkins/GitJenkinsSample NewTag" returned status code 1:
stdout: 
stderr: To /var/lib/jenkins/GitJenkinsSample
 ! [rejected]        NewTag -> NewTag (already exists)
error: failed to push some refs to '/var/lib/jenkins/GitJenkinsSample'
hint: Updates were rejected because the tag already exists in the remote.
(後略)
```

### 成功時のログ

```
> git tag -a -f -m Jenkins Git plugin tagging with NewTag NewTag # timeout=10
Pushing tag NewTag to repo origin
 > git push /var/lib/jenkins/GitJenkinsSample NewTag -f
Pushing HEAD to branch master at repo origin
```

## Branch

![Jenkins-Git-Publisher-Setting-Branch.png](https://qiita-image-store.s3.amazonaws.com/0/27201/16e8f39b-1008-dbb3-f368-b97b559fa436.png)

リモートリポジトリに存在しないBranchにはPushできません。

## Notes

コミットにコメントを付ける機能ですが、使用シーンがよく分からなかったので飛ばします。
Jenkins のコンソール出力やパラメータを Notes に記入して Git で管理するのは良いアイデアかもしれません。