diff --git a/README.md b/README.md index e482d4b..d0dc75d 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ binaryCompatibilityValidator { } // BCV will automatically register a target for testFixtures, but it must be enabled manually - targets.named("testFixtures") { + targets.testFixtures { enabled.set(true) } diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/JavaTestFixturesTest.kt b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/JavaTestFixturesTest.kt index adb0dba..fb9cdb3 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/JavaTestFixturesTest.kt +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/kotlin/kotlinx/validation/test/JavaTestFixturesTest.kt @@ -130,7 +130,7 @@ private fun FunSpec.createTestFixturesProject( |} | |binaryCompatibilityValidator { - | testFixtures { + | targets.testFixtures { | enabled.set($bcvTestFixturesTargetEnabled) | } |} diff --git a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/configuration/jarAsInput/inputJar.gradle.kts b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/configuration/jarAsInput/inputJar.gradle.kts index b8a1585..d894a22 100644 --- a/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/configuration/jarAsInput/inputJar.gradle.kts +++ b/modules/bcv-gradle-plugin-functional-tests/src/functionalTest/resources/examples/gradle/configuration/jarAsInput/inputJar.gradle.kts @@ -4,7 +4,7 @@ tasks.jar { } binaryCompatibilityValidator { - kotlinJvm { + targets.kotlinJvm { inputJar.set(tasks.jar.flatMap { it.archiveFile }) } } diff --git a/modules/bcv-gradle-plugin/api/bcv-gradle-plugin.api b/modules/bcv-gradle-plugin/api/bcv-gradle-plugin.api index a8d194e..fce1d78 100644 --- a/modules/bcv-gradle-plugin/api/bcv-gradle-plugin.api +++ b/modules/bcv-gradle-plugin/api/bcv-gradle-plugin.api @@ -11,7 +11,7 @@ public abstract class dev/adamko/kotlin/binary_compatibility_validator/BCVPlugin public final class dev/adamko/kotlin/binary_compatibility_validator/BCVPlugin$Companion { } -public abstract interface class dev/adamko/kotlin/binary_compatibility_validator/BCVProjectExtension : dev/adamko/kotlin/binary_compatibility_validator/targets/BCVTargetSpec, org/gradle/api/plugins/ExtensionAware { +public abstract class dev/adamko/kotlin/binary_compatibility_validator/BCVProjectExtension : dev/adamko/kotlin/binary_compatibility_validator/targets/BCVTargetSpec, org/gradle/api/plugins/ExtensionAware { public abstract fun getEnabled ()Lorg/gradle/api/provider/Property; public abstract fun getIgnoredClasses ()Lorg/gradle/api/provider/SetProperty; public abstract fun getIgnoredMarkers ()Lorg/gradle/api/provider/SetProperty; @@ -23,7 +23,7 @@ public abstract interface class dev/adamko/kotlin/binary_compatibility_validator public abstract fun getPublicClasses ()Lorg/gradle/api/provider/SetProperty; public abstract fun getPublicMarkers ()Lorg/gradle/api/provider/SetProperty; public abstract fun getPublicPackages ()Lorg/gradle/api/provider/SetProperty; - public abstract fun getTargets ()Lorg/gradle/api/NamedDomainObjectContainer; + public final fun getTargets ()Lorg/gradle/api/NamedDomainObjectContainer; } public abstract class dev/adamko/kotlin/binary_compatibility_validator/BCVProjectPlugin : org/gradle/api/Plugin { @@ -94,7 +94,7 @@ public abstract class dev/adamko/kotlin/binary_compatibility_validator/tasks/BCV public abstract fun getOutputApiBuildDir ()Lorg/gradle/api/file/DirectoryProperty; public abstract fun getProjectName ()Lorg/gradle/api/provider/Property; public abstract fun getRuntimeClasspath ()Lorg/gradle/api/file/ConfigurableFileCollection; - public abstract fun getTargets ()Lorg/gradle/api/NamedDomainObjectContainer; + public final fun getTargets ()Lorg/gradle/api/NamedDomainObjectContainer; } public abstract class dev/adamko/kotlin/binary_compatibility_validator/tasks/BCVDefaultTask : org/gradle/api/DefaultTask { diff --git a/modules/bcv-gradle-plugin/src/main/kotlin/BCVProjectExtension.kt b/modules/bcv-gradle-plugin/src/main/kotlin/BCVProjectExtension.kt index 264891e..bbbe293 100644 --- a/modules/bcv-gradle-plugin/src/main/kotlin/BCVProjectExtension.kt +++ b/modules/bcv-gradle-plugin/src/main/kotlin/BCVProjectExtension.kt @@ -1,51 +1,62 @@ package dev.adamko.kotlin.binary_compatibility_validator +import dev.adamko.kotlin.binary_compatibility_validator.internal.BCVInternalApi +import dev.adamko.kotlin.binary_compatibility_validator.internal.adding +import dev.adamko.kotlin.binary_compatibility_validator.internal.domainObjectContainer import dev.adamko.kotlin.binary_compatibility_validator.targets.BCVTarget import dev.adamko.kotlin.binary_compatibility_validator.targets.BCVTargetSpec +import javax.inject.Inject import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.file.DirectoryProperty +import org.gradle.api.model.ObjectFactory import org.gradle.api.model.ReplacedBy import org.gradle.api.plugins.ExtensionAware import org.gradle.api.provider.Property import org.gradle.api.provider.SetProperty -interface BCVProjectExtension : BCVTargetSpec, ExtensionAware { +abstract class BCVProjectExtension +@BCVInternalApi +@Inject +constructor( + private val objects: ObjectFactory +) : BCVTargetSpec, ExtensionAware { /** Sets the default [BCVTarget.enabled] value for all [targets]. */ - override val enabled: Property + abstract override val enabled: Property /** Sets the default [BCVTarget.ignoredPackages] value for all [targets]. */ - override val ignoredPackages: SetProperty + abstract override val ignoredPackages: SetProperty /** Sets the default [BCVTarget.publicMarkers] for all [targets] */ - override val publicMarkers: SetProperty + abstract override val publicMarkers: SetProperty /** Sets the default [BCVTarget.publicPackages] for all [targets] */ - override val publicPackages: SetProperty + abstract override val publicPackages: SetProperty /** Sets the default [BCVTarget.publicClasses] for all [targets] */ - override val publicClasses: SetProperty + abstract override val publicClasses: SetProperty /** Sets the default [BCVTarget.ignoredMarkers] value for all [targets]. */ - override val ignoredMarkers: SetProperty + abstract override val ignoredMarkers: SetProperty @get:ReplacedBy("ignoredMarkers") @Deprecated("renamed to ignoredMarkers", ReplaceWith("ignoredMarkers")) - val nonPublicMarkers: SetProperty + abstract val nonPublicMarkers: SetProperty /** Sets the default [BCVTarget.ignoredClasses] value for all [targets]. */ - override val ignoredClasses: SetProperty + abstract override val ignoredClasses: SetProperty /** * The directory that contains the API declarations. * * Defaults to [BCVPlugin.API_DIR]. */ - val outputApiDir: DirectoryProperty + abstract val outputApiDir: DirectoryProperty - val projectName: Property + abstract val projectName: Property - val kotlinxBinaryCompatibilityValidatorVersion: Property + abstract val kotlinxBinaryCompatibilityValidatorVersion: Property - val targets: NamedDomainObjectContainer + val targets: NamedDomainObjectContainer = + extensions.adding("targets") { objects.domainObjectContainer() } } diff --git a/modules/bcv-gradle-plugin/src/main/kotlin/BCVProjectPlugin.kt b/modules/bcv-gradle-plugin/src/main/kotlin/BCVProjectPlugin.kt index a9d1aaf..79cceee 100644 --- a/modules/bcv-gradle-plugin/src/main/kotlin/BCVProjectPlugin.kt +++ b/modules/bcv-gradle-plugin/src/main/kotlin/BCVProjectPlugin.kt @@ -119,10 +119,6 @@ constructor( ignoredPackages.convention(extension.ignoredPackages) } - extension.targets.all { - extension.extensions.add(platformType, this) - } - return extension } diff --git a/modules/bcv-gradle-plugin/src/main/kotlin/internal/gradleUtils.kt b/modules/bcv-gradle-plugin/src/main/kotlin/internal/gradleUtils.kt new file mode 100644 index 0000000..11c1b97 --- /dev/null +++ b/modules/bcv-gradle-plugin/src/main/kotlin/internal/gradleUtils.kt @@ -0,0 +1,48 @@ +package dev.adamko.kotlin.binary_compatibility_validator.internal + +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.NamedDomainObjectFactory +import org.gradle.api.model.ObjectFactory +import org.gradle.api.plugins.ExtensionContainer +import org.gradle.kotlin.dsl.* + + +/** + * Create a new [NamedDomainObjectContainer], using + * [org.gradle.kotlin.dsl.domainObjectContainer] + * (but [T] is `reified`). + * + * @param[factory] an optional factory for creating elements + * @see org.gradle.kotlin.dsl.domainObjectContainer + */ +internal inline fun ObjectFactory.domainObjectContainer( + factory: NamedDomainObjectFactory? = null +): NamedDomainObjectContainer = + if (factory == null) { + domainObjectContainer(T::class) + } else { + domainObjectContainer(T::class, factory) + } + + +/** + * [Add][ExtensionContainer.add] a value (from [valueProvider]) with [name], and return the value. + * + * Adding an extension is especially useful for improving the DSL in build scripts when [T] is a + * [NamedDomainObjectContainer]. + * Using an extension will allow Gradle to generate + * [type-safe model accessors](https://docs.gradle.org/current/userguide/kotlin_dsl.html#kotdsl:accessor_applicability) + * for added types. + * + * ([name] should match the property name. This has to be done manually because using a + * delegated-property provider means Gradle can't introspect the types properly, so it fails to + * create accessors). + */ +internal inline fun ExtensionContainer.adding( + name: String, + crossinline valueProvider: () -> T, +): T { + val value: T = valueProvider() + add(name, value) + return value +} diff --git a/modules/bcv-gradle-plugin/src/main/kotlin/tasks/BCVApiGenerateTask.kt b/modules/bcv-gradle-plugin/src/main/kotlin/tasks/BCVApiGenerateTask.kt index f2924a5..57fe878 100644 --- a/modules/bcv-gradle-plugin/src/main/kotlin/tasks/BCVApiGenerateTask.kt +++ b/modules/bcv-gradle-plugin/src/main/kotlin/tasks/BCVApiGenerateTask.kt @@ -1,6 +1,8 @@ package dev.adamko.kotlin.binary_compatibility_validator.tasks import dev.adamko.kotlin.binary_compatibility_validator.internal.BCVInternalApi +import dev.adamko.kotlin.binary_compatibility_validator.internal.adding +import dev.adamko.kotlin.binary_compatibility_validator.internal.domainObjectContainer import dev.adamko.kotlin.binary_compatibility_validator.targets.BCVTarget import dev.adamko.kotlin.binary_compatibility_validator.workers.BCVSignaturesWorker import java.io.* @@ -8,6 +10,7 @@ import javax.inject.Inject import kotlinx.validation.api.* import org.gradle.api.* import org.gradle.api.file.* +import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Property import org.gradle.api.tasks.* import org.gradle.kotlin.dsl.* @@ -21,10 +24,12 @@ abstract class BCVApiGenerateTask constructor( private val workers: WorkerExecutor, private val fs: FileSystemOperations, + private val objects: ObjectFactory, ) : BCVDefaultTask() { @get:Nested - abstract val targets: NamedDomainObjectContainer + val targets: NamedDomainObjectContainer = + extensions.adding("targets") { objects.domainObjectContainer() } @get:InputFiles @get:PathSensitive(PathSensitivity.RELATIVE)