GitLab Test Summary 详情如何显示颜色或过滤 ANSI 色码?
结论
可以保留 job 日志的颜色,在上传前单独清理 JUnit XML 中的色码。题述 Test Summary 详情页中的 #x1B[...]m 不会因为修改 TERM 而自动显示成颜色。
GitLab 公开的 JUnit 报告配置中没有启用 ANSI 颜色渲染的开关。针对题述现象,建议让测试详情显示不含色码的普通文本,不要依靠调整容器终端设置。这个判断依据公开配置和题述现象,未在 v18.10.1 实例上实测。GitLab 单元测试报告文档
为什么日志正常,测试详情却出现色码
job 日志和 Test Summary 使用不同的数据来源。Test Summary 读取 artifacts:reports:junit 指定的 XML 文件,从中提取失败信息、错误信息和测试输出。GitLab JUnit 字段说明
示例中的 #x1B 是可见文本,不是真正的 ESC 控制字符。pytest 的 JUnit 实现会将 XML 不允许的控制字符转换成这样的表示,其中 ESC 对应 #x1B。它也不是 XML 字符引用 。pytest JUnit 实现
只匹配真实 \x1b 的 ANSI 清理脚本可能无法处理这个报告,需要同时考虑真实 ESC 和 pytest 写出的 #x1B。具体是哪一个测试工具或依赖最先输出了颜色,还需要查看实际报告和调用链,不能仅凭 @allure 判断。
在上传前清理 JUnit 报告
可以在项目中新增 ci/strip_junit_colors.py,只删除报告里的 SGR 颜色和样式序列:
from pathlib import Path
import re
import sys
import xml.etree.ElementTree as ET
report = Path(sys.argv[1])
# 匹配真实 ESC 或 pytest 的可见表示 #x1B。
# 仅处理以 m 结束的 SGR 序列。
sgr = re.compile(rb"(?:\x1b|#x1[Bb])\[[0-9;:]*m")
if not report.is_file():
print(f"JUnit report not found, skipping: {report}")
else:
original = report.read_bytes()
cleaned = sgr.sub(b"", original)
# 检查清理后的 XML 能否解析,再覆盖报告。
ET.fromstring(cleaned)
report.write_bytes(cleaned)
print(f"Cleaned JUnit report: {report}")
按这个规则,题述字符串会变为:
@allure
脚本直接处理文件字节,不重新序列化 XML,因此不会主动调整报告缩进或属性顺序。XML 解析检查只能确认文件可解析,不能证明测试结果或报告内容正确。
然后将下面的 after_script 合并到 .portal-gui-base 中,保留现有的 variables、artifacts 和测试执行配置:
.portal-gui-base:
# 保留现有配置
after_script:
- python3 ci/strip_junit_colors.py "$CI_PROJECT_DIR/junit-${CI_JOB_NAME_SLUG}.xml"
执行环境需要能直接调用 python3。如果 Python 只安装在虚拟环境中,应改用对应的解释器路径。
GitLab Runner 在上传 artifacts 之前执行 after_script,修改后的报告会被后续上传。不要只把清理命令接在 pytest 后面,测试失败时,普通脚本执行可能提前停止。GitLab after_script 文档
这套处理只修改 JUnit 文件,不会改变已经写入 job 日志的彩色输出。
合并配置时需要注意什么
- 如果当前 job、父模板或子 job 已定义
after_script,需要合并清理命令,并检查最终继承配置,避免覆盖已有清理步骤。 after_script在独立 shell 中执行,不会继承主脚本临时激活的虚拟环境。使用明确的解释器路径更可靠。- 示例只处理 SGR 颜色和样式序列,并非完整的终端控制序列解析器。如果报告还包含光标控制、OSC 超链接或其他转义形式,应根据实际内容增加处理。
- 如果测试本身在验证 ANSI 字符串,过滤会改变这些字符串的展示。此时应保留原始报告副本,或限制清理范围。
after_script失败通常不会改变主脚本的退出状态,超时等情况也可能影响它的执行。若报告清理必须成功,应在主脚本中显式保存 pytest 退出码、执行清理,再按约定返回状态。GitLab after_script 执行规则
不要把 #x1B 替换回真实 ESC 来尝试恢复颜色;这可能产生不合法的 XML,也无法为详情页增加 ANSI 渲染能力。
配置完成后,运行一次包含失败用例的流水线,检查上传的 JUnit 文件和 Test Summary 详情是否已去掉色码,同时确认 job 日志仍保留颜色。
备注:内容仅供参考。
