Merge pull request #416 from eed3si9n/wip/repro-6745

Reproduce sbt/sbt#6745
This commit is contained in:
eugene yokota 2023-05-06 23:07:16 -04:00 committed by GitHub
commit af23adcbac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 63 additions and 34 deletions

View File

@ -83,47 +83,52 @@ object EvictionError {
}
}: _*)
def calculateCompatible(p: EvictionPair): (Boolean, String, Boolean, String) = {
val winnerOpt = p.winner map { _.module }
val extraAttributes = ((p.winner match {
case Some(r) => r.extraAttributes.toMap
case _ => Map.empty
}): collection.immutable.Map[String, String]) ++ (winnerOpt match {
case Some(w) => w.extraAttributes.toMap
case _ => Map.empty
})
// prioritize user-defined version scheme to allow overriding the real scheme
val schemeOpt = userDefinedSchemes
.get((p.organization, p.name))
.orElse(userDefinedSchemes.get((p.organization, "*")))
.orElse(VersionSchemes.extractFromExtraAttributes(extraAttributes))
.orElse(userDefinedSchemes.get(("*", "*")))
val f = (winnerOpt, schemeOpt) match {
case (Some(_), Some(scheme)) => VersionSchemes.evalFunc(scheme)
case _ => EvictionWarningOptions.guessTrue
}
val scheme =
if (isNameScalaSuffixed(p.name)) assumedVersionScheme
else assumedVersionSchemeJava
val guess = VersionSchemes.evalFunc(scheme)
(p.evicteds forall { r =>
f((r.module, winnerOpt, module.scalaModuleInfo))
}, schemeOpt.getOrElse("?"), p.evicteds forall { r =>
guess((r.module, winnerOpt, module.scalaModuleInfo))
}, scheme)
}
pairs foreach {
// don't report on a transitive eviction that does not have a winner
// https://github.com/sbt/sbt/issues/4946
case p if p.winner.isDefined =>
val r = calculateCompatible(p)
if (!r._1) {
incompatibleEvictions += (p -> r._2)
} else if (!r._3) {
assumedIncompatEvictions += (p -> r._4)
val winner = p.winner.get
def hasIncompatibleVersionForScheme(scheme: String) = {
val isCompat = VersionSchemes.evalFunc(scheme)
p.evicteds.exists { r =>
!isCompat((r.module, Some(winner.module), module.scalaModuleInfo))
}
}
// from libraryDependencyScheme or defined in the pom using the `info.versionScheme` attribute
val userDefinedSchemeOrFromPom = {
def fromLibraryDependencySchemes(org: String = "*", mod: String = "*") =
userDefinedSchemes.get((org, mod))
def fromWinnerPom = VersionSchemes.extractFromExtraAttributes(
winner.extraAttributes.toMap ++ winner.module.extraAttributes
)
fromLibraryDependencySchemes(p.organization, p.name) // by org and name
.orElse(fromLibraryDependencySchemes(p.organization)) // for whole org
.orElse(fromWinnerPom) // from pom
.orElse(fromLibraryDependencySchemes()) // global
}
// We want the user to be able to suppress eviction errors for a specific library,
// which would result in an incompatible eviction based on the assumed version scheme.
// So, only fall back to the assumed scheme if there is no given scheme by the user or the pom.
userDefinedSchemeOrFromPom match {
case Some(givenScheme) =>
if (hasIncompatibleVersionForScheme(givenScheme))
incompatibleEvictions += (p -> givenScheme)
case None =>
val assumedScheme =
if (isNameScalaSuffixed(p.name)) assumedVersionScheme
else assumedVersionSchemeJava
if (hasIncompatibleVersionForScheme(assumedScheme))
assumedIncompatEvictions += (p -> assumedScheme)
}
case _ => ()
}
new EvictionError(
incompatibleEvictions.toList,
assumedIncompatEvictions.toList,

View File

@ -97,6 +97,23 @@ object EvictionErrorSpec extends BaseIvySpecification {
assert(EvictionError(report, m, overrideRules).incompatibleEvictions.isEmpty)
}
test("it should selectively allow opt-out from the error despite assumed scheme") {
val deps = Vector(`scala2.12.17`, `akkaActor2.6.0`, `swagger-akka-http1.4.0`)
val m = module(defaultModuleId, deps, Some("2.12.17"))
val report = ivyUpdate(m)
val overrideRules = List("org.scala-lang.modules" %% "scala-java8-compat" % "always")
assert(
EvictionError(
report = report,
module = m,
schemes = overrideRules,
assumedVersionScheme = "early-semver",
assumedVersionSchemeJava = "always",
assumedEvictionErrorLevel = Level.Error,
).assumedIncompatibleEvictions.isEmpty
)
}
// older Akka was on pvp
def oldAkkaPvp = List("com.typesafe.akka" % "*" % "pvp")
@ -104,8 +121,12 @@ object EvictionErrorSpec extends BaseIvySpecification {
ModuleID("com.typesafe.akka", "akka-actor", "2.1.4").withConfigurations(Some("compile")) cross CrossVersion.binary
lazy val `akkaActor2.3.0` =
ModuleID("com.typesafe.akka", "akka-actor", "2.3.0").withConfigurations(Some("compile")) cross CrossVersion.binary
lazy val `akkaActor2.6.0` =
ModuleID("com.typesafe.akka", "akka-actor", "2.6.0").withConfigurations(Some("compile")) cross CrossVersion.binary
lazy val `scala2.10.4` =
ModuleID("org.scala-lang", "scala-library", "2.10.4").withConfigurations(Some("compile"))
lazy val `scala2.12.17` =
ModuleID("org.scala-lang", "scala-library", "2.12.17").withConfigurations(Some("compile"))
lazy val `scala2.13.3` =
ModuleID("org.scala-lang", "scala-library", "2.13.3").withConfigurations(Some("compile"))
lazy val `bananaSesame0.4` =
@ -122,6 +143,9 @@ object EvictionErrorSpec extends BaseIvySpecification {
("org.typelevel" %% "cats-parse" % "0.1.0").withConfigurations(Some("compile"))
lazy val `cats-parse0.2.0` =
("org.typelevel" %% "cats-parse" % "0.2.0").withConfigurations(Some("compile"))
lazy val `swagger-akka-http1.4.0` =
("com.github.swagger-akka-http" %% "swagger-akka-http" % "1.4.0")
.withConfigurations(Some("compile"))
def dummyScalaModuleInfo(v: String): ScalaModuleInfo =
ScalaModuleInfo(