From 68211670324eb7af250d7dddaa68e92d0884b4f5 Mon Sep 17 00:00:00 2001 From: BinaryWorldTl <124203751+mohamed0803@users.noreply.github.com> Date: Tue, 10 Mar 2026 20:46:51 -0700 Subject: [PATCH] [2.x] fix: Handle scala/toolkit.local when passed as argument to sbt new (#8887) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Running sbt new scala/toolkit.local with the template slug on the command line throws: The same templates work when chosen from the interactive menu (sbt new with no args). The code path for “arguments provided” only consulted external template resolvers (e.g. Giter8), which do not handle these built-in local templates. --- .../main/scala/sbt/TemplateCommandUtil.scala | 10 ++++-- .../scala/sbt/TemplateCommandUtilTest.scala | 35 +++++++++++++++++++ .../lm-coursier/tests-classifier/build.sbt | 2 +- 3 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 main/src/test/scala/sbt/TemplateCommandUtilTest.scala diff --git a/main/src/main/scala/sbt/TemplateCommandUtil.scala b/main/src/main/scala/sbt/TemplateCommandUtil.scala index f06609972..915281fd5 100644 --- a/main/src/main/scala/sbt/TemplateCommandUtil.scala +++ b/main/src/main/scala/sbt/TemplateCommandUtil.scala @@ -53,8 +53,14 @@ private[sbt] object TemplateCommandUtil { def terminate = TerminateAction :: s1.copy(remainingCommands = Nil) def reload = "reboot" :: s1.copy(remainingCommands = Nil) if (args0.nonEmpty) { - run(infos, args0, s0.configuration, lm, globalBase, scalaModuleInfo, log) - terminate + args0 match { + case arg :: Nil if arg.endsWith(".local") => + extracted.runInputTask(Keys.templateRunLocal, " " + arg, s0) + reload + case _ => + run(infos, args0, s0.configuration, lm, globalBase, scalaModuleInfo, log) + terminate + } } else { fortifyArgs(templateDescriptions.toList) match { case Nil => terminate diff --git a/main/src/test/scala/sbt/TemplateCommandUtilTest.scala b/main/src/test/scala/sbt/TemplateCommandUtilTest.scala new file mode 100644 index 000000000..d0b490322 --- /dev/null +++ b/main/src/test/scala/sbt/TemplateCommandUtilTest.scala @@ -0,0 +1,35 @@ +/* + * sbt + * Copyright 2023, Scala center + * Copyright 2011 - 2022, Lightbend, Inc. + * Copyright 2008 - 2010, Mark Harrah + * Licensed under Apache License 2.0 (see LICENSE) + */ + +package sbt + +import sbt.util.Logger + +object TemplateCommandUtilTest extends verify.BasicTestSuite: + + private val localTemplateSlugs = List( + "scala/toolkit.local", + "typelevel/toolkit.local", + "sbt/cross-platform.local" + ) + + test("defaultTemplateDescriptions includes all built-in local template slugs"): + val slugs = TemplateCommandUtil.defaultTemplateDescriptions.map(_._1) + for slug <- localTemplateSlugs do + assert(slugs.contains(slug), s"defaultTemplateDescriptions should contain '$slug'") + + test("defaultRunLocalTemplate throws for unknown .local slug"): + val log = Logger.Null + val ex = + try { + TemplateCommandUtil.defaultRunLocalTemplate(List("unknown/template.local"), log) + null + } catch { case e: IllegalArgumentException => e } + assert(ex ne null) + assert(ex.getMessage.contains("Local template not found for:")) + assert(ex.getMessage.contains("unknown/template.local")) diff --git a/sbt-app/src/sbt-test/lm-coursier/tests-classifier/build.sbt b/sbt-app/src/sbt-test/lm-coursier/tests-classifier/build.sbt index bee4bee2b..98ca7556a 100644 --- a/sbt-app/src/sbt-test/lm-coursier/tests-classifier/build.sbt +++ b/sbt-app/src/sbt-test/lm-coursier/tests-classifier/build.sbt @@ -18,7 +18,7 @@ lazy val b = project classpathTypes += "test-jar", libraryDependencies ++= Seq( org %% nme % ver, - org %% nme % ver % "test" classifier "tests" + (org %% nme % ver % "test").classifier("tests") ) )