diff --git a/devtools/cli/src/main/java/io/quarkus/cli/Dev.java b/devtools/cli/src/main/java/io/quarkus/cli/Dev.java index e00d29cd4c15e..9bee92717ec2a 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/Dev.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/Dev.java @@ -34,8 +34,8 @@ public Integer call() { output.throwIfUnmatchedArguments(spec.commandLine()); BuildSystemRunner runner = getRunner(); - List> commandArgs = runner.prepareDevMode(devOptions, debugOptions, - params); + List> commandArgs = runner.prepareDevTestMode( + true, devOptions, debugOptions, params); if (devOptions.isDryRun()) { dryRunDev(spec.commandLine().getHelp(), runner.getBuildTool(), commandArgs.iterator().next().get()); diff --git a/devtools/cli/src/main/java/io/quarkus/cli/QuarkusCli.java b/devtools/cli/src/main/java/io/quarkus/cli/QuarkusCli.java index fad864c6f8b1c..82a13ece6989b 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/QuarkusCli.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/QuarkusCli.java @@ -23,7 +23,8 @@ import picocli.CommandLine.UnmatchedArgumentException; @CommandLine.Command(name = "quarkus", subcommands = { - Create.class, Build.class, Dev.class, ProjectExtensions.class, Registry.class, Info.class, Update.class, Version.class, + Create.class, Build.class, Dev.class, Test.class, ProjectExtensions.class, Registry.class, Info.class, Update.class, + Version.class, Completion.class }, scope = ScopeType.INHERIT, sortOptions = false, showDefaultValues = true, versionProvider = Version.class, subcommandsRepeatable = false, mixinStandardHelpOptions = false, commandListHeading = "%nCommands:%n", synopsisHeading = "%nUsage: ", optionListHeading = "Options:%n", headerHeading = "%n", parameterListHeading = "%n") public class QuarkusCli implements QuarkusApplication, Callable { static { diff --git a/devtools/cli/src/main/java/io/quarkus/cli/Test.java b/devtools/cli/src/main/java/io/quarkus/cli/Test.java new file mode 100644 index 0000000000000..4b4ce81792038 --- /dev/null +++ b/devtools/cli/src/main/java/io/quarkus/cli/Test.java @@ -0,0 +1,77 @@ +package io.quarkus.cli; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.concurrent.Callable; +import java.util.function.Supplier; + +import io.quarkus.cli.build.BaseBuildCommand; +import io.quarkus.cli.build.BuildSystemRunner; +import io.quarkus.cli.common.DebugOptions; +import io.quarkus.cli.common.DevOptions; +import io.quarkus.devtools.project.BuildTool; +import picocli.CommandLine; +import picocli.CommandLine.Parameters; + +@CommandLine.Command(name = "test", showEndOfOptionsDelimiterInUsageHelp = true, header = "Run the current project in continuous testing mode.") +public class Test extends BaseBuildCommand implements Callable { + + @CommandLine.ArgGroup(order = 1, exclusive = false, heading = "%nContinuous Test Mode options:%n") + DevOptions testOptions = new DevOptions(); + + @CommandLine.ArgGroup(order = 3, exclusive = false, validate = true, heading = "%nDebug options:%n") + DebugOptions debugOptions = new DebugOptions(); + + @Parameters(description = "Parameters passed to the application.") + List params = new ArrayList<>(); + + @Override + public Integer call() { + try { + output.debug("Run project in test mode with initial parameters: %s", this); + output.throwIfUnmatchedArguments(spec.commandLine()); + + BuildSystemRunner runner = getRunner(); + List> commandArgs = runner.prepareDevTestMode( + false, testOptions, debugOptions, params); + + if (testOptions.isDryRun()) { + dryRunTest(spec.commandLine().getHelp(), runner.getBuildTool(), commandArgs.iterator().next().get()); + return CommandLine.ExitCode.OK; + } + int ret = 1; + for (Supplier i : commandArgs) { + ret = runner.run(i.get()); + if (ret != 0) { + return ret; + } + } + return ret; + } catch (Exception e) { + return output.handleCommandException(e, + "Unable to launch project in test mode: " + e.getMessage()); + } + } + + void dryRunTest(CommandLine.Help help, BuildTool buildTool, BuildSystemRunner.BuildCommandArgs args) { + output.printText("\nRun current project in test mode\n", + "\t" + projectRoot().toString()); + Map dryRunOutput = new TreeMap<>(); + dryRunOutput.put("Build tool", buildTool.name()); + output.info(help.createTextTable(dryRunOutput).toString()); + + output.printText("\nCommand line:\n", + args.showCommand()); + } + + @Override + public String toString() { + return "Test [debugOptions=" + debugOptions + + ", testOptions=" + testOptions + + ", properties=" + propertiesOptions.properties + + ", output=" + output + + ", params=" + params + "]"; + } +} diff --git a/devtools/cli/src/main/java/io/quarkus/cli/build/BuildSystemRunner.java b/devtools/cli/src/main/java/io/quarkus/cli/build/BuildSystemRunner.java index 9aecbf81c324e..b34656bfd736c 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/build/BuildSystemRunner.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/build/BuildSystemRunner.java @@ -106,8 +106,8 @@ Integer listExtensions(RunModeOption runMode, ListFormatOptions format, boolean BuildCommandArgs prepareBuild(BuildOptions buildOptions, RunModeOption runMode, List params); - List> prepareDevMode(DevOptions devOptions, DebugOptions debugOptions, - List params); + List> prepareDevTestMode(boolean devMode, DevOptions commonOptions, + DebugOptions debugOptions, List params); Path getProjectRoot(); diff --git a/devtools/cli/src/main/java/io/quarkus/cli/build/GradleRunner.java b/devtools/cli/src/main/java/io/quarkus/cli/build/GradleRunner.java index 014edef1ff244..f86f13d13c1f8 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/build/GradleRunner.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/build/GradleRunner.java @@ -10,7 +10,6 @@ import java.util.List; import java.util.Set; import java.util.function.Supplier; -import java.util.stream.Collectors; import io.quarkus.cli.common.BuildOptions; import io.quarkus.cli.common.CategoryListFormatOptions; @@ -178,23 +177,20 @@ public BuildCommandArgs prepareBuild(BuildOptions buildOptions, RunModeOption ru } @Override - public List> prepareDevMode(DevOptions devOptions, DebugOptions debugOptions, - List params) { + public List> prepareDevTestMode(boolean devMode, DevOptions commonOptions, + DebugOptions debugOptions, List params) { ArrayDeque args = new ArrayDeque<>(); List jvmArgs = new ArrayList<>(); setGradleProperties(args, false); - if (devOptions.clean) { + if (commonOptions.clean) { args.add("clean"); } - args.add("quarkusDev"); - if (devOptions.skipTests()) { // TODO: does this make sense for dev mode? - setSkipTests(args); - } + args.add(devMode ? "quarkusDev" : "quarkusTest"); - if (devOptions.offline) { + if (commonOptions.offline) { args.add("--offline"); } @@ -206,27 +202,19 @@ public List> prepareDevMode(DevOptions devOptions, De try { Path outputFile = Files.createTempFile("quarkus-dev", ".txt"); - args.add("-Dio.quarkus.devmode-args=" + outputFile.toAbsolutePath().toString()); + if (devMode) { + args.add("-Dio.quarkus.devmode-args=" + outputFile.toAbsolutePath()); + } BuildCommandArgs buildCommandArgs = prependExecutable(args); - return Arrays.asList(new Supplier() { - @Override - public BuildCommandArgs get() { - return buildCommandArgs; - } - }, new Supplier() { - @Override - public BuildCommandArgs get() { - try { - List lines = Files.readAllLines(outputFile).stream().filter(s -> !s.isBlank()) - .collect(Collectors.toList()); - BuildCommandArgs cmd = new BuildCommandArgs(); - cmd.arguments = lines.toArray(new String[0]); - cmd.targetDirectory = buildCommandArgs.targetDirectory; - return cmd; - } catch (IOException e) { - throw new RuntimeException(e); - } + return Arrays.asList(() -> buildCommandArgs, () -> { + try { + BuildCommandArgs cmd = new BuildCommandArgs(); + cmd.arguments = Files.readAllLines(outputFile).stream().filter(s -> !s.isBlank()).toArray(String[]::new); + cmd.targetDirectory = buildCommandArgs.targetDirectory; + return cmd; + } catch (IOException e) { + throw new RuntimeException(e); } }); } catch (IOException e) { diff --git a/devtools/cli/src/main/java/io/quarkus/cli/build/JBangRunner.java b/devtools/cli/src/main/java/io/quarkus/cli/build/JBangRunner.java index 62327cdbcd9a5..2972d29e4e43c 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/build/JBangRunner.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/build/JBangRunner.java @@ -105,7 +105,8 @@ public BuildCommandArgs prepareBuild(BuildOptions buildOptions, RunModeOption ru } @Override - public List> prepareDevMode(DevOptions devOptions, DebugOptions debugOptions, + public List> prepareDevTestMode(boolean devMode, DevOptions commonOptions, + DebugOptions debugOptions, List params) { throw new UnsupportedOperationException("Not there yet. ;)"); } diff --git a/devtools/cli/src/main/java/io/quarkus/cli/build/MavenRunner.java b/devtools/cli/src/main/java/io/quarkus/cli/build/MavenRunner.java index 2c801a999901a..ef639411eb56c 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/build/MavenRunner.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/build/MavenRunner.java @@ -191,23 +191,19 @@ public BuildCommandArgs prepareBuild(BuildOptions buildOptions, RunModeOption ru } @Override - public List> prepareDevMode(DevOptions devOptions, DebugOptions debugOptions, - List params) { + public List> prepareDevTestMode(boolean devMode, DevOptions commonOptions, + DebugOptions debugOptions, List params) { ArrayDeque args = new ArrayDeque<>(); List jvmArgs = new ArrayList<>(); setMavenProperties(args, false); - if (devOptions.clean) { + if (commonOptions.clean) { args.add("clean"); } - args.add("quarkus:dev"); + args.add(devMode ? "quarkus:dev" : "quarkus:test"); - if (devOptions.skipTests()) { // TODO: does this make sense? - setSkipTests(args); - } - - if (devOptions.offline) { + if (commonOptions.offline) { args.add("--offline"); } @@ -218,12 +214,7 @@ public List> prepareDevMode(DevOptions devOptions, De paramsToQuarkusArgs(params, args); BuildCommandArgs buildCommandArgs = prependExecutable(args); - return Collections.singletonList(new Supplier() { - @Override - public BuildCommandArgs get() { - return buildCommandArgs; - } - }); + return Collections.singletonList(() -> buildCommandArgs); } void setSkipTests(ArrayDeque args) { diff --git a/devtools/cli/src/main/java/io/quarkus/cli/common/DevOptions.java b/devtools/cli/src/main/java/io/quarkus/cli/common/DevOptions.java index 4db0f8f3770ee..3a708f0fcb888 100644 --- a/devtools/cli/src/main/java/io/quarkus/cli/common/DevOptions.java +++ b/devtools/cli/src/main/java/io/quarkus/cli/common/DevOptions.java @@ -14,9 +14,9 @@ public class DevOptions { "--clean" }, description = "Perform clean as part of build. False by default.", negatable = true) public boolean clean = false; - @CommandLine.Option(order = 4, names = { - "--no-tests" }, description = "Toggle continuous testing mode. Enabled by default.", negatable = true, hidden = true) - public boolean runTests = true; // TODO: does this make sense re: continuous test? + // Invalid w/ continuous test mode. Leave for compat (hidden) + @CommandLine.Option(order = 4, names = { "--no-tests" }, negatable = true, hidden = true) + public boolean runTests = true; @CommandLine.Option(order = 5, names = { "--offline" }, description = "Work offline.", defaultValue = "false") public boolean offline = false; diff --git a/devtools/cli/src/test/java/io/quarkus/cli/CliProjectGradleTest.java b/devtools/cli/src/test/java/io/quarkus/cli/CliProjectGradleTest.java index f27bb1a3860bc..0a99027fe806b 100644 --- a/devtools/cli/src/test/java/io/quarkus/cli/CliProjectGradleTest.java +++ b/devtools/cli/src/test/java/io/quarkus/cli/CliProjectGradleTest.java @@ -309,8 +309,8 @@ public void testDevOptions() throws Exception { Assertions.assertFalse(result.stdout.contains(" clean"), "gradle command should not specify 'clean'\n" + result); - Assertions.assertTrue(result.stdout.contains("-x test"), - "gradle command should specify '-x test'\n" + result); + Assertions.assertFalse(result.stdout.contains("-x test"), + "gradle command should not specify '-x test' (ignored)\n" + result); Assertions.assertTrue(result.stdout.contains("-Ddebug=false"), "gradle command should specify '-Ddebug=false'\n" + result); diff --git a/devtools/cli/src/test/java/io/quarkus/cli/CliProjectMavenTest.java b/devtools/cli/src/test/java/io/quarkus/cli/CliProjectMavenTest.java index 94a151b331de4..796ecd0acb71c 100644 --- a/devtools/cli/src/test/java/io/quarkus/cli/CliProjectMavenTest.java +++ b/devtools/cli/src/test/java/io/quarkus/cli/CliProjectMavenTest.java @@ -183,7 +183,7 @@ public void testBuildOptions() throws Exception { } @Test - public void testDevOptions() throws Exception { + public void testDevTestOptions() throws Exception { CliDriver.Result result = CliDriver.execute(workspaceRoot, "create", "app", "-e", "-B", "--verbose"); Assertions.assertEquals(CommandLine.ExitCode.OK, result.exitCode, "Expected OK return code." + result); @@ -225,10 +225,10 @@ public void testDevOptions() throws Exception { Assertions.assertFalse(result.stdout.contains(" clean"), "mvn command should not specify 'clean'\n" + result); - Assertions.assertTrue(result.stdout.contains("-DskipTests"), - "mvn command should specify -DskipTests\n" + result); - Assertions.assertTrue(result.stdout.contains("-Dmaven.test.skip=true"), - "mvn command should specify -Dmaven.test.skip=true\n" + result); + Assertions.assertFalse(result.stdout.contains("-DskipTests"), + "mvn command should not specify -DskipTests (ignored)\n" + result); + Assertions.assertFalse(result.stdout.contains("-Dmaven.test.skip=true"), + "mvn command should not specify -Dmaven.test.skip=true (ignored)\n" + result); Assertions.assertTrue(result.stdout.contains("-Ddebug=false"), "mvn command should specify '-Ddebug=false'\n" + result); @@ -254,6 +254,12 @@ public void testDevOptions() throws Exception { Assertions.assertTrue(result.stdout.contains("-Dquarkus.args='arg1 arg2'"), "mvn command should not specify -Dquarkus.args='arg1 arg2'\n" + result); + + // 4 TEST MODE: test --clean --debug --suspend --offline + result = CliDriver.execute(project, "test", "-e", "--dry-run", + "--clean", "--debug", "--suspend", "--debug-mode=listen", "--offline"); + Assertions.assertEquals(CommandLine.ExitCode.OK, result.exitCode, + "Expected OK return code. Result:\n" + result); } @Test