**Problem**
In an Ivy resolver pattern, the [organisation]/[organization] token has its dots rewritten to slashes (org.example → org/example), behaving like Ivy's [orgPath] token rather than being literal. Per the [Apache Ivy spec](http://ant.apache.org/ivy/history/latest-milestone/concept.html), [organisation] should be substituted literally and [orgPath] is the slash-separated form.
Root cause: Patterns.isMavenCompatible defaulted to true, which sbt forwards to Apache Ivy as setM2compatible(true); with m2-compatibility on, Ivy rewrites the [organisation] token to slash form. A user supplying a custom Ivy pattern (e.g. for an SFTP/SSH resolver) inherited that default and got the wrong paths, with no obvious indication why. The only workaround was the non-obvious withIsMavenCompatible(false).
**Solution**
Flip the default of Patterns.isMavenCompatible from true to false, so a hand-written Patterns keeps [organisation] literal by default — matching the Ivy spec.
**Problem**
Platform suffix is absent in published artifacts.
#9118 partially solved this. It didn't touch publish-side naming though, so the published files still drop the suffix in three places.
**Solution**
This fixes
- ivyless publication names - CoursierArtifactsTasks.coursierPublicationsTask
- ivyless POM <artifactId> (the coordinate written inside the .pom) - PomGenerator.crossVersionDep
- Ivy backend (useIvy := true) - CrossVersion.substituteCross via IvyActions
* Add Test configuration to evictionWarningOptions
* Add Test configuration to default evictionWarningOptions
* Deduplicate eviction errors based on callers.
* Update eviction error test for semantic versioning.
* Group evictions by configuration and update test.
getFileProperty returned relative File objects when system properties
like sbt.global.base were set to relative paths (e.g. via -sbt-dir
../cache in .sbtopts). This caused an assertion failure in
IO.directoryURI: "Not absolute: ../cache/plugins".
Also fixes misleading scaladoc in SemanticSelector that claimed
`<=1.0` is equivalent to `<1.1.0` — they differ for pre-release
versions like 1.1.0-M1 (#4423).
Fixes#3729
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
**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
Fixessbt/sbt#8942
Problem
libraryDependencySchemes didn't work for platforms like Scala.JS
Solution
Modified EvictionError.scala to extract the suffix.
Changed from _: Binary to b: Binary and added ${b.suffix} to the module name.
---------
Co-authored-by: oolokioo7 <loki021107@gmail.com>
Step 5 of #7640 — removes the compile-time dependency on lm-ivy from main/ by creating a standalone sbt-ivy plugin module.
- Create new sbt-ivy/ subproject with IvyDependencyPlugin AutoPlugin that provides all Ivy-specific functionality (ivySbt, ivyModule, ivyConfiguration, publisher, projectDescriptors, deliver/makeIvyXml)
- Move IvyXml.scala from main/ to sbt-ivy/
- Add UpdateReportCache case class wrapping UpdateReportLite with stats/stamps
- Implement toCache/fromCache for conversion between UpdateReport and cache
- Add readFrom/writeTo for CacheStore persistence with backward compatibility
- Add fromLiteFull to JsonUtil for full reconstruction from lite format
- Update LibraryManagement to use new persistence API
- Add benchmark comparing full vs lite deserialization
- Add unit tests for persistence correctness
- Add scripted test for cache round-trip verification
**Problem**
Excluding artifacts using `.exclude(org, name)` requires you to
explicitly set scala version in `name`.
**Solution**
- Deprecating `.exclude(org, name)` in favor of new
`.exclude(OrganizationArtifactName)`
- Fixing `lmcoursier.FromSbt` ignores `excludeRule.crossVersion`
When a dependency declares a version range (e.g. Ivy [1.3.1,2.3] or comma-separated "1.3.1,2.3" as used by Coursier), and the resolver picks a version inside that range, sbt was still reporting an eviction warning. The chosen version satisfies the range, so it should not be reported as an eviction.
Example (from #6244): oauth2-oidc-sdk and nimbus-jose-jwt both depend on net.minidev:json-smart with range [1.3.1,2.3]. Resolution selects 2.3, which is within the range. Before this fix, sbt reported an eviction for json-smart even though 2.3 satisfies [1.3.1,2.3].
**Problem**
Some scripted tests are failing due to the fact that -bin-SNAPSHOT
isn't being recognized.
**Solution**
This fixes sbtApiVersion to recognize BinCompatV.
- Add `versionSatisfiesRange()` function to `VersionRange.scala` supporting Maven-style ranges (`[x,y)`, `(x,y]`, `[x,)`, etc.) and plus ranges (`1.0+`)
- Check if winner version satisfies evicted module's version range in `guessCompatible()`
Add support for `"3-latest.candidate"` to automatically resolve to the latest Scala 3 RC from Maven Central.
```scala
scalaVersion := "3-latest.candidate"
```
Ref https://github.com/sbt/sbt/discussions/8590
* test: Migrate UpdateReportSpec to verify.BasicTestSuite (#8543)
Migrate UpdateReportSpec.scala from ScalaTest's AnyFlatSpec + Matchers
to verify.BasicTestSuite, following the pattern established by other
test files in the lm-core module.
Changes:
- Replace AnyFlatSpec class with BasicTestSuite object
- Remove ScalaTest Matchers dependency
- Convert 'should ... in' syntax to 'test(...)' syntax
- Use Scala 3 syntax with colon indentation
- Change === to == for assertions (BasicTestSuite style)
- Add explicit types for lazy vals
- Add 'end UpdateReportSpec' marker
Fixes#8543
* Update lm-core/src/test/scala/UpdateReportSpec.scala
---------
Co-authored-by: GlobalStar117 <GlobalStar117@users.noreply.github.com>
**Problem**
When project A's dependencies changed and A was compiled in one command, project B (depending on A) would not invalidate its update cache in a subsequent command. This caused stale classpaths.
The root cause was that `depsUpdated` only checked `!stats.cached`, which only detected fresh resolves within the same command. When a dependency was served from cache (even if resolved fresh in a previous command), `cached` was marked `true`, causing incorrect cache reuse.
Debug scenario from issue:
sbt:aaa> clean
sbt:aaa> a/compile
sbt:aaa> show itTests/depsUpdated
[info] * false <-- BUG: should be true
**Solution**
Added `stamp: String` field to `UpdateStats` that records when the update was resolved. This stamp persists across commands and enables accurate cross-command comparison:
- If any dependency's stamp > our cached stamp, we re-resolve
- Falls back to `!cached` check for backwards compatibility with old caches
- Using `String` type allows future transition from timestamps to content hashes
When using `ProjectMatrix` with `CrossVersion.full` and Scala 2 versions like `2.13.18`, the project ID incorrectly became `$1$2_13_18` instead of `foo2_13_18`.
**Root cause:** The Scala 3 compiler creates synthetic intermediate vals (e.g., `$1`) during macro expansion. The `enclosingTerm` function in the macros was stopping at these synthetic symbols instead of continuing up the symbol tree to find the actual val name.
**Fix:** Added `Flags.Synthetic` check to skip compiler-generated symbols in:
- `main-settings/src/main/scala/sbt/std/KeyMacro.scala`
- `lm-core/src/main/scala/sbt/librarymanagement/ConfigurationExtra.scala`
---------
Co-authored-by: byteforge38 <joseph.mc0803@gmail.com>
Eviction warnings and errors were not reported for Test dependencies because
`EvictionError` only checked the Compile configuration.
This fix runs the eviction check for both Compile and Test configurations
separately, with distinct error messages:
- Compile: `found version conflict(s) in library dependencies`
- Test: `found version conflict(s) in Test dependencies`
**Problem**
During the milestone releases of Scala, e.g. Scala 2.13.0-M1,
scalaBinaryVersion by design points to 2.13.0-M1,
and also the source directory uses scala-2.13.0-M1,
but in most cases we actually want to pretend compatibility
and use scala-2.13 directory.
**Solution**
This introduces a new setting called scalaEarlyVersion,
which is the scalaBinaryVersion of the release version of milestones.
We have been calling this "partial version", but that broke
down for Scala 3, which adopted semantic versioning.
The current deprecation messages for `sonatypeRepo()` & `sonatypeOssRepos()` (added with https://github.com/sbt/librarymanagement/pull/517) say:
> use the following instead: resolvers += Resolver.sonatypeCentral**Snapshots**
...but following this advice can expose projects to using **snapshot** artifacts when they did not previously! This is unfortunate, as snapshots artifacts are inherently more risky, due to being mutable.
For example, invocations of `sonatypeOssRepos()` like [this](76234e013f/project/plugins.sbt (L10)):
```scala
resolvers ++= Resolver.sonatypeOssRepos("releases")
```
...should _not_ be replaced by `sonatypeCentralSnapshots()`, as, AFAIK, only non-snapshot releases would be in `sonatypeOssRepos("releases")`