2013-08-30

Jenkinsのプラグインを作ってみる。(Redmine Build Notifier Plugin)


今回は、夏休みの自由研究?で、Jenkinsプラグインの作成をしてみたお話です。
すでに似たようなプラグイン、高機能なプラグインがありますが、ご興味を持っていただけたら、ソース/バイナリを評価いただけると幸いです。

ちょっと長いので、見出しのみ先に書かせていただきます。
  • プラグイン作成の背景
  • IntelliJさん、出番です!
  • GitHubに上げてみました!
  • DEV@cloudを使ってみました!
  • 今回のまとめ

プラグイン作成の背景


ただいまお仕事にて、DBのちょっとしたデータ変換作業をしています。

ただし、一気に作業するのではなくて、対象を決めて『今日はこの範囲の作業するよー』という感じで処理しています。また、作業に関しては、Redmineにチケットを作成し、『この範囲を処理、作業者はxxx、終了はxx時、変換結果はxxx』という情報を記録しています。

この変換処理ですが、ある程度定型化できるため、Jenkinsのジョブとして作成しています。たとえば、こんな感じです。

  • 切り戻しのためのデータのバックアップ
  • テスト(テストサーバ&ロールバックを使った、ある意味Dry Run) 用の処理
  • 実行記録の書き出し
  • 作業範囲を切り替えできるように、ジョブのパラメータ化
  • ビルドパラメータ-> シェル -> ストアドプロシージャの変数という形で処理
  • バックアップ用データファイル、変換前後の差分レポートを成果物として保存
この方法はなかなか上手く行っており、チケットとビルドの間には非常に関連性が高いのですが、『リポジトリにソースをコミットしたら処理が走る』タイプではありません。
このため、Jenkins Redmine Plugin や、Redmine Hudson Plugin を利用してのチケットとジョブの自動関連付けができず、数回ジョブのURLと結果をRedmineのチケットに手で貼付けて、記録を残していました

でも、人がWebから入力するので、間違いもあったりしますし、証跡とするにもちょっと説得力が弱いです。

No Ticket, No Commit. / No Ticket, No Work. ならぬ、No Ticket, No Build. な利用シーンが多いので、できれば自動で連携して欲しいところ...。

なんとか自動で結果をRedmine側にリンクさせたい、できればジョブの実行者や実行時間、成果物へのリンクはチケットに勝手に貼付けたい...という思いは前々からあったので、最初はシェルからRedmineのREST APIを叩いてPOSTしようかと考えました。

ですが、この方法だと、別なジョブには応用しにくくなります。ジョブのcopyをすれば良いのですが、Windows Slave上で動かす場合は利用できません.....(><)

ということで、Jenkinsのプラグインとして作れないか...?と考えた次第です。

IntelliJさん、出番です!


とは言え、私にとってはあこがれのJenkinsのプラグイン...。
ずっと前から、いつか作ってみたいなと思っていましたが、そんなスキルはありません。

そうこうしているうちに、Jenkinsの活用やプラグイン作成されたみなさんの情報が増えてきて、『もしかしたら作れる?』という淡い期待を抱くようになりました。

こちらを参考にやってみると、プラグインのひな形作成は、思った以上に簡単....。
わたしのやったことなんて、settings.xml と pom.xmlの作成くらいじゃなかろうか、という感じです....。

その上で、幸運にもIntelliJを使える機会がやってきたので、何はともあれMaven Projectとしてインポートし、サンプルのHello Worldを修正していくことから始めました。

やっとIntelliJらしい使い方が!

コマンドライン & Viでの作業と違って、Jenkins本体のソースも全部参照できる& デバッグできるので、Javaもフレームワークもよくわかっていないわたしでも、変数を頼りになんとか『この辺り変えればいいのかも』という見当を付けることができました。

あとは、近そうな動作をするプラグインのソースを眺めて、(恥ずかしながら)コピペと修正を実施。

