skip to content
私的歌詞倉庫

マルチモジュールなプロジェクトでdetektをComposite Buildsにまとめて各モジュールに適用する

/ 6 min read

Updated:
Table of Contents

はじめに

Kotlin向けの静的解析ツールにdetektというツールがあります。今回はフォーマッターとしてdetektをマルチモジュールなプロジェクトに適用したいと思い使ってみました。

Hello from detekt | detekt

普通に各モジュールに適用するだけでもいいのですが設定を各モジュールに書くと大変なので、GradleのComposite Buiildsを使ってdetektの設定をプラグインとして切り出し、各モジュールは切り出した自作プラグインを適用するだけにします。

Composite Buiildsは、droidkaigiやnowinandroidでも使われていてAndroidエンジニアとしても勉強せねば…というモチベーションで使ってみました。

GitHub - DroidKaigi/conference-app-2024: The Official Conference App for DroidKaigi 2024

GitHub - android/nowinandroid: A fully functional Android app built entirely with Kotlin and Jetpack Compose

実際に作ったコードはGitHub上に公開しています。

GitHub - Tatsumi0000/nemomemo

実装

今回使っているライブラリのバージョンは以下の通りです。

[versions]
detekt = "1.23.7"
detektComposeRule = "0.4.16"
[libraries]
detektGradlePlugin = { group = "io.gitlab.arturbosch.detekt", name = "detekt-gradle-plugin", version.ref = "detekt" }
detektFormatting = { group = "io.gitlab.arturbosch.detekt", name = "detekt-formatting", version.ref = "detekt" }
detektComposeRule = { group = "io.nlopez.compose.rules", name = "detekt", version.ref = "detektComposeRule" }
[plugins]
detektGradlePlugin = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
[bundles]
plugins = [
"detektGradlePlugin"
]

bundlesのpluginsは書かなくてもいいのですが、このように書いたほうが複数のプラグインを使う時に楽なのでまとめています(droidkaigiがこの書き方で参考にしました)。

dependencies {
// 一行で済む
implementation(libs.bundles.plugins)
}

Composite Buiildsはモジュールではなくサブプロジェクトとして作るようなので、メインのプロジェクトで使っているVersion Catalogをサブプロジェクトからも見えるように設定を書きます。今回はbuild-logicという名前で作成しました。droidkaigiやnowinandroidや解説サイトでもこの名前が多かったので参考にしました。

どうしてサブプロジェクトとして作るのかはあまり理解できてないので、そこら辺の理解も深めたい…

dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}

Version Catalogで定義したライブラリやプラグイン名をlibs で取れるようにしたいので、設定を追加します。

internal val Project.libs: VersionCatalog
get() = extensions.getByType<VersionCatalogsExtension>().named("libs")

detektの設定を書きます。普通だったらbuild.gradle.ktなどに書いていく設定をここに書きます。

class DetektPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
// build.gradleでapply("hogefuga")している
pluginManager.apply("io.gitlab.arturbosch.detekt")
// detektを適用するディレクトリなどを設定
val fileTree = project.files("./").asFileTree.matching {
include("**/*.kt")
include("**/*.kts")
exclude("**/build/**")
exclude("**/resources/**")
}
val extension = extensions.getByType<DetektExtension>()
// build.gradleのdetektブロックでする設定
extension.apply {
buildUponDefaultConfig = true
autoCorrect = true
config.setFrom(project.files("${project.rootProject.rootDir}/config/detekt.yml"))
debug = true
source.setFrom(fileTree)
}
dependencies {
// detektPluginsを使って適用するライブラリ
// フォーマッタとJetpack Composeのライブラリを追加
"detektPlugins"(libs.findLibrary("detektFormatting").get())
"detektPlugins"(libs.findLibrary("detektComposeRule").get())
}
}
}
}

DetektPluginで自作したプラグインをGradleのプラグインとして登録します。

gradlePlugin {
plugins {
register("detekt") {
id = "love.aespa.nemomemo.detekt"
implementationClass = "DetektPlugin"
}
}
}

これでlove.aespa.nemomemo.detektという名前でプラグインを使えるようになったので各モジュールに設定します。

plugins {
id("love.aespa.nemomemo.detekt")
}

detektの準備が整ったので、設定ファイルを生成しコードを整形します。

Terminal window
detektの設定ファイルを生成
./gradlew detektConfig
detektを使ってコードを整形
./gradlew detekt --auto-correct

終わりに

マルチモジュールなプロジェクトでComposite Buidsを使ってdetektの設定をプラグインとしてまとめ、各モジュールに適用する方法を説明しました。

Composite Buildsを使うことで設定をまとめることでき、コードの見通しが非常によくなりました。しかし、Composite Builds自体の設定が難しいのでこれをチームに導入するには、チームの認識を揃えてからにしないと使われなくなりそう…と感じました。

自分も人に説明できるくらいには理解して使いこなせるようになりたいです!

参考文献