import groovy.json.JsonSlurper import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.kapt) alias(libs.plugins.hilt) } android { namespace = "net.opcapp.flash" compileSdk = 34 defaultConfig { applicationId = "net.opcapp.flash" minSdk = 26 targetSdk = 34 versionCode = 1 versionName = "0.1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables.useSupportLibrary = true javaCompileOptions { annotationProcessorOptions { arguments += mapOf("room.schemaLocation" to "$projectDir/schemas") } } } buildTypes { release { isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro", ) } } buildFeatures { compose = true buildConfig = false } composeOptions { kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get() } compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } packaging { resources.excludes += "/META-INF/{AL2.0,LGPL2.1}" } sourceSets { getByName("main").assets.srcDir(rootProject.file("content/packages")) getByName("test").resources.srcDir(rootProject.file("content/packages")) } testOptions { unitTests.isReturnDefaultValues = true } } kotlin { jvmToolchain(17) } kapt { correctErrorTypes = true } tasks.withType().configureEach { kotlinOptions.jvmTarget = "17" } dependencies { val composeBom = platform(libs.androidx.compose.bom) implementation(libs.androidx.core.ktx) implementation(libs.androidx.activity.compose) implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.lifecycle.runtime.compose) implementation(libs.androidx.lifecycle.viewmodel.compose) implementation(composeBom) implementation(libs.androidx.compose.ui) implementation(libs.androidx.compose.ui.tooling.preview) implementation(libs.androidx.compose.material3) implementation(libs.androidx.navigation.compose) implementation(libs.androidx.room.runtime) implementation(libs.androidx.room.ktx) kapt(libs.androidx.room.compiler) implementation(libs.androidx.datastore.preferences) implementation(libs.hilt.android) kapt(libs.hilt.compiler) testImplementation(libs.junit) androidTestImplementation(composeBom) androidTestImplementation(libs.androidx.test.ext.junit) androidTestImplementation(libs.androidx.test.runner) androidTestImplementation(libs.androidx.compose.ui.test.junit4) androidTestImplementation(libs.androidx.room.testing) debugImplementation(libs.androidx.compose.ui.tooling) debugImplementation(libs.androidx.compose.ui.test.manifest) } tasks.withType().configureEach { useJUnit() maxParallelForks = 1 maxHeapSize = "192m" jvmArgs("-XX:MaxMetaspaceSize=128m", "-XX:+UseSerialGC") testLogging { events("failed", "skipped") exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL } } tasks.register("verifyDependencyLicenses") { group = "verification" description = "Ensures every resolved debug runtime/test artifact has a reviewed license entry." doLast { @Suppress("UNCHECKED_CAST") val manifest = JsonSlurper().parse(rootProject.file("config/dependency-licenses.json")) as Map @Suppress("UNCHECKED_CAST") val components = manifest.getValue("components") as List> @Suppress("UNCHECKED_CAST") val groupPolicies = manifest.getValue("groupPolicies") as List> val reviewedCoordinates = components.mapNotNull { it["coordinates"] as String? }.toSet() val resolvedCoordinates = listOf( "debugRuntimeClasspath", "debugUnitTestRuntimeClasspath", "debugAndroidTestRuntimeClasspath", ) .flatMap { configurationName -> configurations.getByName(configurationName) .resolvedConfiguration .resolvedArtifacts .mapNotNull { artifact -> if (artifact.id.componentIdentifier !is org.gradle.api.artifacts.component.ModuleComponentIdentifier) { return@mapNotNull null } val id = artifact.moduleVersion.id "${id.group}:${id.name}:${id.version}" } } .toSet() val missing = resolvedCoordinates.filterNot { coordinates -> if (coordinates in reviewedCoordinates) return@filterNot true val group = coordinates.substringBefore(":") groupPolicies.any { policy -> val prefix = policy.getValue("groupPrefix") as String group == prefix || group.startsWith("$prefix.") } } check(missing.isEmpty()) { "Dependencies missing reviewed license entries: ${missing.sorted().joinToString()}" } logger.lifecycle( "Dependency license coverage passed for ${resolvedCoordinates.size} artifacts " + "with ${groupPolicies.size} reviewed group policies.", ) } }