Open johnynek opened 7 years ago
I believe this issue could be closed as Jacoco code coverage for Scala works.
Thanks! from your previous post it sounds like it works but in awkward way. Is this bazel's fault, rules_scala's fault or just how coverage business works? (We don't do coverage internally so I don't really know)
I believe this issue could be closed as Jacoco code coverage for Scala works.
If we have a working example can we document it. Some times as passed so things may have changed but this is where we're currently blocked
scala_rules@5261499b0485f33799a1b210796fcdfa720a5344 bazel@1.2.1
bazel coverage //...
[snip]
*** RUN ABORTED *** (857 milliseconds)
java.lang.NoClassDefFoundError: org/jacoco/agent/rt/internal_1f1cc91/Offline
at com.meetup.base.secret.Secrets.<clinit>(Secrets.java)
at sun.reflect.GeneratedSerializationConstructorAccessor1.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:45)
at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
at org.mockito.internal.creation.instance.ObjenesisInstantiator.newInstance(ObjenesisInstantiator.java:14)
at org.mockito.internal.creation.cglib.ClassImposterizer.createProxy(ClassImposterizer.java:143)
at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:58)
at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:49)
at org.mockito.internal.creation.cglib.CglibMockMaker.createMock(CglibMockMaker.java:24)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:33)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:59)
at org.mockito.Mockito.mock(Mockito.java:1285)
at org.mockito.Mockito.mock(Mockito.java:1163)
at org.scalatest.mockito.MockitoSugar$class.mock(MockitoSugar.scala:73)
at com.meetup.base.db.pool.ConnectionPoolTest.mock(ConnectionPoolTest.scala:14)
at com.meetup.base.db.pool.ConnectionPoolTest$$anonfun$1$$anonfun$apply$mcV$sp$1$$anonfun$apply$mcV$sp$3.apply(ConnectionPoolTest.scala:18)
at com.meetup.base.db.pool.ConnectionPoolTest$$anonfun$1$$anonfun$apply$mcV$sp$1$$anonfun$apply$mcV$sp$3.apply(ConnectionPoolTest.scala:17)
at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
at org.scalatest.Transformer.apply(Transformer.scala:22)
at org.scalatest.Transformer.apply(Transformer.scala:20)
at org.scalatest.FunSpecLike$$anon$1.apply(FunSpecLike.scala:454)
at org.scalatest.TestSuite$class.withFixture(TestSuite.scala:196)
at org.scalatest.FunSpec.withFixture(FunSpec.scala:1630)
at org.scalatest.FunSpecLike$class.invokeWithFixture$1(FunSpecLike.scala:451)
at org.scalatest.FunSpecLike$$anonfun$runTest$1.apply(FunSpecLike.scala:464)
at org.scalatest.FunSpecLike$$anonfun$runTest$1.apply(FunSpecLike.scala:464)
at org.scalatest.SuperEngine.runTestImpl(Engine.scala:289)
at org.scalatest.FunSpecLike$class.runTest(FunSpecLike.scala:464)
at org.scalatest.FunSpec.runTest(FunSpec.scala:1630)
at org.scalatest.FunSpecLike$$anonfun$runTests$1.apply(FunSpecLike.scala:497)
at org.scalatest.FunSpecLike$$anonfun$runTests$1.apply(FunSpecLike.scala:497)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:396)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:384)
at scala.collection.immutable.List.foreach(List.scala:392)
at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:384)
at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:373)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:410)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:384)
at scala.collection.immutable.List.foreach(List.scala:392)
at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:384)
at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:373)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:410)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:384)
at scala.collection.immutable.List.foreach(List.scala:392)
at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:384)
at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:379)
at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:461)
at org.scalatest.FunSpecLike$class.runTests(FunSpecLike.scala:497)
at org.scalatest.FunSpec.runTests(FunSpec.scala:1630)
at org.scalatest.Suite$class.run(Suite.scala:1147)
at org.scalatest.FunSpec.org$scalatest$FunSpecLike$$super$run(FunSpec.scala:1630)
at org.scalatest.FunSpecLike$$anonfun$run$1.apply(FunSpecLike.scala:501)
at org.scalatest.FunSpecLike$$anonfun$run$1.apply(FunSpecLike.scala:501)
at org.scalatest.SuperEngine.runImpl(Engine.scala:521)
at org.scalatest.FunSpecLike$class.run(FunSpecLike.scala:501)
at org.scalatest.FunSpec.run(FunSpec.scala:1630)
at org.scalatest.Suite$class.callExecuteOnSuite$1(Suite.scala:1210)
at org.scalatest.Suite$$anonfun$runNestedSuites$1.apply(Suite.scala:1257)
at org.scalatest.Suite$$anonfun$runNestedSuites$1.apply(Suite.scala:1255)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
at scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:186)
at org.scalatest.Suite$class.runNestedSuites(Suite.scala:1255)
at org.scalatest.tools.DiscoverySuite.runNestedSuites(DiscoverySuite.scala:30)
at org.scalatest.Suite$class.run(Suite.scala:1144)
at org.scalatest.tools.DiscoverySuite.run(DiscoverySuite.scala:30)
at org.scalatest.tools.SuiteRunner.run(SuiteRunner.scala:45)
at org.scalatest.tools.Runner$$anonfun$doRunRunRunDaDoRunRun$1.apply(Runner.scala:1346)
at org.scalatest.tools.Runner$$anonfun$doRunRunRunDaDoRunRun$1.apply(Runner.scala:1340)
at scala.collection.immutable.List.foreach(List.scala:392)
at org.scalatest.tools.Runner$.doRunRunRunDaDoRunRun(Runner.scala:1340)
at org.scalatest.tools.Runner$$anonfun$runOptionallyWithPassFailReporter$2.apply(Runner.scala:1011)
at org.scalatest.tools.Runner$$anonfun$runOptionallyWithPassFailReporter$2.apply(Runner.scala:1010)
at org.scalatest.tools.Runner$.withClassLoaderAndDispatchReporter(Runner.scala:1506)
at org.scalatest.tools.Runner$.runOptionallyWithPassFailReporter(Runner.scala:1010)
at org.scalatest.tools.Runner$.main(Runner.scala:827)
at org.scalatest.tools.Runner.main(Runner.scala)
at io.bazel.rulesscala.scala_test.Runner.main(Runner.java:34)
Cause: java.lang.ClassNotFoundException: org.jacoco.agent.rt.internal_1f1cc91.Offline
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at com.meetup.base.secret.Secrets.<clinit>(Secrets.java)
at sun.reflect.GeneratedSerializationConstructorAccessor1.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:45)
at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
at org.mockito.internal.creation.instance.ObjenesisInstantiator.newInstance(ObjenesisInstantiator.java:14)
at org.mockito.internal.creation.cglib.ClassImposterizer.createProxy(ClassImposterizer.java:143)
at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:58)
at org.mockito.internal.creation.cglib.ClassImposterizer.imposterise(ClassImposterizer.java:49)
at org.mockito.internal.creation.cglib.CglibMockMaker.createMock(CglibMockMaker.java:24)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:33)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:59)
at org.mockito.Mockito.mock(Mockito.java:1285)
at org.mockito.Mockito.mock(Mockito.java:1163)
at org.scalatest.mockito.MockitoSugar$class.mock(MockitoSugar.scala:73)
at com.meetup.base.db.pool.ConnectionPoolTest.mock(ConnectionPoolTest.scala:14)
at com.meetup.base.db.pool.ConnectionPoolTest$$anonfun$1$$anonfun$apply$mcV$sp$1$$anonfun$apply$mcV$sp$3.apply(ConnectionPoolTest.scala:18)
at com.meetup.base.db.pool.ConnectionPoolTest$$anonfun$1$$anonfun$apply$mcV$sp$1$$anonfun$apply$mcV$sp$3.apply(ConnectionPoolTest.scala:17)
at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
at org.scalatest.Transformer.apply(Transformer.scala:22)
at org.scalatest.Transformer.apply(Transformer.scala:20)
at org.scalatest.FunSpecLike$$anon$1.apply(FunSpecLike.scala:454)
at org.scalatest.TestSuite$class.withFixture(TestSuite.scala:196)
at org.scalatest.FunSpec.withFixture(FunSpec.scala:1630)
at org.scalatest.FunSpecLike$class.invokeWithFixture$1(FunSpecLike.scala:451)
at org.scalatest.FunSpecLike$$anonfun$runTest$1.apply(FunSpecLike.scala:464)
at org.scalatest.FunSpecLike$$anonfun$runTest$1.apply(FunSpecLike.scala:464)
at org.scalatest.SuperEngine.runTestImpl(Engine.scala:289)
at org.scalatest.FunSpecLike$class.runTest(FunSpecLike.scala:464)
at org.scalatest.FunSpec.runTest(FunSpec.scala:1630)
at org.scalatest.FunSpecLike$$anonfun$runTests$1.apply(FunSpecLike.scala:497)
at org.scalatest.FunSpecLike$$anonfun$runTests$1.apply(FunSpecLike.scala:497)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:396)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:384)
at scala.collection.immutable.List.foreach(List.scala:392)
at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:384)
at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:373)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:410)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:384)
at scala.collection.immutable.List.foreach(List.scala:392)
at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:384)
at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:373)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:410)
at org.scalatest.SuperEngine$$anonfun$traverseSubNodes$1$1.apply(Engine.scala:384)
at scala.collection.immutable.List.foreach(List.scala:392)
at org.scalatest.SuperEngine.traverseSubNodes$1(Engine.scala:384)
at org.scalatest.SuperEngine.org$scalatest$SuperEngine$$runTestsInBranch(Engine.scala:379)
at org.scalatest.SuperEngine.runTestsImpl(Engine.scala:461)
at org.scalatest.FunSpecLike$class.runTests(FunSpecLike.scala:497)
at org.scalatest.FunSpec.runTests(FunSpec.scala:1630)
at org.scalatest.Suite$class.run(Suite.scala:1147)
at org.scalatest.FunSpec.org$scalatest$FunSpecLike$$super$run(FunSpec.scala:1630)
at org.scalatest.FunSpecLike$$anonfun$run$1.apply(FunSpecLike.scala:501)
at org.scalatest.FunSpecLike$$anonfun$run$1.apply(FunSpecLike.scala:501)
at org.scalatest.SuperEngine.runImpl(Engine.scala:521)
at org.scalatest.FunSpecLike$class.run(FunSpecLike.scala:501)
at org.scalatest.FunSpec.run(FunSpec.scala:1630)
at org.scalatest.Suite$class.callExecuteOnSuite$1(Suite.scala:1210)
at org.scalatest.Suite$$anonfun$runNestedSuites$1.apply(Suite.scala:1257)
at org.scalatest.Suite$$anonfun$runNestedSuites$1.apply(Suite.scala:1255)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
at scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:186)
at org.scalatest.Suite$class.runNestedSuites(Suite.scala:1255)
at org.scalatest.tools.DiscoverySuite.runNestedSuites(DiscoverySuite.scala:30)
at org.scalatest.Suite$class.run(Suite.scala:1144)
at org.scalatest.tools.DiscoverySuite.run(DiscoverySuite.scala:30)
at org.scalatest.tools.SuiteRunner.run(SuiteRunner.scala:45)
at org.scalatest.tools.Runner$$anonfun$doRunRunRunDaDoRunRun$1.apply(Runner.scala:1346)
at org.scalatest.tools.Runner$$anonfun$doRunRunRunDaDoRunRun$1.apply(Runner.scala:1340)
at scala.collection.immutable.List.foreach(List.scala:392)
at org.scalatest.tools.Runner$.doRunRunRunDaDoRunRun(Runner.scala:1340)
at org.scalatest.tools.Runner$$anonfun$runOptionallyWithPassFailReporter$2.apply(Runner.scala:1011)
at org.scalatest.tools.Runner$$anonfun$runOptionallyWithPassFailReporter$2.apply(Runner.scala:1010)
at org.scalatest.tools.Runner$.withClassLoaderAndDispatchReporter(Runner.scala:1506)
at org.scalatest.tools.Runner$.runOptionallyWithPassFailReporter(Runner.scala:1010)
at org.scalatest.tools.Runner$.main(Runner.scala:827)
at org.scalatest.tools.Runner.main(Runner.scala)
at io.bazel.rulesscala.scala_test.Runner.main(Runner.java:34)
Thanks! from your previous post it sounds like it works but in awkward way. Is this bazel's fault, rules_scala's fault or just how coverage business works? (We don't do coverage internally so I don't really know)
I believe this issue could be closed as Jacoco code coverage for Scala works.
If we have a working example can we document it. Some times as passed so things may have changed but this is where we're currently blocked
scala_rules@5261499b0485f33799a1b210796fcdfa720a5344 bazel@1.2.1
Your rules_scala version seems to be a bit old (August 2019). I tried with 26cf9b74fc46f1e9a970c97837447549ed7257b6, that is from November 2019.
Also, I used rules_jvm_external 3.1 for this test to add the JVM dependencies.
Here is a working example:
https://github.com/gergelyfabian/bazel-scala-example
Run:
bazel coverage --extra_toolchains="@io_bazel_rules_scala//test/coverage:enable_code_coverage_aspect" //...
EDIT: example was updated with multiple targets generating code coverage and a demonstration how to use genhtml (with a script inspired by Gerrit project).
Maybe this could be a documentation PR?
On Thu, 2 Jan 2020 at 18:13 Gergely Fábián notifications@github.com wrote:
Here is a working example:
https://github.com/gergelyfabian/bazel-scala-example
Run:
bazel coverage --extra_toolchains="@io_bazel_rules_scala//test/coverage:enable_code_coverage_aspect" //...
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bazelbuild/rules_scala/issues/184?email_source=notifications&email_token=AAKQQF3R7JU6FMP5NRSQWVLQ3YG4BA5CNFSM4DI3PEGKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEH6WPQQ#issuecomment-570255298, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAKQQF5NLTKMQC4RHIFEYPTQ3YG4BANCNFSM4DI3PEGA .
--
Ittai Zeidman
40 Hanamal street, Tel Aviv, Israel
Maybe this could be a documentation PR?
Sure :) However, please let me know what you mean by that, as I'm a bazel beginner :) How should I create a documentation PR, and for which component? rules_scala I guess?
I mean send a PR to rules_scala which adds a detailed explanation on how to use coverage. It sounds like this can be lengthy so maybe have a separate markdown file and link to it from the main readme?
On Tue, 7 Jan 2020 at 13:25 Gergely Fábián notifications@github.com wrote:
Maybe this could be a documentation PR?
Sure :) However, please let me know what you mean by that, as I'm a bazel beginner :) How should I create a documentation PR, and for which component? rules_scala I guess?
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bazelbuild/rules_scala/issues/184?email_source=notifications&email_token=AAKQQF2W3IM224GLIQPMKSLQ4RRBXA5CNFSM4DI3PEGKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEIIR7JY#issuecomment-571547559, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAKQQF6GB5RMABE3E2OUMELQ4RRBXANCNFSM4DI3PEGA .
--
Ittai Zeidman
40 Hanamal street, Tel Aviv, Israel
Just a quick update for anyone still paying attention: https://github.com/bazelbuild/rules_scala/pull/1006
This should completely remove the need to run any scripts to fix file paths. You should just be able to run genhtml from your directory and passing in the coverage.dat (although it will add noise to your code, but that's a different conversations :joy:)
Just a quick update for anyone still paying attention: #1006
This should completely remove the need to run any scripts to fix file paths. You should just be able to run genhtml from your directory and passing in the coverage.dat (although it will add noise to your code, but that's a different conversations )
After merging #1006 to master indeed code coverage support in rules_scala become a lot better. I confirm that for my usecase indeed simply running genhtml works without any path fixes.
@gergelyfabian great! Wdyt about sending a PR to the readme of what one should do to get coverage? Also this is only for scalatest Targets, right? I think junit/specs2 should be low cost but AFAIU they aren’t currently supported
Here is the PR for documentation on coverage: https://github.com/bazelbuild/rules_scala/pull/1017
I only tested with scalatest.
Regarding scoverage integration: FYI, as commented in
The scala side should be easy. What I don't know is how to plug in to bazel's expectations (if they are even standard). Like where should we write the coverage files to? What should the format be? https://github.com/bazelbuild/rules_scala/issues/184#issuecomment-299544682
the scala side isn't hard, we can create an extra instrumented version of build target, then it writes to the location we specified. like this https://github.com/tanishiking/bazel-playground/blob/main/18-scala-scoverage
The thing is "how to plug in to bazel's expectations (if they are even standard)", and maybe now we have good references
sluongng commented on May 11, 2021 Good references should be from rules_go: https://github.com/bazelbuild/rules_go/issues/140 (and some PRs mentioned here) https://docs.google.com/document/d/1-ZWHF-Q-qCKf19ik-t33ie58BkNurrYYzKR4OLtcilY/edit Generally Bazel's coverage is not yet complete. If your code coverage tooling does not follow the Java's convention, you gona have a bad time. https://github.com/bazelbuild/rules_rust/issues/690#issuecomment-837872013
Hey, I've been trying to get rules_scala
to integrate well with scoverage
, and I've found that it's not possible with the current scoverage
implementation 😞
I'll leave some insights I gained during my struggle.
https://github.com/tanishiking/bazel-playground/tree/main/18-scala-scoverage
While JaCoCo instrument the compiled bytecode, Scoverage instrument against the source code (Scala AST) in the very early stages of the compilation phases.
To instrument the given scala code, we'll provde the following scalacopts
-Xplugin:/path/to/plugin/scalac-scoverage-plugin_1.4.11.jar # for scoverage >2, we have to add some more deps
-P:scoverage:dataDir:/path/to/project/output
-P:scoverage:sourceRoot:/path-to/project/root
scoverage.coverage
to dataDir
specified in scalacopts.scoverage.measurements
into dataDir
specified in scalacopts.scoverage.coverage
+ scoverage.measurements
files in dataDir
s, and generate HTML or XML coverage report.Watch @ckipp01's video for more details 👍 https://www.youtube.com/watch?v=SIkNgemGmYQ
So, I tried to make PoC scoverage + rules_scala works here
https://github.com/tanishiking/bazel-playground/tree/main/18-scala-scoverage
//src/main/scala/mypackage:mypackage.instrumented
.
-P:scoverage:dataDir:/tmp/scoverage-data/src_main_scala_mypackage_mypackage.instrumented
.//src/main/scala/mypackage:mypackage.instrumented
.//src/main/scala/mypackage:mypackage.instrumented
it will write scoverage.coverage
file into specified dataDir
scoverage.measurements
into specified dataDir
.CoverageAggregator
Even though it doesn't follow "bazel way" (it generates coverage report by bazel test
, tests have to depends on instrumented targets, and it writes things into somewhere outside output base), it somehow "works".
However, there're plenty of problems with this implementation, of course.
scoverage.coverage
won't be cached.Since we specify -P:scoverage:dataDir:/tmp/...
and we don't register them as outputs
, they will of course not be cached.
As a result, when the build is cached, scoverage.coverage
won't be available and we won't be able to do any coverage aggregation. (Actually, the dataDir won't be created and invokers will fail to write measurements).
We have to make scoverage.coverage
to be cached.
Suppose we're trying to add/replace a phase using customized_phase.
phase_scalacopts
and add "-P:scoverage:dataDir": + ctx.outputs.scoverage
to scalacopts
.
bazel-workers/worker-x-scalac
at compile time (scoverage.coverage
), and it tries to write from path relative to exec root at runtime (scoverage.measurements
). It seems like we have to provide absolute path to dataDir
.-P:scoverage:dataDir
?
ctx.declare_directory("/tmp/.....")
?
Error in declare_directory: the output directory '/tmp/scoverage-data/...' is not under package directory '...' for target '...'
/tmp
directory and copy it into somewhere under bazel-out?
TreeArtifact
or File
object with bazel-skylib's copy_directory_action and ctx.actions.run_shellctx.declare_directory
to retrieve the TreeArtifact
represents the /tmp/...
directory, but we can't because of the above reason.That being said, it seems like we may want to scoverage-scalac-plugin
to write scoverage.coverage
information into output JAR file together?
scoverage.measurements
won't be cached.Since scoverage.measurements
also not registered as rule's output, they won't be cached too.
As a result, if a test is cached, the coverage data also won't be available.
The problem is scoverage-scalac-plugin will write measurements files into dataDir
specified in target under test, tests can't know where the measurements files will be written.
bazel coverage
???For JaCoCo, Bazel will instrument the compiled bytecode and create .uninstrumented
class file, and normal class files.
However, tools that instrument against source code such as scoverage and cargo-tarpaulin for Rust making two (instrumented and uninstrumented) compiled artifact means we have to run compilation twice, which seems not acceptable, especially for Scala (which isn't compile that fast).
+1
This would look like using:
https://github.com/scoverage/scalac-scoverage-plugin
to get the scala test rules to emit code coverage reports, then aggregating them across the repo.
It is related to https://github.com/bazelbuild/bazel/issues/1118 but I don't think it is actually a blocker. We may just be able to produce coverage output of each test rule, then an aspect to walk all the rules and aggregate a total.