【初級】GitHub Actionsを使ってnuxtアプリのlint、テストを自動化する

## GitHub Actionsとは

端的にいうと、GitHubが提供してくれるサーバーレスの実行環境です。

GitHub上でのpush、issueの作成などをトリガーとしてユーザーが独自で定義したアクションを実行してくれます。

アクションは複数を順序づけて実行することが可能で、そのまとまりをワークフローと呼ばれます。

アクションは実態はdockerコンテナであり、再利用などが前提とされ、公式やAWSなどの他クラウドサービスからも様々なアクションが提供されています。

例として、`pushをしたらlintとtestを実行する`ワークフローを考えると、下記の図のようになります。

<img width="490" alt="イメージ図" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166596/92e02dc8-589f-6478-19ea-63c0f320eb70.png">

大きく3つのアクションに分けられ、実行環境上でそれらが実行されるようにユーザーがワークフローを定義します。

1. pushしたcommit番号を取得し、checkoutする
2. (npm install)を行って、lintを回す
3. testを回す

今回は試しにnuxt.jsのプロジェクトを使って、実際にワークフローを作成します。

## 環境

筆者の環境です

- node v12.14.1
- npm v6.13.4
- yarn v1.21.1
- nuxt.js v2.11.0
  - create-nuxt-appでESLint、Jestをインストールしてプロジェクトを用意しました。

記事の最後にgithubのリポジトリも載せておきます。

## 作成するワークフローの確認

今回はESLintとJestを自動で実行するようなワークフローを作成します。

実際に作ってみてのすごく個人的なワークフロー作成時のコツですが、**when(いつ), what(何をする)**で大まかな流れを考え、whatを細分化して考えるのがまとまりやすくて良いです。

今回は、**マージリクエストの作成、commit時にlintとtestを実行する**ワークフローと定義します。

lintとtestの実行とは、

1. マージリクエストの最新のcommitの取得
2. node packageのinstall
3. package.jsonに定義された、lintの実行
4. package.jsonに定義された、jestの実行

## ワークフローの作成

下記ymlが実際に作成したワークフローです。
作成するのはこの1ファイルで完結します。

```yml:.github/workflows/lint-test.yml

name: Check code using lint and test, when push a commit
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  run_lint_and_test:
    runs-on: ubuntu-18.04
    strategy:
      matrix:
        node: [ '12.14.1' ]
    timeout-minutes: 300
    steps:
      - name: checkout pushed commit
        uses: actions/checkout@v2
        with:
          ref: ${{ github.event.pull_request.head.sha }}
      - name: run lint and test
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node }}
      - run: yarn install
      - run: yarn lint
      - run: yarn test
```

他のciツールのymlなどと比べてどうかはわかりませんが、個人的にはGitHub Actionsのymlの中身は割と綺麗だと思っています。

少し要点を絞って見てみます。

### ワークフローの作成するディレクトリ

`.github/workflows/`下に作成してあげましょう。

該当ディレクトリ内のymlをGitHub Actionsの方で認識をして、ワークフローとして登録してくれます。

### 実際に作成をする方法

大きく2つあります。

1. 好きなエディターを使って自分の好きに作る。
2. 公式GUIでサンプルを基に作成する。

1に関しては自身でディレクトリを作成し、好きに作ってcommit、pushをしてあげればOKです。

2に関しては、自身のGitHubのリポジトリページからweb上でワークフローの作成が行うことができます。

- リポジトリのメニューからActionsを選択

<img width="988" alt="スクリーンショット 2020-01-13 18.42.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166596/e174e26e-4b3c-9076-31a6-0d6356217e0f.png">

- 基となるサンプルを選ぶ

<img width="1079" alt="スクリーンショット 2020-01-13 18.42.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166596/dfe9d615-d8f9-0012-3829-3e708225f9a6.png">

- web上のエディターでサンプルを書き換える

<img width="956" alt="スクリーンショット 2020-01-13 18.46.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166596/60760d2f-23d1-adcc-ad84-6e980c42fd79.png">

こんな感じでワークフローの作成も行えます。

サンプルがなかなか豊富で様々な種類あるので、一度見て書き方を理解する、その後自分で作成する、といったプロセスが良いかもしれません。

### yml内の記述

全部は説明しきれませんが、要点絞って説明します。

