Add build plugin to check android badging for changes
This commit is contained in:
parent
5ebf7e50af
commit
e119f1d66d
5 changed files with 156 additions and 3 deletions
|
@ -1,6 +1,7 @@
|
|||
plugins {
|
||||
id(ThunderbirdPlugins.App.android)
|
||||
alias(libs.plugins.dependency.guard)
|
||||
id("thunderbird.quality.badging")
|
||||
}
|
||||
|
||||
val testCoverageEnabled: Boolean by extra
|
||||
|
|
|
@ -13,7 +13,8 @@ Gradle Plugins.
|
|||
The `build-plugin` is used as included build in the root `settings.gradle.kts` and provides all
|
||||
included `xyz.gradle.kts` as plugins under their `xyz` name to the whole project.
|
||||
|
||||
The plugins should try to accomplish single responsibility and leave one-off configuration to the module's `build.gradle.kts`.
|
||||
The plugins should try to accomplish single responsibility and leave one-off configuration to the
|
||||
module's `build.gradle.kts`.
|
||||
|
||||
## Convention plugins
|
||||
|
||||
|
@ -35,6 +36,10 @@ The plugins should try to accomplish single responsibility and leave one-off con
|
|||
- `thunderbird.quality.spotless` - [Spotless - Code formatter](https://github.com/diffplug/spotless)
|
||||
with [Ktlint - Kotlin linter and formatter](https://pinterest.github.io/ktlint/)
|
||||
- Use `./gradlew spotlessCheck` to check for any issue and `./gradlew spotlessApply` to format your code
|
||||
- `thunderbird.quality.badging` - [Android Badging Check Plugin](https://github.com/android/nowinandroid/blob/main/build-logic/convention/src/main/kotlin/com/google/samples/apps/nowinandroid/Badging.kt)
|
||||
- Use `./gradlew generate{VariantName}Badging` to generate badging file
|
||||
- Use `./gradlew check{VariantName}Badging` to validate allowed badging
|
||||
- Use `./gradlew update{VariantName}Badging` to update allowed badging
|
||||
|
||||
## Add new build plugin
|
||||
|
||||
|
@ -44,8 +49,8 @@ If you need to access dependencies that are not yet defined in `build-plugin/bui
|
|||
|
||||
1. Add the dependency to the version catalog `gradle/libs.versions.toml`
|
||||
2. Then add it to `build-plugin/build.gradle.kts`.
|
||||
1. In case of a plugin dependency use `implementation(plugin(libs.plugins.YOUR_PLUGIN_DEPENDENCY))`.
|
||||
1. Otherwise `implementation(libs.YOUR_DEPENDENCY))`.
|
||||
1. In case of a plugin dependency use `implementation(plugin(libs.plugins.YOUR_PLUGIN_DEPENDENCY))`.
|
||||
2. Otherwise `implementation(libs.YOUR_DEPENDENCY))`.
|
||||
|
||||
When done, add the plugin to `build-plugin/src/main/kotlin/ThunderbirdPlugins.kt`
|
||||
|
||||
|
|
|
@ -15,6 +15,9 @@ dependencies {
|
|||
implementation(plugin(libs.plugins.spotless))
|
||||
implementation(plugin(libs.plugins.detekt))
|
||||
implementation(plugin(libs.plugins.dependency.check))
|
||||
|
||||
compileOnly(libs.android.tools.common)
|
||||
compileOnly(libs.assertk)
|
||||
}
|
||||
|
||||
fun plugin(provider: Provider<PluginDependency>) = with(provider.get()) {
|
||||
|
|
|
@ -0,0 +1,141 @@
|
|||
import assertk.assertThat
|
||||
import assertk.assertions.isEqualTo
|
||||
import com.android.SdkConstants
|
||||
import com.android.build.api.artifact.SingleArtifact
|
||||
import org.gradle.configurationcache.extensions.capitalized
|
||||
|
||||
/**
|
||||
* This is a Gradle plugin that adds a task to generate the badging of the APKs and a task to check that the
|
||||
* generated badging is the same as the golden badging.
|
||||
*
|
||||
* This is taken from [nowinandroid](https://github.com/android/nowinandroid) and follows recommendations from
|
||||
* [Prevent regressions with CI and badging](https://android-developers.googleblog.com/2023/12/increase-your-apps-availability-across-device-types.html).
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
}
|
||||
|
||||
androidComponents {
|
||||
onVariants { variant ->
|
||||
val capitalizedVariantName = variant.name.capitalized()
|
||||
val generateBadgingTaskName = "generate${capitalizedVariantName}Badging"
|
||||
val generateBadging = tasks.register<GenerateBadgingTask>(generateBadgingTaskName) {
|
||||
apk.set(variant.artifacts.get(SingleArtifact.APK_FROM_BUNDLE))
|
||||
aapt2Executable.set(
|
||||
File(
|
||||
android.sdkDirectory,
|
||||
"${SdkConstants.FD_BUILD_TOOLS}/" +
|
||||
"${android.buildToolsVersion}/" +
|
||||
SdkConstants.FN_AAPT2,
|
||||
),
|
||||
)
|
||||
badging.set(
|
||||
project.layout.buildDirectory.file(
|
||||
"outputs/apk_from_bundle/${variant.name}/${variant.name}-badging.txt",
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
val updateBadgingTaskName = "update${capitalizedVariantName}Badging"
|
||||
tasks.register<Copy>(updateBadgingTaskName) {
|
||||
from(generateBadging.get().badging)
|
||||
into(project.layout.projectDirectory.dir("badging"))
|
||||
}
|
||||
|
||||
val checkBadgingTaskName = "check${capitalizedVariantName}Badging"
|
||||
val goldenBadgingPath = project.layout.projectDirectory.file("badging/${variant.name}-badging.txt")
|
||||
tasks.register<CheckBadgingTask>(checkBadgingTaskName) {
|
||||
if (goldenBadgingPath.asFile.exists()) {
|
||||
goldenBadging.set(goldenBadgingPath)
|
||||
}
|
||||
generatedBadging.set(
|
||||
generateBadging.get().badging,
|
||||
)
|
||||
this.updateBadgingTaskName.set(updateBadgingTaskName)
|
||||
|
||||
output.set(
|
||||
project.layout.buildDirectory.dir("intermediates/$checkBadgingTaskName"),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CacheableTask
|
||||
abstract class GenerateBadgingTask : DefaultTask() {
|
||||
|
||||
@get:OutputFile
|
||||
abstract val badging: RegularFileProperty
|
||||
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
@get:InputFile
|
||||
abstract val apk: RegularFileProperty
|
||||
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
@get:InputFile
|
||||
abstract val aapt2Executable: RegularFileProperty
|
||||
|
||||
@get:Inject
|
||||
abstract val execOperations: ExecOperations
|
||||
|
||||
@TaskAction
|
||||
fun taskAction() {
|
||||
execOperations.exec {
|
||||
commandLine(
|
||||
aapt2Executable.get().asFile.absolutePath,
|
||||
"dump",
|
||||
"badging",
|
||||
apk.get().asFile.absolutePath,
|
||||
)
|
||||
standardOutput = badging.asFile.get().outputStream()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@CacheableTask
|
||||
abstract class CheckBadgingTask : DefaultTask() {
|
||||
|
||||
// In order for the task to be up-to-date when the inputs have not changed,
|
||||
// the task must declare an output, even if it's not used. Tasks with no
|
||||
// output are always run regardless of whether the inputs changed
|
||||
@get:OutputDirectory
|
||||
abstract val output: DirectoryProperty
|
||||
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
@get:Optional
|
||||
@get:InputFile
|
||||
abstract val goldenBadging: RegularFileProperty
|
||||
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
@get:InputFile
|
||||
abstract val generatedBadging: RegularFileProperty
|
||||
|
||||
@get:Input
|
||||
abstract val updateBadgingTaskName: Property<String>
|
||||
|
||||
override fun getGroup(): String = LifecycleBasePlugin.VERIFICATION_GROUP
|
||||
|
||||
@TaskAction
|
||||
fun taskAction() {
|
||||
if (goldenBadging.isPresent.not()) {
|
||||
logger.error(
|
||||
"Golden badging file does not exist! " +
|
||||
"If this is the first time running this task, " +
|
||||
"run ./gradlew ${updateBadgingTaskName.get()}",
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
val goldenBadgingContent = goldenBadging.get().asFile.readText()
|
||||
val generatedBadgingContent = generatedBadging.get().asFile.readText()
|
||||
if (goldenBadgingContent == generatedBadgingContent) {
|
||||
logger.info("Generated badging is the same as golden badging!")
|
||||
return
|
||||
}
|
||||
|
||||
assertThat(generatedBadgingContent).isEqualTo(goldenBadgingContent)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3,7 +3,9 @@
|
|||
|
||||
[versions]
|
||||
gradle = "8.5"
|
||||
# AGP and tools should be updated together
|
||||
androidGradlePlugin = "8.2.1"
|
||||
androidTools = "31.2.1"
|
||||
ktlint = "1.0.1"
|
||||
|
||||
kotlin = "1.9.22"
|
||||
|
@ -58,6 +60,7 @@ dependency-guard = { id = "com.dropbox.dependency-guard", version.ref = "pluginD
|
|||
|
||||
[libraries]
|
||||
desugar = "com.android.tools:desugar_jdk_libs:2.0.4"
|
||||
android-tools-common = { group = "com.android.tools", name = "common", version.ref = "androidTools" }
|
||||
|
||||
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
|
||||
kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = "kotlin" }
|
||||
|
|
Loading…
Reference in a new issue