I ran the following gradle tasks locally on my machine and successfully got the analysis results on sonar cloud for that branch:
./gradlew clean :app:assembleStaging variantCoverage lintStaging detekt -PignoreFailures sonar
where variantCoverage simply executes unit tests and generates the jacoco XML report.
Going to sonar cloud afterwards correctly shows the unit test information, any detect issues as well as the code scanned (correctly with both our /java dirs). However, when the same tasks are executed via GitHub actions, the scan completes successfully and I do see a result on sonar cloud, but this time, there does not seem to be any info on coverage, unit tests and the code tab is empty. Is that due to the previous scan that occurred (and no different results being available) or is sonar unable to scan the source dirs?
Here’s the YML file for reference and the sonar setup:
name: SonarCloud Analysis
on:
pull_request:
branches: [ "my branches" ]
types: [ opened, synchronize, reopened, ready_for_review, assigned ]
workflow_dispatch:
inputs:
variant:
description: 'Android variant to analyze'
required: false
default: "staging"
options:
- Options..
permissions:
pull-requests: write
contents: read
env:
VARIANT: ${{ github.event.inputs.variant || 'staging' }}
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
jobs:
setup:
name: Setup Environment & Cache
runs-on: ubuntu-latest
outputs:
gradle-key: ${{ steps.gradle-cache-key.outputs.key }}
steps:
- uses: actions/checkout@v4
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v2
- name: Compute Gradle Cache Key
id: gradle-cache-key
run: echo "key=${{ runner.os }}-gradle-$(sha1sum **/*.gradle* **/gradle-wrapper.properties | sha1sum | cut -d' ' -f1)" >> "$GITHUB_OUTPUT"
- name: Cache Gradle
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
~/.gradle/caches/build-cache-1
key: ${{ steps.gradle-cache-key.outputs.key }}
restore-keys: |
${{ runner.os }}-gradle-
build-and-test:
name: Build & Test
runs-on: 8vcpu-32GB-x64-ubuntu
needs: setup
timeout-minutes: 80
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: 17
distribution: 'zulu'
- uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
~/.gradle/caches/build-cache-1
key: ${{ needs.setup.outputs.gradle-key }}
- run: ./gradlew clean
- run: ./gradlew :app:assemble${{ env.VARIANT }} variantCoverage --no-daemon --stacktrace --info
- name: Test Summary
uses: test-summary/action@v2
if: always()
with:
paths: "**/build/test-results/test**/TEST-*.xml"
show: "always" # ensures summary appears even if tests fail
comment_mode: "always" # posts or updates a PR comment automatically
- name: Upload Test Results
uses: actions/upload-artifact@v4
if: always()
with:
name: test-results
path: '**/build/test-results/test*/*.xml'
retention-days: 1
- name: Upload Coverage Reports
uses: actions/upload-artifact@v4
if: always()
with:
name: coverage-reports
path: '**/build/reports/jacoco/**/*.xml'
retention-days: 1
- name: Upload Build Outputs
uses: actions/upload-artifact@v4
if: always()
with:
name: build-outputs
path: |
**/build/intermediates/javac/**/classes/**
**/build/tmp/kotlin-classes/**
**/build/intermediates/compile_*_jar_classes/**
**/build/classes/**
retention-days: 1
lint:
name: Android Lint
runs-on: 8vcpu-32GB-x64-ubuntu
needs: setup
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: 17
distribution: 'zulu'
- uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
~/.gradle/caches/build-cache-1
key: ${{ needs.setup.outputs.gradle-key }}
- run: ./gradlew lint${{ env.VARIANT }} --no-daemon --stacktrace --info
- name: Upload Lint Report
uses: actions/upload-artifact@v4
if: always()
with:
name: lint-report
path: '**/build/reports/lint-results-*.xml'
retention-days: 1
detekt:
name: Detekt Static Analysis
runs-on: 8vcpu-32GB-x64-ubuntu
needs: setup
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: 17
distribution: 'zulu'
- uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
~/.gradle/caches/build-cache-1
key: ${{ needs.setup.outputs.gradle-key }}
- run: ./gradlew detekt -PignoreFailures --no-daemon --stacktrace --info
- name: Upload Detekt Report
uses: actions/upload-artifact@v4
if: always()
with:
name: detekt-report
path: '**/build/reports/detekt/detekt.xml'
retention-days: 1
sonar:
name: SonarCloud Analysis
needs: [ build-and-test, lint, detekt ]
runs-on: ubuntu-latest
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
steps:
- uses: actions/checkout@v4
- uses: gradle/wrapper-validation-action@v2
- uses: actions/setup-java@v4
with:
java-version: 17
distribution: 'zulu'
- uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
~/.gradle/caches/build-cache-1
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- uses: actions/cache@v4
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: |
${{ runner.os }}-sonar
- name: Download Test Results
uses: actions/download-artifact@v4
with:
name: test-results
path: .
- name: Download Coverage Reports
uses: actions/download-artifact@v4
with:
name: coverage-reports
path: .
- name: Download Build Outputs
uses: actions/download-artifact@v4
with:
name: build-outputs
path: .
- name: Download Detekt Report
uses: actions/download-artifact@v4
with:
name: detekt-report
path: .
- name: Download Lint Report
uses: actions/download-artifact@v4
with:
name: lint-report
path: .
- name: Run SonarCloud Analysis
run: |
./gradlew sonar \
-Dsonar.kotlin.detekt.reportPaths="${GITHUB_WORKSPACE}/app/build/reports/detekt/detekt.xml" \
-Dsonar.coverage.jacoco.xmlReportPaths="${GITHUB_WORKSPACE}/app/build/reports/jacoco/variantStaging/coverage.xml" \
-Dsonar.android.lint.report="${GITHUB_WORKSPACE}/app/build/reports/lint-results-variantStaging.xml" \
--no-daemon --stacktrace --info
Sonar setup in project-level build.gradle.kts script:
subprojects {
sonar {
setAndroidVariant("staging")
properties {
property(
"sonar.kotlin.detekt.reportPaths",
"${project.buildDir}/reports/detekt/detekt.xml"
)
property(
"sonar.coverage.jacoco.xmlReportPaths",
"${project.buildDir}/reports/jacoco/${androidVariant}/coverage.xml"
)
property(
"sonar.android.lint.report",
"${project.buildDir}/build/reports/lint-results-${androidVariant}.xml"
)
property(
"sonar.tests",
"src/test/java,src/testvariant/java"
)
property("sonar.test.inclusions", "**/com/{package}/**")
}
}
}
sonar {
properties {
property("sonar.projectKey", "mykey")
property("sonar.organization", "myorg")
property("sonar.projectName", "Android")
property("sonar.host.url", "https://sonarcloud.io")
property("sonar.token", System.getenv("SONAR_TOKEN"))
property("sonar.sources", "app/src/main/java,app/src/variant/java")
}
}
Some things found from the CI logs:
Importing …./detekt.xml
Sensor Import of detekt issues [kotlin] (done) | time=76ms
Sensor Import of Android Lint issues [kotlin]
2539/2539 source files have been analyzed
The property "sonar.tests" is not set. To improve the analysis accuracy… (--> which seems weird considering that property is set right above!)