我正在尝试在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退出,也没什么区别。
因此,我的问题是:为什么脚本的第一行以非零代码退出?我该如何预防?
或者也许:有没有更简单的方法来实现相同的目标?
答案 0 :(得分:1)
Gitlab设置了许多您实际上不需要的“有用的” shell选项。其中有errexit
,aka set -e
和pipefail
(通常是个好主意,但与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
用于定义将在所有作业(包括失败的作业)之后运行的命令。它必须是数组或多行字符串。”