GitLab Runner中sed命令执行异常 无法正确提取测试覆盖率
GitLab Runner环境下npm测试覆盖率提取脚本失效修复
问题现象
编写脚本执行npm run test并捕获测试覆盖率数值,目标是提取输出中总覆盖率的36.95数值,作为GitLab Job的输出内容。
本地环境执行脚本可正常返回提取到的36.95,经确认使用的GitLab Runner为GNU版本,但在Runner上运行时会直接返回npm run test的原始输出,无法完成数值提取,需要适配当前Runner环境。
初始失效脚本如下:
RES=$(npm test -- --coverage --watchAll=false) TOTAL=$(sed -E 's/^.* All files \| ([^ ]+) \| .*$/\1/' <<< $RES) echo "Current test coverage is : " $TOTAL
初步判断here-string(<<<)语法与Runner运行环境不兼容,也不排除脚本本身存在编写问题。当前使用的GitLab Pipeline配置如下:
test: stage: test image: node:16.13.1 before_script: - npm i - npx node -v - npx npm -v script: - echo "running test coverage" - bash test.sh
其中test.sh文件内容即为上述用于提取测试覆盖率的脚本。
根因分析
- Jest的覆盖率报告默认输出到stderr而非stdout,原脚本仅捕获stdout内容,在容器环境下没有拿到覆盖率表格数据,自然无法提取数值,本地环境能跑是因为本地npm/shell配置默认将stderr重定向到了stdout
- here-string(
<<<)是Bash专属语法,部分精简版容器镜像内的Bash实现存在兼容问题,且如果脚本缺少明确shebang头,存在被POSIX sh(node镜像默认是dash)解析的可能,会直接语法失效 - 原sed匹配规则写死了空格数量,不同终端宽度下jest输出的表格对齐空格数变化,会导致匹配失败
修复方案
修改test.sh内容为以下版本即可:
#!/bin/bash # 同时捕获stdout、stderr的所有输出 RES=$(npm test -- --coverage --watchAll=false 2>&1) # 用POSIX标准管道语法替换here-string,适配所有shell环境 # 优化正则匹配规则,兼容任意数量的对齐空白字符 TOTAL=$(echo "$RES" | sed -E 's/^.*All files[[:space:]]+\|[[:space:]]+([0-9]+\.[0-9]+)[[:space:]]+\|.*$/\1/') echo "Current test coverage is : $TOTAL"
修复点说明:
- 脚本开头加
#!/bin/bashshebang头,明确指定解释器,避免被其他shell解析 - 重定向配置加
2>&1,将stderr输出合并到stdout,确保覆盖率表格内容能被完整捕获到变量中 - 用管道写法替换here-string语法,兼容所有POSIX标准shell,不存在版本兼容问题
- 优化sed匹配规则,用
[[:space:]]+匹配任意数量的对齐空白字符,适配不同输出宽度下的表格格式
原有GitLab Pipeline配置不需要额外修改,保持原有逻辑即可正常运行。
内容的提问来源于stack exchange,提问作者leo
相关产品推荐
相关产品推荐

