我有一个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就不会检测对存储库的更改。)
答案 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禁用错误检查。
这是您可能会发现有用的模式。我们将在其中:
set +e
)bzr commit whatever
set -e
)让我们实现这一点。如果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
),转储文件。
我希望这会有所帮助。