This is an automated email from the ASF dual-hosted git repository.
maciej pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iggy.git
The following commit(s) were added to refs/heads/master by this push:
new 2e74a3e10 ci(Java): add JaCoCo code coverage with Codecov integration
(#2623)
2e74a3e10 is described below
commit 2e74a3e100637dc17c2a28f9dc3c928730e06c14
Author: Qichao Chu <[email protected]>
AuthorDate: Mon Feb 9 12:35:47 2026 -0800
ci(Java): add JaCoCo code coverage with Codecov integration (#2623)
---
.github/actions/java-gradle/pre-merge/action.yml | 21 ++++++++++++
.github/workflows/_test.yml | 12 +++++++
codecov.yml | 9 ++++-
foreign/java/build.gradle.kts | 39 ++++++++++++++++++++++
.../kotlin/iggy.java-common-conventions.gradle.kts | 31 +++++++++++++++++
foreign/java/gradle/libs.versions.toml | 1 +
.../org/apache/iggy/serde/BytesSerializer.java | 3 +-
7 files changed, 114 insertions(+), 2 deletions(-)
diff --git a/.github/actions/java-gradle/pre-merge/action.yml
b/.github/actions/java-gradle/pre-merge/action.yml
index df02a52fc..7c76044f4 100644
--- a/.github/actions/java-gradle/pre-merge/action.yml
+++ b/.github/actions/java-gradle/pre-merge/action.yml
@@ -93,6 +93,27 @@ runs:
USE_EXTERNAL_SERVER: true
run: ./gradlew test
+ - name: Generate coverage report
+ if: inputs.task == 'test'
+ shell: bash
+ working-directory: foreign/java
+ env:
+ USE_EXTERNAL_SERVER: true
+ run: ./gradlew jacocoAggregatedReport
+
+ - name: Copy coverage reports
+ if: ${{ !cancelled() && inputs.task == 'test' }}
+ shell: bash
+ run: |
+ if [ -f
"foreign/java/build/reports/jacoco/aggregate/jacocoAggregated.xml" ]; then
+ echo "Found aggregated coverage report"
+ mkdir -p reports/java-coverage
+ cp foreign/java/build/reports/jacoco/aggregate/jacocoAggregated.xml
reports/java-coverage/
+ if [ -d "foreign/java/build/reports/jacoco/aggregate/html" ]; then
+ cp -r foreign/java/build/reports/jacoco/aggregate/html
reports/java-coverage/
+ fi
+ fi
+
- name: Copy test reports
if: ${{ !cancelled() && inputs.task == 'test' }}
shell: bash
diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml
index d83ee8add..b05626676 100644
--- a/.github/workflows/_test.yml
+++ b/.github/workflows/_test.yml
@@ -104,6 +104,18 @@ jobs:
with:
task: ${{ inputs.task }}
+ - name: Upload Java coverage to Codecov
+ if: inputs.component == 'sdk-java' && inputs.task == 'test'
+ uses: codecov/codecov-action@v5
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ files: reports/java-coverage/jacocoAggregated.xml
+ disable_search: true
+ flags: java
+ fail_ci_if_error: false
+ verbose: true
+ override_pr: ${{ github.event.pull_request.number }}
+
# C# SDK
- name: Run C# SDK task
if: inputs.component == 'sdk-csharp'
diff --git a/codecov.yml b/codecov.yml
index 0cdb369b5..1926f1853 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -48,6 +48,13 @@ ignore:
- "core/harness_derive/**"
- "bdd/**"
- "examples/**"
- - "foreign/**"
+ - "foreign/csharp/**"
+ - "foreign/go/**"
+ - "foreign/node/**"
+ - "foreign/python/**"
- "web/**"
- "**/tests/**"
+ - "**/*Test.java"
+ - "**/test/**"
+ - "**/build/**"
+ - "**/target/**"
diff --git a/foreign/java/build.gradle.kts b/foreign/java/build.gradle.kts
index d1d66fb3b..a0693eb03 100644
--- a/foreign/java/build.gradle.kts
+++ b/foreign/java/build.gradle.kts
@@ -21,6 +21,11 @@ import com.diffplug.gradle.spotless.SpotlessExtension
plugins {
alias(libs.plugins.spotless) apply false
+ jacoco
+}
+
+repositories {
+ mavenCentral()
}
subprojects {
@@ -103,3 +108,37 @@ subprojects {
}
}
}
+
+tasks.register<JacocoReport>("jacocoAggregatedReport") {
+ description = "Generates aggregated code coverage report for all modules"
+ group = "verification"
+
+ dependsOn(subprojects.map { it.tasks.named("test") })
+
+ // Aggregate execution data from all subprojects
+ executionData.setFrom(files(subprojects.mapNotNull {
+ val testTask = it.tasks.withType<Test>().findByName("test")
+ if (testTask != null && it.plugins.hasPlugin("java")) {
+ it.layout.buildDirectory.file("jacoco/test.exec").get().asFile
+ } else {
+ null
+ }
+ }.filter { it.exists() }))
+
+ // Aggregate source and class files
+ subprojects.forEach { subproject ->
+ if (subproject.plugins.hasPlugin("java")) {
+ val sourceSets =
subproject.extensions.getByType<SourceSetContainer>()
+
sourceDirectories.from(sourceSets.getByName("main").allSource.srcDirs)
+ classDirectories.from(files(sourceSets.getByName("main").output))
+ }
+ }
+
+ reports {
+ xml.required.set(true)
+
xml.outputLocation.set(layout.buildDirectory.file("reports/jacoco/aggregate/jacocoAggregated.xml"))
+ html.required.set(true)
+
html.outputLocation.set(layout.buildDirectory.dir("reports/jacoco/aggregate/html"))
+ csv.required.set(false)
+ }
+}
diff --git
a/foreign/java/buildSrc/src/main/kotlin/iggy.java-common-conventions.gradle.kts
b/foreign/java/buildSrc/src/main/kotlin/iggy.java-common-conventions.gradle.kts
index bb86082b9..ba057c6b6 100644
---
a/foreign/java/buildSrc/src/main/kotlin/iggy.java-common-conventions.gradle.kts
+++
b/foreign/java/buildSrc/src/main/kotlin/iggy.java-common-conventions.gradle.kts
@@ -17,8 +17,11 @@
* under the License.
*/
+import org.gradle.api.artifacts.VersionCatalogsExtension
+
plugins {
java
+ jacoco
}
repositories {
@@ -39,6 +42,34 @@ tasks.withType<Javadoc> {
options.encoding = "UTF-8"
}
+jacoco {
+ toolVersion = extensions.getByType<VersionCatalogsExtension>()
+ .named("libs")
+ .findVersion("jacoco")
+ .get()
+ .requiredVersion
+}
+
tasks.withType<Test> {
useJUnitPlatform()
+ finalizedBy(tasks.jacocoTestReport)
+}
+
+tasks.jacocoTestReport {
+ dependsOn(tasks.test)
+ reports {
+ xml.required.set(true)
+ html.required.set(true)
+ csv.required.set(false)
+ }
+}
+
+tasks.jacocoTestCoverageVerification {
+ violationRules {
+ rule {
+ limit {
+ minimum = "0.0".toBigDecimal()
+ }
+ }
+ }
}
diff --git a/foreign/java/gradle/libs.versions.toml
b/foreign/java/gradle/libs.versions.toml
index dd3e8408c..108b5909f 100644
--- a/foreign/java/gradle/libs.versions.toml
+++ b/foreign/java/gradle/libs.versions.toml
@@ -58,6 +58,7 @@ typesafe-config = "1.4.5"
spotless = "8.1.0"
shadow = "9.2.2"
checkstyle = "12.1.2"
+jacoco = "0.8.14"
[libraries]
# Jackson
diff --git
a/foreign/java/java-sdk/src/main/java/org/apache/iggy/serde/BytesSerializer.java
b/foreign/java/java-sdk/src/main/java/org/apache/iggy/serde/BytesSerializer.java
index c9c317189..c4354719c 100644
---
a/foreign/java/java-sdk/src/main/java/org/apache/iggy/serde/BytesSerializer.java
+++
b/foreign/java/java-sdk/src/main/java/org/apache/iggy/serde/BytesSerializer.java
@@ -207,7 +207,8 @@ public final class BytesSerializer {
}
public static ByteBuf toBytes(String value) {
- ByteBuf buffer = Unpooled.buffer(1 + value.length());
+ int bufferLength = 1 + value.length();
+ ByteBuf buffer = Unpooled.buffer(bufferLength);
byte[] stringBytes = value.getBytes(StandardCharsets.UTF_8);
buffer.writeByte(stringBytes.length);
buffer.writeBytes(stringBytes);