| |
| /* |
| * Copyright (C) 2020 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 |
| * |
| * http://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.android.build.api.apiTest |
| import com.google.common.truth.Truth |
| import org.gradle.testkit.runner.TaskOutcome |
| import org.junit.Test |
| import java.io.File |
| import kotlin.test.assertNotNull |
| |
| class KotlinScriptApiTests: VariantApiBaseTest(TestType.Script) { |
| private val testingElements= TestingElements(scriptingLanguage) |
| @Test |
| fun getApksTest() { |
| given { |
| tasksToInvoke.add(":app:debugDisplayApks") |
| addModule(":app") { |
| @Suppress("RemoveExplicitTypeArguments") |
| buildFile = |
| // language=kotlin |
| """ |
| plugins { |
| id("com.android.application") |
| kotlin("android") |
| kotlin("android.extensions") |
| } |
| import org.gradle.api.DefaultTask |
| import org.gradle.api.file.DirectoryProperty |
| import org.gradle.api.tasks.InputFiles |
| import org.gradle.api.tasks.TaskAction |
| |
| import com.android.build.api.variant.BuiltArtifactsLoader |
| import com.android.build.api.artifact.ArtifactType |
| import org.gradle.api.provider.Property |
| import org.gradle.api.tasks.Internal |
| |
| ${testingElements.getDisplayApksTask()} |
| android { |
| ${testingElements.addCommonAndroidBuildLogic()} |
| |
| onVariantProperties { |
| project.tasks.register<DisplayApksTask>("${ '$' }{name}DisplayApks") { |
| apkFolder.set(artifacts.get(ArtifactType.APK)) |
| builtArtifactsLoader.set(artifacts.getBuiltArtifactsLoader()) |
| } |
| } |
| } |
| """.trimIndent() |
| testingElements.addManifest( this) |
| } |
| } |
| withDocs { |
| index = |
| // language=markdown |
| """ |
| # artifacts.get in Kotlin |
| |
| This sample show how to obtain a built artifact from the AGP. The built artifact is identified by |
| its [ArtifactType] and in this case, it's [ArtifactType.APK]. |
| The [onVariantProperties] block will wire the [DisplayApksTask] input property (apkFolder) by using |
| the [Artifacts.get] call with the right [ArtifactType] |
| `apkFolder.set(artifacts.get(ArtifactType.APK))` |
| Since more than one APK can be produced by the build when dealing with multi-apk, you should use the |
| [BuiltArtifacts] interface to load the metadata associated with produced files using |
| [BuiltArtifacts.load] method. |
| `builtArtifactsLoader.get().load(apkFolder.get())' |
| Once loaded, the built artifacts can be accessed. |
| ## To Run |
| /path/to/gradle debugDisplayApks |
| expected result : "Got an APK...." message. |
| """.trimIndent() |
| } |
| check { |
| assertNotNull(this) |
| Truth.assertThat(output).contains("Got an APK") |
| Truth.assertThat(output).contains("BUILD SUCCESSFUL") |
| } |
| } |
| @Test |
| fun manifestReplacementTest() { |
| given { |
| tasksToInvoke.add(":app:processDebugResources") |
| addModule(":app") { |
| buildFile = |
| // language=kotlin |
| """ |
| plugins { |
| id("com.android.application") |
| kotlin("android") |
| kotlin("android.extensions") |
| } |
| import org.gradle.api.DefaultTask |
| import org.gradle.api.file.RegularFileProperty |
| import org.gradle.api.tasks.InputFile |
| import org.gradle.api.tasks.OutputFile |
| import org.gradle.api.tasks.TaskAction |
| import com.android.build.api.artifact.ArtifactType |
| ${testingElements.getGitVersionTask()} |
| ${testingElements.getManifestProducerTask()} |
| android { |
| ${testingElements.addCommonAndroidBuildLogic()} |
| |
| val gitVersionProvider = tasks.register<GitVersionTask>("gitVersionProvider") { |
| gitVersionOutputFile.set( |
| File(project.buildDir, "intermediates/gitVersionProvider/output")) |
| outputs.upToDateWhen { false } |
| } |
| onVariantProperties { |
| val manifestProducer = tasks.register<ManifestProducerTask>("${'$'}{name}ManifestProducer") { |
| gitInfoFile.set(gitVersionProvider.flatMap(GitVersionTask::gitVersionOutputFile)) |
| outputManifest.set( |
| File(project.buildDir, "intermediates/${'$'}{name}/ManifestProducer/output") |
| ) |
| } |
| artifacts.use(manifestProducer) |
| .wiredWith(ManifestProducerTask::outputManifest) |
| .toCreate(ArtifactType.MERGED_MANIFEST) |
| } |
| } |
| """.trimIndent() |
| testingElements.addManifest(this) |
| testingElements.addMainActivity(this) |
| } |
| } |
| check { |
| assertNotNull(this) |
| Truth.assertThat(output).contains("BUILD SUCCESSFUL") |
| arrayOf( |
| ":app:gitVersionProvider", |
| ":app:debugManifestProducer" |
| ).forEach { |
| val task = task(it) |
| assertNotNull(task) |
| Truth.assertThat(task.outcome).isEqualTo(TaskOutcome.SUCCESS) |
| } |
| Truth.assertThat(task(":app:processDebugMainManifest")).isNull() |
| } |
| } |
| |
| @Test |
| fun manifestTransformerTest() { |
| given { |
| addModule(":app") { |
| buildFile = |
| // language=kotlin |
| """ |
| plugins { |
| id("com.android.application") |
| kotlin("android") |
| kotlin("android.extensions") |
| } |
| ${testingElements.getGitVersionTask()} |
| |
| ${testingElements.getManifestTransformerTask()} |
| android { |
| ${testingElements.addCommonAndroidBuildLogic()} |
| |
| onVariantProperties { |
| val gitVersionProvider = tasks.register<GitVersionTask>("${'$'}{name}GitVersionProvider") { |
| gitVersionOutputFile.set( |
| File(project.buildDir, "intermediates/gitVersionProvider/output")) |
| outputs.upToDateWhen { false } |
| } |
| |
| val manifestUpdater = tasks.register<ManifestTransformerTask>("${'$'}{name}ManifestUpdater") { |
| gitInfoFile.set(gitVersionProvider.flatMap(GitVersionTask::gitVersionOutputFile)) |
| } |
| artifacts.use(manifestUpdater) |
| .wiredWithFiles( |
| ManifestTransformerTask::mergedManifest, |
| ManifestTransformerTask::updatedManifest) |
| .toTransform(com.android.build.api.artifact.ArtifactType.MERGED_MANIFEST) |
| } |
| } |
| """.trimIndent() |
| testingElements.addManifest(this) |
| } |
| } |
| check { |
| assertNotNull(this) |
| Truth.assertThat(output).contains("BUILD SUCCESSFUL") |
| arrayOf( |
| ":app:debugGitVersionProvider", |
| ":app:processDebugMainManifest", |
| ":app:debugManifestUpdater" |
| ).forEach { |
| val task = task(it) |
| assertNotNull(task) |
| Truth.assertThat(task.outcome).isEqualTo(TaskOutcome.SUCCESS) |
| } |
| } |
| } |
| |
| @Test |
| fun workerEnabledTransformation() { |
| val outFolderForApk = File(testProjectDir.root, "${testName.methodName}/build/acme_apks") |
| given { |
| tasksToInvoke.add(":app:copyDebugApks") |
| addModule(":app") { |
| // language=kotlin |
| buildFile = """ |
| plugins { |
| id("com.android.application") |
| kotlin("android") |
| kotlin("android.extensions") |
| } |
| import java.io.Serializable |
| import javax.inject.Inject |
| import org.gradle.api.DefaultTask |
| import org.gradle.api.file.RegularFileProperty |
| import org.gradle.api.tasks.InputFile |
| import org.gradle.api.tasks.OutputFile |
| import org.gradle.api.tasks.TaskAction |
| import org.gradle.workers.WorkerExecutor |
| import com.android.build.api.artifact.ArtifactType |
| import com.android.build.api.artifact.ArtifactTransformationRequest |
| import com.android.build.api.variant.BuiltArtifact |
| |
| ${testingElements.getCopyApksTask()} |
| |
| android { |
| ${testingElements.addCommonAndroidBuildLogic()} |
| |
| onVariantProperties { |
| val copyApksProvider = tasks.register<CopyApksTask>("copy${'$'}{name}Apks") |
| |
| val transformationRequest = artifacts.use(copyApksProvider) |
| .wiredWithDirectories( |
| CopyApksTask::apkFolder, |
| CopyApksTask::outFolder) |
| .toTransformMany(ArtifactType.APK) |
| |
| |
| copyApksProvider.configure { |
| this.transformationRequest.set(transformationRequest) |
| this.outFolder.set(File("${outFolderForApk.absolutePath}")) |
| } |
| } |
| } |
| """.trimIndent() |
| testingElements.addManifest(this) |
| } |
| } |
| check { |
| assertNotNull(this) |
| Truth.assertThat(output).contains("BUILD SUCCESSFUL") |
| val task = task(":app:copydebugApks") |
| assertNotNull(task) |
| Truth.assertThat(task.outcome).isEqualTo(TaskOutcome.SUCCESS) |
| Truth.assertThat(outFolderForApk.listFiles()?.asList()?.map { it.name }).containsExactly( |
| "app-debug.apk", "output-metadata.json" |
| ) |
| } |
| } |
| |
| @Test |
| fun getMappingFile() { |
| given { |
| tasksToInvoke.add(":app:debugMappingFileUpload") |
| addModule(":app") { |
| @Suppress("RemoveExplicitTypeArguments") |
| buildFile = |
| // language=kotlin |
| """ |
| plugins { |
| id("com.android.application") |
| kotlin("android") |
| kotlin("android.extensions") |
| } |
| import org.gradle.api.DefaultTask |
| import org.gradle.api.file.RegularFileProperty |
| import org.gradle.api.tasks.InputFile |
| import org.gradle.api.tasks.TaskAction |
| |
| import com.android.build.api.variant.BuiltArtifactsLoader |
| import com.android.build.api.artifact.ArtifactType |
| import org.gradle.api.provider.Property |
| import org.gradle.api.tasks.Internal |
| |
| abstract class MappingFileUploadTask: DefaultTask() { |
| |
| @get:InputFile |
| abstract val mappingFile: RegularFileProperty |
| |
| @TaskAction |
| fun taskAction() { |
| println("Uploading ${'$'}{mappingFile.get().asFile.absolutePath} to fantasy server...") |
| } |
| } |
| android { |
| ${testingElements.addCommonAndroidBuildLogic()} |
| buildTypes { |
| getByName("debug") { |
| isMinifyEnabled = true |
| } |
| } |
| |
| onVariantProperties { |
| project.tasks.register<MappingFileUploadTask>("${ '$' }{name}MappingFileUpload") { |
| mappingFile.set(artifacts.get(ArtifactType.OBFUSCATION_MAPPING_FILE)) |
| } |
| } |
| } |
| """.trimIndent() |
| testingElements.addManifest(this) |
| } |
| } |
| withDocs { |
| index = |
| // language=markdown |
| """ |
| # artifacts.get in Kotlin |
| |
| This sample show how to obtain the obfuscation mapping file from the AGP. |
| The [onVariantProperties] block will wire the [MappingFileUploadTask] input property (apkFolder) by using |
| the [Artifacts.get] call with the right [ArtifactType] |
| `mapping.set(artifacts.get(ArtifactType.OBFUSCATION_MAPPING_FILE))` |
| ## To Run |
| /path/to/gradle debugMappingFileUpload |
| expected result : "Uploading .... to a fantasy server...s" message. |
| """.trimIndent() |
| } |
| check { |
| assertNotNull(this) |
| Truth.assertThat(output).contains("Uploading") |
| Truth.assertThat(output).contains("BUILD SUCCESSFUL") |
| } |
| } |
| |
| @Test |
| fun getBundleTest() { |
| given { |
| tasksToInvoke.add(":app:debugDisplayBundleFile") |
| addModule(":app") { |
| @Suppress("RemoveExplicitTypeArguments") |
| buildFile = |
| // language=kotlin |
| """ |
| plugins { |
| id("com.android.application") |
| kotlin("android") |
| kotlin("android.extensions") |
| } |
| import org.gradle.api.DefaultTask |
| import org.gradle.api.file.RegularFileProperty |
| import org.gradle.api.tasks.InputFile |
| import org.gradle.api.tasks.TaskAction |
| import com.android.build.api.variant.BuiltArtifactsLoader |
| import com.android.build.api.artifact.ArtifactType |
| import org.gradle.api.provider.Property |
| import org.gradle.api.tasks.Internal |
| |
| abstract class DisplayBundleFileTask: DefaultTask() { |
| @get:InputFile |
| abstract val bundleFile: RegularFileProperty |
| |
| @TaskAction |
| fun taskAction() { |
| println("Got the Bundle ${'$'}{bundleFile.get().asFile.absolutePath}") |
| } |
| } |
| android { |
| ${testingElements.addCommonAndroidBuildLogic()} |
| defaultConfig { |
| versionCode = 3 |
| } |
| |
| onVariantProperties { |
| project.tasks.register<DisplayBundleFileTask>("${ '$' }{name}DisplayBundleFile") { |
| bundleFile.set(artifacts.get(ArtifactType.BUNDLE)) |
| } |
| } |
| } |
| """.trimIndent() |
| testingElements.addManifest(this) |
| } |
| } |
| withDocs { |
| index = |
| // language=markdown |
| """ |
| # Artifacts.get in Kotlin |
| |
| This sample shows how to obtain the bundle file from the AGP. |
| The [onVariantProperties] block will wire the [DisplayBundleFile] input property (bundleFile) by using |
| the Artifacts.get call with the right ArtifactType |
| `bundleFile.set(artifacts.get(ArtifactType.BUNDLE))` |
| ## To Run |
| /path/to/gradle debugDisplayBundleFile |
| expected result : "Got the Bundle ...." message. |
| """.trimIndent() |
| } |
| check { |
| assertNotNull(this) |
| Truth.assertThat(output).contains("Got the Bundle") |
| Truth.assertThat(output).contains("BUILD SUCCESSFUL") |
| } |
| } |
| |
| @Test |
| fun bundleTransformerTest() { |
| given { |
| tasksToInvoke.add(":app:debugConsumeBundleFile") |
| addModule(":app") { |
| @Suppress("RemoveExplicitTypeArguments") |
| buildFile = |
| // language=kotlin |
| """ |
| plugins { |
| id("com.android.application") |
| kotlin("android") |
| kotlin("android.extensions") |
| } |
| import org.gradle.api.DefaultTask |
| import org.gradle.api.file.RegularFileProperty |
| import org.gradle.api.tasks.InputFiles |
| import org.gradle.api.tasks.TaskAction |
| import org.gradle.api.provider.Property |
| import org.gradle.api.tasks.Internal |
| import com.android.build.api.artifact.ArtifactType |
| import org.gradle.api.tasks.OutputFile |
| import com.android.utils.appendCapitalized |
| |
| abstract class UpdateBundleFileTask: DefaultTask() { |
| @get: InputFiles |
| abstract val initialBundleFile: RegularFileProperty |
| |
| @get: OutputFile |
| abstract val updatedBundleFile: RegularFileProperty |
| |
| @TaskAction |
| fun taskAction() { |
| val versionCode = "versionCode = 4" |
| println("bundleFilePresent = " + initialBundleFile.isPresent) |
| updatedBundleFile.get().asFile.writeText(versionCode) |
| } |
| } |
| abstract class ConsumeBundleFileTask: DefaultTask() { |
| @get: InputFiles |
| abstract val finalBundle: RegularFileProperty |
| |
| @TaskAction |
| fun taskAction() { |
| println(finalBundle.get().asFile.readText()) |
| } |
| } |
| android { |
| ${testingElements.addCommonAndroidBuildLogic()} |
| defaultConfig { |
| versionCode = 3 |
| } |
| |
| onVariantProperties { |
| val updateBundle = project.tasks.register<UpdateBundleFileTask>("${'$'}{name}UpdateBundleFile") { |
| initialBundleFile.set(artifacts.get(ArtifactType.BUNDLE)) |
| } |
| val finalBundle = project.tasks.register<ConsumeBundleFileTask>("${'$'}{name}ConsumeBundleFile") { |
| finalBundle.set(artifacts.get(ArtifactType.BUNDLE)) |
| } |
| artifacts.use(updateBundle) |
| .wiredWithFiles( |
| UpdateBundleFileTask::initialBundleFile, |
| UpdateBundleFileTask::updatedBundleFile) |
| .toTransform(ArtifactType.BUNDLE) |
| } |
| } |
| """.trimIndent() |
| testingElements.addManifest(this) |
| } |
| } |
| check { |
| assertNotNull(this) |
| Truth.assertThat(output).contains("true") |
| Truth.assertThat(output).contains("versionCode = 4") |
| Truth.assertThat(output).contains("BUILD SUCCESSFUL") |
| } |
| } |
| |
| } |