Jenkins で Pharo る

# はじめに
Smalltalkでの開発を管理する上で、Smalltalkの外の世界から管理することが重要になってきました。自分は運良く HoneyGinger や Jun4Pharo の開発で Inria の Jenkins サーバを利用する機会に恵まれました。そこで得られたノウハウをここで共有したいと思います。自前で Jenkins サーバ立てて運用する人達の参考になれば嬉しいです。

# Pharo で単体テスト

Jenkins での CI を効果的にするためには、単体テストは欠かせません。本節では Pharo 上での単体テストの記述や実行を簡単に紹介します。

## TestCase
TestCase クラスのサブクラスを定義し、必要に応じて setUp メソッドや tearDown メソッドを定義して、メソッド毎のテストコードをtestで始まるメソッド名で定義することで、テストフレームワークを利用することができます。

例えば Jun4Pharo の Jun2dPoint クラスの asArray メソッドをテストするための、Jun2dPointTestクラスの testAsArray メソッドを以下に示します。

```smalltalk:Jun2dPointTest
testAsArray
	| x y z p |
	x := 2.
	y := -3.
	z := 4.
	p := x , y.
	self
		assert: p asArray
		equals:
			{x.
			y}
```

上記の例のように、テストクラスの名前を、テスト対象のクラス名+Testとして、テストメソッドの名前を test+テスト対象のメソッド名 とするのが慣習となっています。

## SystemBrowser でテスト

上記のテストクラス名とテストメソッド名の慣習に従うとツールがその対応関係を理解し、以下のように System Browser 上から単体テストに合格した場合にテスト対象のクラスやメソッドを実行することができます。

