Also update Gradle wrapper with Java version upgrades
We have an existing recipe to upgrade Gradle wrappers; When upgrading applications to Java 11, 17 and beyond, we should also upgrade the Gradle wrapper to the corresponding versions as per the version compatibility matrix.
| Java version | First Gradle version to support it |
|---|---|
| 8 | 2.0 |
| 9 | 4.3 |
| 10 | 4.7 |
| 11 | 5.0 |
| ... | ... |
| 17 | 7.3 |
| 18 | 7.5 |
| 19 | 7.6 |
We should
- Add a dependency on
rewrite-gradle - Add the
org.openrewrite.gradle.UpdateGradleWrapperin for instance src/main/resources/META-INF/rewrite/java-version-17.yml - Pass the appropriate minimum
versionparameter according tot he above table - Take care that we don't accidentally downgrade any Gradle versions.
@timtebeek, this is a great idea and one that I've thought of before. Only aspect though, which could also remove it as a good first issue for now, would be that if the project were using deprecated Gradle features and these recipes were applied it could leave the project in a broken state. Given the OpenRewrite rule of "Do no harm", I think we would have to wait until at least the breaking changes per Gradle major version migration recipes have also been implemented.
Thanks for pointing that out @shanman190 ; that indeed blocks this one until the Gradle version migration recipes catch up.
I'm thinking if there's anything we can do until then as a partial solution; Would you think it'd be helpful to detect and upgrade within the 7.x range for instance? I'm not expecting breaking changes there, and it would get those on 7.0-2 unstuck in moving up to 17, 18, 19, ...
It might mean we need to split the Gradle version migrations similar to what we already do with the Spring version migrations: daisy chain them together and properly guard to only update within a range for certain recipes, which we then use here for now.
@timtebeek, we could do half steps in terms of upgrading within a major line, but that also requires applicability tests to work properly (predicated on https://github.com/openrewrite/rewrite/issues/2746).
In total what comes to mind when talking about an upgrade to JDK 17 for Gradle as an example:
- Update Gradle wrapper to 7.3 or newer (use 7.x in recipe definition)
- Update Java toolchains to JDK 17, if in use
- Change source compatibility to 17, if in use
- Change target compatibility to 17, if in use
- Migrate code to JDK 17
To localize this a bit if the above issue were resolved, then you could easily do a half step of upgrading within the major line. So for folks on 7.x already, they'd get benefits immediately.
@timtebeek, I was thinking about this a little bit more and there's an interesting part of this.
If the project is using Gradle 6.7+ AND using JVM toolchains, then just updating the toolchain to JDK 17 is enough (read: wrapper update is not required). However, if the project is using sourceCompatibility or targetCompatibility instead, then the wrapper must be upgraded to Gradle 7.3+ (read: wrapper update is required) OR the project migrated to JVM toolchains.
That's an interesting take indeed; could spare us some of the pain of migrating between Gradle versions if we provide a recipe to switch people over to toolchains, or merely upgrade the toolchain where applicable. Would you say that warrants a separate recipe, perhaps split off from the one that upgrades source/target compatibility?
Eventually I imagine we might still want to upgrade the wrapper, but that would need to also handle deprecations, which would be more work before we can confidently run that unsupervised.