詳しくは[公式のドキュメント](https://help.github.com/ja/actions)があるので、そちらを読んでみてください。

#### onでトリガーを記述する

該当箇所

```yml

name: Check code using lint and test, when push a commit
on:
  # プルリクエストが作成、もしくはcommitが更新されたら実行するワークフロー
  pull_request:
    types: [opened, synchronize]
```

コメントで書いてある通り、プルリクエストが生成、プルリクエストに対してのcommitをトリガーにワークフローを実施したい場合はこのように記述します。

マージリクエストの他にももちろんGitHub上での動作を大体はトリガーにできるのではないかと思います。

- タグを作成、pushされる
- Projectが作成、削除される
- 任意の時間帯をcronのように指定

またタグやブランチ名の指定、**条件に一致したタグ名の場合のみ**などの条件指定も可能です。

#### jobsに実行したいワークフローを書いていく

該当箇所

```yml

jobs:
  run_lint_and_test:
    runs-on: ubuntu-18.04
    strategy:
      matrix:
        node: [ '12.14.1' ]
    timeout-minutes: 300
    steps:
      - name: checkout pushed commit
        uses: actions/checkout@v2
        with:
          # 該当するプルリクの最新のcommitを取得
          ref: ${{ github.event.pull_request.head.sha }}
      - name: run lint and test
        # nodeの実行環境を用意する
        uses: actions/setup-node@v1
        with:
          # nodeのバージョンはwith内で指定できる
          node-version: ${{ matrix.node }}
      - run: yarn install
      - run: yarn lint
      - run: yarn test
```

`runs-on`はワークフローの実行環境を指定します。
ubuntuとwindows、macOSから指定することが現時点で可能です。

`steps`が実行されるワークフローです。
`uses`が実行されるアクションひとつひとつになり、上から順番に実行されます。

記事書きながら、lintとtestでアクション分ける必要なくrunしてあげてもよかったのではと思います。

usesの指定の仕方は、大きく3パターンに分けられています。

1. すでに用意されているGitHubのパブリックリポジトリからの指定

GitHubの方で汎用的なアクションが用意されています。

- 指定したタグでチェックアウトする
- AWS利用のための認証

[GitHub Actions公式](https://github.com/actions)や[AWS関連](https://github.com/aws-actions)など、本当に色々用意されています。

```yml
# checkoutする
# https://github.com/actions/checkout
uses: actions/checkout@v2
# nodeの実行環境を用意する
# https://github.com/actions/setup-node
uses: actions/setup-node@v1
```

1. DockerHubで公開されているimageを指定

```yml
uses: docker://alpine:3.8
```

1. 自分でアクションを作成してパスを指定

自身でdockerfileを作成してアクションを自作することが可能です。
別の機会でこちらも紹介します。

```yml
uses: ./.github/actions/my-action
```

### runで実行するコマンドを指定する

該当箇所

```yml
      - run: yarn install
      - run: yarn lint
      - run: yarn test
```

## 動作確認

実際にnuxt.js + GitHub Actionsのサンプルを作成しました。下記リポジトリになります。

https://github.com/fussy113/nuxt-actions-sample

実際にわざとlintの通らないcommitをしてマジリクを作ってみます。

<img width="785" alt="build確認" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166596/c99295ba-650e-0938-8ee7-f85394287bbc.png">

マージリクエストの画面の、マージボタンのあたりで作成したワークフローが頑張ってくれてるのがわかります。

<img width="786" alt="lint failed" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166596/74ae36a2-67e8-546e-c202-6436c24046f1.png">

そして無事落ちましたね！無事動いて事前に問題を検知できるので良きですね！

<img width="1435" alt="スクリーンショット 2020-01-16 0.11.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166596/3d9a82ea-f467-e589-adb0-550f3d48c9f2.png">

実際になんで落ちたのか、アクションの詳細は`Actions`タブから確認することができます。
failedの要因がわかるので、debugできます。

<img width="1057" alt="スクリーンショット 2020-01-16 0.15.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/166596/5e1323b6-cb51-c058-bbe7-b5240c9c6176.png">

また`Settiings > Branches`から、指定したcheckが通らないとマージできないようにするなどの設定が可能です。

これで誤ってのマージを防ぐこともできます。安心安心。

## 終わり

いかがだったでしょうか?

- GitHubのみでこうしたCI/CDのような動きができること
- **Runner用のインスタンスを用意する必要のないこと**
- 無料枠も存在する(publicなら完全無料、privateなら2,000分/月)

やれることの幅も広いので、GitHubを利用している方に是非オススメしたいです。
普段アプリケーション側を書いている筆者もドキュメント見ながら書けて、何より自動化していくことの楽しさ、良さを改めて実感することができました。
今後も個人でちょくちょく触っていきたいです。(マージリクエストごとのプレビュー環境作ったり、Railsのrspec実行を自動化するためのAction自作などやってみます。)