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

Proposal: Introduce a "--progressive" mode #16344

Closed
ZacSweers opened this issue Feb 28, 2021 · 3 comments
Closed

Proposal: Introduce a "--progressive" mode #16344

ZacSweers opened this issue Feb 28, 2021 · 3 comments
Labels
in:configuration-model lazy api, domain object container

Comments

@ZacSweers
Copy link

ZacSweers commented Feb 28, 2021

Gradle's APIs have significantly improved over the past few years, ranging from lazy task configuration to the upcoming configuration caching features.

However, there is a lot legacy API cruft that remains today, many even are still the default.

A classic example is .all vs .configureEach. A plugin author or gradle user today may find themselves writing something like this:

tasks.all {
  // Stuff
}

There is no warning that this eagerly configures all tasks! Not in code, not in logs, not in consumer builds.

Even worse - this is the default when invoked without a function.

tasks {
    // More eager configuration!
}

The correct thing to do here is use configure or configureEach

tasks.configureEach {

}

There are numerous other common APIs like this: getters vs provider, properties missing input/output annotations, manual task dependencies rather than property dependencies, etc.

I'd like to propose that Gradle adopt the notion of a --progressive mode, inspired by Kotlin's feature of the same functionality.

We believe that a lot of users could use a much faster cycle where critical compiler bug fixes arrive immediately, making the code more safe and correct. So, Kotlin 1.3 introduces the progressive compiler mode, which can be enabled by passing the argument -progressive to the compiler.
In the progressive mode, some fixes in language semantics can arrive immediately. All these fixes have two important properties:

  • They preserve backward compatibility of source code with older compilers, meaning that all the code which is compilable by the progressive compiler will be compiled fine by non-progressive one.
  • They only make code safer in some sense — e.g., some unsound smartcast can be forbidden, behavior of the generated code may be changed to be more predictable/stable, and so on.

Enabling the progressive mode can require you to rewrite some of your code, but it shouldn't be too much — all the fixes enabled under progressive are carefully handpicked, reviewed, and provided with tooling migration assistance. We expect that the progressive mode will be a nice choice for any actively maintained codebases which are updated to the latest language versions quickly.

Replace "compiler" with "gradle APIs" and I believe you have a compelling story for doing the same with Gradle.

In fact, Configuration Caching's testing behavior already shows that Gradle is a good fit for this model, and the community has benefited immensely from it already. The opt-in nature of it allows for Gradle to be less prescriptive about it while allowing both plugin authors and individual consuming developers to test it freely and report issues early. I think the same methodology could be applied to many of the legacy APIs mentioned above.

Power users could even enable this mode by default to keep their build running as performantly as possible. This would also allow Gradle to more aggressively push patterns they want to see in the community, as community users can help knowledge share based on their own usage from this mode.

Some food for thought of how this mode could behave:

  • Available as a command line parameter or gradle property. i.e. --progressive, org.gradle.progressive=none|summary|warn|fail
  • Consider rolling org.gradle.warning under this, or setting it to warn/fail as a subset of the things progressive mode checks

If I could wave a magic wand, some common cases that would fall under this today would include:

  • Tasks missing input/output annotations
  • Usage of non-lazy-configuration APIs.
@ZacSweers ZacSweers added a:investigation Issues requiring decision or investigation affects-version:7.0 labels Feb 28, 2021
@ZacSweers
Copy link
Author

@autonomousapps pointed me to the ValidatePlugins task. I think this is another great example of the kind of runtime checks this mode could enable (I.e. not just hoping plugin authors run this task in their plugin source projects).

@jjohannes jjohannes added in:configuration-model lazy api, domain object container and removed a:investigation Issues requiring decision or investigation labels Mar 23, 2021
@ZakTaccardi
Copy link

Even AGP seems to be messing these APIs up

https://developer.android.com/studio/build/build-variants#build-types

create("staging") {
            initWith(getByName("debug"))
            manifestPlaceholders["hostName"] = "internal.example.com"
            applicationIdSuffix = ".debugStaging"
        }

create(..) and getByName(..) should be register(..) and named(..) respectively

@ZacSweers
Copy link
Author

ZacSweers commented Jan 31, 2022

Closing due to lack of feedback from Gradle, which is disappointing as a Gradle employee asked me to write this up

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in:configuration-model lazy api, domain object container
Projects
None yet
Development

No branches or pull requests

4 participants