![SystemBrowser上のテスト対象メソッド](https://qiita-image-store.s3.amazonaws.com/0/59918/e280a5c5-76a1-4d91-00df-3481dc4daaae.png)

丸アイコンをクリックすると、テスト結果がボタンの色で示されます。

![SystemBrowser上のテスト結果表示](https://qiita-image-store.s3.amazonaws.com/0/59918/7faa9908-7806-8c15-eaf7-f60fd6c13253.png)

もちろん、同じく System Browser 上でテストコード側からテストを実行したり結果を見ることができます。テストコード側ではメソッド単体だけでなく、テストクラスの全テストメソッドを実行することもできます。

![SystemBorwser上のJun2dPointTest](https://qiita-image-store.s3.amazonaws.com/0/59918/2954bc28-9b46-e5ad-1075-4469142ad5c8.png)

System Browser 上での単体テストの実行UIは、開発初期などでクラスやテストクラスをモリモリと書いていく過程での単体テストに向いています。

## TestRunner でテスト

開発プロジェクト全体について単体テストを一括して実行したり、テストカバレッジを計測する時などは、 TestRunner が便利で、複数のパッケージ、複数のテストクラスを選択して一括実行することができます。

![TestRunner](https://qiita-image-store.s3.amazonaws.com/0/59918/ceefae89-646b-0b25-961d-aa0a23a8ce2b.png)


# Pharo でコンソール

Jenkins を始めとする汎用の開発管理ツールを効果的に利用するためには、GUI だけでなく、コンソール上でのコマンドラインで実行できることが求められます。本節では Pharo をコマンドラインオプションを利用して制御する方法を紹介します。

## コマンドラインオプション

Pharo の Virtual Machine のオプションとして、<tt>--headless</tt> を指定すると、GUI を立ち上げずに Pharo 環境を立ち上げることができます。さらに、イメージファイルに続いて <tt>--list</tt>を指定すると、Pharo環境へのコマンドラインオプションの一覧が得られる。MacOSX 上で実行した場合の結果を以下に示します。

```
Currently installed Command Line Handlers:
    Fuel            Loads fuel files
    config          Install and inspect Metacello Configurations from the command line
    save            Rename the image and changes file
    update          Load updates
    printVersion    Print image version
    st              Loads and executes .st source files
    test            A command line test runner
    clean           Run image cleanup
    eval            Directly evaluates passed in one line scripts
```

使えそうなオプションが並んでいます。とりあえず、save、config、test があれば最低限のビルド＆テストはできそうです。

## CommandLineHandler

コマンドラインオプションは Pharo 環境内の <tt>CommandLineHandler</tt> クラスのサブクラスによって処理されます。既存のサブクラスを参考にしながら新しい Handler クラスを定義すれば、新しいコマンドラインオプションを定義することができます。

# Pharo で Jenkins

Inria の Pharo Contributions で動かしている Jun4Pharo のスクリプトを以下に示します。

```shell-session
# jenkins puts all the params after a / in the job name as well :(
export JOB_NAME=`dirname $JOB_NAME`

wget --quiet -O - get.pharo.org/$PHARO+$VM | bash

./pharo Pharo.image save $JOB_NAME --delete-old
./pharo $JOB_NAME.image --version > version.txt

REPO=http://smalltalkhub.com/mc/tomooda/Jun4Pharo/main
./pharo $JOB_NAME.image config $REPO ConfigurationOfJun --install=$VERSION --group=default
./pharo $JOB_NAME.image test --junit-xml-output "Jun.*"

zip -r $JOB_NAME.zip $JOB_NAME.image $JOB_NAME.changes
```

このスクリプトでやっていることは

* まずは <tt>wget</tt>で Pharo のバージョンと VM を指定してダウンロードスクリプトを取得してきて、それを実行してカレントディレクトリ内に展開します。
* そのままジョブ名でイメージファイルを保存して、さらに、バージョン名をversion.txtに記録しておきます。

REPO=行より下からが本番で、

* config オプションで CI 対象である Jun4Pharo を smalltalkhub のレポジトリから読み込んで、
* Junで始まるテストクラスを実行して XML ファイルに junit と同じ形式で出力します。
* 最後に、できあがったイメージファイルをチェンジファイルといっしょに zip アーカイブにします。

なお、このスクリプトは同じく Inria 内の Pharo Contributions の他のプロジェクトのをコピーして適当に修正したものです。eval オプション等を使えばもっと色々なことができるでしょう。

# PharoLauncher

Jenkins サーバで定期的にイメージを作成しているので、作成した zip をダウンロードしてくれば簡単にパッケージを試用してみたり、まとまった人数に統一した開発イメージを供給することができます。
例えば Jun4Pharo も、https://ci.inria.fr/pharo-contribution/job/Jun4Pharo/PHARO=40,VERSION=last,VM=vm/ で最近のテスト結果の推移を確認して、最新のイメージの zip をダウンロードしてくることができます。

それを Pharo 上で簡単に操作できるようにしたのが PharoLauncher です。

## インストール＆使い方

PharoLauncherは http://www.smalltalkhub.com/#!/~Pharo/PharoLauncher で開発されています。

```smalltalk
MCHttpRepository
	location: 'http://www.smalltalkhub.com/mc/Pharo/PharoLauncher/main'
	user: ''
	password: ''
```
から ConfigurationOfPharoLauncher の最新版を取得して、<tt>ConfigurationOfPharoLauncher load</tt>するか、あるいは Inria の CI サーバ の https://ci.inria.fr/pharo/view/Launcher/job/Launcher/PHARO=40,VERSION=stable,VM=vm,label=linux/ あたりからイメージをダウンロードしてくることもできます。

```smalltalk
PharoLauncher open
```

で PharoLauncher を立ち上げることができます。
現在は Inria の CI サーバ内のイメージを取得するようになっていますが、PhLJenkins2Job のサブクラスを定義して PhLTemplateGroupRepository class>>#groups あたりを修正すれば、他の Jenkins サーバも見ることができるようになると思います。

詳しくは http://www.smalltalkhub.com/#!/~Pharo/PharoLauncher をどうぞ。

# まとめ
Smalltalk での開発環境も、全てを Smalltalk 内で賄うことに拘らずとも、filetree 等と組み合わせて git & Jenkins という選択肢も実践として現実的になってきました。もちろん、従来のように monticello browser や Test Runner や Versionner を使って、できるだけ人手による作業を Smalltalk に閉じた形で行うこともできます。CI は目的ではなく、あくまで手段の1つに過ぎないので、1つの道具に拘らずに、あくまで多様な道具立ての1つとして Jenkins + Pharo を考えていけばよいのではないかと思います。