Windows 和 Travis 上无法运行 Coverity Scan
结论
Windows 上失败的主要原因是 cov-build 无法稳定地直接启动 gradlew.bat。应改用 cmd.exe /c 调用,同时关闭 Gradle Daemon,确保编译器进程处于 cov-build 的监控范围内。
Travis 上需要满足以下条件:
- Coverity 构建命令执行了完整的重新编译;
- 当前构建可以读取
COVERITY_SCAN_TOKEN; - 当前分支匹配
branch_pattern,且构建不是无法读取加密变量的外部 Pull Request。
版本限制也需要考虑。Coverity 8.7 可以捕获 Java 编译,但这不等于它具备 Kotlin 源码分析能力。Kotlin 虽然生成 JVM 字节码,Coverity 也不会因此将其视为 Java 源码。对于 Java/Kotlin 混合项目,先确认 Java 文件能否被捕获。Kotlin 是否受支持,要看 Coverity 的版本和语言许可。
Windows 上的调用方式
先停止已有的 Gradle Daemon,因为已启动的 Daemon 不一定继承 cov-build 注入的捕获环境。
gradlew.bat --stop
配置 Java 编译器:
cov-configure --java
接着通过 cmd.exe 执行 Gradle Wrapper,并把 clean 放在捕获命令中,避免 Gradle 将编译任务判定为 UP-TO-DATE:
cov-build --dir cov-int cmd.exe /d /s /c "gradlew.bat --no-daemon clean jar"
如果只需要验证 Java 捕获,可以暂时缩小构建范围:
cov-build --dir cov-int cmd.exe /d /s /c "gradlew.bat --no-daemon clean compileJava"
各参数的作用如下:
cmd.exe /c用于执行.bat文件,可避免出现The system cannot execute the specified program.。--no-daemon让编译器进程在当前捕获进程下启动。clean要放在cov-build包裹的命令中,以触发实际编译。- 不要先完成一次完整构建,再用
cov-build执行已经没有编译任务的增量构建。
如果 compileJava 可以产生捕获结果,而 jar 或完整构建不行,应先检查 Gradle 的任务依赖关系,暂时不用排查上传流程。
检查是否捕获到 Java 文件
构建命令成功,只能说明 Gradle 没有报错,无法证明 Coverity 已捕获编译单元。先查看:
cov-int/build-log.txt
检查以下内容:
javac是否实际运行;- 日志中是否仍有
No files were emitted; - Java 编译是否被跳过,或显示为
UP-TO-DATE; - 编译任务是否交给了已有的 Gradle Daemon;
cov-configure --java使用的 JDK 是否与 Gradle 实际使用的 JDK 一致。
还需要比较这些命令的输出:
java -version
javac -version
gradlew.bat -version
where java
where javac
where cov-build
如果机器上安装了多个 JDK,请明确设置 JAVA_HOME,然后重新执行 cov-configure --java 和捕获命令。
单独检查 Kotlin 代码
Coverity 捕获的是受支持语言的编译过程。kotlinc 生成 .class 文件,不会把 Kotlin 源码转换成 Java 分析器可以处理的 Java 源码。
对于这个混合项目,可以按以下顺序检查:
- 使用
compileJava验证 Java 捕获是否正常。 - 查看
build-log.txt,确认捕获到的 Java 文件数量不为零。 - 执行包含 Kotlin 任务的完整构建。
- 查阅当前 Coverity 版本的语言支持列表,确认它是否支持项目使用的 Kotlin 版本。
如果 Coverity 8.7 不支持 Kotlin,最终报告中没有 Kotlin 问题是产品能力限制,与 Gradle 配置无关。也不要将反编译得到的 Java 文件当作 Kotlin 源码进行正式分析,否则文件位置、类型信息和告警归属都会失真。
Travis CI 配置示例
旧版 Travis Coverity Scan Add-on 可以参考以下配置。邮箱、项目名和加密 token 需要替换为项目自己的值:
language: java
jdk:
- oraclejdk8
env:
global:
- secure: "TRAVIS_ENCRYPTED_COVERITY_SCAN_TOKEN"
addons:
coverity_scan:
project:
name: "ddimtirov/nuggets"
description: "Nuggets Java/Kotlin library"
notification_email: "YOUR_EMAIL"
build_command_prepend: "./gradlew --stop || true"
build_command: "./gradlew --no-daemon clean jar"
branch_pattern: "coverity_scan"
script:
- ./gradlew --no-daemon check
然后向匹配的分支推送提交,例如:
git checkout -b coverity_scan
git push origin coverity_scan
如果需要在主分支运行,将 branch_pattern 改为实际的分支名,不要直接沿用示例中的名称。
script 中的普通测试成功,并不能说明 Coverity Add-on 已执行。只有分支匹配且 token 可用时,Add-on 才会进行捕获和上传。
Travis 构建成功但没有上传的常见原因
分支不匹配
branch_pattern 用于过滤分支。当前分支不匹配时,普通 Travis 构建仍可能成功,Coverity 步骤则会跳过。
可以在日志中搜索:
Coverity
cov-build
Uploading
如果完全找不到相关输出,通常说明 Add-on 没有触发。
加密 token 不可用
Coverity Scan token 应保存为:
COVERITY_SCAN_TOKEN
来自外部仓库的 Pull Request 通常无法读取仓库的加密环境变量。此时 Travis 仍可正常编译和测试,但无法完成 Coverity 上传。
可以在不泄露 token 的前提下检查变量是否存在:
if [ -n "$COVERITY_SCAN_TOKEN" ]; then
echo "Coverity token is available"
else
echo "Coverity token is unavailable"
fi
不要输出 token 本身。
Gradle 没有重新编译
如果任务使用了缓存或显示为 UP-TO-DATE,Coverity 就没有可捕获的编译器进程。下面的命令可以避免大多数此类问题:
./gradlew --no-daemon clean jar
诊断时也可以临时添加 --rerun-tasks:
./gradlew --no-daemon clean jar --rerun-tasks
通常无须长期保留 --rerun-tasks,因为 clean 已足以强制重新生成项目输出。
手动打包和上传
确认 cov-int 中已有有效的捕获数据后,再进行上传。可以先打包整个目录:
tar czf cov-int.tgz cov-int
上传请求通常需要项目名、token、邮箱、版本和归档文件。Coverity Scan 接口在不同时期可能有所调整,具体命令应以项目设置页当时提供的上传示例为准:
curl \
--form token="$COVERITY_SCAN_TOKEN" \
--form email="YOUR_EMAIL" \
--form file=@cov-int.tgz \
--form version="BUILD_VERSION" \
--form description="Travis CI build" \
"https://scan.coverity.com/builds?project=ddimtirov%2Fnuggets"
不要随意压缩第三方插件生成的目录。Scan 服务需要结构完整、与服务器版本兼容的 Coverity Build Capture 输出。即使插件显示“生成成功”,也不能证明归档格式、捕获器版本和服务端要求相符。
排查顺序
先在 Windows 上运行最小 Java 捕获:
gradlew.bat --stop
cov-configure --java
cov-build --dir cov-int cmd.exe /d /s /c "gradlew.bat --no-daemon clean compileJava"
确认 cov-int/build-log.txt 中存在被捕获的 Java 编译单元后,再改用:
cov-build --dir cov-int cmd.exe /d /s /c "gradlew.bat --no-daemon clean jar"
Windows 捕获正常后,再将相同的处理方式用于 Travis:关闭 Daemon、执行 clean、检查分支是否匹配以及 token 是否可用,并通过日志确认上传步骤已实际运行。
如果 Java 已经成功捕获,而 Kotlin 始终没有结果,就不必再调整 Gradle 或上传脚本。此时应核对当前 Coverity 版本是否支持 Kotlin。构建捕获、语言支持和上传是三个独立环节,需要逐项验证。
备注:内容仅供参考。
