Run coverage in integration tests and drop coverage example (#1454)
* Run coverage in integration tests and drop coverage example
BazelIntegrationTestRunner now runs bazel coverage --combined_report=lcov for discovered *_test targets instead of a dedicated //:coverage_test.
Also removes shell-script hooks (test.sh / bash_path) and deletes the dedicated examples/coverage workspace.
* Windows fix
* Disable coverage run in integration tests on Windows
diff --git a/.bazelrc b/.bazelrc
index 472e393..40d7c5e 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -22,6 +22,12 @@
build:windows --cxxopt=/Zc:__cplusplus
build:windows --host_cxxopt=/Zc:__cplusplus
+# Avoid
+# Exception in thread "main" java.io.IOException: Error getting terminal size: GetConsoleScreenBufferInfo error 6
+# at coursier.jniutils.WindowsAnsiTerminal.terminalSize(WindowsAnsiTerminal.java:10)
+common:windows --repo_env=COURSIER_NO_TERM=true
+common:windows --repo_env=COURSIER_PROGRESS=false
+
# To update these lines, execute
# `bazel run @rules_bazel_integration_test//tools:update_deleted_packages`
build --deleted_packages=examples/android,examples/android/app,examples/android/bzl,examples/android/libAndroid,examples/android/libJava,examples/android/libKtAndroid,examples/android/libKtAndroid/src/test/java/examples/android/lib,examples/android/third_party,examples/anvil,examples/anvil/app,examples/anvil/app/src/androidTest/java/com/squareup/anvil/sample,examples/anvil/app/src/main/java/com/squareup/anvil/sample,examples/anvil/app/src/test/java/com/squareup/anvil/sample,examples/anvil/library,examples/anvil/library/src/main/java/com/squareup/anvil/sample,examples/anvil/repro/src/main/java/com/repro/lib,examples/anvil/scopes,examples/anvil/scopes/src/main/java/com/squareup/scopes,examples/anvil/third_party,examples/associates,examples/associates/projects/core/api,examples/associates/projects/core/api/src/test/kotlin/core/api,examples/associates/projects/core/impl,examples/associates/projects/core/impl/src/test/kotlin/core/impl,examples/coverage,examples/dagger,examples/dagger/third_party,examples/deps,examples/deps/bzl,examples/deps/libAndroid1,examples/deps/libAndroid2,examples/deps/libAndroid3,examples/deps/libAndroid4,examples/deps/libJava1,examples/deps/libJava2,examples/deps/libJava3,examples/deps/libJava4,examples/deps/libKt1,examples/deps/libKt2,examples/deps/libKt3,examples/deps/libKt4,examples/deps/libKtAndroid1,examples/deps/libKtAndroid2,examples/deps/libKtAndroid3,examples/deps/libKtAndroid4,examples/jetpack_compose,examples/jetpack_compose/app,examples/jetpack_compose/compose-ui,examples/ksp,examples/ksp/third_party,examples/multiplex,examples/multiplex/src,examples/nested_module_resources,examples/nested_module_resources/nested,examples/plugin,examples/plugin/src/allopen,examples/plugin/src/allopennoarg,examples/plugin/src/noarg,examples/plugin/src/parcelize,examples/plugin/src/sam_with_receiver,examples/plugin/src/serialization,examples/trivial,examples/trivial/app
diff --git a/examples/coverage/BUILD.bazel b/examples/coverage/BUILD.bazel
deleted file mode 100644
index 183f4ca..0000000
--- a/examples/coverage/BUILD.bazel
+++ /dev/null
@@ -1,16 +0,0 @@
-load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library", "kt_jvm_test")
-
-kt_jvm_library(
- name = "coverage_lib",
- srcs = ["src/main/kotlin/com/example/coverage/SimpleKotlinLib.kt"],
-)
-
-kt_jvm_test(
- name = "coverage_test",
- srcs = ["src/test/kotlin/com/example/coverage/SimpleKotlinTest.kt"],
- test_class = "com.example.coverage.SimpleKotlinTest",
- deps = [
- ":coverage_lib",
- "@junit4//:junit_junit",
- ],
-)
diff --git a/examples/coverage/MODULE.bazel b/examples/coverage/MODULE.bazel
deleted file mode 100644
index 760321d..0000000
--- a/examples/coverage/MODULE.bazel
+++ /dev/null
@@ -1,28 +0,0 @@
-module(
- name = "coverage_example",
- version = "1.0.0",
-)
-
-bazel_dep(name = "rules_java", version = "9.3.0")
-bazel_dep(name = "rules_kotlin", version = "")
-
-# Point to the local rules_kotlin
-local_path_override(
- module_name = "rules_kotlin",
- path = "../..",
-)
-
-bazel_dep(name = "rules_jvm_external", version = "6.9")
-
-# JUnit 4 dependencies
-maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
-maven.install(
- name = "junit4",
- artifacts = [
- "junit:junit:4.13.2",
- ],
- repositories = [
- "https://repo1.maven.org/maven2",
- ],
-)
-use_repo(maven, "junit4")
diff --git a/examples/coverage/README.md b/examples/coverage/README.md
deleted file mode 100644
index b761a0c..0000000
--- a/examples/coverage/README.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# Coverage Example
-
-This example demonstrates Kotlin code coverage with Bazel using `bazel coverage`.
-
-## Background
-
-This example verifies the fix for [issue #1447](https://github.com/bazelbuild/rules_kotlin/issues/1447), which addresses a JaCoCo version mismatch between `rules_kotlin` and `rules_java 9.3.0+`.
-
-The issue occurred because the kotlin_worker.jar was compiled against JaCoCo 0.8.11, but `rules_java 9.3.0` uses JaCoCo 0.8.14. This caused a `NoClassDefFoundError` when running `bazel coverage` on Kotlin targets.
-
-## The Fix
-
-The fix reorders `runtime_deps` to put `@bazel_tools//tools/jdk:JacocoCoverage` **before** the worker. This ensures the newer JaCoCo classes from Bazel's tools are loaded first, taking precedence over the older version bundled in the worker.
-
-## Running the Example
-
-```bash
-cd examples/coverage
-bazel coverage --combined_report=lcov //:coverage_test
-```
-
-To view the HTML report:
-```bash
-genhtml bazel-out/_coverage/_coverage_report.dat -o coverage_html
-```
-
-## Expected Results
-
-The coverage test should run successfully without any `NoClassDefFoundError` exceptions, and generate coverage reports in `bazel-out/_coverage/`.
diff --git a/examples/coverage/src/main/kotlin/com/example/coverage/SimpleKotlinLib.kt b/examples/coverage/src/main/kotlin/com/example/coverage/SimpleKotlinLib.kt
deleted file mode 100644
index 968199b..0000000
--- a/examples/coverage/src/main/kotlin/com/example/coverage/SimpleKotlinLib.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package com.example.coverage
-
-class SimpleKotlinLib {
- fun add(a: Int, b: Int): Int {
- return if (a > 0) {
- a + b
- } else {
- b
- }
- }
-
- fun multiply(a: Int, b: Int): Int {
- return a * b
- }
-}
diff --git a/examples/coverage/src/test/kotlin/com/example/coverage/SimpleKotlinTest.kt b/examples/coverage/src/test/kotlin/com/example/coverage/SimpleKotlinTest.kt
deleted file mode 100644
index ac14db9..0000000
--- a/examples/coverage/src/test/kotlin/com/example/coverage/SimpleKotlinTest.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.example.coverage
-
-import org.junit.Test
-import org.junit.Assert.assertEquals
-
-class SimpleKotlinTest {
- @Test
- fun testAdd() {
- val lib = SimpleKotlinLib()
- assertEquals(3, lib.add(1, 2))
- assertEquals(2, lib.add(0, 2))
- }
-
- @Test
- fun testMultiply() {
- val lib = SimpleKotlinLib()
- assertEquals(6, lib.multiply(2, 3))
- }
-}
diff --git a/examples/coverage/test.sh b/examples/coverage/test.sh
deleted file mode 100755
index bcb6f2e..0000000
--- a/examples/coverage/test.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-# Additional test script for coverage example
-# Runs after standard build/test cycle to verify coverage-specific functionality
-#
-# This script is executed by BazelIntegrationTestRunner using the bash binary
-# from Bazel's shell toolchain.
-#
-# Environment variables provided by BazelIntegrationTestRunner:
-# BIT_BAZEL_BINARY: path to the bazel binary
-# BIT_STARTUP_FLAGS: flags that go before the command (e.g., --bazelrc)
-# BIT_COMMAND_FLAGS: flags that go after the command (e.g., --override_module, --enable_bzlmod)
-
-set -e
-
-BAZEL="${BIT_BAZEL_BINARY:-bazel}"
-
-echo "Running bazel coverage test..."
-# shellcheck disable=SC2086
-OUTPUT=$("$BAZEL" $BIT_STARTUP_FLAGS coverage $BIT_COMMAND_FLAGS --combined_report=lcov //:coverage_test 2>&1) || {
- echo "Coverage test failed"
- echo "$OUTPUT"
- exit 1
-}
-
-# Check if the output contains NoClassDefFoundError for JaCoCo Offline class
-if echo "$OUTPUT" | grep -q "NoClassDefFoundError.*Offline"; then
- echo "JaCoCo version mismatch error detected"
- exit 1
-fi
-
-echo "Coverage test passed!"
diff --git a/src/main/kotlin/io/bazel/kotlin/test/BUILD.bazel b/src/main/kotlin/io/bazel/kotlin/test/BUILD.bazel
index afc2b1f..53656c1 100644
--- a/src/main/kotlin/io/bazel/kotlin/test/BUILD.bazel
+++ b/src/main/kotlin/io/bazel/kotlin/test/BUILD.bazel
@@ -1,7 +1,4 @@
load("//kotlin:jvm.bzl", "kt_jvm_binary")
-load(":bash.bzl", "bash_path")
-
-bash_path(name = "bash_path")
kt_jvm_binary(
name = "BazelIntegrationTestRunner",
@@ -9,12 +6,10 @@
"BazelIntegrationTestRunner.kt",
],
data = [
- ":bash_path",
"//:rules_kotlin_release",
],
jvm_flags = [
"-D@rules_kotlin...rules_kotlin_release=$(rlocationpath //:rules_kotlin_release)",
- "-Dio.bazel.kotlin.test.bash_path=$(rlocationpath :bash_path)",
],
main_class = "io.bazel.kotlin.test.BazelIntegrationTestRunner",
visibility = [
diff --git a/src/main/kotlin/io/bazel/kotlin/test/BazelIntegrationTestRunner.kt b/src/main/kotlin/io/bazel/kotlin/test/BazelIntegrationTestRunner.kt
index a5f0710..d31dc44 100644
--- a/src/main/kotlin/io/bazel/kotlin/test/BazelIntegrationTestRunner.kt
+++ b/src/main/kotlin/io/bazel/kotlin/test/BazelIntegrationTestRunner.kt
@@ -23,6 +23,7 @@
object BazelIntegrationTestRunner {
@JvmStatic
fun main(args: Array<String>) {
+ val isWindows = System.getProperty("os.name").lowercase().contains("windows")
val fs = FileSystems.getDefault()
val bazel = fs.getPath(System.getenv("BIT_BAZEL_BINARY"))
val workspace = fs.getPath(System.getenv("BIT_WORKSPACE_DIR"))
@@ -137,54 +138,38 @@
*commandFlags,
"kind(\".*_test\", \"//...\")",
).ok { process ->
- if (process.stdOut.isNotEmpty()) {
- bazel.run(
- workspace,
- *systemFlags,
- "test",
- *commandFlags,
- "--test_output=all",
- "//...",
- ).onFailThrow()
- }
+ process.stdOut.toString(UTF_8)
+ .lineSequence()
+ .map(String::trim)
+ .filter(String::isNotEmpty)
+ .toList()
+ .sorted()
}
-
- // Run test script if it exists
- val testScript = workspace.resolve("test.sh")
- if (testScript.exists()) {
- val bashPathFile = BazelRunFiles.resolveVerifiedFromProperty(fs, "io.bazel.kotlin.test.bash_path")
- val bash = Files.readString(bashPathFile).trim()
- println("Running test script [${testScript.fileName}]...")
- ProcessBuilder()
- .command(bash, testScript.toString())
- .directory(workspace.toFile())
- .also { pb ->
- pb.environment()["BIT_STARTUP_FLAGS"] = systemFlags.joinToString(" ")
- pb.environment()["BIT_COMMAND_FLAGS"] = commandFlags.joinToString(" ")
- }
- .start()
- .let { process ->
- val executor = Executors.newCachedThreadPool()
- try {
- val stdOut = executor.submit(process.inputStream.streamTo(System.out))
- val stdErr = executor.submit(process.errorStream.streamTo(System.out))
- if (!process.waitFor(600, TimeUnit.SECONDS) || process.exitValue() != 0) {
- throw AssertionError(
- """
- Test script failed with exit code ${process.exitValue()}:
- stdout:
- ${stdOut.get().toString(UTF_8)}
- stderr:
- ${stdErr.get().toString(UTF_8)}
- """.trimIndent(),
- )
- }
- } finally {
- executor.shutdown()
- executor.awaitTermination(1, TimeUnit.SECONDS)
+ .also { testTargets ->
+ if (testTargets.isNotEmpty()) {
+ val coverageTargets = testTargets.toTypedArray()
+ bazel.run(
+ workspace,
+ *systemFlags,
+ "test",
+ *commandFlags,
+ "--test_output=all",
+ "//...",
+ ).onFailThrow()
+ if (isWindows) {
+ println("Skipping coverage on Windows integration runs.")
+ } else {
+ bazel.run(
+ workspace,
+ *systemFlags,
+ "coverage",
+ *commandFlags,
+ "--combined_report=lcov",
+ *coverageTargets,
+ ).onFailThrow()
}
}
- }
+ }
}
}
}
diff --git a/src/main/kotlin/io/bazel/kotlin/test/bash.bzl b/src/main/kotlin/io/bazel/kotlin/test/bash.bzl
deleted file mode 100644
index 53096b6..0000000
--- a/src/main/kotlin/io/bazel/kotlin/test/bash.bzl
+++ /dev/null
@@ -1,19 +0,0 @@
-"""Rule to expose the shell toolchain's bash binary path."""
-
-def _bash_path_impl(ctx):
- toolchain = ctx.toolchains["@bazel_tools//tools/sh:toolchain_type"]
- bash_path = toolchain.path
-
- # Write the path to a file that can be read at runtime
- path_file = ctx.actions.declare_file(ctx.label.name + ".path")
- ctx.actions.write(
- output = path_file,
- content = bash_path,
- )
-
- return [DefaultInfo(files = depset([path_file]))]
-
-bash_path = rule(
- implementation = _bash_path_impl,
- toolchains = ["@bazel_tools//tools/sh:toolchain_type"],
-)