diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 162cc87bed7..1d05e7d3e14 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -28,24 +28,30 @@ concurrency: cancel-in-progress: true jobs: - + build-linux: + uses: ./.github/workflows/run-mill-action.yml + with: + java-version: 11 + millargs: __.compile + populate_cache: true + build-windows: + uses: ./.github/workflows/run-mill-action.yml + with: + os: windows-latest + java-version: 11 + millargs: __.compile + populate_cache: true itest: + needs: build-linux strategy: fail-fast: false matrix: include: # bootstrap tests - java-version: 11 # Have one job on oldest JVM - buildcmd: ci/test-mill-dev.sh + buildcmd: ci/test-mill-dev.sh && ci/test-mill-release.sh && ./mill -i -k __.ivyDepsTree && ./mill -i -k __.ivyDepsTree --withRuntime - java-version: 17 # Have one job on default JVM - buildcmd: ci/test-mill-release.sh - - java-version: 17 buildcmd: ci/test-mill-bootstrap.sh - # Just some reporting to enable reasoning about library upgrades - - java-version: 11 - buildcmd: | - ./mill -i -k __.ivyDepsTree - ./mill -i -k __.ivyDepsTree --withRuntime uses: ./.github/workflows/run-mill-action.yml with: @@ -53,55 +59,48 @@ jobs: buildcmd: ${{ matrix.buildcmd }} linux: + needs: build-linux strategy: fail-fast: false matrix: - java-version: [11, 17] - millargs: - # Run unit and module tests on both oldest and newest Java versions - - '"{main,scalalib,testrunner,bsp}.__.test"' + include: - # For most tests, run them arbitrarily on Java 8 or Java 17 on Linux, and + # For most tests, run them arbitrarily on Java 11 or Java 17 on Linux, and # on the opposite version on Windows below, so we get decent coverage of # each test on each Java version and each operating system + # We also try to group tests together to manuaully balance out the runtimes of each jobs + - java-version: 17 + millargs: "'{main,scalalib,testrunner,bsp,testkit}.__.testCached'" - java-version: 11 - millargs: '"scalajslib.__.test"' - - java-version: 11 - millargs: '"scalanativelib.__.test"' + millargs: "'{scalajslib,scalanativelib}.__.testCached'" - java-version: 17 - millargs: "contrib._.test" + millargs: "contrib.__.testCached" - # 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.javalib.__.local.test'" + millargs: "'example.javalib.__.local.testCached'" - java-version: 17 - millargs: "'example.scalalib.__.local.test'" + millargs: "'example.scalalib.__.local.testCached'" - java-version: 11 - millargs: "'example.thirdparty[{mockito,acyclic,commons-io}].local.test'" + millargs: "'example.thirdparty[{mockito,acyclic,commons-io}].local.testCached'" - java-version: 17 - millargs: "'example.thirdparty[{fansi,jimfs,netty,gatling}].local.test'" + millargs: "'example.thirdparty[{fansi,jimfs,netty,gatling}].local.testCached'" - java-version: 11 - millargs: "'example.depth.__.local.test'" - - java-version: 17 - millargs: "'example.extending.__.local.test'" + millargs: "'example.{depth,extending}.__.local.testCached'" # Most of these integration tests should not depend on which mode they # are run in, so just run them in `local` - java-version: 11 - millargs: "'integration.{failure,feature,ide}[_].local.test'" + millargs: "'integration.{failure,feature,ide}.__.local.testCached'" - # These invalidation tests need to be exercised in all three execution modes + # These invalidation tests need to be exercised in both execution modes # to make sure they work with and without -i/--no-server being passed - java-version: 17 - millargs: "'integration.invalidation[_].local.test'" - - java-version: 17 - millargs: "'integration.invalidation[_].fork.test'" + millargs: "'integration.invalidation.__.fork.testCached'" - java-version: 17 - millargs: "'integration.invalidation[_].server.test'" + millargs: "'integration.invalidation.__.server.testCached'" # Check docsite compiles - - java-version: 17 + - java-version: 11 millargs: docs.githubPages @@ -111,32 +110,22 @@ jobs: millargs: ${{ matrix.millargs }} compiler-bridge: + needs: build-linux uses: ./.github/workflows/run-mill-action.yml with: java-version: '8' millargs: bridge.__.publishLocal env-bridge-versions: 'essential' - format-check: - uses: ./.github/workflows/run-mill-action.yml - with: - java-version: '11' - millargs: mill.scalalib.scalafmt.ScalafmtModule/checkFormatAll __.sources - - scalafix-check: + format-scalafix-bincompat: + needs: build-linux uses: ./.github/workflows/run-mill-action.yml with: java-version: '11' - millargs: -i -k __.fix --check - - bincompat-check: - uses: ./.github/workflows/run-mill-action.yml - with: - java-version: '11' - millargs: __.mimaReportBinaryIssues - continue-on-error: true + buildcmd: ./mill -i mill.scalalib.scalafmt.ScalafmtModule/checkFormatAll __.sources + __.mimaReportBinaryIssues + __.fix --check windows: + needs: build-windows strategy: fail-fast: false matrix: @@ -145,16 +134,12 @@ jobs: # the whole suite can take hours on windows v.s. half an hour on linux - java-version: 11 millargs: '"{main,scalalib,bsp}.__.test"' - - java-version: 17 - millargs: '"scalajslib.__.test"' - java-version: 11 - millargs: '"example.scalalib.basic.__.fork.test"' + millargs: '"example.scalalib.{basic,web}.__.fork.test"' - java-version: 17 - millargs: "'integration.feature[_].fork.test'" + millargs: "'integration.{feature,failure}[_].fork.test'" - java-version: 11 millargs: "'integration.invalidation[_].server.test'" - - java-version: 17 - millargs: "'integration.failure[_].fork.test'" - java-version: 11 millargs: "contrib.__.test" @@ -167,7 +152,7 @@ jobs: publish-sonatype: # when in master repo, publish all tags and manual runs on main if: github.repository == 'com-lihaoyi/mill' && (startsWith( github.ref, 'refs/tags/') || (github.ref == 'refs/heads/main' && github.event_name == 'workflow_dispatch' ) ) - needs: [linux, windows, compiler-bridge, format-check, bincompat-check, scalafix-check, itest] + needs: [linux, windows, compiler-bridge, format-scalafix-bincompat, itest] runs-on: ubuntu-latest diff --git a/.github/workflows/run-mill-action.yml b/.github/workflows/run-mill-action.yml index 9fef5b49d4e..6d7d9266992 100644 --- a/.github/workflows/run-mill-action.yml +++ b/.github/workflows/run-mill-action.yml @@ -18,6 +18,9 @@ on: continue-on-error: default: false type: boolean + populate_cache: + default: false + type: boolean timeout-minutes: default: 60 type: number @@ -38,6 +41,16 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + if: ${{ inputs.populate_cache }} + + - uses: actions/download-artifact@v4 + if: ${{ !inputs.populate_cache }} + with: + path: . + name: ${{ inputs.os }}-artifact + + - name: chmod executable + run: "chmod -R +x ." - uses: coursier/cache-action@v6 @@ -60,5 +73,18 @@ jobs: if: inputs.millargs != '' && !startsWith(inputs.os, 'windows') - name: Run Mill (on Windows) '${{ inputs.millargs }}' - run: cmd /C %GITHUB_WORKSPACE%\ci\mill.bat -i -d -k ${{ inputs.millargs }} - if: inputs.millargs != '' && startsWith(inputs.os, 'windows') \ No newline at end of file + run: cmd /C %GITHUB_WORKSPACE%\ci\mill.bat -ij1 __.resolvedIvyDeps; cmd /C %GITHUB_WORKSPACE%\ci\mill.bat -i -j1 -k ${{ inputs.millargs }} + if: inputs.millargs != '' && startsWith(inputs.os, 'windows') + + - name: Run Mill (on Windows) Worker Cleanup + run: 'taskkill -f -im java* && rm -rf out/mill-worker-*' + if: inputs.millargs != '' && startsWith(inputs.os, 'windows') + shell: bash + continue-on-error: true + + - uses: actions/upload-artifact@v4.3.5 + with: + path: . + name: ${{ inputs.os }}-artifact + include-hidden-files: true + if: ${{ inputs.populate_cache }} \ No newline at end of file diff --git a/build.mill b/build.mill index ca4043efb91..1a02d6470eb 100644 --- a/build.mill +++ b/build.mill @@ -151,7 +151,7 @@ object Deps { val log4j2Core = ivy"org.apache.logging.log4j:log4j-core:2.23.1" val osLib = ivy"com.lihaoyi::os-lib:0.10.5" val pprint = ivy"com.lihaoyi::pprint:0.9.0" - val mainargs = ivy"com.lihaoyi::mainargs:0.7.2" + val mainargs = ivy"com.lihaoyi::mainargs:0.7.4" val millModuledefsVersion = "0.11.0-M2" val millModuledefsString = s"com.lihaoyi::mill-moduledefs:${millModuledefsVersion}" val millModuledefs = ivy"${millModuledefsString}" diff --git a/ci/test-mill-dev.sh b/ci/test-mill-dev.sh index 44828909db0..8ffede49a8c 100755 --- a/ci/test-mill-dev.sh +++ b/ci/test-mill-dev.sh @@ -16,3 +16,5 @@ test -d $EXAMPLE/out/foo/3.3.3/compile.dest ./mill -i dist.run $EXAMPLE show "bar[2.13.8].assembly" test -f $EXAMPLE/out/bar/2.13.8/assembly.dest/out.jar + +./mill -i dist.run $EXAMPLE shutdown \ No newline at end of file diff --git a/ci/test-mill-release.sh b/ci/test-mill-release.sh index 562771dff96..56fd55d69c4 100755 --- a/ci/test-mill-release.sh +++ b/ci/test-mill-release.sh @@ -19,3 +19,5 @@ test -d $EXAMPLE/out/foo/3.3.3/compile.dest (cd $EXAMPLE && ../../../../out/dist/assembly.dest/mill show "bar[2.13.8].assembly") test -f $EXAMPLE/out/bar/2.13.8/assembly.dest/out.jar + +(cd $EXAMPLE && ../../../../out/dist/assembly.dest/mill shutdown) \ No newline at end of file diff --git a/example/depth/large/11-helper-files/build.mill b/example/depth/large/11-helper-files/build.mill index 2f7cd012eb8..416c9a0cf55 100644 --- a/example/depth/large/11-helper-files/build.mill +++ b/example/depth/large/11-helper-files/build.mill @@ -8,6 +8,7 @@ object `package` extends RootModule with MyModule{ "MY_PROJECT_VERSION" -> versions.myProjectVersion, ) } + /** See Also: util.mill */ /** See Also: foo/package.mill */ /** See Also: foo/versions.mill */ diff --git a/example/depth/large/13-helper-files-mill-sc/build.mill.sc b/example/depth/large/13-helper-files-mill-sc/build.mill.sc new file mode 100644 index 00000000000..7a757d7b0ba --- /dev/null +++ b/example/depth/large/13-helper-files-mill-sc/build.mill.sc @@ -0,0 +1,39 @@ +package build +import mill._, scalalib._ +import $file.foo.versions +import $file.util.MyModule +object `package` extends RootModule with MyModule{ + def forkEnv = Map( + "MY_SCALA_VERSION" -> build.scalaVersion(), + "MY_PROJECT_VERSION" -> versions.myProjectVersion, + ) +} +///** See Also: util.mill.sc */ +///** See Also: foo/package.mill.sc */ +///** See Also: foo/versions.mill.sc */ + + +// Apart from having `package` files in subfolders to define modules, Mill +// also allows you to have helper code in any `*.mill` file in the same folder +// as your `build.mill` or a `package.mill`. +// +// Different helper scripts and ``build.mill``/``package`` files can all refer to +// each other using the `build` object, which marks the root object of your build. +// In this example: +// +// * `build.mill` can be referred to as simple `build` +// * `util.mill` can be referred to as simple `$file.util` +// * `foo/package` can be referred to as simple `build.foo` +// * `foo/versions.mill` can be referred to as simple `$file.foo.versions` + +/** Usage + +> ./mill run +Main Env build.util.myScalaVersion: 2.13.14 +Main Env build.foo.versions.myProjectVersion: 0.0.1 + +> ./mill foo.run +Foo Env build.util.myScalaVersion: 2.13.14 +Foo Env build.foo.versions.myProjectVersion: 0.0.1 + +*/ diff --git a/example/depth/large/13-helper-files-mill-sc/foo/package.mill.sc b/example/depth/large/13-helper-files-mill-sc/foo/package.mill.sc new file mode 100644 index 00000000000..a28fe0a29ce --- /dev/null +++ b/example/depth/large/13-helper-files-mill-sc/foo/package.mill.sc @@ -0,0 +1,10 @@ +package build.foo +import mill._, scalalib._ +import $file.util +import $file.foo.versions.myProjectVersion +object `package` extends RootModule with build_.util.MyModule { + def forkEnv = Map( + "MY_SCALA_VERSION" -> util.myScalaVersion, + "MY_PROJECT_VERSION" -> myProjectVersion + ) +} diff --git a/example/depth/large/13-helper-files-mill-sc/foo/src/Foo.scala b/example/depth/large/13-helper-files-mill-sc/foo/src/Foo.scala new file mode 100644 index 00000000000..08fe8028aac --- /dev/null +++ b/example/depth/large/13-helper-files-mill-sc/foo/src/Foo.scala @@ -0,0 +1,8 @@ +package foo + +object Foo { + def main(args: Array[String]): Unit = { + println("Foo Env build.util.myScalaVersion: " + sys.env("MY_SCALA_VERSION")) + println("Foo Env build.foo.versions.myProjectVersion: " + sys.env("MY_PROJECT_VERSION")) + } +} diff --git a/example/depth/large/13-helper-files-mill-sc/foo/versions.mill.sc b/example/depth/large/13-helper-files-mill-sc/foo/versions.mill.sc new file mode 100644 index 00000000000..d2d0681b67c --- /dev/null +++ b/example/depth/large/13-helper-files-mill-sc/foo/versions.mill.sc @@ -0,0 +1,3 @@ +package build.foo + +def myProjectVersion = "0.0.1" \ No newline at end of file diff --git a/example/depth/large/13-helper-files-mill-sc/src/Main.scala b/example/depth/large/13-helper-files-mill-sc/src/Main.scala new file mode 100644 index 00000000000..f8e6fdfa68f --- /dev/null +++ b/example/depth/large/13-helper-files-mill-sc/src/Main.scala @@ -0,0 +1,6 @@ +object Main { + def main(args: Array[String]): Unit = { + println("Main Env build.util.myScalaVersion: " + sys.env("MY_SCALA_VERSION")) + println("Main Env build.foo.versions.myProjectVersion: " + sys.env("MY_PROJECT_VERSION")) + } +} diff --git a/example/depth/large/13-helper-files-mill-sc/util.mill.sc b/example/depth/large/13-helper-files-mill-sc/util.mill.sc new file mode 100644 index 00000000000..0e4b102796e --- /dev/null +++ b/example/depth/large/13-helper-files-mill-sc/util.mill.sc @@ -0,0 +1,9 @@ +package build + +import mill._, scalalib._ + +def myScalaVersion = "2.13.14" + +trait MyModule extends ScalaModule { + def scalaVersion = myScalaVersion +} diff --git a/example/javalib/web/2-hello-spring-boot/build.mill b/example/javalib/web/2-hello-spring-boot/build.mill index da4b7f308c1..cc3ce13aad7 100644 --- a/example/javalib/web/2-hello-spring-boot/build.mill +++ b/example/javalib/web/2-hello-spring-boot/build.mill @@ -23,7 +23,7 @@ object `package` extends RootModule with JavaModule { > mill test ...com.example.HelloSpringBootTest#shouldReturnDefaultMessage() finished... -> mill runBackground; sleep 10 # give time for server to start +> mill runBackground; sleep 15 # give time for server to start > curl http://localhost:8086 ...

