Skip to content

Add AddPlatformDependency recipe. #5371

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

Merged
merged 21 commits into from
Jun 9, 2025

Conversation

BrendanHart
Copy link
Contributor

@BrendanHart BrendanHart commented May 3, 2025

What's changed?

Add recipe to support adding platform/enforcedPlatform dependencies to Gradle build files.

What's your motivation?

Anything in particular you'd like reviewers to focus on?

Anyone you would like to review specifically?

Have you considered any alternatives or workarounds?

Any additional context

Checklist

  • I've added unit tests to cover both positive and negative cases
  • I've read and applied the recipe conventions and best practices
  • I've used the IntelliJ IDEA auto-formatter on affected files

@BrendanHart
Copy link
Contributor Author

BrendanHart commented May 3, 2025

Currently decided to not include "onlyIfUsing" in this recipe, mostly as unsure if it should be explicit if it would be best for users to be explicit in where they want to add a platform dependency? Would appreciate any thoughts, @timtebeek / @shanman190!

@timtebeek timtebeek added the recipe Requested Recipe label May 3, 2025
@shanman190
Copy link
Contributor

So having only read your comment here about onlyIfUsing, in a multi module project, what would be the pattern for only adding the platform dependency to only some of the modules?

Maybe if we go ahead and include something like a ProjectUsesType recipe that was project aware and could be utilized as a project-level precondition? That would mean that the onlyIfUsing pattern could safely be soft deprecated like we did with filePatterns on other recipes.

@BrendanHart
Copy link
Contributor Author

Maybe there's the option of using the dependencies also to work out whether to add a platform dependency? E.g. if a module is using any dependencies matching a group org.springframework* then add the spring-boot-dependencies platform dependency.

Sorry, could you help me understand more on your second point, not sure I followed. Would that be for refactoring out the onlyIfUsing logic into something common that can be used across multiple recipes?

@shanman190
Copy link
Contributor

The short answer is that preconditions are a much more powerful and expressive way to capture these types of extra conditioning (types in use, acceptable file patterns, etc).

With preconditions we can build all kinds of acceptance rules and combine them together arbitrarily in declarative recipes, including using DependencyInsight in the manner that you described for other Spring Boot dependencies being present. There are a ton of possible reasons that you may want to use a condition around when to add a dependency and by having the flexibility of preconditions it means that each of those different "reasons" can be utilized arbitrarily as a recipe author is building out their recipe(s).

@BrendanHart
Copy link
Contributor Author

Thanks for elaborating! Is the suggestion then that these recipes don't require such restrictions built in and we can assume them to be handled in the precondition recipes, and embedding logic into the recipe to restrict to specific modules isn't required?

@shanman190
Copy link
Contributor

That's kinda what I was thinking.

I'd probably go one step further to go ahead and create the precondition recipe (not 100% on the name of it though) while we're here thinking about it, but that's not strictly required. WDYT, @timtebeek ?

@timtebeek
Copy link
Member

Do you mean to create a recipe to check if a GradleProject is using any dependency managed by a BOM? And then to add that as a precondition check on the AddPlatformDependency recipe? would be ideal, I think, to make something like this just work out of the box:

@Test
void twoProjects() {
    rewriteRun(
      spec -> spec.recipe(new AddPlatformDependency(
        "org.springframework.boot", "spring-boot-dependencies", "3.2.4", null, null, null)),
      mavenProject("projectA",
        buildGradle(
          """
            plugins {
                id "java-library"
            }
            repositories {
                mavenCentral()
            }
            dependencies {
                testImplementation "org.springframework:spring-core:6.1.5"
            }
            """,
          """
            plugins {
                id "java-library"
            }
            repositories {
                mavenCentral()
            }
            dependencies {
                testImplementation platform("org.springframework.boot:spring-boot-dependencies:3.2.4")
                testImplementation "org.springframework:spring-core"
            }
            """
        )
      ),
      mavenProject("projectB",
        buildGradle(
          """
            plugins {
                id "java-library"
            }
            repositories {
                mavenCentral()
            }
            """
          // No change, as we're not using any dependencies managed in the platform bom added
        )
      )
    );
}

@shanman190
Copy link
Contributor

So I was more thinking of:

  • AddPlatformDependency adds unconditionally
  • Create secondary recipes for the various conditioning requirements (ie: only if using, has managed dependency, etc) to be used as preconditions on a declarative recipe (or composite programmatic recipe).

