避免在gitlab CI脚本管道中提前退出命令,同时仍然捕获退出状态

时间:2019-05-10 14:48:20

标签: python bash gitlab-ci pylint

我正在尝试在Gitlab CI脚本中从PyLint输出生成徽章。最终,如果PyLint具有非零的退出代码,则该作业将失败。但是在这样做之前,我希望创建徽章。所以我尝试了以下方法:

before_script:
    - [...]
    - mkdir -p public
script:
    - pylint lib --disable R,missing-docstring,wrong-import-order --reports=y | tee public/pylint-report.txt
    - export SUCCESS=${PIPESTATUS[0]}
    - SCORE=$(tail -n 2 public/pylint-report.txt | grep -o -P "\d\d?\.\d+\/\d*" | head -1)
    - echo "PyLint score ${SCORE}"
    - python3.6 -m pybadges --left-text=PyLint --right-text=${SCORE} > public/pylint.svg
    - exit ${SUCCESS}
artifacts:
    when: always
    [...]

如果PyLint退出代码为0,则此方法正常工作:

$ mkdir -p public
$ pylint lib --disable R,missing-docstring,wrong-import-order --reports=y | tee public/pylint-report.txt; export SUCCESS=${PIPESTATUS[0]}
[Pylint report output]
$ SCORE=$(tail -n 2 public/pylint-report.txt | grep -o -P "\d\d?\.\d+\/\d*" | head -1)
$ echo "PyLint score ${SCORE}"
PyLint score 10.00/10
$ python3.6 -m pybadges --left-text=PyLint --right-text=${SCORE} > public/pylint.svg
$ exit ${SUCCESS}
Uploading artifacts...
public/pylint-report.txt: found 1 matching files   
public/pylint.svg: found 1 matching files          
Uploading artifacts to coordinator... ok            id=XXX responseStatus=201 Created token=XXX
Job succeeded

但是,当PyLint以非零值退出时,脚本将在第一行之后中止:

$ mkdir -p public
$ pylint lib --disable R,missing-docstring,wrong-import-order --reports=y | tee public/pylint-report.txt
[Pylint report output]
Uploading artifacts...
public/pylint-report.txt: found 1 matching files   
WARNING: public/pylint.svg: no matching files      
Uploading artifacts to coordinator... ok            id=XXX responseStatus=201 Created token=XXX
ERROR: Job failed: exit code 1

为了澄清:我希望作业失败,但是我想确保脚本始终运行所有行。只有最后一行中的exit命令才能确定作业状态。

这在使用Bash的容器中运行。

我希望tee命令始终以0退出,以使第一行脚本永远不会失败。但这似乎并非如此。

我尝试将|| true调用附加到第一行,但随后的行SUCCESS=${PIPESTATUS[0]}始终为0;也许这是根本原因。

此外,我尝试将export调用(现在为第二行)追加到第一行,并用分号分隔。同样,即使我也期望export调用始终以0退出,也没什么区别。

因此,我的问题是:为什么脚本的第一行以非零代码退出?我该如何预防?

或者也许:有没有更简单的方法来实现相同的目标?

2 个答案:

答案 0 :(得分:1)

Gitlab设置了许多您实际上不需要的“有用的” shell选项。其中有errexit,aka set -epipefail(通常是个好主意,但与set -e结合使用意味着如果管道中的任何组件失败,脚本都会退出)。

要解决此问题:

{ SUCCESS=0; pylint lib ...args... || SUCCESS=$?; } > >(tee public/pylint-report.txt)

我们直接坐在SUCCESS上(不需要export),因此您以后无需再参考PIPESTATUS。分支到命令的返回值会将该命令标记为“已检查”,因此就errexit而言,它不会被视为失败。


顺便说一句,有关set -e的背景以及您为什么不真正想要它的原因,请参见BashFAQ #105

另外,全大写的变量名用于对Shell或POSIX指定的工具有意义的变量,而具有至少一个小写字符的名称保留供应用程序使用,并且保证不冲突。请参阅https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html,请记住,设置外壳程序变量将覆盖任何先前存在的类似名称的环境变量。

答案 1 :(得分:0)

根据您使用的是哪个版本的Gitlab,无论进程是否失败,使用after_script部分作为运行任意代码的替代方法,您可能会有更多的运气。

after_script用于定义将在所有作业(包括失败的作业)之后运行的命令。它必须是数组或多行字符串。”

Link