即使调用的程序之一失败,也将 Hudson 作业解释为成功

发布于 2024-11-10 02:26:01 字数 1314 浏览 6 评论 0原文

我有一份 Hudson 工作,定期合并来自上游集市存储库的更改。

目前,当上游没有更改时,Hudson 会报告此作业失败,因为 bzr commit 命令返回错误。我的脚本看起来像这样:

bzr branch lp:~lorinh/project/my-local-branch
cd my-local-branch
REV_UPSTREAM=`bzr version-info lp:project --custom --template="{revno}"`
bzr merge lp:project
bzr commit -m "merged upstream version ${REV_UPSTREAM}" 
./run_tests.sh 
bzr push lp:~lorinh/project/my-local-branch

如果没有要合并的更改,Hudson 控制台输出看起来像这样:

+ bzr branch lp:~lorinh/project/my-local-branch
Branched 807 revision(s).    
+ bzr merge lp:project
Nothing to do.
+ bzr commit -m merged upstream version 733
Committing to: /var/lib/hudson/jobs/merge-upstream/workspace/myproject/
aborting commit write group: PointlessCommit(No changes to commit)
bzr: ERROR: No changes to commit. Use --unchanged to commit anyhow.
Sending e-mails to: [email protected]
Finished: FAILURE

问题是我不希望 Hudson 将此报告为失败。如何修改我的命令,以便脚本在提交失败时终止,但 Hudson 不会将其解释为错误?我尝试将提交命令更改为:

bzr commit -m "merged upstream version ${REV_UPSTREAM}" || exit 

但这不起作用。

(注意:我意识到我可以使用 Hudson 的“轮询 SCM”而不是“定期构建”。但是,对于 bazaar,如果有人对最近修改之前完成的本地提交进行推送,那么 Hudson 将不会检测到更改到存储库。)

I have a Hudson job that periodically merges changes from an upstream bazaar repository.

Currently, when there are no changes upstream, Hudson reports this job as a failure because the bzr commit command returns with an error. My script looks like something this:

bzr branch lp:~lorinh/project/my-local-branch
cd my-local-branch
REV_UPSTREAM=`bzr version-info lp:project --custom --template="{revno}"`
bzr merge lp:project
bzr commit -m "merged upstream version ${REV_UPSTREAM}" 
./run_tests.sh 
bzr push lp:~lorinh/project/my-local-branch

If there are no changes to merge, the Hudson console output looks something like this:

+ bzr branch lp:~lorinh/project/my-local-branch
Branched 807 revision(s).    
+ bzr merge lp:project
Nothing to do.
+ bzr commit -m merged upstream version 733
Committing to: /var/lib/hudson/jobs/merge-upstream/workspace/myproject/
aborting commit write group: PointlessCommit(No changes to commit)
bzr: ERROR: No changes to commit. Use --unchanged to commit anyhow.
Sending e-mails to: [email protected]
Finished: FAILURE

The problem is that I don't want Hudson to report this as a failure. How do I modify my commands so the script terminates at the failed commit, but it isn't interpreted by Hudson as an error? I tried changing the commit command to:

bzr commit -m "merged upstream version ${REV_UPSTREAM}" || exit 

But that didn't work.

