Bitbucket + Symfony2(PHP5.6) + Wercker でCIをする

プロジェクトが落ち着いてそろそろCI/CDを導入したいねっていう状況でした。

CircleCIを別案件で使ってた人が近くに居るけどBitbucketではCircleCIをサポートしていないようですので、別のCIを検討する必要がありました。

そこで色々検討した結果Werckerを使ってみることにしました。(無料だし）
しかし、WerckerはPHPをサポートしているけど、`Quickstarts` に書いてある事項はSymfony向きではないため混乱しました。
また `wercker.yml` に変更を加えていないのにBuildがfailedになることもありました。（僕は「werckerの機嫌が悪い」って呼んでる）
更にWerckerとWercker2の記述が有りググったときに更に混乱を招きました。

# 導入方法

## 前提/状況/目的

### 前提/状況

* Bitbucketでバージョン管理してる（状態はプライベート）
* Composer使ってる
* PHPUnit(5.4.4)でテストコードが若干あるが網羅率は高くない
    * UnitTestのｍ
* Symfony2.6使ってる。（2.7に移行したい）
        * そのためのテストコードを書いていきたい
* PHP5.6使ってる
* MySQL5.6使ってる
* Docker使っていない
	* 使いたい
	* WerckerはDockerHubのプライベートなやつにも対応できる

### 目的

* テストが自動でおこなわれて、PullRequestからその結果が確認(SUCCESS等)したい
	* Push → PR作成 → 自動でテスト がしたい。Push → 自動テストでもいい
* CDも欲しいけどCIの後で次ステップとして考えているのでCDは一旦後にする

## Werckerに登録

* 画面の案内に従えば特に迷わなかったため省略

## wercker.ymlの作成

迷いまくった結果の結果物(wercker.yml)と、その説明をする。

### 結果物

``` wercker.yml

box:
  id: voak/symfony2
  tag: latest

services:
  - id: mysql
    tag: 5.6
    env:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_ALLOW_EMPTY_PASSWORD: yes
      MYSQL_RANDOM_ROOT_PASSWORD: no
      MYSQL_DATABASE: symfony
      MYSQL_USER: test
      MYSQL_PASSWORD: test

build:
  steps:

    - script:
      name: install dependencies
      code: |-
        sudo apt-get update
        sudo apt-get install -y git libfreetype6-dev libjpeg62-turbo-dev libmcrypt-dev libpng12-dev unzip
        docker-php-ext-install gd
        docker-php-ext-install iconv mcrypt mbstring pdo_mysql
        curl -L https://phar.phpunit.de/phpunit.phar -o /usr/local/bin/phpunit
        chmod +x /usr/local/bin/phpunit
        curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer

    - script:
      name: composer update ʕ•̬͡•ʔ
      code: composer update

    - create-file:
      name: parameters.yml
      filename: app/config/parameters.yml
      overwrite: true
      content: |-
        parameters:
          database_driver: pdo_mysql
          database_host: $MYSQL_PORT_3306_TCP_ADDR
          database_port: 3306
          database_name: symfony
          database_user: test
          database_password: test
          mailer_transport: smtp
          mailer_host: 127.0.0.1
          mailer_user: null
          mailer_password: null
          locale: ja

    - script:
      name: doctrine shema update
      code: php app/console d:s:u --dump-sql --force

    - script:
      name: doctrine fixtures load
      code: php app/console doctrine:fixtures:load

    - script:
      name: php unit test
      code: phpunit -c app/ src/App/AdminBundle/Tests/

```

### 結果物の説明


#### box

```wercker.yml
box:
  id: voak/symfony2
  tag: latest
```

* `box` には使用するDockerイメージを追加する。
* DockerHubに登録されているイメージを使用する。
    * Privateも使用できるとの情報あり
* 上記では自前のDockerイメージを用意せずに公開されているSymfony2のDockerイメージを使う例
* `id` にはDockerイメージのIDを記載
	* 元のDockerHubはこちら、[https://hub.docker.com/r/voak/symfony2/](https://hub.docker.com/r/voak/symfony2/)
* `tag` には`id`で指定したDockerHubで設定されているタグを設定する
	* `PHP5.6-fpm` がlatestのようなので `latest`を設定している。
 [公式ドキュメント Classic wercker.yml](http://devcenter.wercker.com/docs/wercker-yml/wercker-classic.html)は古いwercker.ymlの記述がある。これは移行作業ができるようにするための案内のためある。注意。
 	* `wercker/ruby`とあり、`wercker/php`があるかもなって思ったら無い。そもそもその記述方法は古かった。

#### service

```wercker.yml
services:
  - id: mysql
    tag: 5.6
    env:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_ALLOW_EMPTY_PASSWORD: yes
      MYSQL_RANDOM_ROOT_PASSWORD: no
      MYSQL_DATABASE: symfony
      MYSQL_USER: test
      MYSQL_PASSWORD: test
```

* `service` では利用するMySQL等サービスを指定する
* `id` でDockerイメージを指定する
	* `mysql/mysql-server` を指定していると、`build` の `create-file` で `$MYSQL_PORT_3306_TCP_ADDR`が取れないため注意
* `tag` にはバージョンを設定する
	* [https://hub.docker.com/_/mysql/](https://hub.docker.com/_/mysql/)
	* MySQL5.7にも対応しているようだが、5.6で運用しているので`5.6`にしている。
* `env` には DockerHubのMySQLのページに記載されている`Environment Variables`について書いていく
	* 必須 `MYSQL_ROOT_PASSWORD`(rootユーザーのPW) ・ `MYSQL_ALLOW_EMPTY_PASSWORD`(PW無しユーザー許可) ・ `MYSQL_RANDOM_ROOT_PASSWORD`(rootユーザーのPWがランダムか)
		* 設定しないとFailed.
	* 推奨(僕が) `MYSQL_DATABASE` ・ `MYSQL_USER` ・ `MYSQL_PASSWORD`
		* 設定するとDBやUserを作ってくれる. 便利.


#### build

Pipelineの `build` に関する事

##### ◇build内共通説明

* `- script:` ではコマンド(スクリプト)が実行できる。
	* `name` はWercerの管理画面上に表示される名前。かわいいAA(`ʕ•̬͡•ʔ`)でも大丈夫。
	* `code` は実行するコマンドを書く。`|-` ってやれば改行も扱える
		* コマンド例 `sudo apt-get update`

* `- create-file:` ではファイルが作れる
	* `name` はWercerの管理画面上に表示される名前。かわいいAA(`ʕ•̬͡•ʔ`)でも大丈夫。
	* `filename` は書き出し先のファイル名
	* `overwrite` は上書きするか
	* `content` は書き出し内容。`|-` ってやれば改行も扱える

##### ◇build内個別説明

###### install dependencies

```wercker.yml
    - script:
      name: install dependencies
      code: |-
        sudo apt-get update
        sudo apt-get install -y git libfreetype6-dev libjpeg62-turbo-dev libmcrypt-dev libpng12-dev unzip
        docker-php-ext-install gd
        docker-php-ext-install iconv mcrypt mbstring pdo_mysql
        curl -L https://phar.phpunit.de/phpunit.phar -o /usr/local/bin/phpunit
        chmod +x /usr/local/bin/phpunit
        curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer
```

* `sudo apt-get` でcomposerやgit、PHPで画像を扱うための[GD](http://php.net/manual/ja/book.image.php)を使うために依存しているものをインストールする。
* `docker-php-ext-install` Dockerのコマンドを実行する. 今回は `voak/symfony2`に依存しつつ、今回のプロジェクトで必要な`gd`や`pdo_mysql`などをインストールする。
	* 参考になった: [Docker Hubのオフィシャルイメージを使ったLAMP環境(Apache+PHP+MySQL)構築](http://qiita.com/naga3/items/be1a062075db9339762d)
* `curl` と `chmod` のはPHPUnitやComposerのインストール

###### composer update

```wercker.yml
    - script:
      name: composer update
      code: composer update
```

* `composer update` を実行するだけ

###### parameters.yml

```wercker.yml
    - create-file:
      name: parameters.yml
      filename: app/config/parameters.yml
      overwrite: true
      content: |-
        parameters:
          database_driver: pdo_mysql
          database_host: $MYSQL_PORT_3306_TCP_ADDR
          database_port: 3306
          database_name: symfony
          database_user: test
          database_password: test
          mailer_transport: smtp
          mailer_host: 127.0.0.1
          mailer_user: null
          mailer_password: null
          locale: ja
```

* Symfony2のコンフィグ、`app/config/parameters.yml` を作る
* SwiftmailerやDBの設定だけ書いてある
  * `$MYSQL_PORT_3306_TCP_ADDR` が使えるので `$MYSQL_PORT_3306_TCP_PORT` とかも使える.
  	* 参考になった： [mysql - DockerHub](https://hub.docker.com/_/mysql/)
  * database_nameやuser, passwordは`service` で書いた内容が使える
  * 注意) 僕の環境ではメール送信/受信箇所のテストコードを書いていないためローカルな値となっている

###### doctrine shema update

```wercker.yml
    - script:
      name: doctrine shema update
      code: php app/console d:s:u --dump-sql --force
```

* DBへの接続設定がおわったのでShema更新だけ。


###### doctrine fixtures load

```wercker.yml
    - script:
      name: doctrine fixtures load
      code: php app/console doctrine:fixtures:load
```

* テストで使用するデータはDataFixturesとして作成済み
  * 参考になった： [DoctrineFixturesBundle](http://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html)
* データを流すだけでし


###### php unit test

```wercker.yml
    - script:
      name: php unit test
      code: phpunit -c app/ src/App/AdminBundle/Tests/
```

* テストを実行するだけ。

### build結果の画面

#### Wercker

こんな形で表示されます。
![スクリーンショット 2016-06-15 15.52.13.png](https://qiita-image-store.s3.amazonaws.com/0/93918/bc2f794f-00a7-e828-73e6-bb84eb8d487a.png)

### Bitbucket

* Build結果がBitbucketのPullRequestのリストに表示される.
![スクリーンショット_2016-06-15_15_17_18.png](https://qiita-image-store.s3.amazonaws.com/0/93918/6ed7460a-eb76-cd38-e49d-89540b4ffa40.png)

![スクリーンショット 2016-06-15 15.17.40.png](https://qiita-image-store.s3.amazonaws.com/0/93918/54597d52-c26b-4ae1-87c3-ad3091748024.png)


# TIPS

参考になったこと、気になったこと、転んだところなど。

## Workflowsが設定できる

* Pipelineの実行順序を変更できる。
* Pipelineとは`build` など
  * Pipelineは追加できる

## PrivateなDockerHubも使える


## Werckerの機嫌が悪い現象

### 『setup environment failed』

* 結果に`setup environment failed`とでる。
* `wercker.yml` に何らかの変更を加えたわけではないのでそこでbuildが失敗するのは変。
* `wercker.yml` の読み込みに成功しているが、`context canceled` と表示される。
* RetryするとSuccessする時もある。連続してこの現象が発生することもある。
* `wercker.yml`を読み込み以下Symfony2やMySQLのDockerイメージを読み込み注意に処理が中断されると発生する様だが、原因は不明。
  * タイムアウトが発生しているためか?

#### 発生時のLog(wercker.ymlの最後から掲載)

``` faild.log

    - script:
      name: doctrine shema update
      code: php app/console d:s:u --dump-sql --force

    - script:
      name: doctrine fixtures load
      code: php app/console doctrine:fixtures:load

    - script:
      name: php unit test
      code: phpunit -c app/ src/App/AdminBundle/Tests/

Pulling from voak/symfony2: latest
Digest: sha256:82378ceb2aa364304d48077b18deea38fefca7fdcb5f3ab148132e0963cf0ea7
Status: Image is up to date for voak/symfony2:latest
Pulling from library/mysql: 5.6
Digest: sha256:03646869dfecf96f443640f8b9040fbde78a96269aaf47bbfbb505a4c1adcad9
Status: Image is up to date for mysql:5.6
```

#### 正常時のLog(wercker.ymlの最後から掲載)

```successed.log

    - script:
      name: doctrine shema update
      code: php app/console d:s:u --dump-sql --force

    - script:
      name: doctrine fixtures load
      code: php app/console doctrine:fixtures:load

    - script:
      name: php unit test
      code: phpunit -c app/ src/App/AdminBundle/Tests/

Pulling from voak/symfony2: latest
Pulling fs layer: 6d46aff4cc0b
Pulling fs layer: 5154d7fe8cb1
Pulling fs layer: 5476328463d8
[略]
Digest: sha256:82378ceb2aa364304d48077b18deea38fefca7fdcb5f3ab148132e0963cf0ea7
Status: Downloaded newer image for voak/symfony2:latest
Pulling from library/mysql: 5.6
Digest: sha256:03646869dfecf96f443640f8b9040fbde78a96269aaf47bbfbb505a4c1adcad9
Status: Image is up to date for mysql:5.6
export WERCKER="true"
export WERCKER_ROOT="/pipeline/source"
export WERCKER_SOURCE_DIR="/pipeline/source"
export WERCKER_CACHE_DIR="/pipeline/cache"
[略]
export WERCKER_MAIN_PIPELINE_STARTED="XXXXXXXXX"
```


### buildが実行されない

* 待てども待てども実行されぬ
* `Abord` → `Retry` で実行できるときがある。実行できないときもある。
* 原因不明



## 良かった事


* BitbucketやSlackとの連係が簡単(難しくない)
  * マニュアル込みで分かりやすい。

* (今は)無料で同時にいくつも実行できるので全Commitに対してBuildを走らせれる

* Buid時間が早い
  * codeやDockerイメージの取得はCacheされているためか合わせて20秒程度で完了
  * `apt-get`や`composer`のインストールなどは1分20秒程度で完了
  * `composer update`は1分程度で完了
  * 全体でbuildに掛かる時間は3分程度〜4分程度
  * CircleCIより早く終わるらしい、 参考： [まだ CircleCI で消耗してるの？](http://qiita.com/KeithYokoma/items/b839ef3f5496a22f3e7a#docker-%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%82%92%E3%81%A4%E3%81%8F%E3%82%8D%E3%81%86)

* WerckerのCLIがある
  * [The Wercker Command Line Interface](http://devcenter.wercker.com/cli/index.html)
  * 使っていないが良いとの噂。
    * 使わずにどうしたのか→ 「すぐ出来ると思いwercker.ymlを修正してCommit&Pushで頑張った(真顔)」
      * いれた方が絶対便利

# その他参考になったこと

* [Bitbucket + Werckerを使ってプライベートリポジトリで無料CI（PHPUnit, MySQL)](http://qiita.com/yuichiroTCY/items/f2fc8df922f80bcb8ad3)
* 



以上。
テストかくぞー٩(๑òωó๑)۶