rewrite-gradle-plugin icon indicating copy to clipboard operation
rewrite-gradle-plugin copied to clipboard

Activating Recipes Directly in a Gradle Plugin Without Defining in Configuration

Open k3code06 opened this issue 1 year ago • 7 comments

What version of OpenRewrite are you using?

I am using

  • Gradle plugin v6.1.19

How are you running OpenRewrite?

I am creating gradle plugin by overriding existing open rewrite gradle plugin. All the recipes that need to be activated and implementation of my gradle plugin are present in the same project. (The Path of all the recipes is- src/main/resources/META-INF/rewrite) Screenshot 2024-04-10 at 4 45 41 PM As given in the documentation of Open Rewrite Gradle Plugin, for activating recipes we need to explicitly define them in the Plugin's Configuration. As of now I am adding my project's dependency in plugin's configuration. Is there a way so that my Plugin takes the recipes directly from my project for the activation without defining it in Plugin's configuration?

k3code06 avatar Apr 10 '24 11:04 k3code06

@AnkitaJain06, I'm not exactly sure that I understand your question, but I'll take a stab at it.

The OpenRewrite Gradle plugin requires for jars that contain recipes -- and any dependencies that are pulled directly from the runtime classpath for features such as JavaTemplate usages -- to exist within the rewrite configuration. OpenRewrite will scan the classpath of that configuration searching for classes that extend Recipe as well as declarative recipes found in YAML files within META-INF/rewrite/ of the various dependencies. In order to explicitly know which of the multitude of Gradle configurations to scan explicitly, it was decided to create a dedicated classpath for OpenRewrite which also aligns with Gradle best practices. For the purposes of executing recipes, this classpath doesn't extend any of the existing Gradle configurations because we need to not be influenced by project dependencies as well.

For the Gradle plugin, there does not exist a mechanism to scan the Gradle classpath nor other Gradle configurations. To be honest, I don't think it would be a good idea to do so either as there are dozens of configurations in a default java application and scanning them all would result in a significant amount of time and repeat work all to typically result in not finding anything useful.

Actual recipe activation though can be achieved via the Gradle extension configuration activeRecipe(String), but as well can be activated via arguments provided on the command line as seen here in the documentation: https://docs.openrewrite.org/running-recipes/running-rewrite-on-a-gradle-project-without-modifying-the-build#step-4-run-the-recipe

Hopefully this answers the question that I think you are trying to ask, but if it doesn't please let me know.

shanman190 avatar Apr 10 '24 12:04 shanman190

Firstly, in the Maven plugin, it does not require JARs that contain recipes or other dependencies. Can't this be done in the Gradle plugin as well?

Secondly, coming to my scenario, the plugin implementation and all the rewrite recipes are present in the same repository. All the recipes are located at src/META-INF/rewrite/. Is it possible to override the Gradle plugin to activate recipes present in src/META-INF/rewrite/?

In the use case of my plugin, it will be used by multiple services. They do not need to define rewrite configurations and other dependencies.

k3code06 avatar Apr 10 '24 16:04 k3code06

I'll answer the various parts of your reply in the order in which you bring them up.

Both the Maven and Gradle plugins include the core OpenRewrite libraries necessary for parsing, but as doing so also means that those core libraries also contain various core recipes. If you are using core recipes only, then neither plugin requires any additional configuration. However, if you need one of the myriad of expanded scope recipe libraries, such as rewrite-spring, then those have to be included in the Maven plugin's classpath or the rewrite configuration for the Gradle plugin.

On the Maven plugin, there is a feature to allow inclusion of recipe jars by their coordinates which is not a parallel feature that the Gradle plugin supports from a parity standpoint. There isn't anything that strictly prohibits this, but that particular feature just hasn't been implemented.

As far as using recipes from within the plugin itself, neither the Gradle or Maven plugins support this and I don't think that they should. The expectation and recommendation from an OpenRewrite perspective is that recipe jars should be external of the plugins and then included via the available configuration options.

If you want to be including additional default recipe jars, then it should just be customizing the rewrite dependency configurations from your plugin. You shouldn't need to extend the OpenRewrite plugin code at all, but you would apply the plugin preemptively and then customize the configuration or dependencies as desired.

shanman190 avatar Apr 10 '24 17:04 shanman190

In our use case, I am using the Rewrite Gradle plugin in my project. The recipes that need to be added as dependencies of the Rewrite Gradle plugin are present inside a directory in the same project. Is there a way I can couple these recipes with the plugin? Through our plugin, other recipes will use the recipes that are added as resources for the plugin.

k3code06 avatar Apr 14 '24 17:04 k3code06

If you are trying to share a set of recipes across many projects, then those will need to be packaged up into a library jar that can be included in the rewrite Gradle configuration. Most users have opted for this to be an additional jar specific to OpenRewrite migrations for their libraries, such as rewrite-quarkus or rewrite-spring.

If you just need to use a set of recipes on a single repository, then the best way to do that is to use the existing functionality of defining a rewrite.yaml file containing one or more recipes and just have that temporarily at the root of the Gradle project structure. You can then use the -Drewrite.activeRecipe=... to activate a named recipe from within that YAML file. You can see from the documentation how to include additional third party libraries into the rewrite dependency configuration in the provided init.gradle.

shanman190 avatar Apr 14 '24 17:04 shanman190

In our use case, multiple new recipes will be added in the future, leading to continuous updates of the jar. Is there another way we can do this? Can we make use of the directory that contains all the recipes?

k3code06 avatar Apr 14 '24 19:04 k3code06

It sounds like you want to use this across multiple repositories, so a library jar then would be your best path. To handle the dependency management part of it, I'd suggest tracking latest.integration, latest.release, or using something like dependabot/renovate from an open source standpoint. There is also the Moderne SaaS which carries some advantages (precomputed LSTs, mass recipe execution with mass commit/approve/merge workflows, etc) over the open source components.

shanman190 avatar Apr 14 '24 20:04 shanman190

I'm going to close this issue was it's not immediately actionable from our side; There's a few good options and established patterns described above. Using the rewrite-gradle-plugin wrapped in another plugin is not recommended, as also reported here:

  • https://github.com/openrewrite/rewrite-gradle-plugin/issues/323

Hope you're able to use the above patterns to modernize your applications. See this workshop for the steps in setting up your own recipe library.

timtebeek avatar Sep 21 '24 21:09 timtebeek