こんにちは!
今作っているアプリにCircleCIを導入して、文法チェックツールやテストの実行を自動化しました。
メモ用にやったことを書き残しておきたいと思います。どなたかの参考になると嬉しいです。
環境
- Laravel v6.10.1
- Nuxt.js v2.11.0
- CircleCI v2.1
ディレクトリ構成
1つのリポジトリでBackend(Laravelアプリ)とFrontend(Nuxtアプリ)を管理しています。
project
|- .circleci
| └- config.yml
|- docker
|- docker-compose.yml
|- backend (Laravelアプリ)
└- frontend (Nuxtアプリ)
CircleCIで行っていること
- phpファイルのコーディング規約チェック
- phpファイルを静的解析して、バグになりそうなところをチェック
- jsファイルも同様にコーディング規約チェックとバグになりそうなところチェック
- PHPUnitとJestの実行
- テストカバレッジのアップロード
導入したツール
導入したライブラリ
PHPUnit
PHP用のテストフレームワーク。
Laravelアプリのテストを実行する時に使う。
標準でインストールされているはず。
PHP_CodeSniffer
コーディング規約チェックライブラリ。
Laravelアプリで書いたコードがPHPのコーディング規約にあっているかをチェックする。
Larastan
PHPの静的解析を行うライブラリであるPHPStanのLaravelバージョン。
PHPのソースコードの静的解析を行い、バグがありそうなコードを発見する。
Lint&Prettier
JavaScriptファイルの構文チェックとコーディング規約のチェックを行うライブラリ。
JSのソースコードの静的解析を行い、バグがありそうなコードの発見とコーディング規約にあっているかをチェックする。
Jest
JavaScript用のテストフレームワーク。
Nuxtアプリのテストを実行する時に使う。
手順
CircleCIの設定
まずはProjectのRootディレクトリ直下に.circleci
というフォルダを作成し、設定ファイルであるconfig.yml
を作成します。
mkdir .circleci && touch .circleci/config.yml
設定はYAML形式で行います。YAMLについて詳しくない方はこちらを見ながら、実際にここで試してみるといいかもしれません。
config.yml
を次のように設定してください。
version: 2.1
# ここでは、繰り返し使う値を登録しておきます。管理するjobなどが多くなった時に管理がしやすいです。
# ymlでは、データの前に&でアンカーをつけることができます。定数を宣言するようなイメージです。データを参照する時に、データの前に*をつけます。
# 例) &name: ”ドラえもん",myname: *name => ドラえもん
aliases:
- &composer_key_base composer-v3-
- &composer_key composer-v3-{{ checksum "./backend/composer.lock" }}
- &node_key_base node-v4-
- &node_key node-v4-{{ checksum "./frontend/package.json" }}
- &root ~/Your_APP_NAME_OR_SOMETHING
- &defaults
working_directory: *root
- &package-install
run:
name: npm install
command: npm i
working_directory: frontend
- &restore_composer
restore_cache:
keys:
- *composer_key
- *composer_key_base
- &restore_node
restore_cache:
keys:
- *node_key
- *node_key_base
- &prepare-db
run:
name: Prepare database
command: |
dockerize -wait tcp://127.0.0.1:3306 -timeout 60s
# Codecovにテストカバレッジをアップロードするときに使用します。
orbs:
codecov: codecov/codecov@1.0.5
## ここでjobを設定し、実行します。
jobs:
build:
<<: *defaults
docker:
- image: monicahq/circleci-docker-centralperk:latest
- image: circleci/mysql:5.7
command: mysqld --default-authentication-plugin=mysql_native_password
environment:
MYSQL_DATABASE: homestead
MYSQL_USER: homestead
MYSQL_PASSWORD: secret
MYSQL_ROOT_PASSWORD: password
steps:
- checkout
- run:
name: Prepare environment
command: |
echo $(ls -al)
cp .env.circleci .env
sudo composer self-update
working_directory: backend
## Laravel
- *restore_composer
- run:
command: |
composer global require hirak/prestissimo
composer install --no-interaction --no-suggest --ignore-platform-reqs
working_directory: backend
- save_cache:
key: *composer_key
paths: ~/.composer/cache/
- run:
name: RUN KEY:GENERATE
command: |
php artisan key:generate
working_directory: backend
- *prepare-db
- run:
name: RUN DB MIGRATE
command: |
php artisan migrate
working_directory: backend
- run:
name: RUN Larastan
command: ./vendor/bin/phpstan analyse
working_directory: backend
- run:
name: RUN PHP Code_Sniffer
command: ./vendor/bin/phpcs
working_directory: backend
- run:
name: RUN PHPUnit
command: phpdbg -qrr vendor/bin/phpunit --coverage-clover ./tests/report
working_directory: backend
### Codecovにテストカバレッジをアップロードします
- codecov/upload:
file: ./backend/tests/report
flags: backend
## Nuxt.JS
- *restore_node
- *package-install
- save_cache:
key: *node_key
paths: ~/.cache
- run:
name: Check js and vue lint
command: npm run lint
working_directory: frontend
- run:
name: RUN JUnit
command: npm run test-coverage
working_directory: frontend
### Codecovにテストカバレッジをアップロードします
- codecov/upload:
file: ./frontend/coverage/clover.xml
flags: frontend
CircleCIで使用するDockerイメージは、OSSの1つであるmonicaが開発しているmonicahq/circleci-docker-centralperkを使用しています。
Databaseの設定
CircleCI内でDatabaseを用いて、Laravelアプリのテストを行うことができるように、Databaseの設定を行います。
まずはLaravelアプリのプロジェクトにあるconfig/database.yml
に以下のものを追加します。
'connections' => [
'circleci_test' => [
'driver' => 'mysql',
'host' => env('DB_HOST'),
'port' => '3306',
'database' => env('DB_DATABASE'),
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
],
中略
]
同じくLaravelアプリのプロジェクトに.env.circleciファイル
を作成して、以下のものを貼り付けます。
APP_NAME=Laravel
APP_ENV=circleci_test
APP_KEY=YOUR_APP_KEY
APP_DEBUG=true
APP_URL=http://localhost
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
これでCircleCIの中でDatabaseを用いたテストを実行することができると思います。
PHP_CodeSnifferのインストール&設定
PHP_CodeSnifferは、PHPのソースコードがコーディング規約に合っているかどうかをチェックするライブラリです。PHPのコーディング規約はいくつかあるのですが、ここではPSR-2
を使います。
詳しく知りたい方はこちらの記事がわかりやすいと思います。
では、次のコマンドを実行して、LaravelアプリのプロジェクトにPHP_CodeSnifferをインストールします。
composer require --dev "squizlabs/php_codesniffer=*"
次にLaravelアプリのプロジェクト直下にphpcs.xml
を作成します。
touch phpcs.xml
作成したphpcs.xml
に次の値を設定します。
<?xml version="1.0"?>
<ruleset name="Laravel Standards">
<description>The Laravel Coding Standards</description>
<!-- 対象フォルダ -->
<file>./app</file>
<file>./config</file>
<file>./resources</file>
<file>./routes</file>
<file>./tests</file>
<!-- 除外したいファイル、ディレクトリ -->
<exclude-pattern>*/database/*</exclude-pattern>
<exclude-pattern>*/cache/*</exclude-pattern>
<exclude-pattern>*/*.js</exclude-pattern>
<exclude-pattern>*/*.css</exclude-pattern>
<exclude-pattern>*/*.xml</exclude-pattern>
<exclude-pattern>*/*.blade.php</exclude-pattern>
<exclude-pattern>*/autoload.php</exclude-pattern>
<exclude-pattern>*/storage/*</exclude-pattern>
<exclude-pattern>*/docs/*</exclude-pattern>
<exclude-pattern>*/vendor/*</exclude-pattern>
<exclude-pattern>*/migrations/*</exclude-pattern>
<!-- PSR2をベースとする -->
<rule ref="PSR2">
<!-- 除外したい項目 -->
<exclude name="Generic.Files.LineLength.TooLong"/>
</rule>
<arg name="colors"/>
<arg value="p"/>
<ini name="memory_limit" value="128M"/>
<rule ref="PSR2"/>
</ruleset>
下記のコマンドを実行して、PHP_CodeSnifferを実行してください。コーディング規約に合っていないコードがある場合エラーが出力されます。
./vendor/bin/phpcs
ここで出たエラーを自動で整形したい場合は、以下のコマンドを使います。
./vendor/bin/phpcbr
Larastanのインストール&設定
LarastanはPHPのソースコードにバグらしいコードがないかをチェックするライブラリです。
まず次のコマンドを実行して、LaravelアプリのプロジェクトにLarastanをインストールします。
composer require --dev nunomaduro/larastan
次にLaravelアプリのプロジェクト直下にphpstan.neon
を作成します。
touch phpstan.neon
作成したphpcs.xml
に次の値を設定します。
includes:
- ./vendor/nunomaduro/larastan/extension.neon
parameters:
paths:
- app
- resources
- tests
# The level 8 is the highest level
level: 5
ignoreErrors:
- '#Unsafe usage of new static#'
excludes_analyse:
- ./*/*/FileToBeExcluded.php
checkMissingIterableValueType: false
次のコマンドで解析を行います。バグがありそうなコードが存在する場合、そのコードが出力されると思います。
./vendor/bin/phpstan analyse
また解析のレベルを0-7の間で調整することができます。0に近いほど緩く解析、7に近いほど厳しく解析になります。
./vendor/bin/phpstan analyse --level=4
ESLint & Prettierの設定
ESLintとPrettierは、JavaScriptのソースコードを解析して、バグらしきコードがないかやコーディング規約にあっているかをチェックするライブラリです。
次のコマンドを実行して、Nuxtアプリのプロジェクトに、ESLintとPrettierに必要なパッケージをインストールします。
npm install --save-dev babel-eslint eslint eslint-config-prettier eslint-loader eslint-plugin-vue eslint-plugin-prettier prettier
次にNuxtアプリのプロジェクト直下に.eslintrc.js
を作成します。
touch .eslintrc.js
作成した.eslintrc.js
に次の値を設定します。
module.exports = {
root: true,
env: {
browser: true,
node: true
},
"parser": "vue-eslint-parser",
parserOptions: {
parser: 'babel-eslint'
},
extends: [
"prettier",
"plugin:prettier/recommended",
"plugin:vue/recommended",
"@vue/prettier",
// https://github.com/vuejs/eslint-plugin-vue#priority-a-essential-error-prevention
// consider switching to `plugin:vue/strongly-recommended` or `plugin:vue/recommended` for stricter rules.
// 'plugin:vue/essential'
],
// required to lint *.vue files
plugins: [
'vue'
],
// add your custom rules here
rules: {
"semi": [2, "never"],
"no-unused-vars": ["error", { "args": "none" }],
"prettier/prettier": [
"error",
{
"singleQuote": true,
"semi": false
}
]
}
}
package.json
にlint
とlint-fix
コマンドを追加します。
"scripts": {
"lint": "eslint --ext .js,.vue --ignore-path .gitignore .",
"lint-fix": "eslint --ext .js,.vue --ignore-path .gitignore . --fix",
},
次のコマンドで解析を実行します。コーディング規約に合っていないおよびバグがありそうなコードが存在する場合、エラーが出力されます。
npm run lint
エラーを自動で修正したい場合はこちらのコマンドを実行します。
npm run lint-fix
CircleCIとCodecov連携
ここでは、CircleCIから実行したPHPUnitとJestのテストカバレッジをCodecovで確認する方法を記載します。
登録からCodecovの設定方法を書くのが大変なので、以下のサイト様を参考にしてやってみてください...
CircleCIとCodecovでGitHubにカバレッジバッジをつけよう!
流れとしては、Codecovに登録 -> CodecovからGitHubリポジトリの選択 -> CircleCIにCodecovのトークンを登録 -> ローカルからCircleCIにpush -> CircleCIからCodecovにカバレッジをアップロードという流れになるかと思います。
PHPUnitのテストカバレッジの結果をCodecovにアップロード
次にLaravelアプリのプロジェクトにあるphpunit.xml
に次の設定を追加します。
<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./app/Http/Controllers</directory>
<directory suffix=".php">./app/Models</directory>
</whitelist>
</filter>
ここでテストカバレッジを測定したいフォルダやファイルを設定します。
テストカバレッジを出力するときは次のコマンドを実行してください。
phpdbg -qrr vendor/bin/phpunit --coverage-clover ./tests/report
tests
ディレクトリの下にreport
というファイルが出来ていると思います。
こちらをCircleCIからCodecovにアップロードします。
実際には.circleci/config.yml
の以下の部分でテストの実行とアップロードを行っています。
- run:
name: RUN PHPUnit
command: phpdbg -qrr vendor/bin/phpunit --coverage-clover ./tests/report
working_directory: backend
### Codecovにテストカバレッジをアップロードします
- codecov/upload:
file: ./backend/tests/report
flags: backend
ちなみにphpdbg
を使うとテストカバレッジの出力が高速になるみたいです。
参考: PHP でカバレッジを出すなら phpdbg
Jestのテストカバレッジの結果をCodecovにアップロード
JestはJavaScriptのテストを実行するためのフレームワークです。
次のコマンドを実行して、NuxtアプリにJestをインストールします。
npm install --save-dev jest
次にNuxtアプリのプロジェクト直下にjest.cinfig.js
を作成します。
touch jest.config.js
作成したjest.config.js
に次の値を設定します。
module.exports = {
transform: {
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest'
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1'
},
moduleFileExtensions: ['js', 'json', 'vue']
}
次にtestsフォルダを作成します。
mkdir tests
package.json
に次のコマンドを追加します。
"scripts": {
"test": "jest --verbose ./tests",
"test-coverage": "jest --verbose ./tests --coverage"
},
次のコマンドを実行してテストを実行しましょう。
npm run test-coverage
Nuxtアプリのディレクトリ にcoverage
というフォルダが出来ていると思います。このフォルダ内のclover.xml
をCircleCIからCodecovにアップロードします。
実際には.circleci/config.yml
の以下の部分でテストの実行とアップロードを行っています。
- run:
name: RUN JUnit
command: npm run test-coverage
working_directory: frontend
### Codecovにテストカバレッジをアップロードします
- codecov/upload:
file: ./frontend/coverage/clover.xml
flags: frontend
CircleCIにpushしてみて、Codecovにテストカバレッジが表示されていれば成功です。
何か間違いやこうした方がいいよ!などがございましたら、ご指摘していただけると嬉しいです!
ありがとうございました!