diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 51645eba3b7..c15cb8cb62e 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -74,9 +74,9 @@ jobs: # Group these tests together to try and balance out the runtimes of each job # Just running in `local` mode since they shouldn't depend on the mode - java-version: 17 - millargs: "'example.{basic,scalabuilds,scalamodule,web}[_].local.test'" + millargs: "'example.{basic,scalabuilds,scalamodule,scalatesting,web}[_].local.test'" - java-version: 17 - millargs: "'example.{basicjava,javabuilds,javamodule,javaweb}[_].local.test'" + millargs: "'example.{basicjava,javabuilds,javamodule,javatesting,javaweb}[_].local.test'" - java-version: 11 millargs: "'example.thirdparty[{mockito,acyclic,commons-io}].local.test'" - java-version: 17 diff --git a/build.sc b/build.sc index 1bd7bccffc3..0c354ead2c3 100644 --- a/build.sc +++ b/build.sc @@ -1214,7 +1214,9 @@ object example extends Module { object basic extends Cross[ExampleCrossModule](listIn(millSourcePath / "basic")) object basicjava extends Cross[ExampleCrossModuleJava](listIn(millSourcePath / "basicjava")) object scalabuilds extends Cross[ExampleCrossModule](listIn(millSourcePath / "scalabuilds")) + object scalatesting extends Cross[ExampleCrossModule](listIn(millSourcePath / "scalatesting")) object javabuilds extends Cross[ExampleCrossModuleJava](listIn(millSourcePath / "javabuilds")) + object javatesting extends Cross[ExampleCrossModuleJava](listIn(millSourcePath / "javatesting")) object scalamodule extends Cross[ExampleCrossModule](listIn(millSourcePath / "scalamodule")) object javamodule extends Cross[ExampleCrossModuleJava](listIn(millSourcePath / "javamodule")) object tasks extends Cross[ExampleCrossModule](listIn(millSourcePath / "tasks")) @@ -1229,6 +1231,7 @@ object example extends Module { case "basicjava" => basic case "javabuilds" => scalabuilds case "javamodule" => scalamodule + case "javatesting" => scalatesting } def testRepoRoot = T{ os.copy.over(super.testRepoRoot().path, T.dest) @@ -1242,10 +1245,7 @@ object example extends Module { case None => T {None} case Some(upstream) => T { Some { - val upstreamLines = os.read.lines( - upstream - .testRepoRoot().path / "build.sc" - ) + val upstreamLines = os.read.lines(upstream.testRepoRoot().path / "build.sc") val lines = os.read.lines(super.testRepoRoot().path / "build.sc") import collection.mutable @@ -1255,13 +1255,13 @@ object example extends Module { case s"//// SNIPPET:$name" => current = Some(name) groupedLines(name) = mutable.Buffer() - case s => groupedLines(current.get).append(s) + case s => current.foreach(groupedLines(_).append(s)) } + current = None upstreamLines.flatMap { case s"//// SNIPPET:$name" => if (name != "END") { - current = Some(name) groupedLines(name) } else { @@ -1269,9 +1269,7 @@ object example extends Module { Nil } - case s => - if (current.nonEmpty) None - else Some(s) + case s => if (current.nonEmpty) None else Some(s) } } } @@ -1808,7 +1806,7 @@ object docs extends Module { |""".stripMargin } s"""site: - | title: Mill + | title: The Mill Build Tool | url: ${if (authorMode) s"${T.dest}/site" else Settings.docUrl} | start_page: mill::Java_Intro_to_Mill.adoc | keys: diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index eb973028cb8..8b79dafbe54 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -3,23 +3,25 @@ // but we intentionally skim over them and do not go into depth: the focus is // on end user goals and how to achieve them. -.Java Quick Start -* xref:Java_Intro_to_Mill.adoc[] +.xref:Java_Intro_to_Mill.adoc[] * xref:Java_Installation_IDE_Support.adoc[] * xref:Java_Builtin_Commands.adoc[] -* xref:Java_Build_Examples.adoc[] * xref:Java_Module_Config.adoc[] -* xref:Java_Web_Build_Examples.adoc[] +* xref:Java_Build_Examples.adoc[] +* xref:Testing_Java_Projects.adoc[] +// * xref:Publishing_Java_Projects.adoc[] +* xref:Java_Web_Examples.adoc[] * xref:Case_Study_Mill_vs_Maven.adoc[] * xref:Case_Study_Mill_vs_Gradle.adoc[] -.Scala Quick Start -* xref:Scala_Intro_to_Mill.adoc[] +.xref:Scala_Intro_to_Mill.adoc[] * xref:Scala_Installation_IDE_Support.adoc[] * xref:Scala_Builtin_Commands.adoc[] -* xref:Scala_Build_Examples.adoc[] * xref:Scala_Module_Config.adoc[] -* xref:Scala_Web_Build_Examples.adoc[] +* xref:Scala_Build_Examples.adoc[] +* xref:Testing_Scala_Projects.adoc[] +// * xref:Publishing_Scala_Projects.adoc[] +* xref:Scala_Web_Examples.adoc[] // This section is all about developing a deeper understanding of specific // topics in Mill. This is the opposite of `Quick Start` above: while we touch @@ -33,13 +35,14 @@ * xref:Modules.adoc[] * xref:Cross_Builds.adoc[] * xref:Target_Query_Syntax.adoc[] -* xref:Extending_Mill.adoc[] + * xref:The_Mill_Evaluation_Model.adoc[] // This section talks about Mill plugins. While it could theoretically fit in // either section above, it is probably an important enough topic it is worth // breaking out on its own -.Mill Plugins +.Extending Mill +* xref:Import_File_And_Import_Ivy.adoc[] * xref:Using_Plugins.adoc[] * xref:Contrib_Plugins.adoc[] // See also the list in Contrib_Plugins.adoc @@ -47,7 +50,6 @@ ** xref:contrib/bintray.adoc[] ** xref:contrib/bloop.adoc[] ** xref:contrib/buildinfo.adoc[] -** xref:Plugin_BSP.adoc[] ** xref:contrib/codeartifact.adoc[] ** xref:contrib/docker.adoc[] ** xref:contrib/flyway.adoc[] @@ -60,8 +62,8 @@ ** xref:contrib/testng.adoc[] ** xref:contrib/twirllib.adoc[] ** xref:contrib/versionfile.adoc[] - * xref:Thirdparty_Plugins.adoc[] +* xref:The_Mill_Meta_Build.adoc[] // Reference pages that a typical user would not typically read top-to-bottom, // but may need to look up once in a while, and thus should be written down diff --git a/docs/modules/ROOT/pages/Contrib_Plugins.adoc b/docs/modules/ROOT/pages/Contrib_Plugins.adoc index de7251ffa47..68b20476f47 100644 --- a/docs/modules/ROOT/pages/Contrib_Plugins.adoc +++ b/docs/modules/ROOT/pages/Contrib_Plugins.adoc @@ -1,6 +1,7 @@ = Contrib Plugins :page-aliases: Contrib_Modules.adoc + The ((plugins)) in this section are hosted in the Mill git tree and developed / maintained by the community. For details about including plugins in your `build.sc` read xref:Using_Plugins.adoc[Using Mill Plugins]. @@ -46,4 +47,9 @@ import $ivy.`com.lihaoyi::mill-contrib-bloop:` * xref:contrib/scoverage.adoc[] * xref:contrib/testng.adoc[] * xref:contrib/twirllib.adoc[] -* xref:contrib/versionfile.adoc[] \ No newline at end of file +* xref:contrib/versionfile.adoc[] + + +== Importing Contrib Modules + +include::example/misc/6-contrib-import.adoc[] diff --git a/docs/modules/ROOT/pages/Extending_Mill.adoc b/docs/modules/ROOT/pages/Extending_Mill.adoc deleted file mode 100644 index 73f816030bf..00000000000 --- a/docs/modules/ROOT/pages/Extending_Mill.adoc +++ /dev/null @@ -1,91 +0,0 @@ -= Extending Mill -:link-ammonite: https://ammonite.io/ - -There are different ways of extending Mill, depending on how much customization -and flexibility you need. This page will go through your options from the -easiest/least-flexible to the hardest/most-flexible. - -== import $file and import $ivy - -include::example/misc/3-import-file-ivy.adoc[] - -== The Mill Meta-Build - -The meta-build manages the compilation of the `build.sc`. -If you don't configure it explicitly, a built-in synthetic meta-build is used. - -To customize it, you need to explicitly enable it with `import $meta._`. -Once enabled, the meta-build lives in the `mill-build/` directory. -It needs to contain a top-level module of type `MillBuildRootModule`. - -Meta-builds are recursive, which means, it can itself have a nested meta-builds, and so on. - -To run a task on a meta-build, you specifying the `--meta-level` option to select the meta-build level. - -=== Example: Format the `build.sc` - -As an example of running a task on the meta-build, you can format the `build.sc` with Scalafmt. -Everything is already provided by Mill. -You only need a `.scalafmt.conf` config file which at least needs configure the Scalafmt version. - -.Run Scalafmt on the `build.sc` (and potentially included files) ----- -$ mill --meta-level 1 mill.scalalib.scalafmt.ScalafmtModule/reformatAll sources ----- - -* `--meta-level 1` selects the first meta-build. Without any customization, this is the only built-in meta-build. -* `mill.scalalib.scalafmt.ScalafmtModule/reformatAll` is a generic task to format scala source files with Scalafmt. It requires the targets that refer to the source files as argument -* `sources` this selects the `sources` targets of the meta-build, which at least contains the `build.sc`. - -=== Example: Find plugin updates - -Mill plugins are defined as `ivyDeps` in the meta-build. -Hence, you can easily search for updates with the external `mill.scalalib.Dependency` module. - -.Check for Mill Plugin updates ----- -$ mill --meta-level 1 mill.scalalib.Dependency/showUpdates -Found 1 dependency update for - de.tototec:de.tobiasroeser.mill.vcs.version_mill0.11_2.13 : 0.3.1-> 0.4.0 ----- - -=== Example: Customizing the Meta-Build - -include::example/misc/4-mill-build-folder.adoc[] - -== Using ScalaModule.run as a task - -include::example/misc/5-module-run-task.adoc[] - -== Importing Contrib Modules - -include::example/misc/6-contrib-import.adoc[] - -== Evaluator Commands (experimental) - -_Evaluator Command are experimental and suspected to change. -See {mill-github-url}/issues/502[issue #502] for details._ - -You can define a command that takes in the current `Evaluator` as an argument, -which you can use to inspect the entire build, or run arbitrary tasks. -For example, here is the `mill.scalalib.GenIdea/idea` command which uses this -to traverse the module-tree and generate an Intellij project config for your -build. - -[source,scala] ----- -def idea(ev: Evaluator) = T.command { - mill.scalalib.GenIdea( - implicitly, - ev.rootModule, - ev.discover - ) -} ----- - -Many built-in tools are implemented as custom evaluator commands: -xref:Scala_Builtin_Commands.adoc#_inspect[inspect], -xref:Scala_Builtin_Commands.adoc#_resolve[resolve], -xref:Scala_Builtin_Commands.adoc#_show[show]. -If you want a way to run Mill commands and programmatically manipulate the -tasks and outputs, you do so with your own evaluator command. diff --git a/docs/modules/ROOT/pages/Import_File_And_Import_Ivy.adoc b/docs/modules/ROOT/pages/Import_File_And_Import_Ivy.adoc new file mode 100644 index 00000000000..f1f373b9ede --- /dev/null +++ b/docs/modules/ROOT/pages/Import_File_And_Import_Ivy.adoc @@ -0,0 +1,4 @@ += import $file and import $ivy + +include::example/misc/3-import-file-ivy.adoc[] + diff --git a/docs/modules/ROOT/pages/Java_Build_Examples.adoc b/docs/modules/ROOT/pages/Java_Build_Examples.adoc index 7632c566ed0..2ec46d9e02c 100644 --- a/docs/modules/ROOT/pages/Java_Build_Examples.adoc +++ b/docs/modules/ROOT/pages/Java_Build_Examples.adoc @@ -37,10 +37,6 @@ include::example/javabuilds/3-override-tasks.adoc[] include::example/javabuilds/4-nested-modules.adoc[] -== Java Module With Test Suite - -include::example/javabuilds/5-test-suite.adoc[] - == Publish Module include::example/javabuilds/6-publish-module.adoc[] diff --git a/docs/modules/ROOT/pages/Java_Intro_to_Mill.adoc b/docs/modules/ROOT/pages/Java_Intro_to_Mill.adoc index 9ab81e4a93c..7ad784977cc 100644 --- a/docs/modules/ROOT/pages/Java_Intro_to_Mill.adoc +++ b/docs/modules/ROOT/pages/Java_Intro_to_Mill.adoc @@ -29,8 +29,8 @@ include::partial$Intro_to_Mill_Header.adoc[] Mill is used to build some real-world Java projects, such as the https://github.com/swaldman/c3p0[C3P0 JDBC Connection Pool], and can be used for applications built on top of common Java frameworks like -xref:Java_Web_Build_Examples.adoc#_spring_boot_todomvc_app[Spring Boot] or -xref:Java_Web_Build_Examples.adoc#_micronaut_todomvc_app[Micronaut]. +xref:Java_Web_Examples.adoc#_spring_boot_todomvc_app[Spring Boot] or +xref:Java_Web_Examples.adoc#_micronaut_todomvc_app[Micronaut]. Mill borrows ideas from other tools like https://maven.apache.org/[Maven], https://gradle.org/[Gradle], https://bazel.build/[Bazel], but tries to learn from the diff --git a/docs/modules/ROOT/pages/Java_Module_Config.adoc b/docs/modules/ROOT/pages/Java_Module_Config.adoc index 657fce995c3..d3ca590c740 100644 --- a/docs/modules/ROOT/pages/Java_Module_Config.adoc +++ b/docs/modules/ROOT/pages/Java_Module_Config.adoc @@ -26,10 +26,6 @@ include::example/javamodule/2-ivy-deps.adoc[] include::example/javamodule/3-run-compile-deps.adoc[] -== Test Dependencies - -include::example/javamodule/4-test-deps.adoc[] - == Classpath and Filesystem Resources include::example/javamodule/5-resources.adoc[] diff --git a/docs/modules/ROOT/pages/Java_Web_Build_Examples.adoc b/docs/modules/ROOT/pages/Java_Web_Examples.adoc similarity index 95% rename from docs/modules/ROOT/pages/Java_Web_Build_Examples.adoc rename to docs/modules/ROOT/pages/Java_Web_Examples.adoc index c2dc3b40696..eaa4ed817d3 100644 --- a/docs/modules/ROOT/pages/Java_Web_Build_Examples.adoc +++ b/docs/modules/ROOT/pages/Java_Web_Examples.adoc @@ -1,4 +1,4 @@ -= Java Web Build Examples += Java Web Examples ++++ +++++ + +This page will discuss common topics around working with test suites using the Mill build tool + +== Defining Unit Test Suites + +include::example/javatesting/1-test-suite.adoc[] + + +== Test Dependencies + +include::example/javatesting/2-test-deps.adoc[] + +== Defining Integration Test Suites + +include::example/javatesting/3-integration-suite.adoc[] \ No newline at end of file diff --git a/docs/modules/ROOT/pages/Testing_Scala_Projects.adoc b/docs/modules/ROOT/pages/Testing_Scala_Projects.adoc new file mode 100644 index 00000000000..9443495ecee --- /dev/null +++ b/docs/modules/ROOT/pages/Testing_Scala_Projects.adoc @@ -0,0 +1,22 @@ += Testing Scala Projects + +++++ + +++++ + +This page will discuss common topics around working with test suites using the Mill build tool + +== Defining Unit Test Suites + +include::example/scalatesting/1-test-suite.adoc[] + + +== Test Dependencies + +include::example/scalatesting/2-test-deps.adoc[] + +== Defining Integration Test Suites + +include::example/scalatesting/3-integration-suite.adoc[] \ No newline at end of file diff --git a/docs/modules/ROOT/pages/The_Mill_Evaluation_Model.adoc b/docs/modules/ROOT/pages/The_Mill_Evaluation_Model.adoc index 91fdd9f68c3..b2942a266ce 100644 --- a/docs/modules/ROOT/pages/The_Mill_Evaluation_Model.adoc +++ b/docs/modules/ROOT/pages/The_Mill_Evaluation_Model.adoc @@ -5,7 +5,7 @@ Evaluating a Mill target typically goes through the following phases: 1. *Compilation*: Mill compiles the `build.sc` to classfiles, following the <<_the_mill_bootstrapping_process>> to eventually produce a `RootModule` object -2. *Planning*: Mill resolves the list of xref:Tasks.adoc[] given from the command line, +2. *Resolution*: Mill resolves the list of xref:Tasks.adoc[] given from the command line, e.g. `resolve _` or `foo.compile` or `{bar,qux}.__.test`, to a list of concrete `Task` objects nested on xref:Modules.adoc[] within the `RootModule` along with their transitive dependencies @@ -84,11 +84,14 @@ the overall workflow remains fast even for large projects: https://github.com/com-lihaoyi/mill/pull/2417[#2417] for more details This approach to caching does assume a certain programming style inside your -`build.sc`: we may or may not re-instantiate the `RootModule` of your -`build.sc` depending on caching, and your code should work either way. For code -written in a typical Scala style, this is not a problem at all. - -One thing to note is for code that runs during *Planning*: any reading of +Mill build: we may-or-may-not re-instantiate the modules in your +`build.sc` and we may-or-may-not re-execute any particular task depending on caching, +but your code needs to work either way. Furthermore, task ``def``s and module `object`s in your +build are instantiated lazily on-demand, and your code needs to work regardless +of which order they are executed in. For code written in a typical Scala style, +which tends to avoid side effects, this is not a problem at all. + +One thing to note is for code that runs during *Resolution*: any reading of external mutable state needs to be wrapped in an `interp.watchValue{...}` wrapper. This ensures that Mill knows where these external reads are, so that it can check if their value changed and if so re-instantiate `RootModule` with @@ -137,5 +140,5 @@ Mill supports multiple levels of meta-builds for bootstrapping: - Two level of meta-builds: `mill-build/mill-build/build.sc`, `mill-build/build.sc` and `build.sc` -xref:Extending_Mill.adoc#_the_mill_meta_build[Extending Mill: The Mill Meta Build] works through a simple use case +xref:The_Mill_Meta_Build.adoc[The Mill Meta Build] works through a simple use case and example for meta-builds. \ No newline at end of file diff --git a/docs/modules/ROOT/pages/The_Mill_Meta_Build.adoc b/docs/modules/ROOT/pages/The_Mill_Meta_Build.adoc new file mode 100644 index 00000000000..797bb0ce5a7 --- /dev/null +++ b/docs/modules/ROOT/pages/The_Mill_Meta_Build.adoc @@ -0,0 +1,44 @@ + += The Mill Meta-Build + +The meta-build manages the compilation of the `build.sc`. +If you don't configure it explicitly, a built-in synthetic meta-build is used. + +To customize it, you need to explicitly enable it with `import $meta._`. +Once enabled, the meta-build lives in the `mill-build/` directory. +It needs to contain a top-level module of type `MillBuildRootModule`. + +Meta-builds are recursive, which means, it can itself have a nested meta-builds, and so on. + +To run a task on a meta-build, you specifying the `--meta-level` option to select the meta-build level. + +== Example: Format the `build.sc` + +As an example of running a task on the meta-build, you can format the `build.sc` with Scalafmt. +Everything is already provided by Mill. +You only need a `.scalafmt.conf` config file which at least needs configure the Scalafmt version. + +.Run Scalafmt on the `build.sc` (and potentially included files) +---- +$ mill --meta-level 1 mill.scalalib.scalafmt.ScalafmtModule/reformatAll sources +---- + +* `--meta-level 1` selects the first meta-build. Without any customization, this is the only built-in meta-build. +* `mill.scalalib.scalafmt.ScalafmtModule/reformatAll` is a generic task to format scala source files with Scalafmt. It requires the targets that refer to the source files as argument +* `sources` this selects the `sources` targets of the meta-build, which at least contains the `build.sc`. + +== Example: Find plugin updates + +Mill plugins are defined as `ivyDeps` in the meta-build. +Hence, you can easily search for updates with the external `mill.scalalib.Dependency` module. + +.Check for Mill Plugin updates +---- +$ mill --meta-level 1 mill.scalalib.Dependency/showUpdates +Found 1 dependency update for +de.tototec:de.tobiasroeser.mill.vcs.version_mill0.11_2.13 : 0.3.1-> 0.4.0 +---- + +== Example: Customizing the Meta-Build + +include::example/misc/4-mill-build-folder.adoc[] diff --git a/docs/modules/ROOT/pages/Using_Plugins.adoc b/docs/modules/ROOT/pages/Using_Plugins.adoc index 7b8a2012695..ef0c25b0b34 100644 --- a/docs/modules/ROOT/pages/Using_Plugins.adoc +++ b/docs/modules/ROOT/pages/Using_Plugins.adoc @@ -1,6 +1,6 @@ = Using Plugins -Mill plugins are ordinary jars and are loaded as any other external dependency with the xref:Extending_Mill.adoc#_import_ivy[`import $ivy` mechanism]. +Mill plugins are ordinary jars and are loaded as any other external dependency with the xref:Import_File_And_Import_Ivy.adoc[`import $ivy` mechanism]. There exist a large number of Mill plugins, Many of them are available on GitHub and via Maven Central. We also have a list of plugins, which is most likely not complete, but it might be a good start if you are looking for plugins: xref:Thirdparty_Plugins.adoc[]. diff --git a/docs/modules/ROOT/partials/Intro_to_Mill_Footer.adoc b/docs/modules/ROOT/partials/Intro_to_Mill_Footer.adoc index bed4b2adaec..42d2d75a3dd 100644 --- a/docs/modules/ROOT/partials/Intro_to_Mill_Footer.adoc +++ b/docs/modules/ROOT/partials/Intro_to_Mill_Footer.adoc @@ -29,13 +29,11 @@ $ mill -w foo.runBackground == Parallel Task Execution -By default, mill will evaluate all tasks in sequence. -But mill also supports processing tasks in parallel. -This feature is currently experimental and we encourage you to report any issues -you find on our bug tracker. +By default, mill will evaluate all tasks in parallel, with the number of concurrent +tasks equal to the number of cores on your machine. -To enable parallel task execution, use the `--jobs` (`-j`) option followed by a -number of maximal parallel threads. +You can use the `--jobs` (`-j`) to configure explicitly how many concurrent tasks you +wish to run Example: Use up to 4 parallel threads to compile all modules: @@ -44,10 +42,9 @@ Example: Use up to 4 parallel threads to compile all modules: mill -j 4 __.compile ---- -To use as many threads as your machine has (logical) processor cores use `--jobs 0`. -To disable parallel execution use `--jobs 1`. This is currently the default. +To disable parallel execution use `--jobs 1`. -`mill -j` generates an output file in `out/mill-chrome-profile.json` that can be +`mill` generates an output file in `out/mill-chrome-profile.json` that can be loaded into the Chrome browser's `chrome://tracing` page for visualization. This can make it much easier to analyze your parallel runs to find out what's taking the most time: diff --git a/docs/modules/ROOT/partials/Intro_to_Mill_Header.adoc b/docs/modules/ROOT/partials/Intro_to_Mill_Header.adoc index 3f401434c57..1b91a88343a 100644 --- a/docs/modules/ROOT/partials/Intro_to_Mill_Header.adoc +++ b/docs/modules/ROOT/partials/Intro_to_Mill_Header.adoc @@ -26,7 +26,7 @@ digraph G { } .... -{mill-github-url}[Mill] is a fast JVM build tool that supports {language}, speeding +{mill-github-url}[Mill] is a fast multi-language build tool that supports {language}, speeding up common development workflows by 2-10x xref:Case_Study_Mill_vs_Maven.adoc[compared to Maven], xref:Case_Study_Mill_vs_Gradle.adoc[Gradle], or SBT. Mill aims to make your JVM project's build process performant, maintainable, and flexible @@ -35,20 +35,19 @@ even as it grows from a small project to a large codebase or monorepo with hundr * *Performance*: Mill's xref:Tasks.adoc[build graph] automatically xref:The_Mill_Evaluation_Model.adoc#_caching_at_each_layer_of_the_evaluation_model[caches] and xref:#_parallel_task_execution[parallelizes] build - tasks, minimizing the amount of work that needs to be done and keeping your workflows - fast and responsive. + tasks, keeping your workflows fast and responsive. Mill adds minimal overhead over + the logic necessary to build your project, while providing tools to let you identify + and resolve bottlenecks in your build -* *Maintainability*: Mill build tasks are self contained without side-effects making it easy - to trace the data-flow, and its IDE support - (via xref:{language}_Installation_IDE_Support.adoc#_intellij[IntelliJ] or +* *Maintainability*: Mill config and custom logic is written in + xref:_custom_build_logic[custom build logic] in concise type-checked code, + rather than shell scripts, XML or YAML. This lets IDEs + (xref:{language}_Installation_IDE_Support.adoc#_intellij[IntelliJ] or xref:{language}_Installation_IDE_Support.adoc#_vscode[VSCode]) - lets you "*jump-to-definition*" around your build - as easily as any application codebase. + "jump-to-definition" to navigate around your build as easily as any application codebase. -* *Flexibility*: Mill custom logic is written in xref:_custom_build_logic[custom build logic] - in type-checked code, rather than - error-prone shell scripts, verbose AntRun XML, or complicated external plugins. Mill's - custom tasks and modules allow anything from +* *Flexibility*: Mill's custom tasks and modules allow anything from xref:Tasks.adoc#primitive-tasks[adding simple pipelines], up to - xref:Modules.adoc#_use_case_diy_java_modules[adding entire language toolchains], - meaning it can be easily customized to fit exactly what you need. + xref:Modules.adoc#_use_case_diy_java_modules[entire language toolchains]. + This means Mill can be easily customized to fit exactly what you need without being beholden + to third-party plugins which may not work well together or be well maintained. diff --git a/example/javamodule/5-resources/build.sc b/example/javamodule/5-resources/build.sc index d31612440ae..f3ffa942b06 100644 --- a/example/javamodule/5-resources/build.sc +++ b/example/javamodule/5-resources/build.sc @@ -11,3 +11,7 @@ object foo extends JavaModule { } } +//// SNIPPET:APPLICATIONCODE + +/** See Also: foo/src/Foo.java */ +/** See Also: foo/test/src/FooTests.java */ diff --git a/example/javabuilds/5-test-suite/bar/src/bar/Bar.java b/example/javatesting/1-test-suite/bar/src/bar/Bar.java similarity index 100% rename from example/javabuilds/5-test-suite/bar/src/bar/Bar.java rename to example/javatesting/1-test-suite/bar/src/bar/Bar.java diff --git a/example/javabuilds/5-test-suite/bar/test/src/bar/BarTests.java b/example/javatesting/1-test-suite/bar/test/src/bar/BarTests.java similarity index 100% rename from example/javabuilds/5-test-suite/bar/test/src/bar/BarTests.java rename to example/javatesting/1-test-suite/bar/test/src/bar/BarTests.java diff --git a/example/javabuilds/5-test-suite/build.sc b/example/javatesting/1-test-suite/build.sc similarity index 74% rename from example/javabuilds/5-test-suite/build.sc rename to example/javatesting/1-test-suite/build.sc index b39ba67d12c..9d8bb201014 100644 --- a/example/javabuilds/5-test-suite/build.sc +++ b/example/javatesting/1-test-suite/build.sc @@ -23,11 +23,3 @@ object bar extends JavaModule { } } -//// SNIPPET:BUILD3 -object qux extends JavaModule { - object test extends JavaTests with TestModule.Junit5 - object integration extends JavaTests with TestModule.Junit5 -} - -// This example also demonstrates using Junit 5 instead of Junit 4, -// with diff --git a/example/javabuilds/5-test-suite/foo/src/foo/Foo.java b/example/javatesting/1-test-suite/foo/src/foo/Foo.java similarity index 100% rename from example/javabuilds/5-test-suite/foo/src/foo/Foo.java rename to example/javatesting/1-test-suite/foo/src/foo/Foo.java diff --git a/example/javabuilds/5-test-suite/foo/test/src/foo/FooTests.java b/example/javatesting/1-test-suite/foo/test/src/foo/FooTests.java similarity index 100% rename from example/javabuilds/5-test-suite/foo/test/src/foo/FooTests.java rename to example/javatesting/1-test-suite/foo/test/src/foo/FooTests.java diff --git a/example/javamodule/4-test-deps/baz/src/baz/Baz.java b/example/javatesting/2-test-deps/baz/src/baz/Baz.java similarity index 100% rename from example/javamodule/4-test-deps/baz/src/baz/Baz.java rename to example/javatesting/2-test-deps/baz/src/baz/Baz.java diff --git a/example/javamodule/4-test-deps/baz/test/src/baz/BazTestUtils.java b/example/javatesting/2-test-deps/baz/test/src/baz/BazTestUtils.java similarity index 100% rename from example/javamodule/4-test-deps/baz/test/src/baz/BazTestUtils.java rename to example/javatesting/2-test-deps/baz/test/src/baz/BazTestUtils.java diff --git a/example/javamodule/4-test-deps/baz/test/src/baz/BazTests.java b/example/javatesting/2-test-deps/baz/test/src/baz/BazTests.java similarity index 100% rename from example/javamodule/4-test-deps/baz/test/src/baz/BazTests.java rename to example/javatesting/2-test-deps/baz/test/src/baz/BazTests.java diff --git a/example/javamodule/4-test-deps/build.sc b/example/javatesting/2-test-deps/build.sc similarity index 100% rename from example/javamodule/4-test-deps/build.sc rename to example/javatesting/2-test-deps/build.sc diff --git a/example/javamodule/4-test-deps/qux/src/qux/Qux.java b/example/javatesting/2-test-deps/qux/src/qux/Qux.java similarity index 100% rename from example/javamodule/4-test-deps/qux/src/qux/Qux.java rename to example/javatesting/2-test-deps/qux/src/qux/Qux.java diff --git a/example/javamodule/4-test-deps/qux/test/src/qux/QuxTests.java b/example/javatesting/2-test-deps/qux/test/src/qux/QuxTests.java similarity index 100% rename from example/javamodule/4-test-deps/qux/test/src/qux/QuxTests.java rename to example/javatesting/2-test-deps/qux/test/src/qux/QuxTests.java diff --git a/example/javatesting/3-integration-suite/build.sc b/example/javatesting/3-integration-suite/build.sc new file mode 100644 index 00000000000..2bd8ade47d3 --- /dev/null +++ b/example/javatesting/3-integration-suite/build.sc @@ -0,0 +1,9 @@ +//// SNIPPET:BUILD3 +import mill._, javalib._ +object qux extends JavaModule { + object test extends JavaTests with TestModule.Junit5 + object integration extends JavaTests with TestModule.Junit5 +} + +// This example also demonstrates using Junit 5 instead of Junit 4, +// with diff --git a/example/javabuilds/5-test-suite/qux/integration/src/qux/QuxIntegrationTests.java b/example/javatesting/3-integration-suite/qux/integration/src/qux/QuxIntegrationTests.java similarity index 100% rename from example/javabuilds/5-test-suite/qux/integration/src/qux/QuxIntegrationTests.java rename to example/javatesting/3-integration-suite/qux/integration/src/qux/QuxIntegrationTests.java diff --git a/example/javabuilds/5-test-suite/qux/src/qux/Qux.java b/example/javatesting/3-integration-suite/qux/src/qux/Qux.java similarity index 100% rename from example/javabuilds/5-test-suite/qux/src/qux/Qux.java rename to example/javatesting/3-integration-suite/qux/src/qux/Qux.java diff --git a/example/javabuilds/5-test-suite/qux/test/src/qux/QuxTests.java b/example/javatesting/3-integration-suite/qux/test/src/qux/QuxTests.java similarity index 100% rename from example/javabuilds/5-test-suite/qux/test/src/qux/QuxTests.java rename to example/javatesting/3-integration-suite/qux/test/src/qux/QuxTests.java diff --git a/example/misc/8-multi-build-file/build.sc b/example/misc/8-multi-build-file/build.sc deleted file mode 100644 index 9221a52d6b2..00000000000 --- a/example/misc/8-multi-build-file/build.sc +++ /dev/null @@ -1,30 +0,0 @@ -import mill._, scalalib._ - -trait MyModule extends ScalaModule { - def scalaVersion = "2.13.11" -} - -// Example Docs - - -/** Usage - -> ./mill resolve __ -bar -... -bar.qux.module -... -bar.qux.module.compile -... -foo -... -foo.compile - -> ./mill bar.qux.module.compile - -> ./mill foo.compile - -> ./mill foo.run --foo-text hello --bar-qux-text world -Foo.value: hello -BarQux.value:

