spray / sbt-revolver

An SBT plugin for dangerously fast development turnaround in Scala
Apache License 2.0
850 stars 54 forks source link

Fails to run in test configuration scope despite correct test:reStart::mainClass #82

Open ches opened 6 years ago

ches commented 6 years ago

For esoteric reasons (but reasonable ones can probably be imagined), I have some projects with executable classes living in the sbt test configuration. test:run works fine and show test:reStart::mainClass is set as expected, but running it fails. Here is a trivial reproduction:

$ mkdir -p /tmp/revolver-test/{project,src/test/scala}

$ cd /tmp/revolver-test

$ echo 'sbt.version = 1.0.4' > project/build.properties

$ echo 'addSbtPlugin("io.spray" % "sbt-revolver"  % "0.9.1")' > project/plugins.sbt

$ cat <<'EOF' >> src/test/scala/Hello.scala
> object Hello extends App {
>   println("Hello, world!")
> }
> EOF

$ sbt test:reStart
[info] Loading settings from plugins.sbt ...
[info] Loading global plugins from /Users/cmartin/.sbt/1.0/plugins
[info] Loading settings from plugins.sbt ...
[info] Loading project definition from /private/tmp/revolver-test/project
[info] Set current project to revolver-test (in build file:/private/tmp/revolver-test/)
[info] Application revolver-test not yet started
[error] java.lang.RuntimeException: No main class detected!
[error]     at scala.sys.package$.error(package.scala:27)
[error]     at spray.revolver.Actions$.$anonfun$startApp$2(Actions.scala:38)
[error]     at scala.Option.getOrElse(Option.scala:121)
[error]     at spray.revolver.Actions$.startApp(Actions.scala:38)
[error]     at spray.revolver.Actions$.restartApp(Actions.scala:30)
[error]     at spray.revolver.RevolverPlugin$.$anonfun$settings$6(RevolverPlugin.scala:58)
[error]     at scala.Function1.$anonfun$compose$1(Function1.scala:44)
[error]     at sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:42)
[error]     at sbt.std.Transform$$anon$4.work(System.scala:64)
[error]     at sbt.Execute.$anonfun$submit$2(Execute.scala:257)
[error]     at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:16)
[error]     at sbt.Execute.work(Execute.scala:266)
[error]     at sbt.Execute.$anonfun$submit$1(Execute.scala:257)
[error]     at sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:167)
[error]     at sbt.CompletionService$$anon$2.call(CompletionService.scala:32)
[error]     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[error]     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
[error]     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
[error]     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
[error]     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
[error]     at java.lang.Thread.run(Thread.java:745)
[error] (*:reStart) No main class detected!
[error] Total time: 0 s, completed Dec 28, 2017 1:11:50 AM
ches commented 6 years ago

Not certain yet how this might be achieved in plugins, or if there's a better way, but a workaround is to duplicate the task definition inConfig(Test):

lazy val hello = (project in file("."))
  .settings(
    inConfig(Test) {
      import spray.revolver.Actions._

      reStart := Def.inputTask{
        restartApp(
          streams.value,
          reLogTag.value,
          thisProjectRef.value,
          reForkOptions.value,
          (mainClass in reStart).value,
          (fullClasspath in reStart).value,
          reStartArgs.value,
          startArgsParser.parsed
        )
      }.dependsOn(products in Compile).evaluated
    }
  )

Unfortunately with this ~test:reStart triggered execution doesn't watch main source files, tried many forms of watchSources and couldn't resolve that yet. Edit: this part is possibly sbt's fault, seems like there were a slew of file watch regressions in 1.0.x, follow the rabbit hole from sbt/io#102 and sbt/io#82).