Skip to content
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

Support for (transitive) dependency management / override #1975

Closed
lefou opened this issue Jul 28, 2022 · 2 comments · Fixed by #3924
Closed

Support for (transitive) dependency management / override #1975

lefou opened this issue Jul 28, 2022 · 2 comments · Fixed by #3924
Milestone

Comments

@lefou
Copy link
Member

lefou commented Jul 28, 2022

Mill currently has no way to influence the transitive version management. Since we already have the CoursierModule.mapDependencies task, this is no issue for projects that build applications. But for libraries projects, controlling of downstream dependency selection might be a useful feature.

Once we add such feature, we need to make sure, that dependency resolution behaves consistent between inner-module and ivy-module dependencies. Also, we want to write this information in pom.xml under <dependencyManagement> as well as into ivy.xml as dependency override section.

Also sbt does not have this features. It allows to force or specify (transitive) dependency versions, which is what we can do with mapDependencies. But it does not support to generate dependencyManagement-sections in pom.xml.

Some links:

@alexarchambault
Copy link
Collaborator

Mill currently has no way to influence the transitive version management.

There's at least two:

  • adding dependencies ensures their version is >= to the added one
  • exclusions

Post-processing dependencies is somewhat harmful: if users publish a module where they post-processed dependencies this way, users of the published module won't benefit from the post-processing (while they do benefit of the two points above, which do end up in the POM).

And coursier/coursier#1390 won't change that: if a project uses it and is published, versions aren't forced the same way for its users (when pulling dependencies that have a BOM, the BOM is only used to fill "holes", that is missing versions in the POM - no version is otherwise forced whatsoever). coursier/coursier#1390 is not a way to share forced dependencies for library authors / users, unless users explicitly add the BOM to their project (and if all libraries each supply their own BOM, it's likely some might conflict…)

@lefou
Copy link
Member Author

lefou commented Oct 26, 2022

Thanks for your comment, @alexarchambault.

Mill currently has no way to influence the transitive version management.

There's at least two:

* adding dependencies ensures their version is >= to the added one

* exclusions

Adding dependencies has the downside, that you misuse the mechanism, as you most likely list dependencies which are only transitively needed. There is a high risk those entries run out of date. The reasons may vary, but will be most likely that the upstream dependencies have changed. There is also the somewhat smaller risk to produce incompatibilities combinations.

The dependencyManagement as known from Maven isn't affected by this issue. It will only take control for dependency which are actually part of the (direct and transitive) dependency set.

Exclusions on the other side, are already propagated to the exported pom.xml in current Mill.

Post-processing dependencies is somewhat harmful: if users publish a module where they post-processed dependencies this way, users of the published module won't benefit from the post-processing (while they do benefit of the two points above, which do end up in the POM).

This is essentially the motivation for this very issue and also coursier/coursier#1390. We need a dedicated way to manage dependencies that transcends into package management like Maven (pom.xml) or Ivy.

And coursier/coursier#1390 won't change that: if a project uses it and is published, versions aren't forced the same way for its users (when pulling dependencies that have a BOM, the BOM is only used to fill "holes", that is missing versions in the POM - no version is otherwise forced whatsoever). coursier/coursier#1390 is not a way to share forced dependencies for library authors / users, unless users explicitly add the BOM to their project (and if all libraries each supply their own BOM, it's likely some might conflict…)

I think there is probably a still too vague understanding of the details of coursier/coursier#1390. I envision in it exactly that: a way to let coursier know, that I want to add some dependencies to my current dependencyManagement section. And of course, I want to add those dependencies either directly or by importing an external BOM dependency. The effect should be the same: I can better control what dependencies and versions should be used or excluded. And this management is also effective to downstream users, as we export it as part of the pom.xml.

@lihaoyi lihaoyi closed this as completed in 60e6ce2 Dec 5, 2024
@lefou lefou added this to the 0.12.4 milestone Dec 5, 2024
jodersky pushed a commit to jodersky/mill that referenced this issue Jan 14, 2025
This PR adds support for user-specified BOMs and dependency management
in Mill.

BOM support allows users to pass the coordinates of an existing Maven
"Bill of Material" (BOM), such as [this
one](https://repo1.maven.org/maven2/io/quarkus/quarkus-bom/3.17.0/quarkus-bom-3.17.0.pom),
that contains versions of dependencies, meant to override those pulled
during dependency resolution. (They can also add exclusions to
dependencies.)
```scala
def bomDeps = Agg(
  ivy"io.quarkus:quarkus-bom:3.17.0"
)
```

It also allows users to specify the coordinates of a parent POM, which
are taken into account just like a BOM:
```scala
def parentDep = ivy"org.apache.spark::spark-parent:3.5.3"
```
(in line with `PublishModule#pomParentProject` that's been added
recently)

It allows users to specify "dependency management", which act like the
dependencies listed in a BOM: versions in dependency management override
those pulled transitively during dependency resolution, and exclusions
in its dependencies are added to the same dependencies during dependency
resolution.
```scala
def dependencyManagement = Agg(
  ivy"com.google.protobuf:protobuf-java:4.28.3",
  ivy"org.java-websocket:Java-WebSocket:_" // placeholder version - this one only adds exclusions, no version override
        .exclude(("org.slf4j", "slf4j-api"))
)
```

BOM and dependency management also allow for "placeholder" versions:
users can use `_` as version in their `ivyDeps`, and the version of that
dependency will be picked either in dependency management or in BOMs:
```scala
def bomDeps = Agg(
  ivy"com.google.cloud:libraries-bom:26.50.0"
)
def ivyDeps = Agg(
  ivy"com.google.protobuf:protobuf-java:_"
)
```

A tricky aspect of that PR is that details about BOMs and dependency
management have to be passed around via several paths:
- in the current module: BOMs and dependency management have to be taken
into account during dependency resolution of the module they're added to
- via `moduleDeps`: BOMs and dependency management of module
dependencies have to be applied to the dependencies of the module they
come from
- ~to transitive modules pulled via `moduleDeps`: BOMs and dependency
management of a module dependency have to be applied to the dependencies
of modules they pull transitively (if A depends on B and B depends on C,
from A, the BOMs and dep mgmt of B apply to C's dependencies too)~
(worked out-of-the-box with the previous point, via `transitiveIvyDeps`)
- via `ivy.xml`: when publishing to Ivy repositories (like during
`pubishLocal`), BOMs and dep mgmt details need to be written in the
`ivy.xml` file, so that they're taken into account when resolving that
module from the Ivy repo
- via POM files: when publishing to Maven repositories, BOMs and dep
mgmt details need to be written to POMs, so that they're taken into
account when resolving that module from the Maven repo


Fixes com-lihaoyi#1975
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants