1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
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)
}
}
|