如何设置 SBT 构建以在 Jenkins 测试失败时返回零退出代码?

Posted

技术标签:

【中文标题】如何设置 SBT 构建以在 Jenkins 测试失败时返回零退出代码?【英文标题】:How to set up SBT build to return zero exit code on test failure for Jenkins? 【发布时间】:2014-11-14 07:14:49 【问题描述】:

当我通过 SBT 在 Jenkins 中运行我的 Specs2 测试时,一旦一个测试失败,构建就会被标记为失败。由于 Jenkins 通常会区分构建失败和测试失败,所以我想改变这一点。

我知道 Jenkins 中的构建失败是通过调用 SBT 的退出代码检测到的,只要至少有一个测试失败,该退出代码就会返回 1。

假设我想避免更改我的build.sbt(或一般项目)只是为了解决这个不便,我有哪些选择?

不知何故,我认为应该可以将标准 sbt 项目放入标准 Jenkins 安装中并使其按预期工作。

【问题讨论】:

【参考方案1】:

tl;drtestResultLogger 与不会抛出TestsFailedException 的自定义测试结果记录器一起使用,而TestsFailedException 又会设置非0 退出代码。

刚刚注意到我错过了该要求“以避免更改build.sbt。您可以使用任何其他*.sbt 文件,例如exitcodezero.sbt~/.sbt/0.13/default.sbt 与自定义testResultLogger

事实证明,由于 sbt 0.13.5 有一种方法可以产生这种行为 - 请参阅 Added setting 'testResultLogger' which allows customisation of test reporting testResultLogger 的诞生地。

> help testResultLogger
Logs results after a test task completes.

因为它可能已经在the implementation of TestResultLogger.SilentWhenNoTests 中读取,这是testResultLogger 的默认值:

results.overall match 
  case TestResult.Error | TestResult.Failed => throw new TestsFailedException
  case TestResult.Passed                    =>

这意味着当执行测试出现问题时,会抛出TestsFailedException异常,然后捕获并报告如下:

[error] Failed: Total 3, Failed 1, Errors 0, Passed 2
[error] Failed tests:
[error]         HelloWorldSpec
[error] (test:test) sbt.TestsFailedException: Tests unsuccessful

我的想法是不管执行测试的结果如何都禁止抛出异常。将以下内容添加到build.sbt 并始终使用退出代码0

testResultLogger in (Test, test) := new TestResultLogger 
    import sbt.Tests._
    def run(log: Logger, results: Output, taskName: String): Unit = 
        println("Exit code always 0...as you wish")
        // uncomment to have the default behaviour back
        // TestResultLogger.SilentWhenNoTests.run(log, results, taskName)
    

取消注释 TestResultLogger.SilentWhenNoTests.run 以恢复默认行为。

➜  failing-tests-dont-break-build  xsbt test; echo $?
JAVA_HOME=/Library/Java/JavaVirtualMachines/java8/Contents/Home
SBT_OPTS= -Xms512M -Xmx1536M -Xss1M -XX:+CMSClassUnloadingEnabled -Dfile.encoding=UTF-8
[info] Loading global plugins from /Users/jacek/.sbt/0.13/plugins
[info] Set current project to failing-tests-dont-break-build (in build file:/Users/jacek/sandbox/failing-tests-dont-break-build/)
[info] HelloWorldSpec
[info]
[info] The 'Hello world' string should
[info] x contain 11 characters
[error]    'Hello world' doesn't have size 12 but size 11 (HelloWorldSpec.scala:7)
[info]
[info] + start with 'Hello'
[info] + end with 'world'
[info]
[info] Total for specification HelloWorldSpec
[info] Finished in 15 ms
[info] 3 examples, 1 failure, 0 error
Exit code always 0...as you wish
[success] Total time: 1 s, completed Sep 19, 2014 9:58:09 PM
0

【讨论】:

感谢您的精彩解释。但是“没有在build.sbt”的动机应该更像是“不必改变项目”。 是的,这就足够了。不知道您还可以通过将东西放在那里来更改项目,而不仅仅是元项目(用于插件)。我明天试试这个。【参考方案2】:

您可以运行在始终返回 0 的包装脚本中运行测试的构建部分。(如果您在一次运行中同时运行编译和测试,则必须将其拆分,以免忽略构建错误)

【讨论】:

这是我最后的手段。但我没想过分裂。【参考方案3】:

您可以根据 Jacek Laskowski 的解决方案(至少在 sbt >= 1.2.8 中):


    testResultLogger in (Test, test) := TestResultLogger 
      (log, results, taskName) =>
        try 
          (testResultLogger in (Test, test)).value.run(log, results, taskName)
         catch 
          case _: TestsFailedException =>
            println("Ignore TestsFailedException to get exit code 0")
        
    

如果你有多模块项目,你可以将它实现为插件:

object TestExitCodePlugin extends AutoPlugin 
  override def requires = JvmPlugin

  override def trigger = allRequirements

  override def projectSettings: Seq[Def.Setting[_]] = Seq(
    testResultLogger in(Test, test) := TestResultLogger 
      (log, results, taskName) =>
        try 
          (testResultLogger in(Test, test)).value.run(log, results, taskName)
         catch 
          case _: TestsFailedException =>
            println("Ignore TestsFailedException to get exit code 0")
        
    
  )

【讨论】:

以上是关于如何设置 SBT 构建以在 Jenkins 测试失败时返回零退出代码?的主要内容,如果未能解决你的问题,请参考以下文章

如何在jenkins构建时调用sbt环境变量

如何使用 SBT Jenkins 插件运行特定测试以进行 ScalaTest 测试

设置Jenkins使用Karma和Eslint进行单元测试和Lint检查

在 Jenkins 中使 SBT 缓存的工件本地化到工作区

Jenkins 中的 Nexus 凭证与 sbt

在 build.sbt 中使用 Jenkins 内部版本号通过 sbt-native-packager 构建 RPM