werckerでPHPUnitのCI

githubのプライベートレポジトリでも利用できるCIサービスwerckerでPHPUnitのテスト実行環境を作成してみました。
Ruby on Rails + RSpecの例はよく目にしますが、PHPUnit(&DBUnit)の構築例があまり無かったので、実際に運用しているwercker.ymlと、その簡単な解説を共有します。

## wercker.yml成果物

```yaml:wercker.yml
box: wercker/php
services:
  - wercker/mysql
build:
  steps:
    - script:
        name: Activate PHP 5.3
        code: phpenv global 5.3
    - script:
        name: install ansible
        code: |-
            git clone git://github.com/ansible/ansible.git
            cd ansible
            git checkout v1.7.1
            sudo make install
            type ansible || { echo "ansible not found"; exit 1; }
    - script:
        name: ansible provisioning
        code: sudo ansible-playbook -i ci/wercker/wercker_hosts ci/wercker/wercker.yml -c local
    - script:
        name: setup test db
        code: mysql -h$WERCKER_MYSQL_HOST -P$WERCKER_MYSQL_PORT -u$WERCKER_MYSQL_USERNAME -p$WERCKER_MYSQL_PASSWORD $WERCKER_MYSQL_DATABASE < ci/wercker/db.sql
    - script:
        name: fill mysql env.
        code: |-
            sudo sed -i -e "s/WERCKER_MYSQL_HOST/$WERCKER_MYSQL_HOST/g" $WERCKER_ROOT/test/UnitTest/phpunit.xml
            sudo sed -i -e "s/WERCKER_MYSQL_PORT/$WERCKER_MYSQL_PORT/g" $WERCKER_ROOT/test/UnitTest/phpunit.xml
            sudo sed -i -e "s/WERCKER_MYSQL_USERNAME/$WERCKER_MYSQL_USERNAME/g" $WERCKER_ROOT/test/UnitTest/phpunit.xml
            sudo sed -i -e "s/WERCKER_MYSQL_PASSWORD/$WERCKER_MYSQL_PASSWORD/g" $WERCKER_ROOT/test/UnitTest/phpunit.xml
            sudo sed -i -e "s/WERCKER_MYSQL_DATABASE/$WERCKER_MYSQL_DATABASE/g" $WERCKER_ROOT/test/UnitTest/phpunit.xml
    - script:
        name: echo PHP information
        code: |-
            php -v
            php -i
    - script:
        name: PHPUnit integration tests
        code: |-
            cd test/UnitTest
            phpunit -c phpunit.xml lib/
  after-steps:
    - sherzberg/slack-notify:
        subdomain: my_slack_subdomain
        token: $SLACK_TOKEN
        channel: my_slack_channel
```

## 解説

```
box: wercker/php
services:
  - wercker/mysql
```

werckerオフィシャルBOXの`wercker/php`を利用します。
このBOXには、PHP 5.5, 5.4, 5.3が`phpenv`でインストールされており、環境にあったバージョンを選択できるようになっています。

また、今回はDBUnitのテストも行うため、servicesとして`wercker/mysql`を追加しています。

```
    - script:
        name: Activate PHP 5.3
        code: phpenv global 5.3
```

PHPのバージョンを5.3に設定します。
プロダクション環境のバージョンに合わせて設定すると良いでしょう。
5.3は最新より一つ古い5.3.28がインストールされていました（2014.08.29時点）。

```
    - script:
        name: install ansible
        code: |-
            git clone git://github.com/ansible/ansible.git
            cd ansible
            git checkout v1.7.1
            sudo make install
            type ansible || { echo "ansible not found"; exit 1; }
```

pear/peclのライブラリインストールや、その他環境構築をansibleで行いたかったので、インストールしています。

```
    - script:
        name: ansible provisioning
        code: sudo ansible-playbook -i ci/wercker/wercker_hosts ci/wercker/wercker.yml -c local
```

