From b2d480b2b9de6091a8e7c135dac5dd2c0f653c6b Mon Sep 17 00:00:00 2001 From: Olivier Mélois Date: Thu, 25 Apr 2019 13:59:29 +0200 Subject: Beginning of Bloop integration (#595) * Sync with latest versions, started bloop connection * BloopModule back to the bare minimum * Added first Bloop related unit-tests * More tests * Fixed global module usage. * Added resolution in bloop config * More tests, using correct repository list * revert dev change * Changed moduleSourceMap implementation * Using path-dependant trait for the module This facilitates testing by preventing the trait from referencing a global module. * Added semanticDB to bloopConfig * Added documentation * Install returns pathRefs instead of paths * bumped semanticDB * Better use of mill's cache, avoid duplication of work * addressing comments --- docs/pages/9 - Contrib Modules.md | 59 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) (limited to 'docs') diff --git a/docs/pages/9 - Contrib Modules.md b/docs/pages/9 - Contrib Modules.md index 1b9b55fa..0d65512b 100644 --- a/docs/pages/9 - Contrib Modules.md +++ b/docs/pages/9 - Contrib Modules.md @@ -912,3 +912,62 @@ Publishing to custom local Maven repository [40/40] project.publishM2Local Publishing to /tmp/m2repo ``` + +### Bloop + +This plugin generates [bloop](https://scalacenter.github.io/bloop/) configuration +from your build file, which lets you use the bloop CLI for compiling, and makes +your scala code editable in [Metals](https://scalameta.org/metals/) + + +#### Quickstart: +```scala +// build.sc (or any other .sc file it depends on, including predef) +// Don't forget to replace VERSION +import $ivy.`com.lihaoyi::mill-contrib-bloop:VERSION` +``` + +Then in your terminal : + +``` +> mill mill.contrib.Bloop/install +``` + +#### Mix-in + +You can mix-in the `Bloop.Module` trait with any JavaModule to quickly access +the deserialised configuration for that particular module: + +```scala +// build.sc +import mill._ +import mill.scalalib._ +import mill.contrib.Bloop + +object MyModule extends ScalaModule with Bloop.Module { + def myTask = T { bloop.config() } +} +``` + +#### Note regarding metals: + +Generating the bloop config should be enough for metals to pick it up and for +features to start working in vscode (or the bunch of other editors metals supports). +However, note that this applies only to your project sources. Your mill/ammonite related +`.sc` files are not yet supported by metals. + +The generated bloop config references the semanticDB compiler plugin required by +metals to function. If need be, the version of semanticDB can be overriden by +extending `mill.contrib.bloop.BloopImpl` in your own space. + +#### Note regarding current mill support in bloop + +The mill-bloop integration currently present in the [bloop codebase](https://github.com/scalacenter/bloop/blob/master/integrations/mill-bloop/src/main/scala/bloop/integrations/mill/MillBloop.scala#L10) +will be deprecated in favour of this implementation. + +#### Caveats: + +At this time, only Java/ScalaModule are processed correctly. ScalaJS/ScalaNative integration will +be added in a near future. + + -- cgit v1.2.3 From 547b29f3d0a5a2a8e3f997551272f17797cbe44d Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 25 Apr 2019 14:14:17 +0200 Subject: Fixed plugin order in docs --- docs/pages/9 - Contrib Modules.md | 121 ++++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 58 deletions(-) (limited to 'docs') diff --git a/docs/pages/9 - Contrib Modules.md b/docs/pages/9 - Contrib Modules.md index 0d65512b..be14103e 100644 --- a/docs/pages/9 - Contrib Modules.md +++ b/docs/pages/9 - Contrib Modules.md @@ -2,6 +2,8 @@ The plugins in this section are developed/maintained in the mill git tree. +[comment]: # (Please keep list of plugins in alphabetical order) + ### BuildInfo Generate scala code from your buildfile. @@ -673,6 +675,67 @@ The usage examples given here are most probably outdated and incomplete. If you develop or maintain a mill plugin, please create a [pull request](https://github.com/lihaoyi/mill/pulls) to get your plugin listed here. +[comment]: # (Please keep list of plugins in alphabetical order) + +### Bloop + +This plugin generates [bloop](https://scalacenter.github.io/bloop/) configuration +from your build file, which lets you use the bloop CLI for compiling, and makes +your scala code editable in [Metals](https://scalameta.org/metals/) + + +#### Quickstart: +```scala +// build.sc (or any other .sc file it depends on, including predef) +// Don't forget to replace VERSION +import $ivy.`com.lihaoyi::mill-contrib-bloop:VERSION` +``` + +Then in your terminal : + +``` +> mill mill.contrib.Bloop/install +``` + +#### Mix-in + +You can mix-in the `Bloop.Module` trait with any JavaModule to quickly access +the deserialised configuration for that particular module: + +```scala +// build.sc +import mill._ +import mill.scalalib._ +import mill.contrib.Bloop + +object MyModule extends ScalaModule with Bloop.Module { + def myTask = T { bloop.config() } +} +``` + +#### Note regarding metals: + +Generating the bloop config should be enough for metals to pick it up and for +features to start working in vscode (or the bunch of other editors metals supports). +However, note that this applies only to your project sources. Your mill/ammonite related +`.sc` files are not yet supported by metals. + +The generated bloop config references the semanticDB compiler plugin required by +metals to function. If need be, the version of semanticDB can be overriden by +extending `mill.contrib.bloop.BloopImpl` in your own space. + +#### Note regarding current mill support in bloop + +The mill-bloop integration currently present in the [bloop codebase](https://github.com/scalacenter/bloop/blob/master/integrations/mill-bloop/src/main/scala/bloop/integrations/mill/MillBloop.scala#L10) +will be deprecated in favour of this implementation. + +#### Caveats: + +At this time, only Java/ScalaModule are processed correctly. ScalaJS/ScalaNative integration will +be added in a near future. + + + ### DGraph Show transitive dependencies of your build in your browser. @@ -913,61 +976,3 @@ Publishing to custom local Maven repository Publishing to /tmp/m2repo ``` -### Bloop - -This plugin generates [bloop](https://scalacenter.github.io/bloop/) configuration -from your build file, which lets you use the bloop CLI for compiling, and makes -your scala code editable in [Metals](https://scalameta.org/metals/) - - -#### Quickstart: -```scala -// build.sc (or any other .sc file it depends on, including predef) -// Don't forget to replace VERSION -import $ivy.`com.lihaoyi::mill-contrib-bloop:VERSION` -``` - -Then in your terminal : - -``` -> mill mill.contrib.Bloop/install -``` - -#### Mix-in - -You can mix-in the `Bloop.Module` trait with any JavaModule to quickly access -the deserialised configuration for that particular module: - -```scala -// build.sc -import mill._ -import mill.scalalib._ -import mill.contrib.Bloop - -object MyModule extends ScalaModule with Bloop.Module { - def myTask = T { bloop.config() } -} -``` - -#### Note regarding metals: - -Generating the bloop config should be enough for metals to pick it up and for -features to start working in vscode (or the bunch of other editors metals supports). -However, note that this applies only to your project sources. Your mill/ammonite related -`.sc` files are not yet supported by metals. - -The generated bloop config references the semanticDB compiler plugin required by -metals to function. If need be, the version of semanticDB can be overriden by -extending `mill.contrib.bloop.BloopImpl` in your own space. - -#### Note regarding current mill support in bloop - -The mill-bloop integration currently present in the [bloop codebase](https://github.com/scalacenter/bloop/blob/master/integrations/mill-bloop/src/main/scala/bloop/integrations/mill/MillBloop.scala#L10) -will be deprecated in favour of this implementation. - -#### Caveats: - -At this time, only Java/ScalaModule are processed correctly. ScalaJS/ScalaNative integration will -be added in a near future. - - -- cgit v1.2.3 From 42bc4d1b28fe421949b95c57223ff4a7479c08cd Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 25 Apr 2019 14:58:20 +0200 Subject: Fixed location of bloop module docs, again --- docs/pages/9 - Contrib Modules.md | 115 +++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 57 deletions(-) (limited to 'docs') diff --git a/docs/pages/9 - Contrib Modules.md b/docs/pages/9 - Contrib Modules.md index be14103e..2f9085db 100644 --- a/docs/pages/9 - Contrib Modules.md +++ b/docs/pages/9 - Contrib Modules.md @@ -4,6 +4,64 @@ The plugins in this section are developed/maintained in the mill git tree. [comment]: # (Please keep list of plugins in alphabetical order) +### Bloop + +This plugin generates [bloop](https://scalacenter.github.io/bloop/) configuration +from your build file, which lets you use the bloop CLI for compiling, and makes +your scala code editable in [Metals](https://scalameta.org/metals/) + + +#### Quickstart: +```scala +// build.sc (or any other .sc file it depends on, including predef) +// Don't forget to replace VERSION +import $ivy.`com.lihaoyi::mill-contrib-bloop:VERSION` +``` + +Then in your terminal : + +``` +> mill mill.contrib.Bloop/install +``` + +#### Mix-in + +You can mix-in the `Bloop.Module` trait with any JavaModule to quickly access +the deserialised configuration for that particular module: + +```scala +// build.sc +import mill._ +import mill.scalalib._ +import mill.contrib.Bloop + +object MyModule extends ScalaModule with Bloop.Module { + def myTask = T { bloop.config() } +} +``` + +#### Note regarding metals: + +Generating the bloop config should be enough for metals to pick it up and for +features to start working in vscode (or the bunch of other editors metals supports). +However, note that this applies only to your project sources. Your mill/ammonite related +`.sc` files are not yet supported by metals. + +The generated bloop config references the semanticDB compiler plugin required by +metals to function. If need be, the version of semanticDB can be overriden by +extending `mill.contrib.bloop.BloopImpl` in your own space. + +#### Note regarding current mill support in bloop + +The mill-bloop integration currently present in the [bloop codebase](https://github.com/scalacenter/bloop/blob/master/integrations/mill-bloop/src/main/scala/bloop/integrations/mill/MillBloop.scala#L10) +will be deprecated in favour of this implementation. + +#### Caveats: + +At this time, only Java/ScalaModule are processed correctly. ScalaJS/ScalaNative integration will +be added in a near future. + + ### BuildInfo Generate scala code from your buildfile. @@ -677,63 +735,6 @@ If you develop or maintain a mill plugin, please create a [pull request](https:/ [comment]: # (Please keep list of plugins in alphabetical order) -### Bloop - -This plugin generates [bloop](https://scalacenter.github.io/bloop/) configuration -from your build file, which lets you use the bloop CLI for compiling, and makes -your scala code editable in [Metals](https://scalameta.org/metals/) - - -#### Quickstart: -```scala -// build.sc (or any other .sc file it depends on, including predef) -// Don't forget to replace VERSION -import $ivy.`com.lihaoyi::mill-contrib-bloop:VERSION` -``` - -Then in your terminal : - -``` -> mill mill.contrib.Bloop/install -``` - -#### Mix-in - -You can mix-in the `Bloop.Module` trait with any JavaModule to quickly access -the deserialised configuration for that particular module: - -```scala -// build.sc -import mill._ -import mill.scalalib._ -import mill.contrib.Bloop - -object MyModule extends ScalaModule with Bloop.Module { - def myTask = T { bloop.config() } -} -``` - -#### Note regarding metals: - -Generating the bloop config should be enough for metals to pick it up and for -features to start working in vscode (or the bunch of other editors metals supports). -However, note that this applies only to your project sources. Your mill/ammonite related -`.sc` files are not yet supported by metals. - -The generated bloop config references the semanticDB compiler plugin required by -metals to function. If need be, the version of semanticDB can be overriden by -extending `mill.contrib.bloop.BloopImpl` in your own space. - -#### Note regarding current mill support in bloop - -The mill-bloop integration currently present in the [bloop codebase](https://github.com/scalacenter/bloop/blob/master/integrations/mill-bloop/src/main/scala/bloop/integrations/mill/MillBloop.scala#L10) -will be deprecated in favour of this implementation. - -#### Caveats: - -At this time, only Java/ScalaModule are processed correctly. ScalaJS/ScalaNative integration will -be added in a near future. - ### DGraph -- cgit v1.2.3 From 38fce64bb4884ba0e6cf8509245bca769c03ce1b Mon Sep 17 00:00:00 2001 From: Tobias Roeser Date: Thu, 25 Apr 2019 15:09:38 +0200 Subject: Splitted up modules doc section into contrib and external modules --- docs/pages/10 - Thirdparty Modules.md | 250 +++++++++++++++++++++++++++ docs/pages/9 - Contrib Modules.md | 316 ++++------------------------------ 2 files changed, 281 insertions(+), 285 deletions(-) create mode 100644 docs/pages/10 - Thirdparty Modules.md (limited to 'docs') diff --git a/docs/pages/10 - Thirdparty Modules.md b/docs/pages/10 - Thirdparty Modules.md new file mode 100644 index 00000000..b98b9f67 --- /dev/null +++ b/docs/pages/10 - Thirdparty Modules.md @@ -0,0 +1,250 @@ + +The modules (aka plugins) in this section are developed/maintained outside the mill git tree. + +Besides the documentation provided here, we urge you to consult the respective linked plugin documentation pages. +The usage examples given here are most probably incomplete and sometimes outdated. + +If you develop or maintain a mill plugin, please create a [pull request](https://github.com/lihaoyi/mill/pulls) to get your plugin listed here. + +[comment]: # (Please keep list of plugins in alphabetical order) + +## DGraph + +Show transitive dependencies of your build in your browser. + +Project home: https://github.com/ajrnz/mill-dgraph + +### Quickstart + +```scala +import $ivy.`com.github.ajrnz::mill-dgraph:0.2.0` +``` + +```sh +sh> mill plugin.dgraph.browseDeps(proj)() +``` + +## Ensime + +Create an [.ensime](http://ensime.github.io/ "ensime") file for your build. + +Project home: https://github.com/yyadavalli/mill-ensime + +### Quickstart + +```scala +import $ivy.`fun.valycorp::mill-ensime:0.0.1` +``` + +```sh +sh> mill fun.valycorp.mill.GenEnsime/ensimeConfig +``` + +## Integration Testing Mill Plugins + +Integration testing for mill plugins. + +### Quickstart + +We assume, you have a mill plugin named `mill-demo` + +```scala +// build.sc +import mill._, mill.scalalib._ +object demo extends ScalaModule with PublishModule { + // ... +} +``` + +Add an new test sub-project, e.g. `it`. + +```scala +import $ivy.`de.tototec::de.tobiasroeser.mill.integrationtest:0.1.0` +import de.tobiasroeser.mill.integrationtest._ + +object it extends MillIntegrationTest { + + def millTestVersion = "{exampleMillVersion}" + + def pluginsUnderTest = Seq(demo) + +} +``` + +Your project should now look similar to this: + +```text +. ++-- demo/ +| +-- src/ +| ++-- it/ + +-- src/ + +-- 01-first-test/ + | +-- build.sc + | +-- src/ + | + +-- 02-second-test/ + +-- build.sc +``` + +As the buildfiles `build.sc` in your test cases typically want to access the locally built plugin(s), +the plugins publishes all plugins referenced under `pluginsUnderTest` to a temporary ivy repository, just before the test is executed. +The mill version used in the integration test then used that temporary ivy repository. + +Instead of referring to your plugin with `import $ivy.'your::plugin:version'`, +you can use the following line instead, which ensures you will use the correct locally build plugins. + +```scala +// build.sc +import $exec.plugins +``` + +Effectively, at execution time, this line gets replaced by the content of `plugins.sc`, a file which was generated just before the test started to execute. + +### Configuration and Targets + +The mill-integrationtest plugin provides the following targets. + +#### Mandatory configuration + +* `def millTestVersion: T[String]` + The mill version used for executing the test cases. + Used by `downloadMillTestVersion` to automatically download. + +* `def pluginsUnderTest: Seq[PublishModule]` - + The plugins used in the integration test. + You should at least add your plugin under test here. + You can also add additional libraries, e.g. those that assist you in the test result validation (e.g. a local test support project). + The defined modules will be published into a temporary ivy repository before the tests are executed. + In your test `build.sc` file, instead of the typical `import $ivy.` line, + you should use `import $exec.plugins` to include all plugins that are defined here. + +#### Optional configuration + +* `def sources: Sources` - + Locations where integration tests are located. + Each integration test is a sub-directory, containing a complete test mill project. + +* `def testCases: T[Seq[PathRef]]` - + The directories each representing a mill test case. + Derived from `sources`. + +* `def testTargets: T[Seq[String]]` - + The targets which are called to test the project. + Defaults to `verify`, which should implement test result validation. + +* `def downloadMillTestVersion: T[PathRef]` - + Download the mill version as defined by `millTestVersion`. + Override this, if you need to use a custom built mill version. + Returns the `PathRef` to the mill executable (must have the executable flag). + +#### Commands + +* `def test(): Command[Unit]` - + Run the integration tests. + + +## JBake + +Create static sites/blogs with JBake. + +Plugin home: https://github.com/lefou/mill-jbake + +JBake home: https://jbake.org + +### Quickstart + +```scala +// build.sc +import mill._ +import $ivy.`de.tototec::de.tobiasroeser.mill.jbake:0.1.0` +import de.tobiasroeser.mill.jbake._ + +object site extends JBakeModule { + + def jbakeVersion = "2.6.4" + +} +``` + +Generate the site: + +```sh +bash> mill site.jbake +``` + +Start a local Web-Server on Port 8820 with the generated site: + +```sh +bash> mill site.jbakeServe +``` + + +## OSGi + +Produce OSGi Bundles with mill. + +Project home: https://github.com/lefou/mill-osgi + +### Quickstart + +```scala +import mill._, mill.scalalib._ +import $ivy.`de.tototec::de.tobiasroeser.mill.osgi:0.0.5` +import de.tobiasroeser.mill.osgi._ + +object project extends ScalaModule with OsgiBundleModule { + + def bundleSymbolicName = "com.example.project" + + def osgiHeaders = T{ super.osgiHeaders().copy( + `Export-Package` = Seq("com.example.api"), + `Bundle-Activator` = Some("com.example.internal.Activator") + )} + + // other settings ... + +} +``` + + +## PublishM2 + +Mill plugin to publish artifacts into a local Maven repository. + +Project home: https://github.com/lefou/mill-publishM2 + +### Quickstart + +Just mix-in the `PublishM2Module` into your project. +`PublishM2Module` already extends mill's built-in `PublishModule`. + +File: `build.sc` +```scala +import mill._, scalalib._, publish._ + +import $ivy.`de.tototec::de.tobiasroeser.mill.publishM2:0.0.1` +import de.tobiasroeser.mill.publishM2._ + +object project extends PublishModule with PublishM2Module { + // ... +} +``` + +Publishing to default local Maven repository + +```bash +> mill project.publishM2Local +[40/40] project.publishM2Local +Publishing to /home/user/.m2/repository +``` + +Publishing to custom local Maven repository + +```bash +> mill project.publishM2Local /tmp/m2repo +[40/40] project.publishM2Local +Publishing to /tmp/m2repo +``` + diff --git a/docs/pages/9 - Contrib Modules.md b/docs/pages/9 - Contrib Modules.md index 2f9085db..eca61be3 100644 --- a/docs/pages/9 - Contrib Modules.md +++ b/docs/pages/9 - Contrib Modules.md @@ -1,17 +1,18 @@ -## Contrib Modules The plugins in this section are developed/maintained in the mill git tree. +When using one of these, you should make sure to use the versions that matches your mill version. + [comment]: # (Please keep list of plugins in alphabetical order) -### Bloop +## Bloop This plugin generates [bloop](https://scalacenter.github.io/bloop/) configuration from your build file, which lets you use the bloop CLI for compiling, and makes your scala code editable in [Metals](https://scalameta.org/metals/) -#### Quickstart: +### Quickstart ```scala // build.sc (or any other .sc file it depends on, including predef) // Don't forget to replace VERSION @@ -24,7 +25,7 @@ Then in your terminal : > mill mill.contrib.Bloop/install ``` -#### Mix-in +### Mix-in You can mix-in the `Bloop.Module` trait with any JavaModule to quickly access the deserialised configuration for that particular module: @@ -40,7 +41,7 @@ object MyModule extends ScalaModule with Bloop.Module { } ``` -#### Note regarding metals: +### Note regarding metals Generating the bloop config should be enough for metals to pick it up and for features to start working in vscode (or the bunch of other editors metals supports). @@ -51,18 +52,18 @@ The generated bloop config references the semanticDB compiler plugin required by metals to function. If need be, the version of semanticDB can be overriden by extending `mill.contrib.bloop.BloopImpl` in your own space. -#### Note regarding current mill support in bloop +### Note regarding current mill support in bloop The mill-bloop integration currently present in the [bloop codebase](https://github.com/scalacenter/bloop/blob/master/integrations/mill-bloop/src/main/scala/bloop/integrations/mill/MillBloop.scala#L10) will be deprecated in favour of this implementation. -#### Caveats: +### Caveats At this time, only Java/ScalaModule are processed correctly. ScalaJS/ScalaNative integration will be added in a near future. -### BuildInfo +## BuildInfo Generate scala code from your buildfile. This plugin generates a single object containing information from your build. @@ -87,7 +88,7 @@ object project extends BuildInfo { } ``` -#### Configuration options +### Configuration options * `def buildInfoMembers: T[Map[String, String]]` The map containing all member names and values for the generated info object. @@ -99,7 +100,7 @@ object project extends BuildInfo { The package name of the object. -### Flyway +## Flyway Enables you to configure and run [Flyway](https://flywaydb.org/) commands from your mill build file. The flyway module currently supports the most common flyway use cases with file based migrations. @@ -143,7 +144,7 @@ mill foo.flywayMigrate > You should write some code to populate the settings for flyway instead. > For example `def flywayPassword = T.input(T.ctx().env("FLYWAY_PASSWORD"))` -### Play Framework +## Play Framework This module adds basic Play Framework support to mill: @@ -156,7 +157,7 @@ This module adds basic Play Framework support to mill: There is no specific Play Java support, building a Play Java application will require a bit of customization (mostly adding the proper dependencies). -#### Using the plugin +### Using the plugin There are 2 base modules and 2 helper traits in this plugin, all of which can be found in `mill.playlib`. @@ -178,7 +179,7 @@ directories at the top level alongside the `build.sc` file. This trait takes car * `RouterModule` allows you to use the Play router without the rest of the configuration (see [Using the router module directly](#using-the-router-module-directly).) -#### Using `PlayModule` +### Using `PlayModule` In order to use the `PlayModule` for your application, you need to provide the scala, Play and Twirl versions. You also need to define your own test object which extends the provided @@ -245,7 +246,7 @@ In order to have a working `start` command the following runtime dependency is a ivy"com.typesafe.play::play-akka-http-server:${playVersion()}" ``` -#### Using `PlayApiModule` +### Using `PlayApiModule` The `PlayApiModule` trait behaves the same as the `PlayModule` trait but it won't process .scala .html files and you don't need to define the `twirlVersion: @@ -266,12 +267,12 @@ object core extends PlayApiModule { } ``` -#### Play configuration options +### Play configuration options The Play modules themselves don't have specific configuration options at this point but the [router module configuration options](#router-configuration-options) and the [Twirl module configuration options](#twirl-configuration-options) are applicable. -#### Additional play libraries +### Additional play libraries The following helpers are available to provide additional Play Framework dependencies: @@ -306,7 +307,7 @@ object core extends PlayApiModule { } ``` -#### Commands equivalence +### Commands equivalence Mill commands are targets on a named build. For example if your build is called `core`: @@ -322,7 +323,7 @@ starts a server in *PROD* mode which: command to get a runnable fat jar of the project. The packaging is slightly different but should be find for a production deployment. -#### Using `SingleModule` +### Using `SingleModule` The `SingleModule` trait allows you to have the build descriptor at the same level as the source code on the filesystem. You can move from there to a multi-module build either by refactoring @@ -410,7 +411,7 @@ the layout becomes: └── controllers ``` -##### Using the router module directly +#### Using the router module directly If you want to use the router module in a project which doesn't use the default Play layout, you can mix-in the `mill.playlib.routesModule` trait directly when defining your module. Your app must @@ -429,7 +430,7 @@ object app extends ScalaModule with RouterModule { } ``` -###### Router Configuration options +##### Router Configuration options * `def playVersion: T[String]` (mandatory) - The version of Play to use to compile the routes file. * `def scalaVersion: T[String]` - The scalaVersion in use in your project. @@ -442,7 +443,7 @@ object app extends ScalaModule with RouterModule { * `def generatorType: RouteCompilerType = RouteCompilerType.InjectedGenerator` - The routes compiler type, one of RouteCompilerType.InjectedGenerator or RouteCompilerType.StaticGenerator -###### Details +##### Details The following filesystem layout is expected by default: @@ -483,7 +484,7 @@ object app extends ScalaModule with RouterModule { ``` -### ScalaPB +## ScalaPB This module allows [ScalaPB](https://scalapb.github.io) to be used in Mill builds. ScalaPB is a [Protocol Buffers](https://developers.google.com/protocol-buffers/) compiler plugin that generates Scala case classes, encoders and decoders for protobuf messages. @@ -514,7 +515,7 @@ example/ resources/ ``` -#### Configuration options +### Configuration options * scalaPBVersion (mandatory) - The ScalaPB version `String` e.g. `"0.7.4"` @@ -542,7 +543,7 @@ object example extends ScalaPBModule { } ``` -### TestNG +## TestNG Provides support for [TestNG](https://testng.org/doc/index.html). @@ -559,7 +560,7 @@ object project extends ScalaModule { } ``` -### Tut +## Tut This module allows [Tut](https://tpolecat.github.io/tut) to be used in Mill builds. Tut is a documentation tool which compiles and evaluates Scala code in documentation files and provides various options for configuring how the results will be displayed in the compiled documentation. @@ -598,7 +599,7 @@ In order to compile documentation we can execute the `tut` task in the module: sh> mill example.tut ``` -#### Configuration options +### Configuration options * tutSourceDirectory - This task determines where documentation files must be placed in order to be compiled with Tut. By default this is the `tut` folder at the root of the module. @@ -618,7 +619,7 @@ sh> mill example.tut * tutPluginJars - A task which performs the dependency resolution for the scalac plugins to be used with Tut. -### Twirl +## Twirl Twirl templates support. @@ -637,7 +638,7 @@ object app extends ScalaModule with TwirlModule { } ``` -#### Twirl configuration options +### Twirl configuration options * `def twirlVersion: T[String]` (mandatory) - the version of the twirl compiler to use, like "1.3.15" * `def twirlAdditionalImports: Seq[String] = Nil` - the additional imports that will be added by twirl compiler to the top of all templates @@ -645,7 +646,7 @@ object app extends ScalaModule with TwirlModule { * `def twirlCodec = Codec(Properties.sourceEncoding)` - the codec used to generate the files (the default is the same sbt plugin uses) * `def twirlInclusiveDot: Boolean = false` -#### Details +### Details The following filesystem layout is expected: @@ -719,261 +720,6 @@ Seq( These imports will always be added to every template. You don't need to list them if you override `twirlAdditionalImports`. -#### Example +### Example There's an [example project](https://github.com/lihaoyi/cask/tree/master/example/twirl) - - -## Thirdparty Mill Plugins - -The plugins in this section are developed/maintained outside the mill git tree. - -Besides the documentation provided here, we urge you to consult the respective linked plugin documentation pages. -The usage examples given here are most probably outdated and incomplete. - -If you develop or maintain a mill plugin, please create a [pull request](https://github.com/lihaoyi/mill/pulls) to get your plugin listed here. - -[comment]: # (Please keep list of plugins in alphabetical order) - - - -### DGraph - -Show transitive dependencies of your build in your browser. - -Project home: https://github.com/ajrnz/mill-dgraph - -#### Quickstart - -```scala -import $ivy.`com.github.ajrnz::mill-dgraph:0.2.0` -``` - -```sh -sh> mill plugin.dgraph.browseDeps(proj)() -``` - -### Ensime - -Create an [.ensime](http://ensime.github.io/ "ensime") file for your build. - -Project home: https://github.com/yyadavalli/mill-ensime - -#### Quickstart - -```scala -import $ivy.`fun.valycorp::mill-ensime:0.0.1` -``` - -```sh -sh> mill fun.valycorp.mill.GenEnsime/ensimeConfig -``` - -### Integration Testing Mill Plugins - -Integration testing for mill plugins. - -#### Quickstart - -We assume, you have a mill plugin named `mill-demo` - -```scala -// build.sc -import mill._, mill.scalalib._ -object demo extends ScalaModule with PublishModule { - // ... -} -``` - -Add an new test sub-project, e.g. `it`. - -```scala -import $ivy.`de.tototec::de.tobiasroeser.mill.integrationtest:0.1.0` -import de.tobiasroeser.mill.integrationtest._ - -object it extends MillIntegrationTest { - - def millTestVersion = "{exampleMillVersion}" - - def pluginsUnderTest = Seq(demo) - -} -``` - -Your project should now look similar to this: - -```text -. -+-- demo/ -| +-- src/ -| -+-- it/ - +-- src/ - +-- 01-first-test/ - | +-- build.sc - | +-- src/ - | - +-- 02-second-test/ - +-- build.sc -``` - -As the buildfiles `build.sc` in your test cases typically want to access the locally built plugin(s), -the plugins publishes all plugins referenced under `pluginsUnderTest` to a temporary ivy repository, just before the test is executed. -The mill version used in the integration test then used that temporary ivy repository. - -Instead of referring to your plugin with `import $ivy.'your::plugin:version'`, -you can use the following line instead, which ensures you will use the correct locally build plugins. - -```scala -// build.sc -import $exec.plugins -``` - -Effectively, at execution time, this line gets replaced by the content of `plugins.sc`, a file which was generated just before the test started to execute. - -#### Configuration and Targets - -The mill-integrationtest plugin provides the following targets. - -##### Mandatory configuration - -* `def millTestVersion: T[String]` - The mill version used for executing the test cases. - Used by `downloadMillTestVersion` to automatically download. - -* `def pluginsUnderTest: Seq[PublishModule]` - - The plugins used in the integration test. - You should at least add your plugin under test here. - You can also add additional libraries, e.g. those that assist you in the test result validation (e.g. a local test support project). - The defined modules will be published into a temporary ivy repository before the tests are executed. - In your test `build.sc` file, instead of the typical `import $ivy.` line, - you should use `import $exec.plugins` to include all plugins that are defined here. - -##### Optional configuration - -* `def sources: Sources` - - Locations where integration tests are located. - Each integration test is a sub-directory, containing a complete test mill project. - -* `def testCases: T[Seq[PathRef]]` - - The directories each representing a mill test case. - Derived from `sources`. - -* `def testTargets: T[Seq[String]]` - - The targets which are called to test the project. - Defaults to `verify`, which should implement test result validation. - -* `def downloadMillTestVersion: T[PathRef]` - - Download the mill version as defined by `millTestVersion`. - Override this, if you need to use a custom built mill version. - Returns the `PathRef` to the mill executable (must have the executable flag). - -##### Commands - -* `def test(): Command[Unit]` - - Run the integration tests. - - -### JBake - -Create static sites/blogs with JBake. - -Plugin home: https://github.com/lefou/mill-jbake - -JBake home: https://jbake.org - -#### Quickstart - -```scala -// build.sc -import mill._ -import $ivy.`de.tototec::de.tobiasroeser.mill.jbake:0.1.0` -import de.tobiasroeser.mill.jbake._ - -object site extends JBakeModule { - - def jbakeVersion = "2.6.4" - -} -``` - -Generate the site: - -```sh -bash> mill site.jbake -``` - -Start a local Web-Server on Port 8820 with the generated site: - -```sh -bash> mill site.jbakeServe -``` - - -### OSGi - -Produce OSGi Bundles with mill. - -Project home: https://github.com/lefou/mill-osgi - -#### Quickstart - -```scala -import mill._, mill.scalalib._ -import $ivy.`de.tototec::de.tobiasroeser.mill.osgi:0.0.5` -import de.tobiasroeser.mill.osgi._ - -object project extends ScalaModule with OsgiBundleModule { - - def bundleSymbolicName = "com.example.project" - - def osgiHeaders = T{ super.osgiHeaders().copy( - `Export-Package` = Seq("com.example.api"), - `Bundle-Activator` = Some("com.example.internal.Activator") - )} - - // other settings ... - -} -``` - - -### PublishM2 - -Mill plugin to publish artifacts into a local Maven repository. - -Project home: https://github.com/lefou/mill-publishM2 - -#### Quickstart - -Just mix-in the `PublishM2Module` into your project. -`PublishM2Module` already extends mill's built-in `PublishModule`. - -File: `build.sc` -```scala -import mill._, scalalib._, publish._ - -import $ivy.`de.tototec::de.tobiasroeser.mill.publishM2:0.0.1` -import de.tobiasroeser.mill.publishM2._ - -object project extends PublishModule with PublishM2Module { - // ... -} -``` - -Publishing to default local Maven repository - -```bash -> mill project.publishM2Local -[40/40] project.publishM2Local -Publishing to /home/user/.m2/repository -``` - -Publishing to custom local Maven repository - -```bash -> mill project.publishM2Local /tmp/m2repo -[40/40] project.publishM2Local -Publishing to /tmp/m2repo -``` - -- cgit v1.2.3 From c4a65baab92890d2d5682329a87469bec605fe5d Mon Sep 17 00:00:00 2001 From: Nik Vanderhoof Date: Sat, 18 May 2019 23:22:13 -0400 Subject: Add support for Scoverage (#571) * Add initial work for ScoverageModule * style: Move package scoverage from lib to contrib Suggested by @lefou > I think, it would be better to add under `mill.contrib.scoverage`. Pull request: #571 * Initial changes to non-hardcoded scoverage version * Using task context api to specify dataDir Now measurement data will be written to: PROJECT_ROOT/out/MODULE/scoverage/data/ and the html report will be written to: PROJECT_ROOT/out/MODULE/scoverage/data/htmlReport/ * Remove wild card imports in scoverage Also remove scoverage dependency from build.sc * Move htmlReport into worker Based on what I've seen in scalalib, scalajslib, scalanativelib, playlib, and twirllib modules. Still need to add tests * Add basic docs + tests for scoverage I still am working on testing the actual generation of reports. * Use cross-module for scoverage worker Now we can support multiple versions of scoverage by adding them to the crossmodule list. Also now running the local publish script succeeds. * Add scoverage to ci tests * Add detailed ScoverageModule documentation * Test scoverage dataDir * Remove
 tags in scaladoc

* Add scoverage dependency in less hacky way

* Modify scoverage tests to check classpaths

* Put docs in alphabetical order

* Test classpaths for scoverage runtime

* Remove abstract def test: ScoverageTests

* Construct classloader differently

* Revert "Construct classloader differently"

This reverts commit fccf9a94cc38fb9e2be58a9ff90b00b65f339db6.

* Revert "Construct classloader differently"

Also fixes unfound error in html report

This reverts commit fccf9a94cc38fb9e2be58a9ff90b00b65f339db6.

* Fix classpath for scoverage worker
---
 build.sc                                           |  27 ++++-
 ci/test-mill-0.sh                                  |   3 +-
 ci/test-mill-bootstrap.sh                          |   2 +-
 .../playlib/src/mill/playlib/RouterModule.scala    |   2 +-
 .../api/src/ScoverageReportWorkerApi.scala         |   7 ++
 contrib/scoverage/src/ScoverageModule.scala        | 122 +++++++++++++++++++++
 contrib/scoverage/src/ScoverageReportWorker.scala  |  39 +++++++
 .../resources/hello-world/core/src/Greet.scala     |   6 +
 contrib/scoverage/test/src/HelloWorldTests.scala   | 107 ++++++++++++++++++
 .../1.3.1/src/ScoverageReportWorkerImpl.scala      |  21 ++++
 docs/pages/9 - Contrib Modules.md                  |  44 +++++++-
 11 files changed, 375 insertions(+), 5 deletions(-)
 create mode 100644 contrib/scoverage/api/src/ScoverageReportWorkerApi.scala
 create mode 100644 contrib/scoverage/src/ScoverageModule.scala
 create mode 100644 contrib/scoverage/src/ScoverageReportWorker.scala
 create mode 100644 contrib/scoverage/test/resources/hello-world/core/src/Greet.scala
 create mode 100644 contrib/scoverage/test/src/HelloWorldTests.scala
 create mode 100644 contrib/scoverage/worker/1.3.1/src/ScoverageReportWorkerImpl.scala

(limited to 'docs')

diff --git a/build.sc b/build.sc
index fd5d4e29..215e8d37 100755
--- a/build.sc
+++ b/build.sc
@@ -287,6 +287,31 @@ object contrib extends MillModule {
     def moduleDeps = Seq(scalalib)
   }
 
+  object scoverage extends MillModule {
+    def moduleDeps = Seq(scalalib, scoverage.api)
+
+    def testArgs = T {
+      val mapping = Map(
+        "MILL_SCOVERAGE_REPORT_WORKER_1_3_1" -> worker("1.3.1").compile().classes.path
+      )
+      scalalib.worker.testArgs() ++
+        scalalib.backgroundwrapper.testArgs() ++
+        (for ((k, v) <- mapping) yield s"-D$k=$v")
+    }
+
+    object api extends MillApiModule {
+      def moduleDeps = Seq(scalalib)
+    }
+
+    object worker extends Cross[WorkerModule]("1.3.1")
+
+    class WorkerModule(scoverageVersion: String) extends MillApiModule {
+      def moduleDeps = Seq(scoverage.api)
+
+      def ivyDeps = Agg(ivy"org.scoverage::scalac-scoverage-plugin:${scoverageVersion}")
+    }
+  }
+
   object buildinfo extends MillModule {
     def moduleDeps = Seq(scalalib)
     // why do I need this?
@@ -436,7 +461,7 @@ def launcherScript(shellJvmArgs: Seq[String],
 }
 
 object dev extends MillModule{
-  def moduleDeps = Seq(scalalib, scalajslib, scalanativelib, contrib.scalapblib, contrib.tut)
+  def moduleDeps = Seq(scalalib, scalajslib, scalanativelib, contrib.scalapblib, contrib.tut, contrib.scoverage)
 
   def forkArgs =
     (
diff --git a/ci/test-mill-0.sh b/ci/test-mill-0.sh
index fa8d7604..83c361b1 100755
--- a/ci/test-mill-0.sh
+++ b/ci/test-mill-0.sh
@@ -6,4 +6,5 @@ set -eux
 git clean -xdf
 
 # Run tests
-mill -i all {main,scalalib,scalajslib,contrib.twirllib,contrib.playlib,main.client,contrib.scalapblib,contrib.flyway}.test
+
+mill -i all {main,scalalib,scalajslib,contrib.twirllib,contrib.playlib,main.client,contrib.scalapblib,contrib.flyway,contrib.scoverage}.test
\ No newline at end of file
diff --git a/ci/test-mill-bootstrap.sh b/ci/test-mill-bootstrap.sh
index f95c0646..80086df2 100755
--- a/ci/test-mill-bootstrap.sh
+++ b/ci/test-mill-bootstrap.sh
@@ -27,4 +27,4 @@ git clean -xdf
 rm -rf ~/.mill
 
 # Use second build to run tests using Mill
-~/mill-2 -i all {main,scalalib,scalajslib,contrib.twirllib,contrib.playlib,contrib.scalapblib}.test
+~/mill-2 -i all {main,scalalib,scalajslib,contrib.twirllib,contrib.playlib,contrib.scalapblib,contrib.scoverage}.test
diff --git a/contrib/playlib/src/mill/playlib/RouterModule.scala b/contrib/playlib/src/mill/playlib/RouterModule.scala
index abf3082b..62a4c16b 100644
--- a/contrib/playlib/src/mill/playlib/RouterModule.scala
+++ b/contrib/playlib/src/mill/playlib/RouterModule.scala
@@ -97,4 +97,4 @@ trait RouterModule extends ScalaModule with Version {
   override def generatedSources = T {
     super.generatedSources() ++ routerClasses()
   }
-}
\ No newline at end of file
+}
diff --git a/contrib/scoverage/api/src/ScoverageReportWorkerApi.scala b/contrib/scoverage/api/src/ScoverageReportWorkerApi.scala
new file mode 100644
index 00000000..d74e1275
--- /dev/null
+++ b/contrib/scoverage/api/src/ScoverageReportWorkerApi.scala
@@ -0,0 +1,7 @@
+package mill.contrib.scoverage.api
+
+import mill.eval.PathRef
+
+trait ScoverageReportWorkerApi {
+  def htmlReport(sources: Seq[PathRef], dataDir: String, selfDir: String): Unit
+}
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)
+  }
+}
diff --git a/contrib/scoverage/src/ScoverageReportWorker.scala b/contrib/scoverage/src/ScoverageReportWorker.scala
new file mode 100644
index 00000000..1aaa31ad
--- /dev/null
+++ b/contrib/scoverage/src/ScoverageReportWorker.scala
@@ -0,0 +1,39 @@
+package mill.contrib.scoverage
+
+import mill.{Agg, T}
+import mill.api.{ClassLoader, Ctx, Result}
+import mill.define.{Discover, ExternalModule, Worker}
+import mill.eval.PathRef
+
+class ScoverageReportWorker {
+  private var scoverageInstanceCache = Option.empty[(Long, api.ScoverageReportWorkerApi)]
+
+  def bridge(classpath: Agg[os.Path])
+                    (implicit ctx: Ctx) = {
+    val classloaderSig =
+      classpath.map(p => p.toString().hashCode + os.mtime(p)).sum
+    scoverageInstanceCache match {
+      case Some((sig, bridge)) if sig == classloaderSig => bridge
+      case _ =>
+        val toolsClassPath = classpath.map(_.toIO.toURI.toURL).toVector
+        ctx.log.debug("Loading classes from\n"+toolsClassPath.mkString("\n"))
+        val cl = ClassLoader.create(
+          toolsClassPath,
+          getClass.getClassLoader
+        )
+        val bridge = cl
+          .loadClass("mill.contrib.scoverage.worker.ScoverageReportWorkerImpl")
+          .getDeclaredConstructor()
+          .newInstance()
+          .asInstanceOf[api.ScoverageReportWorkerApi]
+        scoverageInstanceCache = Some((classloaderSig, bridge))
+        bridge
+    }
+  }
+}
+
+object ScoverageReportWorkerApi extends ExternalModule {
+
+  def scoverageReportWorker = T.worker { new ScoverageReportWorker() }
+  lazy val millDiscover = Discover[this.type]
+}
diff --git a/contrib/scoverage/test/resources/hello-world/core/src/Greet.scala b/contrib/scoverage/test/resources/hello-world/core/src/Greet.scala
new file mode 100644
index 00000000..608becc9
--- /dev/null
+++ b/contrib/scoverage/test/resources/hello-world/core/src/Greet.scala
@@ -0,0 +1,6 @@
+object Greet {
+  def greet(name: String, prefix: Option[String]): String = prefix match {
+    case Some(p) => s"Hello, ${p} ${name}!"
+    case None => s"Hello, ${name}!"
+  }
+}
diff --git a/contrib/scoverage/test/src/HelloWorldTests.scala b/contrib/scoverage/test/src/HelloWorldTests.scala
new file mode 100644
index 00000000..98a4201c
--- /dev/null
+++ b/contrib/scoverage/test/src/HelloWorldTests.scala
@@ -0,0 +1,107 @@
+package mill.contrib.scoverage
+
+import mill._
+import mill.api.Result
+import mill.scalalib._
+import mill.util.{TestEvaluator, TestUtil}
+import utest._
+import utest.framework.TestPath
+
+object HelloWorldTests extends utest.TestSuite {
+  val resourcePath = os.pwd / 'contrib / 'scoverage / 'test / 'resources / "hello-world"
+  trait HelloBase extends TestUtil.BaseModule {
+    def millSourcePath =  TestUtil.getSrcPathBase() / millOuterCtx.enclosing.split('.')
+  }
+
+  object HelloWorld extends HelloBase {
+    object core extends ScoverageModule {
+      def scalaVersion = "2.12.4"
+      def scoverageVersion = "1.3.1"
+
+      object test extends ScoverageTests {
+        override def ivyDeps = Agg(ivy"org.scalatest::scalatest:3.0.5")
+        def testFrameworks = Seq("org.scalatest.tools.Framework")
+      }
+    }
+  }
+
+  def workspaceTest[T](m: TestUtil.BaseModule, resourcePath: os.Path = resourcePath)
+                      (t: TestEvaluator => T)
+                      (implicit tp: TestPath): T = {
+    val eval = new TestEvaluator(m)
+    os.remove.all(m.millSourcePath)
+    os.remove.all(eval.outPath)
+    os.makeDir.all(m.millSourcePath / os.up)
+    os.copy(resourcePath, m.millSourcePath)
+    t(eval)
+  }
+
+  def tests: utest.Tests = utest.Tests {
+    "HelloWorld" - {
+      "core" - {
+        "scoverageVersion" - workspaceTest(HelloWorld) { eval =>
+          val Right((result, evalCount)) = eval.apply(HelloWorld.core.scoverageVersion)
+
+          assert(
+            result == "1.3.1",
+            evalCount > 0
+          )
+        }
+        "scoverage" - {
+          "ivyDeps" - workspaceTest(HelloWorld) { eval =>
+            val Right((result, evalCount)) =
+              eval.apply(HelloWorld.core.scoverage.ivyDeps)
+
+            assert(
+              result == Agg(ivy"org.scoverage::scalac-scoverage-runtime:1.3.1"),
+              evalCount > 0
+            )
+          }
+          "scalacPluginIvyDeps" - workspaceTest(HelloWorld) { eval =>
+            val Right((result, evalCount)) =
+              eval.apply(HelloWorld.core.scoverage.scalacPluginIvyDeps)
+
+            assert(
+              result == Agg(ivy"org.scoverage::scalac-scoverage-plugin:1.3.1"),
+              evalCount > 0
+            )
+          }
+          "dataDir" - workspaceTest(HelloWorld) { eval =>
+            val Right((result, evalCount)) = eval.apply(HelloWorld.core.scoverage.dataDir)
+
+            assert(
+              result.toString.endsWith("mill/target/workspace/mill/contrib/scoverage/HelloWorldTests/eval/HelloWorld/core/scoverage/dataDir/core/scoverage/data"),
+              evalCount > 0
+            )
+          }
+        }
+        "test" - {
+          "upstreamAssemblyClasspath" - workspaceTest(HelloWorld) { eval =>
+            val Right((result, evalCount)) = eval.apply(HelloWorld.core.scoverage.upstreamAssemblyClasspath)
+
+            assert(
+              result.map(_.toString).exists(_.contains("scalac-scoverage-runtime")),
+              evalCount > 0
+            )
+          }
+          "compileClasspath" - workspaceTest(HelloWorld) { eval =>
+            val Right((result, evalCount)) = eval.apply(HelloWorld.core.scoverage.compileClasspath)
+
+            assert(
+              result.map(_.toString).exists(_.contains("scalac-scoverage-runtime")),
+              evalCount > 0
+            )
+          }
+          "runClasspath" - TestUtil.disableInJava9OrAbove(workspaceTest(HelloWorld) { eval =>
+            val Right((result, evalCount)) = eval.apply(HelloWorld.core.scoverage.runClasspath)
+
+            assert(
+              result.map(_.toString).exists(_.contains("scalac-scoverage-runtime")),
+              evalCount > 0
+            )
+          })
+        }
+      }
+    }
+  }
+}
diff --git a/contrib/scoverage/worker/1.3.1/src/ScoverageReportWorkerImpl.scala b/contrib/scoverage/worker/1.3.1/src/ScoverageReportWorkerImpl.scala
new file mode 100644
index 00000000..44f506f7
--- /dev/null
+++ b/contrib/scoverage/worker/1.3.1/src/ScoverageReportWorkerImpl.scala
@@ -0,0 +1,21 @@
+package mill.contrib.scoverage.worker
+
+import mill.contrib.scoverage.api.ScoverageReportWorkerApi
+import mill.eval.PathRef
+import _root_.scoverage.Serializer.{ coverageFile, deserialize }
+import _root_.scoverage.IOUtils.{ findMeasurementFiles, invoked }
+import _root_.scoverage.report.ScoverageHtmlWriter
+
+class ScoverageReportWorkerImpl extends ScoverageReportWorkerApi {
+  def htmlReport(sources: Seq[PathRef], dataDir: String, selfDir: String) = {
+    val coverageFileObj = coverageFile(dataDir)
+    val coverage = deserialize(coverageFileObj)
+    coverage(invoked(findMeasurementFiles(dataDir)))
+    val Seq(PathRef(sourceFolderPath, _, _)) = sources
+    val sourceFolders = Seq(sourceFolderPath.toIO)
+    val htmlFolder = new java.io.File(s"${selfDir}/htmlReport")
+    htmlFolder.mkdir()
+    new ScoverageHtmlWriter(sourceFolders, htmlFolder, None)
+      .write(coverage)
+  }
+}
diff --git a/docs/pages/9 - Contrib Modules.md b/docs/pages/9 - Contrib Modules.md
index eca61be3..c3d4751a 100644
--- a/docs/pages/9 - Contrib Modules.md	
+++ b/docs/pages/9 - Contrib Modules.md	
@@ -543,6 +543,49 @@ object example extends ScalaPBModule {
 }
 ```
 
+
+## Scoverage
+
+This module allows you to generate code coverage reports for Scala projects with
+[Scoverage](https://github.com/scoverage) via the
+[scalac-scoverage-plugin](https://github.com/scoverage/scalac-scoverage-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`.
+
+```scala
+// 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/`.
+
+
 ## TestNG
 
 Provides support for [TestNG](https://testng.org/doc/index.html).
@@ -722,4 +765,3 @@ These imports will always be added to every template.  You don't need to list th
 
 ### Example
 There's an [example project](https://github.com/lihaoyi/cask/tree/master/example/twirl)
-
-- 
cgit v1.2.3


From 052af24a530f8bc0532b368a2d360ff30f67d7b8 Mon Sep 17 00:00:00 2001
From: Guillaume Galy 
Date: Sun, 19 May 2019 05:23:18 +0200
Subject: Switch from scalafmt-cli to scalafmt-dynamic (#600)

---
 build.sc                                           |  3 +-
 docs/pages/2 - Configuring Mill.md                 |  6 ++++
 .../mill/scalalib/scalafmt/default.scalafmt.conf   |  0
 scalalib/src/scalafmt/ScalafmtModule.scala         | 16 ++--------
 scalalib/src/scalafmt/ScalafmtWorker.scala         | 37 +++++++++++++---------
 5 files changed, 32 insertions(+), 30 deletions(-)
 create mode 100644 scalalib/resources/mill/scalalib/scalafmt/default.scalafmt.conf

(limited to 'docs')

diff --git a/build.sc b/build.sc
index 215e8d37..c51e8195 100755
--- a/build.sc
+++ b/build.sc
@@ -143,7 +143,8 @@ object scalalib extends MillModule {
   def moduleDeps = Seq(main, scalalib.api)
 
   def ivyDeps = Agg(
-    ivy"org.scala-sbt:test-interface:1.0"
+    ivy"org.scala-sbt:test-interface:1.0",
+    ivy"org.scalameta::scalafmt-dynamic:2.0.0-RC6"
   )
 
   def genTask(m: ScalaModule) = T.task{
diff --git a/docs/pages/2 - Configuring Mill.md b/docs/pages/2 - Configuring Mill.md
index dbcbcee4..f6ca86a0 100644
--- a/docs/pages/2 - Configuring Mill.md	
+++ b/docs/pages/2 - Configuring Mill.md	
@@ -237,6 +237,12 @@ Now you can reformat code with `mill foo.reformat` command.
 You can also reformat your project's code globally with `mill mill.scalalib.scalafmt.ScalafmtModule/reformatAll __.sources` command.
 It will reformat all sources that matches `__.sources` query.
 
+If you add a `.scalafmt.conf` file at the root of you project, it will be used
+to configure formatting. It can contain a `version` key to specify the scalafmt
+version used to format your code. See the
+[scalafmt configuration documentation](https://scalameta.org/scalafmt/docs/configuration.html)
+for details.
+
 ## Common Configuration
 
 ```scala
diff --git a/scalalib/resources/mill/scalalib/scalafmt/default.scalafmt.conf b/scalalib/resources/mill/scalalib/scalafmt/default.scalafmt.conf
new file mode 100644
index 00000000..e69de29b
diff --git a/scalalib/src/scalafmt/ScalafmtModule.scala b/scalalib/src/scalafmt/ScalafmtModule.scala
index 6a81d975..ea254e6d 100644
--- a/scalalib/src/scalafmt/ScalafmtModule.scala
+++ b/scalalib/src/scalafmt/ScalafmtModule.scala
@@ -11,23 +11,12 @@ trait ScalafmtModule extends JavaModule {
       .worker()
       .reformat(
         filesToFormat(sources()),
-        scalafmtConfig().head,
-        scalafmtDeps().map(_.path)
+        scalafmtConfig().head
       )
   }
 
-  def scalafmtVersion: T[String] = "1.5.1"
-
   def scalafmtConfig: Sources = T.sources(os.pwd / ".scalafmt.conf")
 
-  def scalafmtDeps: T[Agg[PathRef]] = T {
-    Lib.resolveDependencies(
-      zincWorker.repositories,
-      Lib.depToDependency(_, "2.12.4"),
-      Seq(ivy"com.geirsson::scalafmt-cli:${scalafmtVersion()}")
-    )
-  }
-
   protected def filesToFormat(sources: Seq[PathRef]) = {
     for {
       pathRef <- sources if os.exists(pathRef.path)
@@ -46,8 +35,7 @@ object ScalafmtModule extends ExternalModule with ScalafmtModule {
         .worker()
         .reformat(
           files,
-          scalafmtConfig().head,
-          scalafmtDeps().map(_.path)
+          scalafmtConfig().head
         )
     }
 
diff --git a/scalalib/src/scalafmt/ScalafmtWorker.scala b/scalalib/src/scalafmt/ScalafmtWorker.scala
index 47d8375f..f9c7e9b4 100644
--- a/scalalib/src/scalafmt/ScalafmtWorker.scala
+++ b/scalalib/src/scalafmt/ScalafmtWorker.scala
@@ -1,9 +1,11 @@
 package mill.scalalib.scalafmt
 
+import java.nio.file.{Paths => JPaths}
+
 import mill._
 import mill.define.{Discover, ExternalModule, Worker}
-import mill.modules.Jvm
 import mill.api.Ctx
+import org.scalafmt.interfaces.Scalafmt
 
 import scala.collection.mutable
 
@@ -18,8 +20,7 @@ private[scalafmt] class ScalafmtWorker {
   private var configSig: Int = 0
 
   def reformat(input: Seq[PathRef],
-               scalafmtConfig: PathRef,
-               scalafmtClasspath: Agg[os.Path])(implicit ctx: Ctx): Unit = {
+               scalafmtConfig: PathRef)(implicit ctx: Ctx): Unit = {
     val toFormat =
       if (scalafmtConfig.sig != configSig) input
       else
@@ -28,8 +29,7 @@ private[scalafmt] class ScalafmtWorker {
     if (toFormat.nonEmpty) {
       ctx.log.info(s"Formatting ${toFormat.size} Scala sources")
       reformatAction(toFormat.map(_.path),
-                     scalafmtConfig.path,
-                     scalafmtClasspath)
+                     scalafmtConfig.path)
       reformatted ++= toFormat.map { ref =>
         val updRef = PathRef(ref.path)
         updRef.path -> updRef.sig
@@ -43,15 +43,22 @@ private[scalafmt] class ScalafmtWorker {
   private val cliFlags = Seq("--non-interactive", "--quiet")
 
   private def reformatAction(toFormat: Seq[os.Path],
-                             config: os.Path,
-                             classpath: Agg[os.Path])(implicit ctx: Ctx) = {
-    val configFlags =
-      if (os.exists(config)) Seq("--config", config.toString) else Seq.empty
-    Jvm.runSubprocess(
-      "org.scalafmt.cli.Cli",
-      classpath,
-      mainArgs = toFormat.map(_.toString) ++ configFlags ++ cliFlags
-    )
-  }
+                             config: os.Path)(implicit ctx: Ctx) = {
+    val scalafmt =
+      Scalafmt
+        .create(this.getClass.getClassLoader)
+        .withRespectVersion(false)
+
+    val configPath =
+      if (os.exists(config))
+        config.toNIO
+      else
+        JPaths.get(getClass.getResource("default.scalafmt.conf").toURI)
 
+    toFormat.foreach { pathToFormat =>
+      val code = os.read(pathToFormat)
+      val formatteCode = scalafmt.format(configPath, pathToFormat.toNIO, code)
+      os.write.over(pathToFormat, formatteCode)
+    }
+  }
 }
-- 
cgit v1.2.3