my build.gradle
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.excludes = [
'**/databinding/*Binding.*',
'**/R.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Test*.*',
'android/**/*.*',
'**/*$ViewInjector*.*',
'**/*$ViewBinder*.*',
'**/Lambda$*.class',
'**/Lambda.class',
'**/*Lambda.class',
'**/*Lambda*.class',
'**/*_MembersInjector.class',
'**/Dagger*Component*.*',
'**/*Module_*Factory.class',
'**/di/module/*',
'**/*_Factory*.*',
'**/*Module*.*',
'**/*Dagger*.*',
'**/*Hilt*.*',
// kotlin
'**/*MapperImpl*.*',
'**/*$ViewInjector*.*',
'**/*$ViewBinder*.*',
'**/BuildConfig.*',
'**/*Component*.*',
'**/*BR*.*',
'**/Manifest*.*',
'**/*$Lambda$*.*',
'**/*Companion*.*',
'**/*Module*.*',
'**/*Dagger*.*',
'**/*Hilt*.*',
'**/*MembersInjector*.*',
'**/*_MembersInjector.class',
'**/*_Factory*.*',
'**/*_Provide*Factory*.*',
'**/*Extensions*.*'
]
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.2.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20"
classpath 'com.google.gms:google-services:4.4.0'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.9'
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:4.0.0.2929"
classpath "org.jacoco:org.jacoco.core:0.8.8"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
plugins {
id 'com.google.dagger.hilt.android' version '2.44' apply false
id 'org.jetbrains.kotlin.android' version '1.6.21' apply false
id "org.sonarqube" version "4.0.0.2929"
id 'jacoco'
}
sonar {
properties {
property "sonar.projectKey", "***************"
property "sonar.projectName", "*************"
property "sonar.qualitygate.wait", true
property "sonar.sources", "src/main/java"
property "sonar.sourceEncoding", "UTF-8"
property "sonar.tests", ["src/test/java"]
property "sonar.test.inclusions", "**/*Test*/**"
property "sonar.java.coveragePlugin", 'jacoco'
property "sonar.coverage.jacoco.xmlReportPaths", "${project.buildDir}/reports/jacoco/jacoco.xml"
property "sonar.exclusions", excludes
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
my jacoco.gradle
apply plugin: 'jacoco'
jacoco {
toolVersion = "0.8.8"
}
project.afterEvaluate {
if (android.hasProperty("applicationVariants")) {
android.applicationVariants.all { variant ->
createVariantCoverage(variant)
}
} else if (android.hasProperty("libraryVariants")) {
android.libraryVariants.all { variant ->
createVariantCoverage(variant)
}
}
}
def createVariantCoverage(variant) {
def variantName = variant.name
def testTaskName = "test${variantName.capitalize()}UnitTest"
// Add unit test coverage tasks
tasks.create(name: "${testTaskName}Coverage", type: JacocoReport, dependsOn: "$testTaskName") {
group = "Reporting"
description = "Generate Jacoco coverage reports for the ${variantName.capitalize()} build."
reports {
xml.required = true
csv.required = false
xml.destination file("${buildDir}/reports/jacoco/jacoco.xml")
}
def javaClasses = fileTree(dir: variant.javaCompileProvider.get().destinationDir, excludes: excludes)
def kotlinClasses = fileTree(dir: "${buildDir}/tmp/kotlin-classes/${variantName}", excludes: excludes)
getClassDirectories().setFrom(files([javaClasses, kotlinClasses]))
getSourceDirectories().setFrom(files([
"$project.projectDir/src/main/java",
"$project.projectDir/src/${variantName}/java",
"$project.projectDir/src/main/kotlin",
"$project.projectDir/src/${variantName}/kotlin"
]))
getExecutionData().setFrom(files("${project.buildDir}/outputs/unit_test_code_coverage/${variantName}UnitTest/${testTaskName}.exec"))
doLast {
def m = new File("${project.buildDir}/reports/jacoco/${testTaskName}Coverage/html/index.html")
.text =~ /Total[^%]*>(\d?\d?\d?%)/
if (m) {
println "Test coverage: ${m[0][1]}"
}
}
}
// Add unit test coverage verification tasks
tasks.create(name: "${testTaskName}CoverageVerification", type: JacocoCoverageVerification, dependsOn: "${testTaskName}Coverage") {
group = "Reporting"
description = "Verifies Jacoco coverage for the ${variantName.capitalize()} build."
violationRules {
rule {
limit {
minimum = 0
}
}
rule {
element = 'BUNDLE'
limit {
counter = 'LINE'
value = 'COVEREDRATIO'
minimum = 0.00
}
}
}
def javaClasses = fileTree(dir: variant.javaCompileProvider.get().destinationDir, excludes: excludes)
def kotlinClasses = fileTree(dir: "${buildDir}/tmp/kotlin-classes/${variantName}", excludes: excludes)
getClassDirectories().setFrom(files([javaClasses, kotlinClasses]))
getSourceDirectories().setFrom(files([
"$project.projectDir/src/main/java",
"$project.projectDir/src/${variantName}/java",
"$project.projectDir/src/main/kotlin",
"$project.projectDir/src/${variantName}/kotlin"
]))
getExecutionData().setFrom(files("${project.buildDir}/outputs/unit_test_code_coverage/${variantName}UnitTest/${testTaskName}.exec"))
}
}
my gitlab.-ci.yml
# This file is a template, and might need editing before it works on your project.
# To contribute improvements to CI/CD templates, please follow the Development guide at:
# https://docs.gitlab.com/ee/development/cicd/templates.html
# This specific template is located at:
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Android.gitlab-ci.yml
# Read more about this script on this blog post https://about.gitlab.com/2018/10/24/setting-up-gitlab-ci-for-android-projects/, by Jason Lenny
# If you are interested in using Android with FastLane for publishing take a look at the Android-Fastlane template.
image: eclipse-temurin:17-jdk-jammy
variables:
# ANDROID_COMPILE_SDK is the version of Android you're compiling with.
# It should match compileSdkVersion.
ANDROID_COMPILE_SDK: "33"
# ANDROID_BUILD_TOOLS is the version of the Android build tools you are using.
# It should match buildToolsVersion.
ANDROID_BUILD_TOOLS: "33.0.2"
# It's what version of the command line tools we're going to download from the official site.
# Official Site-> https://developer.android.com/studio/index.html
# There, look down below at the cli tools only, sdk tools package is of format:
# commandlinetools-os_type-ANDROID_SDK_TOOLS_latest.zip
# when the script was last modified for latest compileSdkVersion, it was which is written down below
ANDROID_SDK_TOOLS: "9477386"
# Packages installation before running script
before_script:
- apt-get --quiet update --yes
- apt-get --quiet install --yes wget unzip
# Setup path as android_home for moving/exporting the downloaded sdk into it
- export ANDROID_HOME="${PWD}/android-sdk-root"
# Create a new directory at specified location
- install -d $ANDROID_HOME
# Here we are installing androidSDK tools from official source,
# (the key thing here is the url from where you are downloading these sdk tool for command line, so please do note this url pattern there and here as well)
# after that unzipping those tools and
# then running a series of SDK manager commands to install necessary android SDK packages that'll allow the app to build
- wget --no-verbose --output-document=$ANDROID_HOME/cmdline-tools.zip https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_TOOLS}_latest.zip
- unzip -q -d "$ANDROID_HOME/cmdline-tools" "$ANDROID_HOME/cmdline-tools.zip"
- mv -T "$ANDROID_HOME/cmdline-tools/cmdline-tools" "$ANDROID_HOME/cmdline-tools/tools"
- export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/cmdline-tools/tools/bin
# Nothing fancy here, just checking sdkManager version
- sdkmanager --version
# use yes to accept all licenses
- yes | sdkmanager --licenses > /dev/null || true
- sdkmanager "platforms;android-${ANDROID_COMPILE_SDK}"
- sdkmanager "platform-tools"
- sdkmanager "build-tools;${ANDROID_BUILD_TOOLS}"
# Not necessary, but just for surity
- chmod +x ./gradlew
stages: # List of stages for jobs, and their order of execution
- build
- test
- deploy
- code-quality
# Basic android and gradle stuff
# Check linting
#lintDebug:
# interruptible: true
# stage: build
# allow_failure: true
# script:
# - ./gradlew -Pci --console=plain :app:lintDevDebug -PbuildDir=lint
# artifacts:
# paths:
# - app/lint/reports/lint-results-debug.html
# expose_as: "lint-report"
# when: always
# only:
# - master
# Make Project
assembleQA:
interruptible: true
stage: build
script:
- ./gradlew assembleQaRelease
artifacts:
paths:
- app/build/outputs/
# only:
# - master
assembleStaging:
stage: deploy
environment:
name: staging
needs:
- assembleQA
when: manual
script:
- ./gradlew assembleStagingRelease
artifacts:
paths:
- app/build/outputs/
only:
- master
assembleSandbox:
stage: deploy
environment:
name: sandbox
needs:
- assembleQA
when: manual
script:
- ./gradlew assembleSandboxRelease
artifacts:
paths:
- app/build/outputs/
only:
- master
assembleProduction:
stage: deploy
environment:
name: production
needs:
- assembleQA
when: manual
script:
- ./gradlew assembleProductionRelease
artifacts:
paths:
- app/build/outputs/
only:
- master
# Run all tests, if any fails, interrupt the pipeline(fail it)
debugTests:
needs: [assembleQA]
interruptible: true
stage: test
script:
- ./gradlew testDevDebugUnitTestCoverageVerification
# only:
# - master
sonar-qube:
stage: code-quality
variables:
SONAR_USER_HOME: "${CI_PROJECT_DIR}/.sonar" # Defines the location of the analysis task cache
GIT_DEPTH: "0" # Tells git to fetch all the branches of the project,required by the analysis task
cache:
key: "${CI_JOB_NAME}"
paths:
- .sonar/cache
allow_failure: true
script: ./gradlew sonar
# only:
# - master
When i run command .\gradlew testDevDebugUnitTestCoverageVerification in my AndroidStudio terminal I can see the xml report file is generated under app/build/reports/jacoco path but in my CI when the job code-quality runs sonarqube reports error saying
No coverage report can be found with sonar.coverage.jacoco.xmlReportPaths=‘/builds//builds/radiusxrllc/radius-xr-android/build/reports/jacoco/jacoco.xml’. Using default locations: target/site/jacoco/jacoco.xml,target/site/jacoco-it/jacoco.xml,build/reports/jacoco/test/jacocoTestReport.xml
I need help