diff --git a/build.sbt b/build.sbt index 98c3ac4..1e9c950 100644 --- a/build.sbt +++ b/build.sbt @@ -11,7 +11,7 @@ inThisBuild(List( url("https://github.com/alexarchambault") ) ), - versionPolicyIntention := Compatibility.BinaryAndSourceCompatible, + versionPolicyIntention := Compatibility.BinaryCompatible, libraryDependencySchemes += "com.typesafe" %% "mima-core" % "semver-spec" )) diff --git a/sbt-version-policy/src/main/scala/sbtversionpolicy/SbtVersionPolicyKeys.scala b/sbt-version-policy/src/main/scala/sbtversionpolicy/SbtVersionPolicyKeys.scala index d1e4142..416be0d 100644 --- a/sbt-version-policy/src/main/scala/sbtversionpolicy/SbtVersionPolicyKeys.scala +++ b/sbt-version-policy/src/main/scala/sbtversionpolicy/SbtVersionPolicyKeys.scala @@ -3,6 +3,7 @@ package sbtversionpolicy import coursier.version.VersionCompatibility import sbt._ import sbt.librarymanagement.DependencyBuilders.OrganizationArtifactName +import sbtversionpolicy.internal.DependencyCheck import scala.util.matching.Regex @@ -13,6 +14,7 @@ trait SbtVersionPolicyKeys { final val versionPolicyCheck = taskKey[Unit]("Runs both versionPolicyReportDependencyIssues and versionPolicyMimaCheck") final val versionPolicyMimaCheck = taskKey[Unit]("Runs Mima to check backward or forward compatibility depending on the intended change defined via versionPolicyIntention.") final val versionPolicyForwardCompatibilityCheck = taskKey[Unit]("Report forward binary compatible issues from Mima.") + final val versionPolicyDependencyIssuesReporter = taskKey[DependencyCheck.Reporter]("Helper to find issues in the library dependencies.") final val versionPolicyFindDependencyIssues = taskKey[Seq[(ModuleID, DependencyCheckReport)]]("Compatibility issues in the library dependencies.") final val versionCheck = taskKey[Unit]("Checks that the version is consistent with the intended compatibility level defined via versionPolicyIntention") diff --git a/sbt-version-policy/src/main/scala/sbtversionpolicy/SbtVersionPolicyMima.scala b/sbt-version-policy/src/main/scala/sbtversionpolicy/SbtVersionPolicyMima.scala index 234ca4c..46094b3 100644 --- a/sbt-version-policy/src/main/scala/sbtversionpolicy/SbtVersionPolicyMima.scala +++ b/sbt-version-policy/src/main/scala/sbtversionpolicy/SbtVersionPolicyMima.scala @@ -27,7 +27,7 @@ object SbtVersionPolicyMima extends AutoPlugin { private def moduleName(m: ModuleID, sv: String, sbv: String): String = moduleName(m.crossVersion, sv, sbv, m.name) - private lazy val previousVersionsFromRepo = Def.setting { + lazy val previousVersionsFromRepo = Def.setting { val projId = Keys.projectID.value val sv = Keys.scalaVersion.value @@ -103,18 +103,20 @@ object SbtVersionPolicyMima extends AutoPlugin { }, mimaPreviousArtifacts := { - val projId = Keys.projectID.value.withExplicitArtifacts(Vector.empty) - val previousVersions0 = versionPolicyPreviousVersions.value - - previousVersions0.toSet.map { version => - projId - .withExtraAttributes { - projId.extraAttributes - .filter(!_._1.stripPrefix("e:").startsWith("info.")) - } - .withRevision(version) - } + computePreviousArtifacts(Keys.projectID.value, versionPolicyPreviousVersions.value) } ) + def computePreviousArtifacts(projectID: ModuleID, previousVersions: Seq[String]) = { + val projId = projectID.withExplicitArtifacts(Vector.empty) + + previousVersions.toSet.map { version => + projId + .withExtraAttributes { + projId.extraAttributes + .filter(!_._1.stripPrefix("e:").startsWith("info.")) + } + .withRevision(version) + } + } } diff --git a/sbt-version-policy/src/main/scala/sbtversionpolicy/SbtVersionPolicySettings.scala b/sbt-version-policy/src/main/scala/sbtversionpolicy/SbtVersionPolicySettings.scala index de059d5..0e5497a 100644 --- a/sbt-version-policy/src/main/scala/sbtversionpolicy/SbtVersionPolicySettings.scala +++ b/sbt-version-policy/src/main/scala/sbtversionpolicy/SbtVersionPolicySettings.scala @@ -93,22 +93,25 @@ object SbtVersionPolicySettings { def previousArtifactsSettings = Def.settings( versionPolicyPreviousArtifactsFromMima := { - import Ordering.Implicits._ - MimaPlugin.autoImport.mimaPreviousArtifacts.value - .toVector - .map { mod => - val splitVersion = mod.revision.split('.').map(s => Try(s.toInt).getOrElse(-1)).toSeq - (splitVersion, mod) - } - .sortBy(_._1) - .map(_._2) + fromMimaArtifacts(MimaPlugin.autoImport.mimaPreviousArtifacts.value) }, - versionPolicyPreviousArtifacts := versionPolicyPreviousArtifactsFromMima.value ) + def fromMimaArtifacts(artifacts: Set[sbt.ModuleID]) = { + import Ordering.Implicits.* + artifacts + .toVector + .map { mod => + val splitVersion = mod.revision.split('.').map(s => Try(s.toInt).getOrElse(-1)).toSeq + (splitVersion, mod) + } + .sortBy(_._1) + .map(_._2) + } + def findIssuesSettings = Def.settings( - versionPolicyFindDependencyIssues := { + versionPolicyDependencyIssuesReporter := { val log = streams.value.log val sv = scalaVersion.value val sbv = scalaBinaryVersion.value @@ -117,9 +120,6 @@ object SbtVersionPolicySettings { sys.error("Compile configuration not found in update report") } - val compatibilityIntention = - versionPolicyIntention.?.value - .getOrElse(throw new MessageOnlyException("Please set the key versionPolicyIntention to declare the compatibility you want to check")) val depRes = versionPolicyDependencyResolution.value val scalaModuleInf = versionPolicyScalaModuleInfo.value val updateConfig = versionPolicyUpdateConfiguration.value @@ -140,32 +140,24 @@ object SbtVersionPolicySettings { log ) + new DependencyCheck.Reporter( + excludedModules, + currentDependencies, + reconciliations, + VersionCompatibility.Strict, + sv, + sbv, + depRes, + scalaModuleInf, + updateConfig, + warningConfig, + log + ) + }, + versionPolicyFindDependencyIssues := { + val compatibilityIntention = requirePolicyIntentionOrThrow(versionPolicyIntention.?.value) val previousModuleIds = versionPolicyPreviousArtifacts.value - - // Skip dependency check if no compatibility is intended - if (compatibilityIntention == Compatibility.None) Nil else { - - previousModuleIds.map { previousModuleId => - - val report0 = DependencyCheck.report( - compatibilityIntention, - excludedModules, - currentDependencies, - previousModuleId, - reconciliations, - VersionCompatibility.Strict, - sv, - sbv, - depRes, - scalaModuleInf, - updateConfig, - warningConfig, - log - ) - - (previousModuleId, report0) - } - } + versionPolicyDependencyIssuesReporter.value.apply(compatibilityIntention, previousModuleIds) }, versionPolicyReportDependencyIssues := { val log = streams.value.log @@ -173,9 +165,7 @@ object SbtVersionPolicySettings { val sbv = scalaBinaryVersion.value val direction = versionPolicyCheckDirection.value val reports = versionPolicyFindDependencyIssues.value - val intention = - versionPolicyIntention.?.value - .getOrElse(throw new MessageOnlyException("Please set the key versionPolicyIntention to declare the compatibility you want to check")) + val intention = requirePolicyIntentionOrThrow(versionPolicyIntention.?.value) val currentModule = projectID.value val formattedPreviousVersions = formatVersions(versionPolicyPreviousVersions.value) @@ -263,9 +253,7 @@ object SbtVersionPolicySettings { }, versionPolicyMimaCheck := Def.taskDyn { import Compatibility._ - val compatibility = - versionPolicyIntention.?.value - .getOrElse(throw new MessageOnlyException("Please set the key versionPolicyIntention to declare the compatibility you want to check")) + val compatibility = requirePolicyIntentionOrThrow(versionPolicyIntention.?.value) val log = streams.value.log val currentModule = projectID.value val formattedPreviousVersions = formatVersions(versionPolicyPreviousVersions.value) @@ -302,6 +290,14 @@ object SbtVersionPolicySettings { }.value ) + private def requirePolicyIntentionOrThrow(maybeCompatibility: Option[Compatibility]) = + maybeCompatibility + .getOrElse( + throw new MessageOnlyException( + "Please set the key versionPolicyIntention to declare the compatibility you want to check" + ) + ) + def skipSettings = Seq( versionCheck / skip := (publish / skip).value, versionPolicyCheck / skip := (publish / skip).value diff --git a/sbt-version-policy/src/main/scala/sbtversionpolicy/internal/DependencyCheck.scala b/sbt-version-policy/src/main/scala/sbtversionpolicy/internal/DependencyCheck.scala index c895c64..05640f5 100644 --- a/sbt-version-policy/src/main/scala/sbtversionpolicy/internal/DependencyCheck.scala +++ b/sbt-version-policy/src/main/scala/sbtversionpolicy/internal/DependencyCheck.scala @@ -75,6 +75,47 @@ object DependencyCheck { log ) + class Reporter( + excludedModules: Set[(String, String)], + currentDependencies: Map[(String, String), String], + reconciliations: Seq[(ModuleMatchers, VersionCompatibility)], + defaultReconciliation: VersionCompatibility, + sv: String, + scalaBinaryVersion: String, + depRes: DependencyResolution, + scalaModuleInf: Option[ScalaModuleInfo], + updateConfig: UpdateConfiguration, + warningConfig: UnresolvedWarningConfiguration, + log: Logger + ) { + def apply(compatibilityIntention: Compatibility, previousModuleIds: Seq[ModuleID]) = + // Skip dependency check if no compatibility is intended + if (compatibilityIntention == Compatibility.None) Nil else { + + previousModuleIds.map { previousModuleId => + + val report0 = report( + compatibilityIntention, + excludedModules, + currentDependencies, + previousModuleId, + reconciliations, + defaultReconciliation, + sv, + sbv, + depRes, + scalaModuleInf, + updateConfig, + warningConfig, + log + ) + + (previousModuleId, report0) + } + } + + } + private[sbtversionpolicy] def report( compatibilityIntention: Compatibility, excludedModules: Set[(String, String)],