M2b: Android skeleton, :core:model contract, :domain passing all vectors
Gradle project in android/ with every module of SPEC §6.2 (build-logic convention plugins, version catalog, architecture check in check), :core:model types and repository interfaces of §14.2.4 and §14.5, :domain implementing §14.5.2 and §14.5.4 (125 vector cases), scenario-driven fakes with the empty scenario, Room 3 entities and KvittDatabase v1 with exported schema, :app shell with Hilt, en/sv strings with MissingTranslation as a lint error, Roborazzi goldens of the empty screen in light and dark. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.android.gradle.plugin)
|
||||
compileOnly(libs.kotlin.gradle.plugin)
|
||||
compileOnly(libs.compose.compiler.gradle.plugin)
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
register("kvittJvmLibrary") {
|
||||
id = "kvitt.jvm.library"
|
||||
implementationClass = "se.hagstedt.kvitt.buildlogic.JvmLibraryPlugin"
|
||||
}
|
||||
register("kvittAndroidLibrary") {
|
||||
id = "kvitt.android.library"
|
||||
implementationClass = "se.hagstedt.kvitt.buildlogic.AndroidLibraryPlugin"
|
||||
}
|
||||
register("kvittAndroidCompose") {
|
||||
id = "kvitt.android.compose"
|
||||
implementationClass = "se.hagstedt.kvitt.buildlogic.AndroidComposePlugin"
|
||||
}
|
||||
register("kvittAndroidFeature") {
|
||||
id = "kvitt.android.feature"
|
||||
implementationClass = "se.hagstedt.kvitt.buildlogic.AndroidFeaturePlugin"
|
||||
}
|
||||
register("kvittAndroidApplication") {
|
||||
id = "kvitt.android.application"
|
||||
implementationClass = "se.hagstedt.kvitt.buildlogic.AndroidApplicationPlugin"
|
||||
}
|
||||
register("kvittAndroidHilt") {
|
||||
id = "kvitt.android.hilt"
|
||||
implementationClass = "se.hagstedt.kvitt.buildlogic.HiltPlugin"
|
||||
}
|
||||
register("kvittArchitecture") {
|
||||
id = "kvitt.architecture"
|
||||
implementationClass = "se.hagstedt.kvitt.buildlogic.ArchitecturePlugin"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
dependencyResolutionManagement {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
versionCatalogs {
|
||||
create("libs") {
|
||||
from(files("../gradle/libs.versions.toml"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = "build-logic"
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package se.hagstedt.kvitt.buildlogic
|
||||
|
||||
import com.android.build.api.dsl.ApplicationExtension
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
|
||||
/** The `:app` module: SDK levels from the catalog, Java 17 bytecode, shared lint rules. */
|
||||
class AndroidApplicationPlugin : Plugin<Project> {
|
||||
override fun apply(target: Project) {
|
||||
with(target) {
|
||||
pluginManager.apply("com.android.application")
|
||||
pluginManager.apply("kvitt.architecture")
|
||||
val catalog = libs
|
||||
extensions.configure(ApplicationExtension::class.java) {
|
||||
compileSdk = catalog.version("compileSdk").toInt()
|
||||
defaultConfig {
|
||||
minSdk = catalog.version("minSdk").toInt()
|
||||
targetSdk = catalog.version("targetSdk").toInt()
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = org.gradle.api.JavaVersion.VERSION_17
|
||||
targetCompatibility = org.gradle.api.JavaVersion.VERSION_17
|
||||
}
|
||||
testOptions {
|
||||
unitTests.isIncludeAndroidResources = true
|
||||
}
|
||||
lint { kvittLint(this) }
|
||||
}
|
||||
configureKotlinAndroid()
|
||||
configureRobolectricJvm()
|
||||
dependencies.add("testImplementation", catalog.library("junit"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package se.hagstedt.kvitt.buildlogic
|
||||
|
||||
import com.android.build.api.dsl.Lint
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.testing.Test
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
/**
|
||||
* Lint rules shared by every Android module. A string key missing from `values-sv` (or present only there) fails the
|
||||
* build (SPEC AC-19.1). No baseline file: findings are fixed, never silenced (CLAUDE.md › Anti-patterns).
|
||||
*/
|
||||
internal fun kvittLint(lint: Lint) {
|
||||
lint.abortOnError = true
|
||||
lint.checkReleaseBuilds = true
|
||||
lint.error.add("MissingTranslation")
|
||||
lint.error.add("ExtraTranslation")
|
||||
}
|
||||
|
||||
/** Kotlin compiled by the Android Gradle Plugin's built-in Kotlin support: Java 17 bytecode, warnings are errors. */
|
||||
internal fun Project.configureKotlinAndroid() {
|
||||
tasks.withType(KotlinCompile::class.java).configureEach {
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_17)
|
||||
allWarningsAsErrors.set(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A module without `src/test` (a module shell) has only the generated R classes on its unit-test classpath, which
|
||||
* Gradle reports as "test sources present, no tests discovered". The guard stays on for every module with tests.
|
||||
*/
|
||||
internal fun Project.failOnNoTestsOnlyWhenTestsExist() {
|
||||
val hasTests = file("src/test").exists()
|
||||
tasks.withType(Test::class.java).configureEach { failOnNoDiscoveredTests.set(hasTests) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Robolectric on the pinned JDK 25 reads FileDescriptor internals through jdk.internal.access; the module system
|
||||
* blocks that unless the package is exported to the test classpath.
|
||||
*/
|
||||
internal fun Project.configureRobolectricJvm() {
|
||||
tasks.withType(Test::class.java).configureEach {
|
||||
jvmArgs("--add-exports=java.base/jdk.internal.access=ALL-UNNAMED", "--add-opens=java.base/java.io=ALL-UNNAMED")
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package se.hagstedt.kvitt.buildlogic
|
||||
|
||||
import com.android.build.api.dsl.ApplicationExtension
|
||||
import com.android.build.api.dsl.LibraryExtension
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
|
||||
/** Jetpack Compose with Material 3 for an Android application or library module. */
|
||||
class AndroidComposePlugin : Plugin<Project> {
|
||||
override fun apply(target: Project) {
|
||||
with(target) {
|
||||
pluginManager.apply("org.jetbrains.kotlin.plugin.compose")
|
||||
pluginManager.withPlugin("com.android.library") {
|
||||
extensions.configure(LibraryExtension::class.java) { buildFeatures.compose = true }
|
||||
}
|
||||
pluginManager.withPlugin("com.android.application") {
|
||||
extensions.configure(ApplicationExtension::class.java) { buildFeatures.compose = true }
|
||||
}
|
||||
val catalog = libs
|
||||
val bom = dependencies.platform(catalog.library("androidx-compose-bom"))
|
||||
dependencies.add("implementation", bom)
|
||||
dependencies.add("testImplementation", bom)
|
||||
dependencies.add("implementation", catalog.library("androidx-compose-ui"))
|
||||
dependencies.add("implementation", catalog.library("androidx-compose-ui-graphics"))
|
||||
dependencies.add("implementation", catalog.library("androidx-compose-ui-tooling-preview"))
|
||||
dependencies.add("implementation", catalog.library("androidx-compose-material3"))
|
||||
dependencies.add("debugImplementation", catalog.library("androidx-compose-ui-tooling"))
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package se.hagstedt.kvitt.buildlogic
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
|
||||
/**
|
||||
* Feature module (SPEC §6.2, convention in android/README.md): Compose screens against the UI contract only.
|
||||
* Features see `:core:model` and `:core:design`; `:core:fakes` only for debug previews and tests, so fakes never reach
|
||||
* a release build. ViewModels are Hilt ViewModels obtained with `hiltViewModel()`.
|
||||
*/
|
||||
class AndroidFeaturePlugin : Plugin<Project> {
|
||||
override fun apply(target: Project) {
|
||||
with(target) {
|
||||
pluginManager.apply("kvitt.android.library")
|
||||
pluginManager.apply("kvitt.android.compose")
|
||||
pluginManager.apply("kvitt.android.hilt")
|
||||
val catalog = libs
|
||||
dependencies.add("implementation", dependencies.project(mapOf("path" to ":core:model")))
|
||||
dependencies.add("implementation", dependencies.project(mapOf("path" to ":core:design")))
|
||||
dependencies.add("debugImplementation", dependencies.project(mapOf("path" to ":core:fakes")))
|
||||
dependencies.add("testImplementation", dependencies.project(mapOf("path" to ":core:fakes")))
|
||||
dependencies.add("implementation", catalog.library("androidx-hilt-lifecycle-viewmodel-compose"))
|
||||
dependencies.add("implementation", catalog.library("androidx-lifecycle-viewmodel-compose"))
|
||||
dependencies.add("implementation", catalog.library("androidx-lifecycle-runtime-compose"))
|
||||
dependencies.add("implementation", catalog.library("kotlinx-coroutines-core"))
|
||||
}
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package se.hagstedt.kvitt.buildlogic
|
||||
|
||||
import com.android.build.api.dsl.LibraryExtension
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
|
||||
/** Android library module: SDK levels from the catalog, Java 17 bytecode, shared lint rules. */
|
||||
class AndroidLibraryPlugin : Plugin<Project> {
|
||||
override fun apply(target: Project) {
|
||||
with(target) {
|
||||
pluginManager.apply("com.android.library")
|
||||
pluginManager.apply("kvitt.architecture")
|
||||
val catalog = libs
|
||||
extensions.configure(LibraryExtension::class.java) {
|
||||
namespace = kvittNamespace()
|
||||
compileSdk = catalog.version("compileSdk").toInt()
|
||||
defaultConfig {
|
||||
minSdk = catalog.version("minSdk").toInt()
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = org.gradle.api.JavaVersion.VERSION_17
|
||||
targetCompatibility = org.gradle.api.JavaVersion.VERSION_17
|
||||
}
|
||||
testOptions {
|
||||
unitTests.isIncludeAndroidResources = true
|
||||
}
|
||||
lint { kvittLint(this) }
|
||||
}
|
||||
configureKotlinAndroid()
|
||||
configureRobolectricJvm()
|
||||
failOnNoTestsOnlyWhenTestsExist()
|
||||
dependencies.add("testImplementation", catalog.library("junit"))
|
||||
}
|
||||
}
|
||||
}
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
package se.hagstedt.kvitt.buildlogic
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.CacheableTask
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
|
||||
/**
|
||||
* Fails the build on a dependency edge outside SPEC §6.2, on `:core:fakes` in a release configuration, and on
|
||||
* imports or fully qualified references outside kotlin.*, kotlinx.* and the project's packages in a pure module.
|
||||
*/
|
||||
@CacheableTask
|
||||
abstract class ArchitectureCheckTask : DefaultTask() {
|
||||
@get:Input
|
||||
abstract val modulePath: Property<String>
|
||||
|
||||
/** Declared project dependencies as `configuration|:path`. */
|
||||
@get:Input
|
||||
abstract val projectDependencies: ListProperty<String>
|
||||
|
||||
/** Declared external dependencies of the main configurations as `configuration|group:name`. */
|
||||
@get:Input
|
||||
abstract val externalDependencies: ListProperty<String>
|
||||
|
||||
@get:Input
|
||||
abstract val androidPluginApplied: Property<Boolean>
|
||||
|
||||
/** Main source files of the module (scanned only for pure modules). */
|
||||
@get:InputFiles
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
abstract val mainSources: ConfigurableFileCollection
|
||||
|
||||
@get:OutputFile
|
||||
abstract val report: RegularFileProperty
|
||||
|
||||
@TaskAction
|
||||
fun check() {
|
||||
val path = modulePath.get()
|
||||
val violations = mutableListOf<String>()
|
||||
if (!ArchitectureRules.allowed.containsKey(path)) {
|
||||
violations += "$path is not in ArchitectureRules.allowed; add it with its allowed edges (SPEC §6.2)"
|
||||
}
|
||||
val allowed = ArchitectureRules.allowed[path]
|
||||
for (entry in projectDependencies.get()) {
|
||||
val (configuration, target) = entry.split('|', limit = 2)
|
||||
if (target == path) continue
|
||||
if (allowed != null && target !in allowed) {
|
||||
violations += "$path -> $target ($configuration) is not an allowed edge (SPEC §6.2)"
|
||||
}
|
||||
if (target == ArchitectureRules.FAKES && !ArchitectureRules.isTestOrDebugConfiguration(configuration)) {
|
||||
violations += "$path -> $target in '$configuration': fakes only in test or debug configurations"
|
||||
}
|
||||
}
|
||||
if (path in ArchitectureRules.pureModules) {
|
||||
if (androidPluginApplied.get()) violations += "$path is pure Kotlin/JVM and must not apply an Android plugin"
|
||||
for (entry in externalDependencies.get()) {
|
||||
val (configuration, coordinate) = entry.split('|', limit = 2)
|
||||
if (ArchitectureRules.pureExternalGroups.none { coordinate.startsWith("$it.") || coordinate.startsWith("$it:") }) {
|
||||
violations += "$path uses $coordinate in '$configuration'; pure modules use only kotlin and kotlinx libraries"
|
||||
}
|
||||
}
|
||||
mainSources.files.sortedBy { it.path }.forEach { file ->
|
||||
file.readLines().forEachIndexed { index, raw ->
|
||||
val line = raw.trim()
|
||||
val where = "${file.name}:${index + 1}"
|
||||
val import = IMPORT.find(line)?.groupValues?.get(1)
|
||||
if (import != null) {
|
||||
if (ArchitectureRules.pureImportPrefixes.none { import.startsWith(it) }) {
|
||||
violations += "$path $where imports $import (only kotlin.*, kotlinx.*, se.hagstedt.kvitt.*)"
|
||||
}
|
||||
} else if (!line.startsWith("//") && !line.startsWith("*") && !line.startsWith("/*")) {
|
||||
QUALIFIED.find(line)?.let { violations += "$path $where references ${it.value} (platform API)" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
val text = if (violations.isEmpty()) "OK $path\n" else violations.joinToString("\n", postfix = "\n")
|
||||
report.get().asFile.apply { parentFile.mkdirs() }.writeText(text)
|
||||
if (violations.isNotEmpty()) {
|
||||
throw GradleException("Architecture check failed:\n" + violations.joinToString("\n") { " $it" })
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val IMPORT = Regex("""^import\s+([\w.]+)""")
|
||||
val QUALIFIED = Regex("""(?<![\w.])(java|javax|android|androidx|dalvik|sun)\.[a-z]\w*""")
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package se.hagstedt.kvitt.buildlogic
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.ExternalModuleDependency
|
||||
import org.gradle.api.artifacts.ProjectDependency
|
||||
import org.gradle.api.plugins.BasePlugin
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
|
||||
/** Registers `architectureCheck` in every module and makes `check` depend on it (SPEC §6.2, owned by M2b). */
|
||||
class ArchitecturePlugin : Plugin<Project> {
|
||||
override fun apply(target: Project) {
|
||||
with(target) {
|
||||
pluginManager.apply(BasePlugin::class.java)
|
||||
val configurations = configurations
|
||||
val projectPath = path
|
||||
val task = tasks.register("architectureCheck", ArchitectureCheckTask::class.java) {
|
||||
group = LifecycleBasePlugin.VERIFICATION_GROUP
|
||||
description = "Checks module dependency edges and pure-module imports (SPEC §6.2)."
|
||||
modulePath.set(projectPath)
|
||||
projectDependencies.set(provider {
|
||||
configurations.flatMap { c ->
|
||||
c.dependencies.withType(ProjectDependency::class.java).map { "${c.name}|${it.path}" }
|
||||
}.distinct().sorted()
|
||||
})
|
||||
externalDependencies.set(provider {
|
||||
configurations.filter { it.name in ArchitectureRules.mainConfigurations }.flatMap { c ->
|
||||
c.dependencies.withType(ExternalModuleDependency::class.java).map { "${c.name}|${it.group}:${it.name}" }
|
||||
}.distinct().sorted()
|
||||
})
|
||||
androidPluginApplied.set(provider { pluginManager.hasPlugin("com.android.library") || pluginManager.hasPlugin("com.android.application") })
|
||||
mainSources.from(fileTree("src/main") { include("**/*.kt", "**/*.java") })
|
||||
report.set(layout.buildDirectory.file("reports/architecture/check.txt"))
|
||||
}
|
||||
tasks.named(LifecycleBasePlugin.CHECK_TASK_NAME) { dependsOn(task) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package se.hagstedt.kvitt.buildlogic
|
||||
|
||||
/**
|
||||
* The module graph of SPEC §6.2 and CLAUDE.md › Architecture rules, as data. One entry per module; a module missing
|
||||
* here fails the check, so a new module must be added on purpose.
|
||||
*/
|
||||
object ArchitectureRules {
|
||||
const val FAKES = ":core:fakes"
|
||||
|
||||
private val features = listOf("onboarding", "home", "account", "expense", "settle", "analytics", "settings")
|
||||
.map { ":feature:$it" }
|
||||
|
||||
/** Pure Kotlin/JVM modules: no Android, no java.time, no java.io; only kotlin.*, kotlinx.* and project imports. */
|
||||
val pureModules: Set<String> = setOf(":core:model", ":domain")
|
||||
|
||||
/** Allowed project dependencies per module. `null` means any module (only `:app`). */
|
||||
val allowed: Map<String, Set<String>?> = buildMap {
|
||||
put(":core:model", emptySet())
|
||||
put(":domain", setOf(":core:model"))
|
||||
put(":core:design", setOf(":core:model"))
|
||||
put(FAKES, setOf(":core:model", ":domain"))
|
||||
put(":data", setOf(":core:model", ":domain"))
|
||||
put(":adapter:fcm", setOf(":core:model"))
|
||||
features.forEach { put(it, setOf(":core:model", ":core:design", FAKES)) }
|
||||
put(":app", null)
|
||||
}
|
||||
|
||||
/** Package prefixes a pure module may import. */
|
||||
val pureImportPrefixes: List<String> = listOf("kotlin.", "kotlinx.", "se.hagstedt.kvitt.")
|
||||
|
||||
/** Group prefixes of external libraries a pure module may use in its main code. */
|
||||
val pureExternalGroups: List<String> = listOf("org.jetbrains.kotlin", "org.jetbrains.kotlinx")
|
||||
|
||||
/** Configurations that feed main (release) code; everything else is a test, debug or tool configuration. */
|
||||
val mainConfigurations: Set<String> = setOf("api", "implementation", "compileOnly", "compileOnlyApi", "runtimeOnly")
|
||||
|
||||
/** `:core:fakes` may appear only in test and debug configurations (fakes never reach a release build). */
|
||||
fun isTestOrDebugConfiguration(name: String): Boolean =
|
||||
name.contains("test", ignoreCase = true) || name.contains("debug", ignoreCase = true)
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package se.hagstedt.kvitt.buildlogic
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.MinimalExternalModuleDependency
|
||||
import org.gradle.api.artifacts.VersionCatalog
|
||||
import org.gradle.api.artifacts.VersionCatalogsExtension
|
||||
import org.gradle.api.provider.Provider
|
||||
|
||||
internal val Project.libs: VersionCatalog
|
||||
get() = extensions.getByType(VersionCatalogsExtension::class.java).named("libs")
|
||||
|
||||
internal fun VersionCatalog.version(name: String): String =
|
||||
findVersion(name).orElseThrow { IllegalStateException("libs.versions.toml has no version '$name'") }.requiredVersion
|
||||
|
||||
internal fun VersionCatalog.library(alias: String): Provider<MinimalExternalModuleDependency> =
|
||||
findLibrary(alias).orElseThrow { IllegalStateException("libs.versions.toml has no library '$alias'") }
|
||||
|
||||
/** Namespace of an Android module, derived from its path: `:feature:home` -> `se.hagstedt.kvitt.feature.home`. */
|
||||
internal fun Project.kvittNamespace(): String = "se.hagstedt.kvitt." + path.removePrefix(":").replace(':', '.')
|
||||
@@ -0,0 +1,16 @@
|
||||
package se.hagstedt.kvitt.buildlogic
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
|
||||
/** Hilt with KSP for an Android module. */
|
||||
class HiltPlugin : Plugin<Project> {
|
||||
override fun apply(target: Project) {
|
||||
with(target) {
|
||||
pluginManager.apply("com.google.devtools.ksp")
|
||||
pluginManager.apply("com.google.dagger.hilt.android")
|
||||
dependencies.add("implementation", libs.library("hilt-android"))
|
||||
dependencies.add("ksp", libs.library("hilt-compiler"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package se.hagstedt.kvitt.buildlogic
|
||||
|
||||
import org.gradle.api.JavaVersion
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.JavaPluginExtension
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
|
||||
|
||||
/** Pure Kotlin/JVM module (`:core:model`, `:domain`): no Android, bytecode Java 17 (SPEC §6.2). */
|
||||
class JvmLibraryPlugin : Plugin<Project> {
|
||||
override fun apply(target: Project) {
|
||||
with(target) {
|
||||
pluginManager.apply("org.jetbrains.kotlin.jvm")
|
||||
pluginManager.apply("kvitt.architecture")
|
||||
extensions.configure(JavaPluginExtension::class.java) {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
tasks.withType(JavaCompile::class.java).configureEach { options.release.set(17) }
|
||||
extensions.configure(KotlinJvmProjectExtension::class.java) {
|
||||
compilerOptions {
|
||||
jvmTarget.set(JvmTarget.JVM_17)
|
||||
freeCompilerArgs.add("-Xjdk-release=17")
|
||||
allWarningsAsErrors.set(true)
|
||||
}
|
||||
}
|
||||
dependencies.add("testImplementation", libs.library("junit"))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user