これは ゆめみ Advent Calendar 2018 の5日目の投稿です。
いまさら感があるのですが、先日にとある Android プロジェクトへ ktlint を導入する機会があったので、その手順をここに残したいと思います。これから導入しようと考えられている方の参考になれば。
前提
- Android Studio:
3.2.1
- ktlint:
0.29.0
ktlint とは
ktlint の README にも書いてありますが、kotlinlang.org と Android Kotlin Style Guide のスタイルガイドを元にコードスタイルのチェックをしてくれる Kotlin 用の Linter です。Gradle のタスクとしてコマンドラインで実行できるので、CI に組み込めたりします。
(追記:CI への組み込みについては GitHub のプルリクエストを Bitrise x Danger x ktlint で自動レビューする に書きました。)
導入
Gradle への導入方法は ktlint の README のとおりですが、例えば Android Studio で新規にプロジェクトを作成した直後の app/build.gradle
に導入(プラグインを使わない方法での導入)すると次のようになります。
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 28
defaultConfig {
applicationId "io.github.hkusu.myapplication"
minSdkVersion 19
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
+ configurations {
+ ktlint
+ }
+ dependencies {
+ ktlint "com.github.shyiko:ktlint:0.29.0"
+ }
+ task ktlint(type: JavaExec, group: "verification") {
+ description = "Check Kotlin code style."
+ classpath = configurations.ktlint
+ main = "com.github.shyiko.ktlint.Main"
+ args "src/**/*.kt"
+ }
+ check.dependsOn ktlint
+ task ktlintFormat(type: JavaExec, group: "formatting") {
+ description = "Fix Kotlin code style deviations."
+ classpath = configurations.ktlint
+ main = "com.github.shyiko.ktlint.Main"
+ args "-F", "src/**/*.kt"
+ }
ktlint のオプションを変更する場合は上記の args
のところを変更します。例えば出力をカラフルにする場合は、args "src/**/*.kt"
の箇所を args "--color", "src/**/*.kt"
とします。参考までに、私の最近のプロジェクトでは、次のようなタスクにしています。
task ktlint(type: JavaExec, group: "verification") {
description = "Check Kotlin code style."
classpath = configurations.ktlint
main = "com.github.shyiko.ktlint.Main"
args "--android", "--color", "--reporter=plain", "--reporter=checkstyle,output=${buildDir}/reports/ktlint-results.xml", "src/**/*.kt"
ignoreExitValue true
}
--android
--color
オプションを追加してるのと、CI 用に checkstyle 形式での出力を追加&チェックにひっかかっても異常終了させない(ignoreExitValue true
)ようにしています。もし手元での lint の実行と CI 上のものでオプションを分けたい場合は、タスクを分ければいいです。
またプロジェクトディレクトリの直下に .editorconfig
ファイルを作成し、追加のルールを指定しておくと良いでしょう。これはファイル末尾に改行が入ってるかのチェックと、コード一行の文字数のチェックです。(ちなみに弊社では最大文字数が Android Studio のデフォルト値?の 100
だとなかなか辛いものがあるので 128
にしています。)
[*.{kt,kts}]
insert_final_newline=true
max_line_length=128
Lint の実行
プロジェクトのルートディレクトリで $ ./gradlew ktlint
を実行します。結果が出力されます。
ちなみに $ ./gradlew ktlintFormat
でコード修正までやってくれるようですが、個人的にはまだ使ってません。
Android Studio のコードスタイル
ktlint でチェックができるとはいえ、ある程度は Android Studio のコードスタイルで自動整形されり、フォーマット時に自動修正されるようにしておきたいものです。
ktlint の README を見ると、次のようにおすすめの設定方法が書いてあります。
(https://github.com/shyiko/ktlint から引用)「Option #1」の方法は、コマンドライン版の ktlint(Gradle でなく curl で導入した ktlint)で実行でき、Android プロジェクトで実行すると、おすすめ設定が反映された下記の5ファイルが生成されます。
- .idea/codeStyles/codeStyleConfig.xml
- .idea/codeStyles/Project.xml
- .idea/inspectionProfiles/profiles_settings.xml
- .idea/inspectionProfiles/ktlint.xml
- .idea/workspace.xml
「Option #2」の方法は、「#1」の設定を手動でやる方法です。
個人的には「#1」の方法で自動生成されるのはなんとなく気持ち悪いし、それだけの為にコマンドライン版の ktlint を導入するのも嫌なので、「#2」の方法で十分かなと思います。
Continuation indent について
これは改行時のインデントのスペース数なのですが、上記のおすすめ設定では通常のインデントと同じ 4
となっています(Android Stuio のデフォルトは 8
)。個人的には改行時のインデントは 8
として通常のインデントと区別した方がよいと思うので 8
のままにしています。
もし 8
スペースで困るケースがあるなら、そもそも「Continuation indent」として扱うか否かを見直した方が良いというスタンスです。これは Android Studio のコードスタイルの設定で、下図のように各ケースについて制御できます。
感想
ktlint の場合、Lint のルールを個別に ON/OFF できる機能はないんですよね(もし勘違いならすみません)。いままで ktlint を導入していなかったプロジェクトへ導入して Lint をかけると大量にエラーになるし、Lint のルールはプロジェクト毎に決めればいいんじゃないか、と初めは思ったりもしました。
が、今は、個別のルールを ON/OFF できない事が逆に良い、と思っています。プロジェクト毎に適用するルールの検討で悩まなくていいし、プロジェクト間でルールに差異が生まれないからです。ktlint でこう決まってるから有無をいわず粛々と対応するだけ、という状況は、ある意味 楽でいいな〜と感じています。
あと、仮に ktlint を導入しない場合でも、Kotlin でコードを書くなら 「Option #2」の方法でも説明されている「Kotlin style guide」の導入はしておくと良いかなと思います。せっかく Android Studio が標準で用意しているものなので。