[2.x] feat: Add dependencyMode setting to control classpath transitivity#8960
[2.x] feat: Add dependencyMode setting to control classpath transitivity#8960eed3si9n merged 3 commits intosbt:developfrom
Conversation
eed3si9n
left a comment
There was a problem hiding this comment.
Some minor refactoring comments, but overall looking great!
**Problem** sbt always includes all transitive dependencies on the classpath. This makes it easy to accidentally depend on transitive dependencies without declaring them, leading to fragile builds that break when a library changes its own dependencies. **Solution** Add a `dependencyMode` setting with three modes: - `DependencyMode.Transitive` (default) — current behavior, all transitive dependencies on the classpath - `DependencyMode.Direct` — only declared dependencies plus scala-library on the classpath - `DependencyMode.PlusOne` — declared dependencies plus their immediate transitive dependencies plus scala-library The filtering is done at the `managedClasspath` level using `Def.taskDyn` so that `allDependencies` and `updateFull` are only evaluated when the mode is not `Transitive`, avoiding any overhead for the default case. Fixes sbt#8942
- Move DependencyMode enum to sbt.librarymanagement package (lm-core) so filtering logic can eventually move there too - Add DependencyMode type/val to Import.scala for build file access - Move private filter implementations (filterByDirectDeps, filterByPlusOne, isScalaLibraryModule, matchesDirectDep, directDepIndex) from Classpaths object to ClasspathImpl object - Clean up ScalaArtifacts import and remove redundant test task
03485c0 to
f9b8501
Compare
Adding DependencyMode type/val to the Import trait introduces new abstract members, which is a binary-incompatible change. Add exclusion filters for the two ReversedMissingMethodProblem entries.
cb72bf3 to
05e982e
Compare
|
@eed3si9n The review feedback has been addressed:
Regarding the remaining CI failure ( |
eed3si9n
left a comment
There was a problem hiding this comment.
Thanks for the contribution!
|
Wow, thank you @eureka928! I will test and report back as soon as an artifact is available. From my understanding
should also be fine for us non-Scala users, because the mechanism in question does not actively add the dep, but simply does not filter it out. So if we have configured the build to not use Scala to start with as before, this will not break anything, I think. :-) |
…ity (sbt#8960) **Problem** sbt always includes all transitive dependencies on the classpath. This makes it easy to accidentally depend on transitive dependencies without declaring them, leading to fragile builds that break when a library changes its own dependencies. **Solution** Add a `dependencyMode` setting with three modes: - DependencyMode.Transitive (default) — current behavior, all transitive dependencies on the classpath - DependencyMode.Direct — only declared dependencies plus scala-library on the classpath - DependencyMode.PlusOne — declared dependencies plus their immediate transitive dependencies plus scala-library Fixes sbt#8942
…ivity (#8960) (#8972) **Problem** sbt always includes all transitive dependencies on the classpath. This makes it easy to accidentally depend on transitive dependencies without declaring them, leading to fragile builds that break when a library changes its own dependencies. **Solution** Add a `dependencyMode` setting with three modes: - DependencyMode.Transitive (default) — current behavior, all transitive dependencies on the classpath - DependencyMode.Direct — only declared dependencies plus scala-library on the classpath - DependencyMode.PlusOne — declared dependencies plus their immediate transitive dependencies plus scala-library Fixes #8942 Co-authored-by: Dream <[email protected]>
|
I tried this with a very simple project and everything works fine on the CLI. But it seems that any action in IntelliJ, like "build" or "test", fails with Reproduction: https://codeberg.org/soc/base-uid/src/branch/dep-direct |
|
Thanks for testing. You can get past the initial error if you use |
Summary
Implements the
dependencyModesetting proposed in #8942, adding explicit dependency tracking similar to Bazel's rules_scala dependency tracking and sbt-explicit-dependencies.DependencyMode.Transitive(default) — all transitive dependencies on the classpath (current behavior, zero overhead)DependencyMode.Direct— only declaredlibraryDependenciesplusscala-libraryDependencyMode.PlusOne— declared dependencies plus their immediate transitive dependencies plusscala-libraryUsage
Design decisions
managedClasspathlevel, not resolution level —updatestill resolves the full transitive graph.dependencyTree, eviction checks, and caching are unaffected.Def.taskDynto avoid evaluatingallDependencies/updateFullwhen mode isTransitive— zero overhead for the default case.cats-core(fromlibraryDependencies) against resolvedcats-core_3on the classpath.scala-libraryalways included regardless of mode, since the Scala standard library is a runtime requirement.Files changed
main/src/main/scala/sbt/DependencyMode.scala— New Scala 3 enummain/src/main/scala/sbt/Keys.scala—dependencyModesetting keymain/src/main/scala/sbt/Defaults.scala— Default value,managedClasspathfiltering logic, helper methods inClasspathssbt-app/src/sbt-test/dependency-management/dependency-mode/— Scripted integration testTest plan
cats-core/cats-kernel) and Java (guava/failureaccess) dependenciesDirectmode applies to bothCompileandTestconfigurationsTransitivemode preserves existing behaviorpublishLocalBin+ real projectsFixes #8942