From a13958123642dc8a23dc382ab82ca988f7b1d410 Mon Sep 17 00:00:00 2001 From: Matt Creaser Date: Thu, 2 May 2024 12:11:20 -0300 Subject: [PATCH 1/3] Add convention plugins for Android Libraries --- annotations/build.gradle.kts | 4 +- .../apollo-appsync-amplify/build.gradle.kts | 4 +- apollo/apollo-appsync/build.gradle.kts | 1 + .../aws-sdk-appsync-amplify/build.gradle.kts | 4 +- appsync/aws-sdk-appsync-core/build.gradle.kts | 1 + .../aws-sdk-appsync-events/build.gradle.kts | 6 +- aws-analytics-pinpoint/build.gradle.kts | 6 +- aws-api-appsync/build.gradle.kts | 4 +- aws-api/build.gradle.kts | 4 +- aws-auth-cognito/build.gradle.kts | 6 +- aws-auth-plugins-core/build.gradle.kts | 6 +- aws-core/build.gradle.kts | 4 +- aws-datastore/build.gradle.kts | 4 +- aws-geo-location/build.gradle.kts | 4 +- aws-logging-cloudwatch/build.gradle.kts | 6 +- aws-pinpoint-core/build.gradle.kts | 6 +- aws-predictions-tensorflow/build.gradle.kts | 4 +- aws-predictions/build.gradle.kts | 6 +- .../build.gradle.kts | 4 +- .../build.gradle.kts | 4 +- aws-storage-s3/build.gradle.kts | 4 +- build-logic/plugins/.gitignore | 1 + build-logic/plugins/build.gradle.kts | 57 ++++++ .../kotlin/AndroidLibraryConventionPlugin.kt | 156 ++++++++++++++ .../kotlin/ApiValidatorConventionPlugin.kt | 37 ++++ .../src/main/kotlin/KoverConventionPlugin.kt | 47 +++++ .../src/main/kotlin/KtLintConventionPlugin.kt | 36 ++++ .../main/kotlin/LicensesConventionPlugin.kt | 66 ++++++ build-logic/plugins/src/main/kotlin/Util.kt | 28 +++ build-logic/settings.gradle.kts | 30 +++ build.gradle.kts | 193 ++---------------- common-core/build.gradle.kts | 6 +- core-kotlin/build.gradle.kts | 4 +- core/build.gradle.kts | 6 +- gradle/libs.versions.toml | 20 ++ gradle/wrapper/gradle-wrapper.properties | 2 +- maplibre-adapter/build.gradle.kts | 6 +- rxbindings/build.gradle.kts | 4 +- settings.gradle.kts | 4 +- testmodels/build.gradle.kts | 3 +- testutils/build.gradle.kts | 5 +- 41 files changed, 557 insertions(+), 246 deletions(-) create mode 100644 build-logic/plugins/.gitignore create mode 100644 build-logic/plugins/build.gradle.kts create mode 100644 build-logic/plugins/src/main/kotlin/AndroidLibraryConventionPlugin.kt create mode 100644 build-logic/plugins/src/main/kotlin/ApiValidatorConventionPlugin.kt create mode 100644 build-logic/plugins/src/main/kotlin/KoverConventionPlugin.kt create mode 100644 build-logic/plugins/src/main/kotlin/KtLintConventionPlugin.kt create mode 100644 build-logic/plugins/src/main/kotlin/LicensesConventionPlugin.kt create mode 100644 build-logic/plugins/src/main/kotlin/Util.kt create mode 100644 build-logic/settings.gradle.kts diff --git a/annotations/build.gradle.kts b/annotations/build.gradle.kts index c9931da5e6..afe594bc8a 100644 --- a/annotations/build.gradle.kts +++ b/annotations/build.gradle.kts @@ -14,11 +14,9 @@ */ plugins { - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) // todo this does not need to be an android library } -apply(from = rootProject.file("configuration/checkstyle.gradle")) apply(from = rootProject.file("configuration/publishing.gradle")) group = properties["POM_GROUP"].toString() diff --git a/apollo/apollo-appsync-amplify/build.gradle.kts b/apollo/apollo-appsync-amplify/build.gradle.kts index 4341af1493..6099886b05 100644 --- a/apollo/apollo-appsync-amplify/build.gradle.kts +++ b/apollo/apollo-appsync-amplify/build.gradle.kts @@ -1,9 +1,9 @@ import java.util.Properties plugins { - id("com.android.library") - id("kotlin-android") alias(libs.plugins.apollo) + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/publishing.gradle")) diff --git a/apollo/apollo-appsync/build.gradle.kts b/apollo/apollo-appsync/build.gradle.kts index 2d827ce4d8..9ae4f01ce1 100644 --- a/apollo/apollo-appsync/build.gradle.kts +++ b/apollo/apollo-appsync/build.gradle.kts @@ -19,6 +19,7 @@ plugins { id("java-library") id("maven-publish") alias(libs.plugins.kotlin.jvm) + alias(libs.plugins.amplify.api) } java { diff --git a/appsync/aws-sdk-appsync-amplify/build.gradle.kts b/appsync/aws-sdk-appsync-amplify/build.gradle.kts index 89801fea8a..1e202cb79b 100644 --- a/appsync/aws-sdk-appsync-amplify/build.gradle.kts +++ b/appsync/aws-sdk-appsync-amplify/build.gradle.kts @@ -16,8 +16,8 @@ import java.util.Properties plugins { - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/publishing.gradle")) diff --git a/appsync/aws-sdk-appsync-core/build.gradle.kts b/appsync/aws-sdk-appsync-core/build.gradle.kts index 519c7274cf..ea473d46a2 100644 --- a/appsync/aws-sdk-appsync-core/build.gradle.kts +++ b/appsync/aws-sdk-appsync-core/build.gradle.kts @@ -19,6 +19,7 @@ plugins { id("java-library") id("maven-publish") alias(libs.plugins.kotlin.jvm) + alias(libs.plugins.amplify.api) } java { diff --git a/appsync/aws-sdk-appsync-events/build.gradle.kts b/appsync/aws-sdk-appsync-events/build.gradle.kts index 41b18df97f..c601c70f8b 100644 --- a/appsync/aws-sdk-appsync-events/build.gradle.kts +++ b/appsync/aws-sdk-appsync-events/build.gradle.kts @@ -16,9 +16,9 @@ import java.util.Properties plugins { - id("com.android.library") - id("kotlin-android") - id("org.jetbrains.kotlin.plugin.serialization") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/publishing.gradle")) diff --git a/aws-analytics-pinpoint/build.gradle.kts b/aws-analytics-pinpoint/build.gradle.kts index ac6bd40caf..e5c92ee758 100644 --- a/aws-analytics-pinpoint/build.gradle.kts +++ b/aws-analytics-pinpoint/build.gradle.kts @@ -14,9 +14,9 @@ */ plugins { - id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10" - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) diff --git a/aws-api-appsync/build.gradle.kts b/aws-api-appsync/build.gradle.kts index 98db533630..b7556ff45e 100644 --- a/aws-api-appsync/build.gradle.kts +++ b/aws-api-appsync/build.gradle.kts @@ -14,8 +14,8 @@ */ plugins { - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) diff --git a/aws-api/build.gradle.kts b/aws-api/build.gradle.kts index 527d4db024..e5ae033595 100644 --- a/aws-api/build.gradle.kts +++ b/aws-api/build.gradle.kts @@ -14,8 +14,8 @@ */ plugins { - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) diff --git a/aws-auth-cognito/build.gradle.kts b/aws-auth-cognito/build.gradle.kts index 4727ce19df..ffd5ec6520 100644 --- a/aws-auth-cognito/build.gradle.kts +++ b/aws-auth-cognito/build.gradle.kts @@ -14,9 +14,9 @@ */ plugins { - id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10" - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/publishing.gradle")) diff --git a/aws-auth-plugins-core/build.gradle.kts b/aws-auth-plugins-core/build.gradle.kts index 48dec87016..0c7c65b51a 100644 --- a/aws-auth-plugins-core/build.gradle.kts +++ b/aws-auth-plugins-core/build.gradle.kts @@ -14,9 +14,9 @@ */ plugins { - id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10" - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) diff --git a/aws-core/build.gradle.kts b/aws-core/build.gradle.kts index 61ebfd06e2..b9c532f02b 100644 --- a/aws-core/build.gradle.kts +++ b/aws-core/build.gradle.kts @@ -14,8 +14,8 @@ */ plugins { - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) diff --git a/aws-datastore/build.gradle.kts b/aws-datastore/build.gradle.kts index 785f249d0c..63b2fd2a2c 100644 --- a/aws-datastore/build.gradle.kts +++ b/aws-datastore/build.gradle.kts @@ -14,8 +14,8 @@ */ plugins { - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) diff --git a/aws-geo-location/build.gradle.kts b/aws-geo-location/build.gradle.kts index 56f51c0100..f41223acaa 100644 --- a/aws-geo-location/build.gradle.kts +++ b/aws-geo-location/build.gradle.kts @@ -14,8 +14,8 @@ */ plugins { - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) apply(from = rootProject.file("configuration/publishing.gradle")) diff --git a/aws-logging-cloudwatch/build.gradle.kts b/aws-logging-cloudwatch/build.gradle.kts index 3ea4674e75..81e8e02e32 100644 --- a/aws-logging-cloudwatch/build.gradle.kts +++ b/aws-logging-cloudwatch/build.gradle.kts @@ -14,9 +14,9 @@ */ plugins { - id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10" - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) diff --git a/aws-pinpoint-core/build.gradle.kts b/aws-pinpoint-core/build.gradle.kts index 5b53aa7ac9..d761fa787f 100644 --- a/aws-pinpoint-core/build.gradle.kts +++ b/aws-pinpoint-core/build.gradle.kts @@ -14,9 +14,9 @@ */ plugins { - id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10" - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) diff --git a/aws-predictions-tensorflow/build.gradle.kts b/aws-predictions-tensorflow/build.gradle.kts index 01af8a2223..a2fb0d3ebb 100644 --- a/aws-predictions-tensorflow/build.gradle.kts +++ b/aws-predictions-tensorflow/build.gradle.kts @@ -14,8 +14,8 @@ */ plugins { - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) diff --git a/aws-predictions/build.gradle.kts b/aws-predictions/build.gradle.kts index 9512ae24b7..9542165e26 100644 --- a/aws-predictions/build.gradle.kts +++ b/aws-predictions/build.gradle.kts @@ -14,9 +14,9 @@ */ plugins { - id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10" - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) diff --git a/aws-push-notifications-pinpoint-common/build.gradle.kts b/aws-push-notifications-pinpoint-common/build.gradle.kts index 6f489c20c7..9d1bd67c87 100644 --- a/aws-push-notifications-pinpoint-common/build.gradle.kts +++ b/aws-push-notifications-pinpoint-common/build.gradle.kts @@ -14,8 +14,8 @@ */ plugins { - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) diff --git a/aws-push-notifications-pinpoint/build.gradle.kts b/aws-push-notifications-pinpoint/build.gradle.kts index a276230be5..91ab9f6b3d 100644 --- a/aws-push-notifications-pinpoint/build.gradle.kts +++ b/aws-push-notifications-pinpoint/build.gradle.kts @@ -14,8 +14,8 @@ */ plugins { - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) diff --git a/aws-storage-s3/build.gradle.kts b/aws-storage-s3/build.gradle.kts index eff192706f..b770e240de 100644 --- a/aws-storage-s3/build.gradle.kts +++ b/aws-storage-s3/build.gradle.kts @@ -14,8 +14,8 @@ */ plugins { - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) diff --git a/build-logic/plugins/.gitignore b/build-logic/plugins/.gitignore new file mode 100644 index 0000000000..796b96d1c4 --- /dev/null +++ b/build-logic/plugins/.gitignore @@ -0,0 +1 @@ +/build diff --git a/build-logic/plugins/build.gradle.kts b/build-logic/plugins/build.gradle.kts new file mode 100644 index 0000000000..6d2326dd2d --- /dev/null +++ b/build-logic/plugins/build.gradle.kts @@ -0,0 +1,57 @@ +/* + * Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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` + alias(libs.plugins.ktlint) +} + +ktlint { + android.set(true) +} + +dependencies { + compileOnly(libs.plugin.android.gradle) + compileOnly(libs.plugin.binary.compatibility) + compileOnly(libs.plugin.kotlin.android) + compileOnly(libs.plugin.kover) + compileOnly(libs.plugin.ktlint) + compileOnly(libs.plugin.licensee) +} + +gradlePlugin { + plugins { + register("androidLibrary") { + id = libs.plugins.amplify.android.library.get().pluginId + implementationClass = "AndroidLibraryConventionPlugin" + } + register("apiValidator") { + id = libs.plugins.amplify.api.get().pluginId + implementationClass = "ApiValidatorConventionPlugin" + } + register("ktlint") { + id = libs.plugins.amplify.ktlint.get().pluginId + implementationClass = "KtLintConventionPlugin" + } + register("kover") { + id = libs.plugins.amplify.kover.get().pluginId + implementationClass = "KoverConventionPlugin" + } + register("licenses") { + id = libs.plugins.amplify.licenses.get().pluginId + implementationClass = "LicensesConventionPlugin" + } + } +} diff --git a/build-logic/plugins/src/main/kotlin/AndroidLibraryConventionPlugin.kt b/build-logic/plugins/src/main/kotlin/AndroidLibraryConventionPlugin.kt new file mode 100644 index 0000000000..6e9364a7d9 --- /dev/null +++ b/build-logic/plugins/src/main/kotlin/AndroidLibraryConventionPlugin.kt @@ -0,0 +1,156 @@ +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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.LibraryExtension +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.tasks.compile.JavaCompile +import org.gradle.api.tasks.testing.Test +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.dependencies +import org.gradle.kotlin.dsl.extra +import org.gradle.kotlin.dsl.provideDelegate +import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +/** + * This convention plugin configures an Android library module + */ +@Suppress("LocalVariableName") +class AndroidLibraryConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target.pluginManager) { + apply("com.android.library") + apply("org.jetbrains.kotlin.android") + + // Apply other convention plugins + apply("amplify.licenses") + apply("amplify.ktlint") + apply("amplify.kover") + } + + @Suppress("ktlint:standard:property-naming") + val POM_GROUP: String by target + + with(target) { + group = POM_GROUP + extensions.configure { + configureAndroid(this) + } + + tasks.withType().configureEach { + options.compilerArgs.apply { + add("-Xlint:all") + add("-Werror") + } + } + + tasks.withType().configureEach { + minHeapSize = "128m" + maxHeapSize = "4g" + } + + configure { + jvmToolchain(17) + } + + tasks.withType().configureEach { + kotlinOptions { + freeCompilerArgs = freeCompilerArgs + amplifyInternalMarkers.map { "-opt-in=$it" } + } + } + } + } + + private fun Project.configureAndroid(extension: LibraryExtension) { + val sdkVersionName = findProperty("VERSION_NAME") ?: rootProject.findProperty("VERSION_NAME") + + if (hasProperty("signingKeyId")) { + println("Getting signing info from protected source.") + extra["signing.keyId"] = findProperty("signingKeyId") + extra["signing.password"] = findProperty("signingPassword") + extra["signing.inMemoryKey"] = findProperty("signingInMemoryKey") + } + + extension.apply { + compileSdk = 34 + + buildFeatures { + buildConfig = true + } + + defaultConfig { + minSdk = 24 + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + testInstrumentationRunnerArguments += "clearPackageData" to "true" + consumerProguardFiles += rootProject.file("configuration/consumer-rules.pro") + buildConfigField("String", "VERSION_NAME", "\"$sdkVersionName\"") + } + + testOptions { + animationsDisabled = true + unitTests { + isIncludeAndroidResources = true + } + execution = "ANDROIDX_TEST_ORCHESTRATOR" + } + + lint { + warningsAsErrors = true + abortOnError = true + enable += listOf("UnusedResources") + disable += listOf( + "GradleDependency", + "NewerVersionAvailable", + "AndroidGradlePluginVersion", + "CredentialDependency" + ) + } + + compileOptions { + isCoreLibraryDesugaringEnabled = true + } + + // Needed when running integration tests. The oauth2 library uses relies on two + // dependencies (Apache's httpcore and httpclient), both of which include + // META-INF/DEPENDENCIES. Tried a couple other options to no avail. + packaging { + resources.excludes.addAll( + listOf( + "META-INF/DEPENDENCIES", + "META-INF/LICENSE.md", + "META-INF/LICENSE-notice.md" + ) + ) + } + + publishing { + singleVariant("release") { + withSourcesJar() + } + } + } + + dependencies { + "coreLibraryDesugaring"(libs.findLibrary("android-desugartools").get()) + constraints { + add("implementation", libs.findLibrary("androidx-annotation-experimental").get()) { + because("Fixes a lint bug with RequiresOptIn") + } + } + } + } +} diff --git a/build-logic/plugins/src/main/kotlin/ApiValidatorConventionPlugin.kt b/build-logic/plugins/src/main/kotlin/ApiValidatorConventionPlugin.kt new file mode 100644 index 0000000000..2015a3899f --- /dev/null +++ b/build-logic/plugins/src/main/kotlin/ApiValidatorConventionPlugin.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 kotlinx.validation.ApiValidationExtension +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure + +/** + * This plugin configures the [Binary Compatibility Validator](https://github.com/Kotlin/binary-compatibility-validator) + * to ensure that we don't change public API surface unintentionally. + */ +class ApiValidatorConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + pluginManager.apply("org.jetbrains.kotlinx.binary-compatibility-validator") + + extensions.configure { + // Ignore anything marked with an internal API marker + nonPublicMarkers += amplifyInternalMarkers + nonPublicMarkers += "androidx.annotation.VisibleForTesting" + } + } + } +} diff --git a/build-logic/plugins/src/main/kotlin/KoverConventionPlugin.kt b/build-logic/plugins/src/main/kotlin/KoverConventionPlugin.kt new file mode 100644 index 0000000000..42da3203aa --- /dev/null +++ b/build-logic/plugins/src/main/kotlin/KoverConventionPlugin.kt @@ -0,0 +1,47 @@ +import kotlinx.kover.gradle.plugin.dsl.KoverProjectExtension +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.tasks.testing.Test +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.withType + +/* + * Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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. + */ + +class KoverConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + pluginManager.apply("org.jetbrains.kotlinx.kover") + extensions.configure { + currentProject { + instrumentation { + excludedClasses.add("jdk.internal.*") + } + } + reports { + filters.excludes.androidGeneratedClasses() + total { + xml.onCheck.set(false) + html.onCheck.set(false) + } + } + } + + tasks.withType { + excludes += "okttp3.*" // added to resolve conflict with mockk + } + } + } +} diff --git a/build-logic/plugins/src/main/kotlin/KtLintConventionPlugin.kt b/build-logic/plugins/src/main/kotlin/KtLintConventionPlugin.kt new file mode 100644 index 0000000000..2b20b3649e --- /dev/null +++ b/build-logic/plugins/src/main/kotlin/KtLintConventionPlugin.kt @@ -0,0 +1,36 @@ + +/* + * Copyright 2023 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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 org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.jlleitschuh.gradle.ktlint.KtlintExtension + +/** + * Applies and configures the KtLint plugin + */ +class KtLintConventionPlugin : Plugin { + override fun apply(target: Project) { + target.pluginManager.apply("org.jlleitschuh.gradle.ktlint") + target.extensions.configure { + version.set("1.5.0") + android.set(true) + filter { + exclude("**/generated/**") + } + } + } +} diff --git a/build-logic/plugins/src/main/kotlin/LicensesConventionPlugin.kt b/build-logic/plugins/src/main/kotlin/LicensesConventionPlugin.kt new file mode 100644 index 0000000000..1d33abfe77 --- /dev/null +++ b/build-logic/plugins/src/main/kotlin/LicensesConventionPlugin.kt @@ -0,0 +1,66 @@ +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure + +/* + * Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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. + */ + +/** + * Applies and configures the [Licensee Plugin](https://github.com/cashapp/licensee) to ensure all our dependencies + * (and transitive dependencies) are using allowed licenses. + */ +class LicensesConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + pluginManager.apply("app.cash.licensee") + + extensions.configure { + allow("Apache-2.0") + allow("MIT") + + allowUrl("http://aws.amazon.com/apache2.0") + allowUrl("https://developer.android.com/studio/terms.html") + + ignoreDependencies("javax.annotation", "javax.annotation-api") { + because("Transitive dependency for androidx.test.espresso:espresso-core") + } + ignoreDependencies("org.junit", "junit-bom") { + because("Unit Testing Dependency") + } + ignoreDependencies("org.junit", "jupiter") { + because("Unit Testing Dependency") + } + ignoreDependencies("org.junit.jupiter", "junit-jupiter") { + because("Unit Testing Dependency") + } + ignoreDependencies("org.junit.jupiter", "junit-jupiter-params") { + because("Unit Testing Dependency") + } + ignoreDependencies("org.junit", "junit-jupiter-params") { + because("Unit Testing Dependency") + } + ignoreDependencies("org.junit.platform", "junit-platform-commons") { + because("Unit Testing Dependency") + } + ignoreDependencies("org.junit.platform", "junit-platform-engine") { + because("Unit Testing Dependency") + } + ignoreDependencies("junit", "junit") { + because("Unit Testing Dependency") + } + } + } + } +} diff --git a/build-logic/plugins/src/main/kotlin/Util.kt b/build-logic/plugins/src/main/kotlin/Util.kt new file mode 100644 index 0000000000..5364e0e5f9 --- /dev/null +++ b/build-logic/plugins/src/main/kotlin/Util.kt @@ -0,0 +1,28 @@ +import org.gradle.api.Project +import org.gradle.api.artifacts.VersionCatalog +import org.gradle.api.artifacts.VersionCatalogsExtension +import org.gradle.kotlin.dsl.getByType + +/* + * Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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. + */ + +val amplifyInternalMarkers = listOf( + "com.amplifyframework.annotations.InternalApiWarning", + "com.amplifyframework.annotations.InternalAmplifyApi", + "com.amplifyframework.annotations.AmplifyFlutterApi" +) + +internal val Project.libs + get(): VersionCatalog = extensions.getByType().named("libs") diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts new file mode 100644 index 0000000000..b2962124d6 --- /dev/null +++ b/build-logic/settings.gradle.kts @@ -0,0 +1,30 @@ +/* + * Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file 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() + maven("https://plugins.gradle.org/m2/") + } + versionCatalogs { + create("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} + +rootProject.name = "build-logic" +include(":plugins") diff --git a/build.gradle.kts b/build.gradle.kts index 37b19a2469..b39ffd0e2e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,12 +13,6 @@ * permissions and limitations under the License. */ -import app.cash.licensee.LicenseeExtension -import com.android.build.gradle.LibraryExtension -import kotlinx.validation.ApiValidationExtension -import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - buildscript { repositories { google() @@ -29,195 +23,34 @@ buildscript { dependencies { classpath(kotlin("gradle-plugin", version = "1.9.10")) classpath("com.google.gms:google-services:4.3.15") - classpath("org.jlleitschuh.gradle:ktlint-gradle:12.2.0") - classpath("app.cash.licensee:licensee-gradle-plugin:1.7.0") } } plugins { - alias(libs.plugins.binary.compatibility.validator) + alias(libs.plugins.android.library) apply false + alias(libs.plugins.apollo) apply false + alias(libs.plugins.binary.compatibility.validator) apply false alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.kotlin.jvm) apply false + alias(libs.plugins.kotlin.parcelize) apply false alias(libs.plugins.kotlin.serialization) apply false - alias(libs.plugins.android.library) apply false alias(libs.plugins.kover) -} + alias(libs.plugins.ktlint) apply false + alias(libs.plugins.licensee) apply false -allprojects { - gradle.projectsEvaluated { - tasks.withType().configureEach { - options.compilerArgs.apply { - add("-Xlint:all") - // add("-Werror") - } - } - tasks.withType().configureEach { - minHeapSize = "128m" - maxHeapSize = "4g" - } - } + // Convention plugins + alias(libs.plugins.amplify.android.library) apply false + alias(libs.plugins.amplify.api) apply false + alias(libs.plugins.amplify.kover) apply false + alias(libs.plugins.amplify.ktlint) apply false + alias(libs.plugins.amplify.licenses) apply false } tasks.register("clean").configure { delete(rootProject.layout.buildDirectory) } -val internalApiAnnotations = listOf( - "com.amplifyframework.annotations.InternalApiWarning", - "com.amplifyframework.annotations.InternalAmplifyApi", - "com.amplifyframework.annotations.AmplifyFlutterApi" -) - -subprojects { - apply(plugin = "org.jlleitschuh.gradle.ktlint") - - configure { - version.set("1.5.0") - android.set(true) - filter { - exclude("**/generated/**") - } - } - - apply(plugin = "app.cash.licensee") - afterEvaluate { - configure { - allow("Apache-2.0") - allow("MIT") - allow("BSD-2-Clause") - allow("CC0-1.0") - allowUrl("https://developer.android.com/studio/terms.html") - allowDependency("net.zetetic", "sqlcipher-android", "4.6.1") { - because("BSD style License") - } - allowDependency("org.jetbrains", "annotations", "16.0.1") { - because("Apache-2.0, but typo in license URL fixed in newer versions") - } - allowDependency("org.mockito", "mockito-core", "3.9.0") { - because("MIT license") - } - allowDependency("junit", "junit", "4.13.2") { - because("Test Dependency") - } - allowUrl("https://raw.githubusercontent.com/apollographql/apollo-kotlin/main/LICENSE") { - because("MIT license") - } - } - - configureAndroid() - - if (!project.name.contains("test")) { - apply(from = rootProject.file("kover.gradle")) - } - } - - tasks.withType { - kotlinOptions { - internalApiAnnotations.forEach { - freeCompilerArgs += "-opt-in=$it" - } - } - } - - pluginManager.withPlugin("kotlin-android") { - configure { - jvmToolchain(17) - } - } -} - -@Suppress("ExpiredTargetSdkVersion") -fun Project.configureAndroid() { - if (hasProperty("signingKeyId")) { - println("Getting signing info from protected source.") - extra["signing.keyId"] = findProperty("signingKeyId") - extra["signing.password"] = findProperty("signingPassword") - extra["signing.inMemoryKey"] = findProperty("signingInMemoryKey") - } - - pluginManager.withPlugin("com.android.library") { - val sdkVersionName = findProperty("VERSION_NAME") ?: rootProject.findProperty("VERSION_NAME") - - configure { - compileSdk = 34 - - buildFeatures { - // Allow specifying custom buildConfig fields - buildConfig = true - } - - defaultConfig { - minSdk = 24 - testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" - testInstrumentationRunnerArguments += "clearPackageData" to "true" - consumerProguardFiles += rootProject.file("configuration/consumer-rules.pro") - buildConfigField("String", "VERSION_NAME", "\"$sdkVersionName\"") - } - - testOptions { - animationsDisabled = true - unitTests { - isIncludeAndroidResources = true - } - execution = "ANDROIDX_TEST_ORCHESTRATOR" - } - - lint { - warningsAsErrors = true - abortOnError = true - enable += listOf("UnusedResources") - disable += listOf( - "GradleDependency", - "NewerVersionAvailable", - "AndroidGradlePluginVersion", - "CredentialDependency" - ) - } - - compileOptions { - isCoreLibraryDesugaringEnabled = true - } - - // Needed when running integration tests. The oauth2 library uses relies on two - // dependencies (Apache's httpcore and httpclient), both of which include - // META-INF/DEPENDENCIES. Tried a couple other options to no avail. - packaging { - resources.excludes.addAll( - listOf( - "META-INF/DEPENDENCIES", - "META-INF/LICENSE.md", - "META-INF/LICENSE-notice.md" - ) - ) - } - - publishing { - singleVariant("release") { - withSourcesJar() - } - } - } - - dependencies { - add("coreLibraryDesugaring", libs.android.desugartools) - constraints { - add("implementation", libs.androidx.annotation.experimental) { - because("Fixes a lint bug with RequiresOptIn") - } - } - } - } -} - -apply(from = rootProject.file("configuration/instrumentation-tests.gradle")) - -configure { - // Interfaces marked with an internal API annotation are not part of the public API - nonPublicMarkers.addAll(internalApiAnnotations) - nonPublicMarkers.add("androidx.annotation.VisibleForTesting") - - ignoredProjects.addAll(setOf("testutils", "testmodels", "annotations")) -} +// apply(from = rootProject.file("configuration/instrumentation-tests.gradle")) dependencies { subprojects.forEach { diff --git a/common-core/build.gradle.kts b/common-core/build.gradle.kts index 40419f7578..453afe6c40 100644 --- a/common-core/build.gradle.kts +++ b/common-core/build.gradle.kts @@ -14,9 +14,9 @@ */ plugins { - id("com.android.library") - id("kotlin-android") - id("kotlin-parcelize") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.kotlin.parcelize) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) diff --git a/core-kotlin/build.gradle.kts b/core-kotlin/build.gradle.kts index fba2206b7b..1b5b675526 100644 --- a/core-kotlin/build.gradle.kts +++ b/core-kotlin/build.gradle.kts @@ -14,8 +14,8 @@ */ plugins { - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/publishing.gradle")) diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 023f636973..ef5b0a07fb 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -14,9 +14,9 @@ */ plugins { - id("org.jetbrains.kotlin.plugin.serialization") - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7312241564..042d8a7696 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -37,6 +37,8 @@ kotest = "5.9.0" kotlin = "1.9.10" kotlin-serialization = "1.6.0" kover = "0.9.1" +ktlint = "12.2.0" +licensee = "1.7.0" maplibre = "9.6.0" maplibre-annotations = "1.0.0" material = "1.8.0" @@ -141,11 +143,29 @@ test-robolectric = { module = "org.robolectric:robolectric", version.ref="robole test-totp = { module = "dev.robinohs:totp-kt", version.ref="totp" } test-turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine"} +# Dependencies for convention plugins +plugin-android-gradle = { module = "com.android.tools.build:gradle", version.ref = "agp" } +plugin-binary-compatibility = { module = "org.jetbrains.kotlinx:binary-compatibility-validator", version.ref = "binary-compatibility-validator" } +plugin-kotlin-android = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } +plugin-kover = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kover" } +plugin-ktlint = { module = "org.jlleitschuh.gradle:ktlint-gradle", version.ref = "ktlint" } +plugin-licensee = { module = "app.cash.licensee:app.cash.licensee.gradle.plugin", version.ref = "licensee" } + [plugins] android-library = { id = "com.android.library", version.ref = "agp" } apollo = { id = "com.apollographql.apollo", version.ref = "apollo" } binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } +ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" } +licensee = { id = "app.cash.licensee", version.ref = "licensee" } + +# Internal convention plugins +amplify-android-library = { id = "amplify.android.library" } +amplify-api = { id = "amplify.api" } +amplify-ktlint = { id = "amplify.ktlint" } +amplify-licenses = { id = "amplify.licenses" } +amplify-kover = { id = "amplify.kover" } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 48c0a02ca4..0d1842103b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/maplibre-adapter/build.gradle.kts b/maplibre-adapter/build.gradle.kts index f21c87e678..9e5e4d6ca7 100644 --- a/maplibre-adapter/build.gradle.kts +++ b/maplibre-adapter/build.gradle.kts @@ -14,9 +14,9 @@ */ plugins { - id("com.android.library") - id("kotlin-android") - id("kotlin-parcelize") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.kotlin.parcelize) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) apply(from = rootProject.file("configuration/publishing.gradle")) diff --git a/rxbindings/build.gradle.kts b/rxbindings/build.gradle.kts index 7ba754de99..5b19c6e624 100644 --- a/rxbindings/build.gradle.kts +++ b/rxbindings/build.gradle.kts @@ -14,8 +14,8 @@ */ plugins { - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.amplify.api) } apply(from = rootProject.file("configuration/checkstyle.gradle")) diff --git a/settings.gradle.kts b/settings.gradle.kts index 87defeea17..2417850b90 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -14,9 +14,11 @@ */ pluginManagement { + includeBuild("build-logic") repositories { gradlePluginPortal() google() + mavenCentral() } } @@ -47,6 +49,7 @@ include(":aws-predictions") include(":aws-predictions-tensorflow") include(":aws-push-notifications-pinpoint") include(":aws-storage-s3") +include(":aws-logging-cloudwatch") // Test Utilities and assets include(":testutils") @@ -59,7 +62,6 @@ include(":aws-api-appsync") include(":maplibre-adapter") include(":aws-pinpoint-core") include(":aws-push-notifications-pinpoint-common") -include(":aws-logging-cloudwatch") // Events API include(":aws-sdk-appsync-core") diff --git a/testmodels/build.gradle.kts b/testmodels/build.gradle.kts index 40d3e81f69..2ed19c5149 100644 --- a/testmodels/build.gradle.kts +++ b/testmodels/build.gradle.kts @@ -14,8 +14,7 @@ */ plugins { - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) } android { diff --git a/testutils/build.gradle.kts b/testutils/build.gradle.kts index 3d2f5ec6a5..d7a6477504 100644 --- a/testutils/build.gradle.kts +++ b/testutils/build.gradle.kts @@ -14,9 +14,8 @@ */ plugins { - id("org.jetbrains.kotlin.plugin.serialization") version "1.9.10" - id("com.android.library") - id("kotlin-android") + alias(libs.plugins.amplify.android.library) + alias(libs.plugins.kotlin.parcelize) } apply(from = rootProject.file("configuration/checkstyle.gradle")) From 55f89b07be89fa0711d9d6699f5ab7acf2c7f527 Mon Sep 17 00:00:00 2001 From: Matt Creaser Date: Thu, 10 Jul 2025 13:09:57 -0300 Subject: [PATCH 2/3] Uncomment instrumentation tests --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index b39ffd0e2e..4f5c46a458 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -50,7 +50,7 @@ tasks.register("clean").configure { delete(rootProject.layout.buildDirectory) } -// apply(from = rootProject.file("configuration/instrumentation-tests.gradle")) +apply(from = rootProject.file("configuration/instrumentation-tests.gradle")) dependencies { subprojects.forEach { From f21b4a4032ac1c603e2e0f89fa509ef94b0392dc Mon Sep 17 00:00:00 2001 From: Matt Creaser Date: Thu, 10 Jul 2025 13:10:07 -0300 Subject: [PATCH 3/3] Fix license check --- .../main/kotlin/LicensesConventionPlugin.kt | 37 ++++++------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/build-logic/plugins/src/main/kotlin/LicensesConventionPlugin.kt b/build-logic/plugins/src/main/kotlin/LicensesConventionPlugin.kt index 1d33abfe77..9e2bdd65c1 100644 --- a/build-logic/plugins/src/main/kotlin/LicensesConventionPlugin.kt +++ b/build-logic/plugins/src/main/kotlin/LicensesConventionPlugin.kt @@ -29,36 +29,23 @@ class LicensesConventionPlugin : Plugin { extensions.configure { allow("Apache-2.0") allow("MIT") - - allowUrl("http://aws.amazon.com/apache2.0") + allow("BSD-2-Clause") + allow("CC0-1.0") allowUrl("https://developer.android.com/studio/terms.html") - - ignoreDependencies("javax.annotation", "javax.annotation-api") { - because("Transitive dependency for androidx.test.espresso:espresso-core") - } - ignoreDependencies("org.junit", "junit-bom") { - because("Unit Testing Dependency") - } - ignoreDependencies("org.junit", "jupiter") { - because("Unit Testing Dependency") - } - ignoreDependencies("org.junit.jupiter", "junit-jupiter") { - because("Unit Testing Dependency") - } - ignoreDependencies("org.junit.jupiter", "junit-jupiter-params") { - because("Unit Testing Dependency") + allowDependency("net.zetetic", "sqlcipher-android", "4.6.1") { + because("BSD style License") } - ignoreDependencies("org.junit", "junit-jupiter-params") { - because("Unit Testing Dependency") + allowDependency("org.jetbrains", "annotations", "16.0.1") { + because("Apache-2.0, but typo in license URL fixed in newer versions") } - ignoreDependencies("org.junit.platform", "junit-platform-commons") { - because("Unit Testing Dependency") + allowDependency("org.mockito", "mockito-core", "3.9.0") { + because("MIT license") } - ignoreDependencies("org.junit.platform", "junit-platform-engine") { - because("Unit Testing Dependency") + allowDependency("junit", "junit", "4.13.2") { + because("Test Dependency") } - ignoreDependencies("junit", "junit") { - because("Unit Testing Dependency") + allowUrl("https://raw.githubusercontent.com/apollographql/apollo-kotlin/main/LICENSE") { + because("MIT license") } } }