Help us understand the problem. What is going on with this article?

Laravel+Nuxt.jsで作っているプロジェクトにCircleCIを導入した。

こんにちは!
今作っているアプリに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.jsonlintlint-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にテストカバレッジが表示されていれば成功です。

何か間違いやこうした方がいいよ!などがございましたら、ご指摘していただけると嬉しいです!
ありがとうございました!

参考にさせていただきました

hosa_progs
4月からエンジニア。 日々気になったことをアウトプットしていけたらと思いますー 言語 Ruby,PHP,JavaScript フレームワーク Rails, Laravel, Vue.js その他 Vim, Docker, Linux
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした