47
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

GitHub ActionsでAndroidアプリのCIを構築する方法

Last updated at Posted at 2020-06-01

はじめに

GitHub Actionsを使い、Androidアプリのビルドと単体テスト、静的解析を行うCIを構築します。

本記事で書かないこと

設定ファイルの紹介

設定ファイルの内容を上から順に紹介します。

name

ワークフローの名前を設定します。

私は単純に「CI」としています。

ci.yml
name: CI

on

ワークフローを実行するトリガーを設定します。

私はGit-flowモデルで開発しており、以下のように設定しています。

ci.yml
on:
  push:
    branches:
      - main
      - develop
    paths-ignore:
      - docs/**
      - README.md
      - LICENSE
  pull_request:
    branches:
      - develop
    paths-ignore:
      - docs/**
      - README.md
      - LICENSE

他の人からPull request(以下、「PR」と呼ぶ)を頂いたときにもCIが動くように、 develop ブランチへのPRをトリガーにしています。
PRのマージ時にもCIが動くように、 developmain ブランチへのプッシュもトリガーにしています。
feature/** ブランチへのプッシュをトリガーにしていない理由は、 develop ブランチへPRを出したときにCIが二重に動作するのを防ぐためです。
早めにCIを動かしたい場合、「WIP:」を付けてPRを出します(GitHubではドラフト機能があるので、それを使うのもありです)。

README.mdLICENSE など、Androidアプリに直接関係ないファイルは、単体でコミットしてもCIが動かないようにしています。
README.md のみ更新してプッシュしてもCIが動くような気がします…。私の設定が誤っているのでしょうか?)

jobs

今回はジョブを4つ用意して並行に実行しているので、順に紹介します。

build

ビルドを実行するジョブです。

基本的には『Androidテスト全書』を参考にしてGradleタスクを実行しているだけなので、詳細は省略します。

Gradleのキャッシュは、READMEの例をそのままコピペしています。
https://github.com/actions/cache/blob/master/examples.md#java---gradle

ci.yml
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    # チェックアウト
    - uses: actions/checkout@v2

    # JDKのセットアップ
    - name: set up JDK 11
      uses: actions/setup-java@v2
      with:
        distribution: 'zulu'
        java-version: '11'

    # Gradleのキャッシュ復元
    - uses: actions/cache@v2
      with:
        path: ~/.gradle/caches
        key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
        restore-keys: |
          ${{ runner.os }}-gradle-

    # 依存関係の出力
    - name: Displays the Android dependencies of the project
      run: ./gradlew androidDependencies

    # コンパイル
    - name: Run Compile
      run: ./gradlew assembleDebug
注意
  • JDKは11を使用している
    • 8を使いたい場合は 8 を指定する

test

単体テストを実行するジョブです。

build ジョブと同様、詳細は省略します。

ci.yml
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    # チェックアウト
    - uses: actions/checkout@v2

    # JDKのセットアップ
    - name: set up JDK 11
      uses: actions/setup-java@v2
      with:
        distribution: 'zulu'
        java-version: '11'

    # Gradleのキャッシュ復元
    - uses: actions/cache@v2
      with:
        path: ~/.gradle/caches
        key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
        restore-keys: |
          ${{ runner.os }}-gradle-

    # テスト
    - name: Test with Gradle
      run: ./gradlew test --stacktrace

    # コードカバレッジをJaCoCo形式で取得
    - name: Get code coverage for JaCoCo
      run: ./gradlew jacocoDebugTestReport

    # コードカバレッジをCodecovへアップロード
    - name: Upload code coverage to Codecov
      run: bash <(curl -s https://codecov.io/bash)
      env:
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

    # テスト結果とコードカバレッジのアップロード
    - name: Upload test results and code coverage Artifact
      uses: actions/upload-artifact@v2
      if: success() || failure()
      with:
        name: results
        path: |
          **/build/reports/tests/**/*
          **/build/reports/test-results/**/*
          **/build/reports/jacoco/**/*
        if-no-files-found: warn
        retention-days: 14