一番問題のRedmineにPOSTをする処理は、自分でHTTPの処理を実装しないといけないかな〜と悩んでいたところ、Redmine Java APIなるものを発見し、これに乗っかることにしました(^^;

#ちなみに、すでにあるJenkins Redmine Pluginも、だいぶ機能がアップしているのですが、上記のRedmine Java APIを利用していました。


GitHubに上げてみました!

まさに皆さんのおかげで、それなりに使えそうな形になってきたので、GitHubにソースをアップ。わたしにとっては初Javaなリポジトリです。

とは言え、やっぱりこうした類いはどんな使い方をするのかイメージしてもらうのが重要。Wikiにもキャプチャをアップ&怪しい英語で説明文を付けていきました。
(本当に、名前からして『ズバリ』な機能を持っているなら、説明は少なくて済むのでしょうけれど...)

Post Build Taskに追加されました!

ビルド側からRedmineチケットへのリンクが出来ました!
Redmineへも簡単な結果をPOSTできました!


ここで考えたのが、『果たして自分のローカルの環境、IntelliJ以外でビルドできるのか?』ということでした。Redmineのプラグインについては、r-labsの方のご好意で、Jenkinsを使ってのテストをさせていただいているのですが、今回はJavaなので、全く別の環境のほうが良い気がしました。

かつ、奥様のお財布にも優しいビルド環境が欲しい...。

そこで、DEV@cloud (CloudBeesのJenkins)を利用してみることにしました。

DEV@cloudを使ってみました!

実は、1年くらい前にアカウントを作成し、Jenkinsのサービスは利用登録をしていたのですが、適当なビルドが思いつかず、活用できていませんでした....。

久しぶりにログインすると、サービスが増えているし、UIもドキュメントもだいぶ変わっていました。わたし専用のJenkinsは、1年の眠りから覚めるのにちょっとの時間を要しましたが、問題なく起動。

Maven Projectとしてジョブを作成し、GitHubのリポジトリの指定と、mvn clean install を指定するといった、ほんの少しの作業で、いよいよビルド実行...。

ビルドできましたー! on DEV@cloud

WARNINGが出たものの、めでたく *.hpi 形式のバイナリが作成されました!

なお、CloudBeesのサービスでは、GitリポジトリやMaven リポジトリも提供されているので、ビルドの成果物をそちらにアップできるようになっていました。

Maven Repositoryの設定画面。アクセス制限が設定できます。

ブラウザ & DAVからアクセス可能になっています。
さて、Jenkins CI利用のフリープランは、300分/月となっています。気がつかなかったものの、設定のミスとか、DEV@cloud専用のプラグインを試しているうち、50分くらい使っちゃっていました。

300分なんてもしかしてすぐかも....と不安になったのですが、実はCloudBeesの環境を利用した、BuildHiveというサービスがリリースされており、オープンソースならこっちも使えることが分かりました!

今回のまとめ


プライベートではありますが、プラグインリストに自分の作ったものが上がってくると、感無量です。

IntelliJを使った点で良かったことの一つが、日本語のメッセージプロパティファイルの編集がしやすかったことです。このおかげで、ついでに表示も日本語/(怪しい)英語の両方サポートしてしまう気力が出ました。(以前にこの手のファイルをいじってた頃は、native2asiiでの変換をかけないといけなかったのです)

また、UIについては、Jenkinsとして統一感を持ったヘルプの作成がしやすいのにビックリでした。(Jenkinsのヘルプの出し方は気に入っていて、Redmineのプラグイン作成時にもちょっと参考にさせていただいてます)

このあたり、もう少し上手くお伝えできれば良いのですが、ひとまずこの辺で。

2013-08-26

yggdrasilを使ってみました。

6月末のshinagawa Redmine勉強会の際、いろいろお世話になっている楠川さん(@tkusukawa さん)が作られた、yggdrasil というツールについて、直接お話を伺う機会を持つことが出来ました。

それまでは、縁のなさそうなツールかな...という印象だったのですが(すみません....)、勉強会でのスライドを拝見しているうちに、「あ、これはいいかも!」と思うようになりました。
#まだまだChefやらPuppetやらには手が出せていないので、そういうたぐいの感じかと、最初は戸惑っていたのです.....。

さっそく、その場で直接質問をさせていただき、変更を各サーバに反映するというアプローチではなくて、『変更が勝手にされていないか、コミット漏れがないか』をチェックすることに主眼を置いていることが分かりました。

目的が違うことが分かり、『No Ticket, No Work!』というキャッチにも、なるほどと共感するところがありました。

また、運用者にとっては、まだなじみ易いSubversionをリポジトリに使っているということもあり、yggdrasil という言葉は抜きにして、『変更はSubversionを使ってるよ』という説明なら、周囲も理解しやすいはず...。

ということで、丁度いじっていたサーバに入れてみることにしました。

インストール後、単体での利用は、なんとなくイメージ通りだったので、このまま使ってみようと判断。ですが、サーバ/クライアント構成の場合は、しばらくどう設定すればいいのか分かりませんでした...(これもすみません....)

その後数回、楠川さんにtweet経由で質問させていただき、お忙しいところにもお返事をいただけたおかげで、「ああ、こんな感じなんだな」というのも見えてきました。

こんな感じ


理解が間違っていないか、ちょっと心配なので、仕組みを書き出してみます。

併せて、現状試していることを図にしてアップしてみます。



仕組みは下記のような感じになります(勝手な理解かもしれませんが...)


1.  yggdrasil スタンドアロン、もしくはclientは、Subvetsionサーバとのやりとりで、設定ファイルをコミットしたりします。svn add/commitではなく、ygg add/commit という形で、yggdrasilがsvnコマンドをラップする形で更新を重ねていきます。

2. ~/.yggdrasil ディレクトリには、Subversionサーバの情報、Subversionと通信する際のユーザの情報や、yggdrasil をclient / server構成で使う時のserverの設定情報が格納されます。
また、mirror というディレクトリが作られ、ここがシステムの / 配下をミラーしたような、Subversionのワーキングディレクトリとなります。

3. ygg check コマンドで、リポジトリに登録されている情報と、実際に扱っているファイルとの差分をチェックします。差分があればエラーと判断します。

4. client / server 構成の場合は、client側がチェック結果をserverに報告しに行きます。server側も、~/.yggdrasil/result  というフォルダにclientからの報告を格納します。そうして、yggserve result というコマンドを使うと、clientたちの結果に問題が無いかどうかを一度に確認することができます。

楠川さんのおすすめは、clientからのserverへの報告はcronで行い、server上では yggserve result  コマンドをJenkinsを使って処理する、というものでした。

私の環境の場合は、ygg serverに当たるサーバはJenkins masterには利用できなかったので、Jenkins slaveとして設定し、いつも使っているJenkins maseter上で他のジョブと一緒にチェックを行うようにしてみました。

実は、わたしも設定ファイルは所々Subversionに登録してはいたのですが、/etc/... とか、/usr/local/... とか、ディレクトリにばらつきがあり、どうもうまく管理できていませんでした。

yggdrasilのおかげで、そういったパスのばらつきを考慮しなくても、yggdrasilのコマンドが宜しくやってSubversionに登録/変更をチェックしてくれるので、『これは良い感じ!』と思いました:)

若干?ハードルになるのは、rubyが必要だというあたり。

インストール直後でほとんどツールが入っていないOSだとすぐには使えませんが、今回はruby入りのサーバをコピーして複数台をチェックという状況でしたので、すんなり使えています。

なお、しがないバックオフィスのスタッフの身なので、恥ずかしながらコマンドラインで使うruby gemは意識して入れるのが初めてでした。

その上で、ソースも拝見して、『こんなふうに書くんだ〜』と、とっても勉強させていただいております。

ということで、ひきつづき1ユーザとしてお世話になってみようと思います!


2013-08-15

GitHub EnterpriseのリポジトリをSVNプロトコルでRedmineから直に参照....。

長いタイトルですみません…。
どなたかすでに試していらっしゃるかと思うのですが、実際やってみて「へぇ~」という思いでしたので、久しぶりにPOSTしてみます。

はじめに:Redmineで分散SCMが面倒くさい

RedmineとGitリポジトリの連携の場合は、Redmineが参照できるローカルなファイルシステム上に、Bare(もしくはmirror)リポジトリをCloneしておいて、そこを示すようにしないといけません。(Subversionの場合は、httpでアクセス可能であれば、ローカルにリポジトリを持つ必要はありません)

せっかくhttp的には参照可能なところにGitのリポジトリがあっても、なんだか面倒...。

いろいろ試し、Gitに変更が入ったら、ミラーのリポジトリにpushするようServiceHookを使うことで、若干のタイムラグはあるもののRedmine側のリポジトリブラウザに反映させることはできました。

その上で...。

たまたま誰かがRetweetして下さった、下記のTweetを発見。

GitHubならSVNプロトコルが使えるよ

github-tweet

『おおっ?』と思ったところ、直にSVNプロトコルでお話できるらしいではありませんか!

早速コマンドラインで試すと、問題なく svn coできます。Git上のmasterはtrunkに相当する感じです。逆に、ローカルのsvnのリポジトリを、GitHubの空っぽのリポジトリにpushすると、trunk -> master に割り振りとなりました。

そうこうしているうちに、『もしかして、RedmineからSubversionリポジトリとして参照できちゃう?』と考えました(^^;

RedmineからSubversionとしてアクセスさせてみた

で、やってみました。

github-svn

....問題ございません、できました....。

上記はgitでコツコツいじっているリポジトリですが、Subversionとしてアクセスすると、trunk, branches, tags というブランチに変換されて連携しています。タグ、ブランチも、それぞれ tags, branches以下で表示されます。

また、リビジョン番号に至っては、律儀にハッシュでなく番号に変化されて表示されますので、『何回コミットしてんの?』というのは意外に分かりやすい!

一方、まっとうな感じでGitリポジトリとして参照させた場合は、下記のような感じです。

github-svn-2

コマンドラインからも確認しよう!

RedmineはSubversionリポジトリのデータを、 svn list --xml というコマンドで取得しています。(subverson_adapter.rb を参照)

コマンドラインで対象のリポジトリを叩くと、XMLでデータが返ってくればバッチリです。

 

$ svn list --xml https://githubのどこかのリポジトリのURL/
 
<?xml version="1.0"?><lists>
<list   path="https://githubのどこかのリポジトリのURL">
<entry   kind="dir">
.............................
</entry>
</list>
</lists>



もしかすると証明書の関係で、下記のようなダイアログが出てくるかもしれませんが、

Error validating server certificate for 'https://github.com:443'

acceptすれば、ちゃんとXMLでデータが取れるようになりました。Redmine からうまく見えてくれないなーという場合も、このエラーで引っかかっている可能性があります。

ぶっちゃけ、ソースの確認だけな らSubversionとして連携させてしまうのもありかも...と思いました。

補足:Bitbucketは?


ちなみに、Bitbucketはどうなんだろう思い、下記のURLも見つけたのですが、コメントの最後のほうにある通り、試しても現在は失敗しちゃうみたいです。