summaryrefslogtreecommitdiff
path: root/contrib/scoverage/src/ScoverageModule.scala
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/scoverage/src/ScoverageModule.scala')
-rw-r--r--contrib/scoverage/src/ScoverageModule.scala122
1 files changed, 122 insertions, 0 deletions
diff --git a/contrib/scoverage/src/ScoverageModule.scala b/contrib/scoverage/src/ScoverageModule.scala
new file mode 100644
index 00000000..b96afa34
--- /dev/null
+++ b/contrib/scoverage/src/ScoverageModule.scala
@@ -0,0 +1,122 @@
+package mill
+package contrib
+package scoverage
+
+import coursier.{Cache, MavenRepository}
+import mill.api.Result
+import mill.eval.PathRef
+import mill.util.Ctx
+import mill.scalalib.{DepSyntax, JavaModule, Lib, ScalaModule, TestModule, Dep}
+import mill.moduledefs.Cacher
+
+
+/** Adds targets to a [[mill.scalalib.ScalaModule]] to create test coverage reports.
+ *
+ * This module allows you to generate code coverage reports for Scala projects with
+ * [[https://github.com/scoverage Scoverage]] via the
+ * [[https://github.com/scoverage/scalac-scoverage-plugin scoverage compiler plugin]].
+ *
+ * To declare a module for which you want to generate coverage reports you can
+ * Extends the `mill.contrib.scoverage.ScoverageModule` trait when defining your
+ * Module. Additionally, you must define a submodule that extends the
+ * `ScoverageTests` trait that belongs to your instance of `ScoverageModule`.
+ *
+ * {{{
+ * // You have to replace VERSION
+ * import $ivy.`com.lihaoyi::mill-contrib-buildinfo:VERSION`
+ * import mill.contrib.scoverage.ScoverageModule
+ *
+ * Object foo extends ScoverageModule {
+ * def scalaVersion = "2.11.8"
+ * def scoverageVersion = "1.3.1"
+ *
+ * object test extends ScoverageTests {
+ * def ivyDeps = Agg(ivy"org.scalatest::scalatest:3.0.5")
+ * def testFrameworks = Seq("org.scalatest.tools.Framework")
+ * }
+ * }
+ * }}}
+ *
+ * In addition to the normal tasks available to your Scala module, Scoverage
+ * Modules introduce a few new tasks and changes the behavior of an existing one.
+ *
+ * - mill foo.scoverage.compile # compiles your module with test instrumentation
+ * # (you don't have to run this manually, running the test task will force its invocation)
+ *
+ * - mill foo.test # tests your project and collects metrics on code coverage
+ * - mill foo.scoverage.htmlReport # uses the metrics collected by a previous test run to generate a coverage report in html format
+ *
+ * The measurement data is available at `out/foo/scoverage/data/`,
+ * And the html report is saved in `out/foo/scoverage/htmlReport/`.
+ */
+trait ScoverageModule extends ScalaModule { outer: ScalaModule =>
+ def scoverageVersion: T[String]
+ private def scoverageRuntimeDep = T {
+ ivy"org.scoverage::scalac-scoverage-runtime:${outer.scoverageVersion()}"
+ }
+ private def scoveragePluginDep = T {
+ ivy"org.scoverage::scalac-scoverage-plugin:${outer.scoverageVersion()}"
+ }
+
+ private def toolsClasspath = T {
+ scoverageReportWorkerClasspath() ++ scoverageClasspath()
+ }
+
+ def scoverageClasspath = T {
+ Lib.resolveDependencies(
+ Seq(Cache.ivy2Local, MavenRepository("https://repo1.maven.org/maven2")),
+ Lib.depToDependency(_, outer.scalaVersion()),
+ Seq(scoveragePluginDep()),
+ ctx = Some(implicitly[mill.util.Ctx.Log])
+ )
+ }
+
+ def scoverageReportWorkerClasspath = T {
+ val workerKey = "MILL_SCOVERAGE_REPORT_WORKER_" + scoverageVersion().replace(".", "_")
+ mill.modules.Util.millProjectModule(
+ workerKey,
+ s"mill-contrib-scoverage-worker-${outer.scoverageVersion()}",
+ repositories,
+ resolveFilter = _.toString.contains("mill-contrib-scoverage-worker")
+ )
+ }
+
+ object scoverage extends ScalaModule {
+ def selfDir = T { T.ctx().dest / os.up / os.up }
+ def dataDir = T { selfDir() / "data" }
+
+ def sources = outer.sources
+ def resources = outer.resources
+ def scalaVersion = outer.scalaVersion()
+ def compileIvyDeps = outer.compileIvyDeps()
+ def ivyDeps = outer.ivyDeps() ++ Agg(outer.scoverageRuntimeDep())
+ def scalacPluginIvyDeps = outer.scalacPluginIvyDeps() ++ Agg(outer.scoveragePluginDep())
+ def scalacOptions = outer.scalacOptions() ++
+ Seq(s"-P:scoverage:dataDir:${dataDir()}")
+
+ def htmlReport() = T.command {
+ ScoverageReportWorkerApi
+ .scoverageReportWorker()
+ .bridge(toolsClasspath().map(_.path))
+ .htmlReport(sources(), dataDir().toString, selfDir().toString)
+ }
+ }
+
+ trait ScoverageTests extends outer.Tests {
+ override def upstreamAssemblyClasspath = T {
+ super.upstreamAssemblyClasspath() ++
+ resolveDeps(T.task{Agg(outer.scoverageRuntimeDep())})()
+ }
+ override def compileClasspath = T {
+ super.compileClasspath() ++
+ resolveDeps(T.task{Agg(outer.scoverageRuntimeDep())})()
+ }
+ override def runClasspath = T {
+ super.runClasspath() ++
+ resolveDeps(T.task{Agg(outer.scoverageRuntimeDep())})()
+ }
+
+ // Need the sources compiled with scoverage instrumentation to run.
+ override def moduleDeps: Seq[JavaModule] = Seq(outer.scoverage)
+ }
+}