-
-
Notifications
You must be signed in to change notification settings - Fork 3
feat: Add JaCoCo coverage and SonarCloud integration #270
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
base: main
Are you sure you want to change the base?
Changes from all commits
0626170
e82334b
f32b15e
b1cfbd4
fb8efa5
e4b7af8
ef1c6b9
e9ab993
877b9ec
fe87b85
6720031
e05ead4
d47572e
e1ee3cc
4af8f30
d9097f7
f44bec4
7e306b4
2d7e3d3
32b0a0f
5cd2bcc
402c17a
644dcda
44c8e3c
390a150
4871ce1
7898cc3
269669f
2dc6357
deb6173
680de63
8cf3ec8
f87cc2a
d02c13f
3b2ee2f
896499c
c4edf73
5316e87
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| --- | ||
| "scopes": minor | ||
| --- | ||
|
|
||
| Add comprehensive code coverage tracking, SonarCloud integration, and security enhancements | ||
|
|
||
| ### New Features | ||
| - **JaCoCo Code Coverage**: Multi-module coverage aggregation with 60% minimum threshold | ||
| - **SonarCloud Integration**: Automated quality gates and code analysis | ||
| - **Gradle Dependency Verification**: Comprehensive SHA256 checksums for supply chain security | ||
|
|
||
| ### Security Improvements | ||
| - Fixed all SonarCloud Code Analysis issues (hardcoded dispatchers, script injection, cognitive complexity) | ||
| - Resolved Security Hotspots through dependency verification and GitHub Actions SHA pinning | ||
| - Enhanced CI/CD security with proper permissions and environment variable usage | ||
|
|
||
| ### New Gradle Tasks | ||
| - `testWithCoverage`: Run tests with coverage reports | ||
| - `sonarqubeWithCoverage`: Complete quality analysis | ||
| - `:coverage-report:testCodeCoverageReport`: Aggregated coverage reporting | ||
|
|
||
| This release significantly improves code quality monitoring and security posture. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| --- | ||
| "scopes": minor | ||
| --- | ||
|
|
||
| Add JaCoCo code coverage and SonarCloud integration for continuous quality monitoring | ||
|
|
||
| - Integrated JaCoCo plugin for code coverage measurement across all modules | ||
| - Added coverage-report module for multi-module coverage aggregation | ||
| - Configured SonarQube plugin for SonarCloud analysis | ||
| - Created GitHub Actions workflow for automated quality checks | ||
| - Added comprehensive documentation and Gradle tasks | ||
| - Set up XML coverage reports for SonarCloud consumption |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,7 @@ | ||
| import org.gradle.api.tasks.testing.Test | ||
| import org.gradle.testing.jacoco.tasks.JacocoCoverageVerification | ||
| import org.gradle.testing.jacoco.tasks.JacocoReport | ||
|
|
||
| plugins { | ||
| alias(libs.plugins.kotlin.jvm) apply false | ||
| alias(libs.plugins.kotlin.serialization) apply false | ||
|
|
@@ -8,6 +12,8 @@ plugins { | |
| alias(libs.plugins.spotless) | ||
| alias(libs.plugins.cyclonedx.bom) | ||
| alias(libs.plugins.spdx.sbom) | ||
| alias(libs.plugins.sonarqube) | ||
| jacoco | ||
| } | ||
|
|
||
| group = "io.github.kamiazya" | ||
|
|
@@ -40,11 +46,63 @@ subprojects { | |
|
|
||
| // Configure Kotlin compilation when plugin is applied | ||
| pluginManager.withPlugin("org.jetbrains.kotlin.jvm") { | ||
| // Apply JaCoCo to all modules with Kotlin code | ||
| apply(plugin = "jacoco") | ||
| // Apply SonarQube plugin to all Kotlin modules | ||
| apply(plugin = "org.sonarqube") | ||
|
|
||
| tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> { | ||
| compilerOptions { | ||
| jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21) | ||
| } | ||
| } | ||
|
|
||
| // Configure JaCoCo | ||
| tasks.withType<JacocoReport> { | ||
| dependsOn(tasks.named("test")) | ||
| reports { | ||
| xml.required.set(true) | ||
| html.required.set(true) | ||
| csv.required.set(false) | ||
| } | ||
| } | ||
|
|
||
| // Configure test task to generate JaCoCo data | ||
| tasks.withType<Test> { | ||
| finalizedBy(tasks.withType<JacocoReport>()) | ||
| useJUnitPlatform() | ||
| testLogging { | ||
| events("passed", "skipped", "failed") | ||
| } | ||
| } | ||
|
Comment on lines
+71
to
+77
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The use of tasks.withType<Test> {
useJUnitPlatform()
testLogging {
events("passed", "skipped", "failed")
}
} |
||
|
|
||
| // JaCoCo coverage verification | ||
| tasks.withType<JacocoCoverageVerification> { | ||
| violationRules { | ||
| rule { | ||
| limit { | ||
| minimum = "0.60".toBigDecimal() | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Configure SonarQube for each module | ||
| sonarqube { | ||
| properties { | ||
| // Only set sources if the directory exists | ||
| if (file("src/main/kotlin").exists()) { | ||
| property("sonar.sources", "src/main/kotlin") | ||
| property("sonar.java.binaries", "build/classes/kotlin/main") | ||
| } | ||
| // Only set test sources if the directory exists | ||
| if (file("src/test/kotlin").exists()) { | ||
| property("sonar.tests", "src/test/kotlin") | ||
| } | ||
| // Each module should report its own JaCoCo XML report path | ||
| property("sonar.coverage.jacoco.xmlReportPaths", "build/reports/jacoco/test/jacocoTestReport.xml") | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Fix circular dependency issue with Kotlin and Java compilation | ||
|
|
@@ -81,6 +139,8 @@ subprojects { | |
|
|
||
| // Custom task to check if GraalVM is available | ||
| tasks.register("checkGraalVM") { | ||
| description = "Check if GraalVM native-image is available in the current environment" | ||
| group = "verification" | ||
| doLast { | ||
| try { | ||
| val isWindows = System.getProperty("os.name").lowercase().contains("windows") | ||
|
|
@@ -147,6 +207,29 @@ tasks.register("konsistTest") { | |
| dependsOn(":quality-konsist:test") | ||
| } | ||
|
|
||
| // Task to run all tests with coverage | ||
| tasks.register("testWithCoverage") { | ||
| description = "Run all tests and generate coverage reports" | ||
| group = "verification" | ||
|
|
||
| // Run all tests | ||
| subprojects.forEach { subproject -> | ||
| subproject.tasks.findByName("test")?.let { | ||
| dependsOn(it) | ||
| } | ||
| } | ||
|
|
||
| // Generate individual coverage reports | ||
| subprojects.forEach { subproject -> | ||
| subproject.tasks.findByName("jacocoTestReport")?.let { | ||
| dependsOn(it) | ||
| } | ||
| } | ||
|
Comment on lines
+215
to
+227
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The // Run all tests and generate individual coverage reports
subprojects.forEach { subproject ->
subproject.tasks.findByName("jacocoTestReport")?.let {
dependsOn(it)
}
} |
||
|
|
||
| // Generate aggregated coverage report | ||
| finalizedBy(":quality-coverage-report:testCodeCoverageReport") | ||
| } | ||
|
|
||
|
Comment on lines
+210
to
+232
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainRepo-wide clean-up: find lingering references to quality/coverage-report Search and fix any remaining wrong module references to prevent task resolution errors. 🏁 Script executed: #!/bin/bash
# Find wrong references
rg -nP 'quality/coverage-report|:quality-coverage-report'
# Confirm correct ones exist
rg -nP 'coverage-report/build/reports/jacoco/testCodeCoverageReport/testCodeCoverageReport\.xml|:coverage-report:testCodeCoverageReport'Length of output: 634 Remove lingering references to
🤖 Prompt for AI Agents |
||
| // Spotless configuration | ||
| configure<com.diffplug.gradle.spotless.SpotlessExtension> { | ||
| kotlin { | ||
|
|
@@ -205,3 +288,30 @@ configure<com.diffplug.gradle.spotless.SpotlessExtension> { | |
| endWithNewline() | ||
| } | ||
| } | ||
|
|
||
| // SonarQube configuration | ||
| sonarqube { | ||
| properties { | ||
| property("sonar.projectKey", "kamiazya_scopes") | ||
| property("sonar.organization", "kamiazya") | ||
| property("sonar.host.url", "https://sonarcloud.io") | ||
| property("sonar.projectName", "Scopes") | ||
| property("sonar.projectVersion", version) | ||
|
|
||
| // Language settings | ||
| property("sonar.language", "kotlin") | ||
| property("sonar.kotlin.detekt.reportPaths", "**/build/reports/detekt/detekt.xml") | ||
|
|
||
|
Comment on lines
+303
to
+304
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainVerify glob support for detekt report paths. Sonar’s detekt property typically expects concrete file paths (comma-separated). Globs may be ignored, leading to missing issues in the analysis. Run: As per coding guidelines 🌐 Web query: 💡 Result: Short answer: No — sonar.kotlin.detekt.reportPaths expects a comma-delimited list of report file paths (concrete paths). Wildcards/globs are only supported for properties that explicitly say so; the Detekt reportPaths entry has no wildcard remark. [1][2] Sources:
Use concrete Detekt report paths instead of globs 🤖 Prompt for AI Agents |
||
| // Coverage configuration - use the aggregated report | ||
| property( | ||
| "sonar.coverage.jacoco.xmlReportPaths", | ||
| "quality/coverage-report/build/reports/jacoco/testCodeCoverageReport/testCodeCoverageReport.xml", | ||
| ) | ||
|
|
||
| // Encoding | ||
| property("sonar.sourceEncoding", "UTF-8") | ||
|
|
||
| // Duplication detection | ||
| property("sonar.cpd.exclusions", "**/*Test.kt,**/*Spec.kt") | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid granting unnecessary
pull-requests: writepermissionThis workflow only posts issue-style comments via
issues.createComment, which already requiresissues: write. The additionalpull-requests: writegrant expands the token’s scope without a functional benefit. Please keep the permissions minimal and drop the extra grant.📝 Committable suggestion
🤖 Prompt for AI Agents