-
Notifications
You must be signed in to change notification settings - Fork 20
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
Toml dependencies #4
Comments
+1 here Would be great to update project. I can try to contribute if you think it makes sense |
Here are my thoughts on the Version Catalog. Took a bit longer, because I still do not have enough experience with it myself to express this in a more compact way. First, some context to relate Catalogs to other Gradle features:
With this in mind, here are the things thatI like and dislike about the Catalog approach. This are just my thoughts and maybe non of them are strong pro or con arguments. IMO, there are two aspects to look at separately (1) GA coordinates of a Component (2) Version of a component. GA coordinates and aliasses (pro) Tool support when accessing entries from the catalog in build scripts (code completion, only allow entries that exist). This is certainly a 'pro', although you can debate if certain tooling should be offered by the IDE directly. E.g. allowing code completion directly for coordinates from Maven Central. I think IDEA already does that for pom.xml files. (pro or con) Aliases that add another indirection. This can be a pro, if you use a dependency in many places. So you can have a short alias for long things like (pro or con) TOML file. It's a pro for those who already managed versions in Versions What I love about Gradle's dependency constraints is that it makes this nice separation of the actual Component (addressed by GA coordinates) and its version. I think this makes a lot of things clearer and also easier to understand. So I like to see dependency declarations that do not include a version number. And define the whole structure of my software project in terms of dependency definitions between components. Without thinking about versions at all. Here is an example of what I mean from my gradle-project-setup-howto project: A component's builld.gradle.kts
The platform for version management
I also like to use BOMs when they exist for aligning versions of multi-component libraries (see link to full example above) and not define a version for the single components at all. I am sorry 😄 , but I just love 😍 how clean and direct this is. I just feels right to me. I love it. The Catalog breaks this again and thus feels like a step backwards to me. Now you again define the GAV together and then add - through the alias - the version to each build script directly. You also can't use BOMs that directly anymore. Of course you can also have BOMs in the catalog, but you don't have your own platform to wrap them nicely into one. You can do it in the catalog via bundles. But it feels a bit off to me that there is this new concept "bundle" - it somehow feels like half re-inventing the wheel. Another thing I am unsure about is how the catalog works together with convention plugins, or is shared when you split your build into multiple included builds. With a platform, it's all so clear because the platform is a component itself that you can depend on everywhere where your need it with Gradle's dependency management. For the catalog, you have to reuse a plain TOML file in several places. It just feels more rough (and thus again like going backwards) to me. (But again maybe it is more a theoretical problem than a practical one.) That's why my current conclusion is that it depends (on many things) if you should use the catalog or not. You may notice, that I have trouble placing the Catalog in the overall Gradle "Model". With other concepts it's much clearer to me why they are there and where Gradle is heading with them. The catalog feels more like a "nice thing on top" that you may or may not use and which is also not connected to anything else. This is a lot of text. I was not able to express this in a more compact way. 🤷 Hope it helps anyway. @gildor PRs are always welcome. And if only to discuss. I think in this project, introducing the catalog can make sense. Especially because it has the ExternalLibrariesExtension right now. Which is like a self-built catalog for only GA coordinates - adding only the alias/code-completion part without breaking the GA vs Version separation. I am not sure if I would have added that if I would do this project today (I would probably just have used the coordinates directly everywhere as in the sample further up). |
As the (main) author of version catalogs, I'd like to add more on the topic. First of all, I have deep experience on using them, since I have designed them, but also used them in many projects. There are intensively used at scale in the Micronaut projects, where they allow us a number of things:
I didn't have to figure out the dependencies, I just had to import the Micronaut catalog and there you go. The build scripts are so much cleaner. It also removes a lot of duplication, with many dependency strings replaced with a single, reusable identifier (the alias). Note that in Micronaut, we're using single version dependencies, that is to say the traditional "require" statement. We don't use richer versions (yet) because it's hard to make it work for both Gradle and Maven consumers. That said, our update mechanism supports them too. The other important part is that a catalog is not a platform, as I tried to describe in the docs. A catalog is, as the name implies, a list of libraries you can pick from, but they have no influence on the dependency graph. This is intentional, and for a framework like Micronaut it makes a lot of sense: there are many dependencies you may add to your graph, and if you want to add them, you have them at hand. Because we also publish a BOM, you get the best of the 2 worlds: something which can influence the dependency graph and single place where to define versions. Last but not least, catalogs do not "pollute" publishing by having a dependency on a platform, which, often, is not what you want. It may be the case, but in general, I am tempted to say it's not. Moreoever there are thousand places where you can define the platform (submodule, buildSrc, included builds) vs single place for the catalog. But, again, you should probably have both. Last but not least, catalogs are easy. They are easy to:
|
Thank you for the addition detailed thoughts Cédric. My conclusion on this, for now, is that it depends on what you are building and how your overall dependency management setup for that is. For this example, I have now added two commits on separate branches that show how to use the Version Catalog instead of the original setup. It‘s linked/documented in the Readme: https://github.com/jjohannes/idiomatic-gradle#summer-2022-update-gradle-751 |
@jjohannes I think it would be beneficial to swap out the default with version catalog and leave the custom (more advanced) versioning scheme as a branch, because people are referencing this repository and they're seeing that Version Catalogs are not idiomatic. |
Having a custom extension with constants for the GA coordinates (which was the state on I changed the repo structure so that the catalog is now used on the There are these alternative branches which might be preferable depending on how you want to do version management in your project (see all the discussions above):
This is also documented in the Readme. |
Something I am still wondering about is how to best share the Catalog in a multi-build (composite build) setup like this. This works:
But it needs to be in quite some places. Maybe sharing the Catalog through dependency management (as you do for the platform) would be cleaner. And then you can seamlessly switch between a in-repository and published catalog (similar as for the platform). This does not work without flaws as the catalog is required early in the build configuration. But you can work around this as we discussed here: gradle/gradle#19288 (comment) |
But sharing it through dependency management does not solve the issue of repeating the dependencyResolutionManagement block in every project that uses it, right? It just changes it from referencing a file to a GAV instead:
I tried to solve this in my composite build by using a settings plugin, but then came across the issue (I suspect) that settings plugins don't quite work in a composite build. So even if the settings plugin resides in a project that is part of the composite build, it will not resolve the settings plugin unless I explicitly include the build in each project that uses the version catalog with this construct:
But then I can no longer build the project independently. |
Catalog Sharing I think being able to refer to the catalog by coordinates is exactly the advantage. Because these are always the same and you do not need to use a relative path that might not work anymore if you move something around. This is what I would do: ed0545b Settings Plugins (imo it's not directly related)
Not sure what you mean. They work as intended (since Gradle 7.x). It's true that you need to explicitly include the settings plugin in each build. That's by design. So that each build also works individually. (And also because technically it's hard to solve the ordering - settings plugin needs to be found first.) But then the settings plugin can be the only build you include and the only plugin you apply in all of your builds. Everything else can be controlled starting from there. It's done in this repo if you look at the builds in the |
Yes, I see now what you mean.
My comment was based on my expectation that gradle would find the settings plugin if it was part of the same composite build, not necessarily included from the same project that applies the plugin. So that I can have a project A that does not include any other build that uses the settings plugin resolved from my maven repository. But also be able to create a separate composite build B that includes both project A and the project containing the settings plugin, in which case the plugin would be resolved from the composite build. This works for build plugins (and of course regular dependencies) but not for settings plugins. But I guess this is not possible. And in any case it is not related to this issue. |
Hello,
Just wanted to ask what is your stance on toml dependencies and if you have considered using them in your project as an idiomatic way of describing them?
Kind regards,
Hristo
The text was updated successfully, but these errors were encountered: