Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CI] Implement SonarCloud #5511

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ jobs:
with:
name: testDebugUnitTest
path: ./**/build/reports/tests/testDebugUnitTest
- uses: ./.github/actions/setup-ruby
- name: Sonar
run: bundle exec fastlane run_sonar_analysis
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

size_check_xml:
name: Size Check XML
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ env:
BUILD_CACHE_AWS_BUCKET: ${{ secrets.BUILD_CACHE_AWS_BUCKET }}
BUILD_CACHE_AWS_ACCESS_KEY_ID: ${{ secrets.BUILD_CACHE_AWS_ACCESS_KEY_ID }}
BUILD_CACHE_AWS_SECRET_KEY: ${{ secrets.BUILD_CACHE_AWS_SECRET_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_PR_NUM: ${{ github.event.pull_request.number }}

concurrency:
group: ${{ github.head_ref }}
Expand Down Expand Up @@ -73,6 +75,11 @@ jobs:
with:
name: testDebugUnitTest
path: ./**/build/reports/tests/testDebugUnitTest
- uses: ./.github/actions/setup-ruby
- name: Sonar
run: bundle exec fastlane run_sonar_analysis
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

rubocop:
name: Rubocop
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/snapshot-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ on:
required: false
default: false

env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_PR_NUM: ${{ github.event.pull_request.number }}

Comment on lines +14 to +17
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are those environment variables needed even though the workflow has not changed?

Copy link
Collaborator Author

@testableapple testableapple Dec 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just figured out that without this impact analysis does not work (for sonar coverage, snapshot tests and e2e tests), so I implemented these variables to other workflows as well as part of this PR even though it is not directly related.

jobs:
run_snapshot_tests:
name: Run
Expand Down
13 changes: 10 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ apply plugin: "com.github.ben-manes.versions"
apply plugin: 'io.github.gradle-nexus.publish-plugin'
apply plugin: 'binary-compatibility-validator'
apply plugin: 'org.jetbrains.dokka'
apply from: "${rootDir}/scripts/sonar.gradle"
apply from: "${rootDir}/scripts/sample-app-versioner.gradle"
apply plugin: UnitTestsPlugin
apply plugin: ReleasePlugin
Expand Down Expand Up @@ -73,15 +74,21 @@ buildscript {
classpath Dependencies.spotlessGradlePlugin
classpath Dependencies.ksp
classpath Dependencies.detektPlugin
classpath Dependencies.sonarQubePlugin

// Workaround for integrate sonarqube plugin with AGP
// It looks like will be fixed after AGP 8.9.0-alpha04 is released
// https://issuetracker.google.com/issues/380600747?pli=1
classpath("org.bouncycastle:bcutil-jdk18on:1.79")
}
}

subprojects {
if (it.name != 'stream-chat-android-docs'
&& it.buildFile.exists()) {
if (it.name != 'stream-chat-android-docs' && it.buildFile.exists()) {
apply from: "${rootDir}/spotless/spotless.gradle"
}
apply plugin: "io.gitlab.arturbosch.detekt"
apply from: "${rootDir}/scripts/coverage.gradle"
}

versionPrint {
Expand Down Expand Up @@ -134,4 +141,4 @@ apiValidation {
]
}

apply from: "${rootDir}/scripts/publish-root.gradle"
apply from: "${rootDir}/scripts/publish-root.gradle"
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ object Versions {
internal const val SHIMMER = "0.5.0"
internal const val SHIMMER_COMPOSE = "1.3.1"
internal const val SHOT = "6.1.0"
internal const val SONARQUBE_PLUGIN = "6.0.1.5171"
internal const val SPOTLESS = "6.20.0"
internal const val STREAM_LOG = "1.3.1"
internal const val STREAM_PUSH = "1.1.9"
Expand Down Expand Up @@ -252,6 +253,7 @@ object Dependencies {
const val allureKotlinCommons = "io.qameta.allure:allure-kotlin-commons:${Versions.ALLURE_KOTLIN}"
const val allureKotlinJunit = "io.qameta.allure:allure-kotlin-junit4:${Versions.ALLURE_KOTLIN}"
const val allureKotlinAndroid = "io.qameta.allure:allure-kotlin-android:${Versions.ALLURE_KOTLIN}"
const val sonarQubePlugin = "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:${Versions.SONARQUBE_PLUGIN}"

@JvmStatic
fun isNonStable(version: String): Boolean = isStable(version).not()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ fun List<String>.selectedUnitTestCommand(rootProject: Project): String {

return filterUnitTestableModules(rootProject)
.filter { (testableModule, _) -> modulesWithTest.contains(testableModule) }
.generateGradleCommand { (module, testType) -> "$module:${testType.testCommand}" }
.generateGradleCommand { (module, testType) ->
"$module:${testType.testCommand} $module:${TestType.JACOCO_TEST_COVERAGE.testCommand}"
}
}

private fun List<String>.filterModulesWithTests(): List<String> {
Expand All @@ -24,7 +26,7 @@ private fun List<String>.filterUnitTestableModules(rootProject: Project): List<P
.filter { project -> project.hasUnitTest() && this.contains(project.name) }
.map { project ->
val testType = when {
project.tasks.any { task -> task.name == "testDebugUnitTest" } -> {
project.tasks.any { task -> task.name == TestType.ANDROID_LIBRARY_TEST.testCommand } -> {
TestType.ANDROID_LIBRARY_TEST
}

Expand All @@ -38,5 +40,5 @@ private fun List<String>.filterUnitTestableModules(rootProject: Project): List<P
}

private fun Project.hasUnitTest(): Boolean = this.tasks.any { task ->
task.name == "testDebugUnitTest" || task.name == "test"
task.name == TestType.ANDROID_LIBRARY_TEST.testCommand || task.name == TestType.JAVA_LIBRARY_TEST.testCommand
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ package io.getstream.chat.android.command.unittest.model
enum class TestType(val testCommand: String) {
JAVA_LIBRARY_TEST("test"),
ANDROID_LIBRARY_TEST("testDebugUnitTest"),
JACOCO_TEST_COVERAGE("testCoverage"),
}
8 changes: 8 additions & 0 deletions fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ lane :stop_mock_server do
Net::HTTP.get_response(URI("http://localhost:#{mock_server_driver_port}/stop")) rescue nil
end

lane :run_sonar_analysis do |options|
next unless is_check_required(sources: sources_matrix[:sonar], force_check: @force_check)

Dir.chdir('..') { sh('./gradlew sonar') }
end

lane :run_snapshot_test do |options|
next unless is_check_required(sources: sources_matrix[:ui], force_check: @force_check)

Expand Down Expand Up @@ -128,8 +134,10 @@ end

private_lane :sources_matrix do
{
unit: ['stream-chat-android-test', 'stream-chat-android-client', 'stream-chat-android-compose/', 'stream-chat-android-core', 'stream-chat-android-markdown-transformer', 'stream-chat-android-offline', 'stream-chat-android-state', 'stream-chat-android-ui-common', 'stream-chat-android-ui-components/', 'stream-chat-android-ui-utils/'],
ui: ['stream-chat-android-ui', '.github/workflows/snapshot-test'],
e2e: ['buildSrc', 'stream-chat-android', '.github/workflows/e2e-test'],
sonar: ['stream-chat-android-client/', 'stream-chat-android-compose/', 'stream-chat-android-core/', 'stream-chat-android-markdown-transformer/', 'stream-chat-android-offline/', 'stream-chat-android-state/', 'stream-chat-android-ui-common/', 'stream-chat-android-ui-components/', 'stream-chat-android-ui-utils/'],
ruby: ['fastlane', 'Gemfile', 'Gemfile.lock']
}
end
Expand Down
61 changes: 61 additions & 0 deletions scripts/coverage.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
if (!rootProject.ext.sonar.ignoreModules.contains(name)) {
apply plugin: 'jacoco'
apply plugin: "org.sonarqube"

def isCore = (name == 'stream-chat-android-core')
def testTask = isCore ? "test" : "testDebugUnitTest"
def jacocoResults = "${buildDir}/reports/jacoco/report.xml"

if (hasProperty('android')) {
android {
buildTypes {
debug {
testCoverageEnabled = true
enableUnitTestCoverage = true
enableAndroidTestCoverage true
}
}
}
}

afterEvaluate {
tasks.withType(Test).configureEach {
jacoco.includeNoLocationClasses = true
jacoco.excludes = ['jdk.internal.*']
}

tasks.register("testCoverage", JacocoReport) {
dependsOn testTask

reports {
xml.required.set(true)
xml.outputLocation.set(file(jacocoResults))
}

executionData.setFrom(fileTree(dir: buildDir, includes: [
"outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec",
"jacoco/test.exec"
]))

def sources = isCore ? sourceSets.main.java.srcDirs : android.sourceSets.main.java.srcDirs
sourceDirectories.setFrom(files(sources))
classDirectories.setFrom(files([
fileTree(
dir: "${buildDir}/tmp/kotlin-classes/debug",
excludes: rootProject.ext.sonar.excludeFilter
),
fileTree(
dir: "${buildDir}/classes/kotlin/main",
excludes: rootProject.ext.sonar.excludeFilter
)
]))
}
}

sonarqube {
properties {
property "sonar.junit.reportPaths", "${buildDir}/test-results/${testTask}"
property "sonar.coverage.jacoco.xmlReportPaths", jacocoResults
}
}
}
45 changes: 45 additions & 0 deletions scripts/sonar.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
apply plugin: "org.sonarqube"

ext.sonar = [
ignoreModules : [
'stream-chat-android-ai-assistant',
'stream-chat-android-previewdata',
'stream-chat-android-docs',
'stream-chat-android-benchmark',
'stream-chat-android-compose-sample',
'stream-chat-android-e2e-test',
'stream-chat-android-test',
'stream-chat-android-ui-guides',
'stream-chat-android-ui-components-sample',
'stream-chat-android-client-test',
'stream-chat-android-ui-uitests'
],
excludeFilter : [
'**/test/**',
'**/androidTest/**',
'**/R.class',
'**/R2.class',
'**/R$*.class',
'**/BuildConfig.*',
'**/Manifest*.*',
'**/*Test*.*'
]
]

ext.sonar.ignoreModules.each {
ext.sonar.excludeFilter << "**/${it}/**"
}

sonarqube {
properties {
property("sonar.host.url", "https://sonarcloud.io")
property("sonar.token", "${System.getenv("SONAR_TOKEN")}")
property("sonar.organization", "getstream")
property("sonar.projectKey", "GetStream_stream-chat-android")
property("sonar.projectName", "stream-chat-android")
property "sonar.java.coveragePlugin", "jacoco"
property "sonar.sourceEncoding", "UTF-8"
property "sonar.java.binaries", "${rootDir}/**/build/tmp/kotlin-classes/debug,${rootDir}/**/build/classes/kotlin/main"
property "sonar.coverage.exclusions", rootProject.ext.sonar.excludeFilter
}
}

This file was deleted.

This file was deleted.

1 change: 0 additions & 1 deletion stream-chat-android-client/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ android {
consumerProguardFiles 'consumer-proguard-rules.pro'
}
debug {
testCoverageEnabled false
consumerProguardFiles 'consumer-proguard-rules.pro'
}
}
Expand Down
3 changes: 0 additions & 3 deletions stream-chat-android-offline/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@ android {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
testCoverageEnabled false
}
}
}

Expand Down
Loading