こんにちは、株式会社ウイングドアの田上です。
弊社では開発業務にGitHubを使っています。
折角GitHubを使っているので、
GitHub Actionsを使ってCI(継続的インテグレーション)を実施したいなと思い、やってみました💪
今回は弊社で多いLaravel案件でも使えるように、
表題の通りGitHub Actions + LaravelでのCIを構築してみます。
GitHub Actionsとは
プッシュ、Issue、リリースなどのGitHubプラットフォームのイベントをトリガーとしてワークフローを起動しましょう。コミュニティが開発・保守し、ユーザが熟知・愛用しているサービスについて、対応するアクションを組み合わせて設定できます。
- 引用元:Actions | GitHub
 
はじめかた
GitHubにLaravelのリモートリポジトリを作成して、Actionsをクリックします。
GitHubにPHPのPJとしてサジェストされていると、[Workflows made for your PHP repository]欄に
Laravelのワークフローテンプレートが表示されているので、[Set up this workflow]を押します。
[Workflows made for your PHP repository]欄が表示されていない時は、
[Continuous integration workflows]欄の[More continuous integration workflows...]
を選択すると、Laravelのテンプレートが見つかります。
GitHub Actionsのワークフローのエディタが開くので、[Start commit] > [Commit new file]ボタンからコミットを実施。
/.github/workflows配下にワークフローのyamlファイルが作られます。
Laravelテンプレートのワークフロー
Laravelテンプレートで作られるyamlについて解説していきます。
name
name: Laravel
ワークフローの名前です。Actionsの一覧に表示されます。
on
on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]
ワークフローの実行されるタイミングを記載します。
今回のテンプレートでは
- masterへのpush
 - masterでのpull request作成
 
の二つのタイミングが記載されています。
jobs
jobs:
  laravel-tests:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2
    - name: Copy .env
      run: php -r "file_exists('.env') || copy('.env.example', '.env');"
    - name: Install Dependencies
      run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
    - name: Generate key
      run: php artisan key:generate
    - name: Directory Permissions
      run: chmod -R 777 storage bootstrap/cache
    - name: Create Database
      run: |
        mkdir -p database
        touch database/database.sqlite
    - name: Execute tests (Unit and Feature tests) via PHPUnit
      env:
        DB_CONNECTION: sqlite
        DB_DATABASE: database/database.sqlite
      run: vendor/bin/phpunit
ワークフローで実行されるジョブを記載します。
このテンプレートで行っていることは
- ubuntu-latestの仮想環境を指定
 - リポジトリをcheckout
 - Laravelの動作に必要なコマンドを実行
- .envの作成
 composer install- APP_KEYの生成
 - ディレクトリのパーミッション設定
 - データベースの作成(SQLite)
 
 PHPUnitを実行
となっています。
それぞれのステップにはnameのアトリビュートで名前がついており、
runのアトリビュートで実行されるコマンドが記載されています。
実行
試しにREADME.mdを軽く編集してmasterにpushしてみました。
GitHub Actionsのページを見ると、ワークフローが実行されています。
実行されたワークフローの詳細画面を開くと、
無事に全てのstepが終了し、PHPUnitまで実行されていることがわかります。
Laravel+MySQLの環境のテスト
既に運用中のLaravelのプロジェクトでは、
「RDBMS向けに書いたマイグレーションがSQLiteで上手く動かないよ〜🥺」
ということがあると思います。ありました😇
Laravel+MySQL用のワークフローを以下に記載しました。
設定方法については、主に以下の記事を参考にさせていただいております🙇♂️
GitHub Actions で LaravelのCI/CD環境を構築する(MySQL, Deployer)
name: UnitTest
on:
  push:
    branches:
      - master
      - 'fix/**'
      - 'feature/**'
jobs:
  laravel_test:
    name: phpunit test
    runs-on: ubuntu-latest
    services:
      mysql:
        image: mysql:8.0.19
        ports:
          - 3306:3306
        options: --health-cmd "mysqladmin ping -h localhost" --health-interval 20s --health-timeout 10s --health-retries 10
        env:
          MYSQL_ROOT_PASSWORD: password
          MYSQL_DATABASE: testdatabase
    env:
      DB_CONNECTION: mysql
      DB_HOST: 127.0.0.1
      DB_PORT: 3306
      DB_DATABASE: testdatabase
      DB_USERNAME: root
      DB_PASSWORD: password
    steps:
      - uses: actions/checkout@v2
      - name: cache vendor
        id: cache
        uses: actions/cache@v1
        with:
          path: ./vendor
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
          restore-keys: |
            ${{ runner.os }}-composer-
      - name: composer install
        if: steps.cache.outputs.cache-hit != 'true'
        run: composer install -n --prefer-dist
      - name: composer dump autoload
        run: composer dump-autoload
      - name: generate key
        run: php artisan key:generate --env=testing
      - name: migrate
        run: php artisan migrate
      - name: unit test
        run: ./vendor/bin/phpunit
MySQLのコンテナ
    services:
      mysql:
        image: mysql:8.0.19
        ports:
          - 3306:3306
        options: --health-cmd "mysqladmin ping -h localhost" --health-interval 20s --health-timeout 10s --health-retries 10
        env:
          MYSQL_ROOT_PASSWORD: password
          MYSQL_DATABASE: testdatabase
    env:
      DB_CONNECTION: mysql
      DB_HOST: 127.0.0.1
      DB_PORT: 3306
      DB_DATABASE: testdatabase
      DB_USERNAME: root
      DB_PASSWORD: password
servicesにMySQLのコンテナを記載します。
接続情報を仮想環境のenvにも追記し、LaravelのDBとして使用します。
composerのキャッシュ
      - name: cache vendor
        id: cache
        uses: actions/cache@v1
        with:
          path: ./vendor
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
          restore-keys: |
            ${{ runner.os }}-composer-
      - name: composer install
        if: steps.cache.outputs.cache-hit != 'true'
        run: composer install -n --prefer-dist
ワークフロー実行の度にcomposer installを実行するのは
時間がかかってしまいもったいないので、./vendor配下をキャッシュさせています。
2回目の実行からは画像のようにcomposer installが行われず、
キャッシュされたライブラリを用いてワークフローが動きます。
composer dump-autoloadの実行
      - name: composer dump autoload
        run: composer dump-autoload
./vendor配下をキャッシュするようにしたので、
名前空間の変更に対応するため、composer dump-autoloadを実施します。
composer dump-autoloadを実施することで、新規に追加したファイルを見つけてくれるようになります。
感想
導入は本当に簡単でした。
メジャーなフレームワークだと既にテンプレートが用意されているので、
GitHubを使っていて、CI環境を構築したい場合はGitHub Actionsが一番スマートだと思います。
ワークフローはyamlで記載するので、docker-composeを普段使いしていると馴染みやすかったです。
今回でLaravelのCIができたので次はCDにも挑戦したいです💪
どんどんワークフローを増やして手作業による属人性を減らしていけたらいいですね🤗

株式会社ウイングドアでは、Ruby on RailsやPHPを活用したwebサービス、webサイト制作を中心に、
スマホアプリや業務系システムなど様々なシステム開発を承っています。
      





