Jenkinsのビルド結果をblink(1)で通知する

注文していたblink(1)が届いたので、早速Jenkinsのビルド結果をチェックして、blink(1)を光らせるスクリプトを書いてみた。

スクリプト

polling_jenkins.py

実行するには、thingmで配布されている"blink1-tool"が必要です。

スクリプトの説明など

JenkinsのRemote access APIを使い、全てのjobの結果をチェックし、1つでもビルド失敗があれば、blink(1)を赤く光らせている。
また、include_jobsとexclued_jobsで特定のjobだけ対象にしたりも出来るようにしてある。

ちなみに、実際に光るとこんな感じです。


ちょっと明かりは弱いです。

blink(1)は簡単に使えますし、XFDに興味ある方は導入してみると良いかも。

msysgitでgit-flowとgit-flow-completionを使う方法

msysgitgit-flowを使おうとして、少しインストールにハマったので、メモ。

環境

  • Windows 7 64bit
  • msysgit 1.8.0(Git-1.8.0-preview20121022.exe)

前提知識

見えないチカラ: A successful Git branching model を翻訳しました

git-flowのインストール

git-flowのインストールにはgetopt.exelibintl3.dllが必要です。
util-linux packageのDownloadからBinariesのZIP、DependenciesのZIPをダウンロードします。
C:\Users\sinsoku\bin\ *1getopt.exelibintl3.dllの2つを入れる。

Git Bashを起動させ、インストール前準備を行う。

sinsoku@PC ~
$ echo "export PATH=\$PATH:~/bin:" >> ~/.bashrc
sinsoku@PC ~
$ source ~/.bashrc

次にgit-flowのコードを取得する。*2

sinsoku@PC ~
$ cd /C
sinsoku@PC /C
$ git clone --recursive git://github.com/nvie/gitflow.git

そして、Windowsコマンドプロンプト管理者として実行で起動*3させ、インストールを実行する。(※ここではGit Bashを使わない)

C:\Windows\system32> cd C:\gitflow
C:\gitflow> contrib\msysgit-install.cmd "C:\Program Files (x86)\Git"

これで、git-flowが使えるようになる。

ちなみに

32bitだと、引数のGitのパスの指定は要らないと思う。

C:\Windows\system32> cd C:\gitflow
C:\gitflow> contrib\msysgit-install.cmd

git-flow-completionをインストールする

git-flowでもコマンドの補完が効くように設定します。
git-flow-completion.bashをダウンロードし、C:\Users\sinsoku\bash_completion.d\ *4に入れる。その後、Git Bashで下記の作業を行う。

sinsoku@PC ~
$ echo "source ~/bash_completion.d/git-flow-completion.bash" >> ~/.bashrc
sinsoku@PC ~
$ source ~/.bashrc

これでgit flowの各コマンドで補完が効くようになります。

.bashrc の中身

この手順でコマンドを実行すると、~/.bashrc の中身が下記のようになるはずです。

export PATH=$PATH:~/bin:
source ~/bash_completion.d/git-flow-completion.bash

*1:存在しない場合、フォルダを新規作成する。sinsokuの部分は自分のユーザ名

*2:git cloneが使えない場合、Githubからzipファイルで落とす方法もあるが、この場合 shFlags がsubmodule になっている点に気をつける

*3:スタートメニュー → すべてのプログラム → アクセサリを開き、コマンドプロンプトの右クリックから

*4:bin\ と同じく、無ければ新規作成する

ECJ (Eclipse Compiler for Java) とjavacでimport文の処理が違う

タイトル通りだけど、「Eclipseだとコンパイルエラーが出ないのに、なぜかGradleだとコンパイルエラーになる」という状況にハマったので、メモ。

サンプルコード

1. 下記のようなシンプルなコードを作成して、helloworld.jarを作成する。

package helloworld.model;

public class HelloWorld {
}

2. 別プロジェクトにhelloworld.jarを追加し、下記のようなコードを作成する。

package sinsoku.app;

import helloworld.*;

public class Client {
}

この状態で、Eclipse上で見ると画像のように特にエラーは出ない。

しかし、javac.exeでコンパイルすると、下記のエラーが出る。

どうもimport文の"helloworld.*"にクラスが一つも無いのが良くないっぽい*1

解決する方法は?

下記のようにimport文を修正する事でコンパイル出来るようになった。

package sinsoku.app;

- import helloworld.*;
+ import helloworld.model.*;

public class Client {
}

別解

政治上の理由*2で、既存のコードを変更出来ない場合はGradleでECJを使う事も出来る。
この方法でもコンパイルが通るようになりました。

*1:Javaの仕様を調べていないので推測ですが・・・

*2:コードの変更に申請が要る、面倒な事になるのでGradleはこっそり使いたい・・・など

JavaのMapを簡単に使えるようにした

追記: これ、ダメだ。。。Foo.map(...).put(...).put(...) だとエラーになる... orz

JavaのMapはリテラルが無いので、Map作るのが面倒!

