[Qodana] [Android静的解析] GitHubのPull Requestに対してAndroid StudioのCode Inspectionsを自動実行する
はじめに
NTTレゾナントテクノロジーの西添です。モバイルアプリエンジニアをやっています。
以前、Android StudioのCode Inspections機能について紹介しました。
この機能は命名規則、冗長な記述、未使用の定義、バグになりそうな箇所を指摘してくれたり、よりKotlinらしいコードにするための提案をしてくれたりします。
ktlintやAndroid Lintには無いような検査ルールが豊富に搭載されており、コード品質を担保する上で非常に重宝しています。
このCode Inspectionsを自動化して開発フローに組み込めたら、常にキレイなコードを維持するのに役立ちそうですよね。
そこで今回は、GitHubのPull Requestの自動コードレビューの一環としてCode Inspectionsを自動で実行する方法を紹介したいと思います。
完成形
GitHubでPull Requestを作成すると変更されたファイルに対して自動的にCode Inspectionsが実行され、結果が[File changed]タブにアノテーションとして表示されるようになります。
また、Pull Requestに対して新しいコミットをプッシュするとCode Inspectionが再実行され、新たな実行結果がアノテーションされます。
実現方法
タイトル詐欺になってしまいますが、Android StudioではなくQodanaを使用します。
Android Studioを使わないの?と疑問に思われた方、安心してください。
Andoird StudioはJetBrains社のIntelliJ IDEAをベースにしたIDEですが、Qodanaは同じくJetBrains社が開発したコード品質監視プラットフォームで、JetBrains製のIDEのCode Inspections機能をCI/CDに導入することを目的とした製品です。
2023年3月時点ではまだEAP (JetBrains' Early Access, Beta, Preview and Nightly Programs) の段階ですが、今回紹介する範囲では無料で使用することができます。
Qodana本体はDockerイメージとして提供されています。
Dockerイメージのラッパーとして動くCLIツールや、さらにCLIツールのラッパーとして動くCIのプラグイン(GitHub Actions、CircleCIなど)も公式で提供されています。
今回はQodanaのGitHub Actionsを使用して、GitHubのPull Requestに対して自動でCode Inspectionsを実行する仕組みを作成します。
前提条件
これから紹介する設定方法では、AndroidプロジェクトがGitリポジトリのルートディレクトリ上に存在することを前提としています。
git-repository
├── .git/
├── .gitignore
├── .gradle/
├── .idea/
├── app/
├── build/
├── build.gradle
├── gradle/
├── gradle.properties
├── gradlew*
├── gradlew.bat
├── local.properties
└── settings.gradle
次のようにAndroidプロジェクトがGitリポジトリのサブディレクトリ上に存在する場合(Monorepoなど)はQodanaが想定通りに動作しません(2023年3月時点)。
このような場合は特殊なワークアラウンドが必要になるため、別の機会に設定方法を紹介したいと思います。
git-repository
├── .git/
└── MyApplication/
├── .gitignore
├── .idea/
├── app/
├── build.gradle
├── gradle/
├── gradle.properties
├── gradlew*
├── gradlew.bat
└── settings.gradle
設定方法
1. GitHub Actionsのワークフロー設定
まずはGitHub Actionsのワークフローを作成します。
Gitリポジトリに .github/workflows/qodana.yml ファイルを作成し、中身を以下のようにします。
name: Qodana
on:
workflow_dispatch:
pull_request:
jobs:
qodana:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: 'Qodana Scan'
uses: JetBrains/qodana-action@v2022.3.4
ほぼ公式ドキュメントのままですが、トリガーからpushを削除し、Pull Requestがまだドラフトの状態のときは実行しないように if: github.event.pull_request.draft == false を追記してあります。
なお、JetBrains/qodana-action のデフォルト設定では次の機能が有効になっています。
pr-mode: Pull Requestで変更されたファイルだけを検査対象にするモードです。プロジェクト全体を検査すると時間がかかるため、ぜひ有効化しておきたい機能です。
use-annotations: 検知された問題をGitHub上にAnnotationとして表示する機能です。Pull Requestの[File changed]タブで該当コードのすぐ下に検知内容が表示されるようになります。
use-caches: キャッシュ機能です。特にAndroidプロジェクトではGradleの依存関係のダウンロードに時間がかかるため、必須機能です。
upload-result: 検査結果をArtifactとしてアップロードする機能です。HTML形式やSARIF JSON形式の検査結果、Qodanaの実行ログなどが保存されています。
詳細については JetBrains/qodana-action のREADMEをお読みください。
2. Qodanaの設定
次にプロジェクトのルートディレクトリにQodanaの設定ファイル qodana.yaml を作成します。
linter: jetbrains/qodana-jvm-android:2022.3-eap
projectJDK: 11
profile:
name: Project Default
disableSanityInspections: true
exclude:
- name: SpellCheckingInspection
各行について簡単に説明します。
linter: jetbrains/qodana-jvm-android:2022.3-eap
QodanaのDockerイメージを指定しています。
Androidプロジェクトですので qodana-jvm-android を指定していますが、この他にもPHP用やPython用などがあったりします。
projectJDK: 11
これを記述しておかないと
com.intellij.openapi.externalSystem.service.execution.ExternalSystemJdkException: Invalid Gradle JDK configuration found.
というエラーが発生して検査が実行されません。
profile:
name: Project Default
Code Inspectionのカスタムプロファイルを指定しています。
これを指定しない場合はQodanaのデフォルトのプロファイルで検査が実行されますが、検査ルールがAndroid StudioのCode Inspectionのデフォルト設定よりもかなり少ないため、正直オススメできません。
また、Android Studioのデフォルトのプロファイルで検査したい場合は、 name: Default と指定するとそれに近いプロファイルになると思います(厳密にはIntelliJ IDEAのバージョンが異なるため差異があります)。
ここで指定している Project Default については作成方法を後述します。
disableSanityInspections: true
Qodanaの Sanity Check 機能を無効化しています。
Sanity Checkは全てのルールを検査する前の段階でプロジェクトの健全性をチェックするための機能です。
特に必要性を感じないため無効化しています。
exclude:
- name: SpellCheckingInspection
実行したくない検査ルールを指定しています。
SpellCheckingInspectionはタイプミスを指摘してくれるルールですが、プロジェクト固有の用語が誤検知されがちですので無効化しています。
※Code Inspectionのプロファイルで無効化するとAndroid Studioのエディタ上の警告も表示されなくなってしまうため、Qodanaだけが無効化されるようにqodana.yamlのexcludeで設定しています。
3. (任意)プロファイルの設定
必須ではありませんが、検査ルールをカスタマイズしたい場合はCode Inspectionsのプロファイルを作成します。
まずAndroid Studioで検査対象のプロジェクトを開き、メニューバー > [Android Studio] > [Preferences...] で設定画面を開きます。
次に、左ペインで [Editor] > [Inspections] と選択します。
設定画面上部にある Profile: のプルダウンメニューは初期値として Project Default が選択されていると思います。
Project Default 以外の名前でプロファイルを作成したい場合は歯車マークを押して [Duplicate...] を選択し、任意の名前のプロファイルを作成してください。
Qodanaの設定ファイル(qodana.yaml)の profile.name で指定するのはこの画面の Profile: 欄に表示されている名前です。
各ルールのチェックボックスのON/OFFを変更してOKボタンを押すと .idea/inspectionProfiles/Project_Default.xml ファイルが作成されます。
例:
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="NonAsciiCharacters" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="TestFunctionName" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
</profile>
</component>
以上で設定は完了です。
実行時間
Android Studioで新規作成したプロジェクトで実行してみたところ、キャッシュが無い状態では7分程度、キャッシュがある状態では5分程度かかりました。キャッシュが無い状態ではGradleのダウンロードなどの通信にかなり時間がかかるため、依存パッケージが多いプロジェクトではもっと時間がかかりそうです。
まとめ
今回は、GitHubのPull Requestに対してAndroid StudioもといQodanaでコードの静的解析を自動実行する方法を紹介しました。皆さんのコード品質改善の一助になれば幸いです。
宣伝
NTTレゾナントテクノロジーでは一緒に働いてくれるAndroid/iOSアプリエンジニアを募集中です。もし興味がありましたら採用ページを是非ご覧ください。