com.autonomousapps.tasks.AdviceTask.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dependency-analysis-gradle-plugin Show documentation
Show all versions of dependency-analysis-gradle-plugin Show documentation
Analyzes dependency usage in Android and JVM projects
@file:Suppress("UnstableApiUsage")
package com.autonomousapps.tasks
import com.autonomousapps.TASK_GROUP_DEP
import com.autonomousapps.advice.ComponentWithTransitives
import com.autonomousapps.extension.Behavior
import com.autonomousapps.extension.DependenciesHandler
import com.autonomousapps.internal.*
import com.autonomousapps.internal.advice.Advisor
import com.autonomousapps.internal.advice.filter.*
import com.autonomousapps.internal.utils.*
import com.autonomousapps.services.InMemoryCache
import org.gradle.api.DefaultTask
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.*
/**
* Produces human- and machine-readable advice on how to modify a project's dependencies in order to have a healthy
* build.
*/
@CacheableTask
abstract class AdviceTask : DefaultTask() {
init {
group = TASK_GROUP_DEP
description = "Provides advice on how best to declare the project's dependencies"
}
/**
* A [`Set`][Component].
*/
@get:PathSensitive(PathSensitivity.NONE)
@get:InputFile
abstract val allComponentsReport: RegularFileProperty
/**
* A [`Set`][ComponentWithTransitives].
*/
@get:PathSensitive(PathSensitivity.NONE)
@get:InputFile
abstract val allComponentsWithTransitives: RegularFileProperty
@get:PathSensitive(PathSensitivity.NONE)
@get:InputFile
abstract val unusedDependenciesReport: RegularFileProperty
@get:PathSensitive(PathSensitivity.NONE)
@get:InputFile
abstract val usedTransitiveDependenciesReport: RegularFileProperty
@get:Optional
@get:PathSensitive(PathSensitivity.NONE)
@get:InputFile
abstract val abiDependenciesReport: RegularFileProperty
@get:PathSensitive(PathSensitivity.NONE)
@get:InputFile
abstract val allDeclaredDependenciesReport: RegularFileProperty
@get:PathSensitive(PathSensitivity.NONE)
@get:InputFile
abstract val unusedProcsReport: RegularFileProperty
@get:PathSensitive(PathSensitivity.NONE)
@get:InputFile
abstract val serviceLoaders: RegularFileProperty
/**
* [`Set`][VariantDependency]
*/
@get:PathSensitive(PathSensitivity.NONE)
@get:InputFile
abstract val usedVariantDependencies: RegularFileProperty
@get:Internal
lateinit var dependenciesHandler: DependenciesHandler
@Input
fun getDependencyBundles(): Map> {
return dependenciesHandler.bundles.asMap.map { (name, groups) ->
name to groups.includes.get()
}.toMap()
}
@get:Input
abstract val ignoreKtx: Property
@get:Input
abstract val dataBindingEnabled: Property
@get:Input
abstract val viewBindingEnabled: Property
/*
* Severity
*/
@get:Input
abstract val anyBehavior: Property
@get:Input
abstract val unusedDependenciesBehavior: Property
@get:Input
abstract val usedTransitiveDependenciesBehavior: Property
@get:Input
abstract val incorrectConfigurationBehavior: Property
@get:Input
abstract val unusedProcsBehavior: Property
@get:Input
abstract val compileOnlyBehavior: Property
/*
* Outputs
*/
@get:OutputFile
abstract val adviceReport: RegularFileProperty
@get:OutputFile
abstract val advicePrettyReport: RegularFileProperty
@get:OutputFile
abstract val adviceConsoleReport: RegularFileProperty
@get:OutputFile
abstract val adviceConsolePrettyReport: RegularFileProperty
@get:Internal
abstract val inMemoryCacheProvider: Property
@TaskAction
fun action() {
// Output
val adviceFile = adviceReport.getAndDelete()
val advicePrettyFile = advicePrettyReport.getAndDelete()
val adviceConsoleFile = adviceConsoleReport.getAndDelete()
val adviceConsolePrettyFile = adviceConsolePrettyReport.getAndDelete()
// Inputs
val usedVariantDependencies = usedVariantDependencies.fromJsonSet()
val allComponents = allComponentsReport.fromJsonSet()
val allComponentsWithTransitives = allComponentsWithTransitives.fromJsonSet()
val unusedDirectComponents = unusedDependenciesReport.fromJsonSet()
val usedTransitiveComponents = usedTransitiveDependenciesReport.fromJsonSet()
val abiDeps = abiDependenciesReport.orNull?.asFile?.readText()?.fromJsonSet()
?.mapToSet { it.dependency }
?: emptySet()
val allDeclaredDeps = allDeclaredDependenciesReport.fromJsonSet()
.mapToSet { it.dependency }
.filterToSet { it.configurationName != null }
val unusedProcs = unusedProcsReport.fromJsonSet()
// Print to the console several lists:
// 1. Dependencies that should be removed.
// 2. Dependencies that are already declared and whose configurations should be modified.
// 3. Dependencies that should be added and the configurations on which to add them.
// 4. Dependencies that are candidates to be compileOnly, but aren't currently.
// 5. Annotation processors that are declared but are not used.
val advisor = Advisor(
usedVariantDependencies = usedVariantDependencies,
allComponents = allComponents,
allComponentsWithTransitives = allComponentsWithTransitives,
unusedComponentsWithTransitives = unusedDirectComponents,
usedTransitiveComponents = usedTransitiveComponents,
abiDeps = abiDeps,
allDeclaredDeps = allDeclaredDeps,
unusedProcs = unusedProcs,
serviceLoaders = serviceLoaders.fromJsonSet(),
dependencyBundles = getDependencyBundles(),
ignoreKtx = ignoreKtx.get()
)
val computedAdvice = advisor.compute(filterSpecBuilder())
val advices = computedAdvice.getAdvices()
val consoleReport = ConsoleReport.from(computedAdvice)
adviceFile.writeText(advices.toJson())
advicePrettyFile.writeText(advices.toPrettyString())
adviceConsoleFile.writeText(consoleReport.toJson())
adviceConsolePrettyFile.writeText(consoleReport.toPrettyString())
if (advices.isNotEmpty()) {
logger.debug("See machine-readable report at ${adviceFile.path}")
logger.debug("See pretty report at ${advicePrettyFile.path}")
logger.debug("See machine-readable console report at ${adviceConsoleFile.path}")
logger.debug("See pretty console report at ${adviceConsolePrettyFile.path}")
}
}
private fun filterSpecBuilder() = FilterSpecBuilder().apply {
universalFilter = CompositeFilter(filters)
anyBehavior = [email protected]()
unusedDependenciesBehavior = [email protected]()
usedTransitivesBehavior = usedTransitiveDependenciesBehavior.get()
incorrectConfigurationsBehavior = incorrectConfigurationBehavior.get()
unusedProcsBehavior = [email protected]()
compileOnlyBehavior = [email protected]()
}
private val filters: List by lazy(mode = LazyThreadSafetyMode.NONE) {
val filters = mutableListOf()
if (dataBindingEnabled.get()) {
filters.add(DataBindingFilter())
}
if (viewBindingEnabled.get()) {
filters.add(ViewBindingFilter())
}
filters
}
}