Map map = new HashMap();
map.put("java", "('A`)");
map.put("ruby", "(´∀`)");
map.put("python", "(`・ω・´)");

mapを扱う機会が多かったので、簡単に作れる方法をググってみたら、Javaにおける疑似Map生成リテラル({ key => value }ばりに簡単にMapを生成する方法) - 矢野勉のはてな日記 とかが見つかった。

引用すると

// Example usage :
import static Literals.map;

Map<String,Integer> example = map("hello",1).map("world",2).map("!",3);

みたいな書き方が出来るらしい。これは良さそう!

だが・・・

諸事情により、クラスを簡単に作成できない環境だったので、
匿名クラスを使ってやってみた。

class Foo {
    public static Map map(Object key, Object value) {
        return new HashMap() {
            public Map put(Object key, Object value) {
                super.put(key, value);
                return this;
            }
        }.put(key, value);
    }
}

これならメソッドを1つ作るだけ*1

Map example = (Map)Foo.map("foo", "var").put("hoo", "piyo");

とかの使い方が出来る!

ここまで書いてはみたけど・・・

普通の開発環境ならリンク先のMapBuilderとかを作った方が良い。

*1:Fooクラスは元々あった適当なクラス

git-svnでsvnリポジトリの変更を自動で取得する

久しぶりにsvnを触ったら、logの表示やupdateがあまりに遅い。
git-svnを使っても、やっぱりupdateは遅い。

という訳で

勝手にgit svn fetchするようにbat/shを書いてみた。

バッチファイル・スクリプト

標準出力で出してる文字は下記の意味にしてる。

  • - : 待機中
  • > : git-svnのfetch 処理中
  • . : git-svnのfetch 終了

auto_svn_update.bat

@echo off

set LIMIT=600
set SLEEP_EXE="%ProgramFiles(x86)%\Git\bin\sleep.exe"
set GIT_EXE="%ProgramFiles(x86)%\Git\bin\git.exe"

%GIT_EXE% svn fetch
:LOOP
  set /p x="-" < nul
  %SLEEP_EXE% %LIMIT%

  set /p x=">" < nul
  %GIT_EXE% svn fetch
  set /p x="." < nul
goto :LOOP

exit /b 0


auto_svn_update.sh

#!/bin/sh

limit=600

git svn fetch
while :
do
  printf "-"
  sleep $limit

  printf ">"
  git svn fetch
  printf "."
done

後はrebaseするなり、resetするなり、自由自在。

Ubuntu 12.04 にGradle 1.2 をインストールする

備忘録。

参考にしたページ

インストール手順

Gradle のページからファイルをダウンロードする。

$ wget http://services.gradle.org/distributions/gradle-1.2-all.zip

解凍する。

$ sudo unzip gradle-1.2-all.zip -d /opt/gradle/

シンボリックリンクを作る。

$ sudo ln -sf /opt/gradle/gradle-1.2/bin/gradle /usr/bin/

動作確認

$ gradle -v

------------------------------------------------------------
Gradle 1.2
------------------------------------------------------------

Gradle build time: 2012年9月12日 10時46分02秒 UTC
Groovy: 1.8.6
Ant: Apache Ant(TM) version 1.8.4 compiled on May 22 2012
Ivy: 2.2.0
JVM: 1.7.0_05 (Oracle Corporation 23.1-b03)
OS: Linux 3.2.0-32-generic amd64

私はRSpecでテストをこんな感じで書いてる

私がRSpec使ってテスト書く時はこんな感じで書いてるよ〜ってのを書いてみた。*1

テストを書く順番について

TDDでコードを書く場合、先にテストを書く事になります。
そして、そのテストを書く順番ですが、私は下記のような順番で書くように意識しています。

  1. 設計する
  2. describe を書く
  3. itを書く
  4. subjectを明確にする
  5. before(context)を明確にする

その他に、気をつけている点はこんな感じ

  • 別のメソッド呼ぶ時は基本的にstubなどで潰す
  • contextは「〜の場合」、it は「〜であること」になるようにする

一つずつ、詳細を書きます。

設計する

テストを書き始める前に、まず実装しようとしてるクラス、メソッドを簡単に設計します。
少なくとも、「クラス名」「クラスメソッド or インスタンスメソッド」「メソッド名」「メソッドの戻り値」ぐらいは決めます。

describe を書く

設計したクラス、メソッド名に合わせてテストを書き始めます。
インスタンスメソッドの場合は下記のように "#〜" で書きます。クラスメソッドの場合は".〜"になるようにしてます。

+# -*- coding: utf-8 -*-
+require_relative 'user'
+
+describe User do
+  describe "#admin?" do
+  end
+end

詳細は後述しますが、これはrspecの実行結果で「それっぽい」出力にするため。

it を書く

まず、「◯◯が管理者であること」のように"結果"から考える。
で、それをspecに書く。

# -*- coding: utf-8 -*-
require_relative 'user'

describe User do
  describe "#admin?" do
+    it { should be_admin }
  end
end

subject を明確にする