注意
  • jacocoDebugTestReport タスクは自作
    • JaCoCoは別記事で説明する予定
  • CodeCovを使う場合は CODECOV_TOKEN をシークレットに追加する
    • CodeCovも別記事で説明する予定
  • テスト結果は成否にかかわらず確認したいため、アーティファクトのアップロードステップで if: success() || failure() を指定している

lint

Android Lintを使って静的解析するジョブです。

./gradlew lint を実行して結果をアップロードしているだけなので、詳細は省略します。

ci.yml
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
    # チェックアウト
    - uses: actions/checkout@v2

    # 静的解析
    - name: Run Inspection
      run: ./gradlew lint

    # 結果の表示
    - name: Show results on GitHub
      uses: yutailang0119/action-android-lint@v1
      with:
        xml_path: '**/build/reports/lint-results-*.xml'

    # アーティファクトへアップロード
    - name: Upload results Artifact
      uses: actions/upload-artifact@v2
      if: success() || failure()
      with:
        name: results
        path: |
          **/build/reports/lint-results-*.html
          **/build/reports/lint-results-*.xml
        if-no-files-found: error
        retention-days: 14
注意
  • 結果のファイル名は lint-results.* から lint-results-{Build variant}.* に変更された
    • おそらくGradle 7から
  • yutailang0119/action-android-lint アクションでGitHub上のファイルに指摘を表示している

detekt

detekt を使って静的解析するジョブです。

./gradlew detekt を実行して結果をアップロードしているだけなので、詳細は省略します。

ci.yml
jobs:
  detekt:
    runs-on: ubuntu-latest
    steps:
    # チェックアウト
    - uses: actions/checkout@v2

    # 静的解析
    - name: Lint with detekt
      run: ./gradlew detekt

    # アーティファクトへアップロード
    - name: Upload results Artifact
      uses: actions/upload-artifact@v2
      if: failure()
      with:
        name: results
        path: |
          **/build/reports/detekt/**/*
        if-no-files-found: error
        retention-days: 14

Android Lintにはない観点で静的解析するため、両方とも使うのがオススメです。

ktlint

ktlint を使って静的解析するジョブです。

ktlint を実行して結果をアップロードしているだけなので、詳細は省略します。

ci.yml
jobs:
  ktlint:
    runs-on: ubuntu-latest
    steps:
    # チェックアウト
    - uses: actions/checkout@v2

    # インストール
    - name: Install ktlint
      run: |
        curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.42.1/ktlint
        chmod a+x ktlint
        sudo mv ktlint /usr/local/bin/

    # 静的解析
    - name: Lint with ktlint
      run: ktlint --reporter=checkstyle,output=build/ktlint-report.xml
      continue-on-error: true

    # 結果の表示
    - name: Show results on GitHub
      uses: yutailang0119/action-ktlint@v1
      with:
        xml_path: build/ktlint-report.xml

    # アーティファクトへアップロード
    - name: Upload results Artifact
      uses: actions/upload-artifact@v2
      if: failure()
      with:
        name: results
        path: |
          **/build/ktlint-report.xml
        if-no-files-found: error
        retention-days: 14
注意
  • yutailang0119/action-ktlint アクションでGitHub上のファイルに指摘を表示している

設定ファイルの全体図

最後に設定ファイルの全体図を載せます。

ci.yml
name: CI

