【Android】Ktlintと少しだけEditorConfigの話

こんにちは。
アドグローブ ソリューション第三事業部の濵(はま)です。
普段はAndroidアプリを開発しています。
今回の記事では、Ktlintと少しだけEditorConfigの話をさせていただきます。


lintって?

lintとは、コンピュータプログラムなどのソースコードを読み込んで内容を分析し、問題点を指摘してくれる静的解析ツール。また、そのようなツールで解析を行うこと。ツールを指す場合は “linter” (リンター)と呼ぶこともある。
lintとは - 意味をわかりやすく - IT用語辞典 e-Words

すごく雑に言えばコーディング規約を守っているかチェックしてくれるツールです。
この辺は指摘する方もされる方も嫌なので、可能な限りはツールを活用したいものです。

Ktlint

Androidアプリの開発で使用する言語は主にKotlin1です。
Kotlin用のlinter、それがKtlintです。
pinterest.github.io チェックするルールは、Kotlin公式の規約とAndroidのKotlin規約がベースになっています。

なにはともあれKtlintを入れてみる

今回はお試しとして新規でプロジェクトを作成し、Ktlintを導入してみます。
(その方が特に前提とかなく分かりやすいですしね)
Android StudioはDolphinを使用します。

テンプレートはEmptyActivity、MinimumSDKはAPI 29としました
無事にプロジェクトが作成できたら、app/build.gradleに以下を追記します。

configurations {
    ktlint
}

task ktlint(type: JavaExec, group: "verification") {
    description = "Check Kotlin code style."
    classpath = configurations.ktlint
    mainClass.set("com.pinterest.ktlint.Main")
    args "src/**/*.kt"
    // see https://pinterest.github.io/ktlint/install/cli/#command-line-usage for more information
}
check.dependsOn ktlint

dependencies {
    ktlint("com.pinterest:ktlint:0.47.1")
}

これで導入は完了です。
横に表示される ▶︎ を押して実行してみましょう。

この ▶︎ です
違反がなければタスクは成功します(逆に言えば違反があれば失敗する)。
プロジェクトを作成してからコードをいじっていないので成功して欲しいですが...
失敗するんですよ、これが
なぜ失敗したか(何が違反なのか)を調べるため、ターミナルからタスクを実行してみます。
プロジェクトのルートまで移動して以下コマンドです。

$ ./gradlew ktlint

すると...

kei: ~/Documents/android_project/Ktlint $ ./gradlew ktlint

> Task :app:ktlint FAILED
/Users/kei/Documents/android_project/Ktlint/app/src/androidTest/java/jp/co/adglobe/ktlint/ExampleInstrumentedTest.kt:1:1: File must end with a newline (\n) (final-newline)
/Users/kei/Documents/android_project/Ktlint/app/src/androidTest/java/jp/co/adglobe/ktlint/ExampleInstrumentedTest.kt:3:1: Imports must be ordered in lexicographic order without any empty lines in-between with "java", "javax", "kotlin" and aliases in the end (import-ordering)
/Users/kei/Documents/android_project/Ktlint/app/src/androidTest/java/jp/co/adglobe/ktlint/ExampleInstrumentedTest.kt:9:1: Wildcard import (cannot be auto-corrected) (no-wildcard-imports)
/Users/kei/Documents/android_project/Ktlint/app/src/test/java/jp/co/adglobe/ktlint/ExampleUnitTest.kt:1:1: File must end with a newline (\n) (final-newline)
/Users/kei/Documents/android_project/Ktlint/app/src/test/java/jp/co/adglobe/ktlint/ExampleUnitTest.kt:3:1: Imports must be ordered in lexicographic order without any empty lines in-between with "java", "javax", "kotlin" and aliases in the end (import-ordering)
/Users/kei/Documents/android_project/Ktlint/app/src/test/java/jp/co/adglobe/ktlint/ExampleUnitTest.kt:5:1: Wildcard import (cannot be auto-corrected) (no-wildcard-imports)
/Users/kei/Documents/android_project/Ktlint/app/src/main/java/jp/co/adglobe/ktlint/MainActivity.kt:1:1: File must end with a newline (\n) (final-newline)
/Users/kei/Documents/android_project/Ktlint/app/src/main/java/jp/co/adglobe/ktlint/MainActivity.kt:3:1: Imports must be ordered in lexicographic order without any empty lines in-between with "java", "javax", "kotlin" and aliases in the end (import-ordering)

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:ktlint'.
> Process 'command '/Applications/Android Studio_Dolphin.app/Contents/jre/Contents/Home/bin/java'' finished with non-zero exit value 1

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 1s
1 actionable task: 1 executed

