openrewrite / rewrite

Automated mass refactoring of source code.
https://docs.openrewrite.org
Apache License 2.0
2.19k stars 329 forks source link

Maven: Allow version exclusions for all Upgrade*Version recipes #4127

Closed smurf667 closed 5 months ago

smurf667 commented 6 months ago

What problem are you trying to solve?

In my company we operate an internal Maven repository which sometimes contains "weird" versions of artifacts (this is probably not limited to the internal registry...). For example, completely ignoring the Maven version formats, sometimes a version has a hashcode, like "9abcdef". This might be considered a very high version number during upgrading, higher than "normal" ones like "1.0.1" or "3.2.1".

As far as I can tell, all the Upgrade*Version recipes pull the version information from Maven metadata and then try to use the "newest". Above situation - which I cannot influence - inadvertently leads to a bogus update, not the latest version, but some "junky" one.

The Maven versions plugin supports a "rule set": https://www.mojohaus.org/versions/versions-model/rule.html This way, it is possible to ignore certain versions.

Describe the solution you'd like

Ideally, all Upgrade*Version recipes offered a way to specify which versions should not be considered as acceptable update values. Maybe they all could accept a similar input to the above described Maven versions ruleset? For example, a property ignorableVersions of type String[] containing regular expressions to match ignorable versions could be introduced.

Example use:

---
type: specs.openrewrite.org/v1beta/recipe
name: com.yourorg.UpgradePluginVersionExample
displayName: Upgrade Maven plugin version example
recipeList:
  - org.openrewrite.maven.UpgradePluginVersion:
      groupId: org.openrewrite.maven
      artifactId: rewrite-maven-plugin
      ignorableVersions:
        - "9abcdef"
        - ".*[aA][lL][pP][hH][aA].*"

This could be applied before considering the list of available versions (see for example https://github.com/openrewrite/rewrite/blob/main/rewrite-maven/src/main/java/org/openrewrite/maven/UpgradePluginVersion.java#L160 of UpgradePluginVersion).

Have you considered any alternatives or workarounds?

I considered checking the update result after running the recipe and discarding "bad" updates, however this would mean that for anything where the update is bad, this dependency would never be updated, which is not what I am looking for.

Additional context

I've looked at the backlog, but did not find anything similar. Apologies if this is a duplicate.

Are you interested in contributing this feature to OpenRewrite?

I am unsure about the code base, and if and how you would implement the feature I describe. I could assist with code or reviews, but I have only limited time available.

timtebeek commented 5 months ago

Hi @smurf667 ; sounds like a quite unfortunate setup you have there that limits your ability to upgrade with automated recipes.

Rather than expand multiple recipes with additional options I'd like to try to limit any changes done to accommodate this to the version patterns we have and use. While I haven't yet explored the specifics as they relate to your situation, we do have a number of selector options that allow you define patterns or ranges any new version should conform to. Perhaps that would already allow you to limit upgrades to regular versions as opposed to the more exotic version qualifiers also in use there.

Do you see any further options within the above constraints to make this fit your use case? You'll know better what all you're working with internally. Alternatively one could set up a filtered virtual Maven repository only containing regular versions and proxy that when running recipe upgrades.

smurf667 commented 5 months ago

Thanks, let me see if I can prevent unwanted versions using the version patterns you suggest - I wish all dependency were following the <major>.<minor>.<patch>, but this is likely not the case.

It would be conceivable to use a proxy for the repository and filter out unwanted versions there, too, but that is also not without complexity.

I see your point about the potential need to expand multiple recipes with additional options. Let me experiment (may take some time) and update this issue later. Thanks!

smurf667 commented 5 months ago

I've prototyped a solution where a proxy filters out unwanted versions, as you suggested. This reads the already existing "rule set" of the Maven Versions plugin and strips all unwanted versions from the metadata file, letting all other Maven files pass through. Complex, but working.

Feel free to close this, though I still think an option to explicitly "ban" certain versions would be helpful for the recipes. Thanks!

timtebeek commented 5 months ago

Glad to hear you were able to get something working based on the suggestions above, and thanks for coming back here to report the your workaround.

I'll close this issue for now then, but we can revisit this if it becomes a common request in the future.