Skip to content
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Change Log

## Unreleased

- Support Splits/Multi-APKs and universal APK modes.

## 1.3.2

### Changed
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ dependencies {
compileOnly(libs.agp.common)
testImplementation(libs.junit)
testImplementation(libs.truth)
testImplementation(libs.testParameterInjector)
fixtureClasspath(libs.agp.build.flatMap { dependency ->
fixtureAgpVersion.map { version ->
"${dependency.group}:${dependency.name}:$version"
Expand Down
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ detekt = "1.23.7"
mavenPublish = "0.29.0"
junit = "4.13.2"
truth = "1.1.3"
testParameterInjector = "1.18"
toolchainsResolver = "0.9.0"

[libraries]
Expand All @@ -16,6 +17,7 @@ agp-build = { module = "com.android.tools.build:gradle", version.ref = "agp" }
agp-common = { module = "com.android.tools:common", version.ref = "agp-common" }
junit = { module = "junit:junit", version.ref = "junit" }
truth = { module = "com.google.truth:truth", version.ref = "truth" }
testParameterInjector = { group = "com.google.testparameterinjector", name = "test-parameter-injector", version.ref = "testParameterInjector" }

[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
package io.github.reactivecircus.appversioning

import com.google.common.truth.Truth.assertThat
import com.google.testing.junit.testparameterinjector.TestParameter
import com.google.testing.junit.testparameterinjector.TestParameterInjector
import io.github.reactivecircus.appversioning.fixtures.AppProjectTemplate
import io.github.reactivecircus.appversioning.fixtures.LibraryProjectTemplate
import io.github.reactivecircus.appversioning.fixtures.withFixtureRunner
Expand All @@ -13,8 +15,10 @@ import org.gradle.testkit.runner.TaskOutcome
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import org.junit.runner.RunWith
import java.io.File

@RunWith(TestParameterInjector::class)
class AppVersioningPluginIntegrationTest {

@get:Rule
Expand Down Expand Up @@ -65,13 +69,15 @@ class AppVersioningPluginIntegrationTest {
}

@Test
fun `plugin tasks are registered for Android App project with product flavors`() {
fun `plugin tasks are registered for Android App project with product flavors`(
@TestParameter useKts: Boolean
) {
GitClient.initialize(fixtureDir.root)

val flavors = listOf("mock", "prod")
withFixtureRunner(
fixtureDir = fixtureDir,
subprojects = listOf(AppProjectTemplate(flavors = flavors))
subprojects = listOf(AppProjectTemplate(useKts = useKts, flavors = flavors))
).runAndCheckResult(
"tasks",
"--group=versioning"
Expand Down Expand Up @@ -199,15 +205,87 @@ class AppVersioningPluginIntegrationTest {
}

@Test
fun `plugin generates versionCode and versionName for the assembled APK when assemble task is run`() {
fun `plugin generates versionCode and versionName for the assembled APK when assemble task is run`(
@TestParameter useKts: Boolean
) {
GitClient.initialize(fixtureDir.root).apply {
val commitId = commit(message = "1st commit.")
tag(name = "1.2.3", message = "1st tag", commitId = commitId)
}

withFixtureRunner(
fixtureDir = fixtureDir,
subprojects = listOf(AppProjectTemplate())
subprojects = listOf(AppProjectTemplate(useKts = useKts))
).runAndCheckResult(
"assembleRelease"
) {
val versionCodeFileContent = File(
fixtureDir.root,
"app/build/outputs/app_versioning/release/version_code.txt"
).readText()
val versionNameFileContent = File(
fixtureDir.root,
"app/build/outputs/app_versioning/release/version_name.txt"
).readText()

assertThat(task(":app:generateAppVersionInfoForRelease")?.outcome).isEqualTo(TaskOutcome.SUCCESS)
assertThat(task(":app:assembleRelease")?.outcome).isEqualTo(TaskOutcome.SUCCESS)

assertThat(output).contains("Generated app version code: 10203.")
assertThat(output).contains("Generated app version name: \"1.2.3\".")

assertThat(versionCodeFileContent).isEqualTo("10203")
assertThat(versionNameFileContent).isEqualTo("1.2.3")
}
}

@Test
fun `plugin generates versionCode and versionName for the assembled APKs when splits-APKs is enabled`(
@TestParameter useKts: Boolean
) {
GitClient.initialize(fixtureDir.root).apply {
val commitId = commit(message = "1st commit.")
tag(name = "1.2.3", message = "1st tag", commitId = commitId)
}

withFixtureRunner(
fixtureDir = fixtureDir,
subprojects = listOf(AppProjectTemplate(useKts = useKts, splitsApks = true))
).runAndCheckResult(
"assembleRelease"
) {
val versionCodeFileContent = File(
fixtureDir.root,
"app/build/outputs/app_versioning/release/version_code.txt"
).readText()
val versionNameFileContent = File(
fixtureDir.root,
"app/build/outputs/app_versioning/release/version_name.txt"
).readText()

assertThat(task(":app:generateAppVersionInfoForRelease")?.outcome).isEqualTo(TaskOutcome.SUCCESS)
assertThat(task(":app:assembleRelease")?.outcome).isEqualTo(TaskOutcome.SUCCESS)

assertThat(output).contains("Generated app version code: 10203.")
assertThat(output).contains("Generated app version name: \"1.2.3\".")

assertThat(versionCodeFileContent).isEqualTo("10203")
assertThat(versionNameFileContent).isEqualTo("1.2.3")
}
}

@Test
fun `plugin generates versionCode and versionName for the assembled APKs when splits-APKs is enabled and universal mode is on`(
@TestParameter useKts: Boolean
) {
GitClient.initialize(fixtureDir.root).apply {
val commitId = commit(message = "1st commit.")
tag(name = "1.2.3", message = "1st tag", commitId = commitId)
}

withFixtureRunner(
fixtureDir = fixtureDir,
subprojects = listOf(AppProjectTemplate(useKts = useKts, splitsApks = true, universalApk = true))
).runAndCheckResult(
"assembleRelease"
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,16 @@ fun gradlePropertiesFileContent(enableConfigurationCache: Boolean): String {
""".trimIndent()
}

abstract class AndroidProjectTemplate {
sealed class AndroidProjectTemplate {
abstract val projectName: String
abstract val pluginExtension: String?
abstract val useKts: Boolean
abstract val flavors: List<String>
abstract val isAppProject: Boolean

val buildFileContent: String get() = if (useKts) ktsBuildFileContent else groovyBuildFileContent

private val isAppProject = this is AppProjectTemplate

private val ktsBuildFileContent: String
get() {
val flavorConfigs = if (flavors.isNotEmpty()) {
Expand All @@ -64,6 +65,24 @@ abstract class AndroidProjectTemplate {
} else {
""
}
val abiConfigs = if (this is AppProjectTemplate) {
if (splitsApks) {
"""
splits {
abi {
isEnable = true
reset()
include("armeabi-v7a", "arm64-v8a", "x86", "x86_64")
isUniversalApk = $universalApk
}
}
""".trimIndent()
} else {
""
}
} else {
""
}
return """
plugins {
id("com.android.${if (isAppProject) "application" else "library"}")
Expand All @@ -84,6 +103,8 @@ abstract class AndroidProjectTemplate {
lintOptions.isCheckReleaseBuilds = false

$flavorConfigs

$abiConfigs
}
""".trimIndent()
}
Expand All @@ -100,6 +121,24 @@ abstract class AndroidProjectTemplate {
} else {
""
}
val abiConfigs = if (this is AppProjectTemplate) {
if (splitsApks) {
"""
splits {
abi {
enable true
reset()
include "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
universalApk $universalApk
}
}
""".trimIndent()
} else {
""
}
} else {
""
}
return """
plugins {
id 'com.android.${if (isAppProject) "application" else "library"}'
Expand All @@ -122,6 +161,8 @@ abstract class AndroidProjectTemplate {
}

$flavorConfigs

$abiConfigs
}
""".trimIndent()
}
Expand All @@ -141,16 +182,14 @@ class AppProjectTemplate(
override val projectName: String = "app",
override val pluginExtension: String? = null,
override val useKts: Boolean = true,
override val flavors: List<String> = emptyList()
) : AndroidProjectTemplate() {
override val isAppProject: Boolean = true
}
override val flavors: List<String> = emptyList(),
val splitsApks: Boolean = false,
val universalApk: Boolean = false,
) : AndroidProjectTemplate()

class LibraryProjectTemplate(
override val projectName: String = "library",
override val pluginExtension: String? = null,
override val useKts: Boolean = true,
override val flavors: List<String> = emptyList()
) : AndroidProjectTemplate() {
override val isAppProject: Boolean = false
}
) : AndroidProjectTemplate()
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package io.github.reactivecircus.appversioning
import com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
import com.android.build.api.variant.ApplicationVariant
import com.android.build.api.variant.VariantOutputConfiguration
import com.android.build.gradle.AppPlugin
import io.github.reactivecircus.appversioning.tasks.GenerateAppVersionInfo
import io.github.reactivecircus.appversioning.tasks.PrintAppVersionInfo
Expand Down Expand Up @@ -60,9 +59,10 @@ class AppVersioningPlugin : Plugin<Project> {

project.registerPrintAppVersionInfoTask(variantName = variant.name)

val mainOutput = variant.outputs.single { it.outputType == VariantOutputConfiguration.OutputType.SINGLE }
mainOutput.versionCode.set(generatedVersionCode)
mainOutput.versionName.set(generatedVersionName)
variant.outputs.forEach { output ->
output.versionCode.set(generatedVersionCode)
output.versionName.set(generatedVersionName)
}
}
}
}
Expand Down