Hello, World!

... diff --git a/example/javalib/web/3-todo-spring-boot/build.mill b/example/javalib/web/3-todo-spring-boot/build.mill index 6b48e5f64af..8f0d5d12abd 100644 --- a/example/javalib/web/3-todo-spring-boot/build.mill +++ b/example/javalib/web/3-todo-spring-boot/build.mill @@ -61,7 +61,7 @@ object `package` extends RootModule with JavaModule { ...com.example.TodomvcIntegrationTests#homePageLoads() finished... ...com.example.TodomvcIntegrationTests#addNewTodoItem() finished... -> mill test.runBackground; sleep 10 # give time for server to start +> mill test.runBackground; sleep 15 # give time for server to start > curl http://localhost:8087 ...

todos

... diff --git a/example/javalib/web/4-hello-micronaut/build.mill b/example/javalib/web/4-hello-micronaut/build.mill index 3dba9169676..ff6ffb67a54 100644 --- a/example/javalib/web/4-hello-micronaut/build.mill +++ b/example/javalib/web/4-hello-micronaut/build.mill @@ -69,7 +69,7 @@ trait MicronautModule extends MavenModule{ > mill test ...example.micronaut.HelloControllerTest#testHello()... -> mill runBackground; sleep 2 # give time for server to start +> mill runBackground; sleep 5 # give time for server to start > curl http://localhost:8088/hello ...Hello World... diff --git a/example/javalib/web/5-todo-micronaut/build.mill b/example/javalib/web/5-todo-micronaut/build.mill index d2b4c180ffe..a81c48a5b88 100644 --- a/example/javalib/web/5-todo-micronaut/build.mill +++ b/example/javalib/web/5-todo-micronaut/build.mill @@ -90,7 +90,7 @@ trait MicronautModule extends MavenModule{ ...example.micronaut.TodoItemControllerTest... ...example.micronaut.HtmxWebJarsTest... -> mill runBackground; sleep 2 # give time for server to start +> mill runBackground; sleep 5 # give time for server to start > curl http://localhost:8088 ...

todos

... diff --git a/integration/failure/build-file-in-subfolder/src/BuildFileInSubfolderTests.scala b/integration/failure/build-file-in-subfolder/src/BuildFileInSubfolderTests.scala index f5d51acafd0..ea464c3864c 100644 --- a/integration/failure/build-file-in-subfolder/src/BuildFileInSubfolderTests.scala +++ b/integration/failure/build-file-in-subfolder/src/BuildFileInSubfolderTests.scala @@ -1,15 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object BuildFileInSubfolderTests extends IntegrationTestSuite { +object BuildFileInSubfolderTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test("success") { - val res = eval(("resolve", "_")) + test("success") - integrationTest { tester => + val res = tester.eval(("resolve", "_")) assert(res.isSuccess == false) assert(res.err.contains("Mill build.mill files can only be in the project root")) } diff --git a/integration/failure/compile-error/src/CompileErrorTests.scala b/integration/failure/compile-error/src/CompileErrorTests.scala index 6c718d80ae4..999c258a9e9 100644 --- a/integration/failure/compile-error/src/CompileErrorTests.scala +++ b/integration/failure/compile-error/src/CompileErrorTests.scala @@ -1,15 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object CompileErrorTests extends IntegrationTestSuite { +object CompileErrorTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test { - val res = eval("foo.scalaVersion") + test - integrationTest { tester => + val res = tester.eval("foo.scalaVersion") assert(res.isSuccess == false) assert(res.err.contains("""bar.mill:15:9: not found: value doesntExist""")) diff --git a/integration/failure/cross-collisions/src/CrossCollisionsTests.scala b/integration/failure/cross-collisions/src/CrossCollisionsTests.scala index f964a019fb7..04805609ab5 100644 --- a/integration/failure/cross-collisions/src/CrossCollisionsTests.scala +++ b/integration/failure/cross-collisions/src/CrossCollisionsTests.scala @@ -1,15 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object CrossCollisionsTests extends IntegrationTestSuite { +object CrossCollisionsTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test("detect-collision") { - val res = eval(("resolve", "foo._")) + test("detect-collision") - integrationTest { tester => + val res = tester.eval(("resolve", "foo._")) assert(!res.isSuccess) assert(res.err.contains("Cross module ")) assert( diff --git a/integration/failure/invalid-meta-module/src/InvalidMetaModuleTests.scala b/integration/failure/invalid-meta-module/src/InvalidMetaModuleTests.scala index 3387cc7fbeb..429d22a44c5 100644 --- a/integration/failure/invalid-meta-module/src/InvalidMetaModuleTests.scala +++ b/integration/failure/invalid-meta-module/src/InvalidMetaModuleTests.scala @@ -1,15 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object InvalidMetaModuleTests extends IntegrationTestSuite { +object InvalidMetaModuleTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test("success") { - val res = eval(("resolve", "_")) + test("success") - integrationTest { tester => + val res = tester.eval(("resolve", "_")) assert(res.isSuccess == false) assert(res.err.contains("object `package` ")) assert(res.err.contains("must extend `MillBuildRootModule`")) diff --git a/integration/failure/invalid-package-declaration/src/InvalidPackageDeclaration.scala b/integration/failure/invalid-package-declaration/src/InvalidPackageDeclaration.scala index b7afb1dbd2e..f2806779c65 100644 --- a/integration/failure/invalid-package-declaration/src/InvalidPackageDeclaration.scala +++ b/integration/failure/invalid-package-declaration/src/InvalidPackageDeclaration.scala @@ -1,15 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object InvalidPackageDeclaration extends IntegrationTestSuite { +object InvalidPackageDeclaration extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test("success") { - val res = eval(("resolve", "_")) + test("success") - integrationTest { tester => + val res = tester.eval(("resolve", "_")) assert(res.isSuccess == false) assert(res.err.contains( """Package declaration "package wrong" in build.mill does not match folder structure. Expected: "package build"""" diff --git a/integration/failure/invalid-root-module/src/InvalidRootModuleTests.scala b/integration/failure/invalid-root-module/src/InvalidRootModuleTests.scala index 7d1573a2044..fc0831494c9 100644 --- a/integration/failure/invalid-root-module/src/InvalidRootModuleTests.scala +++ b/integration/failure/invalid-root-module/src/InvalidRootModuleTests.scala @@ -1,15 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object InvalidRootModuleTests extends IntegrationTestSuite { +object InvalidRootModuleTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test("success") { - val res = eval(("resolve", "_")) + test("success") - integrationTest { tester => + val res = tester.eval(("resolve", "_")) assert(res.isSuccess == false) assert(res.err.contains("object `package` in ")) assert(res.err.contains("must extend `RootModule`")) diff --git a/integration/failure/invalid-subfolder-root-module/src/InvalidSubfolderRootModuleTests.scala b/integration/failure/invalid-subfolder-root-module/src/InvalidSubfolderRootModuleTests.scala index 6cbd9d98f75..8d9c8b11ddc 100644 --- a/integration/failure/invalid-subfolder-root-module/src/InvalidSubfolderRootModuleTests.scala +++ b/integration/failure/invalid-subfolder-root-module/src/InvalidSubfolderRootModuleTests.scala @@ -1,15 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object InvalidSubfolderRootModuleTests extends IntegrationTestSuite { +object InvalidSubfolderRootModuleTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test("success") { - val res = eval(("resolve", "_")) + test("success") - integrationTest { tester => + val res = tester.eval(("resolve", "_")) assert(res.isSuccess == false) assert(res.err.contains("object `package` ")) assert(res.err.contains("must extend `RootModule`")) diff --git a/integration/failure/misnamed-root-module/src/MisnamedRootModuleTests.scala b/integration/failure/misnamed-root-module/src/MisnamedRootModuleTests.scala index 466f32784e7..c21e8da6a32 100644 --- a/integration/failure/misnamed-root-module/src/MisnamedRootModuleTests.scala +++ b/integration/failure/misnamed-root-module/src/MisnamedRootModuleTests.scala @@ -1,15 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object MisnamedRootModuleTests extends IntegrationTestSuite { +object MisnamedRootModuleTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test("success") { - val res = eval(("resolve", "_")) + test("success") - integrationTest { tester => + val res = tester.eval(("resolve", "_")) assert(!res.isSuccess) assert(res.err.contains( "Only one RootModule named `package` can be defined in a build, not: foo" diff --git a/integration/failure/missing-build-file/src/MissingBuildFileTests.scala b/integration/failure/missing-build-file/src/MissingBuildFileTests.scala index 412c1766651..2b6f625d991 100644 --- a/integration/failure/missing-build-file/src/MissingBuildFileTests.scala +++ b/integration/failure/missing-build-file/src/MissingBuildFileTests.scala @@ -1,15 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object MissingBuildFileTests extends IntegrationTestSuite { +object MissingBuildFileTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test { - val res = eval(("resolve", "_")) + test - integrationTest { tester => + val res = tester.eval(("resolve", "_")) assert(!res.isSuccess) val s"build.mill file not found in $msg. Are you in a Mill project folder?" = res.err } diff --git a/integration/failure/module-init-error/src/ModuleInitErrorTests.scala b/integration/failure/module-init-error/src/ModuleInitErrorTests.scala index a0609b6856d..c06cffab877 100644 --- a/integration/failure/module-init-error/src/ModuleInitErrorTests.scala +++ b/integration/failure/module-init-error/src/ModuleInitErrorTests.scala @@ -1,22 +1,20 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object ModuleInitErrorTests extends IntegrationTestSuite { +object ModuleInitErrorTests extends UtestIntegrationTestSuite { def captureOutErr = true val tests: Tests = Tests { - initWorkspace() - - test("resolve") { + test("resolve") - integrationTest { tester => // Ensure that resolve works even of the modules containing the resolved // tasks are broken - val res1 = eval(("resolve", "foo.fooTarget")) + val res1 = tester.eval(("resolve", "foo.fooTarget")) assert(res1.isSuccess == true) assert(res1.out.contains("foo.fooTarget")) - val res2 = eval(("resolve", "_._")) + val res2 = tester.eval(("resolve", "_._")) assert(res2.isSuccess == true) assert( res2.out.contains("bar.barCommand"), @@ -26,11 +24,11 @@ object ModuleInitErrorTests extends IntegrationTestSuite { res2.out.contains("foo.fooCommand") ) - val res3 = eval(("resolve", "__.fooTarget")) + val res3 = tester.eval(("resolve", "__.fooTarget")) assert(res3.isSuccess == true) assert(res3.out.contains("foo.fooTarget")) - val res4 = eval(("resolve", "__")) + val res4 = tester.eval(("resolve", "__")) assert(res4.isSuccess == true) assert(res4.out.contains("bar")) assert(res4.out.contains("bar.barCommand")) @@ -43,21 +41,24 @@ object ModuleInitErrorTests extends IntegrationTestSuite { assert(res4.out.contains("foo.fooTarget")) } - test("rootTarget") { + test("rootTarget") - integrationTest { tester => + import tester._ // If we specify a target in the root module, we are not // affected by the sub-modules failing to initialize val res = eval("rootTarget") assert(res.isSuccess == true) assert(res.out.contains("""Running rootTarget""")) } - test("rootCommand") { + test("rootCommand") - integrationTest { tester => + import tester._ // If we specify a target in the root module, we are not // affected by the sub-modules failing to initialize val res = eval(("rootCommand", "-s", "hello")) assert(res.isSuccess == true) assert(res.out.contains("""Running rootCommand hello""")) } - test("fooTarget") { + test("fooTarget") - integrationTest { tester => + import tester._ val res = eval("foo.fooTarget") assert(res.isSuccess == false) assert(fansi.Str(res.err).plainText.contains("""java.lang.Exception: Foo Boom""")) @@ -65,29 +66,34 @@ object ModuleInitErrorTests extends IntegrationTestSuite { // frames from the Mill launcher assert(fansi.Str(res.err).plainText.linesIterator.size < 20) } - test("fooCommand") { + test("fooCommand") - integrationTest { tester => + import tester._ val res = eval(("foo.fooCommand", "-s", "hello")) assert(res.isSuccess == false) assert(fansi.Str(res.err).plainText.contains("""java.lang.Exception: Foo Boom""")) assert(fansi.Str(res.err).plainText.linesIterator.size < 20) } - test("barTarget") { + test("barTarget") - integrationTest { tester => + import tester._ val res = eval("bar.barTarget") assert(res.isSuccess == true) assert(res.out.contains("""Running barTarget""")) } - test("barCommand") { + test("barCommand") - integrationTest { tester => + import tester._ val res = eval(("bar.barCommand", "-s", "hello")) assert(res.isSuccess == true) assert(res.out.contains("""Running barCommand hello""")) } - test("quxTarget") { + test("quxTarget") - integrationTest { tester => + import tester._ val res = eval("bar.qux.quxTarget") assert(res.isSuccess == false) assert(fansi.Str(res.err).plainText.contains("""java.lang.Exception: Qux Boom""")) assert(fansi.Str(res.err).plainText.linesIterator.size < 20) } - test("quxCommand") { + test("quxCommand") - integrationTest { tester => + import tester._ val res = eval(("bar.qux.quxCommand", "-s", "hello")) assert(res.isSuccess == false) assert(fansi.Str(res.err).plainText.contains("""java.lang.Exception: Qux Boom""")) diff --git a/integration/failure/module-outside-top-level-module/src/ModuleOutsideTopLevelModuleTests.scala b/integration/failure/module-outside-top-level-module/src/ModuleOutsideTopLevelModuleTests.scala index 0633cb930ac..28aac9aea3a 100644 --- a/integration/failure/module-outside-top-level-module/src/ModuleOutsideTopLevelModuleTests.scala +++ b/integration/failure/module-outside-top-level-module/src/ModuleOutsideTopLevelModuleTests.scala @@ -1,14 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object ModuleOutsideTopLevelModuleTests extends IntegrationTestSuite { +object ModuleOutsideTopLevelModuleTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test("success") { + test("success") - integrationTest { tester => + import tester._ val res = eval(("resolve", "_")) assert(!res.isSuccess) assert( diff --git a/integration/failure/no-modules-in-helper-file/src/NoModulesInHelperFileTests.scala b/integration/failure/no-modules-in-helper-file/src/NoModulesInHelperFileTests.scala index 0b5afb37c33..f68f2b874c3 100644 --- a/integration/failure/no-modules-in-helper-file/src/NoModulesInHelperFileTests.scala +++ b/integration/failure/no-modules-in-helper-file/src/NoModulesInHelperFileTests.scala @@ -1,14 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object NoModulesInHelperFileTests extends IntegrationTestSuite { +object NoModulesInHelperFileTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test("success") { + test("success") - integrationTest { tester => + import tester._ val res = eval(("resolve", "_")) assert(res.isSuccess == false) assert( diff --git a/integration/failure/package-file-in-root/src/PackageFileInRootTests.scala b/integration/failure/package-file-in-root/src/PackageFileInRootTests.scala index 87b8f4eddf2..e193c0534fa 100644 --- a/integration/failure/package-file-in-root/src/PackageFileInRootTests.scala +++ b/integration/failure/package-file-in-root/src/PackageFileInRootTests.scala @@ -1,14 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object PackageFileInRootTests extends IntegrationTestSuite { +object PackageFileInRootTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test("success") { + test("success") - integrationTest { tester => + import tester._ val res = eval(("resolve", "_")) assert(res.isSuccess == false) assert(res.err.contains("Mill package.mill files can only be in subfolders")) diff --git a/integration/failure/parse-error/src/ParseErrorTests.scala b/integration/failure/parse-error/src/ParseErrorTests.scala index 772df82f476..8206a60ad60 100644 --- a/integration/failure/parse-error/src/ParseErrorTests.scala +++ b/integration/failure/parse-error/src/ParseErrorTests.scala @@ -1,14 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object ParseErrorTests extends IntegrationTestSuite { +object ParseErrorTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test { + test - integrationTest { tester => + import tester._ val res = eval("foo.scalaVersion") assert(res.isSuccess == false) diff --git a/integration/failure/root-module-compile-error/src/RootModuleCompileErrorTests.scala b/integration/failure/root-module-compile-error/src/RootModuleCompileErrorTests.scala index 97244a3f8e1..d84b9483a14 100644 --- a/integration/failure/root-module-compile-error/src/RootModuleCompileErrorTests.scala +++ b/integration/failure/root-module-compile-error/src/RootModuleCompileErrorTests.scala @@ -1,14 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object RootModuleCompileErrorTests extends IntegrationTestSuite { +object RootModuleCompileErrorTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test { + test - integrationTest { tester => + import tester._ val res = eval("foo.scalaVersion") assert(res.isSuccess == false) diff --git a/integration/failure/root-subfolder-module-collision/src/RootSubfolderModuleCollisionTests.scala b/integration/failure/root-subfolder-module-collision/src/RootSubfolderModuleCollisionTests.scala index c33cbf5ff72..2becba29e17 100644 --- a/integration/failure/root-subfolder-module-collision/src/RootSubfolderModuleCollisionTests.scala +++ b/integration/failure/root-subfolder-module-collision/src/RootSubfolderModuleCollisionTests.scala @@ -1,14 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object RootSubfolderModuleCollisionTests extends IntegrationTestSuite { +object RootSubfolderModuleCollisionTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test("success") { + test("success") - integrationTest { tester => + import tester._ val res = eval(("resolve", "_")) assert(res.isSuccess == false) assert(res.err.contains("cannot override final member")) diff --git a/integration/failure/subfolder-helper-module-collision/src/SubfolderHelperModuleCollisionTests.scala b/integration/failure/subfolder-helper-module-collision/src/SubfolderHelperModuleCollisionTests.scala index d694aab1ed0..fde047ca517 100644 --- a/integration/failure/subfolder-helper-module-collision/src/SubfolderHelperModuleCollisionTests.scala +++ b/integration/failure/subfolder-helper-module-collision/src/SubfolderHelperModuleCollisionTests.scala @@ -1,14 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object SubfolderHelperModuleCollisionTests extends IntegrationTestSuite { +object SubfolderHelperModuleCollisionTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test("success") { + test("success") - integrationTest { tester => + import tester._ val res = eval(("resolve", "_")) assert(res.isSuccess == false) // Not a great error message but it will have to do for now diff --git a/integration/failure/subfolder-missing-build-prefix/src/SubfolderMissingBuildPrefix.scala b/integration/failure/subfolder-missing-build-prefix/src/SubfolderMissingBuildPrefix.scala index 7711bbdc64d..02e744e219d 100644 --- a/integration/failure/subfolder-missing-build-prefix/src/SubfolderMissingBuildPrefix.scala +++ b/integration/failure/subfolder-missing-build-prefix/src/SubfolderMissingBuildPrefix.scala @@ -1,14 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object SubfolderMissingBuildPrefix extends IntegrationTestSuite { +object SubfolderMissingBuildPrefix extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test("success") { + test("success") - integrationTest { tester => + import tester._ val res = eval(("resolve", "_")) assert(res.isSuccess == false) assert(res.err.contains("object y is not a member of package build_.sub")) diff --git a/integration/failure/things-outside-top-level-module/src/ThingsOutsideTopLevelModuleTests.scala b/integration/failure/things-outside-top-level-module/src/ThingsOutsideTopLevelModuleTests.scala index 564df09a65f..cf71ac33e5c 100644 --- a/integration/failure/things-outside-top-level-module/src/ThingsOutsideTopLevelModuleTests.scala +++ b/integration/failure/things-outside-top-level-module/src/ThingsOutsideTopLevelModuleTests.scala @@ -1,14 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object ThingsOutsideTopLevelModuleTests extends IntegrationTestSuite { +object ThingsOutsideTopLevelModuleTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test("success") { + test("success") - integrationTest { tester => + import tester._ val res = eval(("resolve", "_")) assert(!res.isSuccess) assert( diff --git a/integration/feature/auxiliary-class-files/src/AuxiliaryClassFilesTests.scala b/integration/feature/auxiliary-class-files/src/AuxiliaryClassFilesTests.scala index 5551fa0f4e1..e481db1bff9 100644 --- a/integration/feature/auxiliary-class-files/src/AuxiliaryClassFilesTests.scala +++ b/integration/feature/auxiliary-class-files/src/AuxiliaryClassFilesTests.scala @@ -1,59 +1,60 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ // Regress test for issue https://github.com/com-lihaoyi/mill/issues/1901 -object AuxiliaryClassFilesTests extends IntegrationTestSuite { +object AuxiliaryClassFilesTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - test("tasty files are deleted together with companion class files") { - initWorkspace() - assert(eval("app.jvm.compile").isSuccess) + test("tasty files are deleted together with companion class files") - integrationTest { + tester => + import tester._ + assert(eval("app.jvm.compile").isSuccess) - val classes = workspacePath / "out" / "app" / "jvm" / "compile.dest" / "classes" - val firstRun = os.list(classes).map(_.last) + val classes = workspacePath / "out" / "app" / "jvm" / "compile.dest" / "classes" + val firstRun = os.list(classes).map(_.last) - os.remove(workspacePath / "app" / "src" / "foo.scala") + os.remove(workspacePath / "app" / "src" / "foo.scala") - assert(eval("app.jvm.compile").isSuccess) + assert(eval("app.jvm.compile").isSuccess) - val secondRun = os.list(classes).map(_.last) + val secondRun = os.list(classes).map(_.last) - assert(firstRun == Seq("foo$.class", "foo.class", "foo.tasty")) - assert(secondRun == Seq.empty) + assert(firstRun == Seq("foo$.class", "foo.class", "foo.tasty")) + assert(secondRun == Seq.empty) } - test("compilation fails when deleting a class used by other files") { - initWorkspace() + test("compilation fails when deleting a class used by other files") - integrationTest { + tester => + import tester._ + os.write(workspacePath / "app" / "src" / "bar.scala", "object bar { println(foo) }") + val firstRunSuccessful = eval("app.jvm.compile") + assert(firstRunSuccessful.isSuccess) - os.write(workspacePath / "app" / "src" / "bar.scala", "object bar { println(foo) }") - val firstRunSuccessful = eval("app.jvm.compile") - assert(firstRunSuccessful.isSuccess) + val classes = workspacePath / "out" / "app" / "jvm" / "compile.dest" / "classes" + val firstRun = os.list(classes).map(_.last) - val classes = workspacePath / "out" / "app" / "jvm" / "compile.dest" / "classes" - val firstRun = os.list(classes).map(_.last) + os.remove(workspacePath / "app" / "src" / "foo.scala") - os.remove(workspacePath / "app" / "src" / "foo.scala") + val secondRunSuccessful = eval("app.jvm.compile") + assert(!secondRunSuccessful.isSuccess) - val secondRunSuccessful = eval("app.jvm.compile") - assert(!secondRunSuccessful.isSuccess) + val secondRun = os.list(classes).map(_.last) - val secondRun = os.list(classes).map(_.last) - - assert(firstRun == Seq( - "bar$.class", - "bar.class", - "bar.tasty", - "foo$.class", - "foo.class", - "foo.tasty" - )) - assert(secondRun == Seq.empty) + assert(firstRun == Seq( + "bar$.class", + "bar.class", + "bar.tasty", + "foo$.class", + "foo.class", + "foo.tasty" + )) + assert(secondRun == Seq.empty) } - test("nir files are deleted together with companion class files") { - initWorkspace() + test("nir files are deleted together with companion class files") - integrationTest { tester => + import tester._ assert(eval("app.native.compile").isSuccess) val classes = workspacePath / "out" / "app" / "native" / "compile.dest" / "classes" @@ -69,21 +70,22 @@ object AuxiliaryClassFilesTests extends IntegrationTestSuite { assert(secondRun == Seq.empty) } - test("sjsir files are deleted together with companion class files") { - initWorkspace() - assert(eval("app.js.compile").isSuccess) + test("sjsir files are deleted together with companion class files") - integrationTest { + tester => + import tester._ + assert(eval("app.js.compile").isSuccess) - val classes = workspacePath / "out" / "app" / "js" / "compile.dest" / "classes" - val firstRun = os.list(classes).map(_.last) + val classes = workspacePath / "out" / "app" / "js" / "compile.dest" / "classes" + val firstRun = os.list(classes).map(_.last) - os.remove(workspacePath / "app" / "src" / "foo.scala") + os.remove(workspacePath / "app" / "src" / "foo.scala") - assert(eval("app.js.compile").isSuccess) + assert(eval("app.js.compile").isSuccess) - val secondRun = os.list(classes).map(_.last) + val secondRun = os.list(classes).map(_.last) - assert(firstRun == Seq("foo$.class", "foo$.sjsir", "foo.class", "foo.tasty")) - assert(secondRun == Seq.empty) + assert(firstRun == Seq("foo$.class", "foo$.sjsir", "foo.class", "foo.tasty")) + assert(secondRun == Seq.empty) } } } diff --git a/integration/feature/docannotations/src/DocAnnotationsTests.scala b/integration/feature/docannotations/src/DocAnnotationsTests.scala index 8c4948e75be..b23fdeb9b36 100644 --- a/integration/feature/docannotations/src/DocAnnotationsTests.scala +++ b/integration/feature/docannotations/src/DocAnnotationsTests.scala @@ -1,10 +1,10 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object DocAnnotationsTests extends IntegrationTestSuite { +object DocAnnotationsTests extends UtestIntegrationTestSuite { def globMatches(glob: String, input: String): Boolean = { StringContext .glob( @@ -16,8 +16,8 @@ object DocAnnotationsTests extends IntegrationTestSuite { } val tests: Tests = Tests { - initWorkspace() - test("test") - { + test("test") - integrationTest { tester => + import tester._ val res = eval(("inspect", "core.test.ivyDeps")) assert(res.isSuccess == true) diff --git a/integration/feature/hygiene/src/HygieneTests.scala b/integration/feature/hygiene/src/HygieneTests.scala index f805400b1ec..c6094f5f421 100644 --- a/integration/feature/hygiene/src/HygieneTests.scala +++ b/integration/feature/hygiene/src/HygieneTests.scala @@ -1,14 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object HygieneTests extends IntegrationTestSuite { +object HygieneTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test { + test - integrationTest { tester => + import tester._ val res = eval("scala.foo") assert(res.isSuccess == true) val output = out("scala.foo").text diff --git a/integration/feature/import-ivy-worker-invalidation/src/ImportIvyWorkerInvalidation.scala b/integration/feature/import-ivy-worker-invalidation/src/ImportIvyWorkerInvalidation.scala index 999015576c9..41c1ec01022 100644 --- a/integration/feature/import-ivy-worker-invalidation/src/ImportIvyWorkerInvalidation.scala +++ b/integration/feature/import-ivy-worker-invalidation/src/ImportIvyWorkerInvalidation.scala @@ -1,14 +1,14 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object ImportIvyWorkerInvalidation extends IntegrationTestSuite { +object ImportIvyWorkerInvalidation extends UtestIntegrationTestSuite { val tests: Tests = Tests { - test { - initWorkspace() + test - integrationTest { tester => + import tester._ assert(eval("app.compile").isSuccess) modifyFile( workspacePath / "build.mill", diff --git a/integration/feature/init/src/MillInitTests.scala b/integration/feature/init/src/MillInitTests.scala index c7558d05340..7305917fe21 100644 --- a/integration/feature/init/src/MillInitTests.scala +++ b/integration/feature/init/src/MillInitTests.scala @@ -1,13 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object MillInitTests extends IntegrationTestSuite { +object MillInitTests extends UtestIntegrationTestSuite { def tests: Tests = Tests { - test("Mill init works") { - initWorkspace() + test("Mill init works") - integrationTest { tester => + import tester._ eval(("init", "com-lihaoyi/mill-scala-hello.g8", "--name=example")).isSuccess ==> true val projFile = workspacePath / "example" / "build.sc" assert(os.exists(projFile)) diff --git a/integration/feature/large-project/src/LargeProjectTests.scala b/integration/feature/large-project/src/LargeProjectTests.scala index 7bc1585af7b..ad3bba0a3e1 100644 --- a/integration/feature/large-project/src/LargeProjectTests.scala +++ b/integration/feature/large-project/src/LargeProjectTests.scala @@ -1,13 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object LargeProjectTests extends IntegrationTestSuite { +object LargeProjectTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - test("test") - { + test("test") - integrationTest { tester => + import tester._ assert(eval("foo.common.one.compile").isSuccess) } diff --git a/integration/feature/mill-jvm-opts/src/MillJvmOptsTests.scala b/integration/feature/mill-jvm-opts/src/MillJvmOptsTests.scala index b3379e10eb4..4391a7d1322 100644 --- a/integration/feature/mill-jvm-opts/src/MillJvmOptsTests.scala +++ b/integration/feature/mill-jvm-opts/src/MillJvmOptsTests.scala @@ -1,13 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object MillJvmOptsTests extends IntegrationTestSuite { +object MillJvmOptsTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - test("JVM options from file .mill-jvm-opts are properly read") { + test("JVM options from file .mill-jvm-opts are properly read") - integrationTest { tester => + import tester._ assert(eval("checkJvmOpts").isSuccess) } } diff --git a/integration/feature/non-identifier-import/src/NonIdentifierImport.scala b/integration/feature/non-identifier-import/src/NonIdentifierImport.scala index 29fd1117160..daec95905ab 100644 --- a/integration/feature/non-identifier-import/src/NonIdentifierImport.scala +++ b/integration/feature/non-identifier-import/src/NonIdentifierImport.scala @@ -1,13 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object NonIdentifierImport extends IntegrationTestSuite { +object NonIdentifierImport extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - test("test") - { + test("test") - integrationTest { tester => + import tester._ assert(eval("foo-bar-module.compile").isSuccess) } } diff --git a/integration/feature/plugin-classpath/src/MillPluginClasspathTest.scala b/integration/feature/plugin-classpath/src/MillPluginClasspathTest.scala index c7062ff0a35..e6589c451a3 100644 --- a/integration/feature/plugin-classpath/src/MillPluginClasspathTest.scala +++ b/integration/feature/plugin-classpath/src/MillPluginClasspathTest.scala @@ -1,11 +1,10 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object MillPluginClasspathTest extends IntegrationTestSuite { - initWorkspace() +object MillPluginClasspathTest extends UtestIntegrationTestSuite { val embeddedModules: Seq[(String, String)] = Seq( ("com.lihaoyi", "mill-main-client"), @@ -31,37 +30,44 @@ object MillPluginClasspathTest extends IntegrationTestSuite { ) val tests: Tests = Tests { - test("exclusions") - { - val res1 = eval(("--meta-level", "1", "resolveDepsExclusions")) - assert(res1.isSuccess) - val exclusions = out("mill-build.resolveDepsExclusions").value[Seq[(String, String)]] - val expectedExclusions = embeddedModules + test("exclusions") - integrationTest { tester => + import tester._ + retry(3) { + val res1 = eval(("--meta-level", "1", "resolveDepsExclusions")) + assert(res1.isSuccess) - val diff = expectedExclusions.toSet.diff(exclusions.toSet) - assert(diff.isEmpty) + val exclusions = out("mill-build.resolveDepsExclusions").value[Seq[(String, String)]] + val expectedExclusions = embeddedModules + val diff = expectedExclusions.toSet.diff(exclusions.toSet) + assert(diff.isEmpty) + } } - test("runClasspath") - { - // We expect Mill core transitive dependencies to be filtered out - val res1 = eval(("--meta-level", "1", "runClasspath")) - assert(res1.isSuccess) + test("runClasspath") - integrationTest { tester => + import tester._ + retry(3) { + // We expect Mill core transitive dependencies to be filtered out + val res1 = eval(("--meta-level", "1", "runClasspath")) + assert(res1.isSuccess) - val runClasspath = out("mill-build.runClasspath").value[Seq[String]] + val runClasspath = out("mill-build.runClasspath").value[Seq[String]] - val unexpectedArtifacts = embeddedModules.map { - case (o, n) => s"${o.replaceAll("[.]", "/")}/${n}" - } + val unexpectedArtifacts = embeddedModules.map { + case (o, n) => s"${o.replaceAll("[.]", "/")}/${n}" + } - val unexpected = unexpectedArtifacts.flatMap { a => - runClasspath.find(p => p.toString.contains(a)).map((a, _)) - }.toMap - assert(unexpected.isEmpty) + val unexpected = unexpectedArtifacts.flatMap { a => + runClasspath.find(p => p.toString.contains(a)).map((a, _)) + }.toMap + assert(unexpected.isEmpty) - val expected = Seq("com/disneystreaming/smithy4s/smithy4s-mill-codegen-plugin_mill0.11_2.13") - assert(expected.forall(a => - runClasspath.exists(p => p.toString().replace('\\', '/').contains(a)) - )) + val expected = + Seq("com/disneystreaming/smithy4s/smithy4s-mill-codegen-plugin_mill0.11_2.13") + assert(expected.forall(a => + runClasspath.exists(p => p.toString().replace('\\', '/').contains(a)) + )) + } } } diff --git a/integration/feature/private-methods/src/PrivateMethodsTests.scala b/integration/feature/private-methods/src/PrivateMethodsTests.scala index 122e444bfed..51e1ff35374 100644 --- a/integration/feature/private-methods/src/PrivateMethodsTests.scala +++ b/integration/feature/private-methods/src/PrivateMethodsTests.scala @@ -1,13 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object PrivateMethodsTests extends IntegrationTestSuite { +object PrivateMethodsTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - test("simple") { + test("simple") - integrationTest { tester => + import tester._ // Simple public target depending on private target works val pub = eval(("show", "pub")) assert(pub.out == "\"priv\"") diff --git a/integration/feature/repo-config-via-import/src/ImportRepoTests.scala b/integration/feature/repo-config-via-import/src/ImportRepoTests.scala index 9a3d233a26c..99b89760b29 100644 --- a/integration/feature/repo-config-via-import/src/ImportRepoTests.scala +++ b/integration/feature/repo-config-via-import/src/ImportRepoTests.scala @@ -1,13 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object ImportRepoTests extends IntegrationTestSuite { +object ImportRepoTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - test("test") - { + test("test") - integrationTest { tester => + import tester._ // Make sure, we propery parse a line: // ``` // import $repo.`file:///tmp/testrepo` diff --git a/integration/feature/scoverage/src/ScoverageTests.scala b/integration/feature/scoverage/src/ScoverageTests.scala index 8b2497e0414..75c78521f9c 100644 --- a/integration/feature/scoverage/src/ScoverageTests.scala +++ b/integration/feature/scoverage/src/ScoverageTests.scala @@ -1,13 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object ScoverageTests extends IntegrationTestSuite { +object ScoverageTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - test("test") - { + test("test") - integrationTest { tester => + import tester._ assert(eval("__.compile").isSuccess) assert(eval("core[2.13.11].scoverage.xmlReport").isSuccess) } diff --git a/integration/feature/subprocess-stdout/src/SubprocessStdoutTests.scala b/integration/feature/subprocess-stdout/src/SubprocessStdoutTests.scala index cbe745ef2b2..bfdb7219ef4 100644 --- a/integration/feature/subprocess-stdout/src/SubprocessStdoutTests.scala +++ b/integration/feature/subprocess-stdout/src/SubprocessStdoutTests.scala @@ -1,14 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object SubprocessStdoutTests extends IntegrationTestSuite { +object SubprocessStdoutTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test { + test - integrationTest { tester => + import tester._ val res1 = eval("inheritInterleaved", mergeErrIntoOut = true).out // Make sure that when a lot of printed/inherited stdout/stderr is printed // in quick succession, the output ordering is preserved and it doesn't get @@ -62,7 +61,7 @@ object SubprocessStdoutTests extends IntegrationTestSuite { // up in the console somewhere and not disappear // val res2 = eval("inheritRaw", mergeErrIntoOut = true).out - if (!clientServerMode) { + if (!tester.clientServerMode) { // For `fork` tests, which represent `-i`/`--interactive`/`--no-server`, the output should // be properly ordered since it all comes directly from the stdout/stderr of the same process assert( diff --git a/integration/ide/bloop/src/BloopTests.scala b/integration/ide/bloop/src/BloopTests.scala index fe4e7afb5b6..6b342f93453 100644 --- a/integration/ide/bloop/src/BloopTests.scala +++ b/integration/ide/bloop/src/BloopTests.scala @@ -1,28 +1,34 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object BloopTests extends IntegrationTestSuite { - initWorkspace() - - val installResult: Boolean = eval("mill.contrib.bloop.Bloop/install").isSuccess +object BloopTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { test("test") - { - assert(installResult) - test("root module bloop config should be created") { + test("root module bloop config should be created") - integrationTest { tester => + import tester._ + val installResult: Boolean = eval("mill.contrib.bloop.Bloop/install").isSuccess + assert(installResult) assert(os.exists(workspacePath / ".bloop" / "root-module.json")) } - val millBuildJsonFile = workspacePath / ".bloop" / "mill-build-.json" - test("mill-build module bloop config should be created") { + test("mill-build module bloop config should be created") - integrationTest { tester => + import tester._ + val installResult: Boolean = eval("mill.contrib.bloop.Bloop/install").isSuccess + val millBuildJsonFile = workspacePath / ".bloop" / "mill-build-.json" + assert(installResult) assert(os.exists(millBuildJsonFile)) } - val config = ujson.read(os.read.stream(millBuildJsonFile)) - test("mill-build config should contain build.mill source") { + test("mill-build config should contain build.mill source") - integrationTest { tester => + import tester._ + val millBuildJsonFile = workspacePath / ".bloop" / "mill-build-.json" + val installResult: Boolean = eval("mill.contrib.bloop.Bloop/install").isSuccess + val config = ujson.read(os.read.stream(millBuildJsonFile)) + assert(installResult) assert(config("project")("sources").arr.exists(path => os.Path(path.str).last == "build.mill" )) diff --git a/integration/ide/bsp-install/src/BspInstallDebugTests.scala b/integration/ide/bsp-install/src/BspInstallDebugTests.scala index 543c2f6929d..2294dab3571 100644 --- a/integration/ide/bsp-install/src/BspInstallDebugTests.scala +++ b/integration/ide/bsp-install/src/BspInstallDebugTests.scala @@ -1,18 +1,18 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import mill.bsp.Constants import utest._ -object BspInstallDebugTests extends IntegrationTestSuite { +object BspInstallDebugTests extends UtestIntegrationTestSuite { val bsp4jVersion: String = sys.props.getOrElse("BSP4J_VERSION", ???) // we purposely enable debugging in this simulated test env override val debugLog: Boolean = true def tests: Tests = Tests { - test("BSP install forwards --debug option to server") { - initWorkspace() + test("BSP install forwards --debug option to server") - integrationTest { tester => + import tester._ eval("mill.bsp.BSP/install").isSuccess ==> true val jsonFile = workspacePath / Constants.bspDir / s"${Constants.serverName}.json" assert(os.exists(jsonFile)) diff --git a/integration/ide/bsp-install/src/BspInstallTests.scala b/integration/ide/bsp-install/src/BspInstallTests.scala index afeea1d53a1..40f9547da61 100644 --- a/integration/ide/bsp-install/src/BspInstallTests.scala +++ b/integration/ide/bsp-install/src/BspInstallTests.scala @@ -1,15 +1,15 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import mill.bsp.Constants import utest._ -object BspInstallTests extends IntegrationTestSuite { +object BspInstallTests extends UtestIntegrationTestSuite { val bsp4jVersion: String = sys.props.getOrElse("BSP4J_VERSION", ???) def tests: Tests = Tests { - test("BSP install") { - initWorkspace() + test("BSP install") - integrationTest { tester => + import tester._ assert(eval("mill.bsp.BSP/install").isSuccess) val jsonFile = workspacePath / Constants.bspDir / s"${Constants.serverName}.json" assert(os.exists(jsonFile)) diff --git a/integration/ide/bsp-modules/src/BspModulesTests.scala b/integration/ide/bsp-modules/src/BspModulesTests.scala index 8ffb3d10b28..cadc7e31e98 100644 --- a/integration/ide/bsp-modules/src/BspModulesTests.scala +++ b/integration/ide/bsp-modules/src/BspModulesTests.scala @@ -1,21 +1,21 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import mill.bsp.Constants import utest._ -object BspModulesTests extends IntegrationTestSuite { +object BspModulesTests extends UtestIntegrationTestSuite { val bsp4jVersion: String = sys.props.getOrElse("BSP4J_VERSION", ???) def tests: Tests = Tests { test("BSP module with foreign modules") { - test("can be installed") { - initWorkspace() + test("can be installed") - integrationTest { tester => + import tester._ assert(eval("mill.bsp.BSP/install").isSuccess) os.exists(workspacePath / Constants.bspDir / s"${Constants.serverName}.json") ==> true } - test("ModuleUtils resolves all referenced transitive modules") { - initWorkspace() + test("ModuleUtils resolves all referenced transitive modules") - integrationTest { tester => + import tester._ val res = eval("validate") assert(res.isSuccess) val file = workspacePath / "out" / "validate.dest" / "transitive-modules.json" diff --git a/integration/ide/gen-idea/src/GenIdeaExtendedTests.scala b/integration/ide/gen-idea/src/GenIdeaExtendedTests.scala index f60401bd313..ec4d78de0b3 100644 --- a/integration/ide/gen-idea/src/GenIdeaExtendedTests.scala +++ b/integration/ide/gen-idea/src/GenIdeaExtendedTests.scala @@ -1,18 +1,18 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ import scala.util.Try import os.Path -object GenIdeaExtendedTests extends IntegrationTestSuite { +object GenIdeaExtendedTests extends UtestIntegrationTestSuite { override def workspaceSourcePath: Path = super.workspaceSourcePath / "extended" def tests: Tests = Tests { - test("genIdeaTests") { - initWorkspace() + test("genIdeaTests") - integrationTest { tester => + import tester._ val expectedBase = workspacePath / "idea" val resources = os.walk(expectedBase).filter(os.isFile).map(_.subRelativeTo(expectedBase)) diff --git a/integration/ide/gen-idea/src/GenIdeaTests.scala b/integration/ide/gen-idea/src/GenIdeaTests.scala index 913b3903995..fa128c045ad 100644 --- a/integration/ide/gen-idea/src/GenIdeaTests.scala +++ b/integration/ide/gen-idea/src/GenIdeaTests.scala @@ -3,16 +3,16 @@ package mill.integration import utest.{Tests, assert, _} import scala.util.Try -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import GenIdeaUtils._ import os.Path -object GenIdeaTests extends IntegrationTestSuite { +object GenIdeaTests extends UtestIntegrationTestSuite { override def workspaceSourcePath: Path = super.workspaceSourcePath / "hello-idea" def tests: Tests = Tests { - test("helper assertPartialContentMatches works") { + test("helper assertPartialContentMatches works") - integrationTest { tester => val testContent = s"""line 1 |line 2 @@ -51,8 +51,8 @@ object GenIdeaTests extends IntegrationTestSuite { () } - test("genIdeaTests") { - initWorkspace() + test("genIdeaTests") - integrationTest { tester => + import tester._ val expectedBase = workspacePath / "idea" val resources = os.walk(expectedBase).filter(os.isFile).map(_.subRelativeTo(expectedBase)) diff --git a/integration/invalidation/codesig-hello/src/CodeSigHelloTests.scala b/integration/invalidation/codesig-hello/src/CodeSigHelloTests.scala index 25066443a7d..38ff50c4a79 100644 --- a/integration/invalidation/codesig-hello/src/CodeSigHelloTests.scala +++ b/integration/invalidation/codesig-hello/src/CodeSigHelloTests.scala @@ -1,13 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object CodeSigHelloTests extends IntegrationTestSuite { +object CodeSigHelloTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - test("simple") { + test("simple") - integrationTest { tester => + import tester._ // Make sure the simplest case where we have a single target calling a single helper // method is properly invalidated when either the target body, or the helper method's body // is changed, or something changed in the constructor diff --git a/integration/invalidation/codesig-nested/src/CodeSigNestedTests.scala b/integration/invalidation/codesig-nested/src/CodeSigNestedTests.scala index 04a72f94e7b..3e973af3cb8 100644 --- a/integration/invalidation/codesig-nested/src/CodeSigNestedTests.scala +++ b/integration/invalidation/codesig-nested/src/CodeSigNestedTests.scala @@ -1,14 +1,13 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object CodeSigNestedTests extends IntegrationTestSuite { +object CodeSigNestedTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - - test("nested") { + test("nested") - integrationTest { tester => + import tester._ // Make sure the code-change invalidation works in more complex cases: multi-step // target graphs, targets inside module objects, targets inside module traits @@ -190,7 +189,8 @@ object CodeSigNestedTests extends IntegrationTestSuite { assert(addedNewlinesInsideCurlies.out == "") } - test("trait") { + test("trait") - integrationTest { tester => + import tester._ val initial = eval("traitOuter.traitInner.inner") assert( initial.out.linesIterator.toSet == Set( diff --git a/integration/invalidation/codesig-scalamodule/src/CodeSigScalaModuleTests.scala b/integration/invalidation/codesig-scalamodule/src/CodeSigScalaModuleTests.scala index a14ef8d9603..05e8c68a3dd 100644 --- a/integration/invalidation/codesig-scalamodule/src/CodeSigScalaModuleTests.scala +++ b/integration/invalidation/codesig-scalamodule/src/CodeSigScalaModuleTests.scala @@ -1,16 +1,16 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ -object CodeSigScalaModuleTests extends IntegrationTestSuite { +object CodeSigScalaModuleTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { def filterLines(out: String) = { out.linesIterator.filter(!_.contains("[info]")).toSet } - initWorkspace() - test("single") { + test("single") - integrationTest { tester => + import tester._ // Tests for fine-grained method-based invalidation within a single ScalaModule // Check normal behavior for initial run and subsequent fully-cached run @@ -120,7 +120,8 @@ object CodeSigScalaModuleTests extends IntegrationTestSuite { ) } - test("multiple") { + test("multiple") - integrationTest { tester => + import tester._ // Tests for fine-grained method-based invalidation between multiple ScalaModules, // some related and some not diff --git a/integration/invalidation/invalidation/src/ScriptsInvalidationTests.scala b/integration/invalidation/invalidation/src/ScriptsInvalidationTests.scala index ee3d42890d0..895ec42b096 100644 --- a/integration/invalidation/invalidation/src/ScriptsInvalidationTests.scala +++ b/integration/invalidation/invalidation/src/ScriptsInvalidationTests.scala @@ -1,118 +1,108 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.{UtestIntegrationTestSuite, IntegrationTester} import utest._ -object ScriptsInvalidationTests extends IntegrationTestSuite { +object ScriptsInvalidationTests extends UtestIntegrationTestSuite { - def runTask(task: String): Set[String] = { - val res = eval(task) + def runTask(tester: IntegrationTester, task: String): Set[String] = { + val res = tester.eval(task) assert(res.isSuccess) res.out.linesIterator.map(_.trim).toSet } val tests: Tests = Tests { - test("should not invalidate tasks in different untouched sc files") { - test("first run") { - initWorkspace() - - val result = runTask("task") + test("should not invalidate tasks in different untouched sc files") - integrationTest { + tester => + import tester._ + // first run + val result = runTask(tester, "task") val expected = Set("a", "d", "b", "c") assert(result == expected) - } - test("second run modifying script") { + // second run modifying script modifyFile( workspacePath / "build.mill", _.replace("""println("task")""", """System.out.println("task2")""") ) - val stdout = runTask("task") + val stdout = runTask(tester, "task") assert(stdout.isEmpty) - } } - test("should invalidate tasks if leaf file is changed") { - test("first run") { - initWorkspace() - val result = runTask("task") - val expected = Set("a", "d", "b", "c") + test("should invalidate tasks if leaf file is changed") - integrationTest { tester => + import tester._ + // first run - assert(result == expected) - } + val result = runTask(tester, "task") + val expected = Set("a", "d", "b", "c") - test("second run modifying script") { - modifyFile( - workspacePath / "b" / "inputD.mill", - _.replace("""println("d")""", """System.out.println("d2")""") - ) + assert(result == expected) - val result = runTask("task") - val expected = Set("d2", "b") + // second run modifying script + modifyFile( + workspacePath / "b" / "inputD.mill", + _.replace("""println("d")""", """System.out.println("d2")""") + ) - assert(result == expected) - } - } - test("should handle submodules in scripts") { - test("first run") { - initWorkspace() + val result2 = runTask(tester, "task") + val expected2 = Set("d2", "b") - val result = runTask("module.task") - val expected = Set("a", "d", "b", "c", "task") + assert(result2 == expected2) - assert(result == expected) - } + } + test("should handle submodules in scripts") - integrationTest { tester => + import tester._ + // first run + val result = runTask(tester, "module.task") + val expected = Set("a", "d", "b", "c", "task") - test("second run modifying script") { - modifyFile( - workspacePath / "build.mill", - _.replace("""println("task")""", """System.out.println("task2")""") - ) + assert(result == expected) - val result = runTask("module.task") - val expected = Set("task2") + // second run modifying script + modifyFile( + workspacePath / "build.mill", + _.replace("""println("task")""", """System.out.println("task2")""") + ) - assert(result == expected) - } - } - test("should handle ammonite ^ imports") { - test("first run") { - initWorkspace() + val result2 = runTask(tester, "module.task") + val expected2 = Set("task2") - val result = runTask("taskE") + assert(result2 == expected2) + } + test("should handle ammonite ^ imports") - integrationTest { tester => + import tester._ + retry(3) { + // first run + val result = runTask(tester, "taskE") val expected = Set("a", "e", "taskE") assert(result == expected) - } - test("second run modifying script") { + // second run modifying script modifyFile( workspacePath / "build.mill", _.replace("""println("taskE")""", """System.out.println("taskE2")""") ) - val result = runTask("taskE") - val expected = Set("taskE2") + val result2 = runTask(tester, "taskE") + val expected2 = Set("taskE2") - assert(result == expected) + assert(result2 == expected2) } } - test("should handle ammonite paths with symbols") { - initWorkspace() - - val result = runTask("taskSymbols") + test("should handle ammonite paths with symbols") - integrationTest { tester => + val result = runTask(tester, "taskSymbols") val expected = Set("taskSymbols") assert(result == expected) } - test("should handle ammonite files with symbols") { - initWorkspace() - - val result = runTask("taskSymbolsInFile") + test("should handle ammonite files with symbols") - integrationTest { tester => + val result = runTask(tester, "taskSymbolsInFile") val expected = Set("taskSymbolsInFile") assert(result == expected) diff --git a/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala b/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala index 53c3628e0b3..954223c7068 100644 --- a/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala +++ b/integration/invalidation/multi-level-editing/src/MultiLevelBuildTests.scala @@ -1,6 +1,6 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.{UtestIntegrationTestSuite, IntegrationTester} import mill.main.client.OutFiles._ import mill.runner.RunnerState @@ -13,45 +13,44 @@ import scala.util.matching.Regex // that the proper messages are reported, proper build classloaders are // re-used or invalidated, and the proper files end up getting watched // in all cases. -object MultiLevelBuildTests extends IntegrationTestSuite { +object MultiLevelBuildTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - def runAssertSuccess(expected: String) = { - val res = eval("foo.run") + def runAssertSuccess(tester: IntegrationTester, expected: String) = { + val res = tester.eval("foo.run") assert(res.isSuccess == true) assert(res.out.contains(expected)) } - val fooPaths = Seq( - workspacePath / "foo" / "compile-resources", - workspacePath / "foo" / "resources", - workspacePath / "foo" / "src" + def fooPaths(tester: IntegrationTester) = Seq( + tester.workspacePath / "foo" / "compile-resources", + tester.workspacePath / "foo" / "resources", + tester.workspacePath / "foo" / "src" ) - val buildPaths = Seq( - workspacePath / "build.mill", - workspacePath / "mill-build" / "compile-resources", - workspacePath / "mill-build" / "resources", - workspacePath / "mill-build" / "src" + def buildPaths(tester: IntegrationTester) = Seq( + tester.workspacePath / "build.mill", + tester.workspacePath / "mill-build" / "compile-resources", + tester.workspacePath / "mill-build" / "resources", + tester.workspacePath / "mill-build" / "src" ) - val buildPaths2 = Seq( - workspacePath / "mill-build" / "build.mill", - workspacePath / "mill-build" / "mill-build" / "compile-resources", - workspacePath / "mill-build" / "mill-build" / "resources", - workspacePath / "mill-build" / "mill-build" / "src" + def buildPaths2(tester: IntegrationTester) = Seq( + tester.workspacePath / "mill-build" / "build.mill", + tester.workspacePath / "mill-build" / "mill-build" / "compile-resources", + tester.workspacePath / "mill-build" / "mill-build" / "resources", + tester.workspacePath / "mill-build" / "mill-build" / "src" ) - val buildPaths3 = Seq( - workspacePath / "mill-build" / "mill-build" / "build.mill", - workspacePath / "mill-build" / "mill-build" / "mill-build" / "compile-resources", - workspacePath / "mill-build" / "mill-build" / "mill-build" / "resources", - workspacePath / "mill-build" / "mill-build" / "mill-build" / "src" + def buildPaths3(tester: IntegrationTester) = Seq( + tester.workspacePath / "mill-build" / "mill-build" / "build.mill", + tester.workspacePath / "mill-build" / "mill-build" / "mill-build" / "compile-resources", + tester.workspacePath / "mill-build" / "mill-build" / "mill-build" / "resources", + tester.workspacePath / "mill-build" / "mill-build" / "mill-build" / "src" ) - def loadFrames(n: Int) = { + def loadFrames(tester: IntegrationTester, n: Int) = { for (depth <- Range(0, n)) yield { val path = - workspacePath / "out" / Seq.fill(depth)(millBuild) / millRunnerState + tester.workspacePath / "out" / Seq.fill(depth)(millBuild) / millRunnerState if (os.exists(path)) upickle.default.read[RunnerState.Frame.Logged](os.read(path)) -> path else RunnerState.Frame.Logged(Map(), Seq(), Seq(), None, Seq(), 0) -> path } @@ -61,12 +60,14 @@ object MultiLevelBuildTests extends IntegrationTestSuite { * Verify that each level of the multi-level build ends upcausing the * appropriate files to get watched */ - def checkWatchedFiles(expected0: Seq[os.Path]*) = { - for ((expectedWatched0, (frame, path)) <- expected0.zip(loadFrames(expected0.length))) { + def checkWatchedFiles(tester: IntegrationTester, expected0: Seq[os.Path]*) = { + for ( + (expectedWatched0, (frame, path)) <- expected0.zip(loadFrames(tester, expected0.length)) + ) { val frameWatched = frame .evalWatched .map(_.path) - .filter(_.startsWith(workspacePath)) + .filter(_.startsWith(tester.workspacePath)) .filter(!_.segments.contains("mill-launcher")) .sorted @@ -75,14 +76,14 @@ object MultiLevelBuildTests extends IntegrationTestSuite { } } - def evalCheckErr(expectedSnippets: String*) = { + def evalCheckErr(tester: IntegrationTester, expectedSnippets: String*) = { // Wipe out stale state files to make sure they don't get picked up when // Mill aborts early and fails to generate a new one - os.walk(workspacePath / "out").filter(_.last == "mill-runner-state.json").foreach( + os.walk(tester.workspacePath / "out").filter(_.last == "mill-runner-state.json").foreach( os.remove(_) ) - val res = eval("foo.run") + val res = tester.eval("foo.run") assert(res.isSuccess == false) // Prepend a "\n" to allow callsites to use "\n" to test for start of // line, even though the first line doesn't have a "\n" at the start @@ -100,9 +101,12 @@ object MultiLevelBuildTests extends IntegrationTestSuite { * the previous classloader was re-used, `null` means there is no * classloader at that level */ - def checkChangedClassloaders(expectedChanged0: java.lang.Boolean*) = { + def checkChangedClassloaders( + tester: IntegrationTester, + expectedChanged0: java.lang.Boolean* + ) = { val currentClassLoaderIds = - for ((frame, path) <- loadFrames(expectedChanged0.length)) + for ((frame, path) <- loadFrames(tester, expectedChanged0.length)) yield frame.classLoaderIdentity val changed = currentClassLoaderIds @@ -124,197 +128,273 @@ object MultiLevelBuildTests extends IntegrationTestSuite { savedClassLoaderIds = currentClassLoaderIds } - test("validEdits") { - runAssertSuccess("

hello

world

0.8.2

!") - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) + test("validEdits") - integrationTest { tester => + import tester._ + runAssertSuccess(tester, "

hello

world

0.8.2

!") + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) + ) // First run all classloaders are new, except level 0 running user code // which doesn't need generate a classloader which never changes - checkChangedClassloaders(null, true, true, true) + checkChangedClassloaders(tester, null, true, true, true) modifyFile(workspacePath / "foo" / "src" / "Example.scala", _.replace("!", "?")) - runAssertSuccess("

hello

world

0.8.2

?") - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) + runAssertSuccess(tester, "

hello

world

0.8.2

?") + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) + ) // Second run with no build changes, all classloaders are unchanged - checkChangedClassloaders(null, false, false, false) + checkChangedClassloaders(tester, null, false, false, false) modifyFile(workspacePath / "build.mill", _.replace("hello", "HELLO")) - runAssertSuccess("

HELLO

world

0.8.2

?") - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, true, false, false) + runAssertSuccess(tester, "

HELLO

world

0.8.2

?") + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) + ) + checkChangedClassloaders(tester, null, true, false, false) modifyFile( workspacePath / "mill-build" / "build.mill", _.replace("def scalatagsVersion = ", "def scalatagsVersion = \"changed-\" + ") ) - runAssertSuccess("

HELLO

world

changed-0.8.2

?") - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, true, true, false) + runAssertSuccess(tester, "

HELLO

world

changed-0.8.2

?") + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) + ) + checkChangedClassloaders(tester, null, true, true, false) modifyFile( workspacePath / "mill-build" / "mill-build" / "build.mill", _.replace("0.8.2", "0.12.0") ) - runAssertSuccess("

HELLO

world

changed-0.12.0

?") - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, true, true, true) + runAssertSuccess(tester, "

HELLO

world

changed-0.12.0

?") + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) + ) + checkChangedClassloaders(tester, null, true, true, true) modifyFile( workspacePath / "mill-build" / "mill-build" / "build.mill", _.replace("0.12.0", "0.8.2") ) - runAssertSuccess("

HELLO

world

changed-0.8.2

?") - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, true, true, true) + runAssertSuccess(tester, "

HELLO

world

changed-0.8.2

?") + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) + ) + checkChangedClassloaders(tester, null, true, true, true) modifyFile( workspacePath / "mill-build" / "build.mill", _.replace("def scalatagsVersion = \"changed-\" + ", "def scalatagsVersion = ") ) - runAssertSuccess("

HELLO

world

0.8.2

?") - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, true, true, false) + runAssertSuccess(tester, "

HELLO

world

0.8.2

?") + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) + ) + checkChangedClassloaders(tester, null, true, true, false) modifyFile(workspacePath / "build.mill", _.replace("HELLO", "hello")) - runAssertSuccess("

hello

world

0.8.2

?") - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, true, false, false) + runAssertSuccess(tester, "

hello

world

0.8.2

?") + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) + ) + checkChangedClassloaders(tester, null, true, false, false) modifyFile(workspacePath / "foo" / "src" / "Example.scala", _.replace("?", "!")) - runAssertSuccess("

hello

world

0.8.2

!") - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, false, false, false) + runAssertSuccess(tester, "

hello

world

0.8.2

!") + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) + ) + checkChangedClassloaders(tester, null, false, false, false) } - test("parseErrorEdits") { + test("parseErrorEdits") - integrationTest { tester => + import tester._ def causeParseError(p: os.Path) = modifyFile(p, _.replace("extends", "extendx")) def fixParseError(p: os.Path) = modifyFile(p, _.replace("extendx", "extends")) - runAssertSuccess("

hello

world

0.8.2

!") - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, true, true, true) + runAssertSuccess(tester, "

hello

world

0.8.2

!") + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) + ) + checkChangedClassloaders(tester, null, true, true, true) causeParseError(workspacePath / "build.mill") - evalCheckErr( - "\n1 targets failed", - "\ngenerateScriptSources build.mill" - ) - checkWatchedFiles(Nil, buildPaths, Nil, Nil) + evalCheckErr(tester, "\n1 targets failed", "\ngenerateScriptSources build.mill") + checkWatchedFiles(tester, Nil, buildPaths(tester), Nil, Nil) // When one of the meta-builds still has parse errors, all classloaders // remain null, because none of the meta-builds can evaluate. Only once // all of them parse successfully do we get a new set of classloaders for // every level of the meta-build - checkChangedClassloaders(null, null, null, null) + checkChangedClassloaders(tester, null, null, null, null) fixParseError(workspacePath / "build.mill") causeParseError(workspacePath / "mill-build" / "build.mill") - evalCheckErr( - "\n1 targets failed", - "\ngenerateScriptSources mill-build/build.mill" - ) - checkWatchedFiles(Nil, Nil, buildPaths2, Nil) - checkChangedClassloaders(null, null, null, null) + evalCheckErr(tester, "\n1 targets failed", "\ngenerateScriptSources mill-build/build.mill") + checkWatchedFiles(tester, Nil, Nil, buildPaths2(tester), Nil) + checkChangedClassloaders(tester, null, null, null, null) fixParseError(workspacePath / "mill-build" / "build.mill") causeParseError(workspacePath / "mill-build" / "mill-build" / "build.mill") evalCheckErr( + tester, "\n1 targets failed", "\ngenerateScriptSources mill-build/mill-build/build.mill" ) - checkWatchedFiles(Nil, Nil, Nil, buildPaths3) - checkChangedClassloaders(null, null, null, null) + checkWatchedFiles(tester, Nil, Nil, Nil, buildPaths3(tester)) + checkChangedClassloaders(tester, null, null, null, null) fixParseError(workspacePath / "mill-build" / "mill-build" / "build.mill") causeParseError(workspacePath / "mill-build" / "build.mill") - evalCheckErr( - "\n1 targets failed", - "\ngenerateScriptSources mill-build/build.mill" - ) - checkWatchedFiles(Nil, Nil, buildPaths2, Nil) - checkChangedClassloaders(null, null, null, null) + evalCheckErr(tester, "\n1 targets failed", "\ngenerateScriptSources mill-build/build.mill") + checkWatchedFiles(tester, Nil, Nil, buildPaths2(tester), Nil) + checkChangedClassloaders(tester, null, null, null, null) fixParseError(workspacePath / "mill-build" / "build.mill") causeParseError(workspacePath / "build.mill") - evalCheckErr( - "\n1 targets failed", - "\ngenerateScriptSources build.mill" - ) - checkWatchedFiles(Nil, buildPaths, Nil, Nil) - checkChangedClassloaders(null, null, null, null) + evalCheckErr(tester, "\n1 targets failed", "\ngenerateScriptSources build.mill") + checkWatchedFiles(tester, Nil, buildPaths(tester), Nil, Nil) + checkChangedClassloaders(tester, null, null, null, null) fixParseError(workspacePath / "build.mill") - runAssertSuccess("

hello

world

0.8.2

!") - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, true, true, true) + runAssertSuccess(tester, "

hello

world

0.8.2

!") + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) + ) + checkChangedClassloaders(tester, null, true, true, true) } - test("compileErrorEdits") { + test("compileErrorEdits") - integrationTest { tester => + import tester._ def causeCompileError(p: os.Path) = modifyFile(p, _ + "\nimport doesnt.exist") def fixCompileError(p: os.Path) = modifyFile(p, _.replace("import doesnt.exist", "")) - runAssertSuccess("

hello

world

0.8.2

!") - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, true, true, true) + runAssertSuccess(tester, "

hello

world

0.8.2

!") + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) + ) + checkChangedClassloaders(tester, null, true, true, true) causeCompileError(workspacePath / "build.mill") evalCheckErr( + tester, "\n1 targets failed", // Ensure the file path in the compile error is properly adjusted to point // at the original source file and not the generated file (workspacePath / "build.mill").toString, "not found: value doesnt" ) - checkWatchedFiles(Nil, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, null, false, false) + checkWatchedFiles(tester, Nil, buildPaths(tester), buildPaths2(tester), buildPaths3(tester)) + checkChangedClassloaders(tester, null, null, false, false) causeCompileError(workspacePath / "mill-build" / "build.mill") evalCheckErr( + tester, "\n1 targets failed", (workspacePath / "mill-build" / "build.mill").toString, "not found: object doesnt" ) - checkWatchedFiles(Nil, Nil, buildPaths2, buildPaths3) - checkChangedClassloaders(null, null, null, false) + checkWatchedFiles(tester, Nil, Nil, buildPaths2(tester), buildPaths3(tester)) + checkChangedClassloaders(tester, null, null, null, false) causeCompileError(workspacePath / "mill-build" / "mill-build" / "build.mill") evalCheckErr( + tester, "\n1 targets failed", (workspacePath / "mill-build" / "mill-build" / "build.mill").toString, "not found: object doesnt" ) - checkWatchedFiles(Nil, Nil, Nil, buildPaths3) - checkChangedClassloaders(null, null, null, null) + checkWatchedFiles(tester, Nil, Nil, Nil, buildPaths3(tester)) + checkChangedClassloaders(tester, null, null, null, null) fixCompileError(workspacePath / "mill-build" / "mill-build" / "build.mill") evalCheckErr( + tester, "\n1 targets failed", (workspacePath / "mill-build" / "build.mill").toString, "not found: object doesnt" ) - checkWatchedFiles(Nil, Nil, buildPaths2, buildPaths3) - checkChangedClassloaders(null, null, null, true) + checkWatchedFiles(tester, Nil, Nil, buildPaths2(tester), buildPaths3(tester)) + checkChangedClassloaders(tester, null, null, null, true) fixCompileError(workspacePath / "mill-build" / "build.mill") evalCheckErr( + tester, "\n1 targets failed", (workspacePath / "build.mill").toString, "not found: value doesnt" ) - checkWatchedFiles(Nil, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, null, true, false) + checkWatchedFiles(tester, Nil, buildPaths(tester), buildPaths2(tester), buildPaths3(tester)) + checkChangedClassloaders(tester, null, null, true, false) fixCompileError(workspacePath / "build.mill") - runAssertSuccess("

hello

world

0.8.2

!") - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, true, false, false) + runAssertSuccess(tester, "

hello

world

0.8.2

!") + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) + ) + checkChangedClassloaders(tester, null, true, false, false) } - test("runtimeErrorEdits") { + test("runtimeErrorEdits") - integrationTest { tester => + import tester._ val runErrorSnippet = """{ |override def runClasspath = T{ | throw new Exception("boom") @@ -327,58 +407,83 @@ object MultiLevelBuildTests extends IntegrationTestSuite { def fixRuntimeError(p: os.Path) = modifyFile(p, _.replaceFirst(Regex.quote(runErrorSnippet), "\\{")) - runAssertSuccess("

hello

world

0.8.2

!") - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, true, true, true) + runAssertSuccess(tester, "

hello

world

0.8.2

!") + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) + ) + checkChangedClassloaders(tester, null, true, true, true) causeRuntimeError(workspacePath / "build.mill") - evalCheckErr( - "\n1 targets failed", - "foo.runClasspath java.lang.Exception: boom" + evalCheckErr(tester, "\n1 targets failed", "foo.runClasspath java.lang.Exception: boom") + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) ) - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, true, false, false) + checkChangedClassloaders(tester, null, true, false, false) causeRuntimeError(workspacePath / "mill-build" / "build.mill") evalCheckErr( + tester, "\n1 targets failed", "build.mill", "runClasspath java.lang.Exception: boom" ) - checkWatchedFiles(Nil, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, null, true, false) + checkWatchedFiles(tester, Nil, buildPaths(tester), buildPaths2(tester), buildPaths3(tester)) + checkChangedClassloaders(tester, null, null, true, false) causeRuntimeError(workspacePath / "mill-build" / "mill-build" / "build.mill") evalCheckErr( + tester, "\n1 targets failed", "build.mill", "runClasspath java.lang.Exception: boom" ) - checkWatchedFiles(Nil, Nil, buildPaths2, buildPaths3) - checkChangedClassloaders(null, null, null, true) + checkWatchedFiles(tester, Nil, Nil, buildPaths2(tester), buildPaths3(tester)) + checkChangedClassloaders(tester, null, null, null, true) fixRuntimeError(workspacePath / "mill-build" / "mill-build" / "build.mill") evalCheckErr( + tester, "\n1 targets failed", "build.mill", "runClasspath java.lang.Exception: boom" ) - checkWatchedFiles(Nil, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, null, true, true) + checkWatchedFiles(tester, Nil, buildPaths(tester), buildPaths2(tester), buildPaths3(tester)) + checkChangedClassloaders(tester, null, null, true, true) fixRuntimeError(workspacePath / "mill-build" / "build.mill") evalCheckErr( + tester, "\n1 targets failed", "build.mill", "foo.runClasspath java.lang.Exception: boom" ) - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, true, true, false) + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) + ) + checkChangedClassloaders(tester, null, true, true, false) fixRuntimeError(workspacePath / "build.mill") - runAssertSuccess("

hello

world

0.8.2

!") - checkWatchedFiles(fooPaths, buildPaths, buildPaths2, buildPaths3) - checkChangedClassloaders(null, true, false, false) + runAssertSuccess(tester, "

hello

world

0.8.2

!") + checkWatchedFiles( + tester, + fooPaths(tester), + buildPaths(tester), + buildPaths2(tester), + buildPaths3(tester) + ) + checkChangedClassloaders(tester, null, true, false, false) } } diff --git a/integration/invalidation/watch-source-input/src/WatchSourceInputTests.scala b/integration/invalidation/watch-source-input/src/WatchSourceInputTests.scala index 6230a43a2fd..09a2205fb05 100644 --- a/integration/invalidation/watch-source-input/src/WatchSourceInputTests.scala +++ b/integration/invalidation/watch-source-input/src/WatchSourceInputTests.scala @@ -1,6 +1,6 @@ package mill.integration -import mill.testkit.{IntegrationTestSuite, IntegrationTester} +import mill.testkit.{UtestIntegrationTestSuite, IntegrationTester} import mill.main.client.Util import utest._ @@ -20,15 +20,13 @@ import scala.concurrent.ExecutionContext.Implicits.global * 4. `interp.watchValue` * 5. Implicitly watched files, like `build.mill` */ -object WatchSourceInputTests extends IntegrationTestSuite { +object WatchSourceInputTests extends UtestIntegrationTestSuite { val maxDuration = 60000 val tests: Tests = Tests { - initWorkspace() - - def awaitCompletionMarker(name: String) = { + def awaitCompletionMarker(tester: IntegrationTester, name: String) = { val maxTime = System.currentTimeMillis() + maxDuration - while (!os.exists(workspacePath / "out" / name)) { + while (!os.exists(tester.workspacePath / "out" / name)) { if (System.currentTimeMillis() > maxTime) { sys.error(s"awaitCompletionMarker($name) timed out") } @@ -63,14 +61,14 @@ object WatchSourceInputTests extends IntegrationTestSuite { if (show) assert(shows == expectedShows.map('"' + _ + '"')) } - def testWatchSource(show: Boolean) = + def testWatchSource(tester: IntegrationTester, show: Boolean) = testBase(show) { (expectedOut, expectedErr, expectedShows) => val showArgs = if (show) Seq("show") else Nil - + import tester._ val evalResult = Future { eval(("--watch", showArgs, "qux"), timeout = maxDuration) } - awaitCompletionMarker("initialized0") - awaitCompletionMarker("quxRan0") + awaitCompletionMarker(tester, "initialized0") + awaitCompletionMarker(tester, "quxRan0") expectedOut.append( "Setting up build.mill" ) @@ -83,7 +81,7 @@ object WatchSourceInputTests extends IntegrationTestSuite { ) os.write.over(workspacePath / "foo1.txt", "edited-foo1") - awaitCompletionMarker("quxRan1") + awaitCompletionMarker(tester, "quxRan1") expectedErr.append( "Running qux foo contents edited-foo1 initial-foo2", "Running qux bar contents initial-bar" @@ -93,7 +91,7 @@ object WatchSourceInputTests extends IntegrationTestSuite { ) os.write.over(workspacePath / "foo2.txt", "edited-foo2") - awaitCompletionMarker("quxRan2") + awaitCompletionMarker(tester, "quxRan2") expectedErr.append( "Running qux foo contents edited-foo1 edited-foo2", "Running qux bar contents initial-bar" @@ -103,7 +101,7 @@ object WatchSourceInputTests extends IntegrationTestSuite { ) os.write.over(workspacePath / "bar.txt", "edited-bar") - awaitCompletionMarker("quxRan3") + awaitCompletionMarker(tester, "quxRan3") expectedErr.append( "Running qux foo contents edited-foo1 edited-foo2", "Running qux bar contents edited-bar" @@ -113,7 +111,7 @@ object WatchSourceInputTests extends IntegrationTestSuite { ) os.write.append(workspacePath / "build.mill", "\ndef unrelated = true") - awaitCompletionMarker("initialized1") + awaitCompletionMarker(tester, "initialized1") expectedOut.append( "Setting up build.mill" // These targets do not re-evaluate, because the change to the build @@ -126,7 +124,7 @@ object WatchSourceInputTests extends IntegrationTestSuite { ) os.write.over(workspacePath / "watchValue.txt", "exit") - awaitCompletionMarker("initialized2") + awaitCompletionMarker(tester, "initialized2") expectedOut.append("Setting up build.mill") Await.result(evalResult, Duration.apply(maxDuration, SECONDS)) @@ -135,18 +133,30 @@ object WatchSourceInputTests extends IntegrationTestSuite { test("sources") { // Make sure we clean up the workspace between retries - test("noshow") - retry(3) { if (!Util.isWindows) { initWorkspace(); testWatchSource(false) } } - test("show") - retry(3) { if (!Util.isWindows) { initWorkspace(); testWatchSource(true) } } + test("noshow") - retry(3) { + integrationTest { tester => + if (!Util.isWindows) { + testWatchSource(tester, false) + } + } + } + test("show") - retry(3) { + integrationTest { tester => + if (!Util.isWindows) { + testWatchSource(tester, true) + } + } + } } - def testWatchInput(show: Boolean) = + def testWatchInput(tester: IntegrationTester, show: Boolean) = testBase(show) { (expectedOut, expectedErr, expectedShows) => val showArgs = if (show) Seq("show") else Nil - + import tester._ val evalResult = Future { eval(("--watch", showArgs, "lol"), timeout = maxDuration) } - awaitCompletionMarker("initialized0") - awaitCompletionMarker("lolRan0") + awaitCompletionMarker(tester, "initialized0") + awaitCompletionMarker(tester, "lolRan0") expectedOut.append( "Setting up build.mill" ) @@ -156,17 +166,17 @@ object WatchSourceInputTests extends IntegrationTestSuite { expectedShows.append("Running lol baz contents initial-baz") os.write.over(workspacePath / "baz.txt", "edited-baz") - awaitCompletionMarker("lolRan1") + awaitCompletionMarker(tester, "lolRan1") expectedErr.append("Running lol baz contents edited-baz") expectedShows.append("Running lol baz contents edited-baz") os.write.over(workspacePath / "watchValue.txt", "edited-watchValue") - awaitCompletionMarker("initialized1") + awaitCompletionMarker(tester, "initialized1") expectedOut.append("Setting up build.mill") expectedShows.append("Running lol baz contents edited-baz") os.write.over(workspacePath / "watchValue.txt", "exit") - awaitCompletionMarker("initialized2") + awaitCompletionMarker(tester, "initialized2") expectedOut.append("Setting up build.mill") Await.result(evalResult, Duration.apply(maxDuration, SECONDS)) @@ -175,8 +185,20 @@ object WatchSourceInputTests extends IntegrationTestSuite { test("input") { // Make sure we clean up the workspace between retries - test("noshow") - retry(3) { if (!Util.isWindows) { initWorkspace(); testWatchInput(false) } } - test("show") - retry(3) { if (!Util.isWindows) { initWorkspace(); testWatchInput(true) } } + test("noshow") - retry(3) { + integrationTest { tester => + if (!Util.isWindows) { + testWatchInput(tester, false) + } + } + } + test("show") - retry(3) { + integrationTest { tester => + if (!Util.isWindows) { + testWatchInput(tester, true) + } + } + } } } } diff --git a/integration/invalidation/zinc-incremental-compilation/src/ZincIncrementalCompilationTests.scala b/integration/invalidation/zinc-incremental-compilation/src/ZincIncrementalCompilationTests.scala index cf61225ff9f..a0f902721e2 100644 --- a/integration/invalidation/zinc-incremental-compilation/src/ZincIncrementalCompilationTests.scala +++ b/integration/invalidation/zinc-incremental-compilation/src/ZincIncrementalCompilationTests.scala @@ -1,15 +1,15 @@ package mill.integration -import mill.testkit.IntegrationTestSuite +import mill.testkit.UtestIntegrationTestSuite import utest._ // Regress test for issue https://github.com/com-lihaoyi/mill/issues/1901 -object ZincIncrementalCompilationTests extends IntegrationTestSuite { +object ZincIncrementalCompilationTests extends UtestIntegrationTestSuite { val tests: Tests = Tests { - initWorkspace() - test("incremental compilation only compiles changed files") { - val successful = eval("app.compile") + test("incremental compilation only compiles changed files") - integrationTest { tester => + import tester._ + val successful = tester.eval("app.compile") assert(successful.isSuccess) val appSrc = workspacePath / "app" / "src" / "main" / "scala" / "App.scala" @@ -25,7 +25,7 @@ object ZincIncrementalCompilationTests extends IntegrationTestSuite { println("** second run **") os.write.append(appSrc, "\n ") - val succ2nd = eval("app.compile") + val succ2nd = tester.eval("app.compile") assert(succ2nd.isSuccess) val appSrcInfo2 = os.stat(appSrc) diff --git a/main/api/src/mill/api/Result.scala b/main/api/src/mill/api/Result.scala index a06cd191c99..ad7af1e051b 100644 --- a/main/api/src/mill/api/Result.scala +++ b/main/api/src/mill/api/Result.scala @@ -74,8 +74,10 @@ object Result { */ case class Failure[T](msg: String, value: Option[T] = None) extends Failing[T] { def map[V](f: T => V): Failure[V] = Result.Failure(msg, value.map(f(_))) - def flatMap[V](f: T => Result[V]): Failure[V] = + def flatMap[V](f: T => Result[V]): Failure[V] = { Failure(msg, value.flatMap(f(_).asSuccess.map(_.value))) + } + override def toString: String = s"Failure($msg, $value)" } /** diff --git a/main/client/src/mill/main/client/CodeGenConstants.java b/main/client/src/mill/main/client/CodeGenConstants.java index 1245cfc75ff..71136e2d1dd 100644 --- a/main/client/src/mill/main/client/CodeGenConstants.java +++ b/main/client/src/mill/main/client/CodeGenConstants.java @@ -21,17 +21,17 @@ public class CodeGenConstants { /** * The name of the root build file */ - final public static String[] rootBuildFileNames = {"build.mill", "build.sc"}; + final public static String[] rootBuildFileNames = {"build.mill", "build.mill.sc", "build.sc"}; /** * The name of any sub-folder build files */ - final public static String[] nestedBuildFileNames = {"package.mill", "package.sc"}; + final public static String[] nestedBuildFileNames = {"package.mill", "package.mill.sc", "package.sc"}; /** * The extensions used by build files */ - final public static String[] buildFileExtensions = {"mill", "sc"}; + final public static String[] buildFileExtensions = {"mill", "mill.sc", "sc"}; /** * The user-facing name for the root of the module tree. diff --git a/main/client/test/src/mill/main/client/FileToStreamTailerTest.java b/main/client/test/src/mill/main/client/FileToStreamTailerTest.java index bb960cafc4a..0c68b5e12fe 100644 --- a/main/client/test/src/mill/main/client/FileToStreamTailerTest.java +++ b/main/client/test/src/mill/main/client/FileToStreamTailerTest.java @@ -99,12 +99,12 @@ public FileToStreamTailerTest() { final FileToStreamTailer tailer = new FileToStreamTailer(file, ps, 10); ) { tailer.start(); - Thread.sleep(100); + Thread.sleep(500); expectEquals(bas.toString(), ""); out.println("log line"); expectTrue(file.exists()); - Thread.sleep(100); - expectEquals(bas.toString(), "log line" + System.lineSeparator()); + Thread.sleep(500); + expectEquals(bas.toString().trim(), "log line"); } } }); diff --git a/main/server/test/src/mill/main/server/ClientServerTests.scala b/main/server/test/src/mill/main/server/ClientServerTests.scala index d9b14286f5c..e6a0a090696 100644 --- a/main/server/test/src/mill/main/server/ClientServerTests.scala +++ b/main/server/test/src/mill/main/server/ClientServerTests.scala @@ -121,9 +121,9 @@ object ClientServerTests extends TestSuite { } def tests = Tests { - val tester = new Tester - test("hello") - retry(3) { + test("hello") - retry(3) { + val tester = new Tester val res1 = tester(args = Array("world")) assert( @@ -163,6 +163,7 @@ object ClientServerTests extends TestSuite { } test("concurrency") { + val tester = new Tester // Make sure concurrently running client commands results in multiple processes // being spawned, running in different folders import concurrent._ @@ -187,6 +188,7 @@ object ClientServerTests extends TestSuite { } test("clientLockReleasedOnFailure") { + val tester = new Tester // When the client gets interrupted via Ctrl-C, we exit the server immediately. This // is because Mill ends up executing arbitrary JVM code, and there is no generic way // to interrupt such an execution. The two options are to leave the server running @@ -212,6 +214,7 @@ object ClientServerTests extends TestSuite { } test("envVars") - retry(3) { + val tester = new Tester // Make sure the simple "have the client start a server and // exchange one message" workflow works from end to end. diff --git a/main/util/src/mill/util/CoursierSupport.scala b/main/util/src/mill/util/CoursierSupport.scala index 2fa9c7783e3..9fa405f0282 100644 --- a/main/util/src/mill/util/CoursierSupport.scala +++ b/main/util/src/mill/util/CoursierSupport.scala @@ -38,8 +38,12 @@ trait CoursierSupport { )(f: () => T): T = { val tried = Try(f()) tried match { - case Failure(e: NoSuchFileException) - if retryCount > 0 && e.getMessage.contains("__sha1.computed") => + case Failure(e) + if retryCount > 0 + && e.getMessage.contains("__sha1.computed") + && (e.isInstanceOf[NoSuchFileException] || e.isInstanceOf[ + java.nio.file.AccessDeniedException + ]) => // this one is not detected by coursier itself, so we try-catch handle it // I assume, this happens when another coursier thread already moved or rename dthe temporary file ctx.foreach(_.log.debug( diff --git a/mill-build/src/ExampleParser.scala b/mill-build/src/ExampleParser.scala index 55db14aa90a..39988ee2a86 100644 --- a/mill-build/src/ExampleParser.scala +++ b/mill-build/src/ExampleParser.scala @@ -6,7 +6,7 @@ object ExampleParser { val states = collection.mutable.Buffer("scala") val chunks = collection.mutable.Buffer(collection.mutable.Buffer.empty[String]) - val rootBuildFileNames = Seq("build.sc", "build.mill") + val rootBuildFileNames = Seq("build.sc", "build.mill", "build.mill.sc") val buildFile = rootBuildFileNames.map(testRepoRoot / _).find(os.exists) for (line <- os.read.lines(buildFile.get)) { val (newState, restOpt) = line match { diff --git a/runner/linenumbers/src/mill/linenumbers/LineNumberPlugin.scala b/runner/linenumbers/src/mill/linenumbers/LineNumberPlugin.scala index 591023f796c..b8f0aeee877 100644 --- a/runner/linenumbers/src/mill/linenumbers/LineNumberPlugin.scala +++ b/runner/linenumbers/src/mill/linenumbers/LineNumberPlugin.scala @@ -30,7 +30,7 @@ class LineNumberPlugin(val global: Global) extends Plugin { object LineNumberPlugin { def apply(g: Global)(unit: g.CompilationUnit): Unit = { - if (buildFileExtensions.exists(g.currentSource.file.hasExtension(_))) { + if (buildFileExtensions.exists(ex => g.currentSource.file.name.endsWith(s".$ex"))) { val str = new String(g.currentSource.content) val lines = str.linesWithSeparators.toVector diff --git a/runner/src/mill/runner/CodeGen.scala b/runner/src/mill/runner/CodeGen.scala index 3e8c64c4fe5..dbe14739c82 100644 --- a/runner/src/mill/runner/CodeGen.scala +++ b/runner/src/mill/runner/CodeGen.scala @@ -18,18 +18,17 @@ object CodeGen { millTopLevelProjectRoot: os.Path ): Unit = { for (scriptSource <- scriptSources) { - // pprint.log(scriptSource) val scriptPath = scriptSource.path val specialNames = (nestedBuildFileNames ++ rootBuildFileNames).toSet val isBuildScript = specialNames(scriptPath.last) val scriptFolderPath = scriptPath / os.up - if (scriptFolderPath == projectRoot && scriptPath.baseName == "package") { + if (scriptFolderPath == projectRoot && scriptPath.last.split('.').head == "package") { throw Result.Failure(s"Mill ${scriptPath.last} files can only be in subfolders") } - if (scriptFolderPath != projectRoot && scriptPath.baseName == "build") { + if (scriptFolderPath != projectRoot && scriptPath.last.split('.').head == "build") { throw Result.Failure(s"Mill ${scriptPath.last} files can only be in the project root") } @@ -86,7 +85,7 @@ object CodeGen { if (!isBuildScript) { s"""$pkgLine |$aliasImports - |object ${backtickWrap(scriptPath.baseName)} { + |object ${backtickWrap(scriptPath.last.split('.').head)} { |$markerComment |$scriptCode |}""".stripMargin @@ -105,7 +104,7 @@ object CodeGen { ) } - os.write(dest, parts, createFolders = true) + os.write.over(dest, parts, createFolders = true) } } diff --git a/runner/src/mill/runner/FileImportGraph.scala b/runner/src/mill/runner/FileImportGraph.scala index 89199a69f3b..fae30b35174 100644 --- a/runner/src/mill/runner/FileImportGraph.scala +++ b/runner/src/mill/runner/FileImportGraph.scala @@ -51,7 +51,6 @@ object FileImportGraph { var millImport = false def processScript(s: os.Path, useDummy: Boolean = false): Unit = { - val readFileEither = scala.util.Try { val content = if (useDummy) "" else os.read(s) val fileName = s.relativeTo(topLevelProjectRoot).toString @@ -67,7 +66,7 @@ object FileImportGraph { val expectedImportSegments = expectedImportSegments0.map(backtickWrap).mkString(".") if ( // Legacy `.sc` files have their package build be optional - s.ext == "mill" && + (s.last.endsWith(".mill") || s.last.endsWith(".mill.sc")) && expectedImportSegments != importSegments && // Root build.mill file has its `package build` be optional !(importSegments == "" && rootBuildFileNames.contains(s.last)) @@ -137,7 +136,7 @@ object FileImportGraph { case ImportTree(Seq(("$file", end0), rest @ _*), mapping, start, end) => // Only recursively explore imports from legacy `.sc` files, as new `.mill` files // do file discovery via scanning folders containing `package.mill` files - if (s.ext == "sc") { + if (s.last.endsWith(".sc") && !s.last.endsWith(".mill.sc")) { val nextPaths = mapping.map { case (lhs, rhs) => nextPathFor(s, rest.map(_._1) :+ lhs) } @@ -167,8 +166,10 @@ object FileImportGraph { val useDummy = rootBuildFiles.isEmpty val foundRootBuildFileName: String = rootBuildFiles.getOrElse(rootBuildFileNames.head) - val buildFileExtension = buildFileExtensions.find(foundRootBuildFileName.endsWith).get - val nestedBuildFileName = nestedBuildFileNames.find(_.endsWith(buildFileExtension)).get + val buildFileExtension = + buildFileExtensions.find(ex => foundRootBuildFileName.endsWith(s".$ex")).get + + val nestedBuildFileName = s"package.$buildFileExtension" processScript(projectRoot / foundRootBuildFileName, useDummy) val buildFiles = os @@ -184,7 +185,7 @@ object FileImportGraph { val adjacentScripts = (projectRoot +: buildFiles.map(_ / os.up)) .flatMap(os.list(_)) - .filter(_.ext == buildFileExtension) + .filter(_.last.endsWith(s".$buildFileExtension")) (buildFiles ++ adjacentScripts).foreach(processScript(_)) diff --git a/scalalib/src/mill/scalalib/JavaModule.scala b/scalalib/src/mill/scalalib/JavaModule.scala index 98fdc303a40..508793a2664 100644 --- a/scalalib/src/mill/scalalib/JavaModule.scala +++ b/scalalib/src/mill/scalalib/JavaModule.scala @@ -533,7 +533,13 @@ trait JavaModule * Resolved dependencies based on [[transitiveIvyDeps]] and [[transitiveCompileIvyDeps]]. */ def resolvedIvyDeps: T[Agg[PathRef]] = T { - defaultResolver().resolveDeps(transitiveCompileIvyDeps() ++ transitiveIvyDeps()) + def resolvedIvyDeps0() = + defaultResolver().resolveDeps(transitiveCompileIvyDeps() ++ transitiveIvyDeps()) + try resolvedIvyDeps0() + catch { + case e: java.nio.file.AccessDeniedException => + resolvedIvyDeps0() // this is caused by a coursier race condition on windows, just retry + } } /** diff --git a/scalalib/src/mill/scalalib/Lib.scala b/scalalib/src/mill/scalalib/Lib.scala index 556f138a01d..664cf7f52be 100644 --- a/scalalib/src/mill/scalalib/Lib.scala +++ b/scalalib/src/mill/scalalib/Lib.scala @@ -132,7 +132,9 @@ object Lib { root <- sources if os.exists(root.path) path <- (if (os.isDir(root.path)) os.walk(root.path) else Seq(root.path)) - if os.isFile(path) && (extensions.exists(path.ext == _) && !isHiddenFile(path)) + if os.isFile(path) && (extensions.exists(ex => path.last.endsWith(s".$ex")) && !isHiddenFile( + path + )) } yield path } diff --git a/scalalib/src/mill/scalalib/scalafmt/ScalafmtModule.scala b/scalalib/src/mill/scalalib/scalafmt/ScalafmtModule.scala index f10a0595bc6..f28a17624ea 100644 --- a/scalalib/src/mill/scalalib/scalafmt/ScalafmtModule.scala +++ b/scalalib/src/mill/scalalib/scalafmt/ScalafmtModule.scala @@ -57,7 +57,9 @@ trait ScalafmtModule extends JavaModule { file <- { if (os.isDir(pathRef.path)) { os.walk(pathRef.path).filter(file => - os.isFile(file) && (file.ext == "scala" || buildFileExtensions.contains(file.ext)) + os.isFile(file) && (file.ext == "scala" || buildFileExtensions.exists(ex => + file.last.endsWith(s".$ex") + )) ) } else { Seq(pathRef.path) diff --git a/testkit/src/mill/testkit/ExampleTestSuite.scala b/testkit/src/mill/testkit/ExampleTestSuite.scala deleted file mode 100644 index 7d15b65d553..00000000000 --- a/testkit/src/mill/testkit/ExampleTestSuite.scala +++ /dev/null @@ -1,11 +0,0 @@ -package mill.testkit -import utest._ - -object ExampleTestSuite extends IntegrationTestSuiteBase { - val tests: Tests = Tests { - - test("exampleTest") { - new ExampleTester(clientServerMode, workspaceSourcePath, millExecutable).run() - } - } -} diff --git a/testkit/src/mill/testkit/IntegrationTestSuite.scala b/testkit/src/mill/testkit/IntegrationTestSuite.scala index 9ad34228288..e488a51542f 100644 --- a/testkit/src/mill/testkit/IntegrationTestSuite.scala +++ b/testkit/src/mill/testkit/IntegrationTestSuite.scala @@ -1,7 +1,8 @@ package mill.testkit -abstract class IntegrationTestSuite extends IntegrationTestSuiteBase with IntegrationTester.Impl { - override def utestAfterEach(path: Seq[String]): Unit = { - if (clientServerMode) close() - } +abstract class UtestIntegrationTestSuite extends utest.TestSuite with IntegrationTestSuite { + protected def workspaceSourcePath: os.Path = os.Path(sys.env("MILL_TEST_RESOURCE_FOLDER")) + protected def clientServerMode: Boolean = sys.env("MILL_INTEGRATION_SERVER_MODE").toBoolean + protected def millExecutable: os.Path = + os.Path(System.getenv("MILL_INTEGRATION_LAUNCHER"), os.pwd) } diff --git a/testkit/src/mill/testkit/IntegrationTestSuiteBase.scala b/testkit/src/mill/testkit/IntegrationTestSuiteBase.scala index b3a06993be1..24abc745b62 100644 --- a/testkit/src/mill/testkit/IntegrationTestSuiteBase.scala +++ b/testkit/src/mill/testkit/IntegrationTestSuiteBase.scala @@ -1,11 +1,18 @@ package mill.testkit import os.Path -import utest._ -abstract class IntegrationTestSuiteBase extends TestSuite { - def workspaceSourcePath: os.Path = os.Path(sys.env("MILL_TEST_RESOURCE_FOLDER")) - val clientServerMode: Boolean = sys.env("MILL_INTEGRATION_SERVER_MODE").toBoolean +trait IntegrationTestSuite { + protected def workspaceSourcePath: os.Path + protected def clientServerMode: Boolean - def millExecutable: Path = os.Path(System.getenv("MILL_INTEGRATION_LAUNCHER"), os.pwd) + protected def millExecutable: Path + + def debugLog: Boolean = false + def integrationTest[T](t: IntegrationTester => T): T = { + val tester = + new IntegrationTester(clientServerMode, workspaceSourcePath, millExecutable, debugLog) + try t(tester) + finally tester.close() + } } diff --git a/testkit/src/mill/testkit/IntegrationTester.scala b/testkit/src/mill/testkit/IntegrationTester.scala index d6bece57248..9ddc8350f88 100644 --- a/testkit/src/mill/testkit/IntegrationTester.scala +++ b/testkit/src/mill/testkit/IntegrationTester.scala @@ -23,7 +23,8 @@ import scala.util.control.NonFatal class IntegrationTester( val clientServerMode: Boolean, val workspaceSourcePath: os.Path, - val millExecutable: os.Path + val millExecutable: os.Path, + override val debugLog: Boolean = false ) extends IntegrationTester.Impl { initWorkspace() } diff --git a/testkit/src/mill/testkit/IntegrationTesterBase.scala b/testkit/src/mill/testkit/IntegrationTesterBase.scala index a67f5a7b27d..523fc2728a9 100644 --- a/testkit/src/mill/testkit/IntegrationTesterBase.scala +++ b/testkit/src/mill/testkit/IntegrationTesterBase.scala @@ -9,15 +9,17 @@ trait IntegrationTesterBase { * Mill build being tested. Contains the `build.mill` file, any application code, and * the `out/` folder containing the build output * - * Typically just `pwd`, which is a sandbox directory for test suites run using Mill. + * Typically a temp folder inside `pwd`, just in case there's some leftover + * files/processes from previous integration tests that may interfere with the current one */ - val workspacePath: os.Path = os.pwd + val workspacePath: os.Path = os.temp.dir(dir = os.pwd) /** * Initializes the workspace in preparation for integration testing */ def initWorkspace(): Unit = { println(s"Copying integration test sources from $workspaceSourcePath to $workspacePath") + os.makeDir.all(workspacePath) os.list(workspacePath).foreach(os.remove.all(_)) os.list(workspaceSourcePath).filter(_.last != out).foreach(os.copy.into(_, workspacePath)) os.remove.all(workspacePath / "out") diff --git a/testkit/src/mill/testkit/UtestExampleTestSuite.scala b/testkit/src/mill/testkit/UtestExampleTestSuite.scala new file mode 100644 index 00000000000..994a4995a04 --- /dev/null +++ b/testkit/src/mill/testkit/UtestExampleTestSuite.scala @@ -0,0 +1,15 @@ +package mill.testkit +import utest._ + +object UtestExampleTestSuite extends TestSuite { + val workspaceSourcePath: os.Path = os.Path(sys.env("MILL_TEST_RESOURCE_FOLDER")) + val clientServerMode: Boolean = sys.env("MILL_INTEGRATION_SERVER_MODE").toBoolean + + val millExecutable: os.Path = os.Path(System.getenv("MILL_INTEGRATION_LAUNCHER"), os.pwd) + val tests: Tests = Tests { + + test("exampleTest") { + new ExampleTester(clientServerMode, workspaceSourcePath, millExecutable).run() + } + } +} diff --git a/testkit/test/src/mill/testkit/IntegrationTesterTests.scala b/testkit/test/src/mill/testkit/IntegrationTesterTests.scala index 13ed31e1a3e..9172a036427 100644 --- a/testkit/test/src/mill/testkit/IntegrationTesterTests.scala +++ b/testkit/test/src/mill/testkit/IntegrationTesterTests.scala @@ -2,28 +2,27 @@ package mill.testkit import utest._ -object IntegrationTesterTests extends TestSuite { - +object IntegrationTesterTests extends TestSuite with IntegrationTestSuite { + def clientServerMode = true + def workspaceSourcePath = + os.Path(sys.env("MILL_TEST_RESOURCE_FOLDER")) / "integration-test-example-project" + def millExecutable = os.Path(sys.env("MILL_EXECUTABLE_PATH")) def tests: Tests = Tests { test("integration") { - val tester = new IntegrationTester( - clientServerMode = true, - workspaceSourcePath = - os.Path(sys.env("MILL_TEST_RESOURCE_FOLDER")) / "integration-test-example-project", - millExecutable = os.Path(sys.env("MILL_EXECUTABLE_PATH")) - ) + integrationTest { tester => + val res1 = tester.eval("testTask") + assert(res1.isSuccess) + assert(res1.err.contains("compiling 1 Scala source")) // compiling the `build.mill` + assert(tester.out("testTask").value[String] == "HELLO WORLD SOURCE FILE") - val res1 = tester.eval("testTask") - assert(res1.isSuccess) - assert(res1.err.contains("compiling 1 Scala source")) // compiling the `build.mill` - assert(tester.out("testTask").value[String] == "HELLO WORLD SOURCE FILE") + tester.modifyFile(tester.workspacePath / "source-file.txt", _ + "!!!") - tester.modifyFile(tester.workspacePath / "source-file.txt", _ + "!!!") + val res2 = tester.eval("testTask") + assert(!res2.err.contains("compiling 1 Scala source")) // no need to re-compile `build.mill` + assert(tester.out("testTask").value[String] == "HELLO WORLD SOURCE FILE!!!") + } - val res2 = tester.eval("testTask") - assert(!res2.err.contains("compiling 1 Scala source")) // no need to re-compile `build.mill` - assert(tester.out("testTask").value[String] == "HELLO WORLD SOURCE FILE!!!") } } }