-
Notifications
You must be signed in to change notification settings - Fork 454
Simplify Gradle Plugin #1194
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Simplify Gradle Plugin #1194
Conversation
377ac8b
to
c86185e
Compare
a87c0bf
to
dc6d1ac
Compare
ac54b16
to
7e5d83f
Compare
72dd286
to
6abbd43
Compare
529200f
to
6821309
Compare
fun ExternalDocumentationLink.Companion.jdk(jdkVersion: Int): ExternalDocumentationLinkImpl { | ||
return ExternalDocumentationLink( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
=
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
return ExternalDocumentationLink("https://kotlinlang.org/api/latest/jvm/stdlib/") | ||
} | ||
|
||
fun ExternalDocumentationLink.Companion.androidSdk(): ExternalDocumentationLinkImpl { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
=
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅
...gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/sourceSetKotlinGistConfiguration.kt
Outdated
Show resolved
Hide resolved
runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/toDokkaSourceSetImpl.kt
Outdated
Show resolved
Hide resolved
) | ||
} | ||
|
||
private fun GradleDokkaSourceSetBuilder.moduleNameOrDefault(): String { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
=
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌
return name | ||
} | ||
|
||
private fun GradleDokkaSourceSetBuilder.externalDocumentationLinksWithDefaults(): Set<ExternalDocumentationLinkImpl> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
=
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❌
runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/utils.kt
Outdated
Show resolved
Hide resolved
…expected to be distinct
…IBs to the Dokka classpath) into `kotlinClasspathUtils``
cf26c3e
to
689a528
Compare
3959b47
to
69a6ac7
Compare
private set | ||
|
||
@get:Nested | ||
internal val childDokkaTasks: Set<AbstractDokkaTask> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A task inside a task does not seem right. Why is this needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This kind of "parent" tasks are managing multiple "child" tasks. Accessing them like this is not just there for convenience. While not all parent tasks do have task dependencies on its children, they should still re-run if any of the child's configuration changes. This happens to work pretty nicely with this @Nested
pointing to the actual tasks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mh. Usually. This is not a pattern that should be required. I haven't seen this before. :)
While not all parent tasks do have task dependencies on its children, they should still re-run if any of the child's configuration changes.
Maybe you can show a concrete use case? I don't quite understand what that means.
|
||
open class DokkaCollectorTask : AbstractDokkaTask() { | ||
open class DokkaCollectorTask : AbstractDokkaParentTask() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably just 💄 , but I would recommend making all task classes abstract instead of open.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the hint!
Pushed a commit to change this ✅
import org.jetbrains.dokka.utilities.cast | ||
import kotlin.reflect.typeOf | ||
|
||
internal inline fun <reified T : Any> ObjectFactory.safeProperty() = property<T?>() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need these extension methods and can not use property<T>()
directly? It's already <T>
not <T?>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an interesting question:
So the issue that I have with properties is, that it was really hard for me to track whether or not I expect some value being present in a Property, or if it is actually, truly "optional". The current implementation of Property
also does not care. It is like "can be there, might not".
Therefore, I started tracking my expectations of any Property
myself in the Type-System:
The convention internally here is:
Property<T?>
-> No value requiredProperty<T>
-> Fail if value is missing
See this getSafe
method, that I am using everywhere. This will use orNull
if the type T is optional and get
otherwise.
@OptIn(ExperimentalStdlibApi::class)
internal inline fun <reified T> Provider<T>.getSafe(): T =
if (typeOf<T>().isMarkedNullable) orNull as T
else get()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What exactly do you mean by "tracking expectations"? Is there any tooling that helps you here to ensure that the value is set?
Gradle should already do this for you. If you mark a property that you use somewhere as input with @Optional
keeping it unset is allows (basically it is nullable) otherwise, you will get an error if it is not set.
|
||
@Input | ||
@Optional | ||
val displayName: Property<String?> = project.objects.safeProperty() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should use Property here. A property can always be unset and usually that should be enough and there shouldn't be the need to set it to null. You can still use @Optional
to state that unset is a valid state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean I should use a Kotlin property? var displayName: String? = null
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Term property is quite overloaded. :)
This is what I mean:
val displayName: Property<String> = project.objects.property()
or, if you can make the class abstract, just:
abstract val displayName: Property<String>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now I saw the other comment, which answers why you use <String?>
. I'll answer there later.
val displayName: Property<String?> = project.objects.safeProperty() | ||
|
||
@InputFiles | ||
val sourceRoots: ConfigurableFileCollection = project.files() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of objects.fileCollection()
would be the better API if you just need an empty collection (If it is available in the Gradle version you want to support).
Even better would be to make the class and all the properties abstract. Like:
@get:InputFiles
abstract val sourceRoots: ConfigurableFileCollection
Then Gradle will inject everything and you have much less boilerplate. And you probably won't have to pass project
and/or objects
around.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot, I did not know about objects.fileCollection
and I also did not know about the fact, that Gradle will inject into Abstract classes here as well, which is awesome!! 🤪
Pushed a commit for objects.fileCollection
. Making this object abstract will require some tests to be adapted. I will wait for another PR to be merged first to tackle this! :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically everywhere where you pass a class to Gradle so that Gradle does the instantiation, you can use an abstract class and will get an object of an instrumented subclass that does all these things automatically.
Closes #1108
Closes #1107
Closes #995
Closes #1113
Closes #1114
Closes #1285
Closes #1286
Closes #1287
Closes #1288
Closes #1289
Closes #1290
Closes #1291
Closes #1292
Closes #1274
Closes #1106