From bce82a5236abb0086a177b168c9b7dd366625bc5 Mon Sep 17 00:00:00 2001 From: Andy Damevin Date: Tue, 13 Oct 2020 15:43:19 +0200 Subject: [PATCH] Allow custom path and class for spring-web codestart - Make sure that custom `path` and `className` are ignored when resteasy is selected (to avoid conflicts) - Add tests Fixes https://github.com/quarkusio/quarkus/issues/12604 --- .../codestarts/QuarkusCodestartData.java | 6 +- .../devtools/commands/CreateProject.java | 31 +++- .../io/quarkus/devtools/ProjectTestUtil.java | 16 ++ .../QuarkusCodestartGenerationTest.java | 8 +- .../devtools/commands/CreateProjectTest.java | 155 ++++++++++++++---- 5 files changed, 171 insertions(+), 45 deletions(-) diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/QuarkusCodestartData.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/QuarkusCodestartData.java index 68c6cd79d51cc..f99d1fd0aef3f 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/QuarkusCodestartData.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/codestarts/QuarkusCodestartData.java @@ -73,7 +73,11 @@ public enum LegacySupport { RESTEASY_EXAMPLE_RESOURCE_PATH("path"), RESTEASY_EXAMPLE_PACKAGE_NAME(QuarkusCodestartData::convertPackageName), - RESTEASY_EXAMPLE_RESOURCE_CLASS_NAME(QuarkusCodestartData::convertClassName); + RESTEASY_EXAMPLE_RESOURCE_CLASS_NAME(QuarkusCodestartData::convertClassName), + + SPRING_WEB_EXAMPLE_RESOURCE_PATH("path"), + SPRING_WEB_EXAMPLE_PACKAGE_NAME(QuarkusCodestartData::convertPackageName), + SPRING_WEB_EXAMPLE_RESOURCE_CLASS_NAME(QuarkusCodestartData::convertClassName); private final String key; private final Function, Object> converter; diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateProject.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateProject.java index cf7641335ccbd..f01f6f3944814 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateProject.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/commands/CreateProject.java @@ -17,6 +17,7 @@ import java.nio.file.Path; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -44,6 +45,7 @@ public class CreateProject { private final Path projectDirPath; private final QuarkusPlatformDescriptor platformDescr; private String javaTarget; + private Set extensions = new HashSet<>(); private BuildTool buildTool = BuildTool.MAVEN; private Map values = new HashMap<>(); @@ -88,6 +90,11 @@ public CreateProject javaTarget(String javaTarget) { return this; } + public CreateProject resourcePath(String resourcePath) { + setValue(RESOURCE_PATH, resourcePath); + return this; + } + public CreateProject className(String className) { if (className == null) { return this; @@ -100,10 +107,10 @@ public CreateProject className(String className) { } public CreateProject extensions(Set extensions) { - if (isSpringStyle(extensions)) { - setValue(IS_SPRING, true); + if (extensions == null) { + return this; } - setValue(EXTENSIONS, extensions); + this.extensions.addAll(extensions); return this; } @@ -176,7 +183,15 @@ public QuarkusCommandOutcome execute() throws QuarkusCommandException { } else { setValue(JAVA_TARGET, "11"); } - + if (containsSpringWeb(extensions)) { + setValue(IS_SPRING, true); + if (containsRESTEasy(extensions)) { + values.remove(CLASS_NAME); + values.remove(PACKAGE_NAME); + values.remove(RESOURCE_PATH); + } + } + setValue(EXTENSIONS, extensions); final QuarkusProject quarkusProject = QuarkusProject.of(projectDirPath, platformDescr, buildTool); final QuarkusCommandInvocation invocation = new QuarkusCommandInvocation(quarkusProject, values); if (legacyCodegen) { @@ -194,7 +209,11 @@ public static SourceType determineSourceType(Set extensions) { return sourceType.orElse(SourceType.JAVA); } - private static boolean isSpringStyle(Collection extensions) { - return extensions != null && extensions.stream().anyMatch(e -> e.toLowerCase().contains("spring-web")); + private static boolean containsSpringWeb(Collection extensions) { + return extensions.stream().anyMatch(e -> e.toLowerCase().contains("spring-web")); + } + + private static boolean containsRESTEasy(Collection extensions) { + return extensions.isEmpty() || extensions.stream().anyMatch(e -> e.toLowerCase().contains("resteasy")); } } diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/ProjectTestUtil.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/ProjectTestUtil.java index 241ab1c7fb4b9..c03ff9e8b67a5 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/ProjectTestUtil.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/ProjectTestUtil.java @@ -1,10 +1,14 @@ package io.quarkus.devtools; +import static org.assertj.core.api.Assertions.assertThat; + import java.io.File; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.Comparator; +import java.util.function.Consumer; import java.util.stream.Stream; import org.junit.jupiter.api.Assertions; @@ -27,4 +31,16 @@ public static void delete(final File file) throws IOException { Assertions.assertFalse( Files.exists(file.toPath()), "Directory still exists"); } + + public static Consumer checkContains(String s) { + return (p) -> assertThat(getContent(p)).contains(s); + } + + public static String getContent(Path p) { + return org.assertj.core.util.Files.contentOf(p.toFile(), StandardCharsets.UTF_8); + } + + public static Consumer checkMatches(String regex) { + return (p) -> assertThat(getContent(p)).matches(regex); + } } diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/QuarkusCodestartGenerationTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/QuarkusCodestartGenerationTest.java index 59dfe22e5fdf0..5850b925b2cce 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/QuarkusCodestartGenerationTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/codestarts/QuarkusCodestartGenerationTest.java @@ -1,17 +1,15 @@ package io.quarkus.devtools.codestarts; +import static io.quarkus.devtools.ProjectTestUtil.checkContains; import static io.quarkus.devtools.codestarts.QuarkusCodestartData.DataKey.*; import static org.assertj.core.api.Assertions.assertThat; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; -import java.util.function.Consumer; -import org.assertj.core.util.Files; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -540,10 +538,6 @@ private void checkGradleWithKotlinDsl(Path projectDir) { .satisfies(checkContains("rootProject.name=\"test-codestart\"")); } - private Consumer checkContains(String s) { - return (p) -> assertThat(Files.contentOf(p.toFile(), StandardCharsets.UTF_8)).contains(s); - } - private QuarkusCodestartCatalog getCatalog() throws IOException { return QuarkusCodestartCatalog.fromQuarkusPlatformDescriptor(getPlatformDescriptor()); } diff --git a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/CreateProjectTest.java b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/CreateProjectTest.java index c217e0041a43f..5886d1a124ed0 100644 --- a/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/CreateProjectTest.java +++ b/integration-tests/devtools/src/test/java/io/quarkus/devtools/commands/CreateProjectTest.java @@ -1,14 +1,18 @@ package io.quarkus.devtools.commands; +import static io.quarkus.devtools.ProjectTestUtil.checkContains; +import static io.quarkus.devtools.ProjectTestUtil.checkMatches; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.contentOf; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.CountDownLatch; @@ -32,37 +36,134 @@ public class CreateProjectTest extends PlatformAwareTestBase { @Test - public void create() throws Exception { - final File file = new File("target/basic-rest"); + public void createRESTEasy() throws Exception { + final File file = new File("target/basic-resteasy"); + final Path projectDir = file.toPath(); ProjectTestUtil.delete(file); - createProject(file, "io.quarkus", "basic-rest", "1.0.0-SNAPSHOT"); + assertCreateProject(newCreateProject(projectDir) + .groupId("io.foo") + .artifactId("resteasy-app") + .version("1.0.0-FOO") + .className("my.project.resteasy.FooResource") + .resourcePath("/foo") + .extensions(Collections.singleton("resteasy"))); - final File gitignore = new File(file, ".gitignore"); - assertTrue(gitignore.exists()); - final String gitignoreContent = new String(Files.readAllBytes(gitignore.toPath()), StandardCharsets.UTF_8); - assertThat(gitignoreContent).matches("(?s).*target/\\R.*"); + assertThat(projectDir.resolve(".gitignore")) + .exists() + .satisfies(checkMatches("(?s).*target/\\R.*")); + assertThat(projectDir.resolve("src/main/java/my/project/resteasy/FooResource.java")) + .exists() + .satisfies(checkContains("class FooResource")) + .satisfies(checkContains("@Path(\"/foo\")")); + assertThat(projectDir.resolve("pom.xml")) + .exists() + .satisfies(checkContains("io.foo")) + .satisfies(checkContains("resteasy-app")) + .satisfies(checkContains("1.0.0-FOO")) + .satisfies(checkContains("quarkus-resteasy")); + + assertThat(projectDir.resolve("README.md")) + .exists() + .satisfies(checkContains("./mvnw")); + } + + @Test + public void createSpringWeb() throws Exception { + final File file = new File("target/create-spring"); + final Path projectDir = file.toPath(); + ProjectTestUtil.delete(file); + assertCreateProject(newCreateProject(projectDir) + .groupId("io.bar") + .artifactId("spring-web-app") + .version("1.0.0-BAR") + .className("my.project.spring.BarController") + .resourcePath("/bar") + .extensions(Collections.singleton("spring-web"))); + assertThat(projectDir.resolve("pom.xml")) + .exists() + .satisfies(checkContains("io.bar")) + .satisfies(checkContains("spring-web-app")) + .satisfies(checkContains("1.0.0-BAR")) + .satisfies(checkContains("quarkus-spring-web")); + + assertThat(projectDir.resolve("src/main/java/my/project/spring/BarController.java")) + .exists() + .satisfies(checkContains("@RestController")) + .satisfies(checkContains("class BarController")) + .satisfies(checkContains("@RequestMapping(\"/bar\")")); + } + + @Test + public void createRESTEasyAndSpringWeb() throws Exception { + final File file = new File("target/create-spring-resteasy"); + final Path projectDir = file.toPath(); + ProjectTestUtil.delete(file); + assertCreateProject(newCreateProject(projectDir) + .artifactId("spring-web-resteasy-app") + .className("my.project.spring.BarController") + .resourcePath("/bar") + .extensions(new HashSet<>(Arrays.asList("resteasy", "spring-web")))); + assertThat(projectDir.resolve("pom.xml")) + .exists() + .satisfies(checkContains("spring-web-resteasy-app")) + .satisfies(checkContains("quarkus-spring-web")) + .satisfies(checkContains("quarkus-resteasy")); + + assertThat(projectDir.resolve("src/main/java/org/acme/spring/web/ExampleController.java")) + .exists() + .satisfies(checkContains("@RestController")) + .satisfies(checkContains("class ExampleController")) + .satisfies(checkContains("@RequestMapping(\"/springweb/hello\")")); + + assertThat(projectDir.resolve("src/main/java/org/acme/resteasy/ExampleResource.java")) + .exists() + .satisfies(checkContains("class ExampleResource")) + .satisfies(checkContains("@Path(\"/resteasy/hello\")")); } @Test public void createGradle() throws Exception { - final File file = new File("target/basic-rest-gradle"); + final File file = new File("target/create-resteasy-gradle"); + final Path projectDir = file.toPath(); ProjectTestUtil.delete(file); - createProject(BuildTool.GRADLE, file, "io.quarkus", "basic-rest", "1.0.0-SNAPSHOT"); + assertCreateProject(newCreateProject(projectDir) + .buildTool(BuildTool.GRADLE) + .groupId("io.foo") + .artifactId("resteasy-app") + .version("1.0.0-FOO") + .className("my.project.FooResource") + .resourcePath("/foo") + .extensions(Collections.singleton("resteasy"))); + + assertThat(projectDir.resolve(".gitignore")) + .exists() + .satisfies(checkMatches("(?s).*build/\\R.*")) + .satisfies(checkMatches("(?s).*\\.gradle/\\R.*")); + assertThat(projectDir.resolve("src/main/java/my/project/FooResource.java")) + .exists() + .satisfies(checkContains("@Path(\"/foo\")")); + assertThat(projectDir.resolve("build.gradle")) + .exists() + .satisfies(checkContains("group 'io.foo'")) + .satisfies(checkContains("version '1.0.0-FOO'")) + .satisfies(checkContains("implementation 'io.quarkus:quarkus-resteasy'")); - final File gitignore = new File(file, ".gitignore"); - assertTrue(gitignore.exists()); - final String gitignoreContent = new String(Files.readAllBytes(gitignore.toPath()), StandardCharsets.UTF_8); - assertThat(gitignoreContent).doesNotMatch("(?s).*target/\\R.*"); - assertThat(gitignoreContent).matches("(?s).*build/\\R.*"); - assertThat(gitignoreContent).matches("(?s).*\\.gradle/\\R.*"); + assertThat(projectDir.resolve("settings.gradle")) + .exists() + .satisfies(checkContains("rootProject.name='resteasy-app'")); + + assertThat(projectDir.resolve("README.md")) + .exists() + .satisfies(checkContains("./gradlew")); + } - assertThat(new File(file, "README.md")).exists(); - assertThat(contentOf(new File(file, "README.md"), "UTF-8")).contains("./gradlew"); + private CreateProject newCreateProject(Path dir) { + return new CreateProject(dir, getPlatformDescriptor()); } @Test public void createOnTopOfExisting() throws Exception { - final File testDir = new File("target/existing"); + final File testDir = new File("target/create-existing"); ProjectTestUtil.delete(testDir); testDir.mkdirs(); @@ -109,21 +210,13 @@ void createMultipleTimes() throws InterruptedException { latch.await(); } - private void createProject(final File file, String groupId, String artifactId, String version) + private void assertCreateProject(CreateProject createProject) throws QuarkusCommandException { - createProject(BuildTool.MAVEN, file, groupId, artifactId, version); - } - - private void createProject(BuildTool buildTool, File file, String groupId, String artifactId, String version) - throws QuarkusCommandException { - final QuarkusCommandOutcome result = new CreateProject(file.toPath(), getPlatformDescriptor()) - .buildTool(buildTool) - .groupId(groupId) - .artifactId(artifactId) - .version(version) + final QuarkusCommandOutcome result = createProject .quarkusMavenPluginVersion("2.3.5") .quarkusGradlePluginVersion("2.3.5-gradle") .execute(); assertTrue(result.isSuccess()); } + }