spring-gradle-plugins / dependency-management-plugin

A Gradle plugin that provides Maven-like dependency management functionality
696 stars 87 forks source link

Provide convention based fallback method that can be used by spring-boot-gradle-plugin #398

Open ryanflegel opened 3 weeks ago

ryanflegel commented 3 weeks ago

I am using dependency-management-plugin to manage dependencies and it works great, but spring-boot-gradle-plugin doesn't play nice with it, due to spring-boot-gradle-plugin/DependencyManagementPluginAction importing Spring Boot's Maven BOM.

This behaviour overrides the order of my BOM imports by re-importing Boot's BOM when the 'org.springframework.boot' plugin is applied. This means the dependency-management plugin does not work as described here:

4.2.1. Importing Multiple Boms If you import more than one bom, the order in which the boms are imported can be important. The boms are processed in the order in which they are imported. If multiple boms provide dependency management for the same dependency, the dependency management from the last bom will be used.

Instead, I would need to break up my dependencyManagement.imports{} block and apply the Gradle plugin in between in order to get my desired import order. However, this isn't really feasible for me, since I am actually publishing a platform BOM (not a Gradle platform BOM) that includes Spring Boot, among other things.

So, what's happening is that I am ordering the import of Maven BOMs in my platform BOM so that I have the correct final dependencies, but the Gradle projects that use my BOM and are applying the 'org.springframework.boot' plugin after configuring their dependencyManagement{} block have dependencies messed up because the Spring Boot BOM is re-applied.

The only way I can find to work around this is to add workarounds in every service project that depend on the BOM. The order of the imports and plugin application would have to change, but that's actually pretty complicated because it's a multiproject build with dependencyManagement{} being configured in the root project with subprojects{}. Another way is to use ext properties to override/configure the versions in the Spring Boot BOM, but that defeats the purpose of using a platform BOM if each project needs to start managing each dependency version.

I think the fix would be to delete DependencyManagementPluginAction. Especially now that SpringBootPlugin.BOM_COORDINATES is available, I'm not sure why the plugin would need to add the import?

Not sure how desirable that would be, but I can't seem to find a nice way to work around the behaviour. If there was a workaround I could apply in my BOM project I would do that, even if it was ugly, but I can't see a way to do that.

wilkinsona commented 3 weeks ago

I think the fix would be to delete DependencyManagementPluginAction.

Unfortunately, this would be a breaking change and would be quite disruptive as many Gradle projects will be relying on the current behavior. If we're to do anything here, I think we'd have to provide a way of opting out rather than removing the behavior entirely.

Especially now that SpringBootPlugin.BOM_COORDINATES is available, I'm not sure why the plugin would need to add the import?

The constant's primarily for those who aren't using the dependency management plugin and want to use Gradle's platform support instead.

Another way is to use ext properties to override/configure the versions in the Spring Boot BOM, but that defeats the purpose of using a platform BOM if each project needs to start managing each dependency version.

Have you considered writing your own plugin that both configures the necessary ext properties and imports your platform bom? Each service project could then obtain the desired behavior with a single plugin declaration.

ryanflegel commented 3 weeks ago

Thanks for the quick response! It's not the one I was hoping for, but it is what I was expecting.

And sorry, I just realized that I created this issue in the dependency-management-plugin repo instead of the spring-boot repo! Too many GitHub tabs open.

I will consider the plugin idea, thanks. We're also considering migrating to Gradle platforms, but that's a big change and has some annoyances as well.

I'm not sure if this would be desirable either, but another potential option that would be "less" breaking could be to only import the BOM if it has not been imported yet. This would still be breaking in the sense that the ordering would change depending on where the Boot plugin is applied. I think this would solve my specific issue, at least.

In any case, I think we need to work out something for ourselves since we're behind on Spring Boot -- we actually ran into this while preparing for upgrade to Boot 3 -- so any fix would only be to help us out for next time we run into the issue.

wilkinsona commented 3 weeks ago

And sorry, I just realized that I created this issue in the dependency-management-plugin repo instead of the spring-boot repo! Too many GitHub tabs open.

No problem at all. I don't think I'd noticed and had thought it was in the spring-boot repo when I replied above. I'm going to close this one as, unfortunately, issues can't be transferred across orgs. If you'd like to see some more control being provided on the Spring Boot side, please open an issue over there.

philwebb commented 1 week ago

Having looked at the Spring Boot issue, we've decided to reopen this one to see if we can provide an update to the DSL for Spring Boot to use. The idea would be for Spring Boot to register items to be used only if the user hasn't already included them.

ryanflegel commented 1 week ago

Thanks for looking into the issue!

What are you thinking for implementation? I think that making the registered BOMs available so that other plugins can see what's already been imported would be sufficient. I think this would solve my problem in the Boot plugin.