diff --git a/modules/build/src/main/scala/scala/build/PersistentDiagnosticLogger.scala b/modules/build/src/main/scala/scala/build/PersistentDiagnosticLogger.scala index 5dd9f58674..cb654070fd 100644 --- a/modules/build/src/main/scala/scala/build/PersistentDiagnosticLogger.scala +++ b/modules/build/src/main/scala/scala/build/PersistentDiagnosticLogger.scala @@ -26,6 +26,7 @@ class PersistentDiagnosticLogger(parent: Logger) extends Logger { } def log(ex: BuildException): Unit = parent.log(ex) + def debug(ex: BuildException): Unit = parent.debug(ex) def exit(ex: BuildException): Nothing = parent.exit(ex) def coursierLogger(printBefore: String): coursier.cache.CacheLogger = diff --git a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala index 98eba864b6..a601648d43 100644 --- a/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala +++ b/modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala @@ -247,8 +247,8 @@ case object ScalaPreprocessor extends Preprocessor { val toFilePos = Position.Raw.filePos(path, content) val deps = value { dependencyTrees - .map { t => - val pos = toFilePos(Position.Raw(t.start, t.end)) + .map { t => /// skip ivy ($ivy.`) or dep syntax ($dep.`) + val pos = toFilePos(Position.Raw(t.start + "$ivy.`".length, t.end)) val strDep = t.prefix.drop(1).mkString(".") val maybeDep = parseDependency(strDep, pos) maybeDep.map(dep => Positioned(Seq(pos), dep)) diff --git a/modules/build/src/test/scala/scala/build/tests/ActionableDiagnosticTests.scala b/modules/build/src/test/scala/scala/build/tests/ActionableDiagnosticTests.scala new file mode 100644 index 0000000000..d34c12a4ba --- /dev/null +++ b/modules/build/src/test/scala/scala/build/tests/ActionableDiagnosticTests.scala @@ -0,0 +1,108 @@ +package scala.build.tests + +import com.eed3si9n.expecty.Expecty.expect +import scala.build.options.{BuildOptions, InternalOptions} +import scala.build.Ops._ +import scala.build.{BuildThreads, Directories, LocalRepo} +import scala.build.actionable.ActionablePreprocessor +import scala.build.actionable.ActionableDiagnostic._ +import coursier.core.Version + +class ActionableDiagnosticTests extends munit.FunSuite { + + val extraRepoTmpDir = os.temp.dir(prefix = "scala-cli-tests-actionable-diagnostic-") + val directories = Directories.under(extraRepoTmpDir) + val baseOptions = BuildOptions( + internal = InternalOptions( + localRepository = LocalRepo.localRepo(directories.localRepoDir) + ) + ) + val buildThreads = BuildThreads.create() + + test("update os-lib") { + val dependencyOsLib = "com.lihaoyi::os-lib:0.7.8" + val testInputs = TestInputs( + os.rel / "Foo.scala" -> + s"""//> using lib "$dependencyOsLib" + | + |object Hello extends App { + | println("Hello") + |} + |""".stripMargin + ) + testInputs.withBuild(baseOptions, buildThreads, None) { + (_, _, maybeBuild) => + val build = maybeBuild.orThrow + val updateDiagnostics = + ActionablePreprocessor.generateActionableDiagnostics(build.options).orThrow + + val osLibDiagnosticOpt = updateDiagnostics.collectFirst { + case diagnostic: ActionableDependencyUpdateDiagnostic => diagnostic + } + + expect(osLibDiagnosticOpt.nonEmpty) + val osLibDiagnostic = osLibDiagnosticOpt.get + + expect(Version(osLibDiagnostic.newVersion) > Version(osLibDiagnostic.oldDependency.version)) + } + } + + test("update ivy dependence upickle") { + val dependencyOsLib = "com.lihaoyi::upickle:1.4.0" + val testInputs = TestInputs( + os.rel / "Foo.scala" -> + s"""import $$ivy.`$dependencyOsLib` + | + |object Hello extends App { + | println("Hello") + |} + |""".stripMargin + ) + testInputs.withBuild(baseOptions, buildThreads, None) { + (_, _, maybeBuild) => + val build = maybeBuild.orThrow + val updateDiagnostics = + ActionablePreprocessor.generateActionableDiagnostics(build.options).orThrow + + val osLibDiagnosticOpt = updateDiagnostics.collectFirst { + case diagnostic: ActionableDependencyUpdateDiagnostic => diagnostic + } + + expect(osLibDiagnosticOpt.nonEmpty) + val osLibDiagnostic = osLibDiagnosticOpt.get + + expect(osLibDiagnostic.oldDependency.render == dependencyOsLib) + expect(Version(osLibDiagnostic.newVersion) > Version(osLibDiagnostic.oldDependency.version)) + } + } + + test("update dep dependence upickle") { + val dependencyOsLib = "com.lihaoyi::upickle:1.4.0" + val testInputs = TestInputs( + os.rel / "Foo.scala" -> + s"""import $$dep.`$dependencyOsLib` + | + |object Hello extends App { + | println("Hello") + |} + |""".stripMargin + ) + testInputs.withBuild(baseOptions, buildThreads, None) { + (_, _, maybeBuild) => + val build = maybeBuild.orThrow + val updateDiagnostics = + ActionablePreprocessor.generateActionableDiagnostics(build.options).orThrow + + val osLibDiagnosticOpt = updateDiagnostics.collectFirst { + case diagnostic: ActionableDependencyUpdateDiagnostic => diagnostic + } + + expect(osLibDiagnosticOpt.nonEmpty) + val osLibDiagnostic = osLibDiagnosticOpt.get + + expect(osLibDiagnostic.oldDependency.render == dependencyOsLib) + expect(Version(osLibDiagnostic.newVersion) > Version(osLibDiagnostic.oldDependency.version)) + } + } + +} diff --git a/modules/build/src/test/scala/scala/build/tests/BuildProjectTests.scala b/modules/build/src/test/scala/scala/build/tests/BuildProjectTests.scala index 30265924f8..0a199f4bc3 100644 --- a/modules/build/src/test/scala/scala/build/tests/BuildProjectTests.scala +++ b/modules/build/src/test/scala/scala/build/tests/BuildProjectTests.scala @@ -40,7 +40,8 @@ class BuildProjectTests extends munit.FunSuite { this.diagnostics = this.diagnostics ++ diagnostics } - override def log(ex: BuildException): Unit = {} + override def log(ex: BuildException): Unit = {} + override def debug(ex: BuildException): Unit = {} override def exit(ex: BuildException): Nothing = ??? diff --git a/modules/build/src/test/scala/scala/build/tests/TestLogger.scala b/modules/build/src/test/scala/scala/build/tests/TestLogger.scala index 72efee2e35..32ec8c8ec2 100644 --- a/modules/build/src/test/scala/scala/build/tests/TestLogger.scala +++ b/modules/build/src/test/scala/scala/build/tests/TestLogger.scala @@ -37,6 +37,8 @@ case class TestLogger(info: Boolean = true, debug: Boolean = false) extends Logg def log(ex: BuildException): Unit = System.err.println(ex.getMessage) + def debug(ex: BuildException): Unit = + debug(ex.getMessage) def exit(ex: BuildException): Nothing = throw new Exception(ex) diff --git a/modules/cli-options/src/main/scala/scala/cli/commands/DependencyUpdateOptions.scala b/modules/cli-options/src/main/scala/scala/cli/commands/DependencyUpdateOptions.scala new file mode 100644 index 0000000000..219f15e631 --- /dev/null +++ b/modules/cli-options/src/main/scala/scala/cli/commands/DependencyUpdateOptions.scala @@ -0,0 +1,20 @@ +package scala.cli.commands + +import caseapp._ +import caseapp.core.help.Help + +// format: off +@HelpMessage("Update dependencies in project") +final case class DependencyUpdateOptions( + @Recurse + shared: SharedOptions = SharedOptions(), + @Group("DependencyUpdate") + @HelpMessage("Update all dependency") + all: Boolean = false, +) + // format: on + +object DependencyUpdateOptions { + implicit lazy val parser: Parser[DependencyUpdateOptions] = Parser.derive + implicit lazy val help: Help[DependencyUpdateOptions] = Help.derive +} diff --git a/modules/cli/src/main/scala/scala/cli/ScalaCliCommands.scala b/modules/cli/src/main/scala/scala/cli/ScalaCliCommands.scala index 501cc7f766..b1ee354959 100644 --- a/modules/cli/src/main/scala/scala/cli/ScalaCliCommands.scala +++ b/modules/cli/src/main/scala/scala/cli/ScalaCliCommands.scala @@ -37,6 +37,7 @@ class ScalaCliCommands( Compile, Config, DefaultFile, + DependencyUpdate, Directories, Doc, Doctor, diff --git a/modules/cli/src/main/scala/scala/cli/commands/DependencyUpdate.scala b/modules/cli/src/main/scala/scala/cli/commands/DependencyUpdate.scala new file mode 100644 index 0000000000..efc96a1180 --- /dev/null +++ b/modules/cli/src/main/scala/scala/cli/commands/DependencyUpdate.scala @@ -0,0 +1,114 @@ +package scala.cli.commands + +import caseapp._ +import os.Path + +import scala.build.actionable.ActionableDependencyHandler +import scala.build.actionable.ActionableDiagnostic.ActionableDependencyUpdateDiagnostic +import scala.build.internal.CustomCodeWrapper +import scala.build.options.Scope +import scala.build.{CrossSources, Logger, Position, Sources} +import scala.cli.CurrentParams +import scala.cli.commands.util.SharedOptionsUtil._ + +object DependencyUpdate extends ScalaCommand[DependencyUpdateOptions] { + override def group = "Main" + override def sharedOptions(options: DependencyUpdateOptions) = Some(options.shared) + + def run(options: DependencyUpdateOptions, args: RemainingArgs): Unit = { + val verbosity = options.shared.logging.verbosity + CurrentParams.verbosity = verbosity + + val inputs = options.shared.inputsOrExit(args) + val logger = options.shared.logger + val buildOptions = options.shared.buildOptions() + + val (crossSources, _) = + CrossSources.forInputs( + inputs, + Sources.defaultPreprocessors( + buildOptions.scriptOptions.codeWrapper.getOrElse(CustomCodeWrapper), + buildOptions.archiveCache, + buildOptions.internal.javaClassNameVersionOpt + ), + logger + ).orExit(logger) + + val scopedSources = crossSources.scopedSources(buildOptions).orExit(logger) + + def generateActionableUpdateDiagnostic(scope: Scope) + : Seq[ActionableDependencyUpdateDiagnostic] = { + val sources = scopedSources.sources(scope, crossSources.sharedOptions(buildOptions)) + + if (verbosity >= 3) + pprint.err.log(sources) + + val options = buildOptions.orElse(sources.buildOptions) + ActionableDependencyHandler.createActionableDiagnostics(options).orExit(logger) + } + + val actionableMainUpdateDiagnostics = generateActionableUpdateDiagnostic(Scope.Main) + val actionableTestUpdateDiagnostics = generateActionableUpdateDiagnostic(Scope.Test) + val actionableUpdateDiagnostics = + (actionableMainUpdateDiagnostics ++ actionableTestUpdateDiagnostics).distinct + + if (options.all) + updateDependencies(actionableUpdateDiagnostics, logger) + else { + println("Updates") + actionableUpdateDiagnostics.foreach(update => + println(s" * ${update.oldDependency.render} -> ${update.newVersion}") + ) + println("""|To update all dependencies run: + | scala-cli dependency-update --all""".stripMargin) + } + } + + private def updateDependencies( + actionableUpdateDiagnostics: Seq[ActionableDependencyUpdateDiagnostic], + logger: Logger + ): Unit = { + val groupedByFileDiagnostics = + actionableUpdateDiagnostics.flatMap { + diagnostic => + diagnostic.positions.collect { + case file: Position.File => + file.path -> (file, diagnostic) + } + }.groupMap(_._1)(_._2) + + groupedByFileDiagnostics.foreach { + case (Right(file), diagnostics) => + val sortedByLine = diagnostics.sortBy(_._1.startPos._1).reverse + val appliedDiagnostics = updateDependencies(file, sortedByLine) + os.write.over(file, appliedDiagnostics) + diagnostics.foreach(diagnostic => + logger.message(s"Updated dependency to: ${diagnostic._2.to}") + ) + case (Left(file), diagnostics) => + diagnostics.foreach { + diagnostic => + logger.message(s"Warning: Scala CLI can't update ${diagnostic._2.to} in $file") + } + } + } + + private def updateDependencies( + file: Path, + diagnostics: Seq[(Position.File, ActionableDependencyUpdateDiagnostic)] + ): String = { + val fileContent = os.read(file) + val startIndicies = Position.Raw.lineStartIndices(fileContent) + + diagnostics.foldLeft(fileContent) { + case (fileContent, (file, diagnostic)) => + val (line, column) = (file.startPos._1, file.startPos._2) + val startIndex = startIndicies(line) + column + val endIndex = startIndex + diagnostic.oldDependency.render.length() + + val newDependency = diagnostic.to + s"${fileContent.slice(0, startIndex)}$newDependency${fileContent.drop(endIndex)}" + } + } + +} diff --git a/modules/cli/src/main/scala/scala/cli/internal/CliLogger.scala b/modules/cli/src/main/scala/scala/cli/internal/CliLogger.scala index 36498222bb..2e193e3ca8 100644 --- a/modules/cli/src/main/scala/scala/cli/internal/CliLogger.scala +++ b/modules/cli/src/main/scala/scala/cli/internal/CliLogger.scala @@ -119,6 +119,9 @@ class CliLogger( if (verbosity >= 0) printEx(ex, new mutable.HashMap) + def debug(ex: BuildException): Unit = + if (verbosity >= 2) + printEx(ex, new mutable.HashMap) def exit(ex: BuildException): Nothing = if (verbosity < 0) sys.exit(1) diff --git a/modules/core/src/main/scala/scala/build/Logger.scala b/modules/core/src/main/scala/scala/build/Logger.scala index 47bb1264dd..7a6aa11b46 100644 --- a/modules/core/src/main/scala/scala/build/Logger.scala +++ b/modules/core/src/main/scala/scala/build/Logger.scala @@ -25,6 +25,7 @@ trait Logger { ): Unit = log(Seq(Diagnostic(message, severity, positions))) def log(ex: BuildException): Unit + def debug(ex: BuildException): Unit def exit(ex: BuildException): Nothing def coursierLogger(printBefore: String): coursier.cache.CacheLogger @@ -48,6 +49,7 @@ object Logger { def log(diagnostics: Seq[Diagnostic]): Unit = () def log(ex: BuildException): Unit = () + def debug(ex: BuildException): Unit = () def exit(ex: BuildException): Nothing = throw new Exception(ex) diff --git a/modules/core/src/main/scala/scala/build/Position.scala b/modules/core/src/main/scala/scala/build/Position.scala index f0057c56a6..250e20873e 100644 --- a/modules/core/src/main/scala/scala/build/Position.scala +++ b/modules/core/src/main/scala/scala/build/Position.scala @@ -44,7 +44,7 @@ object Position { // from https://github.com/com-lihaoyi/Ammonite/blob/76673f7f3eb9d9ae054482635f57a31527d248de/amm/interp/src/main/scala/ammonite/interp/script/PositionOffsetConversion.scala#L7-L69 - private def lineStartIndices(content: String): Array[Int] = { + def lineStartIndices(content: String): Array[Int] = { val content0 = content.toCharArray diff --git a/modules/integration/src/test/scala/scala/cli/integration/DependencyUpdateTests.scala b/modules/integration/src/test/scala/scala/cli/integration/DependencyUpdateTests.scala new file mode 100644 index 0000000000..a34c6177ef --- /dev/null +++ b/modules/integration/src/test/scala/scala/cli/integration/DependencyUpdateTests.scala @@ -0,0 +1,41 @@ +package scala.cli.integration + +import com.eed3si9n.expecty.Expecty.expect + +class DependencyUpdateTests extends munit.FunSuite { + + test("dependency update test") { + val fileName = "Hello.scala" + val message = "Hello World" + val fileContent = + s"""|//> using lib "com.lihaoyi::os-lib:0.7.8" + |//> using lib "com.lihaoyi::utest:0.7.10" + |import $$ivy.`com.lihaoyi::geny:0.6.5` + |import $$dep.`com.lihaoyi::pprint:0.6.6` + | + |object Hello extends App { + | println("$message") + |}""".stripMargin + val inputs = TestInputs( + Seq( + os.rel / fileName -> fileContent + ) + ) + inputs.fromRoot { root => + // update dependencies + val p = os.proc(TestUtil.cli, "dependency-update", "--all", fileName) + .call( + cwd = root, + stdin = os.Inherit, + mergeErrIntoOut = true + ) + expect(p.out.text().trim.contains("Updated dependency to")) + expect( // check if dependency update command modify file + os.read(root / fileName) != fileContent) + + // after updating dependencies app should run + val out = os.proc(TestUtil.cli, fileName).call(cwd = root).out.text().trim + expect(out == message) + } + } +} diff --git a/modules/options/src/main/scala/scala/build/actionable/ActionableDependencyHandler.scala b/modules/options/src/main/scala/scala/build/actionable/ActionableDependencyHandler.scala new file mode 100644 index 0000000000..7f46fe03f8 --- /dev/null +++ b/modules/options/src/main/scala/scala/build/actionable/ActionableDependencyHandler.scala @@ -0,0 +1,60 @@ +package scala.build.actionable + +import coursier.Versions +import dependency._ + +import scala.build.EitherCps.{either, value} +import scala.build.Positioned +import scala.build.actionable.ActionableDiagnostic._ +import scala.build.actionable.errors.ActionableHandlerError +import scala.build.errors.BuildException +import scala.build.internal.Util._ +import scala.build.options.BuildOptions +import scala.concurrent.duration.DurationInt + +case object ActionableDependencyHandler + extends ActionableHandler[ActionableDependencyUpdateDiagnostic] { + type Setting = Positioned[AnyDependency] + + override def extractSettings(options: BuildOptions): Seq[Positioned[AnyDependency]] = + options.classPathOptions.extraDependencies.toSeq + + override def actionableDiagnostic( + setting: Positioned[AnyDependency], + buildOptions: BuildOptions + ): Either[BuildException, Option[ActionableDependencyUpdateDiagnostic]] = either { + val dependency = setting.value + val currentVersion = dependency.version + val latestVersion = value(findLatestVersion(buildOptions, dependency)) + + if (latestVersion != currentVersion) { + val msg = s"${dependency.render} is outdated, update to $latestVersion" + Some(ActionableDependencyUpdateDiagnostic(msg, setting.positions, dependency, latestVersion)) + } + else + None + } + + private def findLatestVersion( + buildOptions: BuildOptions, + dependency: AnyDependency + ): Either[BuildException, String] = either { + val scalaParams = value(buildOptions.scalaParams) + val cache = buildOptions.finalCache + val csModule = value(dependency.toCs(scalaParams)).module + + val res = cache.withTtl(0.seconds).logger.use { + Versions(cache) + .withModule(csModule) + .result() + .unsafeRun()(cache.ec) + } + + value { + res.versions.latest(coursier.core.Latest.Release).toRight { + new ActionableHandlerError(s"No latest version found for ${dependency.render}") + } + } + } + +} diff --git a/modules/options/src/main/scala/scala/build/actionable/ActionableDiagnostic.scala b/modules/options/src/main/scala/scala/build/actionable/ActionableDiagnostic.scala new file mode 100644 index 0000000000..c8716813f1 --- /dev/null +++ b/modules/options/src/main/scala/scala/build/actionable/ActionableDiagnostic.scala @@ -0,0 +1,38 @@ +package scala.build.actionable + +import dependency._ + +import scala.build.Position +import scala.build.errors.{Diagnostic, Severity} + +abstract class ActionableDiagnostic { + + /** Provide the message of actionable diagnostic + */ + def message: String + + /** Provide the new content which will be replaced by actionable diagnostic + */ + def to: String + def positions: Seq[Position] + + final def toDiagnostic: Diagnostic = Diagnostic( + message = s"""|$message + | To: $to""".stripMargin, + severity = Severity.Warning, + positions = positions + ) +} + +object ActionableDiagnostic { + + case class ActionableDependencyUpdateDiagnostic( + message: String, + positions: Seq[Position], + oldDependency: AnyDependency, + newVersion: String + ) extends ActionableDiagnostic { + override def to: String = oldDependency.copy(version = newVersion).render + } + +} diff --git a/modules/options/src/main/scala/scala/build/actionable/ActionableHandler.scala b/modules/options/src/main/scala/scala/build/actionable/ActionableHandler.scala new file mode 100644 index 0000000000..7c830edb26 --- /dev/null +++ b/modules/options/src/main/scala/scala/build/actionable/ActionableHandler.scala @@ -0,0 +1,43 @@ +package scala.build.actionable + +import scala.build.Ops._ +import scala.build.errors.{BuildException, CompositeBuildException} +import scala.build.options.BuildOptions + +trait ActionableHandler[A <: ActionableDiagnostic] { + + /** Type of setting used to generate actionable diagnostic + */ + type Setting + + /** Extract settings on the basis of which actionable diagnostics will be generated + * + * @param options + * the Build Options to extract settings + * @return + * the list of settings on the basis of which actionable diagnostics will be generated + */ + def extractSettings(options: BuildOptions): Seq[Setting] + + /** The setting on the basis of which the Actionable Diagnostic is generated + * + * @param option + * this option is used to generate an actionable diagnostic + * @param buildOptions + * used to extract additional parameter from buildOptions, such as "ScalaParams" or "Coursier + * Cache" See [[ActionableDependencyHandler]] + */ + def actionableDiagnostic( + setting: Setting, + buildOptions: BuildOptions + ): Either[BuildException, Option[A]] + + final def createActionableDiagnostics( + buildOptions: BuildOptions + ): Either[BuildException, Seq[A]] = + extractSettings(buildOptions) + .map(v => actionableDiagnostic(v, buildOptions)) + .sequence + .left.map(CompositeBuildException(_)) + .map(_.flatten) +} diff --git a/modules/options/src/main/scala/scala/build/actionable/ActionablePreprocessor.scala b/modules/options/src/main/scala/scala/build/actionable/ActionablePreprocessor.scala new file mode 100644 index 0000000000..a267c0df4b --- /dev/null +++ b/modules/options/src/main/scala/scala/build/actionable/ActionablePreprocessor.scala @@ -0,0 +1,21 @@ +package scala.build.actionable + +import scala.build.Ops._ +import scala.build.errors.{BuildException, CompositeBuildException} +import scala.build.options.BuildOptions + +object ActionablePreprocessor { + val actionableHandlers = Seq[ActionableHandler[_]]( + ActionableDependencyHandler + ) + + def generateActionableDiagnostics( + options: BuildOptions + ): Either[BuildException, Seq[ActionableDiagnostic]] = + actionableHandlers + .map(handler => handler.createActionableDiagnostics(options)) + .sequence + .left.map(CompositeBuildException(_)) + .map(_.flatten) + +} diff --git a/modules/options/src/main/scala/scala/build/actionable/errors/ActionableHandlerError.scala b/modules/options/src/main/scala/scala/build/actionable/errors/ActionableHandlerError.scala new file mode 100644 index 0000000000..7bd7ff80b5 --- /dev/null +++ b/modules/options/src/main/scala/scala/build/actionable/errors/ActionableHandlerError.scala @@ -0,0 +1,6 @@ +package scala.build.actionable.errors + +import scala.build.errors.BuildException + +final class ActionableHandlerError(message: String) + extends BuildException(message) diff --git a/website/docs/reference/cli-options.md b/website/docs/reference/cli-options.md index 178c6707b5..11a8f0b209 100644 --- a/website/docs/reference/cli-options.md +++ b/website/docs/reference/cli-options.md @@ -99,6 +99,7 @@ Available in commands: - [`bloop start`](./commands.md#bloop-start) - [`bsp`](./commands.md#bsp) - [`compile`](./commands.md#compile) +- [`dependency-update`](./commands.md#dependency-update) - [`doc`](./commands.md#doc) - [`export`](./commands.md#export) - [`fmt` / `format` / `scalafmt`](./commands.md#fmt) @@ -252,6 +253,7 @@ Available in commands: - [`bsp`](./commands.md#bsp) - [`compile`](./commands.md#compile) - [`config`](./commands.md#config) +- [`dependency-update`](./commands.md#dependency-update) - [`doc`](./commands.md#doc) - [`export`](./commands.md#export) - [`fmt` / `format` / `scalafmt`](./commands.md#fmt) @@ -324,6 +326,7 @@ Force overwriting destination files Available in commands: - [`bsp`](./commands.md#bsp) - [`compile`](./commands.md#compile) +- [`dependency-update`](./commands.md#dependency-update) - [`doc`](./commands.md#doc) - [`export`](./commands.md#export) - [`fmt` / `format` / `scalafmt`](./commands.md#fmt) @@ -358,6 +361,18 @@ Aliases: `-P`, `--plugin` Add compiler plugin dependencies +## Dependency update options + +Available in commands: +- [`dependency-update`](./commands.md#dependency-update) + + + + +#### `--all` + +Update all dependency + ## Directories options Available in commands: @@ -368,6 +383,7 @@ Available in commands: - [`clean`](./commands.md#clean) - [`compile`](./commands.md#compile) - [`config`](./commands.md#config) +- [`dependency-update`](./commands.md#dependency-update) - [`directories`](./commands.md#directories) - [`doc`](./commands.md#doc) - [`export`](./commands.md#export) @@ -500,6 +516,7 @@ Available in commands: - [`compile`](./commands.md#compile) - [`config`](./commands.md#config) - [`default-file`](./commands.md#default-file) +- [`dependency-update`](./commands.md#dependency-update) - [`directories`](./commands.md#directories) - [`doc`](./commands.md#doc) - [`doctor`](./commands.md#doctor) @@ -554,6 +571,7 @@ Print help message, including hidden options, and exit Available in commands: - [`bsp`](./commands.md#bsp) - [`compile`](./commands.md#compile) +- [`dependency-update`](./commands.md#dependency-update) - [`doc`](./commands.md#doc) - [`export`](./commands.md#export) - [`fmt` / `format` / `scalafmt`](./commands.md#fmt) @@ -670,6 +688,7 @@ Available in commands: - [`bloop start`](./commands.md#bloop-start) - [`bsp`](./commands.md#bsp) - [`compile`](./commands.md#compile) +- [`dependency-update`](./commands.md#dependency-update) - [`doc`](./commands.md#doc) - [`export`](./commands.md#export) - [`fmt` / `format` / `scalafmt`](./commands.md#fmt) @@ -733,6 +752,7 @@ Available in commands: - [`compile`](./commands.md#compile) - [`config`](./commands.md#config) - [`default-file`](./commands.md#default-file) +- [`dependency-update`](./commands.md#dependency-update) - [`doc`](./commands.md#doc) - [`export`](./commands.md#export) - [`fmt` / `format` / `scalafmt`](./commands.md#fmt) @@ -1338,6 +1358,7 @@ Temporary / working directory where to write generated launchers Available in commands: - [`bsp`](./commands.md#bsp) - [`compile`](./commands.md#compile) +- [`dependency-update`](./commands.md#dependency-update) - [`doc`](./commands.md#doc) - [`export`](./commands.md#export) - [`fmt` / `format` / `scalafmt`](./commands.md#fmt) @@ -1433,6 +1454,7 @@ Whether to run the Scala.js CLI on the JVM or using a native executable Available in commands: - [`bsp`](./commands.md#bsp) - [`compile`](./commands.md#compile) +- [`dependency-update`](./commands.md#dependency-update) - [`doc`](./commands.md#doc) - [`export`](./commands.md#export) - [`fmt` / `format` / `scalafmt`](./commands.md#fmt) @@ -1494,6 +1516,7 @@ Use default compile options Available in commands: - [`bsp`](./commands.md#bsp) - [`compile`](./commands.md#compile) +- [`dependency-update`](./commands.md#dependency-update) - [`doc`](./commands.md#doc) - [`export`](./commands.md#export) - [`fmt` / `format` / `scalafmt`](./commands.md#fmt) @@ -1564,6 +1587,7 @@ Available in commands: Available in commands: - [`bsp`](./commands.md#bsp) - [`compile`](./commands.md#compile) +- [`dependency-update`](./commands.md#dependency-update) - [`doc`](./commands.md#doc) - [`export`](./commands.md#export) - [`fmt` / `format` / `scalafmt`](./commands.md#fmt) @@ -1643,6 +1667,7 @@ Generate SemanticDBs Available in commands: - [`bsp`](./commands.md#bsp) - [`compile`](./commands.md#compile) +- [`dependency-update`](./commands.md#dependency-update) - [`doc`](./commands.md#doc) - [`export`](./commands.md#export) - [`fmt` / `format` / `scalafmt`](./commands.md#fmt) @@ -1779,6 +1804,7 @@ Available in commands: - [`compile`](./commands.md#compile) - [`config`](./commands.md#config) - [`default-file`](./commands.md#default-file) +- [`dependency-update`](./commands.md#dependency-update) - [`directories`](./commands.md#directories) - [`doc`](./commands.md#doc) - [`doctor`](./commands.md#doctor) @@ -1852,6 +1878,7 @@ Available in commands: - [`bsp`](./commands.md#bsp) - [`clean`](./commands.md#clean) - [`compile`](./commands.md#compile) +- [`dependency-update`](./commands.md#dependency-update) - [`doc`](./commands.md#doc) - [`export`](./commands.md#export) - [`fmt` / `format` / `scalafmt`](./commands.md#fmt) diff --git a/website/docs/reference/commands.md b/website/docs/reference/commands.md index f7e56c1905..4cb83bce96 100644 --- a/website/docs/reference/commands.md +++ b/website/docs/reference/commands.md @@ -45,6 +45,27 @@ Accepts options: - [watch](./cli-options.md#watch-options) - [workspace](./cli-options.md#workspace-options) +## `dependency-update` + +Update dependencies in project + +Accepts options: +- [compilation server](./cli-options.md#compilation-server-options) +- [coursier](./cli-options.md#coursier-options) +- [dependency](./cli-options.md#dependency-options) +- [dependency update](./cli-options.md#dependency-update-options) +- [directories](./cli-options.md#directories-options) +- [help group](./cli-options.md#help-group-options) +- [jvm](./cli-options.md#jvm-options) +- [logging](./cli-options.md#logging-options) +- [Scala.js](./cli-options.md#scalajs-options) +- [Scala Native](./cli-options.md#scala-native-options) +- [scalac](./cli-options.md#scalac-options) +- [shared](./cli-options.md#shared-options) +- [snippet](./cli-options.md#snippet-options) +- [verbosity](./cli-options.md#verbosity-options) +- [workspace](./cli-options.md#workspace-options) + ## `doc` Generate Scaladoc documentation