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

标签 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 退出,但没有区别。

因此我的问题是:为什么脚本的第一行可以以非零代码退出?我该如何防止这种情况?

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

最佳答案

Gitlab 设置了一堆你实际上并不想要的“有用”的 shell 选项。其中有 errexit,又名 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 ,请记住,设置 shell 变量将覆盖任何预先存在的同名环境变量。

关于python - 避免在 gitlab CI 脚本管道中提前退出命令,同时仍捕获退出状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56079993/

相关文章:

python - 无法使用 Puppet 设置 Python 3 的安装目录

python - 带有生成器的 Python 中的 DFS 算法

linux - 在没有root权限的情况下安装zsh?

linux - 你能用 bash/sh 脚本 quine 写一个简单的每周提醒吗?

GitLab CI/CD 管道,部署到 Windows Server

python - 在 Python 中进行堆排序以寻求建议

macos - 如何在一个语句中为一个命令定义两个别名

gradle - Gitlab:构建后apk的位置

Gitlab-ci 多仓库触发一次构建

python - 使用 for 循环附加到 Pandas 中的空数据框