ansible-playbookで環境構築を行います。

```
    - script:
        name: setup test db
        code: mysql -h$WERCKER_MYSQL_HOST -P$WERCKER_MYSQL_PORT -u$WERCKER_MYSQL_USERNAME -p$WERCKER_MYSQL_PASSWORD $WERCKER_MYSQL_DATABASE < ci/wercker/db.sql
```

DBのスキーマを流し込んでいます。
ここで使っているdb.sqlは、

```
$ mysqldump --single-transaction -d -q -hHOST -PPORT -uUSER -pPASSWD DBNAME > db.sql
```

のように-d(--no-data)を付けてプロダクションのDBから取得したスキーマオンリーのSQLファイルです。

`WERCKER_MYSQL_*`の環境変数は、`wercker/mysql`によって自動的に追加されるMySQL接続情報です。
werckerのEnvironment Variablesに自分で設定するものではありません。

値は毎回変わりますが、下記のような感じでした。

| variable | value |
|---|---|
| WERCKER_MYSQL_HOST | 10.0.3.34 |
| WERCKER_MYSQL_PORT | 3306 |
| WERCKER_MYSQL_USER | wercker |
| WERCKER_MYSQL_PASSWORD | wercker |
| WERCKER_MYSQL_DATABASE | werckerdb1 |

```
    - script:
        name: fill mysql env.
        code: |-
            sudo sed -i -e "s/WERCKER_MYSQL_HOST/$WERCKER_MYSQL_HOST/g" $WERCKER_ROOT/test/UnitTest/phpunit.xml
            sudo sed -i -e "s/WERCKER_MYSQL_PORT/$WERCKER_MYSQL_PORT/g" $WERCKER_ROOT/test/UnitTest/phpunit.xml
            sudo sed -i -e "s/WERCKER_MYSQL_USERNAME/$WERCKER_MYSQL_USERNAME/g" $WERCKER_ROOT/test/UnitTest/phpunit.xml
            sudo sed -i -e "s/WERCKER_MYSQL_PASSWORD/$WERCKER_MYSQL_PASSWORD/g" $WERCKER_ROOT/test/UnitTest/phpunit.xml
            sudo sed -i -e "s/WERCKER_MYSQL_DATABASE/$WERCKER_MYSQL_DATABASE/g" $WERCKER_ROOT/test/UnitTest/phpunit.xml
```

PHPUnitで使うconfigファイル中のMySQL接続情報を、`WERCKER_MYSQL_*`の値に書き換えています。

```
    - script:
        name: echo PHP information
        code: |-
            php -v
            php -i
```

テスト前に一応PHPの設定情報をログに残しておきます。

```
    - script:
        name: PHPUnit integration tests
        code: |-
            cd test/UnitTest
            phpunit -c phpunit.xml lib/
```

PHPUnit実行部です。
環境によってパスなどは書き換えてください。

```
  after-steps:
    - sherzberg/slack-notify:
        subdomain: my_slack_subdomain
        token: $SLACK_TOKEN
        channel: "#my_slack_channel"
```

結果をslackに差し込むために、テスト後の処理を追加しています。
`$SLACK_TOKEN`のような情報は、レポジトリに含めずにwerckerのEnvironment Variablesに設定しておくのが良いでしょう。

デプロイは別手順にしているため、werckerでは以上のテスト実行のみを行っています。

## さいごに

werckerはβ版ということもあってか、たまにgithubに結果が返らない（wercker上ではテスト成功となっているが、github上ではPendingのまま）ようなこともありますが、手軽さと、無料でプライベートレポジトリが利用できるのは大きな魅力です。
正式サービスイン時にどういう料金体制になるかはまだ分かりませんが、これからCIを導入する方は、選択肢の一つとして検討しても良いのではないでしょうか。

今後はAndroidアプリのビルド＋テスト＋DeployGateでの配布なんかをやってみようと思っています。