you need to refer to extension classes/convention ...
# announcements
a
you need to refer to extension classes/convention classes more explicitly in Kotlin DSL, they don't magically appear as extension properties on the project
f
do you know any good reference?
a
e.g.
the<JavaPluginConvention>().sourceCompatibility = JavaVersion.VERSION_1_8
a good reference, no, I had to figure this out by noodling around
f
ok, let me give it a try 🙂
a
there is a "withConvention" extension function intended to be used on any object that implements hasConvention (e.g. source sets etc, not just projects)
which I used like this:
Copy code
val SourceSet.scala: SourceDirectorySet
    get() = withConvention(ScalaSourceSet::class) { scala }
f
well, I’m working with extensions, not conventions
a
I got the impression they were mixed together
f
conventions are the older concept
and are replaced by extensions over tome
time
which is why I’m implementing an extension
a
the DSL plugin typically uses "extension" to mean Kotlin extension functions, though
c
Just use
plugins {}
block instead of
buildscript {}
, that will generate proper DSL for you, e.g.
Copy code
plugins {
	java
}
java {
	sourceCompatibility = VERSION_1_8
	targetCompatibility = VERSION_1_8
}
f
ha - seems there is a problem with the test runner…
a
there is an
ExtensionContainerExtensions.kt
in the DSL plugin to allow you to write
extensions["xxx"]
etc
ah, right, so things like
reporting
are project extensions
f
weird one:
Copy code
plugins {
     id("info.florian-wiesner.magicdraw")
}
it is found
but…
the<florianwiesner.gradle.magicdraw.MagicDrawExtension>()
leads to an unresolved reference
will dig deeper - thanks @araqnid
a
is your extension registered with a name? if so, as Alexander said, it should have been added to the generated glue so you can just refer to it by name
you can also just call
extensions.findByType(ReportingExtension::class.java)
which that should be sugar for
f
well, I have a plugin descriptor under META-INF
and I currently try gettings things work under Gradle’s test kit
using Spek as my test framework
my dynamic test script uses the
plugins{}
DSL
and I see the plugin to get loaded
a
don't you have to call something from the plugin method to register the project extension?
f
Copy code
class MagicDrawGradlePlugin : Plugin<Project> {
    private lateinit var project: Project

    override fun apply(project: Project?) {
        if (project == null) throw GradleException("project must not be null")
        this.project = project
        val extension = addExtension<MagicDrawExtension>("magicdraw", project.objects)

        val verifyMagicDrawTask = project.tasks.create("verifyMagicDraw", VerifyMagicDrawTask::class.java)
        verifyMagicDrawTask.installDir = extension.installDir as String? ?: ""
    }

    private inline fun <reified T> addExtension(name: String, vararg args: Any): T = project.extensions.create(name, T::class.java, *args)

}
let me make a snippet
a
right, so it's registered as
magicdraw
so you should be able to write
magicdraw { ... }
in the build script, and the glue should have made a Project.magicdraw extension property
f
magicdraw{...}
is there
but the installDir property is not recognized
a
that's a property of the task or the extension or both?
f
both
a
are you running the test from IntelliJ or Gradle command-line? I had trouble running this kind of test from IntelliJ
with it using old versions of the classes under test
f
in the apply function I copy the property value over to the newly created task
I run it from gradle
a
you copy it from the project extension to the task at the time the plugin is applied? that sounds a bit fishy
f
I wonder whether the test framework
GradleRunner
supports Kotlin DSL
this is just a trial so far
and btw, that’s even done in the Gradle docs, when a task is auto-generated from the plugin
a
I suspect that if it didn't, you encounter problems much earlier
f
and I see a big issue
a
ah? hmm, I should really get more acquainted with those
f
well, how would you generate a default task definition without having the plugin code do so? 😉
a
so what happens when the build file changes the settings in the extension object?
f
anyway…
plugins{id()...)}
finds my plugin and loads it
but the script cannot find my classes
imports fail
so, I guess that the test runner only sees the proxies
but not the plugin classes
plugins{...}
might work because it is somewhat separated from the rest of the script
which is why
Copy code
val fooVersion:String by extra
plugins {
  id("bar") version fooVersion
}
won’t work
a
yes, plugins{} has to be right at the top iirc
f
from a Gradle script perspective yes
it has to be the first element after
buildscript
a
well, using plugins{} should replace buildscript{} entirely
f
but Kotlin could of course to things ahead of the
plugins
block
tell that to the JUnit platform guys..
I will investigate and update this thread
a
kotlin-dsl aiui must grab the set of plugins, use that to generate the "glue" project class with all the extensions/conventions in and then compile the script with an instance of the glue project as receiver
(you can see the "glue" class if you ctrl+click on sth like "java" or "reporting" in a build.gradle.kts)
f
guess that’s option-B on my keyboard
but really, I assume there is breakage in the test runner
a
something like that
f
I will test publish the plugin to MavenLocal()
and then have a standalone project use it
a
I'm trying it here, but even explicitly requesting the extension I'm creating by name isn't working so ...
f
I have to leave for dinner. Will look into it tomorrow and update the thread
thanks so far!
a
hmph, yes, I can register a project extension and it seems to work when referenced entirely separately, but not when trying to use GradleRunner
the "glue" class is written to somewhere like
/tmp/.gradle-test-kit-shaslam/caches/4.5/gradle-kotlin-dsl-accessors
-- i tried just removing the caches, no change
but that generated class doesn't specify the type of my project extension, the extension property is type
Any
so it seems lined up with the problem you're seeing of not finding the classes in the build script?
it writes in a comment above the extension property that the named class is not available -- so it knows what the type should be, it just couldn't load it
Copy code
/**
 * Configures the [webpack][com.timgroup.gradle.webpack.WebpackProjectExtension] project extension.
 *
 * `webpack` is not accessible in a type safe way because:
 * - `com.timgroup.gradle.webpack.WebpackProjectExtension` is not available
 */
fun Project.`webpack`(configure: Any.() -> Unit): Unit =
    extensions.configure("webpack", configure)
but publishing to mavenLocal, and pulling it into another project generates the glue class fine ¯\_(ツ)_/¯
same result with Gradle 4.6. There is also a #C19FD9681 btw 😉
f
ah thanks
m
saw the post in #C19FD9681 - this sounds similar to https://github.com/gradle/kotlin-dsl/issues/492