world

-*/ diff --git a/example/scalabuilds/5-test-suite/build.sc b/example/scalabuilds/5-test-suite/build.sc deleted file mode 100644 index a67c45066e7..00000000000 --- a/example/scalabuilds/5-test-suite/build.sc +++ /dev/null @@ -1,119 +0,0 @@ -//// SNIPPET:BUILD1 -import mill._, scalalib._ - -object foo extends ScalaModule { - def scalaVersion = "2.13.8" - object test extends ScalaTests { - def ivyDeps = Agg(ivy"com.lihaoyi::utest:0.8.4") - def testFramework = "utest.runner.Framework" - } -} - -// This build defines a single module with a test suite, configured to use -// "uTest" as the testing framework. Test suites are themselves ``ScalaModule``s, -// nested within the enclosing module, -//// SNIPPET:END -// and have all the normal tasks like -// `foo.test.compile` available to run, but with an additional `.test` task -// that runs the tests. You can also run the test suite directly, in which case -// it will run the `.test` task as the default task for that module. - -/** Usage - -> mill foo.compile -compiling 1 ... source... - -> mill foo.test.compile -compiling 1 ... source... - -> mill foo.test.test -...foo.FooTests.hello ... -...foo.FooTests.world ... - -> mill foo.test -...foo.FooTests.hello ... -...foo.FooTests.world ... - -*/ - -// For convenience, you can also use one of the predefined test frameworks: -// -// * `TestModule.Junit4` -// * `TestModule.Junit5` -// * `TestModule.TestNg` -// * `TestModule.Munit` -// * `TestModule.ScalaTest` -// * `TestModule.Specs2` -// * `TestModule.Utest` -// * `TestModule.ZioTest` - -//// SNIPPET:BUILD2 -object bar extends ScalaModule { - def scalaVersion = "2.13.8" - - object test extends ScalaTests with TestModule.Utest { - def ivyDeps = Agg(ivy"com.lihaoyi::utest:0.8.4") - } -} -//// SNIPPET:END -/** Usage - -> mill bar.test -...bar.BarTests.hello ... -...bar.BarTests.world ... - -*/ - -// By default, tests are run in a subprocess, and `forkArg` and `forkEnv` can be -// overridden to pass JVM flags & environment variables. You can also use -// -// [source,bash] -// ---- -// mill foo.test.testLocal -// ---- -// -// To run tests in-process in an isolated classloader. -// -// If you want to pass any arguments to the test framework, simply put them after -// `foo.test` in the command line. e.g. {utest-github-url}[uTest] -// lets you pass in a selector to decide which test to run, which in Mill would be: - - -/** Usage - -> mill bar.test bar.BarTests.hello -...bar.BarTests.hello ... - -*/ - -// You can also define multiple test suites if you want, e.g.: -//// SNIPPET:BUILD3 -object qux extends ScalaModule { - def scalaVersion = "2.13.8" - - object test extends ScalaTests with TestModule.Utest { - def ivyDeps = Agg(ivy"com.lihaoyi::utest:0.8.4") - } - object integration extends ScalaTests with TestModule.Utest { - def ivyDeps = Agg(ivy"com.lihaoyi::utest:0.8.4") - } -} -//// SNIPPET:END -// Each of which will expect their sources to be in their respective `foo/test` and -// `foo/integration` folder. - -/** Usage - -> mill qux.test -...qux.QuxTests...hello... -...qux.QuxTests...world... - -> mill qux.integration -...qux.QuxIntegrationTests...helloworld... - -> mill qux.{test,integration} -...qux.QuxTests...hello... -...qux.QuxTests...world... -...qux.QuxIntegrationTests...helloworld... - -*/ \ No newline at end of file diff --git a/example/scalamodule/5-resources/build.sc b/example/scalamodule/5-resources/build.sc index 5f253dbf3d8..d522ec43775 100644 --- a/example/scalamodule/5-resources/build.sc +++ b/example/scalamodule/5-resources/build.sc @@ -18,6 +18,7 @@ object foo extends ScalaModule { ) } } + //// SNIPPET:END /** Usage @@ -31,17 +32,17 @@ object foo extends ScalaModule { // This section discusses how tests can depend on resources locally on disk. // Mill provides two ways to do this: via the JVM classpath resources, and via // the resource folder which is made available as the environment variable -// `TEST_MILL_RESOURCE_FOLDER`; +// `MILL_TEST_RESOURCE_FOLDER`; // // * The *classpath resources* are useful when you want to fetch individual files, // and are bundled with the application by the `.assembly` step when constructing // an assembly jar for deployment. But they do not allow you to list folders // or perform other filesystem operations. // -// * The *resource folder*, available via `TEST_MILL_RESOURCE_FOLDER`, gives you +// * The *resource folder*, available via `MILL_TEST_RESOURCE_FOLDER`, gives you // access to the folder path of the resources on disk. This is useful in allowing // you to list and otherwise manipulate the filesystem, which you cannot do with -// *classpath resources*. However, the `TEST_MILL_RESOURCE_FOLDER` only exists +// *classpath resources*. However, the `MILL_TEST_RESOURCE_FOLDER` only exists // when running tests using Mill, and is not available when executing applications // packaged for deployment via `.assembly` // @@ -49,8 +50,22 @@ object foo extends ScalaModule { // by defining a `T.source` (`otherFiles` above) and passing it to `forkEnv`. This // provide the folder path as an environment variable that the test can make use of // -// You can click the *browse* button in the above example to see an example of code -// the uses these three approaches to load files as part of a test module. +// Example application code demonstrating the techniques above can be seen below: + + +/** See Also: foo/test/resources/test-file-a.txt */ +/** See Also: foo/test/resources/test-file-b.txt */ +/** See Also: foo/test/other-files/other-file.txt */ + +//// SNIPPET:APPLICATIONCODE + +/** See Also: foo/src/Foo.scala */ +/** See Also: foo/test/src/FooTests.scala */ + +//// SNIPPET:END + + +// // // Note that tests require that you pass in any files that they depend on explicitly. // This is necessary so that Mill knows when a test needs to be re-run and when a diff --git a/example/scalabuilds/5-test-suite/bar/src/Bar.scala b/example/scalatesting/1-test-suite/bar/src/Bar.scala similarity index 100% rename from example/scalabuilds/5-test-suite/bar/src/Bar.scala rename to example/scalatesting/1-test-suite/bar/src/Bar.scala diff --git a/example/scalabuilds/5-test-suite/bar/test/src/BarTests.scala b/example/scalatesting/1-test-suite/bar/test/src/BarTests.scala similarity index 100% rename from example/scalabuilds/5-test-suite/bar/test/src/BarTests.scala rename to example/scalatesting/1-test-suite/bar/test/src/BarTests.scala diff --git a/example/scalatesting/1-test-suite/build.sc b/example/scalatesting/1-test-suite/build.sc new file mode 100644 index 00000000000..6a9262b0d3a --- /dev/null +++ b/example/scalatesting/1-test-suite/build.sc @@ -0,0 +1,144 @@ +//// SNIPPET:BUILD1 +import mill._, scalalib._ + +object foo extends ScalaModule { + def scalaVersion = "2.13.8" + object test extends ScalaTests { + def ivyDeps = Agg(ivy"com.lihaoyi::utest:0.8.4") + def testFramework = "utest.runner.Framework" + } +} + +// This build defines a single module with a test suite, configured to use +// "uTest" as the testing framework. Test suites are themselves ``ScalaModule``s, +// nested within the enclosing module, +//// SNIPPET:END +// and have all the normal tasks like +// `foo.test.compile` available to run, but with an additional `.test` task +// that runs the tests. You can also run the test suite directly, in which case +// it will run the `.test` task as the default task for that module. + +/** Usage + +> mill foo.compile +compiling 1 ... source... + +> mill foo.test.compile +compiling 1 ... source... + +> mill foo.test.test +...foo.FooTests.hello ... +...foo.FooTests.world ... + +> mill foo.test +...foo.FooTests.hello ... +...foo.FooTests.world ... + +*/ + +// For convenience, you can also use one of the predefined test frameworks: +// +// * `TestModule.Junit4` +// * `TestModule.Junit5` +// * `TestModule.TestNg` +// * `TestModule.Munit` +// * `TestModule.ScalaTest` +// * `TestModule.Specs2` +// * `TestModule.Utest` +// * `TestModule.ZioTest` + +//// SNIPPET:BUILD2 +object bar extends ScalaModule { + def scalaVersion = "2.13.8" + + object test extends ScalaTests with TestModule.Utest { + def ivyDeps = Agg(ivy"com.lihaoyi::utest:0.8.4") + } +} +//// SNIPPET:END +/** Usage + +> mill bar.test +...bar.BarTests.hello ... +...bar.BarTests.world ... + +*/ + +// You can also select multiple test suites in one command using Mill's +// xref:Target_Query_Syntax.adoc[Target Query Syntax] + +/** Usage + +> mill __.test +...bar.BarTests.hello ... +...bar.BarTests.world ... +...foo.FooTests.hello ... +...foo.FooTests.world ... +... + +*/ + +// Mill provides three ways of running tests +// +// * `foo.test.test`: runs tests in a subprocess in an empty `sandbox/` folder. +// +// * `foo.test.testCached`: runs the tests in an empty `sandbox/` folder and caches the results +// if successful. Also allows multiple test modules to be run in parallel e.g. via `mill __.testCached` +// +// * `foo.test.testLocal`: runs tests in an isolated classloader as part of the main Mill process. +// This can be faster than `.test`, but is less flexible (e.g. you cannot pass `forkEnv`) +// and more prone to interference (due to sharing the `sandbox/` folder provided by the +// Mill process) + +/** Usage + +> mill bar.test.test + +> mill bar.test.testCached + +> mill bar.test.testLocal + +*/ + +// Mill provides three ways of running tests +// +// * `foo.test.test`: runs tests in a subprocess in an empty `sandbox/` folder, and +// `forkArg` and `forkEnv` can be overridden to pass JVM flags & environment variables. +// +// * `foo.test.testCached`: runs the tests in an empty `sandbox/` folder and caches the results +// if successful. Also allows multiple test modules to be run in parallel e.g. via +// `mill __.testCached`. Again, `forkEnv` and `forkArgs` can be configured. +// +// * `foo.test.testLocal`: runs tests in an isolated classloader as part of the main Mill process. +// This can be faster than `.test`, but is less flexible (e.g. you cannot pass `forkEnv`) +// and more prone to interference (due to sharing the `sandbox/` folder provided by the +// Mill process) +// +// +// [source,bash,subs="attributes,verbatim"] +// ---- +// > mill bar.test.test +// +// > mill bar.test.testCached +// +// > mill bar.test.testLocal +// ---- +// +// *Note that Mill runs tests with the working directory set to an empty `sandbox/` folder by default*. +// Tests can access files from their resource directory via the environment variable +// `MILL_TEST_RESOURCE_FOLDER` which provides the path to the resource folder, and additional +// paths can be provided to test via `forkEnv`. See +// xref:Java_Module_Config.adoc#_classpath_and_filesystem_resources[Classpath and Filesystem Resources] +// for more details. +// +// If you want to pass any arguments to the test framework, simply put them after +// `foo.test` in the command line. e.g. {utest-github-url}[uTest] +// lets you pass in a selector to decide which test to run, which in Mill would be: + + +/** Usage + +> mill bar.test bar.BarTests.hello +...bar.BarTests.hello ... + +*/ diff --git a/example/scalabuilds/5-test-suite/foo/src/Foo.scala b/example/scalatesting/1-test-suite/foo/src/Foo.scala similarity index 100% rename from example/scalabuilds/5-test-suite/foo/src/Foo.scala rename to example/scalatesting/1-test-suite/foo/src/Foo.scala diff --git a/example/scalabuilds/5-test-suite/foo/test/src/FooTests.scala b/example/scalatesting/1-test-suite/foo/test/src/FooTests.scala similarity index 100% rename from example/scalabuilds/5-test-suite/foo/test/src/FooTests.scala rename to example/scalatesting/1-test-suite/foo/test/src/FooTests.scala diff --git a/example/scalamodule/4-test-deps/baz/src/Baz.scala b/example/scalatesting/2-test-deps/baz/src/Baz.scala similarity index 100% rename from example/scalamodule/4-test-deps/baz/src/Baz.scala rename to example/scalatesting/2-test-deps/baz/src/Baz.scala diff --git a/example/scalamodule/4-test-deps/baz/test/src/BazTestUtils.scala b/example/scalatesting/2-test-deps/baz/test/src/BazTestUtils.scala similarity index 100% rename from example/scalamodule/4-test-deps/baz/test/src/BazTestUtils.scala rename to example/scalatesting/2-test-deps/baz/test/src/BazTestUtils.scala diff --git a/example/scalamodule/4-test-deps/baz/test/src/BazTests.scala b/example/scalatesting/2-test-deps/baz/test/src/BazTests.scala similarity index 100% rename from example/scalamodule/4-test-deps/baz/test/src/BazTests.scala rename to example/scalatesting/2-test-deps/baz/test/src/BazTests.scala diff --git a/example/scalamodule/4-test-deps/build.sc b/example/scalatesting/2-test-deps/build.sc similarity index 100% rename from example/scalamodule/4-test-deps/build.sc rename to example/scalatesting/2-test-deps/build.sc diff --git a/example/scalamodule/4-test-deps/qux/src/Qux.scala b/example/scalatesting/2-test-deps/qux/src/Qux.scala similarity index 100% rename from example/scalamodule/4-test-deps/qux/src/Qux.scala rename to example/scalatesting/2-test-deps/qux/src/Qux.scala diff --git a/example/scalamodule/4-test-deps/qux/test/src/QuxTests.scala b/example/scalatesting/2-test-deps/qux/test/src/QuxTests.scala similarity index 100% rename from example/scalamodule/4-test-deps/qux/test/src/QuxTests.scala rename to example/scalatesting/2-test-deps/qux/test/src/QuxTests.scala diff --git a/example/scalatesting/3-integration-suite/build.sc b/example/scalatesting/3-integration-suite/build.sc new file mode 100644 index 00000000000..35138f839bf --- /dev/null +++ b/example/scalatesting/3-integration-suite/build.sc @@ -0,0 +1,46 @@ +// You can also define test suites with different names other than `test`. For example, +// the build below defines a test suite with the name `integration`, in addition +// to that named `test`. + +//// SNIPPET:BUILD3 + +import mill._, scalalib._ + +object qux extends ScalaModule { + def scalaVersion = "2.13.8" + + object test extends ScalaTests with TestModule.Utest { + def ivyDeps = Agg(ivy"com.lihaoyi::utest:0.8.4") + } + object integration extends ScalaTests with TestModule.Utest { + def ivyDeps = Agg(ivy"com.lihaoyi::utest:0.8.4") + } +} +//// SNIPPET:END + + +// These two test modules will expect their sources to be in their respective `foo/test` and +// `foo/integration` folder respectively + + +/** Usage + +> mill qux.test # run the normal test suite +...qux.QuxTests...hello... +...qux.QuxTests...world... + + +> mill qux.integration # run the integration test suite +...qux.QuxIntegrationTests...helloworld... + +> mill qux.integration.testCached # run the normal test suite, caching the results +...qux.QuxIntegrationTests...helloworld... + +> mill qux.{test,integration} # run both test suites +...qux.QuxTests...hello... +...qux.QuxTests...world... +...qux.QuxIntegrationTests...helloworld... + +> mill __.integration.testCached # run all integration test suites + +*/ \ No newline at end of file diff --git a/example/scalabuilds/5-test-suite/qux/integration/src/QuxTests.scala b/example/scalatesting/3-integration-suite/qux/integration/src/QuxTests.scala similarity index 100% rename from example/scalabuilds/5-test-suite/qux/integration/src/QuxTests.scala rename to example/scalatesting/3-integration-suite/qux/integration/src/QuxTests.scala diff --git a/example/scalabuilds/5-test-suite/qux/src/Qux.scala b/example/scalatesting/3-integration-suite/qux/src/Qux.scala similarity index 100% rename from example/scalabuilds/5-test-suite/qux/src/Qux.scala rename to example/scalatesting/3-integration-suite/qux/src/Qux.scala diff --git a/example/scalabuilds/5-test-suite/qux/test/src/QuxTests.scala b/example/scalatesting/3-integration-suite/qux/test/src/QuxTests.scala similarity index 100% rename from example/scalabuilds/5-test-suite/qux/test/src/QuxTests.scala rename to example/scalatesting/3-integration-suite/qux/test/src/QuxTests.scala diff --git a/example/misc/8-multi-build-file/bar/module.sc b/example/tasks/10-module-sc/bar/module.sc similarity index 100% rename from example/misc/8-multi-build-file/bar/module.sc rename to example/tasks/10-module-sc/bar/module.sc diff --git a/example/misc/8-multi-build-file/bar/qux/module.sc b/example/tasks/10-module-sc/bar/qux/module.sc similarity index 100% rename from example/misc/8-multi-build-file/bar/qux/module.sc rename to example/tasks/10-module-sc/bar/qux/module.sc diff --git a/example/misc/8-multi-build-file/bar/qux/module/src/BarQux.scala b/example/tasks/10-module-sc/bar/qux/module/src/BarQux.scala similarity index 100% rename from example/misc/8-multi-build-file/bar/qux/module/src/BarQux.scala rename to example/tasks/10-module-sc/bar/qux/module/src/BarQux.scala diff --git a/example/tasks/10-module-sc/build.sc b/example/tasks/10-module-sc/build.sc new file mode 100644 index 00000000000..5ceaa0ba5f0 --- /dev/null +++ b/example/tasks/10-module-sc/build.sc @@ -0,0 +1,54 @@ +import mill._, scalalib._ + +trait MyModule extends ScalaModule { + def scalaVersion = "2.13.11" +} + +/** See Also: foo/module.sc */ + +/** See Also: bar/qux/module.sc */ + +// Mill allows you to break up your `build.sc` file into smaller files by defining the +// build-related logic for any particular subfolder as a `module.sc` file in that subfolder. +// This can be very useful to keep large Mill builds maintainable, as each folder's build logic +// gets co-located with the files that need to be built, and speeds up compilation of the +// build logic since each `build.sc` or `module.sc` file can be compiled independently when +// it is modified without re-compiling all the others. +// +// +// In this example, the root `build.sc` only contains the `trait MyModule`, but it is +// `foo/module.sc` and `bar/qux/module.sc` that define modules using it. The modules +// defined in `foo/module.sc` and `bar/qux/module.sc` are automatically nested within +// `foo` and `bar.qux` respectively, and can be referenced from the command line as below: + +/** Usage + +> ./mill resolve __ +bar +... +bar.qux.module +... +bar.qux.module.compile +... +foo +... +foo.compile + +> ./mill bar.qux.module.compile + +> ./mill foo.compile + +> ./mill foo.run --foo-text hello --bar-qux-text world +Foo.value: hello +BarQux.value:

