【5 Stepでわかる】CircleCIで始める、CakePHP3アプリの継続的インテグレーション

【5 Stepでわかる】CircleCIで始める、CakePHP3アプリの継続的インテグレーション

こんにちは、Apple Watch Series 2を買いましたtanakaです。心拍数、歩数、消費カロリーなどを数値化してくれると、日常がゲームのように感じられて楽しいですね。

最近のプロジェクトで、CakePHP3アプリをCircleCIでビルドする環境を構築しましたので、 アプリを作成するところからCircleCIでビルドするまでをご紹介します。 リポジトリがGitHubで公開されても良いなら、無料で試せますヨ。

目次

  • 継続的インテグレーション(Continuous Integration)とは
  • 前提
  • Step 1) CakePHP3アプリの作成
  • CircleCIでビルドするまでの流れ
  • Step 2) GitHub上のリポジトリにPushする
  • Step 3) CircleCI にアカウント登録
  • Step 4) プロジェクトを選択して、最初のビルドを実行
  • ビルドで何をやっているか
  • Step 5) わざとビルド失敗させてみる
  • Extra) CircleCI向け設定ファイルを書く
  • まとめ

継続的インテグレーション(Continuous Integration)とは

継続的インテグレーションとは、ソフトウェア開発において、ビルドやテストを頻繁に繰り返し行なうことにより問題を早期に発見し、開発の効率化・省力化や納期の短縮を図る手法。特に、専用のツールを用いてこのプロセスを自動化あるいは半自動化し、効率的に実施する方式。

継続的インテグレーションとは|CI|Continuous Integration - 意味 / 定義 / 解説 / 説明 : IT用語辞典

アプリケーションを継続的に開発しつづけていると、数ヶ月前のコミットが原因でアプリにバグが発生していた、ユーザからの連絡で初めて発覚した、という経験、ソフトウェアエンジニアならだれしもあるのではないでしょうか。 私もあります。あのときはとても忙しくてコードレビューする余裕もなく、、、なんて言い訳したくなる状況です。 数行追加した、たいしたことないコードと思っていたのに、大問題になることもあります。 継続的インテグレーション(と自動化されたテスト)は、品質を無理なく確認し続け、問題を早期発見するための習慣です。 この記事ではCakePHP3アプリをCircleCIで「ビルド」する手順について詳しく説明します。

CircleCI とは何か

継続的インテグレーションやそれをさらに推し進めた継続的デリバリーを実践するためのWebサービスです。 GitHubもしくはBitBacket上のGitリポジトリと連携させることで、「リモートリポジトリにPushされたらテスト実行して成功したらデプロイ」という手順を実現できます。

前提

  • PHP, Composer, MySQL, Gitはインストール済み
  • GitHubを使ったことがある

Step 1) CakePHP3アプリの作成

Composerがインストールされているものとして、以下のように実行するとセットアップできます。

$ cd projects_dir
$ composer create-project --no-interaction --prefer-dist cakephp/app cakephp3-circleci-example

サーバーを起動してみましょう。

$ cd cakephp3-circleci-example
$ bin/cake server

以下のような画面が表示されたら成功です!

20161009tanaka-cakephp3circleci01.png

Gitで管理するようにしましょう。

$ git init
$ git add .
$ git commit -m 'create project'

CircleCIでビルドするまでの流れ

CakePHP3アプリを早速CircleCIで「ビルド」しましょう。

CircleCIでビルドする場合、リポジトリサービスはGitHubもしくはBitBucketを選択できますが、今回はGitHubとの連携について説明します。

GitHub上のプロジェクトをCircleCIでビルドする場合、まず、GitHubリポジトリにPushします。

CircleCIにはGitHubアカウントでサインインすると、GitHubで自分が管理しているリポジトリ一覧が表示されますので、そこで選択すればビルド設定は完了です。

次の図のような流れを構築します。

20161011tanaka-cakephp3-build-flow.png

Step 2) GitHub上のリポジトリにPushする

GitHubでプロジェクトを作ると、ローカルリポジトリをPushする手順が表示されますので、それを実行します。

20161009tanaka-cakephp3circleci02.png

$ git remote add origin git@github.com:c-brains/cakephp3-circleci-example.git
$ git push -u origin master
(出力省略)

