如果执行 shell 失败,不要让 jenkins 构建失败

Posted

技术标签:

【中文标题】如果执行 shell 失败,不要让 jenkins 构建失败【英文标题】:don't fail jenkins build if execute shell fails 【发布时间】:2013-01-01 18:36:28 【问题描述】:

作为构建过程的一部分,我将 git commit 作为执行 shell 步骤运行。但是,如果工作区中没有任何更改,则 Jenkins 会导致构建失败。这是因为 git 在没有要提交的更改时返回错误代码。如果是这种情况,我想中止构建,或者将其标记为不稳定。有什么想法吗?

【问题讨论】:

检查是否有什么要提交的,只在那些情况下提交? ***.com/questions/5139290/… 【参考方案1】:

命令失败时停止进一步执行:

command || exit 0

命令失败时继续执行:

command || true

【讨论】:

第一种情况下不需要|| exit 0,如果command返回false,执行将停止。也就是说,第二个选项非常有帮助! @alfasin 你不明白这个问题。 OP 不希望 Jenkins 构建失败;因此我们必须exit 0,因为任何非零退出代码都会导致构建失败。 我明白了,在这种情况下,我会将措辞从:“命令失败时停止进一步执行:”更改为:“命令失败时停止进一步执行并将 Jenkins 作业标记为成功:”。 @alfasin 虽然我同意 Quolonel Questions 的轻率言论是不专业的,但他说的话是对的。 “exit 0”不会标记作业成功。它只会标记当前构建步骤成功。该作业仍可能在接下来的构建步骤之一中失败。 @noamik 你是对的!我正在处理只有一步“执行外壳”的工作,因此产生了误解。感谢您的澄清!【参考方案2】:

Jenkins 默认使用/bin/sh -xe 执行shell 构建步骤。 -x 表示打印执行的每个命令。 -e 表示如果脚本中的任何命令失败,则退出失败。

所以我认为在您的情况下发生的情况是您的 git 命令以 1 退出,并且由于默认的 -e 参数,shell 会选择非 0 退出代码,忽略脚本的其余部分并标记步骤作为失败。如果您可以在此处发布构建步骤脚本,我们可以确认这一点。

如果是这种情况,你可以尝试输入#!/bin/sh,这样脚本就会在没有选项的情况下执行;或在构建步骤之上执行set +e 或类似操作来覆盖此行为。


已编辑:另外需要注意的是,如果您的 shell 脚本中的最后一条命令返回非 0 代码,整个构建步骤仍将被标记为失败即使使用此设置。在这种情况下,您可以简单地在末尾添加一个true 命令来避免这种情况。

Another related question

【讨论】:

【参考方案3】:

如果没有推送 git 返回退出状态 1. Execute shell build step 分别标记为失败。您可以使用 OR 语句 || (双管)。

git commit -m 'some messasge' || echo 'Commit failed. There is probably nothing to commit.'

这意味着,如果第一次失败(返回退出状态> 0),则执行第二个参数。第二个命令总是返回 0。当没有东西可以推送时(退出状态 1 -> 执行第二个命令),echo 将返回 0 并继续构建步骤。

要将构建标记为不稳定,您可以使用构建后步骤 Jenkins 文本查找器。它可以通过控制台输出,匹配模式(你的回声)并将构建标记为不稳定。

【讨论】:

【参考方案4】:

还有另一种流畅的方法可以告诉 Jenkins 不要失败。 您可以在构建步骤中隔离您的提交并将 shell 设置为不失败:

set +e
git commit -m "Bla."
set -e

【讨论】:

请确保在您要运行的命令之后添加set -e,而不考虑退出代码。否则,您最终可能会执行您不打算执行的命令。我想自己处理错误,所以我做了类似的事情:` set +e commit -m "bla" EXIT_CODE="$?" set -e # 处理退出代码逻辑 `【参考方案5】:

This answer 是正确的,但它没有指定 || exit 0|| true 进入 shell 命令中。这是一个更完整的例子:

sh "adb uninstall com.example.app || true"

上述方法可行,但以下方法将失败:

sh "adb uninstall com.example.app" || true

也许这对其他人来说是显而易见的,但我浪费了很多时间才意识到这一点。

【讨论】:

这对我帮助很大!谢谢老兄。【参考方案6】:

Jenkins 通过步骤的返回值来确定步骤的成功/失败。对于 shell 的情况,它应该是最后一个值的返回。对于 Windows CMD 和 (POSIX) Bash shell,您应该能够使用 exit 0 作为最后一个命令手动设置返回值。

【讨论】:

