Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: SonarCloud Analysis | |
| on: | |
| push: | |
| branches: | |
| - '*' | |
| pull_request: | |
| branches: | |
| - '*' | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| sonarcloud: | |
| name: SonarCloud Scan | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Enable KVM group perms | |
| run: | | |
| echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules | |
| sudo udevadm control --reload-rules | |
| sudo udevadm trigger --name-match=kvm | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # Shallow clones should be disabled for better relevancy of analysis | |
| - name: Set up JDK 17 | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: 'temurin' | |
| java-version: 17 | |
| cache: 'gradle' | |
| - name: Gradle cache | |
| uses: gradle/actions/setup-gradle@v3 | |
| - name: Build project and run tests with coverage | |
| run: | | |
| # Build the project | |
| ./gradlew assembleDebug --stacktrace | |
| # Run tests with coverage - allow test failures | |
| ./gradlew testDebugUnitTest jacocoTestReport --stacktrace | |
| TEST_RESULT=$? | |
| if [ $TEST_RESULT -ne 0 ]; then | |
| echo "Some tests failed, but continuing to check for coverage data..." | |
| # Even if tests fail, JaCoCo should generate a report with partial coverage | |
| # from the tests that did pass | |
| fi | |
| # Check if the report was generated with content | |
| if [ -f build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml ]; then | |
| # Use stat command compatible with both Linux and macOS | |
| if [[ "$(uname)" == "Darwin" ]]; then | |
| # macOS syntax | |
| REPORT_SIZE=$(stat -f%z build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml) | |
| else | |
| # Linux syntax | |
| REPORT_SIZE=$(stat -c%s build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml) | |
| fi | |
| if [ "$REPORT_SIZE" -lt 1000 ]; then | |
| echo "JaCoCo report is too small ($REPORT_SIZE bytes), likely empty. Trying to generate from test execution data..." | |
| # Try to generate the report directly from the exec file | |
| if [ -f build/jacoco/testDebugUnitTest.exec ]; then | |
| java -jar ~/.gradle/caches/modules-2/files-2.1/org.jacoco/org.jacoco.cli/0.8.8/*/org.jacoco.cli-0.8.8.jar report build/jacoco/testDebugUnitTest.exec \ | |
| --classfiles build/intermediates/runtime_library_classes_dir/debug \ | |
| --sourcefiles src/main/java \ | |
| --xml build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml | |
| # Check if the report was successfully generated | |
| if [[ "$(uname)" == "Darwin" ]]; then | |
| # macOS syntax | |
| NEW_REPORT_SIZE=$(stat -f%z build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml) | |
| else | |
| # Linux syntax | |
| NEW_REPORT_SIZE=$(stat -c%s build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml) | |
| fi | |
| if [ "$NEW_REPORT_SIZE" -lt 1000 ]; then | |
| echo "ERROR: Failed to generate a valid JaCoCo report with coverage data" | |
| exit 1 | |
| else | |
| echo "JaCoCo report successfully generated with size $NEW_REPORT_SIZE bytes" | |
| fi | |
| else | |
| echo "ERROR: No JaCoCo execution data file found. Tests may not have run correctly." | |
| exit 1 | |
| fi | |
| else | |
| echo "JaCoCo report generated successfully with size $REPORT_SIZE bytes" | |
| fi | |
| else | |
| echo "ERROR: JaCoCo report file not found. Coverage data is missing." | |
| exit 1 | |
| fi | |
| - name: Prepare class files for SonarQube analysis | |
| run: | | |
| echo "Searching for compiled class files..." | |
| # Create the target directory | |
| mkdir -p build/intermediates/runtime_library_classes_dir/debug | |
| # Find all directories containing class files | |
| CLASS_DIRS=$(find build -name "*.class" -type f -exec dirname {} \; | sort -u) | |
| if [ -z "$CLASS_DIRS" ]; then | |
| echo "WARNING: No class files found in the build directory!" | |
| else | |
| echo "Found class files in the following directories:" | |
| echo "$CLASS_DIRS" | |
| # Copy classes from the first directory with classes | |
| FIRST_CLASS_DIR=$(echo "$CLASS_DIRS" | head -1) | |
| echo "Copying classes from $FIRST_CLASS_DIR to build/intermediates/runtime_library_classes_dir/debug" | |
| cp -r $FIRST_CLASS_DIR/* build/intermediates/runtime_library_classes_dir/debug/ || echo "Failed to copy from $FIRST_CLASS_DIR" | |
| # Verify the target directory now has class files | |
| CLASS_COUNT=$(find build/intermediates/runtime_library_classes_dir/debug -name "*.class" | wc -l) | |
| echo "Target directory now contains $CLASS_COUNT class files" | |
| fi | |
| # Update sonar-project.properties with all found class directories as a fallback | |
| echo "\n# Additional binary paths found during build" >> sonar-project.properties | |
| echo "sonar.java.binaries=build/intermediates/runtime_library_classes_dir/debug,$CLASS_DIRS" >> sonar-project.properties | |
| echo "Checking for JaCoCo report files..." | |
| find build -name "*.xml" | grep jacoco || echo "No XML files found" | |
| find build -name "*.exec" | grep jacoco || echo "No exec files found" | |
| echo "Contents of JaCoCo report directory:" | |
| ls -la build/reports/jacoco/jacocoTestReport/ || echo "Directory not found" | |
| echo "\nChecking test execution results:" | |
| find build -name "TEST-*.xml" | xargs cat | grep -E 'tests|failures|errors|skipped' || echo "No test result files found" | |
| echo "\nChecking JaCoCo report content:" | |
| if [ -f build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml ]; then | |
| echo "Report file size: $(wc -c < build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml) bytes" | |
| echo "First 500 chars of report:" | |
| head -c 500 build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml | |
| echo "\n\nCounting coverage elements:" | |
| grep -c "<package" build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml || echo "No packages found" | |
| grep -c "<class" build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml || echo "No classes found" | |
| grep -c "<method" build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml || echo "No methods found" | |
| grep -c "<line" build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml || echo "No lines found" | |
| grep -c 'ci="1"' build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml || echo "No covered lines found" | |
| else | |
| echo "JaCoCo report file not found" | |
| fi | |
| echo "\nChecking binary directories specified in sonar-project.properties:" | |
| echo "build/intermediates/runtime_library_classes_dir/debug:" | |
| ls -la build/intermediates/runtime_library_classes_dir/debug || echo "Directory not found" | |
| echo "\nChecking all available class directories:" | |
| find build -path "*/build/*" -name "*.class" | head -n 5 || echo "No class files found" | |
| # Android instrumented test section for comprehensive coverage | |
| - name: AVD cache | |
| uses: actions/cache@v4 | |
| id: avd-cache | |
| with: | |
| path: | | |
| ~/.android/avd/* | |
| ~/.android/adb* | |
| key: avd-28 | |
| - name: Create AVD and generate snapshot for caching | |
| if: steps.avd-cache.outputs.cache-hit != 'true' | |
| uses: reactivecircus/android-emulator-runner@v2 | |
| with: | |
| api-level: 28 | |
| force-avd-creation: false | |
| emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none | |
| disable-animations: true | |
| script: echo "Generated AVD snapshot for caching." | |
| - name: Assemble debug AndroidTest | |
| run: ./gradlew assembleDebugAndroidTest | |
| - name: Run instrumented tests with coverage | |
| uses: reactivecircus/android-emulator-runner@v2 | |
| with: | |
| api-level: 28 | |
| profile: Galaxy Nexus | |
| script: | | |
| # Run instrumented tests with coverage - allow test failures | |
| # Use a more direct approach to ensure coverage is enabled | |
| ./gradlew assembleDebugAndroidTest | |
| # First, let's determine the correct test package name | |
| echo "\n[DEBUG] Listing all available instrumentation packages:" | |
| adb shell pm list instrumentation | |
| TEST_PACKAGE=$(adb shell pm list instrumentation | grep split | cut -d' ' -f1 | cut -d: -f2) | |
| echo "\n[DEBUG] Found test instrumentation package: $TEST_PACKAGE" | |
| # Check if the test APK is installed properly | |
| echo "\n[DEBUG] Checking installed packages:" | |
| adb shell pm list packages | grep split | |
| # Verify test class exists | |
| echo "\n[DEBUG] Checking if test class exists:" | |
| ./gradlew -q listTestClasses | grep DatabaseInitializationTest || echo "Test class not found in Gradle test classes" | |
| # Run only a single test class with coverage explicitly enabled | |
| echo "\n[DEBUG] Running instrumentation with explicit coverage flag:" | |
| adb shell "am instrument -w -e coverage true -e class tests.database.DatabaseInitializationTest $TEST_PACKAGE" | |
| TEST_RESULT=$? | |
| if [ $TEST_RESULT -ne 0 ]; then | |
| echo "Some instrumented tests failed, but continuing to check for coverage data..." | |
| else | |
| echo "\n[DEBUG] Instrumentation completed successfully" | |
| fi | |
| # Create directory for coverage files | |
| mkdir -p build/outputs/code_coverage/debugAndroidTest/connected/ | |
| # Try to find and pull coverage files from various possible locations | |
| echo "\n[DEBUG] Searching for coverage files..." | |
| # Check if coverage is enabled in the app manifest | |
| echo "\n[DEBUG] Checking test AndroidManifest.xml for coverage settings:" | |
| adb shell pm dump $TEST_PACKAGE | grep -i coverage | |
| # Check for files in external storage | |
| echo "\n[DEBUG] Checking external storage for coverage files:" | |
| adb shell ls -la /sdcard/ | grep -i coverage || echo "No coverage files found in /sdcard/" | |
| # Check app-specific data directory - try both package names | |
| echo "\n[DEBUG] Checking app-specific data directory for coverage files:" | |
| APP_PACKAGE=$(adb shell pm list packages | grep split | cut -d: -f2 | head -1) | |
| echo "\n[DEBUG] App package name: $APP_PACKAGE" | |
| # Try with the detected app package | |
| echo "\n[DEBUG] Searching in /data/data/$APP_PACKAGE/:" | |
| adb shell run-as $APP_PACKAGE find /data/data/$APP_PACKAGE -name "*.ec" | while read -r file; do | |
| echo "Found coverage file: $file" | |
| filename=$(basename "$file") | |
| adb shell run-as $APP_PACKAGE cat "$file" > "build/outputs/code_coverage/debugAndroidTest/connected/$filename" | |
| echo "Pulled coverage file to build/outputs/code_coverage/debugAndroidTest/connected/$filename" | |
| done | |
| # Also try with the hardcoded package name as fallback | |
| echo "\n[DEBUG] Searching in /data/data/io.split.android.android_client/:" | |
| adb shell run-as io.split.android.android_client find /data/data/io.split.android.android_client -name "*.ec" | while read -r file; do | |
| echo "Found coverage file: $file" | |
| filename=$(basename "$file") | |
| adb shell run-as io.split.android.android_client cat "$file" > "build/outputs/code_coverage/debugAndroidTest/connected/$filename" | |
| echo "Pulled coverage file to build/outputs/code_coverage/debugAndroidTest/connected/$filename" | |
| done | |
| # Also check sdcard location | |
| echo "\n[DEBUG] Checking /sdcard/ location:" | |
| adb pull /sdcard/coverage.ec build/outputs/code_coverage/debugAndroidTest/connected/ || echo "No coverage file at /sdcard/coverage.ec" | |
| # Try alternative locations | |
| echo "\n[DEBUG] Checking alternative locations for coverage files:" | |
| adb pull /data/local/tmp/coverage.ec build/outputs/code_coverage/debugAndroidTest/connected/ || echo "No coverage file at /data/local/tmp/coverage.ec" | |
| # List all coverage files to verify | |
| echo "\n[DEBUG] Listing all found coverage files:" | |
| find build -name "*.ec" -o -name "*.exec" | |
| # Run the JaCoCo report task with debug info | |
| echo "\n[DEBUG] Running JaCoCo Android test report task with debug info:" | |
| ./gradlew jacocoAndroidTestReport --debug > jacoco_debug.log | |
| REPORT_RESULT=$? | |
| # Save the important parts of the debug log | |
| echo "\n[DEBUG] Extracting coverage-related info from debug log:" | |
| grep -A 10 -B 2 "JaCoCo" jacoco_debug.log > jacoco_important.log || echo "No JaCoCo info found in debug log" | |
| grep -A 5 -B 2 "coverage" jacoco_debug.log >> jacoco_important.log || echo "No coverage info found in debug log" | |
| grep -A 3 -B 1 "exec" jacoco_debug.log >> jacoco_important.log || echo "No exec info found in debug log" | |
| grep -A 3 -B 1 "ec" jacoco_debug.log >> jacoco_important.log || echo "No .ec info found in debug log" | |
| echo "\n[DEBUG] Important JaCoCo debug info:" | |
| cat jacoco_important.log | |
| if [ $REPORT_RESULT -ne 0 ]; then | |
| echo "\n[DEBUG] Failed to generate Android test coverage report, but continuing..." | |
| echo "\n[DEBUG] Last 20 lines of debug log:" | |
| tail -20 jacoco_debug.log | |
| else | |
| echo "\n[DEBUG] JaCoCo Android test report generated successfully" | |
| fi | |
| # Check if the Android test report was generated with content | |
| if [ -f build/reports/jacoco/jacocoAndroidTestReport/jacocoAndroidTestReport.xml ]; then | |
| # Use stat command compatible with both Linux and macOS | |
| if [[ "$(uname)" == "Darwin" ]]; then | |
| # macOS syntax | |
| REPORT_SIZE=$(stat -f%z build/reports/jacoco/jacocoAndroidTestReport/jacocoAndroidTestReport.xml) | |
| else | |
| # Linux syntax | |
| REPORT_SIZE=$(stat -c%s build/reports/jacoco/jacocoAndroidTestReport/jacocoAndroidTestReport.xml) | |
| fi | |
| echo "Android test JaCoCo report size: $REPORT_SIZE bytes" | |
| if [ "$REPORT_SIZE" -lt 1000 ]; then | |
| echo "WARNING: Android test JaCoCo report is too small, likely empty" | |
| else | |
| echo "Android test JaCoCo report generated successfully" | |
| fi | |
| else | |
| echo "WARNING: Android test JaCoCo report file not found" | |
| fi | |
| continue-on-error: true | |
| - name: Generate combined coverage report | |
| run: | | |
| # Generate combined report - allow failures | |
| ./gradlew jacocoCodeCoverageReport | |
| COMBINED_RESULT=$? | |
| if [ $COMBINED_RESULT -ne 0 ]; then | |
| echo "Failed to generate combined report, but continuing..." | |
| fi | |
| # Check if the combined report was generated with content | |
| if [ -f build/reports/jacoco/jacocoCombinedReport/jacocoCombinedReport.xml ]; then | |
| # Use stat command compatible with both Linux and macOS | |
| if [[ "$(uname)" == "Darwin" ]]; then | |
| # macOS syntax | |
| REPORT_SIZE=$(stat -f%z build/reports/jacoco/jacocoCombinedReport/jacocoCombinedReport.xml) | |
| else | |
| # Linux syntax | |
| REPORT_SIZE=$(stat -c%s build/reports/jacoco/jacocoCombinedReport/jacocoCombinedReport.xml) | |
| fi | |
| echo "Combined JaCoCo report size: $REPORT_SIZE bytes" | |
| if [ "$REPORT_SIZE" -lt 1000 ]; then | |
| echo "WARNING: Combined JaCoCo report is too small, likely empty" | |
| # Try to manually combine the reports | |
| mkdir -p build/reports/jacoco/jacocoCombinedReport/ | |
| cp build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml build/reports/jacoco/jacocoCombinedReport/jacocoCombinedReport.xml | |
| else | |
| echo "Combined JaCoCo report generated successfully" | |
| fi | |
| else | |
| echo "WARNING: Combined JaCoCo report file not found, using unit test report as fallback" | |
| mkdir -p build/reports/jacoco/jacocoCombinedReport/ | |
| cp build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml build/reports/jacoco/jacocoCombinedReport/jacocoCombinedReport.xml | |
| fi | |
| continue-on-error: true | |
| - name: Check combined coverage report | |
| run: | | |
| echo "Checking for all coverage data files:" | |
| find build -name "*.exec" -o -name "*.ec" | sort | |
| echo "\nChecking combined JaCoCo report content:" | |
| if [ -f build/reports/jacoco/jacocoCombinedReport/jacocoCombinedReport.xml ]; then | |
| echo "Report file size: $(wc -c < build/reports/jacoco/jacocoCombinedReport/jacocoCombinedReport.xml) bytes" | |
| echo "First 500 chars of report:" | |
| head -c 500 build/reports/jacoco/jacocoCombinedReport/jacocoCombinedReport.xml | |
| echo "\n\nCounting coverage elements:" | |
| grep -c "<package" build/reports/jacoco/jacocoCombinedReport/jacocoCombinedReport.xml || echo "No packages found" | |
| grep -c "<class" build/reports/jacoco/jacocoCombinedReport/jacocoCombinedReport.xml || echo "No classes found" | |
| grep -c "<method" build/reports/jacoco/jacocoCombinedReport/jacocoCombinedReport.xml || echo "No methods found" | |
| grep -c "<line" build/reports/jacoco/jacocoCombinedReport/jacocoCombinedReport.xml || echo "No lines found" | |
| grep -c 'ci="1"' build/reports/jacoco/jacocoCombinedReport/jacocoCombinedReport.xml || echo "No covered lines found" | |
| else | |
| echo "Combined JaCoCo report file not found" | |
| fi | |
| - name: SonarCloud Scan | |
| uses: SonarSource/sonarqube-scan-action@v5 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information | |
| SONAR_TOKEN: ${{ secrets.SONARQUBE_TOKEN }} | |
| SONAR_HOST_URL: ${{ secrets.SONARQUBE_HOST }} |