All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scala.build.actionable.ActionableDependencyHandler.scala Maven / Gradle / Ivy

package scala.build.actionable

import coursier.Versions
import coursier.core.{Latest, Version}
import coursier.parse.RepositoryParser
import dependency.*

import scala.build.EitherCps.{either, value}
import scala.build.actionable.ActionableDiagnostic.*
import scala.build.errors.{BuildException, RepositoryFormatError, Severity}
import scala.build.internal.Constants
import scala.build.internal.Util.*
import scala.build.options.BuildOptions
import scala.build.options.ScalaVersionUtil.versions
import scala.build.{Logger, Positioned}
import scala.concurrent.duration.DurationInt

case object ActionableDependencyHandler
    extends ActionableHandler[ActionableDependencyUpdateDiagnostic] {
  type Setting = Positioned[AnyDependency]

  override def extractSettings(options: BuildOptions): Seq[Positioned[AnyDependency]] =
    if (options.suppressWarningOptions.suppressOutdatedDependencyWarning.getOrElse(false))
      Nil
    else
      options.classPathOptions.extraDependencies.toSeq

  override def actionableDiagnostic(
    setting: Positioned[AnyDependency],
    buildOptions: BuildOptions,
    loggerOpt: Option[Logger]
  ): Either[BuildException, Option[ActionableDependencyUpdateDiagnostic]] = either {
    val dependency       = setting.value
    val currentVersion   = dependency.version
    val latestVersionOpt = value(findLatestVersion(buildOptions, setting, loggerOpt))

    for {
      latestVersion <- latestVersionOpt
      if Version(latestVersion) > Version(currentVersion) &&
      !isLatestSyntaxVersion(currentVersion)
      // filtering out toolkit-test to prevent double-update-diagnostic
      if !(dependency.userParams.contains(Constants.toolkitName) &&
      dependency.module.name == Constants.toolkitTestName)
    } yield
      if dependency.userParams.contains(Constants.toolkitName)
      then
        val toolkitSuggestion =
          if dependency.module.organization == Constants.toolkitOrganization then latestVersion
          else if dependency.module.organization == Constants.typelevelOrganization then
            s"typelevel:$latestVersion"
          else s"${dependency.module.organization}:$latestVersion"
        ActionableDependencyUpdateDiagnostic(
          setting.positions,
          currentVersion,
          latestVersion,
          dependencyModuleName = Constants.toolkitName,
          suggestion = toolkitSuggestion
        )
      else
        ActionableDependencyUpdateDiagnostic(
          setting.positions,
          currentVersion,
          latestVersion,
          dependencyModuleName = dependency.module.name,
          suggestion = dependency.copy(version = latestVersion).render
        )
  }

  /** Versions like 'latest.*': 'latest.release', 'latest.integration', 'latest.stable'
    */
  private def isLatestSyntaxVersion(version: String): Boolean = Latest(version).nonEmpty
  private def findLatestVersion(
    buildOptions: BuildOptions,
    setting: Positioned[AnyDependency],
    loggerOpt: Option[Logger]
  ): Either[BuildException, Option[String]] = either {
    val dependency   = setting.value
    val scalaParams  = value(buildOptions.scalaParams)
    val cache        = buildOptions.finalCache
    val csModule     = value(dependency.toCs(scalaParams)).module
    val repositories = value(buildOptions.finalRepositories)

    val latestVersionOpt = cache.versions(csModule, repositories)
      .versions
      .latest(coursier.core.Latest.Stable)

    if (latestVersionOpt.isEmpty)
      loggerOpt.foreach(_.diagnostic(
        s"No latest version found for ${dependency.render}",
        Severity.Warning,
        setting.positions
      ))

    latestVersionOpt
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy