PAYATHON 2026

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 源码。

对于这个混合项目,可以按以下顺序检查:

  1. 使用 compileJava 验证 Java 捕获是否正常。
  2. 查看 build-log.txt,确认捕获到的 Java 文件数量不为零。
  3. 执行包含 Kotlin 任务的完整构建。
  4. 查阅当前 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。构建捕获、语言支持和上传是三个独立环节,需要逐项验证。

备注:内容仅供参考。