Skip to content
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

Type-safe Gradle task accessors #1350

Open
krzema12 opened this issue Apr 6, 2024 · 3 comments
Open

Type-safe Gradle task accessors #1350

krzema12 opened this issue Apr 6, 2024 · 3 comments
Labels
enhancement New feature or request

Comments

@krzema12
Copy link
Member

krzema12 commented Apr 6, 2024

Problem

Currently, the only way of calling a specific Gradle task is to give it as string, e.g.:

command = "./gradlew $library:publishToSonatype closeAndReleaseSonatypeStagingRepository --no-configuration-cache",

It requires great attention to type them correctly. It's also risky to keep these as strings with regards to automatic dependency updates. E.g. see https://github.com/gradle-nexus/publish-plugin/releases/tag/v2.0.0:

Backward incompatible changes

  • closeAndReleaseStagingRepository has been renamed to closeAndReleaseStagingRepositories for consistency

In this particular example, we don't call the task that was renamed, but if we did, Renovate would allow merging such change. The worst thing is that it would be caught at the moment of running the release workflow, which currently e.g. for github-workflows-kt happens once a month.

Idea

In the spirit of https://docs.gradle.org/current/userguide/kotlin_dsl.html#type-safe-accessors.

Rough notes, nothing formal:

  • ./gradlew tasks --all returns a list of tasks in a format like [1], there's also Gradle tooling API. We could extract the task hierarchy from there, and generate Kotlin type-safe accessors, e.g. jit-binding-server:run would map to such Kotlin code: jitBindingServer.run
  • in the GitHub workflow using the Kotlin script, we would have a type-safe wrapper over Gradle that would allow passing only tasks defined in the previous step (+a way to refer to a task in an unsafe, string-based way), along with being able to pass extra arguments like --no-configuration-cache and other free-form arguments
  • sometimes we want to run the same task for several projects, e.g. when we loop across them (ref). Ideally the proposed feature would allow it, e.g. by understanding that if project1 and project2 expose a run task, both projects should probably implement a common interface where run in both cases is the same property in terms of API

Example

Before:

val librariesToPublish = listOf(
    ":shared-internal",
    ":github-workflows-kt",
    ":action-binding-generator",
)

librariesToPublish.forEach { library ->
    run(
        name = "Publish '$library' to Sonatype",
        command = "./gradlew $library:publishToSonatype closeAndReleaseSonatypeStagingRepository --no-configuration-cache",
    )
}

After (rough idea, subject to discussion):

val librariesToPublish = listOf(
    projects.sharedInternal,
    projects.githubWorkflowsKt,
    projects.actionBindingGenerator,
)

librariesToPublish.forEach { library ->
    runGradle(
        name = "Publish '$library' to Sonatype",
        tasks = listOf(
            library.publishToSonatype,
            tasks.closeAndReleaseSonatypeStagingRepository,
        ),
        flags = listOf(noConfigurationCache),
    )
}

[1]

> Task :tasks

------------------------------------------------------------
Tasks runnable from root project 'github-workflows-kt-monorepo'
------------------------------------------------------------

Application tasks
-----------------
automation:code-generator:run - Runs this project as a JVM application
jit-binding-server:run - Runs this project as a JVM application
jit-binding-server:runShadow - Runs this project as a JVM application using the shadow jar
jit-binding-server:startShadowScripts - Creates OS specific scripts to run the project as a JVM application using the shadow jar

Build tasks
-----------
assemble - Assembles the outputs of this project.
action-binding-generator:assemble - Assembles the outputs of this project.
automation:code-generator:assemble - Assembles the outputs of this project.
github-workflows-kt:assemble - Assembles the outputs of this project.
jit-binding-server:assemble - Assembles the outputs of this project.
maven-binding-builder:assemble - Assembles the outputs of this project.
...
@krzema12 krzema12 added the enhancement New feature or request label Apr 6, 2024
@krzema12
Copy link
Member Author

krzema12 commented Apr 7, 2024

Discussion along with some suggestions: https://kotlinlang.slack.com/archives/C02UUATR7RC/p1712389327584009

@krzema12
Copy link
Member Author

Experimenting: #1511

@krzema12
Copy link
Member Author

krzema12 commented Jun 20, 2024

New take on the API:

  • if the project and task name is known up front, we should mimic Gradle's type-safe accesors, so projects.fooBar.baz.someTask
  • if we need to build some project or task name out of smaller string parts, we could have projects["foo-bar"]["baz"]["task"], and if someone attempts to access a project/task that doesn't exist, it would fail at Kotlin script runtime, so still better than GitHub workflow runtime

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant