在 Jenkins 中,Execute Shell 如何/何时将构建标记为失败?
Posted
技术标签:
【中文标题】在 Jenkins 中,Execute Shell 如何/何时将构建标记为失败?【英文标题】:How/When does Execute Shell mark a build as failure in Jenkins? 【发布时间】:2014-05-13 22:04:19 【问题描述】:我在寻找这个答案的过程中发现的恐怖故事......
好的,我有一个 .sh 脚本,它几乎可以完成 Jenkins 应该做的所有事情:
查看来自 SVN 的源代码 构建项目 部署项目 自行清理所以在 Jenkins 中,我只需要通过在 Execute Shell 命令中运行脚本来“构建”项目。 脚本已运行(源已下载,项目正在构建/部署),但随后它将构建标记为失败: 构建步骤“执行 shell”将构建标记为失败 即使脚本运行成功!我尝试关闭脚本:
退出 0(仍将其标记为失败) 退出 1(按预期将其标记为失败) 根本没有退出命令(将其标记为失败)Execute Shell 何时、如何以及为何将我的构建标记为失败?
【问题讨论】:
【参考方案1】:首先,将鼠标悬停在下方的灰色区域上。不是答案的一部分,但绝对必须说:
如果你有一个 shell 脚本可以自己“检查、构建、部署”,那么你为什么要使用 Jenkins?您前面提到了 Jenkins 的所有特性,使其成为现在的样子。 您也可以使用 cron 或 SVN 提交后挂钩直接调用脚本。 Jenkins 执行 SVN 结账本身是至关重要的。它允许仅在发生更改时触发构建(或在计时器上,或手动,如果您愿意)。它跟踪构建之间的更改。它显示了这些更改,因此您可以查看哪个构建针对哪组更改。它会在提交者的更改导致构建成功或失败时向提交者发送电子邮件(同样,根据您的喜好进行配置)。当他们的修复修复了失败的构建时,它将向提交者发送电子邮件。而且越来越多。 Jenkins 归档工件也使它们在每次构建时都可以直接从 Jenkins 获得。虽然不如 SVN 结帐那么重要,但它再次成为 Jenkins 不可或缺的一部分。与部署相同。除非您只有一个环境,否则部署通常会发生在多个环境中。 Jenkins 可以通过使用 Promotions 来跟踪部署了特定构建(具有特定的 SVN 更改集)的环境。你在这一切之前。听起来你被告知“你必须使用 Jenkins”,但你并不想这样做,你这样做只是为了让你的老板远离你,只是为了打勾“是的,我用过 Jenkins”
简短的回答是:Jenkin Execute Shell构建步骤的last命令的退出代码决定了构建步骤的成功/失败。 0
- 成功,anything else
- 失败。
请注意,这是确定构建步骤的成功/失败,而不是整个作业运行。整个作业运行的成功/失败可能会进一步受到多个构建步骤以及构建后操作和插件的影响。
您提到了Build step 'Execute shell' marked build as failure
,所以我们将只关注一个构建步骤。如果您的 Execute shell 构建步骤只有一行调用您的 shell 脚本,那么您的 shell 脚本的退出代码将决定构建步骤的成功/失败。如果您有更多行,在您的 shell 脚本执行之后,然后仔细检查它们,因为它们可能会导致失败。
最后,请在此处阅读 Jenkins Build Script exits after Google Test execution。它与您的问题没有直接关系,但请注意关于 Jenkins 启动 Execute Shell 构建步骤的部分,作为带有 /bin/sh -xe
-e
表示 shell 脚本将退出失败,即使只有 1 个命令失败,甚至如果您对该命令进行错误检查(因为脚本在进行错误检查之前退出)。这与shell脚本的正常执行相反,shell脚本通常会打印失败命令的错误消息(或将其重定向为null并通过其他方式处理),然后继续。
要避免这种情况,请将 set +e
添加到 shell 脚本的顶部。
既然您说您的脚本完成了它应该做的所有事情,那么失败的命令很可能在脚本末尾的某个地方。也许是最后的回声?还是某处的文物副本?没有看到完整的控制台输出,我们只是在猜测。
请发布作业运行的控制台输出,最好也发布 shell 脚本本身,然后我们可以准确地告诉您哪一行出错了。
【讨论】:
我还不清楚我仍然使用 Jenkins 的原因......似乎高层的某个人不太了解我们已经有了这个脚本并坚持我们使用 Jenkins。我觉得我在呆伯特地带。感谢您的 -e 提示。它解决了问题 仍然有充分的理由使用 Jenkins:审计跟踪、构建状态可见性等。如果您已经有一个构建脚本,那么在重构它以利用它之前,将其移动到 Jenkins 是一个很好的第一步Jenkins 功能。 交叉链接此答案serverfault.com/a/143576/186454 set +e 和 set -e 可以在脚本中的任何位置指定。如果返回值不为 0,则中间的任何代码都不会导致构建失败。 shell script vs jenkins set 说得很好 我们使用 jenkins 来提供经过身份验证的访问权限和用于作业的 UI。一个cron不会削减它。 Jenkins 不只是运行脚本。【参考方案2】:对您的问题的简单而简短的回答是
请在“执行 shell”构建步骤中添加以下行。
#!/bin/sh
现在让我解释一下为什么我们需要这一行来执行“Execute Shell”构建作业。
默认情况下,Jenkins 采用/bin/sh -xe
,这意味着-x
将打印每个命令。另一个选项-e
,当任何命令以非零值退出时(当任何命令失败)退出代码。
所以通过添加#!/bin/sh
将允许您在没有选项的情况下执行。
【讨论】:
赞成。不知道 -xe 默认值。当我的 grep 命令找不到字符串时,我的整个脚本都失败了,因为 grep 返回了一个非 0 的返回值:) 效果很好!在我的非关键步骤中使用它,一个清理步骤,它只是做类似find . -name 'bower_components' -exec rm \;
的事情,在某些情况下,它失败了。谢谢!
这清除了一切 - '还有另一个选项 -e,当任何命令以非零(当任何命令失败时)退出代码退出时,它会导致 shell 立即停止运行脚本。' 【参考方案3】:
在我看来,关闭 shell 的 -e
选项是一个非常糟糕的主意。最终,由于磁盘空间不足或网络错误等临时情况,脚本中的命令之一将失败。没有-e
Jenkins 不会注意到并会继续愉快地继续前进。如果您设置了 Jenkins 来进行部署,这可能会导致错误的代码被推送并导致您的网站瘫痪。
如果您的脚本中有一行预期会失败,例如 grep 或 find,则只需在该行的末尾添加 || true
。这样可以确保该行将始终返回成功。
如果您需要使用该退出代码,您可以将该命令提升到您的 if 语句中:
grep foo bar; if [ $? == 0 ]; then ... --> if grep foo bar; then ...
或者您可以在||
子句中捕获返回码:
grep foo bar || ret=$?
【讨论】:
谢谢布莱恩。你拯救了我的一天。另外,我认为同时打开 -x 和 -e 是个好主意。这样您就可以在 jenkins 日志中看到。【参考方案4】:简单明了:
如果 Jenkins 看到构建步骤(也是一个脚本)以非零代码退出,则构建会用红球标记(= 失败)。
为什么会发生这种情况取决于您的构建脚本。
我从另一个角度写了类似的东西,但无论如何阅读它可能会有所帮助: Why does Jenkins think my build succeeded?
【讨论】:
【参考方案5】:所以通过添加#!/bin/sh
将允许您在没有选项的情况下执行。
它还帮助我解决了我在我的 Linux 从站上从 Jenkins 主站执行 bash 脚本的问题。只需在“Execute Shell”块中我的实际脚本上方添加#!/bin/bash
,它就解决了我的问题,否则它正在执行 Windows git 提供的 bash shell 版本,它给出了错误。
【讨论】:
【参考方案6】:我已经尝试了所有提到的选项(甚至在没有 -xe 参数的情况下将 sh 更改为 bash),唯一对我有用的选项是:
<command-which-returns-not-zero> || exit 0
【讨论】:
【参考方案7】:在 Jenkins 版本中。 1.635,不可能像这样显示原生环境变量:
$BUILD_NUMBER or $BUILD_NUMBER
在这种情况下,您必须将其设置在其他变量中。
set BUILDNO = $BUILD_NUMBER
$BUILDNO
【讨论】:
以上是关于在 Jenkins 中,Execute Shell 如何/何时将构建标记为失败?的主要内容,如果未能解决你的问题,请参考以下文章
jenkin 不必要的Execute shell执行失败,导致jenkins都失败的解决
jenkins中通过execute shell启动的进程会被杀死的问题