update held a process-global lock around coursier resolution and artifact
fetching whenever a logger was set OR coursier was not in fallback mode. That
lock exists only to serialize coursier's interactive progress bar, which is
rendered solely when no custom logger is supplied and coursier is not in
fallback mode. The loggerOpt.nonEmpty clause therefore over-serialized the
common non-interactive case (IntelliJ re-imports, CI, any non-TTY run, where
sbt supplies a quiet debug-only logger), making update scale with the number
of modules rather than the number of distinct artifacts.
Fixes#5508.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
**Problem**
Some tests are failing.
**Solution**
* Port EvictionErrorSpec to lm-coursier
* Port EvictionWarningSpec to lm-coursier
* Port InclExclSpec to lm-coursier
* Port ZincComponentCompilerSpec to lm-coursier
* Apparently we still need lmIvy
**Problem**
When publishing with coursier, the `visibility` attribute of `<conf />`
elements in `ivy.xml` was hardcoded to `"public"`. Configurations
defined as hidden (e.g. `scala-tool`) were incorrectly published with
`visibility="public"` instead of `"private"`.
The root cause was that `Inputs.configExtendsSeq` only extracted config
names and extends relationships, discarding the `isPublic` flag from
sbt's `Configuration` objects.
**Solution**
Add a `privateConfigNames: Set[String]` field to the lmcoursier
`Project` data class (with `@since` for backward compatibility).
Populate it from `Configuration.isPublic` in `CoursierInputsTasks`,
and use it in both `IvyXml` implementations to set the correct
visibility attribute.
Fixessbt/sbt#5455
**Problem**
Coursier graph.Conflict -> DependencyTree relocation can loop forever when
Maven/Gradle relocation metadata forms a cycle (sbt-site 1.4.1).
**Solution**
Detect relocation cycles with the same step logic as Coursier, skip Conflict
for affected configs, log once per update.
Generated-by: Claude
**Problem**
When a dependency is declared with a classifier (e.g., classifier "linux-x86_64"),
the UpdateReport > ModuleReport.module.explicitArtifacts is empty. The classifier
data is available as Publication objects during Coursier resolution but is lost
when SbtUpdateReport reconstructs the ModuleID.
**Solution**
In SbtUpdateReport.moduleReport, extract explicit artifacts from Publications
with non-empty classifiers and apply them to the ModuleID used by ModuleReport.
This is done on a per-report copy to avoid mutating the shared moduleId cache.
Fixes#5491
Fixes unresolved dependency path reporting for Coursier (`ResolveException.failedPaths`) and adds a stable scripted regression.
This PR addresses 5168 by reconstructing unresolved dependency caller chains from the Coursier resolution graph and attaching them to `ResolveException.failedPaths`. That allows unresolved warnings to show the full path from the missing module up to the root project.
It also adds and stabilizes `lm-coursier/unresolved-path` scripted coverage by:
- using a local test Maven repo fixture (no flaky remote test dependency)
- checking update stream output via an sbt task (`checkLog`) instead of shell `grep`
- asserting the unresolved path includes missing module, transitive caller, and root project
- **Remove `ivyModule` from `updateTask0`**: Replace `IvySbt#Module` with `moduleSettings` + `DependencyResolution.moduleDescriptor()`, eliminating the Ivy dependency in the update path.
- **Replace direct Ivy usage in `Load.scala` and `TemplateCommandUtil`**: Use Coursier's `DependencyResolution` API for plugin bootstrapping and template resolution instead of constructing `IvySbt` instances directly.
- **Break `lm-coursier`'s dependency on `lm-ivy`**: Remove `IvySbt#Module` pattern match from `CoursierDependencyResolution`, replace `IBiblioResolver` usage in `Resolvers` with reflection, and switch build dependencies from `lmIvy` to `lmCore`.
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
**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`
- CacheUrlConversion: normalize paths for comparison (forward slashes)
and strip leading slash on Windows file URIs so cache matching works.
- Apply scalafmt to touched files.
- Add CacheUrlConversion in lm-coursier internal to convert cache file
paths back to original repository URLs (single place for logic).
- CoursierDependencyResolution delegates to CacheUrlConversion.
- DependencyLockManager.createFromUpdateReport now accepts optional
cacheDir; when an artifact has a file URL it either converts via
cache dir (Coursier layout) or fails with a clear message.
- dependencyLock task passes csrCacheDirectory so lock file gets
portable HTTPS URLs instead of machine-specific cache paths.
Expectation 1: Lock file contains original Maven Central (or repo) URLs.
Expectation 2: If conversion is not possible, lock creation fails.
**Problem**
When platform is set, it incorrectly adds the platform suffix to implicit Scala library dependencies even though they explicitly set platform to jvm. This causes resolution errors.
**Solution**
Modified addPlatformSuffix to prioritize explicit platform settings on dependencies. If a dependency has an explicit platform, use that instead of the project platform. The project platform should only apply to dependencies without an explicit platform.
Fixes#8665
Generated-by: Claude Sonnet 4.5
**Consuming BOMs**
- You can declare a BOM with `.pomOnly()` and versionless deps with `"*"`:
- `libraryDependencies += ("com.fasterxml.jackson" % "jackson-bom" % "2.21.0").pomOnly()`
- `libraryDependencies += "com.fasterxml.jackson.core" % "jackson-core" % "*"`
- BOMs are passed to Coursier via `Resolve.addBom()`; version `"*"` is resolved from the BOM.
**makePom**
- POM-only dependencies are emitted under `<dependencyManagement><dependencies>...</dependencies></dependencyManagement>` with `<type>pom</type>` and `<scope>import</scope>`.
- Dependencies with version `"*"` are emitted without a `<version>` element so Maven uses the BOM-managed version.
**Ivy / publishLocal emulation**
- When publishing to Ivy (e.g. `publishLocal`), BOM-resolved versions (deps that had `"*"`) are written into the published `ivy.xml` as forced dependencies (`force="true"`), so consumers that depend on this module get those versions.
**What it does**
When you run `dependencyLock`, sbt generates a `deps.lock` file that captures your resolved dependencies. This file can be checked into version control to ensure reproducible builds across different machines and CI environments.
**New tasks**
- **`dependencyLock`** - Generates the lock file from the current resolution
- **`dependencyLockCheck`** - Validates the lock file is up-to-date (fails build if stale)
**How it works**
The lock file stores a hash of your declared dependencies and resolvers. When dependencies change, the hash changes, and `dependencyLockCheck` will fail until you regenerate the lock file.
If no lock file exists, `dependencyLockCheck` passes silently - this allows gradual adoption.
This adds a new setting that allows users to
configure Coursier's FileCache to cache local file:// artifacts. When enabled,
artifacts from local repositories are copied to the cache directory, which is
useful for scenarios like bundling compiler artifacts in a local repo for
offline use.
Fixes#7547
**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