最近Androidアプリを作るためにKotlinを使いました。
セミコロンのありとかなしとかそういう細かいことで悩みたくないので、自動でコードスタイルをチェックしてフォーマットしてほしいってことでLinterを導入してみました。
環境
Ubuntu 18.0.4
Kotlin 1.3.72
ktlint 0.36.0
Ktlintの導入
IntelliJ IDEAで作成したAndroidプロジェクトにKtlintを導入します。 github.com
ktlintを使用するには3パターンあります。
いろいろ試しましたが、CIを利用してプルリク時にもチェックできる仕組みを導入したかったのでGradleプラグインを利用しないで導入することにしました。
プラグインのktlint-gradleを利用する場合は、app/build.gradle
内に記述すれば利用できるようになります。
Gradle初心者なのでプロジェクトルートディレクトリのbuild.gradleとapp内にあるbuild.gradleと区別して記述するように注意します。
app/build.gradle
に記述します。
apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' android { compileSdkVersion 29 buildToolsVersion "29.0.3" defaultConfig { applicationId "com.example.androidapplication" minSdkVersion 16 targetSdkVersion 29 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } configurations { ktlint } dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.core:core-ktx:1.2.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' ktlint "com.pinterest:ktlint:0.36.0" } // ktlint settings task ktlint(type: JavaExec, group: "verification") { description = "Check Kotlin code style." classpath = configurations.ktlint main = "com.pinterest.ktlint.Main" args "src/**/*.kt", "android", "--reporter=plain", "--reporter=checkstyle,output=${buildDir}/reports/ktlint/ktlint-result.xml" ignoreExitValue true } check.dependsOn ktlint task ktlintFormat(type: JavaExec, group: "formatting") { description = "Fix Kotlin code style deviations." classpath = configurations.ktlint main = "com.pinterest.ktlint.Main" args "-F", "src/**/*.kt", "android", "--reporter=plain", "--reporter=checkstyle,output=${buildDir}/reports/ktlint/ktlint-result.xml" ignoreExitValue true }
Gradle buildに成功後、./gradlew ktlint
コマンドが使えるはずです。
デフォルトの設定の場合チェックに引っかかるとBuild FailedになりますがignoreExitValue true
を設定することで途中で終了せずに実行することができます。
./gradlew ktlintFormat
で自動でフォーマットされるようになります。
コミット時に自動でフォーマットする
プロジェクト内の.git/hooks/pre-commit
に設定すればcommit時に自動でフォーマットするようにもできます。
ktlintコマンドかgradle-ktlintプラグインを使用している場合は自動でgit hookを設定してくれるコマンドが用意されていますがプラグイン無しの場合は自分で設定する必要があります。
gradleのタスクを使用して同じようなコマンドを用意するとプロジェクトのメンバーに親切でしょう。
build.gradleに自動でgit hookを設定してくれるタスクを登録します。
task installGitHook(type: Copy) { from new File(rootProject.rootDir, 'pre-commit') into { new File(rootProject.rootDir, '.git/hooks') } fileMode 0777 } tasks.getByPath(':app:preBuild').dependsOn installGitHook
ルートディレクトリにpre-commit
ファイルを作成します。
#!/bin/bash git stash -q --keep-index echo "Running git pre-commit hook" ./gradlew ktlintFormat RESULT=$? git stash pop -q # return 1 exit code if running checks fails [ $RESULT -ne 0 ] && exit 1 exit 0
./gradlew installGitHook
コマンドを打つと作成したpre-commitファイルを.git/hooks/pre-commit
に作成し commit時に./gradlew ktlintFormat
コマンドを実行してくれるように設定できます。
ktlint CLIとプラグインの場合は実行したいファイルを引数に指定できるのですが、./gradlew ktlintFormat
をするとsrc以下の.ktファイルが全部チェックされるのでこれだと微妙ですね。ファイル数が増えるにつれ遅くなることが予想されます。
プルリクエスト時にCIでktlintでチェックするようにする
GitHub Actionでプルリクエストをしたときに自動でコードのチェックをしてくれるようにします。
Danger + ktlintでPull RequestのKotlinコードスタイルを自動チェックさせる (Travis CI編) - Qiita
こちらを参考にしました。Dangerfileを使用することでktlintに引っかかった箇所を自動でコメントしてくれます。
.github/workflow/ktlint.yml
を作成します。
name: CI on: pull_request: branches: - master jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - name: Setup ruby uses: actions/setup-ruby@v1 with: ruby-version: '2.6' architecture: 'x64' - name: install danger run: | gem install bundler bundle install --path vendor/bundle - name: run ktlint run: ./gradlew ktlint - name: run danger env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: bundle exec danger
ルートディレクトリにDangerfile
ファイルを作成します。
ktlintでチェックに引っかかった場合、app/build/reportsにレポートが作成されます。
# ktlint checkstyle_format.base_path = Dir.pwd checkstyle_format.report 'app/build/reports/ktlint/ktlint-result.xml'
ここのargsで設定した部分ですね。自分の場合はktlint-result.xml
というファイル名で出力するように設定しました。
// ktlint settings task ktlint(type: JavaExec, group: "verification") { description = "Check Kotlin code style." classpath = configurations.ktlint main = "com.pinterest.ktlint.Main" args "src/**/*.kt", "android", "--reporter=plain", "--reporter=checkstyle,output=${buildDir}/reports/ktlint/ktlint-result.xml" ignoreExitValue true }
ktlintをプラグイン無しで利用することにしたのは、gradle-ktlintのプラグインを利用した場合にこのレポートファイルの出力を設定する方法がわからなかったからです。。。
gradle-ktlintを使用すると、app/src以下のディレクトリごとに ディレクトリ名SourceSetCheck.xml
みたいにreportファイルが複数できてしまうんですよねー。
参考
Danger + ktlintでPull RequestのKotlinコードスタイルを自動チェックさせる (Travis CI編) - Qiita
Android, ktlint, and pre-commit Git Hook - Chip Cerio - Medium