这似乎不适用于有 2 行的“执行 windows bat”: git commit -m "message" exit 0 @Ben 我在我的 Windows Jenkins 安装的多个构建中使用 exit 0 和“执行 windows 批处理命令”,它按预期工作。一定有别的事情发生。您能否发布控制台日志的相关部分? 您在第一步中是否将它与 git commit -m "blah" 一起使用?我尝试在机器上手动创建一个 bat 脚本,并在 git 命令之后放置一个 echo 和一个 exit 0。当没有要提交的内容时,其他任何命令都不会运行... 见@xiawei 的回答。 Jenkins 的默认行为是使用 #!/bin/sh -xv 执行 shell,如果遇到任何错误,则会导致脚本停止。【参考方案7】:

我能够使用此处找到的答案来完成这项工作:

How to git commit nothing without an error?

git diff --quiet --exit-code --cached || git commit -m 'bla'

【讨论】:

上面的内容是:“执行git diff 命令,如果失败,执行git commit 命令。基本上,如果git diff 找到要提交的内容,它只会提交。但是@jwernerny 的回答是正确的,您应该能够将exit 0 作为最后一条语句添加到任何脚本以使Jenkins 将其视为成功。我可以想到一种情况,如果您正在执行Linux shell 步骤,这将失败,但是在批处理中,这应该始终有效。 @Ben Jenkins 默认使用/bin/sh -xe 执行shell 构建步骤,如here 所述(在中间)。因此,您可以尝试将#!/bin/bashset +e 放在构建步骤的顶部以覆盖此行为,这将继续该步骤的其余部分,即使退出中的一个命令使用非0代码【参考方案8】:

关于标题中的(更一般的)问题 - 为了防止 Jenkins 失败,您可以阻止它看到退出代码 1。ping 示例:

bash -c "ping 1.2.3.9999 -c 1; exit 0"

现在你可以例如获取 ping 的输出:

output=`bash -c "ping 1.2.3.9999 -c 1; exit 0"`

当然,您可以使用任何命令来代替ping ...,包括git commit

【讨论】:

【参考方案9】:

https://jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#sh-shell-script

如果包含 returnStatus: true 属性,则忽略 shell 返回。

【讨论】:

【参考方案10】:

您可以使用Text-finder Plugin。它将允许您检查输出控制台以获取您选择的表达式,然后将构建标记为Unstable

【讨论】:

这看起来很有希望,但由于某种原因,它一直在构建失败。【参考方案11】:

对于多个shell命令,我通过添加忽略失败:

set +e commands true

【讨论】:

我一般不鼓励取消设置 -e。如果要忽略某些特定命令的返回值,可以加上“|| true”或者更有意义的返回true,如:stop-service.sh || echo 服务已经关闭【参考方案12】:

如果你把这个命令放到 shell 块中:

false
true

您的构建将被标记为失败(至少 1 个非零退出代码),因此您可以添加 (set +e) 以忽略它:

set +e
false
true

不会失败。但是,即使使用 (set +e) 也会失败:

set +e
false

因为最后一个 shell 命令必须以 0 退出。

【讨论】:

【参考方案13】:

以下内容适用于 mercurial,仅在有更改时才提交。所以只有在提交失败时构建才会失败。

hg id | grep "+" || exit 0
hg commit -m "scheduled commit"

【讨论】:

【参考方案14】:

另一个带有一些提示的答案,可能对某人有所帮助:

记得分开你的命令with the following rule:

command1 && command2 - 表示只有在 command1 成功时才会执行 command2

command1 ; command2 - 表示命令 2 将被执行,尽管 command1 有结果

例如:

String run_tests = sh(script: "set +e && cd ~/development/tests/ && gmake test ;set -e;echo 0 ", returnStdout: true).trim()
println run_tests 

如果gmake test 失败(您的测试失败),将使用set -eecho 0 命令成功执行,同时以下代码被剪断:

String run_tests = sh(script: "set +e && cd ~/development/tests/ && gmake test && set -e && echo 0 ", returnStdout: true).trim()
println run_tests 

有点错误,&& gmake test && set -e && echo 0 中的命令 set -eecho 0 将被跳过,使用 println run_tests 语句,因为失败的 gmake test 将中止 jenkins 构建。作为解决方法,您可以切换到 returnStatus:true,但您会错过命令的输出。

【讨论】:

以上是关于如果执行 shell 失败,不要让 jenkins 构建失败的主要内容,如果未能解决你的问题,请参考以下文章

jenkins跳过shell执行错误

Knife bootstrap 通过 Jenkins 执行 shell 失败

jenkins执行shell脚本,使用scp免密传输失败问题

jenkins执行shell脚本,使用scp免密传输失败问题

构建步骤“执行 shell”在 Jenkins CI 上将构建标记为失败,没有任何错误

如何利用jenkins git shell脚本自动部署服务