GitHub上のプロジェクトページにディレクトリ一覧が表示されたら成功です。

20161009tanaka-cakephp3circleci10.png

Step 3) CircleCI にアカウント登録

20161009tanaka-cakephp3circleci03.png

CircleCI はGitHubアカウントを使ってサインアップします。

  • Continuous Integration and Delivery - CircleCIにアクセス
  • Sign Up For Freeをクリック
  • (規約に同意して) Authorize With GitHub をクリック
  • GitHubのページに移動します。 Authorize application をクリックします。(CircleCIがGitHubアカウントに紐付いたリポジトリにアクセスできるようになります)
  • 重要な操作なのでパスワードの再入力を求められますので入力し、 Confirm password を押します。

Step 4) プロジェクトを選択して、最初のビルドを実行

Add projectsにアクセスし、自分のアカウント名か所属しているOrganizationをクリックすると、GitHubのリポジトリ一覧が表示されます。

その一覧から、テストするプロジェクトの横の Build Project をクリックします。

20161009tanaka-cakephp3circleci04.png

いま「ビルド」という言葉を使いましたが、リポジトリへの変更をトリガーにして自動化テストを実行したり、コーディングスタイルをチェックすることを「ビルド」と呼びます。 で、 Build Project をクリックすると、最初のビルドが実行されます。

画面が更新されていって、1分ほどで左上に「SUCCESS」と表示されたらビルド成功です! PublicなGitHubプロジェクトの場合、CircleCIのビルド結果も公開されますので 以下で確認できます。

20161009tanaka-cakephp3circleci05.png

ビルドで何をやっているか

ビルドログをチェックするとなんとなくわかるかと思いますが、以下のようなことをやっています。

  • コンテナ(自動化テストなどのタスクを実行する環境)を起動する
  • Gitリポジトリをコピー
  • composer.json があることから、PHPプロジェクトであることを認識して、composer install
  • (PHPプロジェクトなので)phpunitを実行
  • ビルド結果を表示(SUCCESS または FAILED)

Gitリポジトリを指定しただけでここまでしてくれて便利ですね!

Step 5) わざとビルド失敗させてみる

継続的インテグレーションは何のためにやっているのか…品質上の問題を早期発見するためです。 そこでCIの価値を体感するためにわざと失敗してみましょう。 CakePHPでユニットテストを導入するときに一番導入しやすいのはルーティングだと思います。

routes.php の記述も数が増えてくると相反するルールが出てきたりして、不具合の原因になります。 追加するのがつらくなっていきますので、テストすると気が楽になります。 例として、 '/my' にアクセスしたらMyPageController::index() に接続するためのルーティングのテストを書いてみます。

tests/TestCase/Route/RouteTest.php

<?php
namespace App\Test\TestCase\Route;

use Cake\Routing\Router;
use Cake\TestSuite\TestCase;

class RouteTest extends TestCase
{
    public function testMyPage()
    {
        $actual = Router::parse('/my');
        $expected = [
            'pass' => [],
            'plugin' => null,
            'controller' => 'MyPage',
            'action' => 'index',
            '_matchedRoute' => '/my',
        ];
        $this->assertEquals($expected, $actual);
    }
}

(実際のアプリケーションでは多数のルーティングをチェックすることになるので、データプロバイダを使いますが、ここではわかりやすさ優先のコードになっています)

$ git add tests/TestCase/Route/RouteTest.php
$ git commit -m '"/my" のルーティングテストを追加'
(出力省略)
 $ git push
(出力省略)

初回Push時は、CircleCIのサインアップから作業しましたが、2回目以降のPush時は、Pushをトリガーにして自動的にビルド実行されます。 ビルド一覧を確認すると、"Failed"と赤く表示され、ビルド失敗したことがわかります。

20161009tanaka-cakephp3circleci11.png

ビルドログ #2を確認すると、phpunitでのテスト実行結果でビルドが失敗したことが分かります。

20161009tanaka-cakephp3circleci12.png

それではビルド成功するように修正しましょう。

config/routes.php

47行目あたりに、マイページへのルーティングを追加します。

