Skip to content

Commit

Permalink
Merge pull request #132 from gradle/tt/support-android-test-projects
Browse files Browse the repository at this point in the history
Add support for android-test projects for NiA benchmarks
  • Loading branch information
tresat authored Nov 1, 2024
2 parents c7c0a48 + ab9940b commit 766e6c6
Show file tree
Hide file tree
Showing 13 changed files with 295 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ gradlePlugin {
implementationClass = "org.gradle.api.experimental.android.application.StandaloneAndroidApplicationPlugin"
tags = setOf("declarative-gradle", "android")
}
create("android-test") {
id = "org.gradle.experimental.android-test"
displayName = "Android Test Experimental Declarative Plugin"
description = "Experimental declarative plugin for Android test projects"
implementationClass = "org.gradle.api.experimental.android.application.StandaloneAndroidTestPlugin"
tags = setOf("declarative-gradle", "android")
}
create("android-ecosystem") {
id = "org.gradle.experimental.android-ecosystem"
displayName = "Android Ecosystem Experimental Declarative Plugin"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.gradle.api.experimental.android;

import androidx.baselineprofile.gradle.consumer.BaselineProfileConsumerExtension;
import androidx.baselineprofile.gradle.producer.BaselineProfileProducerExtension;
import androidx.room.gradle.RoomExtension;
import com.android.build.api.dsl.BuildType;
import com.android.build.api.dsl.CommonExtension;
import com.android.build.api.dsl.ManagedVirtualDevice;
import com.android.build.api.dsl.UnitTestOptions;
import com.google.android.libraries.mapsplatform.secrets_gradle_plugin.SecretsPluginExtension;
import com.google.devtools.ksp.gradle.KspExtension;
Expand All @@ -12,7 +14,6 @@
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.experimental.android.extensions.BaselineProfile;
import org.gradle.api.experimental.android.extensions.testing.AndroidTestDependencies;
import org.gradle.api.experimental.android.extensions.testing.TestOptions;
import org.gradle.api.experimental.android.extensions.testing.Testing;
Expand All @@ -22,9 +23,11 @@

import static org.gradle.api.experimental.android.AndroidSupport.ifPresent;
import static org.gradle.api.experimental.android.extensions.ComposeSupport.configureCompose;
import static org.gradle.api.experimental.android.nia.NiaSupport.configureBaselineProfile;

@SuppressWarnings("UnstableApiUsage")
public abstract class AbstractAndroidSoftwarePlugin implements Plugin<Project> {
protected static final int DEFAULT_MIN_ANDROID_SDK = 21;
public static final int DEFAULT_MIN_ANDROID_SDK = 21;

protected abstract AndroidSoftware getAndroidSoftware();

Expand Down Expand Up @@ -64,6 +67,7 @@ public void apply(Project project) {
dslModel.getRoom().getVersion().convention("2.6.1");
dslModel.getLicenses().getEnabled().convention(false);
dslModel.getBaselineProfile().getEnabled().convention(false);
dslModel.getBaselineProfile().getUseConnectedDevices().convention(true);
dslModel.getSecrets().getEnabled().convention(false);

// Setup Test Options conventions
Expand Down Expand Up @@ -112,6 +116,9 @@ protected void linkDslModelToPlugin(Project project, AndroidSoftware dslModel, C
android.getCompileOptions().setSourceCompatibility(JavaVersion.toVersion(jdkVersion));
android.getCompileOptions().setTargetCompatibility(JavaVersion.toVersion(jdkVersion));
});
dslModel.getExperimentalProperties().forEach(property -> {
android.getExperimentalProperties().put(property.getName(), property.getValue());
});

// Link build types
AndroidSoftwareBuildTypes modelBuildType = dslModel.getBuildTypes();
Expand All @@ -129,8 +136,9 @@ protected void linkDslModelToPlugin(Project project, AndroidSoftware dslModel, C
configureLicenses(project, dslModel);

if (project.getExtensions().findByName("baselineProfile") != null) {
BaselineProfileConsumerExtension baselineProfileExtension = project.getExtensions().getByType(BaselineProfileConsumerExtension.class);
configureBaselineProfile(project, dslModel.getBaselineProfile(), baselineProfileExtension);
BaselineProfileProducerExtension baselineProfileProducerExtension = project.getExtensions().getByType(BaselineProfileProducerExtension.class);
BaselineProfileConsumerExtension baselineProfileConsumerExtension = project.getExtensions().getByType(BaselineProfileConsumerExtension.class);
configureBaselineProfile(project, dslModel.getBaselineProfile(), baselineProfileProducerExtension, baselineProfileConsumerExtension);
}

configureSecrets(project, dslModel);
Expand Down Expand Up @@ -211,6 +219,12 @@ protected void configureTesting(Project project, AndroidSoftware dslModel, Commo

TestOptions testOptions = testing.getTestOptions();
ifPresent(testOptions.getTestInstrumentationRunner(), android.getDefaultConfig()::setTestInstrumentationRunner);
testOptions.getManagedDevices().forEach(device -> {
ManagedVirtualDevice managedVirtualDevice = android.getTestOptions().getManagedDevices().getDevices().create(device.getName(), ManagedVirtualDevice.class);
ifPresent(device.getDevice(), managedVirtualDevice::setDevice);
ifPresent(device.getApiLevel(), managedVirtualDevice::setApiLevel);
ifPresent(device.getSystemImageSource(), managedVirtualDevice::setSystemImageSource);
});

UnitTestOptions unitTestOptions = android.getTestOptions().getUnitTests();
unitTestOptions.setIncludeAndroidResources(testOptions.getIncludeAndroidResources().get());
Expand Down Expand Up @@ -245,17 +259,6 @@ protected void configureKotlinSerialization(Project project, AndroidSoftware dsl
}
}

@SuppressWarnings("UnstableApiUsage")
private static void configureBaselineProfile(Project project, BaselineProfile baselineProfile, BaselineProfileConsumerExtension baselineProfileExtension) {
if (baselineProfile.getEnabled().get()) {
project.getPlugins().apply("androidx.baselineprofile");

baselineProfileExtension.setAutomaticGenerationDuringBuild(baselineProfile.getAutomaticGenerationDuringBuild().get());

project.getConfigurations().getByName("baselineProfile").fromDependencyCollector(baselineProfile.getDependencies().getProfile());
}
}

/**
* Links build types from the model to the android extension.
*/
Expand All @@ -270,11 +273,6 @@ protected void linkBuildType(Project project, BuildType buildType, AndroidSoftwa
model.getProguardFiles().get().forEach(proguardFile -> {
buildType.proguardFile(proguardFile.getName().get());
});

if (buildType.getExtensions().findByName("baselineProfile") != null) {
BaselineProfileConsumerExtension baselineProfileExtension = buildType.getExtensions().getByType(BaselineProfileConsumerExtension.class);
configureBaselineProfile(project, model.getBaselineProfile(), baselineProfileExtension);
}
}

@SuppressWarnings("UnstableApiUsage")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.gradle.api.Plugin;
import org.gradle.api.experimental.android.application.StandaloneAndroidApplicationPlugin;
import org.gradle.api.experimental.android.library.StandaloneAndroidLibraryPlugin;
import org.gradle.api.experimental.android.test.StandaloneAndroidTestPlugin;
import org.gradle.api.experimental.jvm.JvmEcosystemConventionsPlugin;
import org.gradle.api.initialization.Settings;
import org.gradle.api.internal.plugins.software.RegistersSoftwareTypes;
Expand All @@ -11,7 +12,7 @@
import javax.inject.Inject;

@SuppressWarnings("UnstableApiUsage")
@RegistersSoftwareTypes({StandaloneAndroidApplicationPlugin.class, StandaloneAndroidLibraryPlugin.class})
@RegistersSoftwareTypes({StandaloneAndroidApplicationPlugin.class, StandaloneAndroidLibraryPlugin.class, StandaloneAndroidTestPlugin.class})
public abstract class AndroidEcosystemPlugin implements Plugin<Settings> {
@Override
public void apply(Settings target) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.android.build.api.dsl.BaseFlavor;
import com.android.build.api.dsl.CommonExtension;
import org.gradle.api.Action;
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.experimental.android.extensions.BaselineProfile;
import org.gradle.api.experimental.android.extensions.Compose;
import org.gradle.api.experimental.android.extensions.CoreLibraryDesugaring;
Expand Down Expand Up @@ -158,4 +159,7 @@ default void lint(Action<? super Lint> action) {
default void secrets(Action<? super Secrets> action) {
action.execute(getSecrets());
}

@Nested
NamedDomainObjectContainer<ExperimentalProperty> getExperimentalProperties();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.gradle.api.experimental.android;

import org.gradle.api.Named;
import org.gradle.api.provider.Property;
import org.gradle.declarative.dsl.model.annotations.Restricted;

@Restricted
public interface ExperimentalProperty extends Named {
@Restricted
Property<Boolean> getValue();
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.gradle.declarative.dsl.model.annotations.Configuring;
import org.gradle.declarative.dsl.model.annotations.Restricted;

// TODO: This might be better split into separate producer/consumer parts
@Restricted
public interface BaselineProfile {
@Restricted
Expand All @@ -37,4 +38,10 @@ public interface BaselineProfile {
default void dependencies(Action<? super BaselineProfileDependencies> action) {
action.execute(getDependencies());
}

@Restricted
Property<String> getAdditionalManagedDevice();

@Restricted
Property<Boolean> getUseConnectedDevices();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.gradle.api.experimental.android.extensions.testing;

import org.gradle.api.Named;
import org.gradle.api.provider.Property;
import org.gradle.declarative.dsl.model.annotations.Restricted;

@Restricted
public interface ManagedDevice extends Named {
@Restricted
abstract Property<String> getDevice();

@Restricted
abstract Property<Integer> getApiLevel();

@Restricted
abstract Property<String> getSystemImageSource();
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

package org.gradle.api.experimental.android.extensions.testing;

import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Nested;
import org.gradle.declarative.dsl.model.annotations.Restricted;

@Restricted
Expand All @@ -29,4 +31,7 @@ public interface TestOptions {

@Restricted
Property<String> getTestInstrumentationRunner();

@Nested
NamedDomainObjectContainer<ManagedDevice> getManagedDevices();
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
@Restricted
public interface Testing {
/**
* Whether or not to set up Jacoco support.
* Whether to set up Jacoco support.
*/
@Nested
Jacoco getJacoco();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.gradle.api.experimental.android.nia;

import androidx.baselineprofile.gradle.consumer.BaselineProfileConsumerExtension;
import androidx.baselineprofile.gradle.producer.BaselineProfileProducerExtension;
import com.android.SdkConstants;
import com.android.build.api.artifact.SingleArtifact;
import com.android.build.api.dsl.ApplicationExtension;
Expand All @@ -16,15 +18,19 @@
import com.android.build.api.variant.BuiltArtifactsLoader;
import com.android.build.api.variant.HasAndroidTest;
import com.android.build.api.variant.LibraryAndroidComponentsExtension;
import com.android.build.api.variant.TestAndroidComponentsExtension;
import com.android.build.gradle.BaseExtension;
import com.android.build.gradle.TestExtension;
import com.dropbox.gradle.plugins.dependencyguard.DependencyGuardPluginExtension;
import com.google.firebase.crashlytics.buildtools.gradle.CrashlyticsExtension;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.text.WordUtils;
import org.gradle.api.*;
import org.gradle.api.experimental.android.AndroidSoftware;
import org.gradle.api.experimental.android.application.AndroidApplication;
import org.gradle.api.experimental.android.extensions.BaselineProfile;
import org.gradle.api.experimental.android.library.AndroidLibrary;
import org.gradle.api.experimental.android.test.AndroidTest;
import org.gradle.api.file.Directory;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.Copy;
Expand Down Expand Up @@ -65,11 +71,30 @@ public static boolean isNiaProject(Project project) {
return Objects.equals(project.getRootProject().getName().replace("-", ""), NiaSupport.NIA_PROJECT_NAME);
}

public static void configureNiaTest(Project project, AndroidTest dslModel) {
TestExtension androidTest = project.getExtensions().getByType(TestExtension.class);
TestAndroidComponentsExtension androidTestComponents = project.getExtensions().getByType(TestAndroidComponentsExtension.class);

androidTest.getDefaultConfig().setTargetSdkPreview(dslModel.getTargetSdk().getOrElse(DEFAULT_TARGET_SDK).toString());

configureFlavors(androidTest);

configureKotlin(project);

configureGradleManagedDevices(androidTest);
configurePrintApksTask(project, androidTestComponents);

if (project.getExtensions().findByName("baselineProfile") != null) {
BaselineProfileProducerExtension baselineProfileProducerExtension = project.getExtensions().getByType(BaselineProfileProducerExtension.class);
BaselineProfileConsumerExtension baselineProfileConsumerExtension = project.getExtensions().getByType(BaselineProfileConsumerExtension.class);
configureBaselineProfile(project, dslModel.getBaselineProfile(), baselineProfileProducerExtension, baselineProfileConsumerExtension);
}
}

public static void configureNiaLibrary(Project project, AndroidLibrary dslModel) {
LibraryExtension androidLib = project.getExtensions().getByType(LibraryExtension.class);
LibraryAndroidComponentsExtension androidLibComponents = project.getExtensions().getByType(LibraryAndroidComponentsExtension.class);

// TODO: This might be removable
//noinspection deprecation
androidLib.getDefaultConfig().setTargetSdkPreview(dslModel.getTargetSdk().getOrElse(DEFAULT_TARGET_SDK).toString());

Expand Down Expand Up @@ -430,4 +455,20 @@ private static void configureDependencyGuard(Project project, AndroidApplication
dependencyGuard.configuration(dslModel.getDependencyGuard().getConfigurationName().get());
}
}

@SuppressWarnings("UnstableApiUsage")
public static void configureBaselineProfile(Project project, BaselineProfile baselineProfile, BaselineProfileProducerExtension baselineProfileProducerExtension, BaselineProfileConsumerExtension baselineProfileConsumerExtension) {
if (baselineProfile.getEnabled().get()) {
project.getPlugins().apply("androidx.baselineprofile");

baselineProfileConsumerExtension.setAutomaticGenerationDuringBuild(baselineProfile.getAutomaticGenerationDuringBuild().get());

if (baselineProfile.getAdditionalManagedDevice().isPresent()) {
baselineProfileProducerExtension.getManagedDevices().add(baselineProfile.getAdditionalManagedDevice().get());
}
ifPresent(baselineProfile.getUseConnectedDevices(), baselineProfileProducerExtension::setUseConnectedDevices);

project.getConfigurations().getByName("baselineProfile").fromDependencyCollector(baselineProfile.getDependencies().getProfile());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package org.gradle.api.experimental.android.test;

import com.android.build.api.dsl.BaseFlavor;
import com.android.build.api.dsl.CommonExtension;
import org.gradle.api.Action;
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.experimental.android.ExperimentalProperty;
import org.gradle.api.experimental.android.extensions.BaselineProfile;
import org.gradle.api.experimental.android.extensions.testing.AndroidTestDependencies;
import org.gradle.api.experimental.android.extensions.testing.TestOptions;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Nested;
import org.gradle.declarative.dsl.model.annotations.Configuring;
import org.gradle.declarative.dsl.model.annotations.Restricted;

// TODO: This probably shouldn't extend AndroidSoftware, as it does not
// represent a project the produces production software. There should be a
// common AbstractAndroidPlugin that AndroidSoftwarePlugin and this plugin
// both extend that folds these commonalities back into it
public interface AndroidTest {
/**
* @see CommonExtension#getNamespace()
*/
@Restricted
Property<String> getNamespace();

/**
* @see CommonExtension#getCompileSdk()
*/
@Restricted
Property<Integer> getCompileSdk();

/**
* @see BaseFlavor#getMinSdk()
*/
@Restricted
Property<Integer> getMinSdk();

@Restricted
Property<Integer> getTargetSdk();

/**
* Flag to enable/disable generation of the `BuildConfig` class.
*
* Default value is `false`.
*/
@Restricted
Property<Boolean> getBuildConfig();

@Nested
BaselineProfile getBaselineProfile();

@Configuring
default void baselineProfile(Action<? super BaselineProfile> action) {
action.execute(getBaselineProfile());
}

@Nested
NamedDomainObjectContainer<ExperimentalProperty> getExperimentalProperties();

@Nested
AndroidTestDependencies getDependencies();

@Configuring
default void dependencies(Action<? super AndroidTestDependencies> action) {
action.execute(getDependencies());
}

@Nested
TestOptions getTestOptions();

@Configuring
default void testOptions(Action<? super TestOptions> action) {
action.execute(getTestOptions());
}

@Restricted
Property<String> getTargetProjectPath();
}
Loading

0 comments on commit 766e6c6

Please sign in to comment.