Skip to content

Instantly share code, notes, and snippets.

@realdadfish
Last active July 18, 2020 21:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save realdadfish/52e6d79ffaf913ab6a87b1a321727a47 to your computer and use it in GitHub Desktop.
Save realdadfish/52e6d79ffaf913ab6a87b1a321727a47 to your computer and use it in GitHub Desktop.
PMD CPD Kotlin Plugin
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.api.BaseVariant
import com.android.build.gradle.internal.tasks.factory.dependsOn
import de.aaschmid.gradle.plugins.cpd.Cpd
import de.aaschmid.gradle.plugins.cpd.CpdExtension
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.internal.HasConvention
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.apply
import org.gradle.kotlin.dsl.closureOf
import org.gradle.kotlin.dsl.configure
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
class CpdPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.configure(project, closureOf<Project> {
apply(plugin = "cpd")
configure<CpdExtension> {
language = "kotlin"
toolVersion = "6.25.0"
minimumTokenCount = 50
}
registerTasks()
})
}
private fun Project.registerTasks() {
project.plugins.withId("kotlin-android") {
// There is not a single Android plugin, but each registers an extension based on BaseExtension,
// so we catch them all by looking for this one
project.afterEvaluate {
val androidExtension = project.extensions.findByType(BaseExtension::class.java)
androidExtension?.let {
val mainTaskProvider = project.tasks.register("${CPD_CHECK_TASK}Main") {
group = "verification"
description = "Run CPD check for all production sources"
}
val testTaskProvider = project.tasks.register("${CPD_CHECK_TASK}Test") {
group = "verification"
description = "Run CPD check for all test sources"
}
androidExtension.variants?.forEach { variant ->
// register individual tasks and add those to the common tasks above
// to run all checks on all variants at once
project.registerAndroidCpdTask(variant).also { provider ->
mainTaskProvider.dependsOn(provider)
}
variant.testVariants.forEach { testVariant ->
project.registerAndroidCpdTask(testVariant).also { provider ->
testTaskProvider.dependsOn(provider)
}
}
}
project.dependOnQuickCheck()
}
}
}
// Kotlin JVM plugin
project.plugins.withId("org.jetbrains.kotlin.jvm") {
project.afterEvaluate {
project.convention.getPlugin(JavaPluginConvention::class.java).sourceSets.forEach { sourceSet ->
project.registerJvmCpdTask(sourceSet)
}
}
}
}
private fun Project.registerAndroidCpdTask(variant: BaseVariant): TaskProvider<Cpd> =
registerCpdTask(CPD_CHECK_TASK + variant.name.capitalize()) {
setSource(variant.sourceSets.map { it.javaDirectories })
group = "verification"
description = "Run CPD check for variant ${variant.name}"
}
private fun Project.registerJvmCpdTask(sourceSet: SourceSet): TaskProvider<Cpd> {
val kotlinSourceSet = (sourceSet as HasConvention).convention.plugins["kotlin"] as? KotlinSourceSet
?: throw GradleException("Kotlin source set not found.")
return registerCpdTask(CPD_CHECK_TASK + sourceSet.name.capitalize()) {
setSource(kotlinSourceSet.kotlin.files)
group = "verification"
description = "Run CPD check for source set ${sourceSet.name}"
}
}
private fun Project.registerCpdTask(
name: String,
configuration: Cpd.() -> Unit
): TaskProvider<Cpd> =
tasks.register(name, Cpd::class.java) {
reports.text.isEnabled = true
reports.xml.isEnabled = true
configuration(this)
}
companion object {
private const val CPD_CHECK_TASK = "cpdCheck"
}
}
internal val BaseExtension.variants: DomainObjectSet<out BaseVariant>?
get() = when (this) {
is AppExtension -> applicationVariants
is LibraryExtension -> libraryVariants
is TestExtension -> applicationVariants
else -> null
}
internal val BaseVariant.testVariants: List<BaseVariant>
get() = if (this is TestedVariant) listOfNotNull(testVariant, unitTestVariant)
else emptyList()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment