From 3af62be0a3962aa050131f436db381ac49a9b96f Mon Sep 17 00:00:00 2001 From: PandaMan Date: Fri, 6 Feb 2026 17:16:20 +0200 Subject: [PATCH] [2.x] fix: Respect explicit platform settings in dependency resolution (#8697) **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 --- .../src/main/scala/lmcoursier/FromSbt.scala | 8 +- .../lmcoursier/FromSbtPlatformSpec.scala | 110 ++++++++++++++++++ .../platform-scala3-library/build.sbt | 40 +++++++ .../platform-scala3-library/test | 2 + 4 files changed, 157 insertions(+), 3 deletions(-) create mode 100644 lm-coursier/src/test/scala/lmcoursier/FromSbtPlatformSpec.scala create mode 100644 sbt-app/src/sbt-test/dependency-management/platform-scala3-library/build.sbt create mode 100644 sbt-app/src/sbt-test/dependency-management/platform-scala3-library/test diff --git a/lm-coursier/src/main/scala/lmcoursier/FromSbt.scala b/lm-coursier/src/main/scala/lmcoursier/FromSbt.scala index 3ffce7f6b..8f346d1db 100644 --- a/lm-coursier/src/main/scala/lmcoursier/FromSbt.scala +++ b/lm-coursier/src/main/scala/lmcoursier/FromSbt.scala @@ -55,9 +55,11 @@ object FromSbt { case _ => s"${name}_$platformName" } (platformOpt, projectPlatform) match { - case (Some(p), None) => addSuffix(p) - case (_, Some(p)) => addSuffix(p) - case _ => name + case (Some(p), _) => + addSuffix(p) // Use explicit platform if set (don't override with project platform) + case (None, Some(p)) => + addSuffix(p) // Only use project platform if dependency has no explicit platform + case _ => name } } diff --git a/lm-coursier/src/test/scala/lmcoursier/FromSbtPlatformSpec.scala b/lm-coursier/src/test/scala/lmcoursier/FromSbtPlatformSpec.scala new file mode 100644 index 000000000..1e9de19c4 --- /dev/null +++ b/lm-coursier/src/test/scala/lmcoursier/FromSbtPlatformSpec.scala @@ -0,0 +1,110 @@ +package lmcoursier + +import org.scalatest.matchers.should.Matchers +import org.scalatest.propspec.AnyPropSpec +import sbt.librarymanagement.* + +final class FromSbtPlatformSpec extends AnyPropSpec with Matchers { + + property("explicit platform should not be overridden by project platform") { + // Test case for issue #8665: Auto-injected Scala library with explicit .platform(Platform.jvm) + // should not get project platform applied + + val scala3Library = ModuleID("org.scala-lang", "scala3-library", "3.7.4") + .withCrossVersion(Binary()) + .platform(Platform.jvm) // Explicit platform set to jvm + + val projectPlatform = Some("native0.5") // Project has native0.5 platform + + // When converting to Coursier module, the name should NOT include native0.5 suffix + val (module, _) = FromSbt.moduleVersion( + scala3Library, + scalaVersion = "3.7.4", + scalaBinaryVersion = "3", + optionalCrossVer = false, + projectPlatform = projectPlatform + ) + + // The module name should be scala3-library_3, NOT scala3-library_native0.5_3 + module.name.value shouldBe "scala3-library_3" + module.name.value should not contain "native0.5" + } + + property("project platform should apply to dependencies without explicit platform") { + // Dependencies without explicit platform should get project platform + val regularDep = ModuleID("com.example", "foo", "1.0.0") + .withCrossVersion(Binary()) + // No explicit platform set + + val projectPlatform = Some("native0.5") + + val (module, _) = FromSbt.moduleVersion( + regularDep, + scalaVersion = "2.13.18", + scalaBinaryVersion = "2.13", + optionalCrossVer = false, + projectPlatform = projectPlatform + ) + + // Should get the project platform suffix + module.name.value shouldBe "foo_native0.5_2.13" + } + + property("explicit platform should take priority over project platform") { + // When a dependency has an explicit platform, it should be used even if project has a different platform + val depWithExplicitPlatform = ModuleID("com.example", "bar", "1.0.0") + .withCrossVersion(Binary()) + .platform("js1") // Explicit platform set to js1 + + val projectPlatform = Some("native0.5") // Project has different platform + + val (module, _) = FromSbt.moduleVersion( + depWithExplicitPlatform, + scalaVersion = "2.13.18", + scalaBinaryVersion = "2.13", + optionalCrossVer = false, + projectPlatform = projectPlatform + ) + + // Should use explicit platform (js1), not project platform (native0.5) + module.name.value shouldBe "bar_js1_2.13" + module.name.value should not contain "native0.5" + } + + property("jvm platform should not add suffix") { + // JVM platform (explicit or project) should not add suffix + val dep = ModuleID("com.example", "baz", "1.0.0") + .withCrossVersion(Binary()) + .platform(Platform.jvm) + + val (module, _) = FromSbt.moduleVersion( + dep, + scalaVersion = "2.13.18", + scalaBinaryVersion = "2.13", + optionalCrossVer = false, + projectPlatform = Some("native0.5") + ) + + // JVM platform should not add suffix, even with project platform set + module.name.value shouldBe "baz_2.13" + module.name.value should not contain "jvm" + module.name.value should not contain "native0.5" + } + + property("no platform when both are None") { + val dep = ModuleID("com.example", "qux", "1.0.0") + .withCrossVersion(Binary()) + // No explicit platform + + val (module, _) = FromSbt.moduleVersion( + dep, + scalaVersion = "2.13.18", + scalaBinaryVersion = "2.13", + optionalCrossVer = false, + projectPlatform = None + ) + + // Should just have cross-version suffix, no platform + module.name.value shouldBe "qux_2.13" + } +} diff --git a/sbt-app/src/sbt-test/dependency-management/platform-scala3-library/build.sbt b/sbt-app/src/sbt-test/dependency-management/platform-scala3-library/build.sbt new file mode 100644 index 000000000..4743f13c6 --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-management/platform-scala3-library/build.sbt @@ -0,0 +1,40 @@ +lazy val check = taskKey[Unit]("Runs the check") + +// Reproduces issue #8665: platform should not be applied to auto-injected Scala library +scalaVersion := "3.7.4" +platform := "native0.5" + +// autoScalaLibrary is true by default, which auto-injects scala3-library +// The auto-injected library has .platform(Platform.jvm) explicitly set +// It should NOT get the native0.5 platform suffix + +TaskKey[Unit]("check") := { + val ur = update.value + + // The auto-injected scala3-library should be resolved as scala3-library_3, NOT scala3-library_native0.5_3 + val scala3LibraryFiles = ur.matching( + moduleFilter(organization = "org.scala-lang", name = "scala3-library_3", revision = "*") + ) + assert( + scala3LibraryFiles.nonEmpty, + s"scala3-library_3 (without platform suffix) was not found in update report. " + + s"This indicates the platform was incorrectly applied to the auto-injected library. " + + s"Update report: $ur" + ) + + // Verify that scala3-library_native0.5_3 does NOT exist (it shouldn't) + val wrongFiles = ur.matching( + moduleFilter(organization = "org.scala-lang", name = "scala3-library_native0.5_3", revision = "*") + ) + assert( + wrongFiles.isEmpty, + s"scala3-library_native0.5_3 was incorrectly found in update report. " + + s"The auto-injected Scala library should not get the project platform suffix. " + + s"Update report: $ur" + ) + + streams.value.log.info("✓ Auto-injected scala3-library correctly resolved without platform suffix") +} + +csrCacheDirectory := baseDirectory.value / "coursier-cache" + diff --git a/sbt-app/src/sbt-test/dependency-management/platform-scala3-library/test b/sbt-app/src/sbt-test/dependency-management/platform-scala3-library/test new file mode 100644 index 000000000..15886c51a --- /dev/null +++ b/sbt-app/src/sbt-test/dependency-management/platform-scala3-library/test @@ -0,0 +1,2 @@ +> check +