ktlintとは
Kotlinのリンターで、フォーマッターも内蔵している
モチベーション
開発チームでコードスタイルを統一する
便利に感じた点
- 設定ファイルを作成することなく公式コードスタイルを適応できる
- Gradleプラグインを公開している
- CIと統合できる
Hands-on
動作環境
- windows 10
- Spring Boot 2.6.7
- Kotlin
spring initializrでGradleプロジェクトを作成
spring initializrでGradleプロジェクトを作成する
設定済みのリンク
ktlintのGradleプラグインを追加
統合開発環境で開きbuild.gradle.ktsにJLLeitschuh/ktlint-gradleを追加する
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "2.6.7"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
+ id("org.jlleitschuh.gradle.ktlint") version "10.3.0"
kotlin("jvm") version "1.6.21"
kotlin("plugin.spring") version "1.6.21"
}
コードスタイルの検証
> gradlew ktlintCheck
or
> gradlew check
検証に失敗しているときコンソールに出力される
C:\Users\Umizoko\Downloads\demo\demo>gradlew ktlintCheck
> Task :ktlintKotlinScriptCheck FAILED
C:\Users\Umizoko\Downloads\demo\demo\build.gradle.kts:4:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\build.gradle.kts:5:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\build.gradle.kts:6:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\build.gradle.kts:7:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\build.gradle.kts:8:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\build.gradle.kts:16:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\build.gradle.kts:20:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\build.gradle.kts:21:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\build.gradle.kts:22:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\build.gradle.kts:23:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\build.gradle.kts:27:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\build.gradle.kts:28:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\build.gradle.kts:29:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\build.gradle.kts:30:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\build.gradle.kts:34:1 Unexpected tab character(s)
> Task :ktlintMainSourceSetCheck FAILED
C:\Users\Umizoko\Downloads\demo\demo\src\main\kotlin\com\example\demo\DemoApplication.kt:10:1 Unexpected tab character(s)
> Task :ktlintTestSourceSetCheck FAILED
C:\Users\Umizoko\Downloads\demo\demo\src\test\kotlin\com\example\demo\DemoApplicationTests.kt:9:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\src\test\kotlin\com\example\demo\DemoApplicationTests.kt:10:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\src\test\kotlin\com\example\demo\DemoApplicationTests.kt:11:1 Unexpected tab character(s)
C:\Users\Umizoko\Downloads\demo\demo\src\test\kotlin\com\example\demo\DemoApplicationTests.kt:12:1 Unexpected blank line(s) before "}"
FAILURE: Build completed with 3 failures.
...
BUILD FAILED in 1s
7 actionable tasks: 3 executed, 4 up-to-date
違反したコードを自動フォーマットする
> gradlew ktlintCheck
BUILD SUCCESSFUL in 5s
7 actionable tasks: 6 executed, 1 up-to-date
GitHub Actionsのワークフローでコードスタイルを検証し、違反がある場合は落とす
Gradle Build Actionを利用してワークフローを設定する
.github/workflows/check_workflow.yaml
name: Run Gradle on PRs
on: pull_request
jobs:
gradle:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
- name: Change Permission
run: chmod +x ./gradlew
- name: Execute Gradle check
run: ./gradlew check
違反したコードでPRを出してワークフローのチェックが落ちるか確認する
> git branch illegal-code-style
> git switch illegal-code-style
コードスタイルを違反したファイルを追加
package com.example.demo.domain.article
class Article private constructor(
val id: String,
var title: String,
val description: String
){
fun changeTitle(title: String) {
this.title = title
}
}
> git push --set-upstream origin illegal-code-style
GitHubからmasterブランチに対してPRを作成する
GitHubのワークフローがktlintの違反で落ちていることを確認
Run ./gradlew check
Downloading https://services.gradle.org/distributions/gradle-7.4.1-bin.zip
...........10%...........20%...........30%...........40%...........50%...........60%...........70%...........80%...........90%...........100%
Welcome to Gradle 7.4.1!
...
> Task :ktlintMainSourceSetCheck FAILED
/home/runner/work/learn-ktlint/learn-ktlint/src/main/kotlin/com/example/demo/domain/article/Article.kt:1:1 File must end with a newline (\n)
/home/runner/work/learn-ktlint/learn-ktlint/src/main/kotlin/com/example/demo/domain/article/Article.kt:7:1 Unexpected indentation (8) (should be 0)
/home/runner/work/learn-ktlint/learn-ktlint/src/main/kotlin/com/example/demo/domain/article/Article.kt:7:9 Unexpected indentation (expected 0, actual 8)
/home/runner/work/learn-ktlint/learn-ktlint/src/main/kotlin/com/example/demo/domain/article/Article.kt:7:10 Missing spacing before "{"
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':ktlintMainSourceSetCheck'.
> A failure occurred while executing org.jlleitschuh.gradle.ktlint.worker.ConsoleReportWorkAction
> KtLint found code style violations. Please see the following reports:
> Task :compileKotlin
6 actionable tasks: 6 executed
- /home/runner/work/learn-ktlint/learn-ktlint/build/reports/ktlint/ktlintMainSourceSetCheck/ktlintMainSourceSetCheck.txt
* 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 1m 15s
Error: Process completed with exit code 1.
自動フォーマットを実行してリモートリポジトリを更新すると、ワークフローがパスする
Run ./gradlew check
To honour the JVM settings for this build a single-use Daemon process will be forked. See https://docs.gradle.org/7.4.1/userguide/gradle_daemon.html#sec:disabling_the_daemon.
Daemon will be stopped at the end of the build
> Task :loadKtlintReporters
> Task :runKtlintCheckOverKotlinScripts
> Task :ktlintKotlinScriptCheck
> Task :runKtlintCheckOverMainSourceSet
> Task :ktlintMainSourceSetCheck
> Task :runKtlintCheckOverTestSourceSet
> Task :ktlintTestSourceSetCheck
> Task :processResources
> Task :processTestResources NO-SOURCE
> Task :compileKotlin
> Task :compileJava NO-SOURCE
> Task :classes
> Task :compileTestKotlin
> Task :compileTestJava NO-SOURCE
> Task :testClasses UP-TO-DATE
> Task :test
> Task :check
BUILD SUCCESSFUL in 27s
11 actionable tasks: 11 executed
まとめ
ktlintをwrapperしたプラグインを導入することで、ローカルで自動フォーマットを実行することができ、GitHub ActionsでPRをトリガーにリンターでの検証を行うことで、プロジェクトのコードスタイルを統一することができた。
使用したリポジトリ: https://github.com/Umizoko/learn-ktlint