on:
  push:
    branches:
      - main
      - develop
    paths-ignore:
      - docs/**
      - README.md
      - LICENSE
  pull_request:
    branches:
      - develop
    paths-ignore:
      - docs/**
      - README.md
      - LICENSE

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    # チェックアウト
    - uses: actions/checkout@v2

    # JDKのセットアップ
    - name: set up JDK 11
      uses: actions/setup-java@v2
      with:
        distribution: 'zulu'
        java-version: '11'

    # Gradleのキャッシュ復元
    - uses: actions/cache@v2
      with:
        path: ~/.gradle/caches
        key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
        restore-keys: |
          ${{ runner.os }}-gradle-

    # 依存関係の出力
    - name: Displays the Android dependencies of the project
      run: ./gradlew androidDependencies

    # コンパイル
    - name: Run Compile
      run: ./gradlew assembleDebug

  test:
    runs-on: ubuntu-latest
    steps:
    # チェックアウト
    - uses: actions/checkout@v2

    # JDKのセットアップ
    - name: set up JDK 11
      uses: actions/setup-java@v2
      with:
        distribution: 'zulu'
        java-version: '11'

    # Gradleのキャッシュ復元
    - uses: actions/cache@v2
      with:
        path: ~/.gradle/caches
        key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
        restore-keys: |
          ${{ runner.os }}-gradle-

    # テスト
    - name: Test with Gradle
      run: ./gradlew test --stacktrace

    # コードカバレッジをJaCoCo形式で取得
    - name: Get code coverage for JaCoCo
      run: ./gradlew jacocoDebugTestReport

    # コードカバレッジをCodecovへアップロード
    - name: Upload code coverage to Codecov
      run: bash <(curl -s https://codecov.io/bash)
      env:
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

    # テスト結果とコードカバレッジのアップロード
    - name: Upload test results and code coverage Artifact
      uses: actions/upload-artifact@v2
      if: success() || failure()
      with:
        name: results
        path: |
          **/build/reports/tests/**/*
          **/build/reports/test-results/**/*
          **/build/reports/jacoco/**/*
        if-no-files-found: warn
        retention-days: 14

  lint:
    runs-on: ubuntu-latest
    steps:
    # チェックアウト
    - uses: actions/checkout@v2

    # 静的解析
    - name: Run Inspection
      run: ./gradlew lint

    # 結果の表示
    - name: Show results on GitHub
      uses: yutailang0119/action-android-lint@v1
      with:
        xml_path: '**/build/reports/lint-results-*.xml'

    # アーティファクトへアップロード
    - name: Upload results Artifact
      uses: actions/upload-artifact@v2
      if: success() || failure()
      with:
        name: results
        path: |
          **/build/reports/lint-results-*.html
          **/build/reports/lint-results-*.xml
        if-no-files-found: error
        retention-days: 14

  detekt:
    runs-on: ubuntu-latest
    steps:
    # チェックアウト
    - uses: actions/checkout@v2

    # 静的解析
    - name: Lint with detekt
      run: ./gradlew detekt

    # アーティファクトへアップロード
    - name: Upload results Artifact
      uses: actions/upload-artifact@v2
      if: failure()
      with:
        name: results
        path: |
          **/build/reports/detekt/**/*
        if-no-files-found: error
        retention-days: 14

  ktlint:
    runs-on: ubuntu-latest
    steps:
    # チェックアウト
    - uses: actions/checkout@v2

    # インストール
    - name: Install ktlint
      run: |
        curl -sSLO https://github.com/pinterest/ktlint/releases/download/0.42.1/ktlint
        chmod a+x ktlint
        sudo mv ktlint /usr/local/bin/

    # 静的解析
    - name: Lint with ktlint
      run: ktlint --reporter=checkstyle,output=build/ktlint-report.xml
      continue-on-error: true

    # 結果の表示
    - name: Show results on GitHub
      uses: yutailang0119/action-ktlint@v1
      with:
        xml_path: build/ktlint-report.xml

    # アーティファクトへアップロード
    - name: Upload results Artifact
      uses: actions/upload-artifact@v2
      if: failure()
      with:
        name: results
        path: |
          **/build/ktlint-report.xml
        if-no-files-found: error
        retention-days: 14

シンプルなYAMLファイルなので、慣れれば読みやすいと思います。

おわりに

GitHub Actionsで基本的なAndroidアプリのCIを回すことができました!

参考リンク

47
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
47
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?