AndroidのマルチモジュールでGithub Actionsを使ってLintの結果をPRのコメントに表示する方法


はじめに

はじめまして。どすこいです。
Qiita初投稿ですので、わかりにくい部分や間違っていることがあればコメントでご指摘ください。

今回、紹介するのはAndroidのマルチモジュールプロジェクトでGithub Actionsを使ってLintチェックをし、その結果をプルリクエストのコメントに表示していく方法です

個人的につまづくところがあったのでメモとして残しておきたく、投稿しました。

本記事で説明しないこと

シングルモジュールでのLintチェック。およびPRのコメント表示
Github Actionsの使い方(こちらに関してはまた今度記事にしたいと思います)

環境

まずローカルで試したいので
Rubyをインストールします。
なぜRuby?となると思いますが、後々わかります。

その後、
gem install nokogiri
gem install danger
gem install danger-android_lint

を実行してください。
nokogiriはLintファイルをまとめるためです。

Bundlerで管理しろよ!と思う方もいると思いますが、Bundlerで管理しない理由も後ほど説明します。

Lintチェック

まずマルチモジュールでのLintチェックの方法から紹介します。
ローカルの環境で、

./gradlew lintDebug

これだけでLintチェックはできます。

ただこれだけだと、各モジュールにlint-result-debug.xmlが散らばってしまいます。

そこでbuild.gradleの

build.gradle
android {
    compileSdkVersion 29
    buildToolsVersion "29.0.3"

    defaultConfig {
        applicationId "◯◯◯"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
}

この中に


lintOptions {
  xmlReport true
  xmlOutput rootProject.file("./build-report/lint-results-${project.getDisplayName()}.xml")
}

これを書くことで、build-reportsディレクトリに各モジュールのLintレポートがまとまってくれます。

Lintレポートを一つのファイルにしたい

全てのレポートをGithub Actionsで表示するのは恐らくできなくはない(筆者はやってないのでわからない)ですが、かなりめんどくさいと思います。

なので全てのLintレポートを一つのファイルにまとめましょう!

merge_linst_report.rb
require 'nokogiri'

Dir.chdir('build-reports')

new_doc = nil

Dir::glob('lint-results-*.xml') do |item|
  file = File.new(item)

  if new_doc.nil?
    new_doc = Nokogiri.XML(file)
  else
    doc = Nokogiri.XML(file)
    issues = doc.search('issue')
    new_doc.at('issues').add_child(issues)
  end
end

File.open('lint-results.xml', 'w') do |file|
  unless new_doc.nil?
    file.puts(new_doc.to_xml(indent: 4))
  end
end

上記のコードを用いてLintレポートを一つにまとめられます。

ruby ./merge_lint_report.xml
これで上記のファイルを実行すると、Lintレポートがbuild-reports/lint-results.xmlにひとまとまりになっていると思います。

Dangerの設定

今回はDangerを使ってPRのコメントにLintレポートを表示したいと思います。
https://github.com/loadsmart/danger-android_lint

dangerをインストールしたら、
danger init

をすると色々質問されますが、Enter連打でなんとかなります。
全ての質問が終わったらDangerfileが自動で生成されます。

Dangerfile
# Sometimes it's a README fix, or something like that - which isn't relevant for
# including in a project's CHANGELOG for example
declared_trivial = github.pr_title.include? "#trivial"

# Make it more obvious that a PR is a work in progress and shouldn't be merged yet
warn("PR is classed as Work in Progress") if github.pr_title.include? "[WIP]"

# Warn when there is a big PR
warn("Big PR") if git.lines_of_code > 500

# Don't let testing shortcuts get into master by accident
fail("fdescribe left in tests") if `grep -r fdescribe specs/ `.length > 1
fail("fit left in tests") if `grep -r fit specs/ `.length > 1

恐らく最初はこんな感じだと思います。

ここに

android_lint.skip_gradle_task=true
android_lint.filtering=false
android_lint.report_file = "build-reports/lint-results.xml"
android_lint.lint(inline_mode: true)

これを書き加えてあげます。これで先ほどひとまとめにしたLintレポートがDangerによってPRのコメントに表示されます。

これでローカルの設定はおわりです。

Dangerfile, merge_lint_result.xmlをGithubにpushしてあげましょう。

Githubの設定

まずはGithubの設定からです。
setting -> Developer Setting -> Personal Access Token
からトークンを発行します。

発行したトークンを現在のプロジェクトのSetting -> Secrets -> new Secretsから保存してください。

workflowファイル

Githubの設定は終わったので、今度はGithub上でこれを実行したいと思います。

lint_chech.yml
name: Lint Check CI

on:
  pull_request:
    branches: [ master ]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v1
      - name: set up Ruby
        uses: actions/setup-ruby@v1
        with:
          ruby-version: 2.6
      - name: gem install
        run: |
          gem install danger
          gem install danger-android_lint
          gem install nokogiri
      - name: Lint Check
        run: ./gradlew lintDebug
      - name: Merge Lint Reports
        run: ruby ./merge_lints_result.rb
      - name: run danger
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN}}
        run: danger

workflowファイルはこんな感じになりました。
詳しくは説明しませんが、masterブランチにPRを送ったら実行してくれます。

ローカルで試した時と同じようにまずは
nokogiri, danger, danger-android_lintをインストール

./gradlew lintDebug
でLintレポートを生成して、

先ほどpushしたmerge_lint_results.xmlを実行しLintレポートを一つのファイルにまとめる。

最後にdangerを実行してPRのコメントにLintレポートを表示する。

これで完成です!

できなかったこと

最初、筆者はGemfileから

Gemfile
gem 'nokogiri
gem `danger`
gem `danger-android_lint'

bundle install
のようにBundlerで管理しようとしたのですが、Github上のrubyのバージョンとnokogiriのバージョンが対応していないよ!と怒られたので、Bundlerで管理するのをやめて個別にインストールするようにしました。

もしこの方法ができた方がいたらコメントで教えていただけたら幸いです!

おわりに

Circle CIやBitriseでCIを実行する記事はありましたが、Github Actionsで実行している記事があまりなくかなりつまづきましたが同じようなことで困っている人のためになればと思い、記事を書きました!

今後もAndroidエンジニア向けの記事を書いていこうと思うのでどうぞよろしくお願いします。

参考にした記事

Android の開発環境へ Danger を導入するメモ [GitHub x Bitrise 編]

Android開発のコードレビューbotを乗り換えた話

AndroidのマルチモジュールでLint結果をDangerでコメントする