I do like the idea of scheduling a RemoveRedundantDependencyVersions recipe execute as an after visit though.

@shanman190
Copy link
Contributor

shanman190 commented May 6, 2025

Just a FYI, I have an idea that I'd like to play with locally for a day or two that would change the need for the GradleConfigurationNames over to a Trait implementation for the specific feature that it's trying to cover. I've got the JvmTestSuite trait working locally, but am presently trying to adapt it to be able to have an addDependency helper function to completely centralize the configuration name editing in addition to the trait's overall simplification and accuracy around Gradle JvmTestSuite usage and identification.

@BrendanHart BrendanHart marked this pull request as ready for review May 11, 2025 21:35
@BrendanHart
Copy link
Contributor Author

BrendanHart commented May 11, 2025

Added more test cases and made the changes mentioned. Marked PR as ready but of course pending any changes you wish to make regarding the configuration names as already mentioned 😄

One thing I'm not sure about is how useful the "inferred" configuration would be, rather than using an explicit configuration from the recipe parameters. Let me know if it should be mandatory to specify the configuration for platform dependencies instead of having such logic as well!

github-actions[bot]

This comment was marked as off-topic.

github-actions[bot]

This comment was marked as off-topic.

github-actions[bot]

This comment was marked as off-topic.

@timtebeek timtebeek moved this from In Progress to Ready to Review in OpenRewrite May 19, 2025
@jevanlingen
Copy link
Contributor

jevanlingen commented May 27, 2025

Just did a review on your code, nice contribution @BrendanHart! I like the introduction of the GradleConfigurationFilter class.

I was wondering though, does it make sense to introduce an abstract class above the AddPlatformDependency and AddDependency recipes? There is a lot of duplicated code there going on in the visitor part. Another option would be to create a separate Dependency visitor class with an "isPlatform" flag or something. What do you think? Also notice Tim's comment in the original issue:

Sharing code with the visitor as described above is of course possible and preferred here. Thanks both! - Tim

@shanman190
Copy link
Contributor

I've still got this @jevanlingen . I've got a JvmTestSuite trait that I just need to fix 2 more test cases for, then it should land here.

@BrendanHart
Copy link
Contributor Author

Thanks for the review @jevanlingen ! Will await @shanman190 's changes and any further comments I can address.

@shanman190
Copy link
Contributor

shanman190 commented Jun 5, 2025

@BrendanHart, @jevanlingen, and @timtebeek, apologies for the delay on this, but I've pushed the new JvmTestSuite trait. I was able to run tests successfully pre merge from main, but then began to have issues with recent Gradle marker/model changes. I'm hopeful that CI doesn't produce any new errors, but let me know what you all think.

As part of this, you'll also notice that we can also now add a dependencies block where one was missing within a JvmTestSuite as well. So that'll be handy also.

shanman190 and others added 2 commits June 4, 2025 20:57
…estSuiteTest.java

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@shanman190 shanman190 force-pushed the add-platform-dependency-recipe branch from 4aab4b3 to ce270c1 Compare June 5, 2025 03:26
@sambsnyd sambsnyd merged commit 8f6d1b5 into openrewrite:main Jun 9, 2025
2 checks passed
@github-project-automation github-project-automation bot moved this from Ready to Review to Done in OpenRewrite Jun 9, 2025
JohannisK pushed a commit that referenced this pull request Jun 10, 2025
* Add AddPlatformDependency recipe.

* Apply suggestions from code review

Co-authored-by: Shannon Pamperl <[email protected]>

* Refactor common logic from AddDependency and AddPlatformDependency.

* Rename class and add header.

* Add header.

* Update rewrite-gradle/src/main/java/org/openrewrite/gradle/GradleConfigurationFilter.java

Co-authored-by: Tim te Beek <[email protected]>

* Make util classes package private. Add test cases.

* Correct test config.

* Cleanup

* Introduce JvmTestSuite trait

* Add missing license header

* Update rewrite-gradle/src/test/java/org/openrewrite/gradle/trait/JvmTestSuiteTest.java

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Remove some now obsolete code

* Fix broken tests

* Add error to first element being visited

* Remove unused method

---------

Co-authored-by: Shannon Pamperl <[email protected]>
Co-authored-by: Tim te Beek <[email protected]>
Co-authored-by: Tim te Beek <[email protected]>
Co-authored-by: lingenj <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
recipe Requested Recipe
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Support adding platform dependencies to Gradle project
5 participants