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

时间:2011-05-24 19:08:04

标签: bash hudson bazaar

我有一个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: me@example.com
Finished: FAILURE

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

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

但那没用。

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

2 个答案:

答案 0 :(得分:4)

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

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

这就是你所要求的,但并不完美。我稍后会谈到的。

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

有关退出的详情

我们如何了解这种退出行为? exit命令是内置的shell - 要查找文档,我们使用help命令:

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.

这是一个不错的tutorial on exit and exit codes in the 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 commit whatever
  3. 的命令
  4. 获取以后的退出代码($?)检查
  5. 重新启用错误退出(使用set -e
  6. 测试并执行任何命令的退出代码
  7. 让我们实现这一点。如果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尽可能少地括起来。如果我们在该部分的脚本中有拼写错误,它们将不会停止脚本并且会出现混乱。阅读帖子“Insufficiently known POSIX shell features”中的“避免设置-e”部分以获取更多想法。

    foo || exit 0出了什么问题?

    正如我前面提到的,我们首次提出的解决方案存在问题。我们已经说过,当bzr commit非零时(即它没有正常提交),我们总是停止并指示成功。即使bzr commit由于某些其他原因(以及其他一些非零退出代码)失败,也会发生这种情况:也许您在命令调用中输了一个错字,或者bzr无法连接到repo。 / p>

    至少在某些情况下,您可能希望将构建标记为失败,以便您可以对其执行某些操作。

    寻求更好的解决方案

    我们希望具体说明我们期望从bzr获得哪些非零退出代码,以及我们将对每种代码做些什么。

    如果你回顾上面的set + e / set -e模式,将上面的条件逻辑(if)扩展为可以处理来自bzr的许多特定退出代码的东西并不困难,对于未预料到的退出代码进行全面检查(我建议),这些退出代码会使构建失败并报告有问题的代码和命令。

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

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

答案 1 :(得分:1)

鉴于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),转储文件。

我希望这会有所帮助。