メインコンテンツまでスキップ

Circle CIでJavaを使ってビルドする

Sato Taichi
yak shaver

ここ何日か Circle CI を使ってみて何となく分かってきた事をまとめておきます。

完成した circle.yml だけ欲しい方はこちらをどうぞ。

checkout:
post:
- chmod +x ./gradlew

machine:
timezone: Asia/Tokyo
environment:
GRADLE_OPTS: -Xmx4G -Dorg.gradle.daemon=true
JAVA_HOME: /usr/lib/jvm/java-8-oracle
post:
- sudo service mysql stop
- sudo service postgresql stop

dependencies:
pre:
- sudo apt-get install software-properties-common
- sudo add-apt-repository -y ppa:webupd8team/java
- sudo apt-get update
- echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | sudo /usr/bin/debconf-set-selections
- sudo apt-get install oracle-java8-installer
override:
- ./gradlew -v
- ./gradlew testClasses

test:
override:
- ./gradlew --full-stacktrace check

シェルスクリプトの実行権限

Windows を使っているとつい忘れがちですけども、シェルスクリプトに実行権限を付けるのを忘れないようにしましょう。

checkout:
post:
- chmod +x ./gradlew

タイムゾーンを自分達が作業しているものに変えよう

ログの中の時間が分かり易いようにタイムゾーンをデフォルト値から変更しておきましょう。

僕は概ね日本時間の夜中に活動しているのでAsia/Tokyoに変更しています。

CircleCI は RDB は二つの RDB が起動している

mysql と postgresql という二つの RDB が標準で動作しています。デフォルトで使えるメモリは 4GBなので、必要のないものは止めてしまいましょう。

machine:
post:
- sudo service mysql stop
- sudo service postgresql stop

尚、サポートに連絡すればメモリは増やして貰えるようです。

CircleCI は言語ランタイムのバージョンが固定されている

Circle CI では、machine設定でプログラミング言語のバージョンを指定できるようになっていますが、細かいリビジョンを指定できません。

例えば、Oracle JDK 8を利用する場合、以下のように設定します。

machine:
java:
version: oraclejdk8

2015/11/30 現在、この指定で動作するのは1.8.0_40です。これがリリースされたのは 2015/03/03 なのでちょっと古すぎるように感じます。

最新の Java を使ってビルドする

Circle CI 上で最新の Java を使ってビルドする方法について模索してみましょう。

方法としては 2 種類あります。

  • Docker を使って最新の Java が入ったイメージをビルドして使う方法
  • apt-get コマンドで最新の Java をインストールする方法

今回は apt-get コマンドで Java をインストールしてみましょう。Circle CI でビルドする際に動作する OS は、公式のマニュアルによるとUbuntu 12.04です。

これにコマンドだけで Java 8 をインストールする場合、以下のように実行します。

sudo apt-get install software-properties-common
sudo add-apt-repository -y ppa:webupd8team/java
sudo apt-get update
echo oracle-java8-installer shared/accepted-oracle-license-v1-1 select true | sudo /usr/bin/debconf-set-selections
sudo apt-get install oracle-java8-installer

まず、software-properties-commonをインストールして、add-apt-repositoryコマンドを使えるようにしています。

次に、add-apt-repositoryコマンドで Oracle Java 8 のメタデータが格納されているppa:webupd8team/javaリポジトリを追加します。

次の、 apt-get updateはパッケージのメタデータをローカルに取込んでいます。

次は、少し長めのコマンドになっています。Circle CI 上では対話的にパッケージをインストールすることは出来ませんが、Oracle Java のインストーラはかなり細かくウィザードに回答しなければなりません。そこで、debconf-utils のdebconf-set-selectionsを使ってウィザードに自動回答するようにしています。

最後に、oracle-java8-installerをインストールしています。これによってインストールされた Java は、/usr/lib/jvm/java-8-oracleというパスに格納されています。

Gradle や Maven から Java を使う際には、JAVA_HOME環境変数の書き換えが必要になりますので忘れないようにしましょう。以下のように記述します。

machine:
environment:
JAVA_HOME: /usr/lib/jvm/java-8-oracle

Gradle Daemon を使おう

Gradle の起動時間は決して速いとは言えませんので、起動時間を少しでも短縮するために Gradle Daemon を使いましょう。

gradlew コマンドのオプションとして--daemonを付けても良いのですが、--daemonが有効なものとそうでないものを切り分けるのが面倒なので、 -Dorg.gradle.daemon=trueを常に起動オプションとして指定してしまいましょう。 その場合、環境変数GRADLE_OPTSが使えます。

Circle CI で環境変数を指定するにはmachine設定のenvironmentセクションを使って以下のように記述します。

machine:
environment:
GRADLE_OPTS: -Xmx4G -Dorg.gradle.daemon=true

ライブラリの依存性解決は dependencies フェイズ内でやろう

Gradle を使ってビルドする場合、必要になるギリギリまで依存ライブラリのダウンロードが行われません。

Circle CI では、database フェイズ中にダウンロードキャッシュの保存を行うため test フェイズ中に依存ライブラリのダウンロードを行ってしまうと上手く保存されず、ビルドのたびに依存ライブラリをダウンロードしてしまいます。

これに対応するために、dependencies設定内でテストコードのビルドまではやってしまいましょう。Gradle でテストコードのビルド及びテストに必要なリソースのコピーを行う標準のタスクはtestClassesでしたね。

つまり、以下のようになります。

dependencies:
override:
- ./gradlew -v
- ./gradlew testClasses

ここでは、Gradle や Java のバージョンをまとめて確認できるように、-vを付けて Gradle をとりあえず起動しています。以下のような出力が得られますので、上手くビルド出来ない時の手掛かりになります。

------------------------------------------------------------
Gradle 2.9
------------------------------------------------------------

Build time: 2015-11-17 07:02:17 UTC
Build number: none
Revision: b463d7980c40d44c4657dc80025275b84a29e31f

Groovy: 2.4.4
Ant: Apache Ant(TM) version 1.9.3 compiled on December 23 2013
JVM: 1.8.0_66 (Oracle Corporation 25.66-b17)
OS: Linux 3.14.28-031428-generic amd64

テストだけでなく静的解析の類も実行しよう

CI サーバでユニットテストだけ実行するのでは物足りませんので、check タスクを実行しましょう。その際に、--full-stacktrace オプションを追加しておくと失敗した際に原因が分かり易くなります。

test:
override:
- ./gradlew --full-stacktrace check

以上です。

より良い方法をご存じの方は@ryushiまでメンションを下さい。