mirror of
				https://github.com/AdrianKuta/android-challange-adrian-kuta.git
				synced 2025-10-31 12:13:39 +01:00 
			
		
		
		
	Initial commit
This commit is contained in:
		
							
								
								
									
										75
									
								
								build-logic/convention/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								build-logic/convention/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,75 @@ | ||||
| import org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21 | ||||
|  | ||||
| /* | ||||
|  * Copyright 2022 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     https://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| plugins { | ||||
|     `kotlin-dsl` | ||||
| } | ||||
|  | ||||
| group = "dev.adriankuta.flights.buildlogic" | ||||
|  | ||||
| java { | ||||
|     sourceCompatibility = JavaVersion.VERSION_21 | ||||
|     targetCompatibility = JavaVersion.VERSION_21 | ||||
| } | ||||
|  | ||||
| kotlin { | ||||
|     compilerOptions { | ||||
|         jvmTarget = JVM_21 | ||||
|     } | ||||
| } | ||||
|  | ||||
| dependencies { | ||||
|     compileOnly(libs.android.gradlePlugin) | ||||
|     compileOnly(libs.compose.gradlePlugin) | ||||
|     compileOnly(libs.detekt.gradlePlugin) | ||||
|     compileOnly(libs.kotlin.gradlePlugin) | ||||
|     compileOnly(libs.ksp.gradlePlugin) | ||||
| } | ||||
|  | ||||
| gradlePlugin { | ||||
|     /** | ||||
|      * Register convention plugins so they are available in the build scripts of the application | ||||
|      */ | ||||
|  | ||||
|     plugins { | ||||
|         register("androidLibrary") { | ||||
|             id = "flights.android.library" | ||||
|             implementationClass = "AndroidLibraryConvention" | ||||
|         } | ||||
|         register("androidLibraryCompose") { | ||||
|             id = "flights.android.library.compose" | ||||
|             implementationClass = "AndroidLibraryComposeConvention" | ||||
|         } | ||||
|         register("androidApplication") { | ||||
|             id = "flights.android.application" | ||||
|             implementationClass = "AndroidApplicationConvention" | ||||
|         } | ||||
|         register("androidApplicationCompose") { | ||||
|             id = "flights.android.application.compose" | ||||
|             implementationClass = "AndroidApplicationComposeConvention" | ||||
|         } | ||||
|         register("androidApplicationHilt") { | ||||
|             id = "flights.android.application.hilt" | ||||
|             implementationClass = "AndroidApplicationHiltConvention" | ||||
|         } | ||||
|         register("androidLibraryHilt") { | ||||
|             id = "flights.android.library.hilt" | ||||
|             implementationClass = "AndroidLibraryHiltConvention" | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,52 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Android Open Source Project | ||||
|  * | ||||
|  *   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  *   you may not use this file except in compliance with the License. | ||||
|  *   You may obtain a copy of the License at | ||||
|  * | ||||
|  *       https://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  *   Unless required by applicable law or agreed to in writing, software | ||||
|  *   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  *   See the License for the specific language governing permissions and | ||||
|  *   limitations under the License. | ||||
|  */ | ||||
|  | ||||
| import com.android.build.api.dsl.ApplicationExtension | ||||
| import dev.adriankuta.flights.configureCompose | ||||
| import dev.adriankuta.flights.configureDetektForComposeModuleExceptions | ||||
| import dev.adriankuta.flights.configureInstrumentation | ||||
| import org.gradle.api.Plugin | ||||
| import org.gradle.api.Project | ||||
| import org.gradle.api.artifacts.VersionCatalogsExtension | ||||
| import org.gradle.kotlin.dsl.configure | ||||
| import org.gradle.kotlin.dsl.dependencies | ||||
| import org.gradle.kotlin.dsl.getByType | ||||
|  | ||||
| @Suppress("unused") // This is called as a string in the gradle plugin block | ||||
| class AndroidApplicationComposeConvention : Plugin<Project> { | ||||
|     override fun apply(target: Project) { | ||||
|         with(target) { | ||||
|             pluginManager.apply("flights.android.application") | ||||
|             val extension = extensions.getByType<ApplicationExtension>() | ||||
|  | ||||
|             extensions.configure<ApplicationExtension> { | ||||
|                 defaultConfig { | ||||
|                     testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             val libs = extensions.getByType<VersionCatalogsExtension>().named("libs") | ||||
|  | ||||
|             configureInstrumentation() | ||||
|             configureCompose(extension) | ||||
|             configureDetektForComposeModuleExceptions() | ||||
|  | ||||
|             dependencies { | ||||
|                 "androidTestImplementation"(libs.findLibrary("androidx.test.core").get()) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,73 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Android Open Source Project | ||||
|  * | ||||
|  *   Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  *   you may not use this file except in compliance with the License. | ||||
|  *   You may obtain a copy of the License at | ||||
|  * | ||||
|  *       https://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  *   Unless required by applicable law or agreed to in writing, software | ||||
|  *   distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  *   See the License for the specific language governing permissions and | ||||
|  *   limitations under the License. | ||||
|  */ | ||||
|  | ||||
| import com.android.build.api.dsl.ApplicationExtension | ||||
| import dev.adriankuta.flights.configureAndroidLint | ||||
| import dev.adriankuta.flights.configureDetektDependencies | ||||
| import dev.adriankuta.flights.configureFlavors | ||||
| import dev.adriankuta.flights.configureKotlinAndroid | ||||
| import dev.adriankuta.flights.configureUnitTests | ||||
| import org.gradle.api.Plugin | ||||
| import org.gradle.api.Project | ||||
| import org.gradle.api.artifacts.VersionCatalogsExtension | ||||
| import org.gradle.kotlin.dsl.configure | ||||
| import org.gradle.kotlin.dsl.getByType | ||||
|  | ||||
| @Suppress("unused") // This is called as a string in the gradle plugin block | ||||
| class AndroidApplicationConvention : Plugin<Project> { | ||||
|     override fun apply(target: Project) { | ||||
|         with(target) { | ||||
|             with(pluginManager) { | ||||
|                 apply("com.android.application") | ||||
|                 apply("io.gitlab.arturbosch.detekt") | ||||
|                 apply("org.jetbrains.kotlin.android") | ||||
|             } | ||||
|  | ||||
|             val libs = extensions.getByType<VersionCatalogsExtension>().named("libs") | ||||
|  | ||||
|             // android block | ||||
|             extensions.configure<ApplicationExtension> { | ||||
|                 configureKotlinAndroid(this) | ||||
|                 defaultConfig.targetSdk = libs.findVersion("targetSdk").get().toString().toInt() | ||||
|                 defaultConfig.vectorDrawables { | ||||
|                     useSupportLibrary = true | ||||
|                 } | ||||
|  | ||||
|                 buildTypes { | ||||
|                     debug { | ||||
|                         testCoverage { | ||||
|                             enableUnitTestCoverage = | ||||
|                                 false // Test coverage spanks memory on the CI with ye older AGP | ||||
|                             enableAndroidTestCoverage = false | ||||
|                         } | ||||
|                         applicationIdSuffix = ".debug" | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 configureFlavors(this) | ||||
|                 configureAndroidLint(this) | ||||
| //                configureGradleManagedDevices(this) | ||||
|             } | ||||
| //            val extension = extensions.getByType<ApplicationAndroidComponentsExtension>() | ||||
| //            configureJacoco(extension) | ||||
|             configureDetektDependencies() | ||||
|             //configureSonar() | ||||
|             configureUnitTests() | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,22 @@ | ||||
| import com.android.build.api.dsl.ApplicationExtension | ||||
| import dev.adriankuta.flights.configureHilt | ||||
| import org.gradle.api.Plugin | ||||
| import org.gradle.api.Project | ||||
| import org.gradle.kotlin.dsl.configure | ||||
|  | ||||
| @Suppress("unused") // This is called as a string in the gradle plugin block | ||||
| internal class AndroidApplicationHiltConvention : Plugin<Project> { | ||||
|     override fun apply(target: Project) { | ||||
|         with(target) { | ||||
|             with(pluginManager) { | ||||
|                 apply("com.google.devtools.ksp") | ||||
|                 apply("dagger.hilt.android.plugin") | ||||
|             } | ||||
|  | ||||
|             // android block | ||||
|             extensions.configure<ApplicationExtension> { | ||||
|                 configureHilt() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,12 @@ | ||||
| import dev.adriankuta.flights.configureDetektForComposeModuleExceptions | ||||
| import org.gradle.api.Plugin | ||||
| import org.gradle.api.Project | ||||
|  | ||||
| @Suppress("unused") // This is called as a string in the gradle plugin block | ||||
| internal class AndroidDetektComposeConvention : Plugin<Project> { | ||||
|     override fun apply(target: Project) { | ||||
|         with(target) { | ||||
|             configureDetektForComposeModuleExceptions() | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,13 @@ | ||||
| import dev.adriankuta.flights.configureDetektForNonUiModule | ||||
| import org.gradle.api.Plugin | ||||
| import org.gradle.api.Project | ||||
|  | ||||
| @Suppress("unused") // This is called as a string in the gradle plugin block | ||||
| internal class AndroidDetektConvention : Plugin<Project> { | ||||
|     override fun apply(target: Project) { | ||||
|         with(target) { | ||||
|             configureDetektForNonUiModule() | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,30 @@ | ||||
| import com.android.build.gradle.LibraryExtension | ||||
| import dev.adriankuta.flights.configureCompose | ||||
| import dev.adriankuta.flights.configureDetektForComposeModuleExceptions | ||||
| import dev.adriankuta.flights.configureInstrumentation | ||||
| import dev.adriankuta.flights.configureLibrary | ||||
| import org.gradle.api.Plugin | ||||
| import org.gradle.api.Project | ||||
| import org.gradle.kotlin.dsl.configure | ||||
| import org.gradle.kotlin.dsl.getByType | ||||
|  | ||||
| @Suppress("unused") // This is called as a string in the gradle plugin block | ||||
| internal class AndroidLibraryComposeConvention : Plugin<Project> { | ||||
|     override fun apply(target: Project) { | ||||
|         with(target) { | ||||
|             configureLibrary() | ||||
|  | ||||
|             extensions.configure<LibraryExtension> { | ||||
|                 defaultConfig { | ||||
|                     testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             val extension = extensions.getByType<LibraryExtension>() | ||||
|             configureCompose(extension) | ||||
|             configureInstrumentation() | ||||
|             configureDetektForComposeModuleExceptions() | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,12 @@ | ||||
| import dev.adriankuta.flights.configureDetektForNonUiModule | ||||
| import dev.adriankuta.flights.configureLibrary | ||||
| import org.gradle.api.Plugin | ||||
| import org.gradle.api.Project | ||||
|  | ||||
| @Suppress("unused") // This is called as a string in the gradle plugin block | ||||
| internal class AndroidLibraryConvention : Plugin<Project> { | ||||
|     override fun apply(target: Project) { | ||||
|         target.configureLibrary() | ||||
|         target.configureDetektForNonUiModule() | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,22 @@ | ||||
| import com.android.build.gradle.LibraryExtension | ||||
| import dev.adriankuta.flights.configureHilt | ||||
| import org.gradle.api.Plugin | ||||
| import org.gradle.api.Project | ||||
| import org.gradle.kotlin.dsl.configure | ||||
|  | ||||
| @Suppress("unused") // This is called as a string in the gradle plugin block | ||||
| internal class AndroidLibraryHiltConvention : Plugin<Project> { | ||||
|     override fun apply(target: Project) { | ||||
|         with(target) { | ||||
|             with(pluginManager) { | ||||
|                 apply("com.google.devtools.ksp") | ||||
|                 apply("dagger.hilt.android.plugin") | ||||
|             } | ||||
|  | ||||
|             // android block | ||||
|             extensions.configure<LibraryExtension> { | ||||
|                 configureHilt() | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,29 @@ | ||||
| package dev.adriankuta.flights | ||||
|  | ||||
| import com.android.build.api.dsl.CommonExtension | ||||
| import org.gradle.api.Project | ||||
|  | ||||
| internal fun Project.configureAndroidLint( | ||||
|     commonExtension: CommonExtension<*, *, *, *, *, *>, | ||||
| ) { | ||||
|     commonExtension.apply { | ||||
|         lint { | ||||
|             baseline = file("lint-baseline.xml") | ||||
|             warningsAsErrors = true | ||||
|             disable += "AndroidGradlePluginVersion" | ||||
|             warning += "LintBaseline" // Still have report remind us of baseline issues | ||||
|             disable += "GradleDependency" // We want to mange dependency updates in own PRs. | ||||
|             disable += "MissingTranslation" // Translations are apart from our normal process at the moment | ||||
|  | ||||
|             // region - Bug in lint/AGP apparently | ||||
|             // TODO Maybe it is, maybe it isnt.  Its a transitory, hard to replicate bug.  Ideally | ||||
|             // we want these lint rules applied. | ||||
|             disable += "StateFlowValueCalledInComposition" | ||||
|             disable += "FlowOperatorInvokedInComposition" | ||||
|             disable += "WrongNavigateRouteType" | ||||
|             disable += "WrongStartDestinationType" | ||||
|             disable += "UnknownIssueId" | ||||
|             // endregion | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,50 @@ | ||||
| package dev.adriankuta.flights | ||||
|  | ||||
| import com.android.build.api.dsl.CommonExtension | ||||
| import org.gradle.api.Project | ||||
| import org.gradle.api.artifacts.VersionCatalogsExtension | ||||
| import org.gradle.kotlin.dsl.assign | ||||
| import org.gradle.kotlin.dsl.configure | ||||
| import org.gradle.kotlin.dsl.dependencies | ||||
| import org.gradle.kotlin.dsl.getByType | ||||
| import org.jetbrains.kotlin.compose.compiler.gradle.ComposeCompilerGradlePluginExtension | ||||
|  | ||||
| internal fun Project.configureCompose( | ||||
|     commonExtension: CommonExtension<*, *, *, *, *, *>, | ||||
| ) { | ||||
|     with(pluginManager) { | ||||
|         apply("org.jetbrains.kotlin.plugin.compose") | ||||
|     } | ||||
|  | ||||
|     val libs = extensions.getByType<VersionCatalogsExtension>().named("libs") | ||||
|  | ||||
|     commonExtension.apply { | ||||
|         buildFeatures { | ||||
|             compose = true | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     extensions.configure<ComposeCompilerGradlePluginExtension> { | ||||
|         enableStrongSkippingMode = true | ||||
|         includeSourceInformation = true | ||||
|     } | ||||
|  | ||||
|     dependencies { | ||||
|         val bom = libs.findLibrary("androidx-compose-bom").get() | ||||
|         "androidTestImplementation"(platform(bom)) | ||||
|         "androidTestImplementation"(libs.findLibrary("androidx.compose.ui.test.junit").get()) | ||||
|  | ||||
|         "debugImplementation"(platform(bom)) | ||||
|         "debugImplementation"(libs.findLibrary("androidx.compose.ui.tooling").get()) | ||||
|         //"debugImplementation"(libs.findLibrary("androidx.compose.ui.testManifest").get()) | ||||
|  | ||||
|         "implementation"(platform(bom)) | ||||
|         "implementation"(libs.findLibrary("androidx.compose.material3").get()) | ||||
|         "implementation"(libs.findLibrary("androidx.compose.ui").get()) | ||||
|         "implementation"(libs.findLibrary("androidx.compose.ui.graphics").get()) | ||||
|         "implementation"(libs.findLibrary("androidx.compose.ui.tooling.preview").get()) | ||||
|         "implementation"(libs.findLibrary("androidx.lifecycle.runtime.compose").get()) | ||||
|         "implementation"(libs.findLibrary("androidx.navigation.compose").get()) | ||||
|         "implementation"(libs.findLibrary("kotlinx.collections.immutable").get()) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,83 @@ | ||||
| package dev.adriankuta.flights | ||||
|  | ||||
| import io.gitlab.arturbosch.detekt.extensions.DetektExtension | ||||
| import org.gradle.api.Project | ||||
| import org.gradle.api.artifacts.VersionCatalogsExtension | ||||
| import org.gradle.kotlin.dsl.configure | ||||
| import org.gradle.kotlin.dsl.dependencies | ||||
| import org.gradle.kotlin.dsl.getByType | ||||
| import java.io.FileWriter | ||||
|  | ||||
| internal fun Project.configureDetektDependencies() { | ||||
|     val libs = extensions.getByType<VersionCatalogsExtension>().named("libs") | ||||
|  | ||||
|     dependencies { | ||||
|         "detektPlugins"(libs.findLibrary("detekt.ktlint").get()) | ||||
|         "detektPlugins"(libs.findLibrary("detekt.compose").get()) | ||||
|     } | ||||
| } | ||||
|  | ||||
| internal fun Project.configureDetektForNonUiModule() = | ||||
|     createDetektConfigFile(NonDefault.trimIndent()) | ||||
|  | ||||
| internal fun Project.configureDetektForComposeModuleExceptions() = | ||||
|     createDetektConfigFile(ComposeExceptions.trimIndent()) | ||||
|  | ||||
| internal fun Project.createDetektConfigFile(deviationsFromDefaultConfig: String) { | ||||
|     val libs = extensions.getByType<VersionCatalogsExtension>().named("libs") | ||||
|  | ||||
|     if (!file(DetektConfigPath).exists()) { | ||||
|         val detektConfigFile = project.file(DetektConfigPath) | ||||
|         detektConfigFile.parentFile.mkdirs() | ||||
|         detektConfigFile.createNewFile() | ||||
|         val writer = FileWriter(detektConfigFile) | ||||
|         writer.write(deviationsFromDefaultConfig) | ||||
|         writer.close() | ||||
|     } | ||||
|  | ||||
|     configure<DetektExtension> { | ||||
|         toolVersion = libs.findVersion("detekt").get().toString() | ||||
|         config.setFrom(files(DetektConfigPath)) | ||||
|         buildUponDefaultConfig = true | ||||
|     } | ||||
| } | ||||
|  | ||||
| private const val DetektConfigPath = "config/detekt/detekt.yml" | ||||
|  | ||||
| private val NonDefault = """ | ||||
|     # Deviations from defaults | ||||
|     formatting: | ||||
|       TrailingCommaOnCallSite: | ||||
|         active: true | ||||
|         autoCorrect: true | ||||
|         useTrailingCommaOnCallSite: true | ||||
|       TrailingCommaOnDeclarationSite: | ||||
|         active: true | ||||
|         autoCorrect: true | ||||
|         useTrailingCommaOnDeclarationSite: true | ||||
| """ | ||||
|  | ||||
| private val ComposeExceptions = """ | ||||
|     # Exceptions for compose. See https://detekt.dev/docs/introduction/compose | ||||
|     naming: | ||||
|       FunctionNaming: | ||||
|         functionPattern: '[a-zA-Z][a-zA-Z0-9]*' | ||||
|      | ||||
|       TopLevelPropertyNaming: | ||||
|         constantPattern: '[A-Z][A-Za-z0-9]*' | ||||
|      | ||||
|     complexity: | ||||
|       LongParameterList: | ||||
|         ignoreAnnotated: ['Composable'] | ||||
|       TooManyFunctions: | ||||
|         ignoreAnnotatedFunctions: ['Preview'] | ||||
|      | ||||
|     style: | ||||
|       MagicNumber: | ||||
|         ignorePropertyDeclaration: true | ||||
|         ignoreCompanionObjectPropertyDeclaration: true | ||||
|         ignoreAnnotated: ['Composable'] | ||||
|      | ||||
|       UnusedPrivateMember: | ||||
|         ignoreAnnotated: ['Composable'] | ||||
| """ + NonDefault | ||||
| @@ -0,0 +1,43 @@ | ||||
| package dev.adriankuta.flights | ||||
|  | ||||
| import com.android.build.api.dsl.ApplicationExtension | ||||
| import com.android.build.api.dsl.ApplicationProductFlavor | ||||
| import com.android.build.api.dsl.CommonExtension | ||||
| import org.gradle.api.Project | ||||
|  | ||||
| @Suppress("EnumEntryName") | ||||
| enum class FlavorDimension { | ||||
|     cost | ||||
| } | ||||
|  | ||||
| // The content for the app can either come from local static data which is useful for demo | ||||
| // purposes, or from a production backend server which supplies up-to-date, real content. | ||||
| // These two product flavors reflect this behaviour. | ||||
| @Suppress("EnumEntryName") | ||||
| enum class FlightsFlavor( | ||||
|     val dimension: FlavorDimension, | ||||
|     val applicationIdSuffix: String? = null, | ||||
| ) { | ||||
|     free(FlavorDimension.cost), | ||||
|     paid(FlavorDimension.cost, applicationIdSuffix = ".paid") | ||||
| } | ||||
|  | ||||
| fun Project.configureFlavors( | ||||
|     commonExtension: CommonExtension<*, *, *, *, *, *>, | ||||
| ) { | ||||
|     commonExtension.apply { | ||||
|         flavorDimensions += FlavorDimension.cost.name | ||||
|         productFlavors { | ||||
|             FlightsFlavor.values().forEach { | ||||
|                 create(it.name) { | ||||
|                     dimension = it.dimension.name | ||||
|                     if (this@apply is ApplicationExtension && this is ApplicationProductFlavor) { | ||||
|                         if (it.applicationIdSuffix != null) { | ||||
|                             applicationIdSuffix = it.applicationIdSuffix | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,48 @@ | ||||
| package dev.adriankuta.flights | ||||
|  | ||||
| import com.android.build.api.dsl.CommonExtension | ||||
| import com.android.build.api.dsl.ManagedVirtualDevice | ||||
| import org.gradle.api.Project | ||||
| import org.gradle.kotlin.dsl.dependencies | ||||
|  | ||||
| internal fun Project.configureGradleManagedDevices( | ||||
|     commonExtension: CommonExtension<*, *, *, *, *, *>, | ||||
| ) { | ||||
|     commonExtension.apply { | ||||
|         testOptions { | ||||
|             managedDevices { | ||||
|                 devices.register("pixel2api30", ManagedVirtualDevice::class.java) { | ||||
|                     device = "Pixel 2" | ||||
|                     apiLevel = 30 | ||||
|                     systemImageSource = "aosp" | ||||
|                 } | ||||
|  | ||||
| // Get rid of devices.register block and uncomment the following once we can update our AGP version. | ||||
| //                localDevices.create("pixel2api30") { | ||||
| //                    // Use device profiles you typically see in Android Studio. | ||||
| //                    device = "Pixel 2" | ||||
| //                    // Use only API levels 27 and higher. | ||||
| //                    apiLevel = 30 | ||||
| //                    // To include Google services, use "google". | ||||
| //                    systemImageSource = "aosp" | ||||
| //                } | ||||
|                 groups.create("default") { | ||||
|                     targetDevices.add(devices.getByName("pixel2api30")) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     dependencies { | ||||
|         // Something has gone awry in 8.3.0-rc01.  I robbed the following from here: | ||||
|         // https://sourceforge.net/projects/guava.mirror/files/v32.1.0/ | ||||
|         // If we are not on 8.3.0-rc01 anymore then remove this and run a test with gradle managed | ||||
|         // device (ie ./gradlew pixel2api30DevDebugAndroidTest).  If you dont see a dependancy problem | ||||
|         // with guava:listenablefuture then we are good to remove it. | ||||
|         modules { | ||||
|             module("com.google.guava:listenablefuture") { | ||||
|                 replacedBy("com.google.guava:guava", "listenablefuture is part of guava") | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,23 @@ | ||||
| package dev.adriankuta.flights | ||||
|  | ||||
| import org.gradle.api.Project | ||||
| import org.gradle.api.artifacts.VersionCatalogsExtension | ||||
| import org.gradle.kotlin.dsl.dependencies | ||||
| import org.gradle.kotlin.dsl.getByType | ||||
|  | ||||
| internal fun Project.configureHilt() { | ||||
|     val libs = extensions.getByType<VersionCatalogsExtension>().named("libs") | ||||
|  | ||||
|     dependencies { | ||||
|         "implementation"(libs.findLibrary("hilt.android").get()) | ||||
|         "ksp"(libs.findLibrary("hilt.compiler").get()) | ||||
|  | ||||
|         // For instrumentation tests | ||||
|         "androidTestImplementation"(libs.findLibrary("hilt.testing").get()) | ||||
|         "kspAndroidTest"(libs.findLibrary("hilt.compiler").get()) | ||||
|  | ||||
|         // For local unit tests hilt-android-testing | ||||
|         "testImplementation"(libs.findLibrary("hilt.testing").get()) | ||||
|         "kspTest"(libs.findLibrary("hilt.compiler").get()) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,18 @@ | ||||
| package dev.adriankuta.flights | ||||
|  | ||||
| import org.gradle.api.Project | ||||
| import org.gradle.api.artifacts.VersionCatalogsExtension | ||||
| import org.gradle.kotlin.dsl.dependencies | ||||
| import org.gradle.kotlin.dsl.getByType | ||||
|  | ||||
| internal fun Project.configureInstrumentation() { | ||||
|     val libs = extensions.getByType<VersionCatalogsExtension>().named("libs") | ||||
|  | ||||
|     dependencies { | ||||
|         "androidTestImplementation"(libs.findLibrary("truth").get()) | ||||
|         "androidTestImplementation"(libs.findLibrary("mockk.android").get()) | ||||
|         "androidTestImplementation"(libs.findLibrary("androidx.test.rules").get()) | ||||
|         "androidTestImplementation"(libs.findLibrary("androidx.test.uiautomator").get()) | ||||
|         //"androidTestImplementation"(libs.findLibrary("turbine").get()) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,148 @@ | ||||
| package dev.adriankuta.flights | ||||
|  | ||||
| import com.android.build.api.variant.AndroidComponentsExtension | ||||
| import org.gradle.api.Project | ||||
| import org.gradle.api.artifacts.VersionCatalogsExtension | ||||
| import org.gradle.api.tasks.testing.Test | ||||
| import org.gradle.kotlin.dsl.configure | ||||
| import org.gradle.kotlin.dsl.getByType | ||||
| import org.gradle.kotlin.dsl.register | ||||
| import org.gradle.kotlin.dsl.withType | ||||
| import org.gradle.testing.jacoco.plugins.JacocoPluginExtension | ||||
| import org.gradle.testing.jacoco.plugins.JacocoTaskExtension | ||||
| import org.gradle.testing.jacoco.tasks.JacocoReport | ||||
| import java.util.Locale | ||||
|  | ||||
| // Mostly robbed off: https://github.com/android/nowinandroid/blob/main/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Jacoco.kt | ||||
| // ./gradlew jacocoTestReport will run lint, all the tests and generate the test coverage. | ||||
| internal fun Project.configureJacoco( | ||||
|     androidComponentsExtension: AndroidComponentsExtension<*, *, *>, | ||||
| ) { | ||||
|     val libs = extensions.getByType<VersionCatalogsExtension>().named("libs") | ||||
|  | ||||
|     configure<JacocoPluginExtension> { | ||||
|         toolVersion = libs.findVersion("jacoco").get().toString() | ||||
|     } | ||||
|  | ||||
|     val jacocoTestReport = tasks.create("jacocoTestReport") { | ||||
|         group = "Verification" | ||||
|         description = "Create test coverage reports" | ||||
|     } | ||||
|  | ||||
|     androidComponentsExtension.onVariants { variant -> | ||||
|         if (variant.name.contains("DevDebug", ignoreCase = true)) { | ||||
|             val unitTestTaskName = "test${variant.name.capitalize()}UnitTest" | ||||
| //            val instrumentedTaskName = "defaultGroup${variant.name.capitalize()}AndroidTest" // This does dick on AGP version ancient (Weavr) | ||||
|             val instrumentedTaskName = "connected${variant.name.capitalize()}AndroidTest" | ||||
|             val lintTaskName = "lint${variant.name.capitalize()}" | ||||
|             val detektTaskName = "detekt${variant.name.capitalize()}" | ||||
|  | ||||
|             val buildDir = layout.buildDirectory.get().asFile | ||||
|             val reportTask = | ||||
|                 tasks.register( | ||||
|                     "jacoco${unitTestTaskName.capitalize()}Report", | ||||
|                     JacocoReport::class, | ||||
|                 ) { | ||||
|                     dependsOn(unitTestTaskName) | ||||
|  | ||||
|                     // Dont bother with teh instrumented test if there isnt any. | ||||
|                     if (file("${projectDir}/src/androidTest").walk().any { it.isFile }) { | ||||
|                         dependsOn(instrumentedTaskName) | ||||
|                     } | ||||
|  | ||||
|                     dependsOn(lintTaskName) | ||||
|                     dependsOn(detektTaskName) | ||||
|  | ||||
|                     reports { | ||||
|                         xml.required.set(true) | ||||
|                         html.required.set(true) | ||||
|                     } | ||||
|  | ||||
|                     classDirectories.setFrom( | ||||
|                         fileTree("$buildDir/tmp/kotlin-classes/${variant.name}") { | ||||
|                             exclude(coverageExclusions) | ||||
|                         }, | ||||
|                     ) | ||||
|  | ||||
|                     sourceDirectories.setFrom( | ||||
|                         files( | ||||
|                             "$projectDir/src/main/java", | ||||
|                             "$projectDir/src/main/kotlin", | ||||
|                         ), | ||||
|                     ) | ||||
|                     executionData.setFrom( | ||||
|                         fileTree("$buildDir") { | ||||
|                             include("outputs/unit_test_code_coverage/devDebugUnitTest/*.exec") | ||||
|                             include("outputs/managed_device_code_coverage/debug/flavors/dev/**/*.ec") | ||||
|                         }, | ||||
|                     ) | ||||
|                 } | ||||
|  | ||||
|             jacocoTestReport.dependsOn(reportTask) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     tasks.withType<Test>().configureEach { | ||||
|         configure<JacocoTaskExtension> { | ||||
|             // Required for JaCoCo + Robolectric | ||||
|             // https://github.com/robolectric/robolectric/issues/2230 | ||||
|             isIncludeNoLocationClasses = true | ||||
|  | ||||
|             // Required for JDK 11 with the above | ||||
|             // https://github.com/gradle/gradle/issues/5184#issuecomment-391982009 | ||||
|             excludes = listOf("jdk.internal.*") | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| private val coverageExclusions = listOf( | ||||
|     // data binding | ||||
|     "android/databinding/**/*.class", | ||||
|     "**/android/databinding/*Binding.class", | ||||
|     "**/android/databinding/*", | ||||
|     "**/androidx/databinding/*", | ||||
|     "**/BR.*", | ||||
|     // android | ||||
|     "**/R.class", | ||||
|     "**/R$*.class", | ||||
|     "**/BuildConfig.*", | ||||
|     "**/Manifest*.*", | ||||
|     "**/*Test*.*", | ||||
|     "android/**/*.*", | ||||
|     // butterKnife | ||||
|     "**/*\$ViewInjector*.*", | ||||
|     "**/*\$ViewBinder*.*", | ||||
|     // dagger | ||||
|     "**/*_MembersInjector.class", | ||||
|     "**/Dagger*Component.class", | ||||
|     "**/Dagger*Component\$Builder.class", | ||||
|     "**/*Module_*Factory.class", | ||||
|     "**/di/module/*", | ||||
|     "**/*_Factory*.*", | ||||
|     "**/*Module*.*", | ||||
|     "**/*Dagger*.*", | ||||
|     "**/*Hilt*.*", | ||||
|     // kotlin | ||||
|     "**/*MapperImpl*.*", | ||||
|     "**/*\$ViewInjector*.*", | ||||
|     "**/*\$ViewBinder*.*", | ||||
|     "**/BuildConfig.*", | ||||
|     "**/*Component*.*", | ||||
|     "**/*BR*.*", | ||||
|     "**/Manifest*.*", | ||||
|     "**/*\$Lambda$*.*", | ||||
|     "**/*Companion*.*", | ||||
|     "**/*Module*.*", | ||||
|     "**/*Dagger*.*", | ||||
|     "**/*Hilt*.*", | ||||
|     "**/*MembersInjector*.*", | ||||
|     "**/*_MembersInjector.class", | ||||
|     "**/*_Factory*.*", | ||||
|     "**/*_Provide*Factory*.*", | ||||
|     "**/*Extensions*.*", | ||||
|     "**/*JsonAdapter.*", | ||||
| ) | ||||
|  | ||||
| private fun String.capitalize() = replaceFirstChar { | ||||
|     if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() | ||||
| } | ||||
| @@ -0,0 +1,68 @@ | ||||
| package dev.adriankuta.flights | ||||
|  | ||||
| import com.android.build.api.dsl.CommonExtension | ||||
| import org.gradle.api.JavaVersion | ||||
| import org.gradle.api.Project | ||||
| import org.gradle.api.artifacts.VersionCatalogsExtension | ||||
| import org.gradle.kotlin.dsl.assign | ||||
| import org.gradle.kotlin.dsl.dependencies | ||||
| import org.gradle.kotlin.dsl.getByType | ||||
| import org.gradle.kotlin.dsl.provideDelegate | ||||
| import org.jetbrains.kotlin.gradle.dsl.JvmTarget | ||||
| import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension | ||||
|  | ||||
| internal fun Project.configureKotlinAndroid( | ||||
|     commonExtension: CommonExtension<*, *, *, *, *, *>, | ||||
| ) { | ||||
|     val libs = extensions.getByType<VersionCatalogsExtension>().named("libs") | ||||
|  | ||||
|     commonExtension.apply { | ||||
|         compileSdk = libs.findVersion("compileSdk").get().toString().toInt() | ||||
|  | ||||
|         defaultConfig { | ||||
|             minSdk = libs.findVersion("minSdk").get().toString().toInt() | ||||
|         } | ||||
|  | ||||
|         compileOptions { | ||||
|             sourceCompatibility = JavaVersion.VERSION_11 | ||||
|             targetCompatibility = JavaVersion.VERSION_11 | ||||
|             isCoreLibraryDesugaringEnabled = true | ||||
|         } | ||||
|  | ||||
|         packaging { | ||||
|             resources.excludes.add("/META-INF/{AL2.0,LGPL2.1}") | ||||
|             resources.excludes.add("/META-INF/LICENSE.md") | ||||
|             resources.excludes.add("/META-INF/LICENSE-notice.md") | ||||
|             resources.excludes.add("/META-INF/INDEX.LIST") | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     with(extensions.getByType<KotlinAndroidProjectExtension>()) { | ||||
|         compilerOptions { | ||||
|             // Treat all Kotlin warnings as errors (disabled by default) | ||||
|             // Override by setting warningsAsErrors=true in your ~/.gradle/gradle.properties | ||||
|             val warningsAsErrors: String? by project | ||||
|             allWarningsAsErrors = warningsAsErrors.toBoolean() | ||||
|  | ||||
|             freeCompilerArgs.addAll( | ||||
|                 listOf( | ||||
|                     "-opt-in=kotlin.RequiresOptIn", | ||||
|                     "-Xwhen-guards", | ||||
|                     // Enable experimental coroutines APIs, including Flow | ||||
|                     "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", | ||||
|                     "-opt-in=kotlinx.coroutines.FlowPreview", | ||||
|                 ), | ||||
|             ) | ||||
|  | ||||
|             jvmTarget.set(JvmTarget.JVM_11) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     dependencies { | ||||
|         "implementation"(libs.findLibrary("androidx.core.ktx").get()) | ||||
|         "implementation"(libs.findLibrary("kotlinx.coroutines.android").get()) | ||||
|         "implementation"(libs.findLibrary("timber").get()) | ||||
|  | ||||
|         "coreLibraryDesugaring"(libs.findLibrary("android.desugarJdkLibs").get()) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,57 @@ | ||||
| package dev.adriankuta.flights | ||||
|  | ||||
| import com.android.build.gradle.LibraryExtension | ||||
| import org.gradle.api.Project | ||||
| import org.gradle.api.artifacts.VersionCatalogsExtension | ||||
| import org.gradle.kotlin.dsl.configure | ||||
| import org.gradle.kotlin.dsl.getByType | ||||
| import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension | ||||
|  | ||||
| internal fun Project.configureLibrary() { | ||||
|     with(pluginManager) { | ||||
|         apply("com.android.library") | ||||
|         apply("io.gitlab.arturbosch.detekt") | ||||
|         apply("org.jetbrains.kotlin.android") | ||||
|         apply("org.gradle.jacoco") | ||||
|     } | ||||
|  | ||||
|     val libs = extensions.getByType<VersionCatalogsExtension>().named("libs") | ||||
|     val targetSdk = libs.findVersion("targetSdk").get().toString().toInt() | ||||
|  | ||||
|     // android block | ||||
|     extensions.configure<LibraryExtension> { | ||||
|         configureKotlinAndroid(this) | ||||
|         defaultConfig.targetSdk = targetSdk | ||||
|         defaultConfig.consumerProguardFiles("consumer-rules.pro") | ||||
|  | ||||
|         buildTypes { | ||||
|             release { | ||||
|                 proguardFiles( | ||||
|                     getDefaultProguardFile("proguard-android-optimize.txt"), | ||||
|                     "proguard-rules.pro", | ||||
|                 ) | ||||
|             } | ||||
|             debug { | ||||
|                 testCoverage { | ||||
|                     enableUnitTestCoverage = | ||||
|                         false // Test coverage spanks memory on the CI with ye older AGP | ||||
|                     enableAndroidTestCoverage = false | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         configureFlavors(this) | ||||
|         configureAndroidLint(this) | ||||
| //                configureGradleManagedDevices(this) | ||||
|     } | ||||
|  | ||||
| //            val extension = extensions.getByType<LibraryAndroidComponentsExtension>() | ||||
| //            configureJacoco(extension) | ||||
|     configureDetektDependencies() | ||||
|     //configureSonar() | ||||
|     configureUnitTests() | ||||
|  | ||||
|     extensions.configure<KotlinAndroidProjectExtension> { | ||||
|         //explicitApi() | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,33 @@ | ||||
| package dev.adriankuta.flights | ||||
|  | ||||
| import org.gradle.api.Project | ||||
|  | ||||
| // If have got Sonar running locally you can try it by setting up a project and then running this | ||||
| // script: | ||||
| // | ||||
| // #!/bin/bash -e | ||||
| // | ||||
| //./gradlew clean | ||||
| //./gradlew jacocoTestReport | ||||
| //./gradlew sonar \ | ||||
| //  -Dsonar.projectKey=YourProjectKey \ | ||||
| //  -Dsonar.projectName='YourProjectName' \ | ||||
| //  -Dsonar.host.url=http://localhost:9000 \ | ||||
| //  -Dsonar.token=sqp_sonarqubelkeywhateveritis | ||||
| // | ||||
| internal fun Project.configureSonar() { | ||||
| //    configure<SonarExtension> { | ||||
| //        properties { | ||||
| //            val buildDir = layout.buildDirectory.get().toString() | ||||
| //            property("sonar.androidLint.reportPaths", "$buildDir/reports/lint-results-devDebug.xml") | ||||
| //            property("sonar.core.codeCoveragePlugin", "jacoco") | ||||
| //            property("sonar.coverage.jacoco.xmlReportPaths", "$buildDir/reports/jacoco/**/*.xml") | ||||
| //            property("sonar.gradle.skipCompile", true) | ||||
| //            property("sonar.kotlin.detekt.reportPaths", "$buildDir/reports/detekt/devDebug.xml") | ||||
| //            property("sonar.verbose", true) | ||||
| // | ||||
| //            property("sonar.junit.reportPaths", | ||||
| //                "$buildDir/test-results/testDevDebugUnitTest,$buildDir/outputs/androidTest-results/managedDevice/debug/flavors/dev/pixel2api30") | ||||
| //        } | ||||
| //    } | ||||
| } | ||||
| @@ -0,0 +1,18 @@ | ||||
| package dev.adriankuta.flights | ||||
|  | ||||
| import org.gradle.api.Project | ||||
| import org.gradle.api.artifacts.VersionCatalogsExtension | ||||
| import org.gradle.kotlin.dsl.dependencies | ||||
| import org.gradle.kotlin.dsl.getByType | ||||
|  | ||||
| internal fun Project.configureUnitTests() { | ||||
|     val libs = extensions.getByType<VersionCatalogsExtension>().named("libs") | ||||
|     dependencies { | ||||
|         "testImplementation"(libs.findLibrary("junit4").get()) | ||||
|         "testImplementation"(libs.findLibrary("androidx.test.core").get()) | ||||
|         "testImplementation"(libs.findLibrary("kotlinx.coroutines.test").get()) | ||||
|         "testImplementation"(libs.findLibrary("truth").get()) | ||||
|         "testImplementation"(libs.findLibrary("mockk.android").get()) | ||||
|         //"testImplementation"(libs.findLibrary("turbine").get()) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										4
									
								
								build-logic/gradle.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								build-logic/gradle.properties
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| # Gradle properties are not passed to included builds https://github.com/gradle/gradle/issues/2534 | ||||
| org.gradle.parallel=true | ||||
| org.gradle.caching=true | ||||
| org.gradle.configureondemand=true | ||||
							
								
								
									
										30
									
								
								build-logic/settings.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								build-logic/settings.gradle.kts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| /* | ||||
|  * Copyright 2022 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     https://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| dependencyResolutionManagement { | ||||
|     repositories { | ||||
|         google() | ||||
|         mavenCentral() | ||||
|     } | ||||
|     versionCatalogs { | ||||
|         create("libs") { | ||||
|             from(files("../gradle/libs.versions.toml")) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| rootProject.name = "build-logic" | ||||
| include(":convention") | ||||
		Reference in New Issue
	
	Block a user