<?php
// 中略
Router::scope('/', function (RouteBuilder $routes) {
    // マイページ
    $routes->connect('/my', ['controller' => 'MyPage', 'action' => 'index']);

    // 以下略

Pushします

$ git add config/routes.php
$ git commit -m '"/my" へのルーティングを追加'
$ git push

ビルド一覧を見ると、「FIXED」と表示され、不具合が直ったことがわかります。

20161009tanaka-cakephp3circleci13.png

Extra) CircleCI向け設定ファイルを書く

とりあえずテストは実行できましたが、ちょっと欲を出して、設定をカスタマイズしたいと思います。

  • 最新のPHPUnitでテストする
  • PHP7.0 でテストする
  • composer install時のGitHub API制限を回避する

最新のPHPUnitでテストする

PHPUnit でテストしていたのに、 ローカル環境にPHPUnitをインストールしてませんでしたね

まず、composerで vendor/ にPHPUnitを追加しましょう。

$ composer require --dev phpunit/phpunit

以下のコマンドでローカルでもユニットテストが実行できるようになります。

$ vendor/bin/phpunit

20161009tanaka-cakephp3circleci14.png

いままでコンテナにインストール済みのphpunitを使っていたので、新しくインストールしたPHPUnitを使うようにします。

PROJECT_ROOT/circle.yml というファイルを追加し、以下のように記述します。

dependencies:
  override:
    - composer install --dev --no-interaction
test:
  override:
    - mkdir -p $CIRCLE_TEST_REPORTS/phpunit
    - vendor/bin/phpunit --configuration phpunit.xml.dist --log-junit $CIRCLE_TEST_REPORTS/phpunit/junit.xml

Pushしましょう。

$ git add composer.json composer.lock circle.yml
$ git commit -m 'PHPUnit インストール'
$ git push

phpunit実行したときのコマンドが変わりました。

20161009tanaka-cakephp3circleci15.png

PHP7.0 でテストする

デフォルトの設定だと、PHP 5.6.17でテスト実行されるそうです。 どうせならPHP7でテストしたいですよね。そんなわけで設定変更してみます。

参考: Ubuntu 14.04 (Trusty) - CircleCI

これもcircle.ymlに設定を追加します。

machine:
   php:
     version: 7.0.11

Pushします。

$ git add circle.yml
$ git commit -m 'CircleCI PHP7でテスト実行'
$ git push

デフォルトのコンテナで指定できるバージョンはUbuntu 14.04 (Trusty) - CircleCIから選択します。

ビルドログを見ると、PHP7.0.11に切り替わっていることがわかります。

20161009tanaka-cakephp3circleci16.png

composer install時のGitHub API制限を回避する

composerでインストールするライブラリが増えてくると、GitHub のアクセス制限にひっかかり、composer installできなくなるかもしれません。その場合は、GitHubでアクセストークンを作成し、CircleCIの画面から環境変数を設定して、ビルドの前処理にてcomposerでアクセストークンを設定してやるようにします。

1. Personal Access Tokensで[Generate Access Token]をクリックして、アクセストークンを作成します。(追加の権限が必要かのチェックボックスがありますが不要です)

  • Token descriptionの内容は自由ですが「CircleCI composer」としておきます
  • Generate Tokenをクリック
  • トークン文字列が生成されるのでコピーします

20161009tanaka-cakephp3circleci17.png

2. CircleCIログイン後の右上に表示される歯車アイコンをクリックして、[Environment Variables]にアクセスします。[Add Variable]で環境変数を登録します

20161009tanaka-cakephp3circleci18.png

3. 設定ファイル circle.yml で環境変数を利用してアクセストークンを設定します

dependencies:
  pre:
    - composer config -g github-oauth.github.com $GITHUB_ACCESS_TOKEN

Pushします

$ git add circle.yml
$ git commit -m 'GitHub API Limit 回避用アクセストークン追加'
$ git push

この設定をするとAPI制限を回避できます。 APIキーなどの秘密情報はリポジトリに登録せず、環境変数経由で取得するのが鉄則です。

まとめ

CIツールで自動化できることは自動化して、開発をラクにしつつ、問題を早期発見できるように習慣化していきましょう。 データベースを使ったテストについてはまた後日解説したいと思います!

データベースを使ったテスト

続編を書きました!→CircleCIで始めるCakePHP3アプリの継続的インテグレーション(2) - MySQL DBを用いたテスト

作図のソースについて

以下の図を利用しました。

  • このエントリーをはてなブックマークに追加

この記事を読んだ人にオススメ