versionScheme setting + better eviction warning

Ref https://github.com/sbt/sbt/issues/5710
Ref https://github.com/sbt/librarymanagement/pull/339

This adds `versionScheme` setting. When set, it is included into POM, and gets picked up on the other side as an extra attribute of ModuleID. That information in turn is used to inform the eviction warning.

This should reduce the false positives associated with SemVer'ed libraries showing up in the eviction warning.
This commit is contained in:
Eugene Yokota 2020-08-05 00:21:51 -04:00
parent e76f61bec5
commit f947970247
8 changed files with 99 additions and 10 deletions

View File

@ -305,6 +305,7 @@ object Defaults extends BuildCommon {
crossVersion :== Disabled(),
buildDependencies := Classpaths.constructBuildDependencies.value,
version :== "0.1.0-SNAPSHOT",
versionScheme :== None,
classpathTypes :== Set("jar", "bundle", "maven-plugin", "test-jar") ++ CustomPomParser.JarPackagings,
artifactClassifier :== None,
checksums := Classpaths.bootChecksums(appConfiguration.value),
@ -2645,7 +2646,7 @@ object Classpaths {
val report = (updateTask tag (Tags.Update, Tags.Network)).value
val log = streams.value.log
val ew =
EvictionWarning(ivyModule.value, (evictionWarningOptions in evicted).value, report)
EvictionWarning(ivyModule.value, (evicted / evictionWarningOptions).value, report)
ew.lines foreach { log.warn(_) }
ew.infoAllTheThings foreach { log.info(_) }
ew
@ -2763,13 +2764,20 @@ object Classpaths {
}
private[sbt] def defaultProjectID: Initialize[ModuleID] = Def.setting {
val base = ModuleID(organization.value, moduleName.value, version.value)
val p0 = ModuleID(organization.value, moduleName.value, version.value)
.cross(crossVersion in projectID value)
.artifacts(artifacts.value: _*)
apiURL.value match {
case Some(u) => base.extra(SbtPomExtraProperties.POM_API_KEY -> u.toExternalForm)
case _ => base
val p1 = apiURL.value match {
case Some(u) => p0.extra(SbtPomExtraProperties.POM_API_KEY -> u.toExternalForm)
case _ => p0
}
val p2 = versionScheme.value match {
case Some(x) =>
VersionSchemes.validateScheme(x)
p1.extra(SbtPomExtraProperties.VERSION_SCHEME_KEY -> x)
case _ => p1
}
p2
}
def pluginProjectID: Initialize[ModuleID] =
Def.setting {

View File

@ -488,6 +488,7 @@ object Keys {
val packagedArtifact = taskKey[(Artifact, File)]("Generates a packaged artifact, returning the Artifact and the produced File.").withRank(CTask)
val checksums = settingKey[Seq[String]]("The list of checksums to generate and to verify for dependencies.").withRank(BSetting)
val forceUpdatePeriod = settingKey[Option[FiniteDuration]]("Duration after which to force a full update to occur").withRank(CSetting)
val versionScheme = settingKey[Option[String]]("""Version scheme used for the subproject: Supported values are Some("early-semver"), Some("pvp"), and Some("semver-spec")""").withRank(BSetting)
val classifiersModule = taskKey[GetClassifiersModule]("classifiers-module").withRank(CTask)
val compatibilityWarningOptions = settingKey[CompatibilityWarningOptions]("Configures warnings around Maven incompatibility.").withRank(CSetting)

View File

@ -28,6 +28,7 @@ import lmcoursier.definitions.{
}
import lmcoursier.credentials.DirectCredentials
import lmcoursier.{ FallbackDependency, FromSbt, Inputs }
import sbt.internal.librarymanagement.mavenint.SbtPomExtraProperties
import sbt.librarymanagement.ivy.{
FileCredentials,
Credentials,
@ -46,6 +47,7 @@ object CoursierInputsTasks {
auOpt: Option[URL],
description: String,
homepage: Option[URL],
vsOpt: Option[String],
log: Logger
): CProject = {
@ -60,12 +62,16 @@ object CoursierInputsTasks {
)
val proj1 = auOpt match {
case Some(au) =>
val props = proj0.properties :+ ("info.apiURL" -> au.toString)
proj0.withProperties(props)
proj0.withProperties(proj0.properties :+ (SbtPomExtraProperties.POM_API_KEY -> au.toString))
case _ => proj0
}
proj1.withInfo(
proj1.info.withDescription(description).withHomePage(homepage.fold("")(_.toString))
val proj2 = vsOpt match {
case Some(vs) =>
proj1.withProperties(proj1.properties :+ (SbtPomExtraProperties.VERSION_SCHEME_KEY -> vs))
case _ => proj1
}
proj2.withInfo(
proj2.info.withDescription(description).withHomePage(homepage.fold("")(_.toString))
)
}
@ -80,6 +86,7 @@ object CoursierInputsTasks {
apiURL.value,
description.value,
homepage.value,
versionScheme.value,
streams.value.log
)
}

View File

@ -13,7 +13,7 @@ object Dependencies {
// sbt modules
private val ioVersion = nightlyVersion.getOrElse("1.4.0-M6")
private val lmVersion =
sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.4.0-M1")
sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.4.0-M2")
val zincVersion = nightlyVersion.getOrElse("1.4.0-M7")
private val sbtIO = "org.scala-sbt" %% "io" % ioVersion

View File

@ -0,0 +1,62 @@
// ThisBuild / useCoursier := false
ThisBuild / organization := "com.example"
ThisBuild / scalaVersion := "2.12.11"
ThisBuild / versionScheme := Some("semver-spec")
def commonSettings: Seq[Def.Setting[_]] =
Seq(
ivyPaths := IvyPaths(
(ThisBuild / baseDirectory).value,
Some((LocalRootProject / target).value / "ivy-cache")
),
csrCacheDirectory := (LocalRootProject / target).value / "cache",
fullResolvers := fullResolvers.value.filterNot(_.name == "inter-project"),
publishTo := Some(MavenCache("local-maven", (LocalRootProject / target).value / "local-maven")),
resolvers += MavenCache("local-maven", (LocalRootProject / target).value / "local-maven"),
)
lazy val root = (project in file("."))
.settings(commonSettings)
val `v1-0-0` = (project in file("v1.0.0"))
.settings(commonSettings)
.settings(
name := "semver-spec-test",
version := "1.0.0",
)
val `v1-1-0` = (project in file("v1.1.0"))
.settings(commonSettings)
.settings(
name := "semver-spec-test",
version := "1.1.0",
)
val middle = project
.settings(commonSettings)
.settings(
name := "middle",
version := "1.0.0",
libraryDependencies += "com.example" %% "semver-spec-test" % "1.0.0",
)
val use = project
.settings(commonSettings)
.settings(
name := "use",
libraryDependencies ++= Seq(
"com.example" %% "semver-spec-test" % "1.1.0",
"com.example" %% "middle" % "1.0.0",
),
TaskKey[Unit]("check") := {
val report = updateFull.value
val log = streams.value.log
val extraAttributes = (report.allModules flatMap { _.extraAttributes}) collect {
case ("info.versionScheme", v) => v
}
log.info(s"extraAttributes = $extraAttributes")
assert(extraAttributes.nonEmpty, s"$extraAttributes is empty")
val ew = EvictionWarning(ivyModule.value, (evicted / evictionWarningOptions).value, report)
assert(ew.directEvictions.isEmpty, s"${ew.directEvictions} is not empty")
},
)

View File

@ -0,0 +1,5 @@
> v1-0-0/publish
> v1-1-0/publish
> middle/publish
> use/check

View File

@ -0,0 +1,3 @@
package example
trait Foo {}

View File

@ -0,0 +1,3 @@
package example
trait Foo {}