我正在尝试构建一个自定义任务,用于在我们的持续集成环境中构建我们的项目。这是一组沿着以下路线的步骤
请注意,如果任何步骤失败,则应执行步骤 10,并且应根据失败的步骤自定义消息,例如如果第 5 步失败,它应该说“编译失败”,如果第 8 步失败,它应该说运行了多少测试以及失败了多少。
为了让事情变得更加有趣,这是一个多项目构建,因此在运行测试和发布结果时,它应该运行所有测试并发布聚合结果。
更有趣的是,npm 测试、jshint 和 artifact 只在
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
都没有s 被执行。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来完成这个?
最佳答案
我找到了一个解决方案,可以让您使用旧的 flatMap
和 map
来编写任务。
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
})
}
每个任务都会按顺序发生,正如您所期望的那样。
关于scala - 你如何在 sbt 中编写任务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32928384/