Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add primary configuration parameter #24

Merged
merged 1 commit into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions generator/api/generator.api
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public abstract class ru/pixnews/gradle/fbase/FbaseGeneratorExtension : com/andr
public static final field Companion Lru/pixnews/gradle/fbase/FbaseGeneratorExtension$Companion;
public abstract fun getAddGoogleAppIdResource ()Lorg/gradle/api/provider/Property;
public abstract fun getConfigurations ()Lorg/gradle/api/NamedDomainObjectContainer;
public abstract fun getPrimaryConfiguration ()Lorg/gradle/api/provider/Property;
}

public final class ru/pixnews/gradle/fbase/FbaseGeneratorExtension$Companion {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,8 @@ class FbaseConfigGeneratorGradlePluginFunctionalTest {

AndroidAppFlavorsFixtures.testedVariants.forEach { testedVariant ->
val apk = ApkAnalyzer(submoduleDir.resolve(testedVariant.apkPath))
// TODO
// assertThat(apk.getStringResource("google_app_id"))
// .isEqualTo(testedVariant.expectedGoogleAppId)
assertThat(apk.getStringResource("google_app_id"))
.isEqualTo(testedVariant.expectedGoogleAppId)

testedVariant.expectedBuilders.forEach { (className, expectedOptions) ->
val code = apk.getDexCode("com.example.samplefbase.config.$className")
Expand Down Expand Up @@ -195,10 +194,83 @@ class FbaseConfigGeneratorGradlePluginFunctionalTest {
assertTrue(result.output.contains("BUILD SUCCESSFUL"))
}

@Test
fun `should fail when multiple configurations are defined and the main configuration is not set`() {
val submoduleName = "android-app-multimple-config-no-primary"
project.setupTestProjectScaffold(submoduleName)

val buildGradleKts = submoduleFixtures.buildGradleKts(
"""
firebaseConfig {
configurations {
create("firebaseOptions1") {
}
create("firebaseOptions2") {
}
}
}
""".trimIndent(),
)
project.writeFilesToSubmoduleRoot(
submoduleName = submoduleName,
buildGradleKts,
submoduleFixtures.application,
)
project.writeFiles(
project.rootDir,
Root.defaultFirebaseProperties,
)

val result = project.buildAndFail("assemble")

assertTrue(
result.output.contains(
"FbaseGeneratorExtension.primaryConfiguration must be set when using multiple configurations",
),
)
}

@Test
fun `should fail when multiple configurations are defined and the main configuration is set to a non-existent`() {
val submoduleName = "android-app-multimple-config-wrong-primary"
project.setupTestProjectScaffold(submoduleName)

val buildGradleKts = submoduleFixtures.buildGradleKts(
"""
firebaseConfig {
primaryConfiguration = "firebaseOptions3"
configurations {
create("firebaseOptions1") {
}
create("firebaseOptions2") {
}
}
}
""".trimIndent(),
)
project.writeFilesToSubmoduleRoot(
submoduleName = submoduleName,
buildGradleKts,
submoduleFixtures.application,
)
project.writeFiles(
project.rootDir,
Root.defaultFirebaseProperties,
)

val result = project.buildAndFail("assemble")

assertTrue(
result.output.contains(
"Configuration named `firebaseOptions3` is not defined",
),
)
}

@Nested
inner class PropertiesFileTests {
@Test
fun `should tail if properties file not found`() {
fun `should fail if properties file not found`() {
val submoduleName = "android-app-no-properties-file"
project.setupTestProjectScaffold(submoduleName)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.android.build.api.variant.Variant
import com.android.build.api.variant.VariantExtension
import com.android.build.api.variant.VariantExtensionConfig
import com.android.build.gradle.api.AndroidBasePlugin
import org.gradle.api.InvalidUserDataException
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Plugin
import org.gradle.api.Project
Expand Down Expand Up @@ -101,35 +102,36 @@ public class FbaseConfigGeneratorGradlePlugin : Plugin<Project> {
addGoogleAppIdResource(
variant,
variantExtension.configurations,
variantExtension.primaryConfiguration,
variantExtension.addGoogleAppIdResource,
)
}
}

private fun createTaskParams(
options: FbaseBuilderExtension,
builderExtension: FbaseBuilderExtension,
variant: Variant,
): GenerateOptionsTaskParams {
val defaultPropertyName = options.name
val defaultPropertyName = builderExtension.name
val defaults = VariantDefaults(objects, providers, variant)
val sourceTransformer = FbaseGeneratorSourceTransformer(project, variant)
return objects.newInstance(GenerateOptionsTaskParams::class.java).apply {
source.set(
options.source
builderExtension.source
.orElse(defaults.defaultSource)
.flatMap(sourceTransformer),
)
targetPackage.set(
options.targetPackage.orElse(defaults.targetPackage),
builderExtension.targetPackage.orElse(defaults.targetPackage),
)
targetFileName.set(
options.targetFileName.orElse(defaults.targetFileName(defaultPropertyName)),
builderExtension.targetFileName.orElse(defaults.targetFileName(defaultPropertyName)),
)
propertyName.set(
options.propertyName.orElse(defaultPropertyName),
builderExtension.propertyName.orElse(defaultPropertyName),
)
visibility.set(
options.visibility.orElse(VariantDefaults.DEFAULT_VISIBILITY),
builderExtension.visibility.orElse(VariantDefaults.DEFAULT_VISIBILITY),
)
}
}
Expand All @@ -140,6 +142,7 @@ public class FbaseConfigGeneratorGradlePlugin : Plugin<Project> {
private fun addGoogleAppIdResource(
variant: Variant,
configurations: NamedDomainObjectContainer<FbaseBuilderExtension>,
primaryConfiguration: Provider<String>,
addGoogleAppIdResource: Provider<Boolean>,
) {
val googleAppIdKey = variant.makeResValueKey("string", "google_app_id")
Expand All @@ -148,10 +151,23 @@ public class FbaseConfigGeneratorGradlePlugin : Plugin<Project> {
if (addGoogleAppIdResource.getOrElse(true) == false) {
return@provider emptyMap<ResValue.Key, ResValue>()
}
val configuration = configurations.firstOrNull()
if (configuration == null) {
if (configurations.size == 0) {
return@provider emptyMap<ResValue.Key, ResValue>()
}

val configuration = if (configurations.size == 1) {
configurations.first()
} else {
@Suppress("MaxLineLength")
val primaryConfigurationName: String =
primaryConfiguration.orNull ?: throw InvalidUserDataException(
"FbaseGeneratorExtension.primaryConfiguration must be set when using multiple configurations",
)
configurations.findByName(primaryConfigurationName) ?: throw InvalidUserDataException(
"Configuration named `$primaryConfigurationName` is not defined",
)
}

val applicationId = configuration.source.flatMap(sourceTransformer).orNull?.applicationId
return@provider if (applicationId != null) {
mapOf(googleAppIdKey to ResValue(applicationId))
Expand Down Expand Up @@ -203,31 +219,27 @@ public class FbaseConfigGeneratorGradlePlugin : Plugin<Project> {
private val globalExtension: FbaseGeneratorExtension,
) : (VariantExtensionConfig<out Variant>) -> VariantExtension {
override fun invoke(
variantExtensionConfig: VariantExtensionConfig<out Variant>,
variantExtensions: VariantExtensionConfig<out Variant>,
): FbaseGeneratorExtension {
val mergedConfigs: SortedMap<String, FbaseBuilderExtension> = TreeMap()
var mergedAddGoogleAppId: Provider<Boolean> = globalExtension.addGoogleAppIdResource
val configs: SortedMap<String, FbaseBuilderExtension> = TreeMap()
var addGoogleAppId: Provider<Boolean> = globalExtension.addGoogleAppIdResource
var primaryConfiguration: Provider<String> = globalExtension.primaryConfiguration

globalExtension.configurations.forEach { item -> mergedConfigs[item.name] = item }
globalExtension.configurations.forEach { item -> configs[item.name] = item }

val buildTypeExtension = variantExtensionConfig.buildTypeExtension(
FbaseGeneratorExtension::class.java,
)
mergedConfigs.addConfigurations(buildTypeExtension.configurations)
mergedAddGoogleAppId = buildTypeExtension.addGoogleAppIdResource
.orElse(mergedAddGoogleAppId)
val extensions = listOf(variantExtensions.buildTypeExtension(FbaseGeneratorExtension::class.java)) +
variantExtensions.productFlavorsExtensions(FbaseGeneratorExtension::class.java).reversed()

val flavorExtensions = variantExtensionConfig.productFlavorsExtensions(
FbaseGeneratorExtension::class.java,
).reversed()
flavorExtensions.forEach { extension ->
mergedConfigs.addConfigurations(extension.configurations)
mergedAddGoogleAppId = extension.addGoogleAppIdResource.orElse(mergedAddGoogleAppId)
extensions.forEach { extension ->
addGoogleAppId = extension.addGoogleAppIdResource.orElse(addGoogleAppId)
primaryConfiguration = extension.primaryConfiguration.orElse(primaryConfiguration)
configs.addConfigurations(extension.configurations)
}

val mergedExtension = objects.newInstance(FbaseGeneratorExtension::class.java).apply {
addGoogleAppIdResource.set(mergedAddGoogleAppId)
configurations.addAll(mergedConfigs.values)
this.addGoogleAppIdResource.set(addGoogleAppId)
this.primaryConfiguration.set(primaryConfiguration)
this.configurations.addAll(configs.values)
}

return mergedExtension
Expand All @@ -236,12 +248,12 @@ public class FbaseConfigGeneratorGradlePlugin : Plugin<Project> {
private fun MutableMap<String, FbaseBuilderExtension>.addConfigurations(
configs: NamedDomainObjectContainer<FbaseBuilderExtension>,
) {
configs.forEach { item ->
val lowPrio = this[item.name]
this[item.name] = if (lowPrio != null) {
mergeExtensions(item, lowPrio)
configs.forEach { highPrioConfig ->
val lowPrioConfig = this[highPrioConfig.name]
this[highPrioConfig.name] = if (lowPrioConfig != null) {
mergeExtensions(highPrioConfig, lowPrioConfig)
} else {
item
highPrioConfig
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,17 @@ public abstract class FbaseGeneratorExtension @Inject internal constructor() : S
/**
* Should the google_app_id string parameter be added to Android resources.
* Enabled by default.
* Android string resource "google_app_id" will be initialized with the value from the first configuration defined.
* Android string resource "google_app_id" will be initialized with the value from the configuration specified
* by [primaryConfiguration].
*/
public abstract val addGoogleAppIdResource: Property<Boolean>

/**
* Name of the configuration from the [configurations] that will be used to fill "google_app_id" string resource.
*
* Required when using 2 or more configurations.
*/
public abstract val primaryConfiguration: Property<String>
public abstract val configurations: NamedDomainObjectContainer<FbaseBuilderExtension>

public companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,15 @@ class ExtensionMergerTest {
val result = ExtensionMerger(objects, globalExtension).invoke(variantExtensionConfig)

assertThat(result.addGoogleAppIdResource).isNotPresent()
assertThat(result.primaryConfiguration).isNotPresent()
assertThat(result.configurations.asMap).isEmpty()
}

@Test
fun `should use globalExtension when variant extensions are empty`() {
globalExtension.apply {
addGoogleAppIdResource.set(true)
primaryConfiguration.set("global")
createConfiguration(
name = "global",
propertiesFileName = "testfile",
Expand All @@ -77,7 +79,8 @@ class ExtensionMergerTest {
val result = ExtensionMerger(objects, globalExtension).invoke(variantExtensionConfig)

assertThat(result.addGoogleAppIdResource).value().isTrue()
assertThat(result.configurations.asMap.keys).containsOnly("global")
assertThat(result.primaryConfiguration).value().isEqualTo("global")
assertThat(result.configurations.names).containsOnly("global")
assertThat(result.configurations.getByName("global")).all {
transform { it.source.get() }.isInstanceOf<PropertiesFileGeneratorSource>().all {
hasFileName("testfile")
Expand All @@ -96,6 +99,7 @@ class ExtensionMergerTest {
fun `should merge globalExtension and build type extension`() {
globalExtension.apply {
addGoogleAppIdResource.set(true)
primaryConfiguration.set("global")
createConfiguration(
name = "global",
propertiesFileName = "testfile",
Expand All @@ -110,6 +114,7 @@ class ExtensionMergerTest {
}
val buildTypeExtension = createExtension().apply {
addGoogleAppIdResource.set(false)
primaryConfiguration.set("local")
createConfiguration(
name = "local",
propertiesFileName = "local_test_file_build_type",
Expand All @@ -132,6 +137,7 @@ class ExtensionMergerTest {
val result = ExtensionMerger(objects, globalExtension).invoke(variantExtensionConfig)

assertThat(result.addGoogleAppIdResource).value().isFalse()
assertThat(result.primaryConfiguration).value().isEqualTo("local")
assertThat(result.configurations.names).containsOnly("local", "global", "shared")
assertThat(result.configurations.getByName("global")).all {
transform { it.source.get() }.isInstanceOf<PropertiesFileGeneratorSource>().all {
Expand Down Expand Up @@ -173,6 +179,7 @@ class ExtensionMergerTest {
fun `should merge flavor extensions`() {
val buildTypeExtension = createExtension().apply {
addGoogleAppIdResource.set(false)
primaryConfiguration.set("shared")
createConfiguration(
name = "localBuildType",
propertiesFileName = "testfileBuildType",
Expand All @@ -187,6 +194,7 @@ class ExtensionMergerTest {
}
val demoModeFlavorExtension = createExtension().apply {
addGoogleAppIdResource.set(true)
primaryConfiguration.set("demoModeFlavor")
createConfiguration(
name = "demoModeFlavor",
propertiesFileName = "demo.properties",
Expand Down Expand Up @@ -223,6 +231,7 @@ class ExtensionMergerTest {
val result = ExtensionMerger(objects, globalExtension).invoke(variantExtensionConfig)

assertThat(result.addGoogleAppIdResource).value().isFalse()
assertThat(result.primaryConfiguration).value().isEqualTo("demoModeFlavor")
assertThat(result.configurations.asMap.keys).containsOnly(
"localBuildType",
"demoModeFlavor",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ android {
create("benchmark") {
applicationIdSuffix = ".benchmark"
extensions.configure<FbaseGeneratorExtension> {
primaryConfiguration = "benchmarkFirebaseOptions"
configurations.create("benchmarkFirebaseOptions") {
fromPropertiesFile {
location = layout.projectDirectory.file("firebase_benchmark.properties")
Expand All @@ -41,6 +42,7 @@ android {
dimension = "mode"
applicationIdSuffix = ".demo"
extensions.configure<FbaseGeneratorExtension> {
primaryConfiguration = "demoFirebaseOptions"
configurations.create("demoFirebaseOptions") {
fromPropertiesFile {
location = layout.projectDirectory.file("firebase_demo.properties")
Expand All @@ -53,6 +55,7 @@ android {
dimension = "mode"
applicationIdSuffix = ".full"
extensions.configure<FbaseGeneratorExtension> {
primaryConfiguration = "fullFirebaseOptions"
configurations.create("fullFirebaseOptions") {
fromPropertiesFile {
location = layout.projectDirectory.file("firebase_full.properties")
Expand All @@ -67,6 +70,7 @@ android {
versionCode = 30000 + (android.defaultConfig.versionCode ?: 0)
versionNameSuffix = "-minApi24"
extensions.configure<FbaseGeneratorExtension> {
primaryConfiguration = "minApi24FirebaseOptions"
configurations.create("minApi24FirebaseOptions") {
fromPropertiesFile {
location = layout.projectDirectory.file("firebase_minapi24.properties")
Expand All @@ -81,6 +85,7 @@ android {
versionCode = 10000 + (android.defaultConfig.versionCode ?: 0)
versionNameSuffix = "-minApi21"
extensions.configure<FbaseGeneratorExtension> {
primaryConfiguration = "minApi21FirebaseOptions"
configurations.create("minApi21FirebaseOptions") {
fromPropertiesFile {
location = layout.projectDirectory.file("firebase_minapi21.properties")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ dependencies {
}

firebaseConfig {
primaryConfiguration = "firebaseOptions"
configurations {
create("firebaseOptions") {
fromPropertiesFile {
Expand Down
Loading