次に、「◯◯」の部分を明確にする。
「管理者のユーザ」として、specに書いてみる。

# -*- coding: utf-8 -*-
require_relative 'user'

describe User do
  describe "#admin?" do
+    subject { @admin_user }
    it { should be_admin }
  end
end

before(context) を明確にする

subject で指定している @admin_user をbefore で用意する。

# -*- coding: utf-8 -*-
require_relative 'user'

describe User do
  describe "#admin?" do
+    before { @admin_user = User.new(role: 'admin') }
+
    subject { @admin_user }
    it { should be_admin }
  end
end

他のパターンも作成し、context を分ける。
ここで、context の内容が、before と一致するように気をつける。

 require_relative 'user'

describe User do
  describe "#admin?" do
-    before { @admin_user = User.new(role: 'admin') }
+    context "管理者の場合" do
+      before { @admin_user = User.new(role: 'admin') }
+
+      subject { @admin_user }
+      it { should be_admin }
+    end
+
+    context "一般ユーザの場合" do
+      before { @user = User.new(role: nil) }
+
+      subject { @user }
+      it { should_not be_admin }
+    end
 
-    subject { @admin_user }
-    it { should be_admin }
  end
end

別のメソッド呼ぶ時は基本的にstubなどで潰す

例えば「管理者のリンディさんだけシステムを起動できる」という機能を作る必要があり、テストを書く場合、admin? のテストは済んでいるため、stub!で潰します。

# -*- coding: utf-8 -*-
require_relative 'user'

describe User do
  describe "#admin?" do
    context "管理者の場合" do
      before { @admin_user = User.new(role: 'admin') }

      subject { @admin_user }
      it { should be_admin }
    end

    context "一般ユーザの場合" do
      before { @user = User.new(role: nil) }

      subject { @user }
      it { should_not be_admin }
    end
  end
+
+  describe "#runnable_system?" do
+     context "管理者がリンディさんの場合" do
+      before do
+        @lindi = User.new(name: 'Lindi')
+        @lindi.stub!(admin?: true)
+      end
+
+      subject { @lindi }
+      it { should be_runnable_system }
+    end
+  end
end

このようにしておく事で、仮に管理者の判定処理( User#admin? )が「管理者はroleが'admin'、もしくはskillが'SS'」みたいな仕様に変わっても、このテストはfailしなくなります。

contextは「〜の場合」、it は「〜であること」になるようにする

まず始めに、この記事で例として書いていたテストを普通に実行した時の出力を紹介します。

$ rspec user_spec.rb
...

Finished in 0.00216 seconds
3 examples, 0 failures

このままでもrspecは実行出来るのですが、オプションで format を指定すると、次のようになります。

  • f d は --format documentation と同じです。
$ rspec -f d user_spec.rb

User
  #admin?
    管理者の場合
      should be admin
    一般ユーザの場合
      should not be admin
  #runnable_system?
    管理者がリンディさんの場合
      should be runnable system

Finished in 0.00236 seconds
3 examples, 0 failures

こんな感じで「◯◯は、△△の場合、〜〜であること」の形になるように意識します。
例: User#admin?のメソッド は、管理者 の場合、admin であること

  • ◯◯:メソッド名
  • △△:状況(context)
  • 〜〜:結果

まとめ

「私がどう書いているか?」を書いただけなので、このやり方が正しいとかではないです。*2
ただ、「itから書いて〜」という私のような書き方が少し検索しても見当たらなかったので、何かの参考になるかなーと書いてみました。

以下、リンク集

はじめに注意点を一つ。
ruby周りのwebの情報は情報が古くなっている事が多いです。出来るだけ、英語の公式ドキュメントやソースコードも読む癖をつけた方が良いです。

あと、新しい情報を探す時に「rails capistrano 2012」のように、調べたい内容の最後に西暦を入れると新しい情報が見つけやすいです。普通に検索した後、念のため最近使った人のブログ記事を検索し、目を通しておく事をおすすめします。

写経してみる

t-wada さんの記事がとても参考になる

ただ、この記事はruby 1.8rspec 1.3.0の内容なので、その点には注意する必要がある。
下記に気づいた点を記載しておく。

No command 'spec'

"spec"コマンドではなく、"rspec"コマンドを使用します。

$ rspec message_filter_spec.rb 
cannot load such file -- message_filter

ruby 1.9.2以降だとロードパスにカレントディレクトリが含まれなくなったため、エラーが起きます。
require_relative を使うようにします。

require_relative 'message_filter'

RSpecについてもっと詳しく知りたい

@ukstudio さんのるびまの記事を読む

RspecRailsで使う時の事が分からない

rspec-railsのREADMEを読む

web上の他の資料

rails 3.2.xの情報。

rails2.x の頃の情報なので、一部古いので注意

参考書籍

The RSpec Book (Professional Ruby Series)

The RSpec Book (Professional Ruby Series)

*1:複雑なテストはここまでシンプルに書けてないですが(´・ω・)

*2:むしろ、RSpecの正しい書き方とか私が知りたいです