You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android项目集成JaCoCo与Coveralls(GitHub Action):覆盖率报告不显示

Android项目集成Coveralls.io覆盖率报告不显示问题排查

问题描述

在Android项目中使用JaCoCo生成代码覆盖率报告,通过Coveralls Gradle插件上传至Coveralls.io。GitHub Action工作流执行无报错,但Coveralls.io平台始终提示‘There have been no builds for this repo.’,无法查看覆盖率报告。

环境概述

JaCoCo: 生成代码覆盖率报告
Coveralls Gradle Plugin: 上传报告至Coveralls.io
GitHub Actions: 执行CI/CD流程

GitHub Action工作流配置

name: CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:
runs-on: macos-latest

steps:
  - uses: actions/checkout@v2
    with:
      fetch-depth: 0
  - name: Execute unit tests
    run: ./gradlew createDebugCoverageReport

  - name: Report Coveralls
    run: ./gradlew coverallsJacoco

build.gradle配置

plugins {
    alias(libs.plugins.android.application)
    alias(libs.plugins.jetbrains.kotlin.android)
    jacoco
    alias(libs.plugins.coveralls.jacoco)
}

android {
    namespace = "io.demo.coveralldemo"
    compileSdk = 34

    defaultConfig {
        applicationId = "io.demo.coveralldemo"
        minSdk = 24
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"

        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
        vectorDrawables {
            useSupportLibrary = true
        }
    }
    testOptions {
        unitTests.all {

        }
        unitTests.isReturnDefaultValues = true
    }
    buildTypes {

        debug {
            enableUnitTestCoverage = true
            isMinifyEnabled = false
        }
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_1_8
        targetCompatibility = JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = "1.8"
    }
    buildFeatures {
        compose = true
    }
    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.1"
    }
    packaging {
        resources {
            excludes += "/META-INF/{AL2.0,LGPL2.1}"
        }
    }
}

dependencies {

    implementation(libs.androidx.core.ktx)
    implementation(libs.androidx.lifecycle.runtime.ktx)
    implementation(libs.androidx.activity.compose)
    implementation(platform(libs.androidx.compose.bom))
    implementation(libs.androidx.ui)
    implementation(libs.androidx.ui.graphics)
    implementation(libs.androidx.ui.tooling.preview)
    implementation(libs.androidx.material3)
    testImplementation(libs.junit)
    androidTestImplementation(libs.androidx.junit)
    androidTestImplementation(libs.androidx.espresso.core)
    androidTestImplementation(platform(libs.androidx.compose.bom))
    androidTestImplementation(libs.androidx.ui.test.junit4)
    debugImplementation(libs.androidx.ui.tooling)
    debugImplementation(libs.androidx.ui.test.manifest)
    testImplementation(libs.kotlinx.coroutines.test)
    testImplementation (libs.androidx.core.testing)
}
apply("$rootDir/jacoco.gradle.kts")
coverallsJacoco {
    reportPath = "${buildDir}/reports/coverage/test/debug/index.html"
}

jacoco.gradle.kts配置

apply(plugin = "jacoco")

tasks.register<JacocoReport>("jacocoTestReport") {
    dependsOn(tasks["testDebugUnitTest"])

    reports {
        xml.required.set(true)
        html.required.set(true)
    }

    val fileFilter = listOf(
        "**/R.class",
        "**/R$*.class",
        "**/BuildConfig.*",
        "**/Manifest*.*",
        "**/*Test*.*"
    )
    val debugTree = fileTree(mapOf("dir" to "$buildDir/intermediates/javac/debug", "excludes" to fileFilter))
    val mainSrc = "$projectDir/src/main/java"

    sourceDirectories.setFrom(files(mainSrc))
    classDirectories.setFrom(files(debugTree))
    executionData.setFrom(fileTree(mapOf("dir" to "$buildDir", "includes" to listOf(
        "jacoco/testDebugUnitTest.exec",
        "outputs/code-coverage/connected/*coverage.ec"
    ))))
}

构建日志

构建日志

排查与解决方案

1. 配置Coveralls仓库令牌

Coveralls插件需要令牌验证身份,当前工作流未传递该变量:

  • 从Coveralls.io的仓库设置页面获取COVERALLS_REPO_TOKEN
  • 在GitHub仓库的Settings > Secrets and variables > Actions中添加该令牌
  • 修改GitHub Action步骤,传递环境变量:
    - name: Report Coveralls
      run: ./gradlew coverallsJacoco
      env:
        COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
    

2. 修正Coveralls插件的报告路径

插件要求上传XML格式的覆盖率报告,而非HTML。修改build.gradle中的配置:

coverallsJacoco {
    reportPath = "${buildDir}/reports/jacoco/jacocoTestReport/jacocoTestReport.xml"
}

3. 确保Jacoco报告任务被执行

自定义的jacocoTestReport任务未被触发,需在上传前执行:

- name: Generate JaCoCo report
  run: ./gradlew jacocoTestReport
- name: Report Coveralls
  run: ./gradlew coverallsJacoco
  env:
    COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}

4. 修复Jacoco报告的class文件路径

Kotlin项目的class文件存放在kotlin/debug目录,而非javac/debug,调整jacoco.gradle.kts:

val debugTree = fileTree(mapOf(
    "dir" to "$buildDir/intermediates/kotlin/debug",
    "excludes" to fileFilter
)) + fileTree(mapOf(
    "dir" to "$buildDir/intermediates/javac/debug",
    "excludes" to fileFilter
))

5. 验证报告文件是否生成

添加步骤检查报告文件是否存在,确认Jacoco任务执行正常:

- name: Check report files
  run: |
    ls -la ${GITHUB_WORKSPACE}/app/build/reports/jacoco/jacocoTestReport/
    ls -la ${GITHUB_WORKSPACE}/app/build/reports/coverage/test/debug/

6. 检查插件版本兼容性

确保libs.plugins.coveralls.jacoco引用最新版本,避免与Gradle、JaCoCo版本冲突。

内容的提问来源于stack exchange,提问作者Jitendra Prajapati

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 22:14:58