ディレクトリ階層深めのLaravelアプリケーションでCircleCIの設定をする

ディレクトリ構成をミスってしまったアプリケーションでCircleCIを導入するのにだいぶハマってしまったので、メモとして残します。

### 環境情報
- PHP 7.2
- Larave l5.6
- Github
- CircleCI 2.0
- mysql 5.7

### アプリケーションのディレクトリ構成
このアプリケーションを作る際に、初めてLaravelをDockerを使って環境構築をしたため、2つネストの深いディレクトリ構成で作ってしまった。この構成がおかしいと気付いた時には、時すでに遅し。気持ち悪いが、特に不便なこともなかったので、この形で進めましたた。

```
app
|-.circleci
├─ src
    ├─ hogehuga
         └─ app
         └─ artisan
         └─ vendor
         └─ tests
         └─ phpunit.xml
         └─ composer.json
         └─ composer.lock
```

### 問題
CIでテストを自動で実行できるようにしたいと考え、GithubとCircleCIを連携させて初期状態の`.circleci/config.yml`ファイルを作ってCIを動かすところまでは、簡単だった。。。

ファイルの中身は下のドキュメント通りのもの。
[言語ガイド：PHP - CircleCI](https://circleci.com/docs/ja/2.0/language-php/)

ドキュメントではこれで一旦、ビルドすれば成功すると書かれているのだが、エラーが。

```sh:エラー内容
#!/bin/bash -eo pipefail
composer install -n --prefer-dist
Composer could not find a composer.json file in /home/circleci/project
To initialize a project, please create a composer.json file as described in the https://getcomposer.org/ "Getting Started" section
Exited with code 1
```

composerがないと怒られる。原因を調べるべく、本当にcomposerがないのか、ビルドの中で、`ls`コマンドを実行させてみると、projectという文字が出てくる。ここで、Laravelのディレクトリが1つ階層下にあるという構造がエラーの原因だとわかる。

```yml
run: ls

###### lsの実行結果 #####
hogehuga
```

### 解決作

- 設定しているパスを全て2つ階層を掘り下げて設定する。(./src/project/の追加)

一見、簡単な解決策なのだが、地味に大変だったので細かく解決策をここに記します。

#### composer

composerの実行は`--working-dir`で指定可能。
`composer.lock`が存在するディレクトリを設定する


```yml:.circleci/config.yml
- restore_cache:
    keys:
      - v1-dependencies-{{ checksum "./src/hogehuga/composer.lock" }}
      - v1-dependencies-
- run: composer install -n --prefer-dist --working-dir=./src/hogehuga
- save_cache:
    key: v1-dependencies-{{ checksum "./src/hogehuga/composer.lock" }}
    paths:
      - ./src/hogehuga/vendor
```

#### yarn

yarn installに関しては、`--cwd`オプションでディレクトリを指定できる。

```yml:.circleci/config.yml
- restore_cache:
    keys:
      - node-v1-{{ checksum "./src/hogehuga/yarn.lock" }}
      - node-v1-
- run: yarn install --cwd ./src/hogehuga
- save_cache:
    key: node-v1-{{ checksum "./src/hogehuga/yarn.lock" }}
    paths:
      - ./src/hogehuga/node_modules
```

#### phpunit

`artisan`コマンドもパスを指定して実行しなければならない。。。
phpunitも`phpunit.xml`が存在しないディレクトリから実行する場合は`phpunit.xml`までパスを指定しないとテストを実行することができないので、注意。

```yml:.circleci/config.yml

- run: php ./src/hogehuga/artisan --env=testing
- run: php ./src/hogehuga/vendor/bin/phpunit --configuration=./src/hogehuga/phpunit.xml
```

### その他、ハマったところ

#### mysqlに接続できない

```sh:エラー内容
[Illuminate\Database\QueryException]
could not find driver (SQL: select * from sqlite_master where type = 'table ' and name = migrations)
 [Doctrine\DBAL\Driver\PDOException]
could not find driver
 [PDOException]
could not find driver
```

これは、ドキュメントだとデータベースをsqliteを使っている為、起きる。MySQLの場合は、`pdo_mysql`をインストールしないといけない。

```yml:.circleci/config.yml
build:
    # 中略
    steps:
      - checkout

      - run: sudo apt update
      - run: sudo docker-php-ext-install zip pdo_mysql
      - run: sudo composer self-update
```

#### mysqlに接続できない2


```yaml:.circleci/config.yml
In Connection.php line 664:
                                                                               
  SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name o  
  r service not known (SQL: SHOW FULL TABLES WHERE table_type = 'BASE TABLE')  
                                                                               

In Connector.php line 70:
                                                                               
  SQLSTATE[HY000] [2002] php_network_getaddresses: getaddrinfo failed: Name o  
  r service not known                                                          
                                                                               

In Connector.php line 70:
                                                                               
  PDO::__construct(): php_network_getaddresses: getaddrinfo failed: Name or s  
  ervice not known                                                             
                                                                               

Exited with code 1
```

こいつは、DBのHOST設定が間違っている。dockerで開発環境を構築する際、DB_HOSTのあたいはDBコンテナ名に揃えると思うのだが、CIで実行するときはローカルホスト`127.0.0.1`で設定しないといけない。

```yml:.env.testing
DB_CONNECTION=mysql
DB_HOST=mysql
```

.env.testingファイルを書き換えても良いが、そうすると自分のPC上でテスト実行したい時にエラーになってしまうので、ciのcofigファイルで設定してあげる。

```.circleci/config.yml
build:
    docker:
      - image: circleci/php:7.2-node-browsers
      - image: circleci/mysql:5.7
        environment:
          - MYSQL_DATABASE: hogehuga_testing
          - MYSQL_ROOT_PASSWORD: password
    environment:
      - DB_HOST: 127.0.0.1
 ```

↑ ちなみに、CIで使用するmysqlイメージはcircleciが用意してくれているものを使うと最適化されていてビルドにかかる時間が短縮されるらしい。

### 終わりに
そもそも、ディレクトリ構造がおかしいまま開発は進めてはいけない。


### 参照

[リポジトリ直下にcomposer.jsonがない場合でCircleCIでハマったこと - Qiita](https://qiita.com/pinekta/items/e4bdf1b22c1cefe886f7)


[DockerでPHPエラー「php_network_getaddresses: getaddrinfo failed: Name or service not known」](https://tech.pjin.jp/blog/2018/02/27/docker%E3%81%A7php%E3%82%A8%E3%83%A9%E3%83%BC%E3%80%8Cphp_network_getaddresses-getaddrinfo-failed-name-or-service-not-known%E3%80%8D/)


[言語ガイド：PHP - CircleCI](https://circleci.com/docs/ja/2.0/language-php/)

[CircleCI 2.0でMySQLのイメージを使うならば、CircleCIが配布しているイメージを使わないと損 - Qiita](https://qiita.com/kunit/items/0021045821ac22508219)