Repository: scala-steward-org/scala-steward
Pull request #3125 (2023-07-19 19:59:04)

Improve error message on overlong lines in `process.slurp`
This wraps the `fs2.text.LineTooLongException` that is thrown by `fs2.text.linesLimited` which is used in `process.slurp` to enrich the error message with more helpful information.

Instead of this:
```
2023-07-19 15:34:45,215 ERROR Steward scala-steward-org/test-repo-1 failed
fs2.text$LineTooLongException: Max line size is 50 but 79 chars have been accumulated
	at fs2.text$.$anonfun$linesImpl$1(text.scala:553)
	...
```
we now get this:
```
2023-07-19 16:02:41,546 ERROR Steward scala-steward-org/test-repo-1 failed
org.scalasteward.core.io.process$ProcessLineTooLongException: 'mvn --batch-mode dependency:list -DexcludeTransitive=true' outputted a line longer than 50 chars. If the process executed normally and the buffer size is just too small, you can increase it with the --max-buffer-size command-line option and/or open a pull request in https://github.com/scala-steward-org/scala-steward that increases the default buffer size.
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------------< com.mycompany.app:my-app >----------------------
[INFO] Building my-app 1.0-SNAPSHOT
	at org.scalasteward.core.io.process$$anonfun$1.applyOrElse(process.scala:69)
	...
Caused by: fs2.text$LineTooLongException: Max line size is 50 but 65 chars have been accumulated
	at fs2.text$.$anonfun$linesImpl$1(text.scala:553)
	...
```
which includes
 * the command that led to the exception
 * the reason why this exception was raised (outputted line is too long)
 * guidance how to avoid it
 * the output of the process before the exception is raised
 * the original exception

This change was motivated by the unhelpful error shown in https://github.com/scala-steward-org/scala-steward-action/pull/505#issuecomment-1641906143.


Patch:
diff --git a/modules/core/src/main/scala/org/scalasteward/core/io/process.scala b/modules/core/src/main/scala/org/scalasteward/core/io/process.scala
index 7c108fad..5f97afcc 100644
--- a/modules/core/src/main/scala/org/scalasteward/core/io/process.scala
+++ b/modules/core/src/main/scala/org/scalasteward/core/io/process.scala
@@ -64,8 +64,11 @@ object process {
         val raiseError = F.raiseError[List[String]] _
 
         val result =
-          readLinesIntoBuffer(process.getInputStream, buffer, maxBufferSize, log).flatMap {
-            maxSizeExceeded =>
+          readLinesIntoBuffer(process.getInputStream, buffer, maxBufferSize, log)
+            .adaptErr { case t: fs2.text.LineTooLongException =>
+              new ProcessLineTooLongException(args, buffer, maxBufferSize, t)
+            }
+            .flatMap { maxSizeExceeded =>
               F.blocking(process.waitFor()).flatMap { exitValue =>
                 if (maxSizeExceeded && !args.slurpOptions(SlurpOption.IgnoreBufferOverflow))
                   raiseError(new ProcessBufferOverflowException(args, buffer, maxBufferSize))
@@ -74,7 +77,7 @@ object process {
                 else
                   raiseError(new ProcessFailedException(args, buffer, exitValue))
               }
-          }
+            }
 
         val onTimeout = F.blocking(process.destroyForcibly()) >>
           raiseError(new ProcessTimedOutException(args, buffer, timeout))
@@ -133,18 +136,32 @@ object process {
       .through(fs2.text.utf8.decode)
       .through(fs2.text.linesLimited(maxBufferSize))
 
+  private val bufferOverflowMessage =
+    s"If the process executed normally and the buffer size is just too small, you can " +
+      s"increase it with the --${Cli.name.maxBufferSize} command-line option and/or open " +
+      s"a pull request in ${org.scalasteward.core.BuildInfo.gitHubUrl} that increases the " +
+      s"default buffer size."
+
   final class ProcessBufferOverflowException(
       args: Args,
       buffer: ListBuffer[String],
       maxBufferSize: Int
   ) extends IOException(makeMessage(args, buffer) {
-        s"outputted more than $maxBufferSize lines. " +
-          s"If the process executed normally and the buffer size is just too small, you can " +
-          s"increase it with the --${Cli.name.maxBufferSize} command-line option and/or open " +
-          s"a pull request in ${org.scalasteward.core.BuildInfo.gitHubUrl} that increases the " +
-          s"default buffer size."
+        s"outputted more than $maxBufferSize lines. $bufferOverflowMessage"
       })
 
+  final class ProcessLineTooLongException(
+      args: Args,
+      buffer: ListBuffer[String],
+      maxBufferSize: Int,
+      cause: fs2.text.LineTooLongException
+  ) extends IOException(
+        makeMessage(args, buffer) {
+          s"outputted a line longer than $maxBufferSize chars. $bufferOverflowMessage"
+        },
+        cause
+      )
+
   final class ProcessFailedException(
       args: Args,
       buffer: ListBuffer[String],


Test patch:
diff --git a/modules/core/src/test/scala/org/scalasteward/core/io/processTest.scala b/modules/core/src/test/scala/org/scalasteward/core/io/processTest.scala
index 1c4f1369..d2beec13 100644
--- a/modules/core/src/test/scala/org/scalasteward/core/io/processTest.scala
+++ b/modules/core/src/test/scala/org/scalasteward/core/io/processTest.scala
@@ -2,7 +2,6 @@ package org.scalasteward.core.io
 
 import cats.effect.IO
 import cats.effect.unsafe.implicits.global
-import fs2.text.LineTooLongException
 import munit.FunSuite
 import org.scalasteward.core.io.process._
 import org.scalasteward.core.util.{DateTimeAlg, Nel}
@@ -47,7 +46,7 @@ class processTest extends FunSuite {
   test("echo: fail, line length > buffer size") {
     val Left(t) =
       slurp3(Nel.of("echo", "-n", "123456"), 4, Set.empty).attempt.unsafeRunSync()
-    assert(clue(t).isInstanceOf[LineTooLongException])
+    assert(clue(t).isInstanceOf[ProcessLineTooLongException])
   }
 
   test("ls: ok") {