diff --git a/crd-generator/gradle-plugin/pom.xml b/crd-generator/gradle-plugin/pom.xml
new file mode 100644
index 00000000000..5ce15a77c45
--- /dev/null
+++ b/crd-generator/gradle-plugin/pom.xml
@@ -0,0 +1,234 @@
+
+
+
+ 4.0.0
+
+
+ crd-generator-parent
+ io.fabric8
+ 7.2-SNAPSHOT
+
+
+
+ io.fabric8.crd-generator
+ io.fabric8.crd-generator.gradle.plugin
+ Fabric8 :: CRD generator :: Gradle Plugin
+
+ jar
+
+
+
+ maven-central
+ https://repo1.maven.org/maven2/
+
+
+ repo.gradle.org
+ https://repo.gradle.org/gradle/libs-releases-local/
+
+ false
+
+
+
+ ext.repo.gradle.org
+ https://repo.gradle.org/gradle/ext-releases-local/
+
+ false
+
+
+
+
+
+
+ org.apache.groovy
+ groovy-all
+ ${groovy-api.version}
+ pom
+ provided
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+ provided
+
+
+ org.gradle
+ gradle-all
+ ${gradle-api.version}
+ provided
+
+
+ javax.inject
+ javax.inject
+ 1
+
+
+
+ io.fabric8
+ crd-generator-api-v2
+
+
+
+ io.fabric8
+ crd-generator-collector
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ test
+
+
+ org.slf4j
+ slf4j-simple
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+ commons-io
+ commons-io
+ test
+
+
+ com.google.guava
+ guava
+ test
+ 33.2.0-jre
+
+
+ io.kotest
+ kotest-assertions-core-jvm
+ 5.9.1
+
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-bom
+ ${gradle.kotlin.version}
+ pom
+ import
+
+
+
+
+
+ 1.9.10
+
+
+
+ ${project.basedir}/src/main/kotlin
+ ${project.basedir}/src/test/kotlin
+
+
+ src/test/resources
+
+
+ src/it/resources
+
+
+
+
+ kotlin-maven-plugin
+ org.jetbrains.kotlin
+ ${gradle.kotlin.version}
+
+
+ test-compile
+ test-compile
+
+ test-compile
+
+
+
+ src/test/kotlin
+ src/it/kotlin
+
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+
+
+ generate-test-sources
+
+ add-source
+
+
+
+ ${project.basedir}/src/test/kotlin
+ ${project.basedir}/src/it/kotlin
+
+
+
+
+
+
+ com.marcnuri.plugins
+ gradle-api-maven-plugin
+ true
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ ${maven.surefire.plugin.version}
+
+
+ integration-tests
+
+ integration-test
+ verify
+
+
+ ${project.basedir}/src/it/kotlin
+
+
+
+
+
+
+ fabric8-client.version
+ ${project.version}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/crd-generator/gradle-plugin/src/it/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorPluginIntegrationTest.kt b/crd-generator/gradle-plugin/src/it/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorPluginIntegrationTest.kt
new file mode 100644
index 00000000000..93b10a1c3b1
--- /dev/null
+++ b/crd-generator/gradle-plugin/src/it/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorPluginIntegrationTest.kt
@@ -0,0 +1,38 @@
+package io.fabric8.crd.generator.gradle.plugin
+
+import io.kotest.matchers.collections.containAll
+import io.kotest.matchers.should
+import io.kotest.matchers.shouldBe
+import org.gradle.testkit.runner.GradleRunner
+import org.gradle.testkit.runner.TaskOutcome
+import org.junit.jupiter.api.Test
+
+class CrdGeneratorPluginIntegrationTest : GradlePluginIntegrationTest() {
+ override val projectFiles =
+ mapOf(
+ "settings.gradle.kts" to "/",
+ "gradle.properties" to "/",
+ "src/integrationTest/kotlin/io/fabric8/crd/generator/example/GreetingResource.kt" to
+ "/src/main/kotlin/io/fabric8/crd/generator/example",
+ "src/functionalTest/resources/base/build.gradle.kts" to
+ "/",
+ )
+
+ @Test
+ fun `it should compile and generate from sources`() {
+ // WHEN: running task
+ val result =
+ GradleRunner
+ .create()
+ .withProjectDir(projectDir)
+ .withArguments("generateCRDs")
+ .withPluginClasspath()
+ .build()
+ // THEN: kotlin sources have been build
+ result.tasks.find { it.path == ":compileKotlin" }?.outcome shouldBe TaskOutcome.SUCCESS
+ // AND: main crds have been generated
+ result.tasks.find { it.path == ":generateCRDsMain" }?.outcome shouldBe TaskOutcome.SUCCESS
+ // AND: generated file exists in the correct directory
+ buildDirOf("crds/main").list()!!.toList() should containAll("greetings.example.com-v1.yml")
+ }
+}
diff --git a/crd-generator/gradle-plugin/src/it/kotlin/io/fabric8/crd/generator/gradle/plugin/GradlePluginIntegrationTest.kt b/crd-generator/gradle-plugin/src/it/kotlin/io/fabric8/crd/generator/gradle/plugin/GradlePluginIntegrationTest.kt
new file mode 100644
index 00000000000..0b413377c93
--- /dev/null
+++ b/crd-generator/gradle-plugin/src/it/kotlin/io/fabric8/crd/generator/gradle/plugin/GradlePluginIntegrationTest.kt
@@ -0,0 +1,35 @@
+package io.fabric8.crd.generator.gradle.plugin
+
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.io.TempDir
+import java.io.File
+
+abstract class GradlePluginIntegrationTest {
+ @TempDir
+ lateinit var projectDir: File
+
+ protected abstract val projectFiles: Map
+
+ protected val buildDir by lazy { File(projectDir, "build") }
+
+ fun buildDirOf(subDir: String) = File(buildDir, subDir)
+
+ private fun File.copyToProjectDir(targetDir: String) {
+ File(projectDir, targetDir.trimStart('/') + name).let { targetFile ->
+ if (!exists()) {
+ throw IllegalArgumentException("source '$absolutePath' does not exist")
+ }
+ targetFile.parentFile.mkdirs()
+ if (isDirectory) {
+ copyRecursively(targetFile)
+ } else {
+ copyTo(targetFile)
+ }
+ }
+ }
+
+ @BeforeEach
+ fun prepareProjectDir() {
+ projectFiles.forEach { File(it.key).copyToProjectDir(it.value) }
+ }
+}
diff --git a/crd-generator/gradle-plugin/src/main/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorConfig.kt b/crd-generator/gradle-plugin/src/main/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorConfig.kt
new file mode 100644
index 00000000000..ec09db4a1c8
--- /dev/null
+++ b/crd-generator/gradle-plugin/src/main/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorConfig.kt
@@ -0,0 +1,76 @@
+package io.fabric8.crd.generator.gradle.plugin
+
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.Input
+import org.gradle.api.tasks.Nested
+import org.gradle.api.tasks.Optional
+
+/**
+ * Configuration used by the [CrdGeneratorTask].
+ */
+abstract class CrdGeneratorConfig {
+ /**
+ * Directive configuring the collection of the classes
+ */
+ @get:Nested
+ abstract val collect: CollectDirective
+
+ /**
+ * Directive configuring the emission of the CRDs.
+ */
+ @get:Nested
+ abstract val emit: EmitDirective
+
+ abstract class CollectDirective {
+ /**
+ * enforce the creation of a jandex index, even if one is found.
+ */
+ @get:Input
+ @get:Optional
+ abstract val forceIndex: Property
+
+ /**
+ * names of the classes to be scanned
+ */
+ @get:Input
+ @get:Optional
+ val classes = mutableSetOf()
+
+ /**
+ * package filter for the classes
+ */
+ @get:Nested
+ @get:Optional
+ abstract val packages: Packages
+
+ abstract class Packages {
+ /**
+ * include the provided packages by name.
+ */
+ @get:Input
+ val include = mutableSetOf()
+
+ /**
+ * exclude the provided packages by name.
+ */
+ @get:Input
+ val exclude = mutableSetOf()
+ }
+ }
+
+ abstract class EmitDirective {
+ /**
+ * if to parallelize the generation of the CRDs
+ */
+ @get:Input
+ @get:Optional
+ abstract val parallel: Property
+
+ /**
+ * apiVersions of the CRDs to be generated
+ */
+ @get:Input
+ @get:Optional
+ val crdVersions = mutableSetOf()
+ }
+}
diff --git a/crd-generator/gradle-plugin/src/main/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorExtension.kt b/crd-generator/gradle-plugin/src/main/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorExtension.kt
new file mode 100644
index 00000000000..475b225aef4
--- /dev/null
+++ b/crd-generator/gradle-plugin/src/main/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorExtension.kt
@@ -0,0 +1,10 @@
+package io.fabric8.crd.generator.gradle.plugin
+
+import org.gradle.api.tasks.Internal
+
+/**
+ * Extension object decorating [CrdGeneratorConfig].
+ */
+abstract class CrdGeneratorExtension(
+ @Internal val generatorTask: CrdGeneratorTask,
+) : CrdGeneratorConfig()
diff --git a/crd-generator/gradle-plugin/src/main/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorPlugin.kt b/crd-generator/gradle-plugin/src/main/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorPlugin.kt
new file mode 100644
index 00000000000..8e287571aee
--- /dev/null
+++ b/crd-generator/gradle-plugin/src/main/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorPlugin.kt
@@ -0,0 +1,52 @@
+package io.fabric8.crd.generator.gradle.plugin
+
+import org.gradle.api.DefaultTask
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.api.Task
+import org.gradle.api.plugins.JavaPlugin
+import org.gradle.api.tasks.SourceSet
+import org.gradle.api.tasks.SourceSetContainer
+import org.gradle.kotlin.dsl.create
+import org.gradle.kotlin.dsl.generateCRDsFor
+import org.gradle.kotlin.dsl.getByType
+
+/**
+ * [Plugin] which generates CRDs from the compiled files of the [SourceSet.MAIN_SOURCE_SET_NAME].
+ */
+class CrdGeneratorPlugin : Plugin {
+ companion object {
+ /**
+ * Name of task to be created.
+ */
+ const val TASK_NAME = "generateCRDs"
+
+ /**
+ * Group of the task
+ */
+ const val GROUP = "build"
+
+ /**
+ * Name of the extension object.
+ */
+ const val EXTENSION_NAME = "crds"
+
+ /**
+ * Aggregation task for generating all CRDs
+ */
+ val Project.generateCRDsTask: Task get() = tasks.getByName(TASK_NAME)
+ }
+
+ override fun apply(target: Project) {
+ // Apply the java plugin, in order to have the main source set
+ target.plugins.apply(JavaPlugin::class.java)
+ // Create an aggregation task
+ target.tasks.create(TASK_NAME) {
+ group = GROUP
+ description = "generates CRDs from all source sets registered"
+ }
+ target.generateCRDsFor(
+ target.extensions.getByType().getByName(SourceSet.MAIN_SOURCE_SET_NAME),
+ )
+ }
+}
diff --git a/crd-generator/gradle-plugin/src/main/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorTask.kt b/crd-generator/gradle-plugin/src/main/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorTask.kt
new file mode 100644
index 00000000000..7537747c554
--- /dev/null
+++ b/crd-generator/gradle-plugin/src/main/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorTask.kt
@@ -0,0 +1,101 @@
+package io.fabric8.crd.generator.gradle.plugin
+
+import io.fabric8.crd.generator.collector.CustomResourceCollector
+import io.fabric8.crdv2.generator.CRDGenerator
+import io.fabric8.kubernetes.api.model.HasMetadata
+import org.gradle.api.DefaultTask
+import org.gradle.api.file.DirectoryProperty
+import org.gradle.api.file.FileCollection
+import org.gradle.api.provider.Property
+import org.gradle.api.tasks.Classpath
+import org.gradle.api.tasks.InputFiles
+import org.gradle.api.tasks.Nested
+import org.gradle.api.tasks.OutputDirectory
+import org.gradle.api.tasks.TaskAction
+import java.net.URLClassLoader
+
+/**
+ * [DefaultTask] which generates the CRDs.
+ */
+abstract class CrdGeneratorTask : DefaultTask() {
+ companion object {
+ /**
+ * File extension for class files.
+ */
+ const val CLASS_FILE_EXTENSION = "class"
+ }
+
+ /**
+ * Input files
+ */
+ @get:InputFiles
+ abstract val input: Property
+
+ /**
+ * Classpath for the analysis
+ */
+ @get:Classpath
+ abstract val classpath: Property
+
+ /**
+ * Output directory.
+ */
+ @get:OutputDirectory
+ abstract val output: DirectoryProperty
+
+ /**
+ * Configuration for the collection of the sources and generation of the CRDs.
+ */
+ @get:Nested
+ abstract val configuration: CrdGeneratorConfig
+
+ /**
+ * Extension [CrdGeneratorTask], with a replaceable [CrdGeneratorTask.configuration].
+ */
+ internal abstract class Extension : CrdGeneratorTask() {
+ override lateinit var configuration: CrdGeneratorConfig
+ }
+
+ @TaskAction
+ fun generateCRDs() {
+ emitCRDs(crdSources())
+ }
+
+ private fun crdSources(): List> {
+ logger.debug("creating classloader for the classpath")
+ val inputDirsURLs = input.get().files
+ val classpathURLs = (classpath.get().files + inputDirsURLs).map { it.toURI().toURL() }
+ // Kindly note: in order to load the classes correctly, we need the CRDGenerator's classloader to be the parent
+ val classloader = URLClassLoader(classpathURLs.toTypedArray(), CRDGenerator::class.java.classLoader)
+ logger.debug("scanning input directory for CRD classes")
+ val classFiles =
+ input
+ .get()
+ .asFileTree.files
+ .filter { it.extension == CLASS_FILE_EXTENSION }
+ val crCollector =
+ CustomResourceCollector()
+ .withParentClassLoader(classloader)
+ .withCustomResourceClasses(configuration.collect.classes)
+ .withForceIndex(configuration.collect.forceIndex.getOrElse(false))
+ .withIncludePackages(configuration.collect.packages.include)
+ .withExcludePackages(configuration.collect.packages.exclude)
+ .withFilesToScan(classFiles)
+ return crCollector.findCustomResourceClasses()
+ }
+
+ private fun emitCRDs(sources: List>) {
+ logger.debug("creating target directory")
+ val outputDir = output.get().asFile.absoluteFile
+ outputDir.mkdirs()
+ logger.debug("emitting CRDs using the generator")
+ val generatedFiles =
+ CRDGenerator()
+ .withParallelGenerationEnabled(configuration.emit.parallel.getOrElse(true))
+ .forCRDVersions(configuration.emit.crdVersions.toList())
+ .inOutputDir(outputDir)
+ .customResourceClasses(sources)
+ .generate()
+ logger.info("emitted $generatedFiles CRD(s)")
+ }
+}
diff --git a/crd-generator/gradle-plugin/src/main/kotlin/org/gradle/kotlin/dsl/CrdGeneratorDsl.kt b/crd-generator/gradle-plugin/src/main/kotlin/org/gradle/kotlin/dsl/CrdGeneratorDsl.kt
new file mode 100644
index 00000000000..67f0010567d
--- /dev/null
+++ b/crd-generator/gradle-plugin/src/main/kotlin/org/gradle/kotlin/dsl/CrdGeneratorDsl.kt
@@ -0,0 +1,82 @@
+package org.gradle.kotlin.dsl
+
+import io.fabric8.crd.generator.gradle.plugin.CrdGeneratorConfig
+import io.fabric8.crd.generator.gradle.plugin.CrdGeneratorExtension
+import io.fabric8.crd.generator.gradle.plugin.CrdGeneratorPlugin
+import io.fabric8.crd.generator.gradle.plugin.CrdGeneratorPlugin.Companion.generateCRDsTask
+import io.fabric8.crd.generator.gradle.plugin.CrdGeneratorTask
+import org.gradle.api.Action
+import org.gradle.api.NamedDomainObjectProvider
+import org.gradle.api.Project
+import org.gradle.api.tasks.SourceSet
+import org.gradle.kotlin.dsl.support.uppercaseFirstChar
+
+/**
+ * Add CRD generation for a [SourceSet].
+ * @param sourceSet to add to
+ * @receiver the project (necessary
+ */
+fun Project.generateCRDsFor(sourceSet: SourceSet): CrdGeneratorConfig {
+ val nameSuffix = sourceSet.name.uppercaseFirstChar()
+ val task =
+ tasks.create("${CrdGeneratorPlugin.TASK_NAME}$nameSuffix") {
+ val extension =
+ extensions.create("${CrdGeneratorPlugin.EXTENSION_NAME}$nameSuffix", this)
+ configuration = extension
+ sourceSet.extensions.add(CrdGeneratorPlugin.EXTENSION_NAME, extension)
+ input.set(sourceSet.output)
+ classpath.set(sourceSet.compileClasspath)
+ output.set(layout.buildDirectory.dir("crds/${sourceSet.name}").get())
+ group = CrdGeneratorPlugin.GROUP
+ description = "Generate CRDs from the compiled classes of '${sourceSet.name}'"
+ dependsOn(sourceSet.classesTaskName)
+ }
+ generateCRDsTask.dependsOn(task)
+ return task.configuration
+}
+
+/**
+ * Acquire the [CrdGeneratorConfig] for a [SourceSet].
+ * @receiver [SourceSet] the CRDs are generated from
+ */
+val SourceSet.crds: CrdGeneratorExtension
+ get() = extensions.getByType()
+
+/**
+ * @see SourceSet.crds but for [NamedDomainObjectProvider]
+ * @receiver [NamedDomainObjectProvider] for the [SourceSet] the CRDs are generated from
+ */
+val NamedDomainObjectProvider.crds: CrdGeneratorExtension
+ get() = this.get().crds
+
+/**
+ * Configure the [CrdGeneratorConfig] for a [SourceSet].
+ * @receiver [SourceSet] the CRDs are generated from
+ */
+fun SourceSet.crds(configure: CrdGeneratorConfig.() -> Unit) {
+ configure(crds)
+}
+
+/**
+ * @see SourceSet.crds but for [NamedDomainObjectProvider]
+ * @receiver [NamedDomainObjectProvider] for the [SourceSet] the CRDs are generated from
+ */
+fun NamedDomainObjectProvider.crds(configure: CrdGeneratorConfig.() -> Unit) {
+ configure(crds)
+}
+
+/**
+ * Configure the [CrdGeneratorConfig] for a [SourceSet].
+ * @receiver [SourceSet] the CRDs are generated from
+ */
+fun SourceSet.crds(configure: Action) {
+ crds(configure::execute)
+}
+
+/**
+ * @see SourceSet.crds but for [NamedDomainObjectProvider]
+ * @receiver [NamedDomainObjectProvider] for the [SourceSet] the CRDs are generated from
+ */
+fun NamedDomainObjectProvider.crds(configure: Action) {
+ crds(configure::execute)
+}
diff --git a/crd-generator/gradle-plugin/src/test/kotlin/io/fabric8/crd/generator/example/GreetingResource.kt b/crd-generator/gradle-plugin/src/test/kotlin/io/fabric8/crd/generator/example/GreetingResource.kt
new file mode 100644
index 00000000000..183ad3c7f81
--- /dev/null
+++ b/crd-generator/gradle-plugin/src/test/kotlin/io/fabric8/crd/generator/example/GreetingResource.kt
@@ -0,0 +1,19 @@
+package io.fabric8.crd.generator.example
+
+import io.fabric8.kubernetes.client.CustomResource
+import io.fabric8.kubernetes.model.annotation.Group
+import io.fabric8.kubernetes.model.annotation.Kind
+import io.fabric8.kubernetes.model.annotation.Version
+
+@Group("example.com")
+@Version("v1")
+@Kind("Greeting")
+class GreetingResource : CustomResource() {
+ data class Spec(
+ val hello: String = "",
+ )
+
+ class Status(
+ val greeting: String = "",
+ )
+}
diff --git a/crd-generator/gradle-plugin/src/test/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorPluginTest.kt b/crd-generator/gradle-plugin/src/test/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorPluginTest.kt
new file mode 100644
index 00000000000..e1e53d9b34f
--- /dev/null
+++ b/crd-generator/gradle-plugin/src/test/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorPluginTest.kt
@@ -0,0 +1,32 @@
+package io.fabric8.crd.generator.gradle.plugin
+
+import io.fabric8.crd.generator.gradle.plugin.CrdGeneratorPlugin.Companion.generateCRDsTask
+import io.kotest.matchers.nulls.beNull
+import io.kotest.matchers.shouldNot
+import org.gradle.api.tasks.SourceSet
+import org.gradle.api.tasks.SourceSetContainer
+import org.gradle.kotlin.dsl.crds
+import org.gradle.kotlin.dsl.getByType
+import org.gradle.testfixtures.ProjectBuilder
+import org.junit.jupiter.api.Test
+
+class CrdGeneratorPluginTest {
+ private val project = ProjectBuilder.builder().build()
+
+ @Test
+ fun `should add task to main source set`() {
+ // WHEN: applying plugin
+ project.plugins.apply(CrdGeneratorPlugin::class.java)
+ // THEN: extension object is present
+ val extObj =
+ project.extensions
+ .getByType()
+ .named(SourceSet.MAIN_SOURCE_SET_NAME)
+ .crds
+ extObj shouldNot beNull()
+ // AND: generator task is present
+ extObj.generatorTask shouldNot beNull()
+ // AND: aggregation task is present
+ project.generateCRDsTask shouldNot beNull()
+ }
+}
diff --git a/crd-generator/gradle-plugin/src/test/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorTaskTest.kt b/crd-generator/gradle-plugin/src/test/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorTaskTest.kt
new file mode 100644
index 00000000000..ac5a2990448
--- /dev/null
+++ b/crd-generator/gradle-plugin/src/test/kotlin/io/fabric8/crd/generator/gradle/plugin/CrdGeneratorTaskTest.kt
@@ -0,0 +1,35 @@
+package io.fabric8.crd.generator.gradle.plugin
+
+import io.kotest.matchers.collections.containAll
+import io.kotest.matchers.should
+import org.gradle.kotlin.dsl.create
+import org.gradle.testfixtures.ProjectBuilder
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.io.TempDir
+import java.io.File
+
+class CrdGeneratorTaskTest {
+ companion object {
+ private val testBuildPath = File("build/classes/kotlin/integrationTest").normalize().absolutePath
+ }
+
+ private val project = ProjectBuilder.builder().build()
+
+ @TempDir
+ protected lateinit var tmpDir: File
+
+ @Test
+ fun `should generate the custom resources`() {
+ // WHEN: creating a task
+ val task =
+ project.tasks.create("test") {
+ input.set(project.layout.files(testBuildPath))
+ output.set(project.layout.dir(project.provider { tmpDir.absoluteFile }))
+ classpath.set(project.layout.files(tmpDir.absolutePath))
+ }
+ // AND: running it
+ task.actions.forEach { it.execute(task) }
+ // THEN: the CRDs are generated
+ tmpDir.list()?.toList()!! should containAll("greetings.example.com-v1.yml")
+ }
+}
diff --git a/crd-generator/gradle-plugin/src/test/kotlin/org/gradle/kotlin/dsl/CrdGeneratorDslTest.kt b/crd-generator/gradle-plugin/src/test/kotlin/org/gradle/kotlin/dsl/CrdGeneratorDslTest.kt
new file mode 100644
index 00000000000..e4e3a5b034c
--- /dev/null
+++ b/crd-generator/gradle-plugin/src/test/kotlin/org/gradle/kotlin/dsl/CrdGeneratorDslTest.kt
@@ -0,0 +1,103 @@
+package org.gradle.kotlin.dsl
+
+import io.fabric8.crd.generator.gradle.plugin.CrdGeneratorConfig
+import io.fabric8.crd.generator.gradle.plugin.CrdGeneratorPlugin
+import io.fabric8.crd.generator.gradle.plugin.CrdGeneratorPlugin.Companion.generateCRDsTask
+import io.kotest.matchers.booleans.shouldBeTrue
+import io.kotest.matchers.collections.contain
+import io.kotest.matchers.nulls.beNull
+import io.kotest.matchers.should
+import io.kotest.matchers.shouldBe
+import io.kotest.matchers.shouldNot
+import io.kotest.matchers.types.instanceOf
+import org.gradle.api.Action
+import org.gradle.api.Project
+import org.gradle.api.Task
+import org.gradle.api.tasks.SourceSet
+import org.gradle.api.tasks.SourceSetContainer
+import org.gradle.testfixtures.ProjectBuilder
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+
+class CrdGeneratorDslTest {
+ private val project = ProjectBuilder.builder().build()
+
+ @BeforeEach
+ fun applyPlugin() {
+ project.plugins.apply(CrdGeneratorPlugin::class.java)
+ }
+
+ @Test
+ fun generateCRDsFor() {
+ // WHEN: adding generation for another source set
+ project.generateCRDsFor(project.sourceSets[SourceSet.TEST_SOURCE_SET_NAME])
+ // THEN: a task is added
+ val newTask = project.tasks.findByName("generateCRDsTest")
+ newTask shouldNot beNull()
+ // AND: the aggregation task depends on the task
+ project.generateCRDsTask.ownDependencies should contain(newTask)
+ }
+
+ @Test
+ fun `crds extension value`() {
+ // EXPECT: the source set has the extension
+ project.sourceSets[SourceSet.MAIN_SOURCE_SET_NAME].crds shouldNot beNull()
+ // EXPECT: the source set provider has the extension
+ project.sourceSets.named(SourceSet.MAIN_SOURCE_SET_NAME).crds shouldNot beNull()
+ }
+
+ @Test
+ fun `crds configuration from source set with closure`() {
+ // WHEN: configuring using the action
+ val action = CrdAction()
+ project.sourceSets[SourceSet.MAIN_SOURCE_SET_NAME].crds(action.asClosure)
+ // THEN: action is called
+ action.shouldHaveBeenCalled()
+ }
+
+ @Test
+ fun `crds configuration from source set with action`() {
+ // WHEN: configuring using the action
+ val action = CrdAction()
+ project.sourceSets[SourceSet.MAIN_SOURCE_SET_NAME].crds(action)
+ // THEN: action is called
+ action.shouldHaveBeenCalled()
+ }
+
+ @Test
+ fun `crds configuration from source provider set with closure`() {
+ // WHEN: configuring using the action
+ val action = CrdAction()
+ project.sourceSets.named(SourceSet.MAIN_SOURCE_SET_NAME).crds(action.asClosure)
+ // THEN: action is called
+ action.shouldHaveBeenCalled()
+ }
+
+ @Test
+ fun `crds configuration from source set provider with action`() {
+ // WHEN: configuring using the action
+ val action = CrdAction()
+ project.sourceSets.named(SourceSet.MAIN_SOURCE_SET_NAME).crds(action)
+ // THEN: action is called
+ action.shouldHaveBeenCalled()
+ }
+
+ val Project.sourceSets
+ get() = extensions.getByType()
+
+ val Task.ownDependencies
+ get() = taskDependencies.getDependencies(this)
+
+ class CrdAction : Action {
+ private var called = false
+
+ val asClosure: CrdGeneratorConfig.() -> Unit get() = { execute(this) }
+
+ fun shouldHaveBeenCalled() = called.shouldBeTrue()
+
+ override fun execute(t: CrdGeneratorConfig) {
+ t shouldBe instanceOf()
+ called = true
+ }
+ }
+}
diff --git a/crd-generator/pom.xml b/crd-generator/pom.xml
index a6cfd1e7d6f..5c678d4e5b3 100644
--- a/crd-generator/pom.xml
+++ b/crd-generator/pom.xml
@@ -36,6 +36,7 @@
apt
collector
maven-plugin
+ gradle-plugin
cli
test
test-apt