2015-10-03 48 views
7

我正在嘗試在持續集成環境中構建我們的項目的自定義任務。這是一組沿着你如何在sbt中撰寫任務?

  1. 發送構建的線的步驟開始的消息到聊天室
  2. 編譯模板
  3. 運行NPM測試
  4. 運行jshint
  5. 編譯
  6. 構建應用程序的神器
  7. 將工件上傳到我們的部署服務器
  8. 運行測試
  9. 測試結果發送到我們的部署服務器
  10. 發送構建結果消息,聊天室

注意一步,如果有任何步驟失敗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)                    
    }                       
    } 

的問題與上面是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) }                 
     }                       
}     

這一個不編譯因爲(executeTasks in Test)...產生Initialize[Task[Unit]]值並且需要Task[Unit]

有沒有辦法用sbt來完成這個?

+0

只是想一想:你可能會考慮編寫一個shell腳本。有沒有嚴格的需要這一切發生在sbt的框架? –

+0

正如所寫,這個問題非常廣泛。除了閱讀說明書之外,很難知道如何回答,如果您遇到某些特定問題,請在此處打開一個或多個問題並顯示您的代碼。 –

+0

我們目前正在使用一些被黑客入侵的shell腳本。問題在於有趣的信息,例如編譯失敗了嗎?有多少測試運行/失敗?並不容易獲得。到目前爲止,我嘗試做的是沿着'sendBuildStart.flatMap((在Compile中編譯).result.flatMap {case Inc(inc)=> sendCompileFailure(inc); case Value(_)=> test in test).result.flatMap {case Inc(inc)=> sendTestFailed(inc); case Value(_)=> ....'不幸的是,似乎沒有任何東西可以運行 – purefn

回答

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) 
} 

然後,你可以定義你的任務

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 
     }) 
    } 

而且每個任務將按順序發生,就像你期望的那樣。

+0

做它作爲一個命令和Project.ru n一路下來。 – pfn

+0

@pfn這是我最終採取的方法。我會更新我的答案。 – purefn