GitHub Actionsでテスト、lint、カバレッジ計測

この記事は[MicroAd \(マイクロアド\) Advent Calendar 2020 \- Qiita](https://qiita.com/advent-calendar/2020/microad)の2日目の記事です。

---

# やること
`GitHub Actions`で`Java`/`Kotlin`製ライブラリ（ビルドツールは`gradle`）の`CI`環境を構築します。
具体的には、以下2項目を行います。

- `PR`を出した際にテストと`lint`を走らせる
- カバレッジを計測する

## サンプルプロジェクトの内容
サンプルコードには以下の加算コードとそのテストコードなどが含まれています。

```kotlin:プロダクションコード
package com.wrongwrong

fun myAdd(a: Double, b: Double) = a + b
```

コード全体は以下で公開しています。

- [k163377/GitHubActionsSampleLib](https://github.com/k163377/GitHubActionsSampleLib)

## テンプレートについて
ワークフローの基本的なテンプレートは[`https://github.com/${ユーザー}/${リポジトリ}/actions/new`に公開されている](https://github.com/k163377/GitHubActionsSampleLib/actions/new)ため、基本的にこれをコピペする形で話を進めます。

# `PR`を出した際にテストと`lint`を走らせる
テストと`lint`は`./gradlew`から呼び出す形で実行するのが簡単です。

## テストを走らせる
まずテストを走らせてみます。
`Java with Gradle`テンプレートを参考に、`${プロジェクトルート}/.github/workflows/ci.yml`を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280230/4d2b3f53-1741-28ce-d1e3-502ecda12608.png)

内容に関しては、`run: ./gradlew test`でテストを呼び出していることが分かれば一旦大丈夫だと思います。

```yml:ci.yml
# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle

name: Test with Gradle

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
      - name: Set up JDK 1.8
        uses: actions/setup-java@v1
        with:
          java-version: 1.8
      - name: Grant execute permission for gradlew
        run: chmod +x gradlew
      - name: Test with Gradle
        run: ./gradlew test
```

これによりテストが走るようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280230/5841c405-d234-391e-dcd9-2edab06d02ef.png)

## lintを走らせる
次に`lint`を走らせます。
`lint`は`ktlint gradle plugin`(`org.jlleitschuh.gradle.ktlint`)を用いて行います。

```kotlin:build.gradle.kts（抜粋）
plugins {
    kotlin("jvm") version "1.4.10"
    id("org.jlleitschuh.gradle.ktlint") version "9.4.1" // 追加
}
```

ワークフロー設定は、`run: ./gradlew ktlint`するだけで行えます。
今回はテストの前に`lint`を走らせる形としました。

```yml:ci.yml（抜粋）
        run: chmod +x gradlew
      # 下2行を追記
      - name: ktlint check
        run: ./gradlew ktlintCheck
      - name: Test with Gradle
        run: ./gradlew test
```

試しに`lint`が引っかかる状態で実行した結果が以下です。
`ktlint check`が追加され、失敗しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280230/95038116-fbfe-acac-0579-ab9af01dfcd5.png)

## バッジを表示する
テストや`lint`が出来たので、`README`にそのステータスバッジを出します。
バッジは当該ワークフローから`Create status budge`すれば取得できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280230/7b897481-8484-b2a0-a324-c45014017cb0.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280230/e1f74c19-d50d-45b9-6f43-19f2a1f084fd.png)

# 2. カバレッジを計測する
続いてテストのカバレッジを計測します。
今回は`JaCoCo`で生成したカバレッジファイルを`Codecov`にアップロードする形でこれを行います。

## JaCoCo関連の設定
まず`JaCoCo`関連の設定を追加します。
詳しい説明は[以前書いた記事の中で説明した](https://qiita.com/wrongwrong/items/3d6dd806558bacf30a1b#jacoco%E3%81%AB%E3%82%88%E3%82%8B%E3%83%AC%E3%83%9D%E3%83%BC%E3%83%88%E3%81%AE%E5%87%BA%E5%8A%9B%E8%A8%AD%E5%AE%9A)ためここでは省略します。

```kotlin:build.gradle.kts（JaCoCo関連の抜粋）
/* 略 */

plugins {

    /* 略 */

    id("jacoco")
}

/* 略 */

tasks {

    /* 略 */

    jacocoTestReport {
        reports {
            xml.isEnabled = true
            csv.isEnabled = false
            html.isEnabled = true
        }
    }
    test {
        useJUnitPlatform()
        // テスト終了時にjacocoのレポートを生成する
        finalizedBy(jacocoTestReport)
    }
}
```

ローカルで`./gradlew test`した際に`${プロジェクトルート}/build/reports/jacoco/`にテストレポートが吐き出されていれば`JaCoCo`関連の設定は完了です。

## Codecovのセットアップ
`Codecov`のセットアップに関しても、[以前書いた記事の中で詳しく説明した](https://qiita.com/wrongwrong/items/3d6dd806558bacf30a1b#codecov%E3%81%AE%E8%A8%AD%E5%AE%9A)ためここでは省略します。
`Repository Upload Token`が取得できれば完了です。

## GitHub Actionsの設定
### Repository Upload TokenをリポジトリのSecretsに追加
リポジトリの`Settings` -> `Secrets` -> `New repository secret`に先ほど生成した`Repository Upload Token`を設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280230/216b31dd-f8d8-b435-9498-cda9d5d4b083.png)

キーの名前は後述するワークフローの設定で参照できれば何でもよいと思いますが、今回は`CODECOV_TOKEN`とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280230/b5e1a402-745d-6647-4f39-65bfcfac3e85.png)

### ワークフローの設定
以下4行を追加することでアップロードが行われるようになります。

```yml:ci.yml（抜粋）
        run: chmod +x gradlew
      - name: ktlint check
        run: ./gradlew ktlintCheck
      - name: Test with Gradle
        run: ./gradlew test
      # 下4行を追記
      - name: upload coverage
        uses: codecov/codecov-action@v1
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
```

この状態でPRを作成することで、`codecov`関係が動くようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280230/e85045ea-845d-2f5f-b2f8-e232c10ed238.png)

結果は以下のように確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280230/38ea4d01-98ba-d759-0389-4f786a48da0a.png)

テスト無しで関数を1つ追加した様子が以下です。
カバレッジが落ちていることが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/280230/abd8fe08-f1bf-40fb-0bcc-3167738a73c8.png)

# 終わりに
`GitHub Actions`で`Java`/`Kotlin`製ライブラリ（ビルドツールは`gradle`）の`CI`環境を構築してみました。

感想としては「連携等で必要な操作も最低限で超簡単だしマジぱねえ」という感じです。
個人開発に関しては`Circle CI`からの乗り換えを決断しました。

仕事で使っている`GitHub Enterprise`については記事執筆時点（11/24）で`Actions`がまだ来ていませんが、2020中に来る来るという話なので、今から楽しみにしています。

明日は@yassan168による`Hadoop`ネタの記事です。

# 参考にさせて頂いた記事
- [GitHub Actionsのバッジをリンク付きでREADMEに追加する \- Qiita](https://qiita.com/akameco/items/e474691964703033e18d)
- [GitHub Actions でテストカバレッジを取得する \| ふらっと Flutter](https://flutter.takuchalle.dev/posts/how-to-test-coverage-on-github-actions/)