(Note: I realize I could use Hudson's "Poll SCM" instead of "Build periodically". However, with bazaar, if somebody does a push with local commits that were done before the most recent modifications, then Hudson won't detect a change to the repository.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

﹏半生如梦愿梦如真 2024-11-17 02:26:01

你们非常接近!这是您尝试的更正版本:

bzr commit -m "merged upstream version ${REV_UPSTREAM}" || exit 0

现在可以满足您的要求,但并不完美。我稍后再讲。

请注意您的版本中的微小重要变化 - 我们现在明确表示,如果 bzr 命令不这样做,我们应该以代码 0 退出(成功)。在您的版本中, exit (不带参数)将终止您的脚本,但返回最后执行的命令的退出代码 - 在本例中为 bzr 提交。

有关退出的更多信息

我们如何了解这种退出行为? exit 命令是一个内置的 shell - 要查找有关它的文档,我们使用帮助命令:

help exit

在我的机器上它告诉我:

exit: exit [n]
Exit the shell.

Exits the shell with a status of N.  If N is omitted, the exit status
is that of the last command executed.

这是一个不错的 有关 bash shell 中的退出和退出代码的教程

Hudson 和退出代码

Hudson 遵循这一常见规则解释退出代码的约定0 表示成功,任何其他代码表示失败。如果它执行的构建脚本以非零代码退出,它将把您的构建标记为失败。

为什么你的脚本在 bzr 提交后停止

如果,正如你所说,你有以下内容,并且你的脚本在 bzr 提交后停止......

bzr commit -m "merged upstream version ${REV_UPSTREAM}" 
./run_tests.sh 

我怀疑你的脚本有一条指令,例如set -e 或使用诸如 bash -e build_script.sh 之类的东西调用,

如果命令以非零状态退出,其中任何一个都会告诉 shell 立即退出,并传递相同的“失败”退出代码。 (有一些微妙之处 - 见脚注 1)。

禁用错误退出

虽然这种错误退出行为非常有用,但有时我们想暂时禁用它。您已经找到了一种方法,

bzr commit whatever || true

我们还可以使用 set +e 禁用错误检查。

您可能会发现以下有用的模式。在其中,我们将:

  1. 禁用错误退出(使用 set +e
  2. 运行可能会出错的命令 bzr commitwhat
  3. 捕获其退出代码 ($?) for < em>稍后检查
  4. 重新启用错误退出(使用set -e
  5. 测试并根据任何命令的退出代码采取行动

让我们实现它。如果 bzr 命令失败,我们将再次退出 0(成功)。

set +e
bzr commit whatever
commit_status=$?
set -e
if [[ "$commit_status" != "0" ]]; then
  echo "bzr commit finds nothing to do.  Build will stop, with success"
  exit 0
fi
echo "On we go with the rest of the build script..."

请注意,我们使用 set +e / set -e 尽可能少地括起来。如果我们在该部分的脚本中有拼写错误,他们不会停止脚本并且会出现混乱。请阅读“不充分了解 POSIX shell 功能”中的“避免 set -e”部分”以获得更多想法。

foo || 有什么问题吗? exit 0

正如我之前提到的,我们第一个提出的解决方案存在问题。我们说过,当bzr commit非零(即它没有正常提交)时,我们将总是停止并指示成功 。即使 bzr commit 由于某些其他原因(以及其他一些非零退出代码)失败,也会发生这种情况:也许您在命令调用中犯了拼写错误,或者 bzr 无法连接到回购协议。

至少在其中一些情况下,您可能希望将构建标记为失败,以便您可以采取一些措施。

寻求更好的解决方案

我们希望具体说明我们期望 bzr 提供哪些非零退出代码,以及我们将如何处理每个代码。

如果您回顾上面的 set +e / set -e 模式,应该不难将上面的条件逻辑 (if) 扩展为可以处理 bzr 中的许多特定退出代码的东西,并带有一个 catch -all 用于意外的退出代码(我建议)使构建失败并报告有问题的代码和命令。

要查找任何命令的退出代码,请阅读文档或运行命令,然后运行 ​​echo $? 作为下一个命令。 $?保存前一个命令的退出代码。

脚注 1:使用 set -e 切换的错误退出行为有一些您需要阅读的微妙之处,涉及命令在管道、条件语句和其他结构中时的行为。

You were very close! Here's the corrected version of what you were trying:

bzr commit -m "merged upstream version ${REV_UPSTREAM}" || exit 0

This now does what you asked for, but isn't perfect. I'll get to that later.

Note the tiny important change from your version - we are now being explicit that we should exit with code 0 (success), if the bzr command does not do so. In your version, exit (with no argument) will terminate your script but return the exit code of the last command executed - in this case the bzr commit.

More about exit

How do we find out about this behaviour of exit? The exit command is a shell built-in - to find documentation on it we use the help command:

help exit

Which on my machine tells me:

exit: exit [n]
Exit the shell.

Exits the shell with a status of N.  If N is omitted, the exit status
is that of the last command executed.

Here's a decent tutorial on exit and exit codes in the bash shell

Hudson and exit codes

Hudson follows this common convention of interpreting exit code 0 as success, and any other code as failure. It will flag your build as a failure if the build script it executes exits with a non-zero code.

Why your script is stopping after the bzr commit

If, as you say, you have the following and your script is stopping after the bzr commit...

bzr commit -m "merged upstream version ${REV_UPSTREAM}" 
./run_tests.sh 

... I suspect your script has an instruction such as set -e or is being invoked with something like bash -e build_script.sh

Either of these tells the shell to exit immediately if a command exits with a non-zero status, and to pass along that same "failure" exit code. (There are subtleties - see footnote 1).

Disabling exit-on-error

While this behaviour of exiting on error is extremely useful, sometimes we'd like to disable it temporarily. You've found one way, in

bzr commit whatever || true

We can also disable the error-checking with set +e.

Here's a pattern you may find useful. In it we will:

  1. Disable exit-on-error (with set +e)
  2. run the command which may error bzr commit whatever
  3. capture its exit code ($?) for later inspection
  4. Re-enable exit-on-error (with set -e)
  5. Test and act upon the exit code of any commands

Let's implement that. Again we'll exit 0 (success) if the bzr command failed.

set +e
bzr commit whatever
commit_status=$?
set -e
if [[ "$commit_status" != "0" ]]; then
  echo "bzr commit finds nothing to do.  Build will stop, with success"
  exit 0
fi
echo "On we go with the rest of the build script..."

Note that we bracket as little as possible with set +e / set -e. If we have typos in our script in that section, they won't stop the script and there'll be chaos. Read the section "Avoiding set -e" in the post "Insufficiently known POSIX shell features" for more ideas.

What's wrong with foo || exit 0 ?

As I mentioned earlier, there's a problem with our first proposed solution. We've said that when bzr commit is non-zero (i.e. it doesn't commit normally) we'll always stop and indicate success. This will happen even if bzr commit fails for some other reason (and with some other non-zero exit code): perhaps you've made a typo in your command invocation, or bzr can't connect to the repo.

In at least some of these cases, you'd probably want the build to be flagged as a failure so you can do something about it.

Towards a better solution

We want to be specific about which non-zero exit codes we expect from bzr, and what we'll do about each.

If you look back at the set +e / set -e pattern above, it shouldn't be difficult to expand the conditional logic (if) above into something that can deal with a number of specific exit codes from bzr, and with a catch-all for unanticipated exit codes which (I suggest) fails the build and reports the offending code and command.

To find out the exit codes for any command, read the docs or run the command and then run echo $? as the next command. $? holds the exit code of the previous command.

Footnote 1: The exit-on-error behaviour switched with set -e has some subtleties you'll need to read up on, concerning behaviour when commands are in pipelines, conditional statements and other constructs.

捶死心动 2024-11-17 02:26:01

鉴于 bzr 似乎没有发出正确的退出代码(基于您的 bzr ... || exit 示例),一种解决方案是捕获 bzr 的输出,然后扫描 ERROR 或其他。

 bzr commit -m "merged upstream version ${REV_UPSTREAM}" 2>&1 | tee /tmp/bzr_tmp.$

 case $( < /tmp/bzr_tmp.$ ) in
   *ERROR* ) 
     printf "error running bzr, found error msg = $(< /tmp/bzr_tmp.$)\n"
     exit 1
   ;;
   * )
     : # everything_OK this case target
       # just to document the default action of 'nothing' ;-)
   ;;
 esac

根据您的示例输出,一个稍微简单的案例目标正则表达式将是 *FAILURE ) ...

$( < file ) 是 shell 的一项新功能,您可以将其视为 $(cat file),但在使用进程资源方面更有效,因为它不需要启动新进程(cat)来转储文件。

我希望这有帮助。

given that bzr doesn't seem to emit a correct exit code (based on you bzr ... || exit example), one solution is to capture the output of bzr and then scan for ERROR or other.

 bzr commit -m "merged upstream version ${REV_UPSTREAM}" 2>&1 | tee /tmp/bzr_tmp.$

 case $( < /tmp/bzr_tmp.$ ) in
   *ERROR* ) 
     printf "error running bzr, found error msg = $(< /tmp/bzr_tmp.$)\n"
     exit 1
   ;;
   * )
     : # everything_OK this case target
       # just to document the default action of 'nothing' ;-)
   ;;
 esac

A slightly easier case target regex, based on your sample output, would be *FAILURE ) ....

the $( < file ) is a newer feature of the shell that you can think of as $(cat file), but is more efficient in use of process resources, as it doesn't need to launch a new process (cat), to dump a file.

I hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文