Add Kover code coverage support#1527
Add Kover code coverage support#1527oliviernotteghem wants to merge 4 commits intobazel-contrib:masterfrom
Conversation
3c31758 to
99ac6ea
Compare
Summary
This commit integrates Kover (JetBrains' Kotlin code coverage tool) into rules_kotlin as an alternative to JaCoCo. Kover uses a JVM agent for runtime
instrumentation, eliminating the need for build-time bytecode modification.
---
File-by-File Changes
1. kotlin/internal/jvm/kover.bzl (NEW - 167 lines)
Purpose: Core Kover integration logic.
┌───────────────────────────────────┬─────────┬───────────────────────────────────────────────────┐
│ Function │ Lines │ Description │
├───────────────────────────────────┼─────────┼───────────────────────────────────────────────────┤
│ is_kover_enabled(ctx) │ 49-50 │ Checks if Kover is enabled via toolchain │
├───────────────────────────────────┼─────────┼───────────────────────────────────────────────────┤
│ get_kover_agent_file(ctx) │ 52-63 │ Retrieves Kover agent JAR from toolchain │
├───────────────────────────────────┼─────────┼───────────────────────────────────────────────────┤
│ get_kover_jvm_flags(...) │ 65-72 │ Generates -javaagent:kover.jar=file:args.txt flag │
├───────────────────────────────────┼─────────┼───────────────────────────────────────────────────┤
│ create_kover_agent_actions(...) │ 74-99 │ Creates .ic output file and args file for agent │
├───────────────────────────────────┼─────────┼───────────────────────────────────────────────────┤
│ create_kover_metadata_action(...) │ 102-167 │ Generates metadata file for Kover CLI reports │
└───────────────────────────────────┴─────────┴───────────────────────────────────────────────────┘
Key implementation details:
- Uses ctx.actions.run_shell hack to declare the .ic file (created by agent at runtime)
- Filters source files and classfiles to include only same-package dependencies
- Supports exclusions by class pattern, annotation, and inherited class
---
2. kotlin/internal/jvm/compile.bzl (+5 lines)
Changes:
# Added import
load("//kotlin/internal/jvm:kover.bzl", _is_kover_enabled = "is_kover_enabled")
# Modified instrumentation flag
args.add("--instrument_coverage", ctx.coverage_instrumented() and not _is_kover_enabled(ctx))
Effect: Disables JaCoCo bytecode instrumentation when Kover is enabled, preventing conflicts.
---
3. kotlin/internal/jvm/impl.bzl (+40 lines)
Changes to kt_jvm_junit_test_impl:
# Before (JaCoCo only)
if ctx.configuration.coverage_enabled:
jacocorunner = ctx.toolchains[_TOOLCHAIN_TYPE].jacocorunner
coverage_runfiles = jacocorunner.files.to_list()
# After (Kover + JaCoCo)
if ctx.configuration.coverage_enabled:
if _is_kover_enabled(ctx):
# Setup Kover agent
kover_agent_files = _get_kover_agent_files(ctx)
kover_output_file, kover_args_file = _create_kover_agent_actions(...)
kover_output_metadata_file = _create_kover_metadata_action(...)
coverage_jvm_flags = [_get_kover_jvm_flags(...)]
coverage_inputs = [depset(kover_agent_files)]
coverage_runfiles = [kover_args_file, kover_output_metadata_file]
else:
# Existing JaCoCo path
jacocorunner = ctx.toolchains[_TOOLCHAIN_TYPE].jacocorunner
coverage_runfiles = jacocorunner.files.to_list()
---
4. kotlin/internal/jvm/kt_android_local_test_impl.bzl (+199 lines)
Major changes:
1. _process_jvm function: Added Kover support mirroring the JVM test changes
2. _process_stub function (NEW): Custom stub processor that:
- Skips merged instrumentation JAR creation when using Kover
- Properly handles coverage environment variables for both Kover and JaCoCo
3. Helper functions (NEW):
- _get_test_class(ctx) - Infers test class from sources
- _create_stub(...) - Creates test launcher shell script
- _get_classpath(s) - Formats classpath entries
- _get_jvm_flags(...) - Assembles JVM flags for Robolectric
---
5. kotlin/internal/toolchains.bzl (+32 lines)
New toolchain attributes:
┌───────────────────────────────────────────┬─────────────┬───────────────────────────────┐
│ Attribute │ Type │ Description │
├───────────────────────────────────────────┼─────────────┼───────────────────────────────┤
│ experimental_kover_enabled │ bool │ Enable Kover (default: False) │
├───────────────────────────────────────────┼─────────────┼───────────────────────────────┤
│ experimental_kover_agent │ label │ Kover agent JAR target │
├───────────────────────────────────────────┼─────────────┼───────────────────────────────┤
│ experimental_kover_exclude │ string_list │ Class exclusion patterns │
├───────────────────────────────────────────┼─────────────┼───────────────────────────────┤
│ experimental_kover_exclude_annotation │ string_list │ Annotation-based exclusions │
├───────────────────────────────────────────┼─────────────┼───────────────────────────────┤
│ experimental_kover_exclude_inherited_from │ string_list │ Inherited class exclusions │
└───────────────────────────────────────────┴─────────────┴───────────────────────────────┘
Updated functions:
- _kotlin_toolchain_impl: Adds Kover attributes to toolchain info
- define_kt_toolchain: Adds Kover parameters to public API
---
Architecture Diagram
┌─────────────────────────────────────────────────────────────────┐
│ bazel coverage //test │
└─────────────────────────────────────────────────────────────────┘
│
┌───────────────┴───────────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Kover Enabled │ │ JaCoCo Path │
└──────────────┘ └──────────────┘
│ │
▼ ▼
┌───────────────────┐ ┌─────────────────────┐
│ No recompilation │ │ Bytecode modified │
│ Agent instruments │ │ at compile time │
│ at runtime │ └─────────────────────┘
└───────────────────┘
│
▼
┌───────────────────┐
│ test-kover.args.txt│ ← Agent configuration
│ test-kover_report.ic│ ← Binary coverage data
│ test-kover_metadata.txt│ ← CLI report args
└───────────────────┘
│
▼
┌───────────────────────────────────────┐
│ External: java -jar kover-cli.jar │
│ report @metadata.txt │
└───────────────────────────────────────┘
Usage
To enable Kover in your project:
define_kt_toolchain(
name = "kotlin_toolchain",
experimental_kover_enabled = True,
experimental_kover_agent = "@maven//:org_jetbrains_kotlinx_kover_jvm_agent",
experimental_kover_exclude = ["com.example.generated.*"],
experimental_kover_exclude_annotation = ["Generated"],
)
Then run: bazel coverage //your/kotlin/test_target
Android Code Duplication
kt_android_local_test_impl.bzl duplicates significant logic from rules_android. This needs to be kept in sync manually. There's ongoing work with Google to add better
extensibility points to rules_android.
99ac6ea to
b96fd43
Compare
|
General, LGTM, modulo the windows check. |
| # rules_java and Bazel core. For now, we disabled JaCoCo instrumentation accross the board, | ||
| # you will need to cherry-pick this PR https://github.com/uber-common/bazel/commit/cb9f6f042c64af96bbd77e21fe6fb75936c74f47 |
| ), | ||
| ) | ||
|
|
||
| # TODO: follow up with Google to have rules_android provide better extensibility points |
There was a problem hiding this comment.
Is there a specific ticket regarding this?
There was a problem hiding this comment.
I asked them directly about this, they're open if we submit a PR that's reasonable.
| "-Xbootclasspath/a:%s" % (kover_agent_files[0].short_path), | ||
| "-javaagent:%s=file:%s" % (kover_agent_files[0].short_path, kover_args_file.short_path), | ||
| ] | ||
| return " ".join(jvm_args) |
There was a problem hiding this comment.
JVM argument parser might split this incorrectly -- return list?
| kover_output_file = ctx.actions.declare_file(binary_output_name) | ||
|
|
||
| # Hack: there is curently no way to indicate this file will be created Kover agent | ||
| ctx.actions.run_shell( |
There was a problem hiding this comment.
This can cause some issues with non *nix OSes. Use:
ctx.actions.write(kover_output_file, "")| ) | ||
| ctx.actions.write( | ||
| kover_args_file, | ||
| "report.file=../../%s" % binary_output_name, # Kotlin compiler runs in runfiles folder, make sure file is created is correct location |
There was a problem hiding this comment.
Relationship between the runfiles root and bazel-bin is not guaranteed and can vary by OS, --sandbox_base setting, and execution strategy.
Try kover_output_file.short_path (workspace-relative path resolved at runtime) or construct the path via ctx.bin_dir.path. Might want to use ${RUNFILES_DIR} to anchor it.
| excludes = [] | ||
|
|
||
| for dep in deps: | ||
| if dep.label.package != ctx.label.package: |
There was a problem hiding this comment.
Hm. dep.label.package == ctx.label.packagewhich will drop all cross-package deps. Example: test is in //tests/foo:bar_test and the library under test is in //core/baz:baz_lib, coverage will be empty.
What's the goal on this?
| srcs.extend(["--src", path]) | ||
|
|
||
| if JavaInfo in dep: | ||
| for classfile in dep[JavaInfo].transitive_runtime_jars.to_list(): |
There was a problem hiding this comment.
Same comment above about reducing memory usage.
| @@ -1,6 +1,9 @@ | |||
| load(":jvm_deps_tests.bzl", "jvm_deps_test_suite") | |||
| load(":kover_test.bzl", "kover_test_suite") | |||
There was a problem hiding this comment.
Missing kover_toolchain_test_suite, so the toolchain tests are never run.
|
|
||
| # Expected format includes both -Xbootclasspath/a and -javaagent flags | ||
| expected = "-Xbootclasspath/a:external/kover/kover-jvm-agent.jar -javaagent:external/kover/kover-jvm-agent.jar=file:bazel-out/k8-fastbuild/bin/test-kover.args.txt" | ||
| asserts.equals(env, expected, result) |
There was a problem hiding this comment.
Hm. Is this right? feels like it should be two strings for the jvm parse.
| load( | ||
| "//kotlin/internal/jvm:kover.bzl", | ||
| _create_kover_agent_actions = "create_kover_agent_actions", | ||
| _create_kover_metadata_action = "create_kover_metadata_action", |
There was a problem hiding this comment.
nit: _get_kover_agent_files (plural) does not match the exported symbol get_kover_agent_file.
Also, single file, rather than list? Would clean up the ambiguous [0] bits below.
| metadata_output_name = "%s-kover_metadata.txt" % name | ||
| kover_output_metadata_file = ctx.actions.declare_file(metadata_output_name) | ||
|
|
||
| srcs = [] |
There was a problem hiding this comment.
use Args for these collections.
| continue | ||
|
|
||
| if InstrumentedFilesInfo in dep: | ||
| for src in dep[InstrumentedFilesInfo].instrumented_files.to_list(): |
There was a problem hiding this comment.
to_list is almost always a bad idea.
This can be accomplish this in a way that doesn't blow out starlark memory by using map and closure -- e.g.:
def filter(src):
if src.short_path.startswith(ctx.label.package + "/"):
path = _paths.dirname(src.short_path)
return "--src\n" + path
src.add_joined(
dep[InstrumentedFilesInfo].instrumented_files,
join_with="\n",
map_each=lambda src:
allow_closure = True,
uniquify = True
)Summary
This commit integrates Kover (JetBrains' Kotlin code coverage tool) into rules_kotlin as an alternative to JaCoCo. Kover uses a JVM agent for runtime
instrumentation, eliminating the need for build-time bytecode modification.
---
File-by-File Changes
1. kotlin/internal/jvm/kover.bzl (NEW - 167 lines)
Purpose: Core Kover integration logic.
┌───────────────────────────────────┬─────────┬───────────────────────────────────────────────────┐
│ Function │ Lines │ Description │
├───────────────────────────────────┼─────────┼───────────────────────────────────────────────────┤
│ is_kover_enabled(ctx) │ 49-50 │ Checks if Kover is enabled via toolchain │
├───────────────────────────────────┼─────────┼───────────────────────────────────────────────────┤
│ get_kover_agent_file(ctx) │ 52-63 │ Retrieves Kover agent JAR from toolchain │
├───────────────────────────────────┼─────────┼───────────────────────────────────────────────────┤
│ get_kover_jvm_flags(...) │ 65-72 │ Generates -javaagent:kover.jar=file:args.txt flag │
├───────────────────────────────────┼─────────┼───────────────────────────────────────────────────┤
│ create_kover_agent_actions(...) │ 74-99 │ Creates .ic output file and args file for agent │
├───────────────────────────────────┼─────────┼───────────────────────────────────────────────────┤
│ create_kover_metadata_action(...) │ 102-167 │ Generates metadata file for Kover CLI reports │
└───────────────────────────────────┴─────────┴───────────────────────────────────────────────────┘
Key implementation details:
- Uses ctx.actions.run_shell hack to declare the .ic file (created by agent at runtime)
- Filters source files and classfiles to include only same-package dependencies
- Supports exclusions by class pattern, annotation, and inherited class
---
2. kotlin/internal/jvm/compile.bzl (+5 lines)
Changes:
# Added import
load("//kotlin/internal/jvm:kover.bzl", _is_kover_enabled = "is_kover_enabled")
# Modified instrumentation flag
args.add("--instrument_coverage", ctx.coverage_instrumented() and not _is_kover_enabled(ctx))
Effect: Disables JaCoCo bytecode instrumentation when Kover is enabled, preventing conflicts.
---
3. kotlin/internal/jvm/impl.bzl (+40 lines)
Changes to kt_jvm_junit_test_impl:
# Before (JaCoCo only)
if ctx.configuration.coverage_enabled:
jacocorunner = ctx.toolchains[_TOOLCHAIN_TYPE].jacocorunner
coverage_runfiles = jacocorunner.files.to_list()
# After (Kover + JaCoCo)
if ctx.configuration.coverage_enabled:
if _is_kover_enabled(ctx):
# Setup Kover agent
kover_agent_files = _get_kover_agent_files(ctx)
kover_output_file, kover_args_file = _create_kover_agent_actions(...)
kover_output_metadata_file = _create_kover_metadata_action(...)
coverage_jvm_flags = [_get_kover_jvm_flags(...)]
coverage_inputs = [depset(kover_agent_files)]
coverage_runfiles = [kover_args_file, kover_output_metadata_file]
else:
# Existing JaCoCo path
jacocorunner = ctx.toolchains[_TOOLCHAIN_TYPE].jacocorunner
coverage_runfiles = jacocorunner.files.to_list()
---
4. kotlin/internal/jvm/kt_android_local_test_impl.bzl (+199 lines)
Major changes:
1. _process_jvm function: Added Kover support mirroring the JVM test changes
2. _process_stub function (NEW): Custom stub processor that:
- Skips merged instrumentation JAR creation when using Kover
- Properly handles coverage environment variables for both Kover and JaCoCo
3. Helper functions (NEW):
- _get_test_class(ctx) - Infers test class from sources
- _create_stub(...) - Creates test launcher shell script
- _get_classpath(s) - Formats classpath entries
- _get_jvm_flags(...) - Assembles JVM flags for Robolectric
---
5. kotlin/internal/toolchains.bzl (+32 lines)
New toolchain attributes:
┌───────────────────────────────────────────┬─────────────┬───────────────────────────────┐
│ Attribute │ Type │ Description │
├───────────────────────────────────────────┼─────────────┼───────────────────────────────┤
│ experimental_kover_enabled │ bool │ Enable Kover (default: False) │
├───────────────────────────────────────────┼─────────────┼───────────────────────────────┤
│ experimental_kover_agent │ label │ Kover agent JAR target │
├───────────────────────────────────────────┼─────────────┼───────────────────────────────┤
│ experimental_kover_exclude │ string_list │ Class exclusion patterns │
├───────────────────────────────────────────┼─────────────┼───────────────────────────────┤
│ experimental_kover_exclude_annotation │ string_list │ Annotation-based exclusions │
├───────────────────────────────────────────┼─────────────┼───────────────────────────────┤
│ experimental_kover_exclude_inherited_from │ string_list │ Inherited class exclusions │
└───────────────────────────────────────────┴─────────────┴───────────────────────────────┘
Updated functions:
- _kotlin_toolchain_impl: Adds Kover attributes to toolchain info
- define_kt_toolchain: Adds Kover parameters to public API
---
Architecture Diagram
┌─────────────────────────────────────────────────────────────────┐
│ bazel coverage //test │
└─────────────────────────────────────────────────────────────────┘
│
┌───────────────┴───────────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Kover Enabled │ │ JaCoCo Path │
└──────────────┘ └──────────────┘
│ │
▼ ▼
┌───────────────────┐ ┌─────────────────────┐
│ No recompilation │ │ Bytecode modified │
│ Agent instruments │ │ at compile time │
│ at runtime │ └─────────────────────┘
└───────────────────┘
│
▼
┌───────────────────┐
│ test-kover.args.txt│ ← Agent configuration
│ test-kover_report.ic│ ← Binary coverage data
│ test-kover_metadata.txt│ ← CLI report args
└───────────────────┘
│
▼
┌───────────────────────────────────────┐
│ External: java -jar kover-cli.jar │
│ report @metadata.txt │
└───────────────────────────────────────┘
Usage
To enable Kover in your project:
define_kt_toolchain(
name = "kotlin_toolchain",
experimental_kover_enabled = True,
experimental_kover_agent = "@maven//:org_jetbrains_kotlinx_kover_jvm_agent",
experimental_kover_exclude = ["com.example.generated.*"],
experimental_kover_exclude_annotation = ["Generated"],
)
Then run: bazel coverage //your/kotlin/test_target
Android Code Duplication
kt_android_local_test_impl.bzl duplicates significant logic from rules_android. This needs to be kept in sync manually. There's ongoing work with Google to add better
extensibility points to rules_android.
Summary
This commit integrates Kover (JetBrains' Kotlin code coverage tool) into rules_kotlin as an alternative to JaCoCo. Kover uses a JVM agent for runtime
instrumentation, eliminating the need for build-time bytecode modification.
---
File-by-File Changes
1. kotlin/internal/jvm/kover.bzl (NEW - 167 lines)
Purpose: Core Kover integration logic.
┌───────────────────────────────────┬─────────┬───────────────────────────────────────────────────┐
│ Function │ Lines │ Description │
├───────────────────────────────────┼─────────┼───────────────────────────────────────────────────┤
│ is_kover_enabled(ctx) │ 49-50 │ Checks if Kover is enabled via toolchain │
├───────────────────────────────────┼─────────┼───────────────────────────────────────────────────┤
│ get_kover_agent_file(ctx) │ 52-63 │ Retrieves Kover agent JAR from toolchain │
├───────────────────────────────────┼─────────┼───────────────────────────────────────────────────┤
│ get_kover_jvm_flags(...) │ 65-72 │ Generates -javaagent:kover.jar=file:args.txt flag │
├───────────────────────────────────┼─────────┼───────────────────────────────────────────────────┤
│ create_kover_agent_actions(...) │ 74-99 │ Creates .ic output file and args file for agent │
├───────────────────────────────────┼─────────┼───────────────────────────────────────────────────┤
│ create_kover_metadata_action(...) │ 102-167 │ Generates metadata file for Kover CLI reports │
└───────────────────────────────────┴─────────┴───────────────────────────────────────────────────┘
Key implementation details:
- Uses ctx.actions.run_shell hack to declare the .ic file (created by agent at runtime)
- Filters source files and classfiles to include only same-package dependencies
- Supports exclusions by class pattern, annotation, and inherited class
---
2. kotlin/internal/jvm/compile.bzl (+5 lines)
Changes:
# Added import
load("//kotlin/internal/jvm:kover.bzl", _is_kover_enabled = "is_kover_enabled")
# Modified instrumentation flag
args.add("--instrument_coverage", ctx.coverage_instrumented() and not _is_kover_enabled(ctx))
Effect: Disables JaCoCo bytecode instrumentation when Kover is enabled, preventing conflicts.
---
3. kotlin/internal/jvm/impl.bzl (+40 lines)
Changes to kt_jvm_junit_test_impl:
# Before (JaCoCo only)
if ctx.configuration.coverage_enabled:
jacocorunner = ctx.toolchains[_TOOLCHAIN_TYPE].jacocorunner
coverage_runfiles = jacocorunner.files.to_list()
# After (Kover + JaCoCo)
if ctx.configuration.coverage_enabled:
if _is_kover_enabled(ctx):
# Setup Kover agent
kover_agent_files = _get_kover_agent_files(ctx)
kover_output_file, kover_args_file = _create_kover_agent_actions(...)
kover_output_metadata_file = _create_kover_metadata_action(...)
coverage_jvm_flags = [_get_kover_jvm_flags(...)]
coverage_inputs = [depset(kover_agent_files)]
coverage_runfiles = [kover_args_file, kover_output_metadata_file]
else:
# Existing JaCoCo path
jacocorunner = ctx.toolchains[_TOOLCHAIN_TYPE].jacocorunner
coverage_runfiles = jacocorunner.files.to_list()
---
4. kotlin/internal/jvm/kt_android_local_test_impl.bzl (+199 lines)
Major changes:
1. _process_jvm function: Added Kover support mirroring the JVM test changes
2. _process_stub function (NEW): Custom stub processor that:
- Skips merged instrumentation JAR creation when using Kover
- Properly handles coverage environment variables for both Kover and JaCoCo
3. Helper functions (NEW):
- _get_test_class(ctx) - Infers test class from sources
- _create_stub(...) - Creates test launcher shell script
- _get_classpath(s) - Formats classpath entries
- _get_jvm_flags(...) - Assembles JVM flags for Robolectric
---
5. kotlin/internal/toolchains.bzl (+32 lines)
New toolchain attributes:
┌───────────────────────────────────────────┬─────────────┬───────────────────────────────┐
│ Attribute │ Type │ Description │
├───────────────────────────────────────────┼─────────────┼───────────────────────────────┤
│ experimental_kover_enabled │ bool │ Enable Kover (default: False) │
├───────────────────────────────────────────┼─────────────┼───────────────────────────────┤
│ experimental_kover_agent │ label │ Kover agent JAR target │
├───────────────────────────────────────────┼─────────────┼───────────────────────────────┤
│ experimental_kover_exclude │ string_list │ Class exclusion patterns │
├───────────────────────────────────────────┼─────────────┼───────────────────────────────┤
│ experimental_kover_exclude_annotation │ string_list │ Annotation-based exclusions │
├───────────────────────────────────────────┼─────────────┼───────────────────────────────┤
│ experimental_kover_exclude_inherited_from │ string_list │ Inherited class exclusions │
└───────────────────────────────────────────┴─────────────┴───────────────────────────────┘
Updated functions:
- _kotlin_toolchain_impl: Adds Kover attributes to toolchain info
- define_kt_toolchain: Adds Kover parameters to public API
---
Architecture Diagram
┌─────────────────────────────────────────────────────────────────┐
│ bazel coverage //test │
└─────────────────────────────────────────────────────────────────┘
│
┌───────────────┴───────────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Kover Enabled │ │ JaCoCo Path │
└──────────────┘ └──────────────┘
│ │
▼ ▼
┌───────────────────┐ ┌─────────────────────┐
│ No recompilation │ │ Bytecode modified │
│ Agent instruments │ │ at compile time │
│ at runtime │ └─────────────────────┘
└───────────────────┘
│
▼
┌───────────────────┐
│ test-kover.args.txt│ ← Agent configuration
│ test-kover_report.ic│ ← Binary coverage data
│ test-kover_metadata.txt│ ← CLI report args
└───────────────────┘
│
▼
┌───────────────────────────────────────┐
│ External: java -jar kover-cli.jar │
│ report @metadata.txt │
└───────────────────────────────────────┘
Usage
To enable Kover in your project:
define_kt_toolchain(
name = "kotlin_toolchain",
experimental_kover_enabled = True,
experimental_kover_agent = "@maven//:org_jetbrains_kotlinx_kover_jvm_agent",
experimental_kover_exclude = ["com.example.generated.*"],
experimental_kover_exclude_annotation = ["Generated"],
)
Then run: bazel coverage //your/kotlin/test_target
Android Code Duplication
kt_android_local_test_impl.bzl duplicates significant logic from rules_android. This needs to be kept in sync manually. There's ongoing work with Google to add better
extensibility points to rules_android.
Summary
This PR adds Kover (JetBrains' Kotlin code coverage tool) as an alternative to JaCoCo for code coverage in
rules_kotlin.Why Kover?
New Toolchain Attributes
Usage
Output files are created alongside test outputs:
*-kover_report.ic- Binary coverage data*-kover_metadata.txt- Metadata for Kover CLI report generationGenerate reports with:
Changes
kt_jvm_testNotes
-Xbootclasspath/a:and-javaagent:to support code using the bootstrap classloaderTest plan
get_kover_jvm_flagsfunctionUsage
To enable Kover in your project:
Android Code Duplication
kt_android_local_test_impl.bzl duplicates significant logic from rules_android. This needs to be kept in sync manually. There's ongoing work with Google to add better extensibility points to rules_android.