Skip to content

Add variant exclusion per-project in DSL #1461

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

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) 2025. Tony Robalik.
// SPDX-License-Identifier: Apache-2.0
package com.autonomousapps.android

import com.autonomousapps.android.projects.AbiExcludedVariantProject

import static com.autonomousapps.utils.Runner.build
import static com.google.common.truth.Truth.assertThat

final class AbiExclusionsSpec extends AbstractAndroidSpec {

def "can exclude variant from ABI analysis (#gradleVersion AGP #agpVersion)"() {
given:
def project = new AbiExcludedVariantProject(agpVersion)
gradleProject = project.gradleProject

when:
build(gradleVersion, gradleProject.rootDir, 'buildHealth')

then:
assertThat(project.actualBuildHealth()).containsExactlyElementsIn(project.expectedBuildHealth)

where:
[gradleVersion, agpVersion] << gradleAgpMatrix()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright (c) 2025. Tony Robalik.
// SPDX-License-Identifier: Apache-2.0
package com.autonomousapps.android.projects

import com.autonomousapps.kit.GradleProject
import com.autonomousapps.kit.Source
import com.autonomousapps.kit.SourceType
import com.autonomousapps.model.Advice
import com.autonomousapps.model.AndroidScore
import com.autonomousapps.model.ModuleAdvice
import com.autonomousapps.model.PluginAdvice
import com.autonomousapps.model.ProjectAdvice

import static com.autonomousapps.AdviceHelper.*
import static com.autonomousapps.kit.gradle.dependencies.Dependencies.commonsCollections

final class AbiExcludedVariantProject extends AbstractAndroidProject {

final GradleProject gradleProject

AbiExcludedVariantProject(String agpVersion) {
super(agpVersion)
this.gradleProject = build()
}

private GradleProject build() {
return newAndroidGradleProjectBuilder(agpVersion)
.withRootProject { root ->
root.withBuildScript { bs ->
bs.withGroovy("""\
dependencyAnalysis {
abi {
exclusions {
excludeVariants('release')
}
}
}"""
)
}
}
.withAndroidSubproject('lib') { l ->
l.sources = libSources
l.manifest = libraryManifest()
l.withBuildScript { bs ->
bs.plugins = androidLibWithKotlin
bs.android = defaultAndroidLibBlock()
bs.dependencies = [
// This dependency would normally cause an unused dependency warning
// but we're excluding the release variant from analysis
commonsCollections("releaseImplementation")
]
}
}
.write()
}

private List<Source> libSources = [
// Only has code in debug source set - no code in main source set
new Source(
SourceType.KOTLIN, "DebugLibrary", "com/example/lib",
"""\
package com.example.lib

class DebugLibrary
""".stripIndent(),
"debug"
)
]

Set<ProjectAdvice> actualBuildHealth() {
return actualProjectAdvice(gradleProject)
}

private final AndroidScore androidScore = androidScoreBuilder().with {
hasAndroidAssets = false
hasAndroidRes = false
usesAndroidClasses = false
hasBuildConfig = false
hasAndroidDependencies = false
hasBuildTypeSourceSplits = true
build()
}

final Set<ProjectAdvice> expectedBuildHealth = [
projectAdvice(
':lib',
[] as Set<Advice>,
[] as Set<PluginAdvice>,
[androidScore] as Set<ModuleAdvice>,
false
),
]
}
10 changes: 10 additions & 0 deletions src/main/kotlin/com/autonomousapps/extension/AbiHandler.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import javax.inject.Inject
* abi {
* exclusions {
* excludeSourceSets(/* source sets to exclude from ABI analysis */)
* excludeVariants(/* variants to exclude from ABI analysis */)
*
* ignoreSubPackage("internal")
* ignoreInternalPackages()
Expand Down Expand Up @@ -46,6 +47,7 @@ abstract class ExclusionsHandler @Inject constructor(objects: ObjectFactory) {
internal val annotationExclusions = objects.setProperty<String>().convention(emptySet())
internal val pathExclusions = objects.setProperty<String>().convention(emptySet())
internal val excludedSourceSets = objects.setProperty<String>().convention(emptySet())
internal val excludedVariants = objects.setProperty<String>().convention(emptySet())

/**
* Exclude the given [sourceSets] from ABI analysis, which means that regardless of the level of exposure of any given
Expand All @@ -55,6 +57,14 @@ abstract class ExclusionsHandler @Inject constructor(objects: ObjectFactory) {
excludedSourceSets.addAll(*sourceSets)
}

/**
* Exclude the given [variants] from ABI analysis. This is useful for Android projects that have only debug sources
* and analyzing the release configuration is not useful.
*/
fun excludeVariants(vararg variants: String) {
excludedVariants.addAll(*variants)
}

/**
* Exclude "internal" packages from ABI analysis, which means that any class in a package that contains ".internal."
* will not be considered as part of the module's ABI.
Expand Down
9 changes: 6 additions & 3 deletions src/main/kotlin/com/autonomousapps/subplugin/ProjectPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,8 @@ internal class ProjectPlugin(private val project: Project) {
/** Has the `com.android.application` plugin applied. */
private fun Project.configureAndroidAppProject() {
val project = this
val ignoredVariantNames = androidIgnoredVariants()
val ignoredVariantNames = androidIgnoredVariants() +
dagpExtension.abiHandler.exclusionsHandler.excludedVariants.get()

val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
// val newAgpVersion = androidComponents.pluginVersion.toString().removePrefix("Android Gradle Plugin version ")
Expand Down Expand Up @@ -312,7 +313,8 @@ internal class ProjectPlugin(private val project: Project) {
/** Has the `com.android.library` plugin applied. */
private fun Project.configureAndroidLibProject() {
val project = this
val ignoredVariantNames = androidIgnoredVariants()
val ignoredVariantNames = androidIgnoredVariants() +
dagpExtension.abiHandler.exclusionsHandler.excludedVariants.get()

val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
// val newAgpVersion = androidComponents.pluginVersion.toString().removePrefix("Android Gradle Plugin version ")
Expand Down Expand Up @@ -391,7 +393,8 @@ internal class ProjectPlugin(private val project: Project) {
/** Has the `com.android.test` plugin applied. */
private fun Project.configureAndroidTestProject() {
val project = this
val ignoredVariantNames = androidIgnoredVariants()
val ignoredVariantNames = androidIgnoredVariants() +
dagpExtension.abiHandler.exclusionsHandler.excludedVariants.get()

val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
// val newAgpVersion = androidComponents.pluginVersion.toString().removePrefix("Android Gradle Plugin version ")
Expand Down
Loading