diff --git a/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt index 698bf7a79..824bf5dcf 100644 --- a/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidApplicationConventionPlugin.kt @@ -14,8 +14,10 @@ * limitations under the License. */ +import com.android.build.api.variant.ApplicationAndroidComponentsExtension import com.android.build.gradle.internal.dsl.BaseAppModuleExtension import com.google.samples.apps.nowinandroid.configureKotlinAndroid +import com.google.samples.apps.nowinandroid.configurePrintApksTask import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.configure @@ -32,6 +34,9 @@ class AndroidApplicationConventionPlugin : Plugin { configureKotlinAndroid(this) defaultConfig.targetSdk = 32 } + extensions.configure { + configurePrintApksTask(this) + } } } diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt index 6b2861fde..4c000737e 100644 --- a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt @@ -14,9 +14,11 @@ * limitations under the License. */ +import com.android.build.api.variant.LibraryAndroidComponentsExtension import com.android.build.gradle.LibraryExtension import com.google.samples.apps.nowinandroid.configureFlavors import com.google.samples.apps.nowinandroid.configureKotlinAndroid +import com.google.samples.apps.nowinandroid.configurePrintApksTask import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.artifacts.VersionCatalogsExtension @@ -37,7 +39,9 @@ class AndroidLibraryConventionPlugin : Plugin { defaultConfig.targetSdk = 32 configureFlavors(this) } - + extensions.configure { + configurePrintApksTask(this) + } val libs = extensions.getByType().named("libs") dependencies { configurations.configureEach { @@ -50,5 +54,4 @@ class AndroidLibraryConventionPlugin : Plugin { } } } - -} +} \ No newline at end of file diff --git a/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/PrintTestApks.kt b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/PrintTestApks.kt new file mode 100644 index 000000000..20e209aeb --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/PrintTestApks.kt @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package com.google.samples.apps.nowinandroid + +import com.android.build.api.artifact.SingleArtifact +import com.android.build.api.variant.AndroidComponentsExtension +import com.android.build.api.variant.BuiltArtifactsLoader +import com.android.build.api.variant.HasAndroidTest +import org.gradle.api.DefaultTask +import org.gradle.api.Project +import org.gradle.api.file.Directory +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.InputFiles +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.TaskAction +import java.io.File + +internal fun Project.configurePrintApksTask(extension: AndroidComponentsExtension<*, *, *>) { + extension.onVariants { variant -> + if (variant is HasAndroidTest) { + val loader = variant.artifacts.getBuiltArtifactsLoader() + val artifact = variant.androidTest?.artifacts?.get(SingleArtifact.APK) + val testSources = variant.androidTest?.sources?.java?.all + if (artifact != null && testSources != null) { + tasks.register( + "${variant.name}PrintTestApk", + PrintApkLocationTask::class.java + ) { + apkFolder.set(artifact) + builtArtifactsLoader.set(loader) + variantName.set(variant.name) + sources.set(testSources) + } + } + } + } +} + +internal abstract class PrintApkLocationTask : DefaultTask() { + @get:InputDirectory + abstract val apkFolder: DirectoryProperty + + @get:InputFiles + abstract val sources: ListProperty + + @get:Internal + abstract val builtArtifactsLoader: Property + + @get:Input + abstract val variantName: Property + + @TaskAction + fun taskAction() { + val hasFiles = sources.orNull?.any { directory -> + directory.asFileTree.files.any { it.isFile } + } ?: throw RuntimeException("Cannot check androidTest sources") + + // Don't print APK location if there are no androidTest source files + if (!hasFiles) { + return + } + + val builtArtifacts = builtArtifactsLoader.get().load(apkFolder.get()) + ?: throw RuntimeException("Cannot load APKs") + if (builtArtifacts.elements.size != 1) + throw RuntimeException("Expected one APK !") + val apk = File(builtArtifacts.elements.single().outputFile).toPath() + println(apk) + } +} \ No newline at end of file diff --git a/kokoro/build.sh b/kokoro/build.sh old mode 100644 new mode 100755 index 1d21ee299..c283382d7 --- a/kokoro/build.sh +++ b/kokoro/build.sh @@ -58,12 +58,12 @@ run_firebase_test_lab() { set +e # To not exit on an error to retry flaky tests local counter=0 local result=1 - local module=$1 + local testApk=$1 while [ $result != 0 -a $counter -lt $MAX_RETRY ]; do gcloud firebase test android run \ --type instrumentation \ --app "app/build/outputs/apk/demo/debug/app-demo-debug.apk" \ - --test "$module/build/outputs/apk/androidTest/demo/debug/$module-demo-debug-androidTest.apk" \ + --test "$testApk" \ --device-ids $deviceIds \ --os-version-ids $osVersionIds \ --locales en \ @@ -76,17 +76,14 @@ run_firebase_test_lab() { # All modules with androidTest to run tests on. -# This command will create a list like ["app", "sync"] based on which subdirectories -# (assumed to be modules) have an androidTest source directory. -# The sed regex pulls out the module name from the matched directory -modules=($(find . -regex ".*/src/androidTest" | sed -E 's|\./([^/]*)/.*|\1|g')) +testApks=($(./gradlew -q demoDebugPrintTestApk)) # Run all modules in parallel with Firebase Test Lab, and fail if any fail pids="" result=0 -for module in ${modules[@]}; do - run_firebase_test_lab $module & +for testApk in ${testApks[@]}; do + run_firebase_test_lab $testApk & pids="$pids $!" done