When working with multi-project build setups in SBT, running coverage tools like sbt-scoverage across the entire build often results in benign yet noisy warnings. If you have a root project, non-Scala modules, or Scala subprojects without unit tests, running sbt coverage test coverageReport typically yields output like this:

[info] Reading scoverage instrumentation [/path/to/my-project/not-scala/target/scala-2.13/scoverage-data/scoverage.coverage]
[warn] No coverage data, skipping reports

While this warning does not break your build, it adds unnecessary noise to your CI/CD logs. Fortunately, there are clean ways to suppress these warnings depending on your project structure.

Method 1: Disable Scoverage Plugin on Specific Projects (Recommended)

The cleanest approach is to disable the ScoverageSbtPlugin entirely on subprojects that do not contain testable Scala code or on the root aggregation project itself. Because sbt-scoverage is an AutoPlugin, it automatically attaches to all projects in your build unless explicitly told not to.

You can use .disablePlugins(ScoverageSbtPlugin) in your build.sbt file:

// Root project aggregation
lazy val root = (project in file("."))
  .aggregate(scalaA, scalaB, notScala, scalaNoTests)
  .settings(
    name := "my-project"
  )
  .disablePlugins(ScoverageSbtPlugin)

// Non-Scala subproject
lazy val notScala = (project in file("not-scala"))
  .disablePlugins(ScoverageSbtPlugin)

// Scala project with no application code/tests
lazy val scalaNoTests = (project in file("scala-no-tests"))
  .disablePlugins(ScoverageSbtPlugin)

By disabling the plugin on these modules, SBT skips generating coverage metadata and attempting to read instrumentation for them, completely eliminating the warning.

Method 2: Skip Coverage Reporting Per Project

If you still want coverage settings present in subprojects for potential future tests, but want to skip report generation when running task aggregations, you can set the coverageReport / skip key to true (for modern sbt-scoverage versions like 2.x):

lazy val scalaNoTests = (project in file("scala-no-tests"))
  .settings(
    coverageReport / skip := true
  )

Alternatively, you can explicitly set coverage to disabled for that specific scope:

lazy val notScala = (project in file("not-scala"))
  .settings(
    coverageEnabled := false
  )

Summary

  • Root or Non-Scala projects: Use .disablePlugins(ScoverageSbtPlugin) to completely detach coverage tasks and avoid unnecessary warnings.
  • Scala modules without tests: Either disable the plugin or configure coverageReport / skip := true in the project's settings.

Applying these adjustments ensures your build logs stay clean, concise, and focused on actual test results and coverage metrics.