diff --git a/.circleci/config.yml b/.circleci/config.yml index 5aca1c2e..fe3c122b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,6 +1,6 @@ version: 2.1 orbs: - codecov: codecov/codecov@3.2.4 + codecov: codecov/codecov@5.4.3 ruby: circleci/ruby@2.0.0 commands: @@ -9,7 +9,11 @@ commands: - restore_cache: key: v1-gradle-wrapper-{{ arch }}-{{ checksum "gradle/wrapper/gradle-wrapper.properties" }} - restore_cache: - key: v1-gradle-cache-{{ arch }}-{{ checksum "build.gradle" }} + key: v1-gradle-cache-{{ arch }}-{{ checksum "build.gradle" }}-{{ checksum "settings.gradle" }}-{{ checksum "gradle.properties" }}-{{ checksum "app/build.gradle.kts" }} + restore_bundler_cache: + steps: + - restore_cache: + key: v1-bundler-cache-{{ checksum "Gemfile.lock" }} save_gradle_cache: steps: @@ -20,7 +24,13 @@ commands: - save_cache: paths: - ~/.gradle/caches - key: v1-gradle-cache-{{ arch }}-{{ checksum "build.gradle" }} + key: v1-gradle-cache-{{ arch }}-{{ checksum "build.gradle" }}-{{ checksum "settings.gradle" }}-{{ checksum "gradle.properties" }}-{{ checksum "app/build.gradle.kts" }} + save_bundler_cache: + steps: + - save_cache: + paths: + - vendor/bundle + key: v1-bundler-cache-{{ checksum "Gemfile.lock" }} executors: android-machine: @@ -37,6 +47,7 @@ jobs: steps: - checkout - restore_gradle_cache + - restore_bundler_cache - ruby/install-deps: with-cache: true - run: @@ -44,11 +55,12 @@ jobs: command: | bundle exec fastlane testDev - save_gradle_cache + - save_bundler_cache - run: name: Analyze on SonarCloud command: ./gradlew lintDebug sonar - codecov/upload: - file: app/build/mergedReportDir/jacocoTestReport/jacocoTestReport.xml + files: app/build/mergedReportDir/jacocoTestReport/jacocoTestReport.xml - store_test_results: path: app/build/test-results/testDebugUnitTest - store_artifacts: diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index e03a03bd..26d5d569 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -96,3 +96,17 @@ jobs: with: api-level: 29 script: ./gradlew connectedCheck + + notify-slack: + needs: unit-test + runs-on: ubuntu-latest + if: always() # Runs regardless of success or failure of unit-test + steps: + - name: Send Slack notification + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL_GITHUB_BUILD_INFO }} + run: | + STATUS="${{ needs.unit-test.result }}" + curl -X POST -H 'Content-type: application/json' \ + --data "{\"text\":\"Unit tests completed: $STATUS\"}" \ + $SLACK_WEBHOOK_URL diff --git a/Gemfile b/Gemfile index 2ccf2ecb..68230327 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,5 @@ source "https://rubygems.org" -gem "fastlane" +gem "fastlane", ">= 2.220.0" plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile') eval_gemfile(plugins_path) if File.exist?(plugins_path) diff --git a/Gemfile.lock b/Gemfile.lock index d5b4e4ee..924f46d2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -10,19 +10,19 @@ GEM artifactory (3.0.17) atomos (0.1.3) aws-eventstream (1.3.2) - aws-partitions (1.1095.0) - aws-sdk-core (3.222.3) + aws-partitions (1.1108.0) + aws-sdk-core (3.224.1) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) base64 jmespath (~> 1, >= 1.6.1) logger - aws-sdk-kms (1.99.0) + aws-sdk-kms (1.101.0) aws-sdk-core (~> 3, >= 3.216.0) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.184.0) - aws-sdk-core (~> 3, >= 3.216.0) + aws-sdk-s3 (1.187.0) + aws-sdk-core (~> 3, >= 3.224.1) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) aws-sigv4 (1.11.0) @@ -70,14 +70,14 @@ GEM faraday_middleware (1.2.1) faraday (~> 1.0) fastimage (2.4.0) - fastlane (2.218.0) + fastlane (2.227.2) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) aws-sdk-s3 (~> 1.0) babosa (>= 1.0.3, < 2.0.0) bundler (>= 1.12.0, < 3.0.0) - colored + colored (~> 1.2) commander (~> 4.6) dotenv (>= 2.1.1, < 3.0.0) emoji_regex (>= 0.1, < 4.0) @@ -86,9 +86,11 @@ GEM faraday-cookie_jar (~> 0.0.6) faraday_middleware (~> 1.0) fastimage (>= 2.1.0, < 3.0.0) + fastlane-sirp (>= 1.0.0) gh_inspector (>= 1.1.2, < 2.0.0) google-apis-androidpublisher_v3 (~> 0.3) google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-env (>= 1.6.0, < 2.0.0) google-cloud-storage (~> 1.31) highline (~> 2.0) http-cookie (~> 1.0.5) @@ -97,10 +99,10 @@ GEM mini_magick (>= 4.9.4, < 5.0.0) multipart-post (>= 2.0.0, < 3.0.0) naturally (~> 2.2) - optparse (>= 0.1.1) + optparse (>= 0.1.1, < 1.0.0) plist (>= 3.1.0, < 4.0.0) rubyzip (>= 2.0.0, < 3.0.0) - security (= 0.1.3) + security (= 0.1.5) simctl (~> 1.6.3) terminal-notifier (>= 2.0.0, < 3.0.0) terminal-table (~> 3) @@ -108,53 +110,50 @@ GEM tty-spinner (>= 0.8.0, < 1.0.0) word_wrap (~> 1.0.0) xcodeproj (>= 1.13.0, < 2.0.0) - xcpretty (~> 0.3.0) - xcpretty-travis-formatter (>= 0.0.3) - fastlane-plugin-firebase_app_distribution (0.9.1) + xcpretty (~> 0.4.1) + xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) + fastlane-plugin-firebase_app_distribution (0.10.1) google-apis-firebaseappdistribution_v1 (~> 0.3.0) google-apis-firebaseappdistribution_v1alpha (~> 0.2.0) + fastlane-sirp (1.0.0) + sysrandom (~> 1.0) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.78.0) - google-apis-core (>= 0.15.0, < 2.a) - google-apis-core (0.17.0) + google-apis-androidpublisher_v3 (0.54.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-core (0.11.3) addressable (~> 2.5, >= 2.5.1) - googleauth (~> 1.9) - httpclient (>= 2.8.3, < 3.a) + googleauth (>= 0.16.2, < 2.a) + httpclient (>= 2.8.1, < 3.a) mini_mime (~> 1.0) - mutex_m representable (~> 3.0) retriable (>= 2.0, < 4.a) + rexml google-apis-firebaseappdistribution_v1 (0.3.0) google-apis-core (>= 0.11.0, < 2.a) google-apis-firebaseappdistribution_v1alpha (0.2.0) google-apis-core (>= 0.11.0, < 2.a) - google-apis-iamcredentials_v1 (0.23.0) - google-apis-core (>= 0.15.0, < 2.a) - google-apis-playcustomapp_v1 (0.16.0) - google-apis-core (>= 0.15.0, < 2.a) - google-apis-storage_v1 (0.50.0) - google-apis-core (>= 0.15.0, < 2.a) + google-apis-iamcredentials_v1 (0.17.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-playcustomapp_v1 (0.13.0) + google-apis-core (>= 0.11.0, < 2.a) + google-apis-storage_v1 (0.31.0) + google-apis-core (>= 0.11.0, < 2.a) google-cloud-core (1.8.0) google-cloud-env (>= 1.0, < 3.a) google-cloud-errors (~> 1.0) - google-cloud-env (2.3.0) - base64 (~> 0.2) - faraday (>= 1.0, < 3.a) + google-cloud-env (1.6.0) + faraday (>= 0.17.3, < 3.0) google-cloud-errors (1.5.0) - google-cloud-storage (1.56.0) + google-cloud-storage (1.47.0) addressable (~> 2.8) digest-crc (~> 0.4) - google-apis-core (~> 0.13) - google-apis-iamcredentials_v1 (~> 0.18) - google-apis-storage_v1 (>= 0.42) + google-apis-iamcredentials_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.31.0) google-cloud-core (~> 1.6) - googleauth (~> 1.9) + googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - google-logging-utils (0.2.0) - googleauth (1.14.0) - faraday (>= 1.0, < 3.a) - google-cloud-env (~> 2.2) - google-logging-utils (~> 0.1) + googleauth (1.8.1) + faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) multi_json (~> 1.11) os (>= 0.9, < 2.0) @@ -165,7 +164,7 @@ GEM httpclient (2.9.0) mutex_m jmespath (1.6.2) - json (2.11.3) + json (2.12.2) jwt (2.10.1) base64 logger (1.7.0) @@ -188,10 +187,10 @@ GEM uber (< 0.2.0) retriable (3.1.2) rexml (3.4.1) - rouge (2.0.7) + rouge (3.28.0) ruby2_keywords (0.0.5) rubyzip (2.4.1) - security (0.1.3) + security (0.1.5) signet (0.20.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) @@ -200,6 +199,7 @@ GEM simctl (1.6.10) CFPropertyList naturally + sysrandom (1.0.5) terminal-notifier (2.0.0) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) @@ -218,8 +218,8 @@ GEM colored2 (~> 3.1) nanaimo (~> 0.4.0) rexml (>= 3.3.6, < 4.0) - xcpretty (0.3.0) - rouge (~> 2.0.7) + xcpretty (0.4.1) + rouge (~> 3.28.0) xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) @@ -230,7 +230,7 @@ PLATFORMS x86_64-linux DEPENDENCIES - fastlane + fastlane (>= 2.220.0) fastlane-plugin-firebase_app_distribution BUNDLED WITH diff --git a/README.md b/README.md index 01708181..b5f32636 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ More info on official Sonar docs: [SonarScanner for Gradle](https://docs.sonarcl ## Knows Issues +- Jacoco coverage report is incorrect - Please feel free inform me about new issues diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5ebd0cf9..629b4f76 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -70,8 +70,9 @@ android { animationsDisabled = true + @Suppress("UnstableApiUsage") managedDevices { - devices { + allDevices { maybeCreate("pixel2api30").apply { device = "Pixel 2" apiLevel = 30 @@ -109,16 +110,25 @@ tasks.register("jacocoTestReport") { csv.required.set(false) } - val fileFilter = listOf("**/R.class", "**/R$*.class", "**/BuildConfig.*", "**/Manifest*.*", "**/*Test*.*", "android/**/*.*") - val debugTree = fileTree("${layout.buildDirectory}/tmp/kotlin-classes/debug") { exclude(fileFilter) } - val mainSrc = "${layout.projectDirectory}/src/main/kotlin" - - sourceDirectories.from(files(setOf(mainSrc))) - classDirectories.from(files(setOf(debugTree))) - executionData.from(fileTree(layout.buildDirectory) { include(setOf( - "outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec", - "outputs/managed_device_code_coverage/pixel2api30/coverage.ec" - ))}) + val fileFilter = listOf( + "**/R.class", "**/R$*.class", "**/BuildConfig.*", "**/Manifest*.*", + "**/*Test*.*", "android/**/*.*", + "**/Dagger*.*", "**/*_Hilt*.*", "**/*Hilt*.*", + "**/ui/**" // Exclude UI files from coverage + ) + val javaDebugTree = fileTree(layout.buildDirectory.dir("intermediates/javac/debug/classes")) { exclude(fileFilter) } + val kotlinDebugTree = fileTree(layout.buildDirectory.dir("tmp/kotlin-classes/debug")) { exclude(fileFilter) } + val mainJavaSrc = layout.projectDirectory.dir("src/main/java") + val mainKotlinSrc = layout.projectDirectory.dir("src/main/kotlin") + sourceDirectories.from(files(mainJavaSrc, mainKotlinSrc)) + classDirectories.from(files(javaDebugTree, kotlinDebugTree)) + executionData.from(fileTree(layout.buildDirectory) { + include( + "outputs/unit_test_code_coverage/**/*.exec", + "outputs/managed_device_code_coverage/**/*.ec", + "outputs/managed_device_code_coverage/**/*.exec" + ) + }) } sonarqube { @@ -284,4 +294,4 @@ dependencies { // Android Serial Controller implementation("com.github.superus8r:UsbSerial:6.1.1") -} \ No newline at end of file +} diff --git a/build.gradle b/build.gradle index 30e0c129..a3b0a9ce 100644 --- a/build.gradle +++ b/build.gradle @@ -23,22 +23,20 @@ plugins { } task clean(type: Delete) { - delete rootProject.buildDir + delete layout.buildDirectory } sonarqube { properties { - property "sonar.organization", "superus8r" - property "sonar.projectKey", "superus8r_arduino-usb-terminal" - property "sonar.projectName", "arduino-usb-terminal" - property "sonar.sourceEncoding", "UTF-8" - property "sonar.host.url", "https://sonarcloud.io" + property("sonar.organization", "superus8r") + property("sonar.projectKey", "superus8r_arduino-usb-terminal") + property("sonar.projectName", "arduino-usb-terminal") + property("sonar.sourceEncoding", "UTF-8") + property("sonar.host.url", "https://sonarcloud.io") - // sonar requires relative path for sources and binaries - property "sonar.sources", "/app/src/main/java" - property "sonar.binaries", "/app/build/tmp/kotlin-classes/debug" + property("sonar.binaries", project(":app").layout.buildDirectory.dir("tmp/kotlin-classes/debug").get().asFile.absolutePath) // sonar requires absolute path for lint and jacoco reports! - property "sonar.androidLint.reportPaths", "$rootDir/app/build/reports/lint-results-debug.xml" - property "sonar.coverage.jacoco.xmlReportPaths", "$rootDir/app/build/mergedReportDir/jacocoTestReport/jacocoTestReport.xml" + property("sonar.androidLint.reportPaths", project(":app").layout.buildDirectory.dir("reports/lint-results-debug.xml").get().asFile.absolutePath) + property("sonar.coverage.jacoco.xmlReportPaths", project(":app").layout.buildDirectory.dir("mergedReportDir/jacocoTestReport/jacocoTestReport.xml").get().asFile.absolutePath) } -} \ No newline at end of file +}