just came up with such idea <Type-safe Gradle task...
# github-workflows-kt
p
just came up with such idea Type-safe Gradle task accessors thoughts? @Vampire I think you may like it, or may even have a clue if some Gradle internals can be reused to implement it?
v
Generally a great idea, but some concerns: • don't call a task and parse its output, instead use the tooling API to extract the information you want like an ide does • when / where would you generate the accessors? They must be generated before compiling the script • Unless you have a verify-all step you would still only on release see that it is broken
p
don't call a task and parse its output, instead use the tooling API to extract the information you want like an ide does
thanks for the hint!
when / where would you generate the accessors? They must be generated before compiling the script
assuming that creating a compiler plugin is still not recommended because of unstable API and inconvenient usage from within the scripts, I thought about having an extra step in the consistency check job, similar to where action bindings are generated in the client-side generation (ref). The API is TBD, I thought about providing a generic extension point to be able to inject custom steps in this job
Unless you have a verify-all step you would still only on release see that it is broken
yes, maybe it's about time to provide proper tooling/docs on how to implement such complete check (ref)
v
I think having to have an extra workflow step you earn the same problems why you now see that client side generation doesn't work out to good. If it works on the fly, so once compiler plugins might be supported or KSP or similar, it might be nice. But currently I wouldn't put too much effort in that in the current state, but better implement other things like the type-safe inputs/output wiring.
p
playing with Gradle tooling API, simpler than I thought: https://github.com/typesafegithub/github-workflows-kt/pull/1511
I just don't understand what
public
flag means: https://github.com/gradle/gradle/blob/f6f93cbb52aa152409d15d65513d4356f8c45480/pla[…]le/plugins/ide/internal/tooling/model/LaunchableGradleTask.java - is it like an internal task, not a part of the API?
when generating the type-safe accessors, I should still generate the accessors for the private tasks because it's up to the user to decide whether to depend on them, right?
v
I'd say so, yes.
If a group has not "group" set it is considered implementation detail / internal / hidden / whaterver you want to call it
Those are not shown by
gw tasks
but are shown by
gw tasks --all
.
If you look at the Gradle toolwindow in IntelliJ, the "other" tasks are those
👍 1
-If a group has not +If a task has no
If you generate accessors, you could maybe even group them so that you first have an accessor for the group (and one "other" for the "hidden" tasks) and then under the group the actual tasks, just like the IDE shows it.
Or at least one such sub-accessor for all "other" tasks that most often meant to not be called directly
And there must still be some manual option, because task rules for example are not listable as they are parsed and dynamically created from the task name you request.
p
> If you generate accessors, you could maybe even group them so that you first have an accessor for the group (and one "other" for the "hidden" tasks) and then under the group the actual tasks, just like the IDE shows it. My idea for the first iteration is as follows: 1. Refer to Gradle tasks the same way one can refer to them using Gradle CLI, that's why I'm hesitant to add the group names when accessing the tasks. We can play with this at some point, however. 2. I don't want to generate any Kotlin code for now, and instead produce a JSON file with the task structure. Then, the JSON file would be read by the library to validate if a reference to a task that would look something like
tasks["shared"]["model"]["build"]
is valid. If it's not, the script would fail in runtime. I know, it's not proper type-safety and it doesn't give proper task discoverability in the IDE, but it will still fail before running the YAML so the benefit is there. I'm willing to switch to generating the Kotlin accessors once Kotlin Scripting gets some reasonable integration with code generation or compiler plugins. Without this, it's just too much hassle. Let me know if it looks sound!
v
Sounds fine. Maybe nicer would be if
tasks
is a method that gets the path like
tasks(":shared:model:build")
or if
tasks
is already some thing, an
invoke(...)
method that accepts
String
for
vararg String
to get that same syntax
But yeah, the groups and so on are more when having accessors for better code completion
👍 1
p
good ideas, thanks 👍 I'll play with this
v
But still, there is the point that you cannot list all possible task names
So you still need a way to give something arbitrary that is not checked
There can be task rules where tasks are created dynamically if the requested name matches a configured naming convention
And theoretically one can use
buil
if this resolves unambiguously to
build
p
sure, some
tasksUnsafe
function or equivalent
v
This is maybe not so relevant, but the task rules are
👍 1
Maybe not "unsafe", that sounds dangerous while it is a normal use-case
p
tasksUnchecked
,
tasksDynamic
?
v
Yeah, just typed those also 😄
🙌 1
Or
tasksUnverified
Or whatever, not sure
Naming is one of the hardest parts in software development 😄
p
oddily, harder than giving children names 😄
👌 1
@Vampire there's a problem with depending on
org.gradle:gradle-tooling-api
. It's hosted in a different repo than Maven Central (
<https://repo.gradle.org/gradle/libs-releases|https://repo.gradle.org/gradle/libs-releases>
) and adding a dependency on this lib forces the users of their scripts to add this repo with
@file:Repository
. I don't like it because it's effectively a breaking change caused by changing an implementation detail of the lib. Some users may not even care about this feature, so I don't want to force everyone to add the repo. I have two ideas: 1. Ask Gradle folks to publish the lib to Maven Central. 2. Bundle the lib in github-workflows-kt's JAR, something like a fat JAR but only with this single library attached. Thoughts? 😊
BTW, is it a bug in Kotlin Scripting? I haven't checked it, but I think in a regular Gradle project, if you depend on something that needs its dependency from an exotic repo, this piece of info is taken from the POM.
v
No it is not. With Maven it is, but it's a horrible idea like many other stupid design decisions in Maven. The final consumer always has to have the final say on where something is taken from. Otherwise your can for example not easily fulfill corporate rules like everything has come from an internal audited mirror. I'm generally a big disliker of any dependency shading, and especially in libs. If you really want to do it, at least also relocate the classes. Better would be a feature variant on the same source set with the additional dependency. That will then end up as optional dependency in the POM, so to use the feature you have to provide the dependency additionally. This way it would also be a non-breaking change.
p
Could you elaborate on your recommended idea, how to implement it?
Ok, I probably get how to achieve the "optional dependency" -
compileOnly
?
v
That's one way, but not what I said. What I said was a feature variant. The end result will basically be the same for non-Gradle consumers, but better for Gradle consumers