在 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

的 shell 脚本

-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启动的进程会被杀死的问题

jenkins:Send files or execute commands over SSH使用方式【原创】

远程(jenkins)调用shell 不能正常结束

在 jenkins 中运行命令 shell

在Jenkins中配置执行远程shell命令