我正在尝试从 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 退出,但没有区别。
因此我的问题是:为什么脚本的第一行可以以非零代码退出?我该如何防止这种情况?
或者也许:是否有更简单的方法来实现相同的目标?
最佳答案
Gitlab 设置了一堆你实际上并不想要的“有用”的 shell 选项。其中有 errexit
,又名 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 ,请记住,设置 shell 变量将覆盖任何预先存在的同名环境变量。
关于python - 避免在 gitlab CI 脚本管道中提前退出命令,同时仍捕获退出状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56079993/