This message was deleted.
# plugin-development
s
This message was deleted.
v
Not 100% what you mean. If you have a full task class, there is at least a validation that all properties have a configuration whether they are input, output, or neither.
m
Copy code
abstract class MyTask: DefaultTask() {
  @get:Input
  abstract val myInput: Property<String>

  @TaskAction
  fun doStuff() { ... }
}
If
MyTask.myInput
is not set, it will fail at runtime, I'd like to detect this at build time
Or maybe "set" is not the correct language, maybe just "wired"
v
How should you be able to?
m
If everything was constructor arguments maybe
But I don't see how to make this typesafe since Gradle owns the constructor
v
I don't think this is really possible, especially as the code registering the task usually does not call its constructor
m
Ideally this
Copy code
class MyTask(val myInput: Property<String>) : DefaultTask() {
  @TaskAction
  fun doStuff() { ... }
}
But yea the constructor is not really accessible
v
If you want to enforce this for a plugin of yours, you could for example have some extension method that registers the task and has the necessary fields as parameters.
But I don't think there is really something sensefully possible in a generic way
m
have some extension method that registers the task and has the necessary fields as parameters.
That's what I'm doing but that extension method code is the weak link in the chain now because I need to make sure I do not forget any input
Anyways, maybe something for later. Thanks for the discussion, as always!
👌 1
a
do you mean you want something so it's easier to instantiate and set the convention for a property? E.g. if you wired in ObjectsFactory you could write a shortcut function, like this:
Copy code
@get:Input
  val myInput: Property<String> = property(convention = "foo")
you could use some delegate properties to try to move the boilerplate of defining new properties. If Gradle didn't require
@get:Input
annotations (which are ugly imo) then you could even remove them and register the inputs using the runtime inputs API.
m
Problem I'm trying to solve is: 1. I add a new parameter to my codegen engine 2. In order to use it in a Gradle task, I add a matching input field to my Gradle task 3. This task input needs to be exposed either to the user or set in the plugin code I tend to forget 3.
Conventions could help I guess for optional inputs but a lot of them are required
In a way, it's a bit like builders vs constructors. If everything is a builder method then it's not really typesafe because you don't know what is required vs what's not. Same for tasks, there's no real way to enforce setting a property with a value. Maybe we need a
Provider
that can never be absent or so
Sorry I'm not sure where I'm going with this, was just curious if there was existing discussions or if others shared the concern
v
Providers do always need a value. At least if you
get()
them. If it is optional you have to check presence or specify a default value to get.
And the checks you want are there, they are just runtime checks, as only at runtime you can tell whether a required value is given or not.
What you asked for was a compile-time check, and that I don't think is really nicely possible in a generic way.
m
Only if the task is created during configuration (and not in plugin application) I guess
v
?
plugin application is during configuration
a
hmm so perhaps instead of
Copy code
tasks.register(FooTask::class) {
 /* properties that you forget to set */
}
you'd want a function with args?
Copy code
tasks.register(FooTask::class, 
  a = "a",
)
And then when you add a new
b
property to FooTask, you'd get an error
Copy code
tasks.register(FooTask::class, 
  a = "a",
  // error: missing value for arg 'b'
)
m
> plugin application is during configuration yea sorry, what I meant is this is all coming back to the "declarative" vs "imperative" thing. Currently you create a task when you apply the plugin with a bunch of inputs that are set at runtime. In a more "imperative" way, you could force the user to provide the values (even if lazy) when creating the task (and have that checked at compile time).
you'd want a function with args?
This could work but isn't 100% typesafe, is it? All parameters are of
Any
type IIRC
a
yeah - it doesn't work at the moment
personally I think asking users to manually register tasks is a no-no. All the configuration should be done via a plugin DSL, and then you can have more control over the inputs.
m
manually register tasks is a no-no
It can be hidden behind a DSL method.
a
but that doesn't help trying to remember to copy all the conventions from the plugin's extension into the task
m
Copy code
myExtension {
  createTask("name", "mandatoryParam", otherTask.flatMap { it.mandatoryRegularFile }, mandatoryIntParam) {
     optionalParam.set(...)
  }
}
a
it'd be cool if there was a Kotlin compiler plugin that could generate a "register task" function with the required input properties as args. I'm thinking of something like https://kopyk.at/
👀 1
v
You would probably need some compiler plugin, or a static code analysis that checks what properties a task has and whether they all get set.
m
Compiler plugin would work 👍
Project #5800 😅
💯 1
👌 1
a
if
@Nested
worked properly with recursion and output directories you could create a FooTaskProperties class that had to be manually instantiated and then passed into the FooTask's constructor...
👀 1
e
within AGP, task classes have associated creation action classes. if you stick to a pattern like that, you can't miss inputs
👀 1
but I don't think it's that big of a deal usually.
--dry-run
will catch missing required inputs, IIRC
v
His concern is, that he would forget to add the input to the "creation action class" if I got it right.
👍 1
Because we also suggested methods for task creation above already
m
within AGP, task classes have associated creation action classes
Stuff like this (
CreationAction
)? If yes then indeed I'd have to write this manually. Which is doable but error prone.