見てみるとファイルの最終行が空行でないとか

MainActivity.kt:1:1: File must end with a newline (\n) (final-newline)

ワイルドカードインポートを使っているよとか

ExampleUnitTest.kt:5:1: Wildcard import (cannot be auto-corrected) (no-wildcard-imports)

のようですね。直していきましょう。
全て直し終えたら再度実行し、

kei: ~/Documents/android_project/Ktlint $ ./gradlew ktlint

BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed

と成功すれば導入は完了です!

だけれども従いたくないこともある

Ktlintが教えてくれる違反の中には「いやいやそれは無視でいいよ」とか、
「それはここまで緩くしてくれよ」となるものがあるかもしれません。
(1行を何文字まで許容するとか...)
特に既にコードがある状態から導入すると違反が大量発生して嫌気が差すかもしれません。
なのでルールを変える方法を少し見てみましょう。

EditorConfigの導入

まず結果が分かりやすいよう、Ktlintが違反とする状態に戻します。
(具体的にはソースファイルの最終行を空行でなくし、以下の実行結果になるようにします)

kei: ~/Documents/android_project/Ktlint $ ./gradlew ktlint

> Task :app:ktlint FAILED
/Users/kei/Documents/android_project/Ktlint/app/src/androidTest/java/jp/co/adglobe/ktlint/ExampleInstrumentedTest.kt:1:1: File must end with a newline (\n) (final-newline)
/Users/kei/Documents/android_project/Ktlint/app/src/test/java/jp/co/adglobe/ktlint/ExampleUnitTest.kt:1:1: File must end with a newline (\n) (final-newline)
/Users/kei/Documents/android_project/Ktlint/app/src/main/java/jp/co/adglobe/ktlint/MainActivity.kt:1:1: File must end with a newline (\n) (final-newline)

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:ktlint'.
> Process 'command '/Applications/Android Studio_Dolphin.app/Contents/jre/Contents/Home/bin/java'' finished with non-zero exit value 1

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 1s
1 actionable task: 1 executed

そうしたら、.editorconfigファイルをプロジェクトの直下に作成します。

こんな配置
したらばファイルの中にこんな風に記述し保存します。

# コメントアウトは#です
root = true

# 拡張子が kt または kts のファイルで
[*.{kt, kts}]
# 最終行に空行を入れない
insert_final_newline = false

この状態で再度実行します。
設定が反映されていれば、コードは手を加えなくても成功します。

kei: ~/Documents/android_project/Ktlint $ ./gradlew ktlint

BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed

Ktlint(とAndroid Studio)はEditorConfigでの設定内容を見てくれるので、最終行に空行がないことが違反でなくなる(あると逆に違反になる)わけですね。

だけどまぁ、EditorConfigで設定できる項目は少ない

EditorConfig公式 をみると設定できる項目は少ないです。
しかしながらAndroid Studio(というかIntelliJ系)で独自の設定項目が用意されており、例えば以下の設定のようにものによってはKtlintにも有効に作用します。

# org.junit.Assert.* のワイルドカードインポートは許可する
ij_kotlin_packages_to_use_import_on_demand = org.junit.Assert.*

# ちなみに↓こんな風にコメントを入れるとタスクが失敗したりするので、コメントは行を分けた方が良いです
indent_style = space # インデント方式

独自の設定項目は生憎探す時間がありませんでしたが、Android Studioで.editorconfigを編集する際に候補が表示されるのでなんとなくは設定できるかと思います。

候補を表示してくれる。えらい

最後に

いかがでしたでしょうか?
今回の記事では、KtlintとEditorConfigの話をさせていただきました。
便利なツールなので、みなさんも是非活用していただければ嬉しいです。
最後までお読みいただきありがとうございました!




現在アドグローブではエンジニアを含め、さまざまなポジションで一緒に働く仲間を募集しています。
詳細については下記からご確認ください。みなさまからのご応募お待ちしております。

hrmos.co