world

+*/ + +// Note that in this example, `foo/module.sc` defines `object build extends RootModule`, +// and so the name `.build` does not need to be provided at the command line. In contrast, +// `bar/qux/module.sc` defines `object module` that does not extend `RootModule`, and so +// we need to explicitly reference it with a `.module` suffix. +// +// `module.sc` files are only discovered in direct subfolders of the root `build.sc` or +// subfolders of another folder containing a `module.sc`; Hence in this example, we need +// an `bar/module.sc` to be present for `bar/qux/module.sc` to be discovered, even +// though `bar/module.sc` is empty \ No newline at end of file diff --git a/example/misc/8-multi-build-file/foo/module.sc b/example/tasks/10-module-sc/foo/module.sc similarity index 100% rename from example/misc/8-multi-build-file/foo/module.sc rename to example/tasks/10-module-sc/foo/module.sc diff --git a/example/misc/8-multi-build-file/foo/src/Foo.scala b/example/tasks/10-module-sc/foo/src/Foo.scala similarity index 100% rename from example/misc/8-multi-build-file/foo/src/Foo.scala rename to example/tasks/10-module-sc/foo/src/Foo.scala diff --git a/example/tasks/2-primary-tasks/build.sc b/example/tasks/2-primary-tasks/build.sc index 934d824e044..923f06c68ae 100644 --- a/example/tasks/2-primary-tasks/build.sc +++ b/example/tasks/2-primary-tasks/build.sc @@ -32,7 +32,7 @@ def allSources = T { } def lineCount: T[Int] = T { - println("Computing line count") + println("Computing line count!!!") allSources() .map(p => os.read.lines(p.path).size) .sum @@ -69,11 +69,43 @@ Computing line count */ +// Furthermore, when code changes occur, targets only invalidate if the code change +// may directly or indirectly affect it. e.g. adding a comment to `lineCount` will +// not cause it to recompute: + +// ```diff +// def lineCount: T[Int] = T { +// println("Computing line count") +//+ // Hello World +// allSources() +// .map(p => os.read.lines(p.path).size) +// .sum +// ``` +// +// But changing the code of the target or any upstream helper method will cause the +// old value to be invalidated and a new value re-computed (with a new `println`) +// next time it is invoked: +// +// ```diff +// def lineCount: T[Int] = T { +//- println("Computing line count") +//+ println("Computing line count!!!") +// allSources() +// .map(p => os.read.lines(p.path).size) +// .sum +// ``` +// +// For more information on how the bytecode analysis necessary for invalidating targets +// based on code-changes work, see https://github.com/com-lihaoyi/mill/pull/2417[PR#2417] +// that implemented it. +// // The return-value of targets has to be JSON-serializable via // {upickle-github-url}[uPickle]. You can run targets directly from the command // line, or use `show` if you want to see the JSON content or pipe it to // external tools. +// ==== T.dest +// // Each target, e.g. `classFiles`, is assigned a {mill-doc-url}/api/latest/mill/api/Ctx.html#dest:os.Path[T.dest] // folder e.g. `out/classFiles.dest/` on disk as scratch space & to store its // output files , and its returned metadata is automatically JSON-serialized @@ -124,6 +156,16 @@ Generating jar */ +// *Note that `os.pwd` of the Mill process is set to an empty `sandbox/` folder by default.* +// This is to stop you from accidentally reading and writing files to the base repository root, +// which would cause problems with Mill's caches not invalidating properly or files from different +// tasks colliding and causing issues. +// You should never use `os.pwd` or rely on the process working directory, and always explicitly +// use `T.dest` or the `.path` of upstream ``PathRef``s when accessing files. In the rare case where +// you truly need the Mill project root folder, you can access it via `T.workspace` +// +// ==== Dependent Targets +// // Targets can depend on other targets via the `foo()` syntax. // The graph of inter-dependent targets is evaluated in topological order; that // means that the body of a target will not even begin to evaluate if one of its @@ -169,6 +211,8 @@ Finding Largest File */ +// ==== Custom Types +// // uPickle comes with built-in support for most Scala primitive types and // builtin data structures: tuples, collections, ``PathRef``s, etc. can be // returned and automatically serialized/de-serialized as necessary. One @@ -254,9 +298,9 @@ def run(args: String*) = T.command { // === Overrides -// Targets and sources can be overriden, with the override task callable via `super`. -// This lets you override-and-extend source lists the same way you would any other target -// definition: +// Tasks can be overriden, with the overriden task callable via `super`. +// You can also override a task with a different type of task, e.g. below +// we override `sourceRoots` which is a `T.sources` with a `T{}` target: // trait Foo extends Module { diff --git a/example/tasks/7-modules/build.sc b/example/tasks/7-modules/build.sc index 4eec984adae..e0c77c2c104 100644 --- a/example/tasks/7-modules/build.sc +++ b/example/tasks/7-modules/build.sc @@ -219,3 +219,10 @@ object outer2 extends MyModule { ..."value": "hello contents of file inside outer2/nested/inner/sources/"... */ + +// *Note that `os.pwd` of the Mill process is set to an empty `sandbox/` folder by default.* +// When defining a module's source files, you should always use `millSourcePath` to ensure the +// paths defined are relative to the module's root folder, so the module logic can continue +// to work even if moved into a different subfolder. In the rare case where you need the +// Mill project root path, and you truly know what you are doing, you can call +// g`mill.api.WorkspaceRoot.workspaceRoot`. \ No newline at end of file diff --git a/readme.adoc b/readme.adoc index 2c6463d65a7..9055be3b816 100644 --- a/readme.adoc +++ b/readme.adoc @@ -302,6 +302,36 @@ endif::[] // find-replace-regex: https://github.com/com-lihaoyi/mill/pull/(\d*) -> {link-pr}/$1[#$1] +[#main] branch +=== main + +* Builds can now be modularized into per-folder definitions by defining +`module.sc` files in subfolders {link-pr}/3213[#3213] + +* Turn on parallelism for task evaluation by default, except for commands +which always run serially at the end {link-pr}/3265[#3265] +* This can be disabled by passing `--jobs 1` + +* Overhaul the Mill client-server protocol to improve robustness +{link-pr}/3363[#3363] {link-pr}/3366[#3366] {link-pr}/3368[#3368] {link-pr}/3370[#3370] + +* Mill uses empty sandbox folders as the working directory for running its own code and +{link-pr}/3367[#3367] and test suites {link-pr}/3347[#3347], to avoid accidental interference +between tasks and tests due to parallelism +* This can be disabled by adding `def testSandboxWorkingDir = false` in your test module + +* Mill now publishes unit, integration, and example test fixtures for writing plugins {link-pr}/3398[#3398] +for downstream plugin authors to use in testing their own Mill extensions + +* Bump default Sonatype Maven Central publishing timeouts to 10 minutes to avoid +timeouts due to slowness https://github.com/com-lihaoyi/mill/commit/b4c9386b0233fab53a312426715e226e4a7f6302 + +* Importing Mill projects into IntelliJ via BSP now properly marks the `out/`, `.idea/`, and `.bsp/` folders +as excluded {link-pr}/3329[#3329] + +* Optimizations to Mill evaluation logic to reduce fixed overhead of running Mill +on large projects {link-pr}/3388[#3388] + [#0-11-12] === 0.11.12 - 2024-08-20 :version: 0.11.12