From 058a1088323b020b6c9c77a6451e0ed071a8087d Mon Sep 17 00:00:00 2001 From: bittoby <218712309+bittoby@users.noreply.github.com> Date: Thu, 9 Apr 2026 20:09:47 +0000 Subject: [PATCH] Fix stack traces suppressed in thin client batch mode (fixes #7322) --- main/src/main/scala/sbt/Main.scala | 10 +++++++++- .../actions/streams-trace-level/build.sbt | 17 +++++++++++++++++ .../sbt-test/actions/streams-trace-level/test | 3 +++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 sbt-app/src/sbt-test/actions/streams-trace-level/build.sbt create mode 100644 sbt-app/src/sbt-test/actions/streams-trace-level/test diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index f7bbb12b9..37fe90b49 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -1144,12 +1144,20 @@ object BuiltinCommands { .getOpt(Keys.minForcegcInterval) .getOrElse(GCUtil.defaultMinForcegcInterval) val exec: Exec = getExec(s1, minGCInterval) + val isInteractive = exec.source match { + case Some(src) if src.channelName.startsWith("network") => + exchange.channelForName(src.channelName) match { + case Some(nc: NetworkChannel) => nc.isInteractive + case _ => true + } + case _ => true + } val newState = s1 .copy( onFailure = Some(Exec(Shell, None)), remainingCommands = exec +: Exec(Shell, None) +: s1.remainingCommands ) - .setInteractive(true) + .setInteractive(isInteractive) val res = if (exec.commandLine.trim.isEmpty) newState else newState.clearGlobalLog diff --git a/sbt-app/src/sbt-test/actions/streams-trace-level/build.sbt b/sbt-app/src/sbt-test/actions/streams-trace-level/build.sbt new file mode 100644 index 000000000..c1791843d --- /dev/null +++ b/sbt-app/src/sbt-test/actions/streams-trace-level/build.sbt @@ -0,0 +1,17 @@ +lazy val helloWithoutStreams = taskKey[Unit]("") +lazy val helloWithStreams = taskKey[Unit]("") +lazy val checkTraceLevel = taskKey[Unit]("") + +helloWithoutStreams := { + throw new RuntimeException("boom without streams!") +} + +helloWithStreams := { + val log = streams.value.log + throw new RuntimeException("boom with streams!") +} + +checkTraceLevel := { + val level = traceLevel.value + assert(level != -1, s"Expected traceLevel != -1 in batch mode, but got $level") +} diff --git a/sbt-app/src/sbt-test/actions/streams-trace-level/test b/sbt-app/src/sbt-test/actions/streams-trace-level/test new file mode 100644 index 000000000..e554c4a16 --- /dev/null +++ b/sbt-app/src/sbt-test/actions/streams-trace-level/test @@ -0,0 +1,3 @@ +-> helloWithoutStreams +-> helloWithStreams +> checkTraceLevel