2015-10-03 24 views
7

Sto cercando di creare un'attività personalizzata per la creazione del nostro progetto nel nostro ambiente di integrazione continua. Si tratta di una serie di passi lungo le linee diCome si compongono le attività in sbt?

  1. Invia accumulo iniziato messaggio a una chat room modelli
  2. compilazione
  3. test NPM Run
  4. Run jshint
  5. Compile
  6. Corporatura applicazione artefatto
  7. Carica artefatto sul server di distribuzione
  8. Esegui test
  9. inviare i risultati dei test al nostro server di distribuzione
  10. Invia costruire risultati messaggio in una chat room

Si noti che il passaggio 10 dovrebbe essere fatto se tutte le misure falliscono, e il messaggio deve essere personalizzato a seconda di quale passaggio non riuscito, per esempio se il passaggio 5 fallisce dovrebbe dire "Compilazione fallita", se il passo 8 fallisce dovrebbe dire quanti test sono stati eseguiti e quanti falliti.

Per rendere le cose più interessanti, si tratta di una build a più progetti, quindi quando si eseguono test e si pubblicano i risultati, è necessario eseguire tutti i test e pubblicare risultati aggregati.

Per rendere le cose ancora più interessanti, i test npm, jshint e artefatto hanno davvero senso solo nel sottoprogetto webapp, in cui risiede Javascript e il server web.

Ho guardato a sbt-release per l'ispirazione, ma sono ostacolato su come prendere il valore prodotto da un'attività e usarlo nel prossimo, come eseguire attività in aggregato e ottenere i valori prodotti (Vedo un metodo in Extracted per eseguire attività aggregate, ma non fornisce valori prodotti), come eseguire attività in un sottoprogetto e ottenere il valore prodotto e come gestire gli errori.

Finora ho provato due approcci

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

Il problema con quanto sopra è che executeTests viene sempre eseguito, anche se npmTest fallisce. E nessuno degli println s viene eseguito.

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

Questo non compilato perché (executeTasks in Test)... produce un valore Initialize[Task[Unit]] è richiesta una Task[Unit].

C'è un modo per ottenere questo risultato con sbt?

+0

Solo un pensiero: si potrebbe prendere in considerazione solo la scrittura di uno script di shell. Esiste una stretta necessità che tutto ciò avvenga con il framework di sbt? –

+0

Come scritto, la domanda è terribilmente ampia. È difficile sapere come rispondere ad altri che non dire leggere il manuale, e se rimani bloccato su qualcosa di specifico, apri una o più domande qui e mostra il tuo codice. –

+0

Attualmente stiamo usando un po 'di uno script di shell hackerato. Il problema è che le informazioni interessanti, ad esempio, la compilazione non è riuscita? quanti test sono stati eseguiti/falliti? non sono così facilmente disponibili. Quello che ho cercato di fare finora è qualcosa sulla falsariga di 'sendBuildStart.flatMap ((compila in Compila) .result.flatMap {case Inc (inc) => sendCompileFailure (inc); case Value (_) => (test in Test) .result.flatMap {case Inc (inc) => sendTestFailed (inc); caso Valore (_) => .... 'sfortunatamente non sembra che venga eseguito niente. – purefn

risposta

4

Ho trovato una soluzione che consente di utilizzare il buon vecchio flatMap e map per comporre attività.

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

Quindi è possibile definire i compiti

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

E ogni compito accadrà in sequenza, proprio come ci si aspetterebbe.

+0

Fatelo come comando e Project.ru nScarica fino in fondo. – pfn

+0

@pfn Questo è l'approccio che ho intrapreso. Aggiornerò la mia risposta – purefn

Problemi correlati