你如何在sbt中组成任务?

pur*_*efn 7 scala sbt

我正在尝试构建一个自定义任务,用于在我们的持续集成环境中构建项目.这是一系列的步骤

  1. 将构建开始消息发送到聊天室
  2. 编译模板
  3. 运行npm测试
  4. 运行jshint
  5. 构建应用程序工件
  6. 将工件上载到我们的部署服务器
  7. 运行测试
  8. 将测试结果发送到我们的部署服务器
  9. 将构建结果消息发送到聊天室

请注意,如果任何步骤失败,则应该执行步骤10,并且应根据哪个步骤失败来自定义消息,例如,如果步骤5失败,则应说"编译失败",如果步骤8失败,则应说明运行了多少测试并且多少失败了.

为了使事情更有趣,这是一个多项目构建,因此在运行测试和发布结果时,它应该运行所有测试并发布聚合结果.

为了使事情变得更有趣,npm测试,jshint和工件只webapp在Javascript存在且Web服务器所在的子项目中才有意义.

我一直在寻找sbt-release的灵感,但我在如何获取一个任务产生的值并在下一个任务中使用它,如何在聚合中运行任务并获得生成的值(我看到一个方法Extracted来运行集中的任务,但它并没有给生产值),如何在一个子项目运行任务,并获得生产价值,以及如何做错误处理.

到目前为止,我尝试了两种方法

npmTest.result.value match {                                                                    
  case Inc(inc) =>                                                                              
    println(inc)                                                                                
  case Value(res) => Def.taskDyn {                                                              
    (executeTests in Test).result.value match {                                                 
      case Inc(inc) =>                                                                          
        println(inc)                                                                            
      case Value(res) =>                                                                        
        println(res)                                                                            
    }                                                                                           
  }
Run Code Online (Sandbox Code Playgroud)

上述问题是executeTests即使npmTest失败也始终运行.并且没有一个println被执行.

npmTest.result.                                                                                    
 flatMap {-                                                                                       
   case Inc(inc) =>                                                                               
     task { println(inc) }                                                                        
   case Value(res) =>-                                                                            
     (executeTests in Test).result.                                                               
       flatMap {                                                                                  
         case Inc(inc) =>                                                                         
           task { println(inc) }                                                                  
         case Value(res) =>                                                                       
           task { println(res) }                                                                  
       }                                                                                          
 }                
Run Code Online (Sandbox Code Playgroud)

这个不编译因为(executeTasks in Test)...产生一个Initialize[Task[Unit]]值而且Task[Unit]是必需的.

有没有办法用sbt完成这个?

pur*_*efn 4

我找到了一个解决方案,允许您使用旧的flatMapmap编写任务。

sealed abstract class Step[A] {
  def run: Def.Initialize[Task[Result[A]]]
  def map[B](f: A => B): Step[B]
  def flatMap[B](f: A => Step[B]): Step[B]
}

object Step {
  val thisProjectRef = settingKey(Keys.thisProjectRef)
  val clean = taskKey(Keys.clean)
  val compile = taskKey(Keys.compile.in(Compile))
  val assembly = taskKey(sbtassembly.AssemblyPlugin.autoImport.assembly)

  private[this] def apply[A](task: Def.Initialize[Task[Result[A]]]): Step[A] =
    new Step[A] {
      val run = task

      def map[B](f: A => B): Step[B] =
        apply[B](Def.taskDyn {
          run.value match {
            case Inc(inc) => Def.task(Inc(inc): Result[B])
            case Value(a) => Def.task(Value(f(a)))
          }
        })

      def flatMap[B](f: A => Step[B]): Step[B] =
        apply[B](Def.taskDyn {
          run.value match {
            case Inc(inc) => Def.task(Inc(inc): Result[B])
            case Value(a) => Def.task(f(a).run.value)
          }
        })
    }

  def task[A](t: Def.Initialize[Task[A]]): Step[A] =
    apply(t.result)

  def taskKey[A](t: TaskKey[A]): Step[A] =
    apply(Def.task(t.result.value))

  def settingKey[A](s: SettingKey[A]): Step[A] =
    apply(Def.task(s.value).result)
}
Run Code Online (Sandbox Code Playgroud)

然后你可以将你的任务定义为

    rainicornPublish <<= {
      val result = 
        for {
          ass <- Step.assembly
          juri <- uploadAssemblyTask(ass)
          to <- runAllTests
          _ <- finish(ass, juri, to)
        } yield (ass, to)

      Def.task(result.run.value match {
        case Inc(inc) => throw new RainicornException(None)
        case Value(v) => v
      })
    }
Run Code Online (Sandbox Code Playgroud)

每个任务都会按顺序发生,正如您所期望的那样。