diff --git a/.config/mill-version b/.config/mill-version index 2ba084d296a..274afb051be 100644 --- a/.config/mill-version +++ b/.config/mill-version @@ -1 +1 @@ -0.12.5-68-e4bf78 \ No newline at end of file +0.12.5-68-e4bf78-native \ No newline at end of file diff --git a/.github/actions/post-build-setup/action.yml b/.github/actions/post-build-setup/action.yml index 772c5e2411b..d449020d496 100644 --- a/.github/actions/post-build-setup/action.yml +++ b/.github/actions/post-build-setup/action.yml @@ -14,10 +14,8 @@ inputs: runs: using: "composite" steps: - - uses: actions/setup-java@v4 - with: - java-version: ${{ inputs.java-version }} - distribution: temurin + - run: echo temurin:${{ inputs.java-version }} > .mill-jvm-version + shell: bash # Need to fix cached artifact file permissions because github actions screws it up # https://github.com/actions/upload-artifact/issues/38 diff --git a/.github/workflows/pre-build.yml b/.github/workflows/pre-build.yml index cd5529c9151..ba41e55506e 100644 --- a/.github/workflows/pre-build.yml +++ b/.github/workflows/pre-build.yml @@ -30,11 +30,15 @@ jobs: with: ref: ${{ github.base_ref }} + - run: echo temurin:${{ inputs.java-version }} > .mill-jvm-version + - run: chmod -R 777 . # normalize permissions before and after upload/download-artifact - run: mkdir out && touch out/mill-selective-execution.json shell: bash + - run: cat .mill-jvm-version + - run: ./mill -i -k selective.prepare ${{ inputs.prepareargs }} if: ${{ github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'run-all-tests') }} diff --git a/.github/workflows/publish-artifacts.yml b/.github/workflows/publish-artifacts.yml index 9a9b259c632..07452b5516a 100644 --- a/.github/workflows/publish-artifacts.yml +++ b/.github/workflows/publish-artifacts.yml @@ -33,10 +33,7 @@ jobs: - uses: coursier/cache-action@v6 - - uses: actions/setup-java@v4 - with: - java-version: '11' - distribution: temurin + - run: "echo temurin:11 > .mill-jvm-version" - run: ./mill -i __.publishArtifacts @@ -81,10 +78,7 @@ jobs: - uses: coursier/cache-action@v6 - - uses: actions/setup-java@v4 - with: - java-version: '11' - distribution: temurin + - run: "echo temurin:11 > .mill-jvm-version" - run: ./mill -i mill.scalalib.PublishModule/ @@ -119,10 +113,7 @@ jobs: - uses: actions/checkout@v4 with: { fetch-depth: 0 } - - uses: actions/setup-java@v4 - with: - java-version: '11' - distribution: temurin + - run: "echo temurin:11 > .mill-jvm-version" - run: ./mill -i mill.scalalib.PublishModule/ --publishArtifacts dist.native.publishArtifacts @@ -151,9 +142,6 @@ jobs: - uses: coursier/cache-action@v6 - - uses: actions/setup-java@v4 - with: - java-version: '11' - distribution: temurin + - run: "echo temurin:11 > .mill-jvm-version" - run: ./mill -i dist.uploadToGithub --authKey $REPO_ACCESS_TOKEN diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml index 1d37f8c7ccc..ffdb1a6729f 100644 --- a/.github/workflows/publish-docs.yml +++ b/.github/workflows/publish-docs.yml @@ -27,9 +27,6 @@ jobs: - uses: coursier/cache-action@v6 - - uses: actions/setup-java@v4 - with: - java-version: '11' - distribution: temurin + - run: "echo temurin:11 > .mill-jvm-version" - run: ci/publish-docs.sh diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 4fce9edc28b..42b68178486 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -1,4 +1,6 @@ # Uncommment this to replace the rest of the file when you want to debug stuff in CI + +# #name: Run Debug # #on: @@ -7,21 +9,18 @@ # workflow_dispatch: # #jobs: -# debug: +# debug-windows: ## runs-on: ubuntu-latest # runs-on: windows-latest # steps: # - uses: actions/checkout@v4 # with: { fetch-depth: 1 } -# - uses: actions/setup-java@v4 -# with: -# distribution: 'temurin' -# java-version: '17' # -# - run: ./mill 'example.scalalib.publishing[7-native-image].packaged.server.test' +# - run: ./mill 'example.scalalib.basic[1-simple].packaged.fork.test' # env: # COURSIER_ARCHIVE_CACHE: "C:/coursier-arc" + name: Run Tests # We run full CI on push builds to main and on all pull requests @@ -71,10 +70,7 @@ jobs: - uses: actions/checkout@v4 with: { fetch-depth: 0 } - - uses: actions/setup-java@v4 - with: - distribution: 'temurin' - java-version: '17' + - run: "echo temurin:17 > .mill-jvm-version" - run: ./mill -i example.javalib.basic.__.local.server.test @@ -139,7 +135,7 @@ jobs: # Most of these integration tests should not depend on which mode they # are run in, so just run them in `local` - java-version: '17' - millargs: "'integration.{failure,feature,ide}.__.native.server.test'" + millargs: "'integration.{failure,feature,ide}.__.packaged.server.test'" install-android-sdk: false # These invalidation tests need to be exercised in both execution modes # to make sure they work with and without -i/--no-server being passed @@ -174,7 +170,7 @@ jobs: - java-version: 17 millargs: "'integration.{feature,failure}.__.packaged.fork.test'" - - java-version: 11 + - java-version: 11 # Run this with Mill native launcher as a smoketest millargs: "'integration.invalidation.__.packaged.server.test'" - java-version: 11 diff --git a/.mill-jvm-version b/.mill-jvm-version new file mode 100644 index 00000000000..240aeffce9f --- /dev/null +++ b/.mill-jvm-version @@ -0,0 +1 @@ +temurin:17.0.6 \ No newline at end of file diff --git a/contrib/scalapblib/test/src/mill/contrib/scalapblib/TutorialTests.scala b/contrib/scalapblib/test/src/mill/contrib/scalapblib/TutorialTests.scala index ef3b7c872c0..7e513af3904 100644 --- a/contrib/scalapblib/test/src/mill/contrib/scalapblib/TutorialTests.scala +++ b/contrib/scalapblib/test/src/mill/contrib/scalapblib/TutorialTests.scala @@ -83,57 +83,61 @@ object TutorialTests extends TestSuite { test("compileScalaPB") { test("calledDirectly") - UnitTester(Tutorial, resourcePath).scoped { eval => - val Right(result) = eval.apply(Tutorial.core.compileScalaPB) + if (!mill.main.client.Util.isWindows) { + val Right(result) = eval.apply(Tutorial.core.compileScalaPB) - val outPath = protobufOutPath(eval) + val outPath = protobufOutPath(eval) - val outputFiles = os.walk(result.value.path).filter(os.isFile) + val outputFiles = os.walk(result.value.path).filter(os.isFile) - val expectedSourcefiles = compiledSourcefiles.map(outPath / _) + val expectedSourcefiles = compiledSourcefiles.map(outPath / _) - assert( - result.value.path == eval.outPath / "core/compileScalaPB.dest", - outputFiles.nonEmpty, - outputFiles.forall(expectedSourcefiles.contains), - outputFiles.size == 5, - result.evalCount > 0 - ) + assert( + result.value.path == eval.outPath / "core/compileScalaPB.dest", + outputFiles.nonEmpty, + outputFiles.forall(expectedSourcefiles.contains), + outputFiles.size == 5, + result.evalCount > 0 + ) - // don't recompile if nothing changed - val Right(result2) = eval.apply(Tutorial.core.compileScalaPB) + // don't recompile if nothing changed + val Right(result2) = eval.apply(Tutorial.core.compileScalaPB) - assert(result2.evalCount == 0) + assert(result2.evalCount == 0) + } } test("calledWithSpecificFile") - UnitTester( TutorialWithSpecificSources, resourcePath ).scoped { eval => - val Right(result) = eval.apply(TutorialWithSpecificSources.core.compileScalaPB) + if (!mill.main.client.Util.isWindows) { + val Right(result) = eval.apply(TutorialWithSpecificSources.core.compileScalaPB) - val outPath = protobufOutPath(eval) + val outPath = protobufOutPath(eval) - val outputFiles = os.walk(result.value.path).filter(os.isFile) + val outputFiles = os.walk(result.value.path).filter(os.isFile) - val expectedSourcefiles = Seq[os.RelPath]( - os.rel / "AddressBook.scala", - os.rel / "Person.scala", - os.rel / "TutorialProto.scala", - os.rel / "IncludeProto.scala" - ).map(outPath / _) + val expectedSourcefiles = Seq[os.RelPath]( + os.rel / "AddressBook.scala", + os.rel / "Person.scala", + os.rel / "TutorialProto.scala", + os.rel / "IncludeProto.scala" + ).map(outPath / _) - assert( - result.value.path == eval.outPath / "core/compileScalaPB.dest", - outputFiles.nonEmpty, - outputFiles.forall(expectedSourcefiles.contains), - outputFiles.size == 3, - result.evalCount > 0 - ) + assert( + result.value.path == eval.outPath / "core/compileScalaPB.dest", + outputFiles.nonEmpty, + outputFiles.forall(expectedSourcefiles.contains), + outputFiles.size == 3, + result.evalCount > 0 + ) - // don't recompile if nothing changed - val Right(result2) = eval.apply(Tutorial.core.compileScalaPB) + // don't recompile if nothing changed + val Right(result2) = eval.apply(Tutorial.core.compileScalaPB) - assert(result2.evalCount == 0) + assert(result2.evalCount == 0) + } } // // This throws a NullPointerException in coursier somewhere diff --git a/dist/package.mill b/dist/package.mill index f400384df2b..41fd1df7a76 100644 --- a/dist/package.mill +++ b/dist/package.mill @@ -231,13 +231,6 @@ object `package` extends RootModule with InstallModule { | JAVACMD="$$JAVA_HOME/bin/java" |fi | - |# Client-server mode doesn't seem to work on WSL, just disable it for now - |# https://stackoverflow.com/a/43618657/871202 - |if grep -qEi "(Microsoft|WSL)" /proc/version > /dev/null 2> /dev/null ; then - | if [ -z $$COURSIER_CACHE ] ; then - | COURSIER_CACHE=.coursier - | fi - |fi |exec "$$JAVACMD" $jvmArgsStr $$JAVA_OPTS -cp "$classpathStr" $millMainClass "$$@" |""".stripMargin }, @@ -247,11 +240,6 @@ object `package` extends RootModule with InstallModule { s"""setlocal EnableDelayedExpansion |set "JAVACMD=java.exe" |if not "%JAVA_HOME%"=="" set "JAVACMD=%JAVA_HOME%\\bin\\java.exe" - |if "%1" == "-i" set _I_=true - |if "%1" == "--interactive" set _I_=true - |if "%1" == "--repl" set _I_=true - |if "%1" == "--no-server" set _I_=true - |if "%1" == "--bsp" set _I_=true | |"%JAVACMD%" $jvmArgsStr %JAVA_OPTS% -cp "$classpathStr" $millMainClass %* | diff --git a/integration/failure/module-init-error/src/ModuleInitErrorTests.scala b/integration/failure/module-init-error/src/ModuleInitErrorTests.scala index 8c790ab4622..34ce8716d57 100644 --- a/integration/failure/module-init-error/src/ModuleInitErrorTests.scala +++ b/integration/failure/module-init-error/src/ModuleInitErrorTests.scala @@ -41,63 +41,50 @@ object ModuleInitErrorTests extends UtestIntegrationTestSuite { assert(res4.out.contains("foo.fooTask")) } - test("rootTask") - integrationTest { tester => + test("tasks") - integrationTest { tester => import tester._ // If we specify a task in the root module, we are not // affected by the sub-modules failing to initialize val res = eval("rootTask") assert(res.isSuccess == true) assert(res.out.contains("""Running rootTask""")) - } - test("rootCommand") - integrationTest { tester => + import tester._ // If we specify a task 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("fooTask") - integrationTest { tester => - import tester._ - val res = eval("foo.fooTask") - assert(res.isSuccess == false) - assert(fansi.Str(res.err).plainText.contains("""java.lang.Exception: Foo Boom""")) + val res1 = eval(("rootCommand", "-s", "hello")) + assert(res1.isSuccess == true) + assert(res1.out.contains("""Running rootCommand hello""")) + + val res2 = eval("foo.fooTask") + assert(res2.isSuccess == false) + assert(fansi.Str(res2.err).plainText.contains("""java.lang.Exception: Foo Boom""")) // Make sure the stack trace is "short" and does not contain all the stack // frames from the Mill launcher - assert(fansi.Str(res.err).plainText.linesIterator.size < 20) - } - 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("barTask") - integrationTest { tester => - import tester._ - val res = eval("bar.barTask") - assert(res.isSuccess == true) - assert(res.out.contains("""Running barTask""")) - } - 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("quxTask") - integrationTest { tester => - import tester._ - val res = eval("bar.qux.quxTask") - 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") - 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""")) - assert(fansi.Str(res.err).plainText.linesIterator.size < 20) + assert(fansi.Str(res2.err).plainText.linesIterator.size < 20) + + val res3 = eval(("foo.fooCommand", "-s", "hello")) + assert(res3.isSuccess == false) + assert(fansi.Str(res3.err).plainText.contains("""java.lang.Exception: Foo Boom""")) + assert(fansi.Str(res3.err).plainText.linesIterator.size < 20) + + val res4 = eval("bar.barTask") + assert(res4.isSuccess == true) + assert(res4.out.contains("""Running barTask""")) + + val res5 = eval(("bar.barCommand", "-s", "hello")) + assert(res5.isSuccess == true) + assert(res5.out.contains("""Running barCommand hello""")) + + val res6 = eval("bar.qux.quxTask") + assert(res6.isSuccess == false) + assert(fansi.Str(res6.err).plainText.contains("""java.lang.Exception: Qux Boom""")) + assert(fansi.Str(res6.err).plainText.linesIterator.size < 20) + + val res7 = eval(("bar.qux.quxCommand", "-s", "hello")) + assert(res7.isSuccess == false) + assert(fansi.Str(res7.err).plainText.contains("""java.lang.Exception: Qux Boom""")) + assert(fansi.Str(res7.err).plainText.linesIterator.size < 20) } } } diff --git a/integration/feature/launcher-old-versions/src/LauncherOldVersionsTests.scala b/integration/feature/launcher-old-versions/src/LauncherOldVersionsTests.scala index 62f75b07d66..df63f5838c3 100644 --- a/integration/feature/launcher-old-versions/src/LauncherOldVersionsTests.scala +++ b/integration/feature/launcher-old-versions/src/LauncherOldVersionsTests.scala @@ -21,28 +21,13 @@ class LauncherOldVersionsTests(version: String) extends UtestIntegrationTestSuit // Run Mill once beforehand just to make sure it gets initialized and // none of the initialization output gets into `outText` - os.call( - cmd = (launcherScript, "version"), - cwd = workspacePath, - stderr = os.Pipe, - env = Map("MILL_VERSION" -> version) - ) + os.call(cmd = (launcherScript, "version"), cwd = workspacePath, stderr = os.Pipe) - val res = os.call( - cmd = (launcherScript, "version"), - cwd = workspacePath, - stderr = os.Pipe, - env = Map("MILL_VERSION" -> version) - ) + val res = os.call(cmd = (launcherScript, "version"), cwd = workspacePath, stderr = os.Pipe) val outText = res.out.text().trim assert(outText == version) - os.call( - cmd = (launcherScript, "shutdown"), - cwd = workspacePath, - check = false, - env = Map("MILL_VERSION" -> version) - ) + os.call(cmd = (launcherScript, "shutdown"), cwd = workspacePath, check = false) os.remove.all(workspacePath / "out") } } @@ -62,3 +47,4 @@ class LauncherOldVersionsTests(version: String) extends UtestIntegrationTestSuit //object LauncherVersionTests_0_9 extends LauncherOldVersionsTests("0.9.12") //object LauncherVersionTests_0_10 extends LauncherOldVersionsTests("0.10.15") object LauncherVersionTests_0_11 extends LauncherOldVersionsTests("0.11.13") +//object LauncherVersionTests_0_12 extends LauncherOldVersionsTests("0.12.5") diff --git a/integration/ide/bsp-server/resources/snapshots/workspace-build-targets.json b/integration/ide/bsp-server/resources/snapshots/workspace-build-targets.json index 95ffef505be..90cdc666060 100644 --- a/integration/ide/bsp-server/resources/snapshots/workspace-build-targets.json +++ b/integration/ide/bsp-server/resources/snapshots/workspace-build-targets.json @@ -26,7 +26,7 @@ }, "dataKind": "jvm", "data": { - "javaHome": "file:///java-home/", + "javaHome": " java-home", "javaVersion": "" } }, @@ -52,7 +52,7 @@ }, "dataKind": "jvm", "data": { - "javaHome": "file:///java-home/", + "javaHome": "java-home", "javaVersion": "" } }, @@ -78,7 +78,7 @@ }, "dataKind": "jvm", "data": { - "javaHome": "file:///java-home/", + "javaHome": "java-home", "javaVersion": "" } }, @@ -105,7 +105,7 @@ }, "dataKind": "jvm", "data": { - "javaHome": "file:///java-home/", + "javaHome": "java-home", "javaVersion": "" } }, @@ -145,7 +145,7 @@ "file:///coursier-cache/https/repo1.maven.org/maven2/net/java/dev/jna/jna//jna-.jar" ], "jvmBuildTarget": { - "javaHome": "file:///java-home/", + "javaHome": "java-home", "javaVersion": "" } } @@ -183,7 +183,7 @@ "file:///coursier-cache/https/repo1.maven.org/maven2/org/scala-lang/scala-library//scala-library-.jar" ], "jvmBuildTarget": { - "javaHome": "file:///java-home/", + "javaHome": "java-home", "javaVersion": "" } } diff --git a/integration/ide/bsp-server/src/BspServerTestUtil.scala b/integration/ide/bsp-server/src/BspServerTestUtil.scala index 0c23e4fac27..395232e2e84 100644 --- a/integration/ide/bsp-server/src/BspServerTestUtil.scala +++ b/integration/ide/bsp-server/src/BspServerTestUtil.scala @@ -46,7 +46,7 @@ object BspServerTestUtil { case (input0, (from0, to0)) => val (from, to) = if (inverse) (to0, from0) else (from0, to0) input0.replace(from, to) - } + }.replaceAll("\"javaHome\": \"[^\"]+\"", "\"javaHome\": \"java-home\"") // This can be false only when generating test data for the first time. // In that case, updateSnapshots needs to be true, so that we write test data on disk. @@ -58,52 +58,39 @@ object BspServerTestUtil { ) } - if (!expectedValueOpt.contains(value)) { - lazy val jsonStr = gson.toJson( + lazy val jsonStr = normalizeLocalValues( + gson.toJson( value, implicitly[ClassTag[T]].runtimeClass ) - lazy val expectedJsonStr = expectedValueOpt match { - case Some(v) => gson.toJson(v, implicitly[ClassTag[T]].runtimeClass) - case None => "" - } - if (updateSnapshots) { - System.err.println(if (exists) s"Updating $snapshotPath" else s"Writing $snapshotPath") - os.write.over(snapshotPath, normalizeLocalValues(jsonStr), createFolders = true) - } else { - Predef.assert( - false, - if (exists) { - val diff = os.call(( - "git", - "diff", - os.temp(jsonStr, suffix = s"${snapshotPath.last}-jsonStr"), - os.temp(expectedJsonStr, suffix = s"${snapshotPath.last}-expectedJsonStr") - )) - s"""Error: value differs from snapshot in $snapshotPath - | - |You might want to set BspServerTestUtil.updateSnapshots to true, - |run this test again, and commit the updated test data files. - | - |$diff - |""".stripMargin - } else s"Error: no snapshot found at $snapshotPath" - ) - } - } else if (updateSnapshots) { - // Snapshot on disk might need to be updated anyway, if normalizedLocalValues changed - // and new strings should be replaced - val obtainedJsonStr = normalizeLocalValues( - gson.toJson( - value, - implicitly[ClassTag[T]].runtimeClass - ) + ) + + lazy val expectedJsonStr = expectedValueOpt match { + case Some(v) => normalizeLocalValues(gson.toJson(v, implicitly[ClassTag[T]].runtimeClass)) + case None => "" + } + if (updateSnapshots) { + System.err.println(if (exists) s"Updating $snapshotPath" else s"Writing $snapshotPath") + os.write.over(snapshotPath, jsonStr, createFolders = true) + } else { + Predef.assert( + jsonStr == expectedJsonStr, + if (exists) { + val diff = os.call(( + "git", + "diff", + os.temp(jsonStr, suffix = s"${snapshotPath.last}-jsonStr"), + os.temp(expectedJsonStr, suffix = s"${snapshotPath.last}-expectedJsonStr") + )) + s"""Error: value differs from snapshot in $snapshotPath + | + |You might want to set BspServerTestUtil.updateSnapshots to true, + |run this test again, and commit the updated test data files. + | + |$diff + |""".stripMargin + } else s"Error: no snapshot found at $snapshotPath" ) - val expectedJsonStr = os.read(snapshotPath) - if (obtainedJsonStr != expectedJsonStr) { - System.err.println(s"Updating $snapshotPath") - os.write.over(snapshotPath, obtainedJsonStr) - } } } diff --git a/main/server/src/mill/main/server/Server.scala b/main/server/src/mill/main/server/Server.scala index 66313e7338d..75f66d4f4ed 100644 --- a/main/server/src/mill/main/server/Server.scala +++ b/main/server/src/mill/main/server/Server.scala @@ -100,7 +100,7 @@ abstract class Server[T]( exitServer() } }, - "Server ID Checker Thread" + "Server ID Checker Thread: " + serverDir ) serverIdThread.start() } diff --git a/mill b/mill index 1b435e26bae..67fd45a031b 100755 --- a/mill +++ b/mill @@ -103,7 +103,7 @@ fi MILL_NATIVE_SUFFIX="-native" FULL_MILL_VERSION=$MILL_VERSION - +ARTIFACT_SUFFIX="" case "$MILL_VERSION" in *"$MILL_NATIVE_SUFFIX") MILL_VERSION=${MILL_VERSION%"$MILL_NATIVE_SUFFIX"} @@ -117,7 +117,6 @@ case "$MILL_VERSION" in fi esac - MILL="${MILL_DOWNLOAD_PATH}/${FULL_MILL_VERSION}" try_to_use_system_mill() { diff --git a/mill.bat b/mill.bat index d1b7fbbbaaa..88d60786ae3 100644 --- a/mill.bat +++ b/mill.bat @@ -72,6 +72,7 @@ rem without bat file extension, cmd doesn't seem to be able to run it set "MILL_NATIVE_SUFFIX=-native" set "FULL_MILL_VERSION=%MILL_VERSION%" set "MILL_EXT=.bat" +set "ARTIFACT_SUFFIX=" REM Check if MILL_VERSION contains MILL_NATIVE_SUFFIX echo %MILL_VERSION% | findstr /C:"%MILL_NATIVE_SUFFIX%" >nul if %errorlevel% equ 0 ( diff --git a/testkit/src/mill/testkit/ExampleTester.scala b/testkit/src/mill/testkit/ExampleTester.scala index c62c9d2c00a..01a8d7b218c 100644 --- a/testkit/src/mill/testkit/ExampleTester.scala +++ b/testkit/src/mill/testkit/ExampleTester.scala @@ -69,7 +69,7 @@ object ExampleTester { } class ExampleTester( - clientServerMode: Boolean, + val clientServerMode: Boolean, val workspaceSourcePath: os.Path, millExecutable: os.Path, bashExecutable: String = ExampleTester.defaultBashExecutable(), @@ -120,7 +120,8 @@ class ExampleTester( stderr = os.Pipe, cwd = workspacePath, mergeErrIntoOut = true, - env = Map(MILL_TEST_SUITE -> this.getClass().toString()), + env = + Map(MILL_TEST_SUITE -> this.getClass().toString(), "JAVA_HOME" -> sys.props("java.home")), check = false ) diff --git a/testkit/src/mill/testkit/IntegrationTester.scala b/testkit/src/mill/testkit/IntegrationTester.scala index 50e3fdefc65..01deb2f44e7 100644 --- a/testkit/src/mill/testkit/IntegrationTester.scala +++ b/testkit/src/mill/testkit/IntegrationTester.scala @@ -72,9 +72,10 @@ object IntegrationTester { val debugArgs = Option.when(debugLog)("--debug") val shellable: os.Shellable = (millExecutable, serverArgs, "--disable-ticker", debugArgs, cmd) + val res0 = os.call( cmd = shellable, - env = env, + env = env ++ Seq("JAVA_HOME" -> sys.props("java.home")), cwd = cwd, stdin = stdin, stdout = stdout, diff --git a/testkit/src/mill/testkit/IntegrationTesterBase.scala b/testkit/src/mill/testkit/IntegrationTesterBase.scala index 891a0a09845..08b93a70393 100644 --- a/testkit/src/mill/testkit/IntegrationTesterBase.scala +++ b/testkit/src/mill/testkit/IntegrationTesterBase.scala @@ -5,6 +5,7 @@ import mill.main.client.ServerFiles.serverId trait IntegrationTesterBase { def workspaceSourcePath: os.Path + def clientServerMode: Boolean /** * The working directory of the integration test suite, which is the root of the @@ -58,14 +59,10 @@ trait IntegrationTesterBase { * Remove any ID files to try and force them to exit */ def removeServerIdFile(): Unit = { - val outDir = os.Path(out, workspacePath) - if (os.exists(outDir)) { - val serverIdFiles = for { - outPath <- os.list.stream(outDir) - if outPath.last.startsWith(millServer) - } yield outPath / serverId + val serverPath0 = os.Path(out, workspacePath) / millServer + if (clientServerMode) { + for (serverPath <- os.list.stream(serverPath0)) os.remove(serverPath / serverId) - serverIdFiles.foreach(os.remove(_)) Thread.sleep(500) // give a moment for the server to notice the file is gone and exit } } diff --git a/testkit/test/src/mill/testkit/IntegrationTesterTests.scala b/testkit/test/src/mill/testkit/IntegrationTesterTests.scala index 4afbd81cf26..c3845d5c21b 100644 --- a/testkit/test/src/mill/testkit/IntegrationTesterTests.scala +++ b/testkit/test/src/mill/testkit/IntegrationTesterTests.scala @@ -1,6 +1,7 @@ package mill.testkit -import utest._ +import mill.main.client.ServerFiles +import utest.* object IntegrationTesterTests extends TestSuite with IntegrationTestSuite { def clientServerMode = true @@ -10,7 +11,8 @@ object IntegrationTesterTests extends TestSuite with IntegrationTestSuite { def tests: Tests = Tests { test("integration") { - integrationTest { tester => + + val workspacePath = integrationTest { tester => val res1 = tester.eval("testTask") assert(res1.isSuccess) assert(res1.err.contains("compiling 1 Scala source")) // compiling the `build.mill` @@ -21,8 +23,16 @@ object IntegrationTesterTests extends TestSuite with IntegrationTestSuite { 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!!!") + + tester.workspacePath } + // Make sure serverId file is correctly removed to ensure the Mill + // server process shuts down + val remainingServerIdFiles = + os.walk(workspacePath / "out").filter(_.last == ServerFiles.serverId) + assert(remainingServerIdFiles.isEmpty) + } } }