Skip to content

Pass arguments from the command line into a single configurable recipe #799

@commonquail

Description

@commonquail

We can already run OpenRewrite via the Maven plugin without modifying files up front:

mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \
  -Drewrite.activeRecipes=org.openrewrite.java.RemoveUnusedImports

but sadly only for recipes that require no configuration. Recipes that do require configuration have no (canonical) inline invocation form, instead necessitating the creation of a verbose and complex file merely to communicate what is often trivial information to the recipe, and then you even still need the rewrite.activeRecipes user property from the example. This severely limits the practical utility of OpenRewrite. Instead of being a hypothetical arbitrary rename-refactor the tool is only really interesting for completely static transformations, or for dynamic transformations that are particularly complex or that have to run in batch mode.

What problem are you trying to solve?

Consider a trivial recipe with a structure comparable to

---
type: specs.openrewrite.org/v1beta/recipe
name: com.yourorg.ChangePackageExample
displayName: Rename package name example
recipeList:
  - org.openrewrite.java.ChangePackage:
      oldPackageName: com.yourorg.foo
      newPackageName: com.yourorg.bar

Suppose this needs to be run by many different individuals for different values of oldPackageName or newPackageName. For <reasons> we can distribute instructions for defining and executing a recipe but distributing a recipe itself is impractical; say, for example, that we cannot know literally every variation of package names, or that the old package name can exist in multiple artifacts and should be turned into numerous divergent package names.

The YAML configuration file works well with distribution when distribution is already a solved problem, but distribution is a difficult problem to solve and cumbersome even when already solved. It requires a distribution channel, which you may not already have, and if you do have one, using it may necessitate a disproportionate amount of bureaucracy namely if you're subject to auditing regulations. Even if distribution is feasible, some recipes are impossible to distribute in practice, like the examples from the previous paragraph.

But I don't see why we couldn't "just" pass the package names as user properties like we can with rewrite.activeRecipes.

Describe the solution you'd like

Imagine I could run something like

mvn -U org.openrewrite.maven:rewrite-maven-plugin:run \
  -Drewrite.activeRecipes=org.openrewrite.java.ChangePackage \
  -Drewrite.ChangePackage.oldPackageName=com.yourorg.foo \
  -Drewrite.ChangePackage.newPackageName=com.yourorg.bar

Generalizing, -Drewrite.RecipeSimpleName.optionName=value.

This is a command I can email blast to lots of individuals, each of whom can easily adjust the invocation as necessary with no further effort.

The pattern I propose means you can run each distinct recipe only once per invocation but is acceptable to me. Repeating the command for variations in configuration option values is trivial, and if you need to do that a lot you're probably in a situation where the overhead of the configuration file approach is amortized anyway. An n-ary invocation form is theoretically possible, it just doesn't seem worth the implementation complexity or the impact to invocation complexity.

I don't care about the exact format of the user property. It only needs to be reasonably resistant to collision and should feature the option name verbatim for clarity.

Have you considered any alternatives or workarounds?

On multiple occasions I've discounted OpenRewrite in favour of low level tools like sed and mv and Python on account of this limitation. I've thought about making tools to generate specialized OpenRewrite configuration files but that has not been worth the effort so far.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions