From e2814804265f772781970b2c9ffe465ee49eac14 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Wed, 21 Nov 2018 15:20:08 +0100 Subject: [PATCH] Switch project structure to use the new generator This commit removes the former `ProjectGenerator` api based on mustache template in favour of a new DSL infrastructure to be detailed in further commits. Event handling is now web-specific with a `ProjectRequest` and a `WebProjectRequest` that gathers the base input from the request and some additional web-specific metadata, respectively. As a consequence the `initializr-actuator` module has now a dependency on the `initializr-web` module. See gh-340 Co-authored-by: Stephane Nicoll --- .gitignore | 1 - initializr-actuator/pom.xml | 10 +- .../stat/ProjectGenerationStatPublisher.java | 2 +- .../stat/ProjectRequestDocumentFactory.java | 29 +- .../stat/AbstractInitializrStatTests.java | 50 - .../ProjectGenerationStatPublisherTests.java | 45 +- .../ProjectRequestDocumentFactoryTests.java | 53 +- initializr-generator/pom.xml | 10 + .../initializr/generator/BuildProperties.java | 60 -- .../generator/ProjectGenerator.java | 758 -------------- .../initializr/generator/ProjectRequest.java | 328 ------ .../ProjectRequestPostProcessor.java | 59 -- .../generator/ProjectRequestResolver.java | 61 -- .../gradle3/gradle/wrapper/gradle-wrapper.jar | Bin 54711 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - .../main/resources/project/gradle3/gradlew | 172 ---- .../resources/project/gradle3/gradlew.bat | 84 -- .../gradle4/gradle/wrapper/gradle-wrapper.jar | Bin 56177 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 - .../main/resources/project/gradle4/gradlew | 172 ---- .../resources/project/gradle4/gradlew.bat | 84 -- .../src/main/resources/project/maven/mvnw | 286 ----- .../src/main/resources/project/maven/mvnw.cmd | 161 --- .../project/maven/wrapper/maven-wrapper.jar | Bin 48337 -> 0 bytes .../maven/wrapper/maven-wrapper.properties | 1 - .../resources/templates/Application.groovy | 14 - .../main/resources/templates/Application.java | 14 - .../main/resources/templates/Application.kt | 22 - .../templates/ApplicationTests.groovy | 15 - .../resources/templates/ApplicationTests.java | 15 - .../resources/templates/ApplicationTests.kt | 15 - .../templates/ServletInitializer.groovy | 14 - .../templates/ServletInitializer.java | 14 - .../resources/templates/ServletInitializer.kt | 13 - .../main/resources/templates/gitignore.tmpl | 37 - .../resources/templates/starter-build.gradle | 121 --- .../main/resources/templates/starter-pom.xml | 276 ----- .../templates/starter-settings.gradle | 1 - .../AbstractProjectGeneratorTests.java | 154 --- .../CustomProjectGeneratorTests.java | 98 -- .../generator/ProjectGeneratorBuildTests.java | 274 ----- .../ProjectGeneratorLanguageTests.java | 146 --- .../generator/ProjectGeneratorTests.java | 973 ------------------ .../ProjectRequestResolverTests.java | 121 --- .../generator/ProjectRequestTests.java | 417 -------- .../test/generator/GradleBuildAssert.java | 89 -- .../test/generator/GradleSettingsAssert.java | 43 - .../initializr/test/generator/PomAssert.java | 513 --------- .../test/generator/ProjectAssert.java | 274 ----- .../test/generator/SourceCodeAssert.java | 83 -- .../test/resources/project/custom/custom.txt | 4 - ...tion-processor-dependency-build.gradle.gen | 30 - .../gradle/bom-ordering-build.gradle.gen | 36 - .../gradle/bom-property-build.gradle.gen | 38 - .../compile-only-dependency-build.gradle.gen | 30 - .../resources/project/gradle/gitignore.gen | 26 - .../gradle/kotlin-java11-build.gradle.gen | 48 - .../gradle/repositories-build.gradle.gen | 31 - .../repositories-milestone-build.gradle.gen | 32 - .../gradle/version-override-build.gradle.gen | 33 - .../previous/DemoApplication.groovy.gen | 14 - .../previous/ServletInitializer.groovy.gen | 14 - .../project/groovy/previous/build.gradle.gen | 28 - .../project/groovy/previous/pom.xml.gen | 66 -- .../standard/DemoApplication.groovy.gen | 14 - .../standard/DemoApplicationTests.groovy.gen | 17 - .../DemoApplicationTestsWeb.groovy.gen | 17 - .../standard/ServletInitializer.groovy.gen | 14 - .../project/groovy/standard/build.gradle.gen | 29 - .../project/groovy/standard/pom.xml.gen | 66 -- .../groovy/standard/war-build.gradle.gen | 31 - .../project/groovy/standard/war-pom.xml.gen | 72 -- .../java/previous/DemoApplication.java.gen | 14 - .../java/previous/ServletInitializer.java.gen | 14 - .../project/java/previous/build.gradle.gen | 27 - .../project/java/previous/pom.xml.gen | 43 - .../java/standard/DemoApplication.java.gen | 14 - .../standard/DemoApplicationTests.java.gen | 17 - .../standard/DemoApplicationTestsWeb.java.gen | 17 - .../java/standard/ServletInitializer.java.gen | 14 - .../project/java/standard/build.gradle.gen | 28 - .../project/java/standard/pom.xml.gen | 43 - .../java/standard/war-build.gradle.gen | 30 - .../project/java/standard/war-pom.xml.gen | 49 - .../kotlin/previous/DemoApplication.kt.gen | 12 - .../kotlin/previous/ServletInitializer.kt.gen | 13 - .../project/kotlin/previous/build.gradle.gen | 47 - .../project/kotlin/previous/pom.xml.gen | 93 -- .../kotlin/standard/DemoApplication.kt.gen | 12 - .../standard/DemoApplicationTests.kt.gen | 17 - .../standard/DemoApplicationTestsWeb.kt.gen | 17 - .../kotlin/standard/ServletInitializer.kt.gen | 13 - .../project/kotlin/standard/build.gradle.gen | 48 - .../project/kotlin/standard/pom.xml.gen | 73 -- .../kotlin/standard/war-build.gradle.gen | 50 - .../project/kotlin/standard/war-pom.xml.gen | 79 -- ...nnotation-processor-dependency-pom.xml.gen | 52 - .../project/maven/bom-ordering-pom.xml.gen | 69 -- .../project/maven/bom-property-pom.xml.gen | 56 - .../maven/compile-only-dependency-pom.xml.gen | 52 - .../resources/project/maven/gitignore.gen | 25 - .../project/maven/kotlin-java11-pom.xml.gen | 73 -- .../maven/repositories-milestone-pom.xml.gen | 74 -- .../project/maven/repositories-pom.xml.gen | 63 -- .../maven/version-override-pom.xml.gen | 45 - initializr-web/pom.xml | 12 + .../web}/InvalidProjectRequestException.java | 4 +- .../web}/ProjectResourceLocator.java | 4 +- .../InitializrAutoConfiguration.java | 62 +- .../project/AbstractInitializrController.java | 2 +- .../web/project/MainController.java | 56 +- .../web/project}/ProjectFailedEvent.java | 8 +- .../web/project}/ProjectGeneratedEvent.java | 9 +- .../web/project/ProjectGenerationInvoker.java | 215 ++++ .../web/project/ProjectRequest.java | 6 +- .../web/project}/ProjectRequestEvent.java | 13 +- .../ProjectRequestToDescriptionConverter.java | 167 +++ .../web/project/WebProjectRequest.java | 61 ++ .../AbstractInitializrIntegrationTests.java | 2 +- .../InitializrAutoConfigurationTests.java | 60 +- .../CommandLineExampleIntegrationTests.java | 2 +- ...ainControllerDefaultsIntegrationTests.java | 6 +- .../MainControllerEnvIntegrationTests.java | 2 +- .../MainControllerIntegrationTests.java | 2 +- ...GenerationDescriptionCustomizerTests.java} | 50 +- .../ProjectGenerationInvokerTests.java | 253 +++++ .../project/ProjectGenerationSmokeTests.java | 4 +- ...ectRequestToDescriptionConverterTests.java | 177 ++++ pom.xml | 46 + 129 files changed, 1153 insertions(+), 8245 deletions(-) delete mode 100755 initializr-actuator/src/test/java/io/spring/initializr/actuate/stat/AbstractInitializrStatTests.java delete mode 100644 initializr-generator/src/main/java/io/spring/initializr/generator/BuildProperties.java delete mode 100644 initializr-generator/src/main/java/io/spring/initializr/generator/ProjectGenerator.java delete mode 100644 initializr-generator/src/main/java/io/spring/initializr/generator/ProjectRequest.java delete mode 100644 initializr-generator/src/main/java/io/spring/initializr/generator/ProjectRequestPostProcessor.java delete mode 100644 initializr-generator/src/main/java/io/spring/initializr/generator/ProjectRequestResolver.java delete mode 100644 initializr-generator/src/main/resources/project/gradle3/gradle/wrapper/gradle-wrapper.jar delete mode 100644 initializr-generator/src/main/resources/project/gradle3/gradle/wrapper/gradle-wrapper.properties delete mode 100755 initializr-generator/src/main/resources/project/gradle3/gradlew delete mode 100755 initializr-generator/src/main/resources/project/gradle3/gradlew.bat delete mode 100644 initializr-generator/src/main/resources/project/gradle4/gradle/wrapper/gradle-wrapper.jar delete mode 100644 initializr-generator/src/main/resources/project/gradle4/gradle/wrapper/gradle-wrapper.properties delete mode 100755 initializr-generator/src/main/resources/project/gradle4/gradlew delete mode 100644 initializr-generator/src/main/resources/project/gradle4/gradlew.bat delete mode 100755 initializr-generator/src/main/resources/project/maven/mvnw delete mode 100755 initializr-generator/src/main/resources/project/maven/mvnw.cmd delete mode 100755 initializr-generator/src/main/resources/project/maven/wrapper/maven-wrapper.jar delete mode 100755 initializr-generator/src/main/resources/project/maven/wrapper/maven-wrapper.properties delete mode 100644 initializr-generator/src/main/resources/templates/Application.groovy delete mode 100644 initializr-generator/src/main/resources/templates/Application.java delete mode 100644 initializr-generator/src/main/resources/templates/Application.kt delete mode 100644 initializr-generator/src/main/resources/templates/ApplicationTests.groovy delete mode 100644 initializr-generator/src/main/resources/templates/ApplicationTests.java delete mode 100644 initializr-generator/src/main/resources/templates/ApplicationTests.kt delete mode 100644 initializr-generator/src/main/resources/templates/ServletInitializer.groovy delete mode 100644 initializr-generator/src/main/resources/templates/ServletInitializer.java delete mode 100644 initializr-generator/src/main/resources/templates/ServletInitializer.kt delete mode 100644 initializr-generator/src/main/resources/templates/gitignore.tmpl delete mode 100644 initializr-generator/src/main/resources/templates/starter-build.gradle delete mode 100644 initializr-generator/src/main/resources/templates/starter-pom.xml delete mode 100644 initializr-generator/src/main/resources/templates/starter-settings.gradle delete mode 100755 initializr-generator/src/test/java/io/spring/initializr/generator/AbstractProjectGeneratorTests.java delete mode 100755 initializr-generator/src/test/java/io/spring/initializr/generator/CustomProjectGeneratorTests.java delete mode 100755 initializr-generator/src/test/java/io/spring/initializr/generator/ProjectGeneratorBuildTests.java delete mode 100755 initializr-generator/src/test/java/io/spring/initializr/generator/ProjectGeneratorLanguageTests.java delete mode 100755 initializr-generator/src/test/java/io/spring/initializr/generator/ProjectGeneratorTests.java delete mode 100755 initializr-generator/src/test/java/io/spring/initializr/generator/ProjectRequestResolverTests.java delete mode 100755 initializr-generator/src/test/java/io/spring/initializr/generator/ProjectRequestTests.java delete mode 100644 initializr-generator/src/test/java/io/spring/initializr/test/generator/GradleBuildAssert.java delete mode 100644 initializr-generator/src/test/java/io/spring/initializr/test/generator/GradleSettingsAssert.java delete mode 100644 initializr-generator/src/test/java/io/spring/initializr/test/generator/PomAssert.java delete mode 100644 initializr-generator/src/test/java/io/spring/initializr/test/generator/ProjectAssert.java delete mode 100644 initializr-generator/src/test/java/io/spring/initializr/test/generator/SourceCodeAssert.java delete mode 100644 initializr-generator/src/test/resources/project/custom/custom.txt delete mode 100644 initializr-generator/src/test/resources/project/gradle/annotation-processor-dependency-build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/gradle/bom-ordering-build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/gradle/bom-property-build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/gradle/compile-only-dependency-build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/gradle/gitignore.gen delete mode 100644 initializr-generator/src/test/resources/project/gradle/kotlin-java11-build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/gradle/repositories-build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/gradle/repositories-milestone-build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/gradle/version-override-build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/groovy/previous/DemoApplication.groovy.gen delete mode 100644 initializr-generator/src/test/resources/project/groovy/previous/ServletInitializer.groovy.gen delete mode 100644 initializr-generator/src/test/resources/project/groovy/previous/build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/groovy/previous/pom.xml.gen delete mode 100644 initializr-generator/src/test/resources/project/groovy/standard/DemoApplication.groovy.gen delete mode 100644 initializr-generator/src/test/resources/project/groovy/standard/DemoApplicationTests.groovy.gen delete mode 100644 initializr-generator/src/test/resources/project/groovy/standard/DemoApplicationTestsWeb.groovy.gen delete mode 100644 initializr-generator/src/test/resources/project/groovy/standard/ServletInitializer.groovy.gen delete mode 100644 initializr-generator/src/test/resources/project/groovy/standard/build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/groovy/standard/pom.xml.gen delete mode 100644 initializr-generator/src/test/resources/project/groovy/standard/war-build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/groovy/standard/war-pom.xml.gen delete mode 100644 initializr-generator/src/test/resources/project/java/previous/DemoApplication.java.gen delete mode 100644 initializr-generator/src/test/resources/project/java/previous/ServletInitializer.java.gen delete mode 100644 initializr-generator/src/test/resources/project/java/previous/build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/java/previous/pom.xml.gen delete mode 100644 initializr-generator/src/test/resources/project/java/standard/DemoApplication.java.gen delete mode 100644 initializr-generator/src/test/resources/project/java/standard/DemoApplicationTests.java.gen delete mode 100644 initializr-generator/src/test/resources/project/java/standard/DemoApplicationTestsWeb.java.gen delete mode 100644 initializr-generator/src/test/resources/project/java/standard/ServletInitializer.java.gen delete mode 100644 initializr-generator/src/test/resources/project/java/standard/build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/java/standard/pom.xml.gen delete mode 100644 initializr-generator/src/test/resources/project/java/standard/war-build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/java/standard/war-pom.xml.gen delete mode 100644 initializr-generator/src/test/resources/project/kotlin/previous/DemoApplication.kt.gen delete mode 100644 initializr-generator/src/test/resources/project/kotlin/previous/ServletInitializer.kt.gen delete mode 100644 initializr-generator/src/test/resources/project/kotlin/previous/build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/kotlin/previous/pom.xml.gen delete mode 100644 initializr-generator/src/test/resources/project/kotlin/standard/DemoApplication.kt.gen delete mode 100644 initializr-generator/src/test/resources/project/kotlin/standard/DemoApplicationTests.kt.gen delete mode 100644 initializr-generator/src/test/resources/project/kotlin/standard/DemoApplicationTestsWeb.kt.gen delete mode 100644 initializr-generator/src/test/resources/project/kotlin/standard/ServletInitializer.kt.gen delete mode 100644 initializr-generator/src/test/resources/project/kotlin/standard/build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/kotlin/standard/pom.xml.gen delete mode 100644 initializr-generator/src/test/resources/project/kotlin/standard/war-build.gradle.gen delete mode 100644 initializr-generator/src/test/resources/project/kotlin/standard/war-pom.xml.gen delete mode 100644 initializr-generator/src/test/resources/project/maven/annotation-processor-dependency-pom.xml.gen delete mode 100644 initializr-generator/src/test/resources/project/maven/bom-ordering-pom.xml.gen delete mode 100644 initializr-generator/src/test/resources/project/maven/bom-property-pom.xml.gen delete mode 100644 initializr-generator/src/test/resources/project/maven/compile-only-dependency-pom.xml.gen delete mode 100644 initializr-generator/src/test/resources/project/maven/gitignore.gen delete mode 100644 initializr-generator/src/test/resources/project/maven/kotlin-java11-pom.xml.gen delete mode 100644 initializr-generator/src/test/resources/project/maven/repositories-milestone-pom.xml.gen delete mode 100644 initializr-generator/src/test/resources/project/maven/repositories-pom.xml.gen delete mode 100644 initializr-generator/src/test/resources/project/maven/version-override-pom.xml.gen rename {initializr-generator/src/main/java/io/spring/initializr/generator => initializr-web/src/main/java/io/spring/initializr/web}/InvalidProjectRequestException.java (91%) rename {initializr-generator/src/main/java/io/spring/initializr/generator => initializr-web/src/main/java/io/spring/initializr/web}/ProjectResourceLocator.java (95%) rename {initializr-generator/src/main/java/io/spring/initializr/generator => initializr-web/src/main/java/io/spring/initializr/web/project}/ProjectFailedEvent.java (82%) rename {initializr-generator/src/main/java/io/spring/initializr/generator => initializr-web/src/main/java/io/spring/initializr/web/project}/ProjectGeneratedEvent.java (78%) create mode 100644 initializr-web/src/main/java/io/spring/initializr/web/project/ProjectGenerationInvoker.java rename initializr-generator/src/main/java/io/spring/initializr/generator/BasicProjectRequest.java => initializr-web/src/main/java/io/spring/initializr/web/project/ProjectRequest.java (96%) rename {initializr-generator/src/main/java/io/spring/initializr/generator => initializr-web/src/main/java/io/spring/initializr/web/project}/ProjectRequestEvent.java (83%) create mode 100644 initializr-web/src/main/java/io/spring/initializr/web/project/ProjectRequestToDescriptionConverter.java create mode 100644 initializr-web/src/main/java/io/spring/initializr/web/project/WebProjectRequest.java rename initializr-web/src/test/java/io/spring/initializr/web/project/{ProjectGenerationPostProcessorTests.java => ProjectGenerationDescriptionCustomizerTests.java} (52%) create mode 100644 initializr-web/src/test/java/io/spring/initializr/web/project/ProjectGenerationInvokerTests.java create mode 100644 initializr-web/src/test/java/io/spring/initializr/web/project/ProjectRequestToDescriptionConverterTests.java diff --git a/.gitignore b/.gitignore index 9c644a14..f0d3e23c 100644 --- a/.gitignore +++ b/.gitignore @@ -13,7 +13,6 @@ .factorypath *.iml bin -build target .springBeans .vscode/ diff --git a/initializr-actuator/pom.xml b/initializr-actuator/pom.xml index 37958ffa..a2633c82 100644 --- a/initializr-actuator/pom.xml +++ b/initializr-actuator/pom.xml @@ -19,7 +19,10 @@ io.spring.initializr initializr-generator - + + io.spring.initializr + initializr-web + org.springframework.boot spring-boot-autoconfigure @@ -75,11 +78,6 @@ test-jar test - - io.spring.initializr - initializr-web - test - io.spring.initializr initializr-web diff --git a/initializr-actuator/src/main/java/io/spring/initializr/actuate/stat/ProjectGenerationStatPublisher.java b/initializr-actuator/src/main/java/io/spring/initializr/actuate/stat/ProjectGenerationStatPublisher.java index 8f367c96..aecf55af 100644 --- a/initializr-actuator/src/main/java/io/spring/initializr/actuate/stat/ProjectGenerationStatPublisher.java +++ b/initializr-actuator/src/main/java/io/spring/initializr/actuate/stat/ProjectGenerationStatPublisher.java @@ -23,7 +23,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.spring.initializr.actuate.stat.StatsProperties.Elastic; -import io.spring.initializr.generator.ProjectRequestEvent; +import io.spring.initializr.web.project.ProjectRequestEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/initializr-actuator/src/main/java/io/spring/initializr/actuate/stat/ProjectRequestDocumentFactory.java b/initializr-actuator/src/main/java/io/spring/initializr/actuate/stat/ProjectRequestDocumentFactory.java index d9798680..41513663 100644 --- a/initializr-actuator/src/main/java/io/spring/initializr/actuate/stat/ProjectRequestDocumentFactory.java +++ b/initializr-actuator/src/main/java/io/spring/initializr/actuate/stat/ProjectRequestDocumentFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,12 +24,13 @@ import io.spring.initializr.actuate.stat.ProjectRequestDocument.ClientInformatio import io.spring.initializr.actuate.stat.ProjectRequestDocument.DependencyInformation; import io.spring.initializr.actuate.stat.ProjectRequestDocument.ErrorStateInformation; import io.spring.initializr.actuate.stat.ProjectRequestDocument.VersionInformation; -import io.spring.initializr.generator.ProjectFailedEvent; -import io.spring.initializr.generator.ProjectRequest; -import io.spring.initializr.generator.ProjectRequestEvent; import io.spring.initializr.metadata.InitializrMetadata; import io.spring.initializr.util.Agent; import io.spring.initializr.util.Version; +import io.spring.initializr.web.project.ProjectFailedEvent; +import io.spring.initializr.web.project.ProjectRequest; +import io.spring.initializr.web.project.ProjectRequestEvent; +import io.spring.initializr.web.project.WebProjectRequest; import org.springframework.util.StringUtils; @@ -43,7 +44,6 @@ public class ProjectRequestDocumentFactory { public ProjectRequestDocument createDocument(ProjectRequestEvent event) { InitializrMetadata metadata = event.getMetadata(); ProjectRequest request = event.getProjectRequest(); - ProjectRequestDocument document = new ProjectRequestDocument(); document.setGenerationTimestamp(event.getTimestamp()); document.setGroupId(request.getGroupId()); @@ -118,16 +118,19 @@ public class ProjectRequestDocumentFactory { } private ClientInformation determineClientInformation(ProjectRequest request) { - Agent agent = determineAgent(request); - String ip = determineIp(request); - String country = determineCountry(request); - if (agent != null || ip != null || country != null) { - return new ClientInformation(agent, ip, country); + if (request instanceof WebProjectRequest) { + WebProjectRequest webProjectRequest = (WebProjectRequest) request; + Agent agent = determineAgent(webProjectRequest); + String ip = determineIp(webProjectRequest); + String country = determineCountry(webProjectRequest); + if (agent != null || ip != null || country != null) { + return new ClientInformation(agent, ip, country); + } } return null; } - private Agent determineAgent(ProjectRequest request) { + private Agent determineAgent(WebProjectRequest request) { String userAgent = (String) request.getParameters().get("user-agent"); if (StringUtils.hasText(userAgent)) { return Agent.fromUserAgent(userAgent); @@ -135,13 +138,13 @@ public class ProjectRequestDocumentFactory { return null; } - private String determineIp(ProjectRequest request) { + private String determineIp(WebProjectRequest request) { String candidate = (String) request.getParameters().get("cf-connecting-ip"); return (StringUtils.hasText(candidate)) ? candidate : (String) request.getParameters().get("x-forwarded-for"); } - private String determineCountry(ProjectRequest request) { + private String determineCountry(WebProjectRequest request) { String candidate = (String) request.getParameters().get("cf-ipcountry"); if (StringUtils.hasText(candidate) && !"xx".equalsIgnoreCase(candidate)) { return candidate; diff --git a/initializr-actuator/src/test/java/io/spring/initializr/actuate/stat/AbstractInitializrStatTests.java b/initializr-actuator/src/test/java/io/spring/initializr/actuate/stat/AbstractInitializrStatTests.java deleted file mode 100755 index 19eca313..00000000 --- a/initializr-actuator/src/test/java/io/spring/initializr/actuate/stat/AbstractInitializrStatTests.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.actuate.stat; - -import io.spring.initializr.generator.ProjectRequest; -import io.spring.initializr.metadata.InitializrMetadata; -import io.spring.initializr.metadata.InitializrMetadataProvider; -import io.spring.initializr.metadata.SimpleInitializrMetadataProvider; -import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder; - -/** - * @author Stephane Nicoll - */ -abstract class AbstractInitializrStatTests { - - private final InitializrMetadata metadata = InitializrMetadataTestBuilder - .withDefaults().addDependencyGroup("core", "security", "validation", "aop") - .addDependencyGroup("web", "web", "data-rest", "jersey") - .addDependencyGroup("data", "data-jpa", "jdbc") - .addDependencyGroup("database", "h2", "mysql").build(); - - protected InitializrMetadataProvider createProvider(InitializrMetadata metadata) { - return new SimpleInitializrMetadataProvider(metadata); - } - - protected ProjectRequest createProjectRequest() { - ProjectRequest request = new ProjectRequest(); - request.initialize(this.metadata); - return request; - } - - public InitializrMetadata getMetadata() { - return this.metadata; - } - -} diff --git a/initializr-actuator/src/test/java/io/spring/initializr/actuate/stat/ProjectGenerationStatPublisherTests.java b/initializr-actuator/src/test/java/io/spring/initializr/actuate/stat/ProjectGenerationStatPublisherTests.java index 289531cb..40b33de0 100755 --- a/initializr-actuator/src/test/java/io/spring/initializr/actuate/stat/ProjectGenerationStatPublisherTests.java +++ b/initializr-actuator/src/test/java/io/spring/initializr/actuate/stat/ProjectGenerationStatPublisherTests.java @@ -26,8 +26,11 @@ import java.util.Collections; import java.util.UUID; import io.spring.initializr.actuate.stat.StatsProperties.Elastic; -import io.spring.initializr.generator.ProjectGeneratedEvent; -import io.spring.initializr.generator.ProjectRequest; +import io.spring.initializr.metadata.InitializrMetadata; +import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder; +import io.spring.initializr.web.project.ProjectGeneratedEvent; +import io.spring.initializr.web.project.ProjectRequest; +import io.spring.initializr.web.project.WebProjectRequest; import org.json.JSONException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -59,7 +62,13 @@ import static org.springframework.test.web.client.response.MockRestResponseCreat * * @author Stephane Nicoll */ -class ProjectGenerationStatPublisherTests extends AbstractInitializrStatTests { +class ProjectGenerationStatPublisherTests { + + private final InitializrMetadata metadata = InitializrMetadataTestBuilder + .withDefaults().addDependencyGroup("core", "security", "validation", "aop") + .addDependencyGroup("web", "web", "data-rest", "jersey") + .addDependencyGroup("data", "data-jpa", "jdbc") + .addDependencyGroup("database", "h2", "mysql").build(); private RetryTemplate retryTemplate; @@ -132,13 +141,13 @@ class ProjectGenerationStatPublisherTests extends AbstractInitializrStatTests { .andRespond(withStatus(HttpStatus.CREATED) .body(mockResponse(UUID.randomUUID().toString(), true)) .contentType(MediaType.APPLICATION_JSON)); - this.statPublisher.handleEvent(createProjectGeneratedEvent(request)); + handleEvent(request); this.mockServer.verify(); } @Test void publishDocument() { - ProjectRequest request = createProjectRequest(); + WebProjectRequest request = createProjectRequest(); request.setGroupId("com.example.acme"); request.setArtifactId("project"); request.setType("maven-project"); @@ -156,7 +165,7 @@ class ProjectGenerationStatPublisherTests extends AbstractInitializrStatTests { .body(mockResponse(UUID.randomUUID().toString(), true)) .contentType(MediaType.APPLICATION_JSON)); - this.statPublisher.handleEvent(createProjectGeneratedEvent(request)); + handleEvent(request); this.mockServer.verify(); } @@ -177,7 +186,7 @@ class ProjectGenerationStatPublisherTests extends AbstractInitializrStatTests { .body(mockResponse(UUID.randomUUID().toString(), true)) .contentType(MediaType.APPLICATION_JSON)); - this.statPublisher.handleEvent(createProjectGeneratedEvent(request)); + handleEvent(request); this.mockServer.verify(); } @@ -198,7 +207,7 @@ class ProjectGenerationStatPublisherTests extends AbstractInitializrStatTests { .body(mockResponse(UUID.randomUUID().toString(), true)) .contentType(MediaType.APPLICATION_JSON)); - this.statPublisher.handleEvent(createProjectGeneratedEvent(request)); + handleEvent(request); this.mockServer.verify(); } @@ -219,7 +228,7 @@ class ProjectGenerationStatPublisherTests extends AbstractInitializrStatTests { .body(mockResponse(UUID.randomUUID().toString(), true)) .contentType(MediaType.APPLICATION_JSON)); - this.statPublisher.handleEvent(createProjectGeneratedEvent(request)); + handleEvent(request); this.mockServer.verify(); } @@ -241,7 +250,7 @@ class ProjectGenerationStatPublisherTests extends AbstractInitializrStatTests { .body(mockResponse(UUID.randomUUID().toString(), true)) .contentType(MediaType.APPLICATION_JSON)); - this.statPublisher.handleEvent(createProjectGeneratedEvent(request)); + handleEvent(request); this.mockServer.verify(); } @@ -262,7 +271,7 @@ class ProjectGenerationStatPublisherTests extends AbstractInitializrStatTests { .body(mockResponse(UUID.randomUUID().toString(), true)) .contentType(MediaType.APPLICATION_JSON)); - this.statPublisher.handleEvent(createProjectGeneratedEvent(request)); + handleEvent(request); this.mockServer.verify(); } @@ -284,7 +293,7 @@ class ProjectGenerationStatPublisherTests extends AbstractInitializrStatTests { .body(mockResponse(UUID.randomUUID().toString(), true)) .contentType(MediaType.APPLICATION_JSON)); - this.statPublisher.handleEvent(createProjectGeneratedEvent(request)); + handleEvent(request); this.mockServer.verify(); } @@ -302,12 +311,18 @@ class ProjectGenerationStatPublisherTests extends AbstractInitializrStatTests { .andExpect(method(HttpMethod.POST)) .andRespond(withStatus(HttpStatus.INTERNAL_SERVER_ERROR)); - this.statPublisher.handleEvent(createProjectGeneratedEvent(request)); + handleEvent(request); this.mockServer.verify(); } - private ProjectGeneratedEvent createProjectGeneratedEvent(ProjectRequest request) { - return new ProjectGeneratedEvent(request, getMetadata()); + private WebProjectRequest createProjectRequest() { + WebProjectRequest request = new WebProjectRequest(); + request.initialize(this.metadata); + return request; + } + + private void handleEvent(ProjectRequest request) { + this.statPublisher.handleEvent(new ProjectGeneratedEvent(request, this.metadata)); } private static String mockResponse(String id, boolean created) { diff --git a/initializr-actuator/src/test/java/io/spring/initializr/actuate/stat/ProjectRequestDocumentFactoryTests.java b/initializr-actuator/src/test/java/io/spring/initializr/actuate/stat/ProjectRequestDocumentFactoryTests.java index 53643c97..6073307d 100755 --- a/initializr-actuator/src/test/java/io/spring/initializr/actuate/stat/ProjectRequestDocumentFactoryTests.java +++ b/initializr-actuator/src/test/java/io/spring/initializr/actuate/stat/ProjectRequestDocumentFactoryTests.java @@ -18,9 +18,12 @@ package io.spring.initializr.actuate.stat; import java.util.Arrays; -import io.spring.initializr.generator.ProjectFailedEvent; -import io.spring.initializr.generator.ProjectGeneratedEvent; -import io.spring.initializr.generator.ProjectRequest; +import io.spring.initializr.metadata.InitializrMetadata; +import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder; +import io.spring.initializr.web.project.ProjectFailedEvent; +import io.spring.initializr.web.project.ProjectGeneratedEvent; +import io.spring.initializr.web.project.ProjectRequest; +import io.spring.initializr.web.project.WebProjectRequest; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; @@ -30,7 +33,13 @@ import static org.assertj.core.api.Assertions.assertThat; * * @author Stephane Nicoll */ -class ProjectRequestDocumentFactoryTests extends AbstractInitializrStatTests { +class ProjectRequestDocumentFactoryTests { + + private final InitializrMetadata metadata = InitializrMetadataTestBuilder + .withDefaults().addDependencyGroup("core", "security", "validation", "aop") + .addDependencyGroup("web", "web", "data-rest", "jersey") + .addDependencyGroup("data", "data-jpa", "jdbc") + .addDependencyGroup("database", "h2", "mysql").build(); private final ProjectRequestDocumentFactory factory = new ProjectRequestDocumentFactory(); @@ -58,9 +67,19 @@ class ProjectRequestDocumentFactoryTests extends AbstractInitializrStatTests { assertThat(document.getVersion().getMinor()).isEqualTo("2.1"); } + @Test + void createDocumentWithNonWebProjectRequest() { + ProjectRequest request = new ProjectRequest(); + request.setBootVersion("2.1.0.RELEASE"); + request.setType("maven-build"); + ProjectGeneratedEvent event = createProjectGeneratedEvent(request); + ProjectRequestDocument document = this.factory.createDocument(event); + assertThat(document.getClient()).isNull(); + } + @Test void createDocumentWithRequestIp() { - ProjectRequest request = createProjectRequest(); + WebProjectRequest request = createProjectRequest(); request.getParameters().put("x-forwarded-for", "10.0.0.123"); ProjectGeneratedEvent event = createProjectGeneratedEvent(request); ProjectRequestDocument document = this.factory.createDocument(event); @@ -70,7 +89,7 @@ class ProjectRequestDocumentFactoryTests extends AbstractInitializrStatTests { @Test void createDocumentWithRequestIpv6() { - ProjectRequest request = createProjectRequest(); + WebProjectRequest request = createProjectRequest(); request.getParameters().put("x-forwarded-for", "2001:db8:a0b:12f0::1"); ProjectGeneratedEvent event = createProjectGeneratedEvent(request); ProjectRequestDocument document = this.factory.createDocument(event); @@ -80,7 +99,7 @@ class ProjectRequestDocumentFactoryTests extends AbstractInitializrStatTests { @Test void createDocumentWithCloudFlareHeaders() { - ProjectRequest request = createProjectRequest(); + WebProjectRequest request = createProjectRequest(); request.getParameters().put("cf-connecting-ip", "10.0.0.123"); request.getParameters().put("cf-ipcountry", "BE"); ProjectGeneratedEvent event = createProjectGeneratedEvent(request); @@ -91,7 +110,7 @@ class ProjectRequestDocumentFactoryTests extends AbstractInitializrStatTests { @Test void createDocumentWithCloudFlareIpv6() { - ProjectRequest request = createProjectRequest(); + WebProjectRequest request = createProjectRequest(); request.getParameters().put("cf-connecting-ip", "2001:db8:a0b:12f0::1"); ProjectGeneratedEvent event = createProjectGeneratedEvent(request); ProjectRequestDocument document = this.factory.createDocument(event); @@ -101,7 +120,7 @@ class ProjectRequestDocumentFactoryTests extends AbstractInitializrStatTests { @Test void createDocumentWithCloudFlareHeadersAndOtherHeaders() { - ProjectRequest request = createProjectRequest(); + WebProjectRequest request = createProjectRequest(); request.getParameters().put("cf-connecting-ip", "10.0.0.123"); request.getParameters().put("x-forwarded-for", "192.168.1.101"); ProjectGeneratedEvent event = createProjectGeneratedEvent(request); @@ -112,7 +131,7 @@ class ProjectRequestDocumentFactoryTests extends AbstractInitializrStatTests { @Test void createDocumentWithCloudFlareCountrySetToXX() { - ProjectRequest request = createProjectRequest(); + WebProjectRequest request = createProjectRequest(); request.getParameters().put("cf-connecting-ip", "Xx"); // case insensitive ProjectGeneratedEvent event = createProjectGeneratedEvent(request); ProjectRequestDocument document = this.factory.createDocument(event); @@ -121,7 +140,7 @@ class ProjectRequestDocumentFactoryTests extends AbstractInitializrStatTests { @Test void createDocumentWithUserAgent() { - ProjectRequest request = createProjectRequest(); + WebProjectRequest request = createProjectRequest(); request.getParameters().put("user-agent", "HTTPie/0.8.0"); ProjectGeneratedEvent event = createProjectGeneratedEvent(request); ProjectRequestDocument document = this.factory.createDocument(event); @@ -131,7 +150,7 @@ class ProjectRequestDocumentFactoryTests extends AbstractInitializrStatTests { @Test void createDocumentWithUserAgentNoVersion() { - ProjectRequest request = createProjectRequest(); + WebProjectRequest request = createProjectRequest(); request.getParameters().put("user-agent", "IntelliJ IDEA"); ProjectGeneratedEvent event = createProjectGeneratedEvent(request); ProjectRequestDocument document = this.factory.createDocument(event); @@ -221,7 +240,7 @@ class ProjectRequestDocumentFactoryTests extends AbstractInitializrStatTests { @Test void createDocumentWithProjectFailedEvent() { ProjectRequest request = createProjectRequest(); - ProjectFailedEvent event = new ProjectFailedEvent(request, getMetadata(), + ProjectFailedEvent event = new ProjectFailedEvent(request, this.metadata, new IllegalStateException("my test message")); ProjectRequestDocument document = this.factory.createDocument(event); assertThat(document.getErrorState().isInvalid()).isTrue(); @@ -233,8 +252,14 @@ class ProjectRequestDocumentFactoryTests extends AbstractInitializrStatTests { assertThat(document.getErrorState().getMessage()).isEqualTo("my test message"); } + private WebProjectRequest createProjectRequest() { + WebProjectRequest request = new WebProjectRequest(); + request.initialize(this.metadata); + return request; + } + private ProjectGeneratedEvent createProjectGeneratedEvent(ProjectRequest request) { - return new ProjectGeneratedEvent(request, getMetadata()); + return new ProjectGeneratedEvent(request, this.metadata); } } diff --git a/initializr-generator/pom.xml b/initializr-generator/pom.xml index e6607e6a..3afd7c85 100644 --- a/initializr-generator/pom.xml +++ b/initializr-generator/pom.xml @@ -14,6 +14,10 @@ + + io.spring.initializr.experimental + initializr-generator-spring + org.springframework.boot spring-boot @@ -38,6 +42,12 @@ true + + io.spring.initializr.experimental + initializr-generator + test + test-jar + org.junit.jupiter junit-jupiter diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/BuildProperties.java b/initializr-generator/src/main/java/io/spring/initializr/generator/BuildProperties.java deleted file mode 100644 index 68cad7e9..00000000 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/BuildProperties.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2012-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.generator; - -import java.util.Map; -import java.util.TreeMap; -import java.util.function.Supplier; - -import io.spring.initializr.util.VersionProperty; - -/** - * Build properties associated to a project request. - * - * @author Stephane Nicoll - */ -public class BuildProperties { - - /** - * Maven-specific build properties, added to the regular {@code properties} element. - */ - private final TreeMap> maven = new TreeMap<>(); - - /** - * Gradle-specific build properties, added to the {@code buildscript} section of the - * gradle build. - */ - private final TreeMap> gradle = new TreeMap<>(); - - /** - * Version properties. Shared between the two build systems. - */ - private final TreeMap> versions = new TreeMap<>(); - - public Map> getMaven() { - return this.maven; - } - - public Map> getGradle() { - return this.gradle; - } - - public Map> getVersions() { - return this.versions; - } - -} diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectGenerator.java b/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectGenerator.java deleted file mode 100644 index dd98a048..00000000 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectGenerator.java +++ /dev/null @@ -1,758 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.generator; - -import java.beans.PropertyDescriptor; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import io.spring.initializr.InitializrException; -import io.spring.initializr.metadata.BillOfMaterials; -import io.spring.initializr.metadata.Dependency; -import io.spring.initializr.metadata.InitializrConfiguration.Env.Maven; -import io.spring.initializr.metadata.InitializrConfiguration.Env.Maven.ParentPom; -import io.spring.initializr.metadata.InitializrMetadata; -import io.spring.initializr.metadata.InitializrMetadataProvider; -import io.spring.initializr.util.TemplateRenderer; -import io.spring.initializr.util.Version; -import io.spring.initializr.util.VersionProperty; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import org.springframework.beans.BeanWrapperImpl; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.util.Assert; -import org.springframework.util.FileSystemUtils; -import org.springframework.util.StreamUtils; - -/** - * Generate a project based on the configured metadata. - * - * @author Dave Syer - * @author Stephane Nicoll - * @author Sebastien Deleuze - * @author Andy Wilkinson - * @author Chris Vogel - */ -public class ProjectGenerator { - - private static final Logger log = LoggerFactory.getLogger(ProjectGenerator.class); - - private static final Version VERSION_1_5_0 = Version.parse("1.5.0.RELEASE"); - - private static final Version VERSION_2_0_0 = Version.parse("2.0.0.RELEASE"); - - @Autowired - private ApplicationEventPublisher eventPublisher; - - @Autowired - private InitializrMetadataProvider metadataProvider; - - @Autowired - private ProjectRequestResolver requestResolver; - - @Autowired - private TemplateRenderer templateRenderer = new TemplateRenderer(); - - @Autowired - private ProjectResourceLocator projectResourceLocator = new ProjectResourceLocator(); - - @Value("${TMPDIR:.}/initializr") - private String tmpdir; - - private File temporaryDirectory; - - private transient Map> temporaryFiles = new LinkedHashMap<>(); - - public InitializrMetadataProvider getMetadataProvider() { - return this.metadataProvider; - } - - public void setEventPublisher(ApplicationEventPublisher eventPublisher) { - this.eventPublisher = eventPublisher; - } - - public void setMetadataProvider(InitializrMetadataProvider metadataProvider) { - this.metadataProvider = metadataProvider; - } - - public void setRequestResolver(ProjectRequestResolver requestResolver) { - this.requestResolver = requestResolver; - } - - public void setTemplateRenderer(TemplateRenderer templateRenderer) { - this.templateRenderer = templateRenderer; - } - - public void setProjectResourceLocator(ProjectResourceLocator projectResourceLocator) { - this.projectResourceLocator = projectResourceLocator; - } - - public void setTmpdir(String tmpdir) { - this.tmpdir = tmpdir; - } - - public void setTemporaryDirectory(File temporaryDirectory) { - this.temporaryDirectory = temporaryDirectory; - } - - public void setTemporaryFiles(Map> temporaryFiles) { - this.temporaryFiles = temporaryFiles; - } - - /** - * Generate a Maven pom for the specified {@link ProjectRequest}. - * @param request the project request - * @return the Maven POM - */ - public byte[] generateMavenPom(ProjectRequest request) { - InitializrMetadata metadata = this.metadataProvider.get(); - try { - Map model = resolveModel(request, metadata); - if (!isMavenBuild(request)) { - throw new InvalidProjectRequestException("Could not generate Maven pom, " - + "invalid project type " + request.getType()); - } - byte[] content = doGenerateMavenPom(model); - publishProjectGeneratedEvent(request, metadata); - return content; - } - catch (InitializrException ex) { - publishProjectFailedEvent(request, metadata, ex); - throw ex; - } - } - - /** - * Generate a Gradle build file for the specified {@link ProjectRequest}. - * @param request the project request - * @return the gradle build - */ - public byte[] generateGradleBuild(ProjectRequest request) { - InitializrMetadata metadata = this.metadataProvider.get(); - try { - Map model = resolveModel(request, metadata); - if (!isGradleBuild(request)) { - throw new InvalidProjectRequestException( - "Could not generate Gradle build, " + "invalid project type " - + request.getType()); - } - byte[] content = doGenerateGradleBuild(model); - publishProjectGeneratedEvent(request, metadata); - return content; - } - catch (InitializrException ex) { - publishProjectFailedEvent(request, metadata, ex); - throw ex; - } - } - - /** - * Generate a project structure for the specified {@link ProjectRequest}. Returns a - * directory containing the project. - * @param request the project request - * @return the generated project structure - */ - public File generateProjectStructure(ProjectRequest request) { - InitializrMetadata metadata = this.metadataProvider.get(); - try { - Map model = resolveModel(request, metadata); - File rootDir = generateProjectStructure(request, model); - publishProjectGeneratedEvent(request, metadata); - return rootDir; - } - catch (InitializrException ex) { - publishProjectFailedEvent(request, metadata, ex); - throw ex; - } - } - - /** - * Generate a project structure for the specified {@link ProjectRequest} and resolved - * model. - * @param request the project request - * @param model the source model - * @return the generated project structure - */ - protected File generateProjectStructure(ProjectRequest request, - Map model) { - File rootDir; - try { - rootDir = File.createTempFile("tmp", "", getTemporaryDirectory()); - } - catch (IOException ex) { - throw new IllegalStateException("Cannot create temp dir", ex); - } - addTempFile(rootDir.getName(), rootDir); - rootDir.delete(); - rootDir.mkdirs(); - - File dir = initializerProjectDir(rootDir, request); - - if (isGradleBuild(request)) { - String gradle = new String(doGenerateGradleBuild(model)); - writeText(new File(dir, "build.gradle"), gradle); - String settings = new String(doGenerateGradleSettings(model)); - writeText(new File(dir, "settings.gradle"), settings); - writeGradleWrapper(dir, Version.safeParse(request.getBootVersion())); - } - else { - String pom = new String(doGenerateMavenPom(model)); - writeText(new File(dir, "pom.xml"), pom); - writeMavenWrapper(dir); - } - - generateGitIgnore(dir, request); - - String applicationName = request.getApplicationName(); - String language = request.getLanguage(); - - String codeLocation = language; - File src = new File(new File(dir, "src/main/" + codeLocation), - request.getPackageName().replace(".", "/")); - src.mkdirs(); - String extension = ("kotlin".equals(language) ? "kt" : language); - write(new File(src, applicationName + "." + extension), - "Application." + extension, model); - - if ("war".equals(request.getPackaging())) { - String fileName = "ServletInitializer." + extension; - write(new File(src, fileName), fileName, model); - } - - File test = new File(new File(dir, "src/test/" + codeLocation), - request.getPackageName().replace(".", "/")); - test.mkdirs(); - setupTestModel(request, model); - write(new File(test, applicationName + "Tests." + extension), - "ApplicationTests." + extension, model); - - File resources = new File(dir, "src/main/resources"); - resources.mkdirs(); - writeText(new File(resources, "application.properties"), ""); - - if (request.hasWebFacet()) { - new File(dir, "src/main/resources/templates").mkdirs(); - new File(dir, "src/main/resources/static").mkdirs(); - } - return rootDir; - } - - /** - * Create a distribution file for the specified project structure directory and - * extension. - * @param dir the directory - * @param extension the file extension - * @return the distribution file - */ - public File createDistributionFile(File dir, String extension) { - File download = new File(getTemporaryDirectory(), dir.getName() + extension); - addTempFile(dir.getName(), download); - return download; - } - - private File getTemporaryDirectory() { - if (this.temporaryDirectory == null) { - this.temporaryDirectory = new File(this.tmpdir, "initializr"); - this.temporaryDirectory.mkdirs(); - } - return this.temporaryDirectory; - } - - /** - * Clean all the temporary files that are related to this root directory. - * @param dir the directory to clean - * @see #createDistributionFile - */ - public void cleanTempFiles(File dir) { - List tempFiles = this.temporaryFiles.remove(dir.getName()); - if (!tempFiles.isEmpty()) { - tempFiles.forEach((File file) -> { - if (file.isDirectory()) { - FileSystemUtils.deleteRecursively(file); - } - else if (file.exists()) { - file.delete(); - } - }); - } - } - - private void publishProjectGeneratedEvent(ProjectRequest request, - InitializrMetadata metadata) { - ProjectGeneratedEvent event = new ProjectGeneratedEvent(request, metadata); - this.eventPublisher.publishEvent(event); - } - - private void publishProjectFailedEvent(ProjectRequest request, - InitializrMetadata metadata, Exception cause) { - ProjectFailedEvent event = new ProjectFailedEvent(request, metadata, cause); - this.eventPublisher.publishEvent(event); - } - - /** - * Generate a {@code .gitignore} file for the specified {@link ProjectRequest}. - * @param dir the root directory of the project - * @param request the request to handle - */ - protected void generateGitIgnore(File dir, ProjectRequest request) { - Map model = new LinkedHashMap<>(); - if (isMavenBuild(request)) { - model.put("build", "maven"); - model.put("mavenBuild", true); - } - else { - model.put("build", "gradle"); - } - write(new File(dir, ".gitignore"), "gitignore.tmpl", model); - } - - /** - * Resolve the specified {@link ProjectRequest} and return the model to use to - * generate the project. - * @param originalRequest the request to handle - * @param metadata the initializr metadata - * @return a model for that request - */ - protected Map resolveModel(ProjectRequest originalRequest, - InitializrMetadata metadata) { - Assert.notNull(originalRequest.getBootVersion(), "boot version must not be null"); - Map model = new LinkedHashMap<>(); - - ProjectRequest request = this.requestResolver.resolve(originalRequest, metadata); - - // request resolved so we can log what has been requested - Version bootVersion = Version.safeParse(request.getBootVersion()); - if (bootVersion.compareTo(VERSION_1_5_0) < 0) { - throw new InvalidProjectRequestException("Invalid Spring Boot version " - + bootVersion + " must be 1.5.0 or higher"); - } - - List dependencies = request.getResolvedDependencies(); - List dependencyIds = dependencies.stream().map(Dependency::getId) - .collect(Collectors.toList()); - log.info("Processing request{type=" + request.getType() + ", dependencies=" - + dependencyIds); - - if (isWar(request)) { - model.put("war", true); - } - - // Kotlin supported as of 2.0 - final boolean kotlinSupport = VERSION_2_0_0.compareTo(bootVersion) <= 0; - model.put("kotlinSupport", kotlinSupport); - - if (isMavenBuild(request)) { - model.put("mavenBuild", true); - Maven maven = metadata.getConfiguration().getEnv().getMaven(); - ParentPom parentPom = maven.resolveParentPom(request.getBootVersion()); - if (parentPom.isIncludeSpringBootBom() - && !request.getBoms().containsKey("spring-boot")) { - request.getBoms().put("spring-boot", metadata.createSpringBootBom( - request.getBootVersion(), "spring-boot.version")); - } - if (!maven.isSpringBootStarterParent(parentPom)) { - request.getBuildProperties().getMaven() - .put("project.build.sourceEncoding", () -> "UTF-8"); - request.getBuildProperties().getMaven() - .put("project.reporting.outputEncoding", () -> "UTF-8"); - } - model.put("mavenParentGroupId", parentPom.getGroupId()); - model.put("mavenParentArtifactId", parentPom.getArtifactId()); - model.put("mavenParentVersion", parentPom.getVersion()); - model.put("includeSpringBootBom", parentPom.isIncludeSpringBootBom()); - model.put("defaultPackaging", "jar".equals(request.getPackaging())); - } - - model.put("repositoryValues", request.getRepositories().entrySet()); - if (!request.getRepositories().isEmpty()) { - model.put("hasRepositories", true); - } - - List> resolvedBoms = buildResolvedBoms(request); - model.put("resolvedBoms", resolvedBoms); - ArrayList> reversedBoms = new ArrayList<>(resolvedBoms); - Collections.reverse(reversedBoms); - model.put("reversedBoms", reversedBoms); - - model.put("compileDependencies", - filterDependencies(dependencies, Dependency.SCOPE_COMPILE)); - model.put("runtimeDependencies", - filterDependencies(dependencies, Dependency.SCOPE_RUNTIME)); - model.put("compileOnlyDependencies", - filterDependencies(dependencies, Dependency.SCOPE_COMPILE_ONLY)); - model.put("annotationProcessorDependencies", - filterDependencies(dependencies, Dependency.SCOPE_ANNOTATION_PROCESSOR)); - model.put("providedDependencies", - filterDependencies(dependencies, Dependency.SCOPE_PROVIDED)); - model.put("testDependencies", - filterDependencies(dependencies, Dependency.SCOPE_TEST)); - - request.getBoms().forEach((k, v) -> { - if (v.getVersionProperty() != null) { - request.getBuildProperties().getVersions() - .computeIfAbsent(v.getVersionProperty(), (key) -> v::getVersion); - } - }); - - Map versions = new LinkedHashMap<>(); - model.put("buildPropertiesVersions", versions.entrySet()); - request.getBuildProperties().getVersions().forEach( - (k, v) -> versions.put(computeVersionProperty(request, k), v.get())); - if (!versions.isEmpty()) { - model.put("hasBuildPropertiesVersions", true); - } - Map gradle = new LinkedHashMap<>(); - model.put("buildPropertiesGradle", gradle.entrySet()); - request.getBuildProperties().getGradle() - .forEach((k, v) -> gradle.put(k, v.get())); - Map maven = new LinkedHashMap<>(); - model.put("buildPropertiesMaven", maven.entrySet()); - request.getBuildProperties().getMaven().forEach((k, v) -> maven.put(k, v.get())); - - // Add various versions - model.put("dependencyManagementPluginVersion", metadata.getConfiguration() - .getEnv().getGradle().getDependencyManagementPluginVersion()); - if ("kotlin".equals(request.getLanguage())) { - model.put("kotlinVersion", metadata.getConfiguration().getEnv().getKotlin() - .resolveKotlinVersion(bootVersion)); - model.put("kotlin", true); - } - if ("groovy".equals(request.getLanguage())) { - model.put("groovy", true); - } - - model.put("isRelease", request.getBootVersion().contains("RELEASE")); - setupApplicationModel(request, model); - - final boolean bootTwoZeroAvailable = VERSION_2_0_0.compareTo(bootVersion) <= 0; - model.put("bootTwoZeroAvailable", bootTwoZeroAvailable); - - // Servlet Initializer - model.put("servletInitializrImport", new Imports(request.getLanguage()) - .add(getServletInitializrClass(request)).toString()); - - // Kotlin-specific dep - model.put("kotlinStdlibArtifactId", "kotlin-stdlib-jdk8"); - - // Java versions - model.put("java8OrLater", isJava8OrLater(request)); - - // Facets - request.getFacets().forEach((facet) -> model.put("facets." + facet, true)); - - // Append the project request to the model - BeanWrapperImpl bean = new BeanWrapperImpl(request); - for (PropertyDescriptor descriptor : bean.getPropertyDescriptors()) { - if (bean.isReadableProperty(descriptor.getName())) { - model.put(descriptor.getName(), - bean.getPropertyValue(descriptor.getName())); - } - } - if (!request.getBoms().isEmpty()) { - model.put("hasBoms", true); - } - - return model; - } - - private List> buildResolvedBoms(ProjectRequest request) { - return request.getBoms().values().stream() - .sorted(Comparator.comparing(BillOfMaterials::getOrder)) - .map((bom) -> toBomModel(request, bom)).collect(Collectors.toList()); - } - - private Map toBomModel(ProjectRequest request, BillOfMaterials bom) { - Map model = new HashMap<>(); - model.put("groupId", bom.getGroupId()); - model.put("artifactId", bom.getArtifactId()); - model.put("versionToken", - (bom.getVersionProperty() != null) ? "${" - + computeVersionProperty(request, bom.getVersionProperty()) + "}" - : bom.getVersion()); - return model; - } - - private String computeVersionProperty(ProjectRequest request, - VersionProperty property) { - if (isGradleBuild(request) && property.isInternal()) { - return property.toCamelCaseFormat(); - } - return property.toStandardFormat(); - } - - protected void setupApplicationModel(ProjectRequest request, - Map model) { - Imports imports = new Imports(request.getLanguage()); - Annotations annotations = new Annotations(); - imports.add("org.springframework.boot.autoconfigure.SpringBootApplication"); - annotations.add("@SpringBootApplication"); - model.put("applicationImports", imports.toString()); - model.put("applicationAnnotations", annotations.toString()); - - } - - protected void setupTestModel(ProjectRequest request, Map model) { - Imports imports = new Imports(request.getLanguage()); - Annotations testAnnotations = new Annotations(); - imports.add("org.springframework.boot.test.context.SpringBootTest") - .add("org.springframework.test.context.junit4.SpringRunner"); - model.put("testImports", imports.withFinalCarriageReturn().toString()); - model.put("testAnnotations", - testAnnotations.withFinalCarriageReturn().toString()); - } - - protected String getServletInitializrClass(ProjectRequest request) { - Version bootVersion = Version.safeParse(request.getBootVersion()); - if (VERSION_2_0_0.compareTo(bootVersion) > 0) { - return "org.springframework.boot.web.support.SpringBootServletInitializer"; - } - return "org.springframework.boot.web.servlet.support.SpringBootServletInitializer"; - } - - private static boolean isJava8OrLater(ProjectRequest request) { - return !request.getJavaVersion().equals("1.6") - && !request.getJavaVersion().equals("1.7"); - } - - private static boolean isGradleBuild(ProjectRequest request) { - return "gradle".equals(request.getBuild()); - } - - private static boolean isMavenBuild(ProjectRequest request) { - return "maven".equals(request.getBuild()); - } - - private static boolean isWar(ProjectRequest request) { - return "war".equals(request.getPackaging()); - } - - private static boolean isGradle4Available(Version bootVersion) { - return VERSION_2_0_0.compareTo(bootVersion) <= 0; - } - - private byte[] doGenerateMavenPom(Map model) { - return this.templateRenderer.process("starter-pom.xml", model).getBytes(); - } - - private byte[] doGenerateGradleBuild(Map model) { - return this.templateRenderer.process("starter-build.gradle", model).getBytes(); - } - - private byte[] doGenerateGradleSettings(Map model) { - return this.templateRenderer.process("starter-settings.gradle", model).getBytes(); - } - - private void writeGradleWrapper(File dir, Version bootVersion) { - String gradlePrefix = (isGradle4Available(bootVersion)) ? "gradle4" : "gradle3"; - writeTextResource(dir, "gradlew.bat", gradlePrefix + "/gradlew.bat"); - writeTextResource(dir, "gradlew", gradlePrefix + "/gradlew"); - - File wrapperDir = new File(dir, "gradle/wrapper"); - wrapperDir.mkdirs(); - writeTextResource(wrapperDir, "gradle-wrapper.properties", - gradlePrefix + "/gradle/wrapper/gradle-wrapper.properties"); - writeBinaryResource(wrapperDir, "gradle-wrapper.jar", - gradlePrefix + "/gradle/wrapper/gradle-wrapper.jar"); - } - - private void writeMavenWrapper(File dir) { - writeTextResource(dir, "mvnw.cmd", "maven/mvnw.cmd"); - writeTextResource(dir, "mvnw", "maven/mvnw"); - - File wrapperDir = new File(dir, ".mvn/wrapper"); - wrapperDir.mkdirs(); - writeTextResource(wrapperDir, "maven-wrapper.properties", - "maven/wrapper/maven-wrapper.properties"); - writeBinaryResource(wrapperDir, "maven-wrapper.jar", - "maven/wrapper/maven-wrapper.jar"); - } - - private File writeBinaryResource(File dir, String name, String location) { - return doWriteProjectResource(dir, name, location, true); - } - - private File writeTextResource(File dir, String name, String location) { - return doWriteProjectResource(dir, name, location, false); - } - - private File doWriteProjectResource(File dir, String name, String location, - boolean binary) { - File target = new File(dir, name); - if (binary) { - writeBinary(target, this.projectResourceLocator - .getBinaryResource("classpath:project/" + location)); - } - else { - writeText(target, this.projectResourceLocator - .getTextResource("classpath:project/" + location)); - } - return target; - } - - private File initializerProjectDir(File rootDir, ProjectRequest request) { - if (request.getBaseDir() != null) { - File dir = new File(rootDir, request.getBaseDir()); - dir.mkdirs(); - return dir; - } - else { - return rootDir; - } - } - - public void write(File target, String templateName, Map model) { - String body = this.templateRenderer.process(templateName, model); - writeText(target, body); - } - - private void writeText(File target, String body) { - try (OutputStream stream = new FileOutputStream(target)) { - StreamUtils.copy(body, Charset.forName("UTF-8"), stream); - } - catch (Exception ex) { - throw new IllegalStateException("Cannot write file " + target, ex); - } - } - - private void writeBinary(File target, byte[] body) { - try (OutputStream stream = new FileOutputStream(target)) { - StreamUtils.copy(body, stream); - } - catch (Exception ex) { - throw new IllegalStateException("Cannot write file " + target, ex); - } - } - - private void addTempFile(String group, File file) { - this.temporaryFiles.computeIfAbsent(group, (key) -> new ArrayList<>()).add(file); - } - - private static List filterDependencies(List dependencies, - String scope) { - return dependencies.stream().filter((dep) -> scope.equals(dep.getScope())) - .sorted(DependencyComparator.INSTANCE).collect(Collectors.toList()); - } - - private static class DependencyComparator implements Comparator { - - private static final DependencyComparator INSTANCE = new DependencyComparator(); - - @Override - public int compare(Dependency o1, Dependency o2) { - if (isSpringBootDependency(o1) && isSpringBootDependency(o2)) { - return o1.getArtifactId().compareTo(o2.getArtifactId()); - } - if (isSpringBootDependency(o1)) { - return -1; - } - if (isSpringBootDependency(o2)) { - return 1; - } - int group = o1.getGroupId().compareTo(o2.getGroupId()); - if (group != 0) { - return group; - } - return o1.getArtifactId().compareTo(o2.getArtifactId()); - } - - private boolean isSpringBootDependency(Dependency dependency) { - return dependency.getGroupId().startsWith("org.springframework.boot"); - } - - } - - private static class Imports { - - private final List statements = new ArrayList<>(); - - private final String language; - - private boolean finalCarriageReturn; - - Imports(String language) { - this.language = language; - } - - public Imports add(String type) { - this.statements.add(generateImport(type, this.language)); - return this; - } - - public Imports withFinalCarriageReturn() { - this.finalCarriageReturn = true; - return this; - } - - private String generateImport(String type, String language) { - String end = (("groovy".equals(language) || "kotlin".equals(language)) ? "" - : ";"); - return "import " + type + end; - } - - @Override - public String toString() { - if (this.statements.isEmpty()) { - return ""; - } - String content = String.join(String.format("%n"), this.statements); - return (this.finalCarriageReturn ? String.format("%s%n", content) : content); - } - - } - - private static class Annotations { - - private final List statements = new ArrayList<>(); - - private boolean finalCarriageReturn; - - public Annotations add(String type) { - this.statements.add(type); - return this; - } - - public Annotations withFinalCarriageReturn() { - this.finalCarriageReturn = true; - return this; - } - - @Override - public String toString() { - if (this.statements.isEmpty()) { - return ""; - } - String content = String.join(String.format("%n"), this.statements); - return (this.finalCarriageReturn ? String.format("%s%n", content) : content); - } - - } - -} diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectRequest.java b/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectRequest.java deleted file mode 100644 index aba732c5..00000000 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectRequest.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright 2012-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.generator; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -import io.spring.initializr.metadata.BillOfMaterials; -import io.spring.initializr.metadata.DefaultMetadataElement; -import io.spring.initializr.metadata.Dependency; -import io.spring.initializr.metadata.InitializrMetadata; -import io.spring.initializr.metadata.Repository; -import io.spring.initializr.metadata.Type; -import io.spring.initializr.util.Version; - -import org.springframework.beans.BeanWrapperImpl; -import org.springframework.util.StringUtils; - -/** - * A request to generate a project. - * - * @author Dave Syer - * @author Stephane Nicoll - */ -public class ProjectRequest extends BasicProjectRequest { - - /** - * The id of the starter to use if no dependency is defined. - */ - public static final String DEFAULT_STARTER = "root_starter"; - - private final Map parameters = new LinkedHashMap<>(); - - // Resolved dependencies based on the ids provided by either "style" or "dependencies" - private List resolvedDependencies; - - private final Map boms = new LinkedHashMap<>(); - - private final Map repositories = new LinkedHashMap<>(); - - private final BuildProperties buildProperties = new BuildProperties(); - - private List facets = new ArrayList<>(); - - private String build; - - public List getResolvedDependencies() { - return this.resolvedDependencies; - } - - public void setResolvedDependencies(List resolvedDependencies) { - this.resolvedDependencies = resolvedDependencies; - } - - public List getFacets() { - return this.facets; - } - - public void setFacets(List facets) { - this.facets = facets; - } - - public String getBuild() { - return this.build; - } - - public void setBuild(String build) { - this.build = build; - } - - /** - * Return the additional parameters that can be used to further identify the request. - * @return the parameters - */ - public Map getParameters() { - return this.parameters; - } - - public Map getBoms() { - return this.boms; - } - - public Map getRepositories() { - return this.repositories; - } - - /** - * Return the build properties. - * @return the build properties - */ - public BuildProperties getBuildProperties() { - return this.buildProperties; - } - - /** - * Initializes this instance with the defaults defined in the specified - * {@link InitializrMetadata}. - * @param metadata the initializr metadata - */ - public void initialize(InitializrMetadata metadata) { - BeanWrapperImpl bean = new BeanWrapperImpl(this); - metadata.defaults().forEach((key, value) -> { - if (bean.isWritableProperty(key)) { - // We want to be able to infer a package name if none has been - // explicitly set - if (!key.equals("packageName")) { - bean.setPropertyValue(key, value); - } - } - }); - } - - /** - * Resolve this instance against the specified {@link InitializrMetadata}. - * @param metadata the initializr metadata - */ - public void resolve(InitializrMetadata metadata) { - List depIds = (!getStyle().isEmpty() ? getStyle() : getDependencies()); - String actualBootVersion = (getBootVersion() != null) ? getBootVersion() - : metadata.getBootVersions().getDefault().getId(); - Version requestedVersion = Version.parse(actualBootVersion); - this.resolvedDependencies = depIds.stream().map((it) -> { - Dependency dependency = metadata.getDependencies().get(it); - if (dependency == null) { - throw new InvalidProjectRequestException( - "Unknown dependency '" + it + "' check project metadata"); - } - return dependency.resolve(requestedVersion); - }).collect(Collectors.toList()); - this.resolvedDependencies.forEach((it) -> { - it.getFacets().forEach((facet) -> { - if (!this.facets.contains(facet)) { - this.facets.add(facet); - } - }); - if (!it.match(requestedVersion)) { - throw new InvalidProjectRequestException( - "Dependency '" + it.getId() + "' is not compatible " - + "with Spring Boot " + requestedVersion); - } - if (it.getBom() != null) { - resolveBom(metadata, it.getBom(), requestedVersion); - } - if (it.getRepository() != null) { - String repositoryId = it.getRepository(); - this.repositories.computeIfAbsent(repositoryId, (s) -> metadata - .getConfiguration().getEnv().getRepositories().get(s)); - } - }); - if (getType() != null) { - Type type = metadata.getTypes().get(getType()); - if (type == null) { - throw new InvalidProjectRequestException( - "Unknown type '" + getType() + "' check project metadata"); - } - String buildTag = type.getTags().get("build"); - if (buildTag != null) { - this.build = buildTag; - } - } - if (getPackaging() != null) { - DefaultMetadataElement packaging = metadata.getPackagings() - .get(getPackaging()); - if (packaging == null) { - throw new InvalidProjectRequestException("Unknown packaging '" - + getPackaging() + "' check project metadata"); - } - } - if (getLanguage() != null) { - DefaultMetadataElement language = metadata.getLanguages().get(getLanguage()); - if (language == null) { - throw new InvalidProjectRequestException("Unknown language '" - + getLanguage() + "' check project metadata"); - } - } - - if (!StringUtils.hasText(getApplicationName())) { - setApplicationName( - metadata.getConfiguration().generateApplicationName(getName())); - } - setPackageName(metadata.getConfiguration().cleanPackageName(getPackageName(), - metadata.getPackageName().getContent())); - - initializeRepositories(metadata, requestedVersion); - - initializeProperties(metadata, requestedVersion); - - afterResolution(metadata); - } - - /** - * Set the repositories that this instance should use based on the - * {@link InitializrMetadata} and the requested Spring Boot {@link Version}. - * @param metadata the initializr metadata - * @param requestedVersion the requested version - */ - protected void initializeRepositories(InitializrMetadata metadata, - Version requestedVersion) { - if (!"RELEASE".equals(requestedVersion.getQualifier().getQualifier())) { - this.repositories.put("spring-snapshots", metadata.getConfiguration().getEnv() - .getRepositories().get("spring-snapshots")); - this.repositories.put("spring-milestones", metadata.getConfiguration() - .getEnv().getRepositories().get("spring-milestones")); - } - this.boms.values().forEach((it) -> it.getRepositories().forEach((key) -> { - this.repositories.computeIfAbsent(key, - (s) -> metadata.getConfiguration().getEnv().getRepositories().get(s)); - })); - } - - protected void initializeProperties(InitializrMetadata metadata, - Version requestedVersion) { - Supplier kotlinVersion = () -> metadata.getConfiguration().getEnv() - .getKotlin().resolveKotlinVersion(requestedVersion); - if ("gradle".equals(this.build)) { - this.buildProperties.getGradle().put("springBootVersion", - this::getBootVersion); - if ("kotlin".equals(getLanguage())) { - this.buildProperties.getGradle().put("kotlinVersion", kotlinVersion); - } - } - else { - this.buildProperties.getMaven().put("java.version", this::getJavaVersion); - if ("kotlin".equals(getLanguage())) { - this.buildProperties.getMaven().put("kotlin.version", kotlinVersion); - } - } - } - - private void resolveBom(InitializrMetadata metadata, String bomId, - Version requestedVersion) { - if (!this.boms.containsKey(bomId)) { - BillOfMaterials bom = metadata.getConfiguration().getEnv().getBoms() - .get(bomId).resolve(requestedVersion); - bom.getAdditionalBoms() - .forEach((id) -> resolveBom(metadata, id, requestedVersion)); - this.boms.put(bomId, bom); - } - } - - /** - * Update this request once it has been resolved with the specified - * {@link InitializrMetadata}. - * @param metadata the initializr metadata - */ - protected void afterResolution(InitializrMetadata metadata) { - if ("war".equals(getPackaging())) { - if (!hasWebFacet()) { - // Need to be able to bootstrap the web app - this.resolvedDependencies.add(determineWebDependency(metadata)); - this.facets.add("web"); - } - // Add the tomcat starter in provided scope - Dependency tomcat = new Dependency().asSpringBootStarter("tomcat"); - tomcat.setScope(Dependency.SCOPE_PROVIDED); - this.resolvedDependencies.add(tomcat); - } - if (this.resolvedDependencies.stream().noneMatch(Dependency::isStarter)) { - // There"s no starter so we add the default one - addDefaultDependency(); - } - } - - private Dependency determineWebDependency(InitializrMetadata metadata) { - Dependency web = metadata.getDependencies().get("web"); - if (web != null) { - return web; - } - return Dependency.withId("web").asSpringBootStarter("web"); - } - - /** - * Add a default dependency if the project does not define any dependency. - */ - protected void addDefaultDependency() { - Dependency root = new Dependency(); - root.setId(DEFAULT_STARTER); - root.asSpringBootStarter(""); - this.resolvedDependencies.add(root); - } - - /** - * Specify if this request has the web facet enabled. - * @return {@code true} if the project has the web facet - */ - public boolean hasWebFacet() { - return hasFacet("web"); - } - - /** - * Specify if this request has the specified facet enabled. - * @param facet the facet to check - * @return {@code true} if the project has the facet - */ - public boolean hasFacet(String facet) { - return this.facets.contains(facet); - } - - @Override - public String toString() { - return "ProjectRequest [" + "parameters=" + this.parameters + ", " - + ((this.resolvedDependencies != null) - ? "resolvedDependencies=" + this.resolvedDependencies + ", " : "") - + "boms=" + this.boms + ", " + "repositories=" + this.repositories + ", " - + "buildProperties=" + this.buildProperties + ", " - + ((this.facets != null) ? "facets=" + this.facets + ", " : "") - + ((this.build != null) ? "build=" + this.build : "") + "]"; - } - -} diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectRequestPostProcessor.java b/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectRequestPostProcessor.java deleted file mode 100644 index 112ad918..00000000 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectRequestPostProcessor.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2012-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.generator; - -import io.spring.initializr.metadata.InitializrMetadata; - -/** - * Project generation hook that allows for custom modification of {@link ProjectRequest} - * instances, e.g. adding custom dependencies or forcing certain settings based on custom - * logic. - * - * @author Stephane Nicoll - */ -public interface ProjectRequestPostProcessor { - - /** - * Apply this post processor to the given {@code ProjectRequest} before it gets - * resolved against the specified {@code InitializrMetadata}. - *

- * Consider using this hook to customize basic settings of the {@code request}; for - * more advanced logic (in particular with regards to dependencies), consider using - * {@code postProcessAfterResolution}. - * @param request an unresolved {@link ProjectRequest} - * @param metadata the metadata to use to resolve this request - * @see ProjectRequest#resolve(InitializrMetadata) - */ - default void postProcessBeforeResolution(ProjectRequest request, - InitializrMetadata metadata) { - } - - /** - * Apply this post processor to the given {@code ProjectRequest} after it has - * been resolved against the specified {@code InitializrMetadata}. - *

- * Dependencies, repositories, bills of materials, default properties and others - * aspects of the request will have been resolved prior to invocation. In particular, - * note that no further validation checks will be performed. - * @param request an resolved {@code ProjectRequest} - * @param metadata the metadata that were used to resolve this request - */ - default void postProcessAfterResolution(ProjectRequest request, - InitializrMetadata metadata) { - } - -} diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectRequestResolver.java b/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectRequestResolver.java deleted file mode 100644 index 21db2842..00000000 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectRequestResolver.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2012-2018 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.generator; - -import java.util.ArrayList; -import java.util.List; - -import io.spring.initializr.metadata.InitializrMetadata; - -import org.springframework.util.Assert; - -/** - * Resolve {@link ProjectRequest} instances, honouring callback hook points. - * - * @author Stephane Nicoll - */ -public class ProjectRequestResolver { - - private final List postProcessors; - - public ProjectRequestResolver(List postProcessors) { - this.postProcessors = new ArrayList<>(postProcessors); - } - - public ProjectRequest resolve(ProjectRequest request, InitializrMetadata metadata) { - Assert.notNull(request, "Request must not be null"); - applyPostProcessBeforeResolution(request, metadata); - request.resolve(metadata); - applyPostProcessAfterResolution(request, metadata); - return request; - } - - private void applyPostProcessBeforeResolution(ProjectRequest request, - InitializrMetadata metadata) { - for (ProjectRequestPostProcessor processor : this.postProcessors) { - processor.postProcessBeforeResolution(request, metadata); - } - } - - private void applyPostProcessAfterResolution(ProjectRequest request, - InitializrMetadata metadata) { - for (ProjectRequestPostProcessor processor : this.postProcessors) { - processor.postProcessAfterResolution(request, metadata); - } - } - -} diff --git a/initializr-generator/src/main/resources/project/gradle3/gradle/wrapper/gradle-wrapper.jar b/initializr-generator/src/main/resources/project/gradle3/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 1a958be6420a4dd04b588fe4b31eb5d7ff8748c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54711 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 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn ( ) { - echo "$*" -} - -die ( ) { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save ( ) { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/initializr-generator/src/main/resources/project/gradle3/gradlew.bat b/initializr-generator/src/main/resources/project/gradle3/gradlew.bat deleted file mode 100755 index f9553162..00000000 --- a/initializr-generator/src/main/resources/project/gradle3/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/initializr-generator/src/main/resources/project/gradle4/gradle/wrapper/gradle-wrapper.jar b/initializr-generator/src/main/resources/project/gradle4/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 29953ea141f55e3b8fc691d31b5ca8816d89fa87..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 56177 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 i;x|p)^~-yfPOPa3(|vBayXKz \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/initializr-generator/src/main/resources/project/gradle4/gradlew.bat b/initializr-generator/src/main/resources/project/gradle4/gradlew.bat deleted file mode 100644 index f9553162..00000000 --- a/initializr-generator/src/main/resources/project/gradle4/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/initializr-generator/src/main/resources/project/maven/mvnw b/initializr-generator/src/main/resources/project/maven/mvnw deleted file mode 100755 index 5551fde8..00000000 --- a/initializr-generator/src/main/resources/project/maven/mvnw +++ /dev/null @@ -1,286 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven2 Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" - # TODO classpath? -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - wget "$jarUrl" -O "$wrapperJarPath" - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - curl -o "$wrapperJarPath" "$jarUrl" - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/initializr-generator/src/main/resources/project/maven/mvnw.cmd b/initializr-generator/src/main/resources/project/maven/mvnw.cmd deleted file mode 100755 index e5cfb0ae..00000000 --- a/initializr-generator/src/main/resources/project/maven/mvnw.cmd +++ /dev/null @@ -1,161 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven2 Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar" -FOR /F "tokens=1,2 delims==" %%A IN (%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties) DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - echo Found %WRAPPER_JAR% -) else ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - powershell -Command "(New-Object Net.WebClient).DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')" - echo Finished downloading %WRAPPER_JAR% -) -@REM End of extension - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% diff --git a/initializr-generator/src/main/resources/project/maven/wrapper/maven-wrapper.jar b/initializr-generator/src/main/resources/project/maven/wrapper/maven-wrapper.jar deleted file mode 100755 index 01e67997377a393fd672c7dcde9dccbedf0cb1e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48337 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 { -{{^kotlinSupport}} - SpringApplication.run({{applicationName}}::class.java, *args) -{{/kotlinSupport}} -{{#kotlinSupport}} - runApplication<{{applicationName}}>(*args) -{{/kotlinSupport}} -} - diff --git a/initializr-generator/src/main/resources/templates/ApplicationTests.groovy b/initializr-generator/src/main/resources/templates/ApplicationTests.groovy deleted file mode 100644 index 853e160c..00000000 --- a/initializr-generator/src/main/resources/templates/ApplicationTests.groovy +++ /dev/null @@ -1,15 +0,0 @@ -package {{packageName}} - -import org.junit.Test -import org.junit.runner.RunWith -{{testImports}} -@RunWith(SpringRunner) -@SpringBootTest -{{testAnnotations}}class {{applicationName}}Tests { - - @Test - void contextLoads() { - } - -} - diff --git a/initializr-generator/src/main/resources/templates/ApplicationTests.java b/initializr-generator/src/main/resources/templates/ApplicationTests.java deleted file mode 100644 index 33cd18fa..00000000 --- a/initializr-generator/src/main/resources/templates/ApplicationTests.java +++ /dev/null @@ -1,15 +0,0 @@ -package {{packageName}}; - -import org.junit.Test; -import org.junit.runner.RunWith; -{{testImports}} -@RunWith(SpringRunner.class) -@SpringBootTest -{{testAnnotations}}public class {{applicationName}}Tests { - - @Test - public void contextLoads() { - } - -} - diff --git a/initializr-generator/src/main/resources/templates/ApplicationTests.kt b/initializr-generator/src/main/resources/templates/ApplicationTests.kt deleted file mode 100644 index 2601dfa4..00000000 --- a/initializr-generator/src/main/resources/templates/ApplicationTests.kt +++ /dev/null @@ -1,15 +0,0 @@ -package {{packageName}} - -import org.junit.Test -import org.junit.runner.RunWith -{{testImports}} -@RunWith(SpringRunner::class) -@SpringBootTest -{{testAnnotations}}class {{applicationName}}Tests { - - @Test - fun contextLoads() { - } - -} - diff --git a/initializr-generator/src/main/resources/templates/ServletInitializer.groovy b/initializr-generator/src/main/resources/templates/ServletInitializer.groovy deleted file mode 100644 index 4f41c9db..00000000 --- a/initializr-generator/src/main/resources/templates/ServletInitializer.groovy +++ /dev/null @@ -1,14 +0,0 @@ -package {{packageName}} - -import org.springframework.boot.builder.SpringApplicationBuilder -{{servletInitializrImport}} - -class ServletInitializer extends SpringBootServletInitializer { - - @Override - protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { - application.sources({{applicationName}}) - } - -} - diff --git a/initializr-generator/src/main/resources/templates/ServletInitializer.java b/initializr-generator/src/main/resources/templates/ServletInitializer.java deleted file mode 100644 index 7bd85332..00000000 --- a/initializr-generator/src/main/resources/templates/ServletInitializer.java +++ /dev/null @@ -1,14 +0,0 @@ -package {{packageName}}; - -import org.springframework.boot.builder.SpringApplicationBuilder; -{{servletInitializrImport}} - -public class ServletInitializer extends SpringBootServletInitializer { - - @Override - protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { - return application.sources({{applicationName}}.class); - } - -} - diff --git a/initializr-generator/src/main/resources/templates/ServletInitializer.kt b/initializr-generator/src/main/resources/templates/ServletInitializer.kt deleted file mode 100644 index 50b391b3..00000000 --- a/initializr-generator/src/main/resources/templates/ServletInitializer.kt +++ /dev/null @@ -1,13 +0,0 @@ -package {{packageName}} - -import org.springframework.boot.builder.SpringApplicationBuilder -{{servletInitializrImport}} - -class ServletInitializer : SpringBootServletInitializer() { - - override fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder { - return application.sources({{applicationName}}::class.java) - } - -} - diff --git a/initializr-generator/src/main/resources/templates/gitignore.tmpl b/initializr-generator/src/main/resources/templates/gitignore.tmpl deleted file mode 100644 index bf88cef0..00000000 --- a/initializr-generator/src/main/resources/templates/gitignore.tmpl +++ /dev/null @@ -1,37 +0,0 @@ -{{#mavenBuild}} -/target/ -!.mvn/wrapper/maven-wrapper.jar -{{/mavenBuild}} -{{^mavenBuild}} -.gradle -/build/ -!gradle/wrapper/gradle-wrapper.jar -{{/mavenBuild}} - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr -{{^mavenBuild}} -/out/ -{{/mavenBuild}} - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -{{#mavenBuild}} -/build/ -{{/mavenBuild}} diff --git a/initializr-generator/src/main/resources/templates/starter-build.gradle b/initializr-generator/src/main/resources/templates/starter-build.gradle deleted file mode 100644 index b7e87a1f..00000000 --- a/initializr-generator/src/main/resources/templates/starter-build.gradle +++ /dev/null @@ -1,121 +0,0 @@ -buildscript { - ext { - {{#buildPropertiesGradle}} - {{key}} = '{{value}}' - {{/buildPropertiesGradle}} - } - repositories { - mavenCentral() - {{^isRelease}} - maven { url 'https://repo.spring.io/snapshot' } - maven { url 'https://repo.spring.io/milestone' } - {{/isRelease}} - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - {{#kotlin}} - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}") - classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}") - {{#facets.jpa}} - classpath("org.jetbrains.kotlin:kotlin-noarg:${kotlinVersion}") - {{/facets.jpa}} - {{/kotlin}} - } -} - -apply plugin: '{{language}}' -{{#kotlin}} -apply plugin: 'kotlin-spring' -{{#facets.jpa}} -apply plugin: 'kotlin-jpa' -{{/facets.jpa}} -{{/kotlin}} -apply plugin: 'org.springframework.boot' -{{#bootTwoZeroAvailable}} -apply plugin: 'io.spring.dependency-management' -{{/bootTwoZeroAvailable}} -{{#war}} -apply plugin: 'war' -{{/war}} - -group = '{{groupId}}' -version = '{{version}}' -sourceCompatibility = '{{javaVersion}}' - -repositories { - mavenCentral() - {{#repositoryValues}} - maven { url '{{value.url}}' } - {{/repositoryValues}} -} - -{{^war}} -{{#providedDependencies}} -configurations { - providedRuntime -} - -{{/providedDependencies}} -{{/war}} -{{#hasBuildPropertiesVersions}} -ext { -{{#buildPropertiesVersions}} - set('{{key}}', '{{value}}') -{{/buildPropertiesVersions}} -} - -{{/hasBuildPropertiesVersions}} -dependencies { - {{#compileDependencies}} - implementation '{{groupId}}:{{artifactId}}{{#version}}:{{version}}{{/version}}{{#type}}@{{type}}{{/type}}' - {{/compileDependencies}} - {{#groovy}} - implementation 'org.codehaus.groovy:groovy' - {{/groovy}} - {{#kotlin}} - implementation "org.jetbrains.kotlin:{{kotlinStdlibArtifactId}}{{^kotlinSupport}}:${kotlinVersion}{{/kotlinSupport}}" - implementation "org.jetbrains.kotlin:kotlin-reflect{{^kotlinSupport}}:${kotlinVersion}{{/kotlinSupport}}" - {{/kotlin}} - {{#runtimeDependencies}} - runtimeOnly '{{groupId}}:{{artifactId}}{{#version}}:{{version}}{{/version}}{{#type}}@{{type}}{{/type}}' - {{/runtimeDependencies}} - {{#compileOnlyDependencies}} - compileOnly '{{groupId}}:{{artifactId}}{{#version}}:{{version}}{{/version}}{{#type}}@{{type}}{{/type}}' - {{/compileOnlyDependencies}} - {{#annotationProcessorDependencies}} - annotationProcessor '{{groupId}}:{{artifactId}}{{#version}}:{{version}}{{/version}}{{#type}}@{{type}}{{/type}}' - {{/annotationProcessorDependencies}} - {{#providedDependencies}} - providedRuntime '{{groupId}}:{{artifactId}}{{#version}}:{{version}}{{/version}}{{#type}}@{{type}}{{/type}}' - {{/providedDependencies}} - testImplementation 'org.springframework.boot:spring-boot-starter-test' - {{#testDependencies}} - testImplementation '{{groupId}}:{{artifactId}}{{#version}}:{{version}}{{/version}}{{#type}}@{{type}}{{/type}}' - {{/testDependencies}} -} -{{#hasBoms}} - -dependencyManagement { - imports { - {{#reversedBoms}} - mavenBom "{{groupId}}:{{artifactId}}:{{versionToken}}" - {{/reversedBoms}} - } -} -{{/hasBoms}} -{{#kotlin}} - -compileKotlin { - kotlinOptions { - freeCompilerArgs = ['-Xjsr305=strict']{{#java8OrLater}} - jvmTarget = '1.8'{{/java8OrLater}} - } -} - -compileTestKotlin { - kotlinOptions { - freeCompilerArgs = ['-Xjsr305=strict']{{#java8OrLater}} - jvmTarget = '1.8'{{/java8OrLater}} - } -} -{{/kotlin}} \ No newline at end of file diff --git a/initializr-generator/src/main/resources/templates/starter-pom.xml b/initializr-generator/src/main/resources/templates/starter-pom.xml deleted file mode 100644 index 5f8200ee..00000000 --- a/initializr-generator/src/main/resources/templates/starter-pom.xml +++ /dev/null @@ -1,276 +0,0 @@ - - - 4.0.0 - - {{mavenParentGroupId}} - {{mavenParentArtifactId}} - {{mavenParentVersion}} - - - {{groupId}} - {{artifactId}} - {{version}}{{^defaultPackaging}} - {{packaging}}{{/defaultPackaging}} - {{name}} - {{description}} - - - {{#buildPropertiesMaven}} - <{{key}}>{{#value}}{{.}}{{/value}} - {{/buildPropertiesMaven}} - {{#buildPropertiesVersions}} - <{{key}}>{{#value}}{{.}}{{/value}} - {{/buildPropertiesVersions}} - - - - {{#compileDependencies}} - - {{groupId}} - {{artifactId}} - {{#version}} - {{version}} - {{/version}} - {{#type}} - {{type}} - {{/type}} - - {{/compileDependencies}} - {{#groovy}} - - org.codehaus.groovy - groovy - - {{/groovy}} - {{#kotlin}} - - org.jetbrains.kotlin - kotlin-reflect - {{^kotlinSupport}} - ${kotlin.version} - {{/kotlinSupport}} - - - org.jetbrains.kotlin - {{kotlinStdlibArtifactId}} - {{^kotlinSupport}} - ${kotlin.version} - {{/kotlinSupport}} - - {{/kotlin}} - - {{#runtimeDependencies}} - - {{groupId}} - {{artifactId}} - {{#version}} - {{version}} - {{/version}} - runtime - {{#type}} - {{type}} - {{/type}} - - {{/runtimeDependencies}} - {{#compileOnlyDependencies}} - - {{groupId}} - {{artifactId}} - {{#version}} - {{version}} - {{/version}} - true - {{#type}} - {{type}} - {{/type}} - - {{/compileOnlyDependencies}} - {{#annotationProcessorDependencies}} - - {{groupId}} - {{artifactId}} - {{#version}} - {{version}} - {{/version}} - true - {{#type}} - {{type}} - {{/type}} - - {{/annotationProcessorDependencies}} - {{#providedDependencies}} - - {{groupId}} - {{artifactId}} - {{#version}} - {{version}} - {{/version}} - provided - {{#type}} - {{type}} - {{/type}} - - {{/providedDependencies}} - - org.springframework.boot - spring-boot-starter-test - test - - {{#testDependencies}} - - {{groupId}} - {{artifactId}} - {{#version}} - {{version}} - {{/version}} - test - {{#type}} - {{type}} - {{/type}} - - {{/testDependencies}} - -{{#hasBoms}} - - - - {{#resolvedBoms}} - - {{groupId}} - {{artifactId}} - {{versionToken}} - pom - import - - {{/resolvedBoms}} - - -{{/hasBoms}} - - - {{#kotlin}} - ${project.basedir}/src/main/kotlin - ${project.basedir}/src/test/kotlin - {{/kotlin}} - - - org.springframework.boot - spring-boot-maven-plugin - - {{#groovy}} - - org.codehaus.gmavenplus - gmavenplus-plugin - 1.5 - - - - addSources - addTestSources - generateStubs - compile - testGenerateStubs - testCompile - removeStubs - removeTestStubs - - - - - {{/groovy}} - {{#kotlin}} - - org.jetbrains.kotlin - kotlin-maven-plugin - {{^kotlinSupport}} - ${kotlin.version} - {{/kotlinSupport}} - - - -Xjsr305=strict - - - spring - {{#facets.jpa}} - jpa - {{/facets.jpa}} - - {{^kotlinSupport}} - {{#java8OrLater}} - 1.8 - {{/java8OrLater}} - {{/kotlinSupport}} - - {{^kotlinSupport}} - - - compile - compile - - compile - - - - test-compile - test-compile - - test-compile - - - - {{/kotlinSupport}} - - - org.jetbrains.kotlin - kotlin-maven-allopen - ${kotlin.version} - - {{#facets.jpa}} - - org.jetbrains.kotlin - kotlin-maven-noarg - ${kotlin.version} - - {{/facets.jpa}} - - - {{/kotlin}} - - -{{#hasRepositories}} - - - {{#repositoryValues}} - - {{key}} - {{value.name}} - {{value.url}} - {{#value.snapshotsEnabled}} - - true - - {{/value.snapshotsEnabled}} - - {{/repositoryValues}} - -{{/hasRepositories}} -{{^isRelease}} - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - -{{/isRelease}} - - diff --git a/initializr-generator/src/main/resources/templates/starter-settings.gradle b/initializr-generator/src/main/resources/templates/starter-settings.gradle deleted file mode 100644 index cc08101c..00000000 --- a/initializr-generator/src/main/resources/templates/starter-settings.gradle +++ /dev/null @@ -1 +0,0 @@ -rootProject.name = '{{artifactId}}' diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/AbstractProjectGeneratorTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/AbstractProjectGeneratorTests.java deleted file mode 100755 index d63b9381..00000000 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/AbstractProjectGeneratorTests.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.generator; - -import java.io.File; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; - -import io.spring.initializr.metadata.Dependency; -import io.spring.initializr.metadata.InitializrMetadata; -import io.spring.initializr.metadata.SimpleInitializrMetadataProvider; -import io.spring.initializr.test.generator.GradleBuildAssert; -import io.spring.initializr.test.generator.PomAssert; -import io.spring.initializr.test.generator.ProjectAssert; -import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.io.TempDir; -import org.mockito.ArgumentMatcher; - -import org.springframework.context.ApplicationEventPublisher; - -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; - -/** - * @author Stephane Nicoll - */ -public abstract class AbstractProjectGeneratorTests { - - protected final ProjectGenerator projectGenerator; - - protected final ApplicationEventPublisher eventPublisher = mock( - ApplicationEventPublisher.class); - - protected AbstractProjectGeneratorTests() { - this(new ProjectGenerator()); - } - - protected AbstractProjectGeneratorTests(ProjectGenerator projectGenerator) { - this.projectGenerator = projectGenerator; - } - - @BeforeEach - public void setup(@TempDir Path folder) { - Dependency web = Dependency.withId("web"); - web.getFacets().add("web"); - InitializrMetadata metadata = initializeTestMetadataBuilder() - .addDependencyGroup("web", web).addDependencyGroup("test", "security", - "data-jpa", "aop", "batch", "integration") - .build(); - applyMetadata(metadata); - this.projectGenerator.setEventPublisher(this.eventPublisher); - this.projectGenerator - .setRequestResolver(new ProjectRequestResolver(new ArrayList<>())); - this.projectGenerator.setTmpdir(folder.toString()); - } - - protected InitializrMetadataTestBuilder initializeTestMetadataBuilder() { - return InitializrMetadataTestBuilder.withDefaults(); - } - - protected PomAssert generateMavenPom(ProjectRequest request) { - request.setType("maven-build"); - String content = new String(this.projectGenerator.generateMavenPom(request)); - return new PomAssert(content); - } - - protected GradleBuildAssert generateGradleBuild(ProjectRequest request) { - request.setType("gradle-build"); - String content = new String(this.projectGenerator.generateGradleBuild(request)); - return new GradleBuildAssert(content); - } - - protected ProjectAssert generateProject(ProjectRequest request) { - File dir = this.projectGenerator.generateProjectStructure(request); - return new ProjectAssert(dir); - } - - public ProjectRequest createProjectRequest(String... styles) { - ProjectRequest request = new ProjectRequest(); - request.initialize(this.projectGenerator.getMetadataProvider().get()); - request.getStyle().addAll(Arrays.asList(styles)); - return request; - } - - protected void applyMetadata(InitializrMetadata metadata) { - this.projectGenerator - .setMetadataProvider(new SimpleInitializrMetadataProvider(metadata)); - } - - protected void verifyProjectSuccessfulEventFor(ProjectRequest request) { - verify(this.eventPublisher, times(1)) - .publishEvent(argThat(new ProjectGeneratedEventMatcher(request))); - } - - protected void verifyProjectFailedEventFor(ProjectRequest request, Exception ex) { - verify(this.eventPublisher, times(1)) - .publishEvent(argThat(new ProjectFailedEventMatcher(request, ex))); - } - - protected static class ProjectGeneratedEventMatcher - implements ArgumentMatcher { - - private final ProjectRequest request; - - ProjectGeneratedEventMatcher(ProjectRequest request) { - this.request = request; - } - - @Override - public boolean matches(ProjectGeneratedEvent event) { - return this.request.equals(event.getProjectRequest()); - } - - } - - private static class ProjectFailedEventMatcher - implements ArgumentMatcher { - - private final ProjectRequest request; - - private final Exception cause; - - ProjectFailedEventMatcher(ProjectRequest request, Exception cause) { - this.request = request; - this.cause = cause; - } - - @Override - public boolean matches(ProjectFailedEvent event) { - return this.request.equals(event.getProjectRequest()) - && this.cause.equals(event.getCause()); - } - - } - -} diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/CustomProjectGeneratorTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/CustomProjectGeneratorTests.java deleted file mode 100755 index 869bac0e..00000000 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/CustomProjectGeneratorTests.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.generator; - -import java.io.File; -import java.util.Map; - -import io.spring.initializr.test.generator.ProjectAssert; -import org.junit.jupiter.api.Test; -import org.mockito.InOrder; -import org.mockito.Mockito; - -import org.springframework.core.io.ClassPathResource; - -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; - -/** - * Test for custom {@link ProjectGenerator}. - * - * @author Torsten Walter - * @author Stephane Nicoll - */ -class CustomProjectGeneratorTests extends AbstractProjectGeneratorTests { - - CustomProjectGeneratorTests() { - super(new MyProjectGenerator()); - } - - @Test - void generateCustomResource() { - ProjectRequest request = createProjectRequest(); - request.setType("maven-project"); - request.setGroupId("com.example.custom"); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert("custom.txt") - .equalsTo(new ClassPathResource("project/custom/custom.txt")); - } - - @Test - void generateCustomResourceDisabled() { - ProjectRequest request = createProjectRequest(); - request.setType("gradle-build"); - request.setGroupId("com.example.custom"); - ProjectAssert project = generateProject(request); - project.hasNoFile("custom.txt"); - } - - @Test - void projectGenerationEventFiredAfterCustomization() { - ProjectRequest request = createProjectRequest(); - request.setType("maven-project"); - request.setGroupId("com.example.custom"); - generateProject(request); - verifyProjectSuccessfulEventFor(request); - - Runnable customFileGenerated = ((MyProjectGenerator) this.projectGenerator).customFileGenerated; - InOrder inOrder = Mockito.inOrder(this.eventPublisher, customFileGenerated); - - inOrder.verify(customFileGenerated, times(1)).run(); - inOrder.verify(this.eventPublisher, times(1)) - .publishEvent(argThat(new ProjectGeneratedEventMatcher(request))); - } - - private static class MyProjectGenerator extends ProjectGenerator { - - private Runnable customFileGenerated = mock(Runnable.class); - - @Override - protected File generateProjectStructure(ProjectRequest request, - Map model) { - model.put("customValue", 42); - File dir = super.generateProjectStructure(request, model); - if ("maven".equals(request.getBuild())) { - write(new File(dir, "custom.txt"), "custom.txt", model); - this.customFileGenerated.run(); - } - return dir; - } - - } - -} diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/ProjectGeneratorBuildTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/ProjectGeneratorBuildTests.java deleted file mode 100755 index d52ca00f..00000000 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/ProjectGeneratorBuildTests.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.generator; - -import java.util.stream.Stream; - -import io.spring.initializr.metadata.BillOfMaterials; -import io.spring.initializr.metadata.Dependency; -import io.spring.initializr.metadata.InitializrMetadata; -import io.spring.initializr.test.generator.ProjectAssert; -import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder; -import io.spring.initializr.util.VersionProperty; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import org.springframework.core.io.ClassPathResource; - -/** - * Project generator tests for supported build systems. - * - * @author Stephane Nicoll - */ -class ProjectGeneratorBuildTests extends AbstractProjectGeneratorTests { - - public static Stream parameters() { - return Stream.of(Arguments.arguments("maven", "pom.xml"), - Arguments.arguments("gradle", "build.gradle")); - } - - @ParameterizedTest - @MethodSource("parameters") - public void currentGenerationJarJava(String build, String fileName) { - testCurrentGenerationJar("java", build, fileName); - } - - @ParameterizedTest - @MethodSource("parameters") - public void currentGenerationJarGroovy(String build, String fileName) { - testCurrentGenerationJar("groovy", build, fileName); - } - - @ParameterizedTest - @MethodSource("parameters") - public void currentGenerationJarKotlin(String build, String fileName) { - testCurrentGenerationJar("kotlin", build, fileName); - } - - private void testCurrentGenerationJar(String language, String build, - String fileName) { - ProjectRequest request = createProjectRequestForType(build); - request.setLanguage(language); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert(fileName).equalsTo(new ClassPathResource( - "project/" + language + "/standard/" + getAssertFileName(fileName))); - } - - @ParameterizedTest - @MethodSource("parameters") - public void currentGenerationWarJava(String build, String fileName) { - testCurrentGenerationWar("java", build, fileName); - } - - @ParameterizedTest - @MethodSource("parameters") - public void currentGenerationWarGroovy(String build, String fileName) { - testCurrentGenerationWar("groovy", build, fileName); - } - - @ParameterizedTest - @MethodSource("parameters") - public void currentGenerationWarKotlin(String build, String fileName) { - testCurrentGenerationWar("kotlin", build, fileName); - } - - private void testCurrentGenerationWar(String language, String build, - String fileName) { - ProjectRequest request = createProjectRequestForType(build, "web"); - request.setPackaging("war"); - request.setLanguage(language); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert(fileName).equalsTo(new ClassPathResource( - "project/" + language + "/standard/war-" + getAssertFileName(fileName))); - } - - @ParameterizedTest - @MethodSource("parameters") - public void previousGenerationJarJava(String build, String fileName) { - testPreviousGenerationJar("java", build, fileName); - } - - @ParameterizedTest - @MethodSource("parameters") - public void previousGenerationJarGroovy(String build, String fileName) { - testPreviousGenerationJar("groovy", build, fileName); - } - - @ParameterizedTest - @MethodSource("parameters") - public void previousGenerationJarKotlin(String build, String fileName) { - testPreviousGenerationJar("kotlin", build, fileName); - } - - private void testPreviousGenerationJar(String language, String build, - String fileName) { - ProjectRequest request = createProjectRequestForType(build); - request.setLanguage(language); - request.setBootVersion("1.5.18.RELEASE"); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert(fileName).equalsTo(new ClassPathResource( - "project/" + language + "/previous/" + getAssertFileName(fileName))); - } - - @ParameterizedTest - @MethodSource("parameters") - public void kotlinJava11(String build, String fileName) { - ProjectRequest request = createProjectRequestForType(build); - request.setLanguage("kotlin"); - request.setJavaVersion("11"); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert(fileName).equalsTo(new ClassPathResource( - "project/" + build + "/kotlin-java11-" + getAssertFileName(fileName))); - } - - @ParameterizedTest - @MethodSource("parameters") - public void versionOverride(String build, String fileName) { - ProjectRequest request = createProjectRequestForType(build, "web"); - request.getBuildProperties().getVersions().put( - VersionProperty.of("spring-foo.version", false), () -> "0.1.0.RELEASE"); - request.getBuildProperties().getVersions() - .put(VersionProperty.of("spring-bar.version"), () -> "0.2.0.RELEASE"); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert(fileName).equalsTo(new ClassPathResource( - "project/" + build + "/version-override-" + getAssertFileName(fileName))); - } - - @ParameterizedTest - @MethodSource("parameters") - public void bomWithVersionProperty(String build, String fileName) { - Dependency foo = Dependency.withId("foo", "org.acme", "foo"); - foo.setBom("the-bom"); - BillOfMaterials bom = BillOfMaterials.create("org.acme", "foo-bom", "1.3.3"); - bom.setVersionProperty("foo.version"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("foo", foo).addBom("the-bom", bom).build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequestForType(build, "foo"); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert(fileName).equalsTo(new ClassPathResource( - "project/" + build + "/bom-property-" + getAssertFileName(fileName))); - } - - @ParameterizedTest - @MethodSource("parameters") - public void compileOnlyDependency(String build, String fileName) { - Dependency foo = Dependency.withId("foo", "org.acme", "foo"); - foo.setScope(Dependency.SCOPE_COMPILE_ONLY); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("core", "web", "data-jpa") - .addDependencyGroup("foo", foo).build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequestForType(build, "foo", "web", - "data-jpa"); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert(fileName).equalsTo(new ClassPathResource("project/" - + build + "/compile-only-dependency-" + getAssertFileName(fileName))); - } - - @ParameterizedTest - @MethodSource("parameters") - public void annotationProcessorDependency(String build, String fileName) { - Dependency annotationProcessor = Dependency.withId("configuration-processor", - "org.springframework.boot", "spring-boot-configuration-processor"); - annotationProcessor.setScope(Dependency.SCOPE_ANNOTATION_PROCESSOR); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("core", "web", "data-jpa") - .addDependencyGroup("configuration-processor", annotationProcessor) - .build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequestForType(build, - "configuration-processor", "web", "data-jpa"); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert(fileName) - .equalsTo(new ClassPathResource( - "project/" + build + "/annotation-processor-dependency-" - + getAssertFileName(fileName))); - } - - @ParameterizedTest - @MethodSource("parameters") - public void bomWithOrdering(String build, String fileName) { - Dependency foo = Dependency.withId("foo", "org.acme", "foo"); - foo.setBom("foo-bom"); - BillOfMaterials barBom = BillOfMaterials.create("org.acme", "bar-bom", "1.0"); - barBom.setOrder(50); - BillOfMaterials bizBom = BillOfMaterials.create("org.acme", "biz-bom"); - bizBom.setOrder(40); - bizBom.getAdditionalBoms().add("bar-bom"); - bizBom.getMappings().add(BillOfMaterials.Mapping.create("1.0.0.RELEASE", "1.0")); - BillOfMaterials fooBom = BillOfMaterials.create("org.acme", "foo-bom", "1.0"); - fooBom.setOrder(20); - fooBom.getAdditionalBoms().add("biz-bom"); - - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("foo", foo).addBom("foo-bom", fooBom) - .addBom("bar-bom", barBom).addBom("biz-bom", bizBom).build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequestForType(build, "foo"); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert(fileName).equalsTo(new ClassPathResource( - "project/" + build + "/bom-ordering-" + getAssertFileName(fileName))); - } - - @ParameterizedTest - @MethodSource("parameters") - public void repositories(String build, String fileName) { - Dependency foo = Dependency.withId("foo", "org.acme", "foo"); - foo.setRepository("foo-repository"); - Dependency bar = Dependency.withId("bar", "org.acme", "bar"); - bar.setRepository("bar-repository"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("test", foo, bar) - .addRepository("foo-repository", "foo-repo", "https://example.com/foo", - false) - .addRepository("bar-repository", "bar-repo", "https://example.com/bar", - true) - .build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequestForType(build, "foo", "bar"); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert(fileName).equalsTo(new ClassPathResource( - "project/" + build + "/repositories-" + getAssertFileName(fileName))); - } - - @ParameterizedTest - @MethodSource("parameters") - public void repositoriesMilestone(String build, String fileName) { - Dependency foo = Dependency.withId("foo", "org.acme", "foo"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("test", foo).build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequestForType(build, "foo"); - request.setBootVersion("2.2.0.M1"); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert(fileName).equalsTo(new ClassPathResource("project/" - + build + "/repositories-milestone-" + getAssertFileName(fileName))); - } - - public ProjectRequest createProjectRequestForType(String build, String... styles) { - ProjectRequest request = super.createProjectRequest(styles); - request.setType(build + "-project"); - return request; - } - - private String getAssertFileName(String fileName) { - return fileName + ".gen"; - } - -} diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/ProjectGeneratorLanguageTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/ProjectGeneratorLanguageTests.java deleted file mode 100755 index d6e1d5df..00000000 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/ProjectGeneratorLanguageTests.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.generator; - -import java.util.stream.Stream; - -import io.spring.initializr.test.generator.ProjectAssert; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -import org.springframework.core.io.ClassPathResource; - -/** - * Project generator tests for supported languages. - * - * @author Stephane Nicoll - */ -class ProjectGeneratorLanguageTests extends AbstractProjectGeneratorTests { - - public static Stream parameters() { - return Stream.of(Arguments.arguments("java", "java"), - Arguments.arguments("groovy", "groovy"), - Arguments.arguments("kotlin", "kt")); - } - - @ParameterizedTest - @MethodSource("parameters") - public void currentGenerationJar(String language, String extension) { - ProjectRequest request = createProjectRequest(); - request.setLanguage(language); - generateProject(request).isGenericProject(ProjectAssert.DEFAULT_PACKAGE_NAME, - ProjectAssert.DEFAULT_APPLICATION_NAME, language, extension); - } - - @ParameterizedTest - @MethodSource("parameters") - public void currentGenerationWar(String language, String extension) { - ProjectRequest request = createProjectRequest("web"); - request.setLanguage(language); - request.setPackaging("war"); - generateProject(request).isGenericWarProject(ProjectAssert.DEFAULT_PACKAGE_NAME, - ProjectAssert.DEFAULT_APPLICATION_NAME, language, extension); - } - - @ParameterizedTest - @MethodSource("parameters") - public void currentGenerationMainClass(String language, String extension) { - ProjectRequest request = createProjectRequest(); - request.setLanguage(language); - - ProjectAssert project = generateProject(request); - project.sourceCodeAssert( - "src/main/" + language + "/com/example/demo/DemoApplication." + extension) - .equalsTo(new ClassPathResource( - "project/" + language + "/standard/DemoApplication." - + getExpectedExtension(extension))); - } - - @ParameterizedTest - @MethodSource("parameters") - public void previousGenerationMainClass(String language, String extension) { - ProjectRequest request = createProjectRequest(); - request.setLanguage(language); - request.setBootVersion("1.5.18.RELEASE"); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert( - "src/main/" + language + "/com/example/demo/DemoApplication." + extension) - .equalsTo(new ClassPathResource("project/" + language + "/previous/" - + "/DemoApplication." + getExpectedExtension(extension))); - } - - @ParameterizedTest - @MethodSource("parameters") - public void currentGenerationTestClass(String language, String extension) { - ProjectRequest request = createProjectRequest(); - request.setLanguage(language); - - ProjectAssert project = generateProject(request); - project.sourceCodeAssert("src/test/" + language - + "/com/example/demo/DemoApplicationTests." + extension) - .equalsTo(new ClassPathResource( - "project/" + language + "/standard/DemoApplicationTests." - + getExpectedExtension(extension))); - } - - @ParameterizedTest - @MethodSource("parameters") - public void currentGenerationTestClassWeb(String language, String extension) { - ProjectRequest request = createProjectRequest("web"); - request.setLanguage(language); - - ProjectAssert project = generateProject(request); - project.sourceCodeAssert("src/test/" + language - + "/com/example/demo/DemoApplicationTests." + extension) - .equalsTo(new ClassPathResource( - "project/" + language + "/standard/DemoApplicationTestsWeb." - + getExpectedExtension(extension))); - } - - @ParameterizedTest - @MethodSource("parameters") - public void currentGenerationServletInitializer(String language, String extension) { - ProjectRequest request = createProjectRequest(); - request.setLanguage(language); - request.setPackaging("war"); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert("src/main/" + language - + "/com/example/demo/ServletInitializer." + extension) - .equalsTo(new ClassPathResource("project/" + language + "/standard/" - + "ServletInitializer." + getExpectedExtension(extension))); - } - - @ParameterizedTest - @MethodSource("parameters") - public void previousGenerationServletInitializer(String language, String extension) { - ProjectRequest request = createProjectRequest(); - request.setLanguage(language); - request.setBootVersion("1.5.18.RELEASE"); - request.setPackaging("war"); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert("src/main/" + language - + "/com/example/demo/ServletInitializer." + extension) - .equalsTo(new ClassPathResource("project/" + language + "/previous/" - + "ServletInitializer." + getExpectedExtension(extension))); - } - - private String getExpectedExtension(String extension) { - return extension + ".gen"; - } - -} diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/ProjectGeneratorTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/ProjectGeneratorTests.java deleted file mode 100755 index 34a8661d..00000000 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/ProjectGeneratorTests.java +++ /dev/null @@ -1,973 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.generator; - -import java.util.Collections; - -import io.spring.initializr.metadata.BillOfMaterials; -import io.spring.initializr.metadata.Dependency; -import io.spring.initializr.metadata.InitializrMetadata; -import io.spring.initializr.test.generator.ProjectAssert; -import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder; -import io.spring.initializr.util.VersionProperty; -import org.junit.jupiter.api.Test; - -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.core.io.ClassPathResource; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.assertj.core.api.Assertions.fail; - -/** - * Tests for {@link ProjectGenerator} - * - * @author Stephane Nicoll - * @author Andy Wilkinson - */ -class ProjectGeneratorTests extends AbstractProjectGeneratorTests { - - @Override - protected InitializrMetadataTestBuilder initializeTestMetadataBuilder() { - return InitializrMetadataTestBuilder.withBasicDefaults(); - } - - @Test - void defaultMavenPom() { - ProjectRequest request = createProjectRequest("web"); - generateMavenPom(request).hasGroupId(request.getGroupId()) - .hasArtifactId(request.getArtifactId()).hasVersion(request.getVersion()) - .hasPackaging(request.getPackaging()).hasName(request.getName()) - .hasDescription(request.getDescription()) - .hasJavaVersion(request.getJavaVersion()) - .hasSpringBootParent(request.getBootVersion()).hasNoRepository() - .hasSpringBootStarterDependency("web"); - verifyProjectSuccessfulEventFor(request); - } - - @Test - void defaultGradleBuild() { - ProjectRequest request = createProjectRequest("web"); - generateGradleBuild(request).hasVersion(request.getVersion()) - .hasSpringBootBuildScriptPlugin(request.getBootVersion()) - .hasJavaVersion(request.getJavaVersion()).doesNotContain("import"); - verifyProjectSuccessfulEventFor(request); - } - - @Test - void defaultProject() { - ProjectRequest request = createProjectRequest("web"); - generateProject(request).isJavaProject().isMavenProject().pomAssert() - .hasNoRepository().hasSpringBootStarterDependency("web"); - verifyProjectSuccessfulEventFor(request); - } - - @Test - void defaultProjectWithGradle() { - ProjectRequest request = createProjectRequest("web"); - request.setType("gradle-build"); - ProjectAssert gradleProject = generateProject(request).isGradleProject(); - gradleProject.gradleBuildAssert().contains( - "implementation 'org.springframework.boot:spring-boot-starter-web'") - .contains( - "testImplementation 'org.springframework.boot:spring-boot-starter-test'"); - gradleProject.gradleSettingsAssert().hasProjectName("demo"); - verifyProjectSuccessfulEventFor(request); - } - - @Test - void mavenBuildWithCustomCoordinates() { - ProjectRequest request = createProjectRequest("web"); - request.setGroupId("com.example.test"); - request.setArtifactId("test-project"); - request.setVersion("1.0.0.TEST-SNAPSHOT"); - request.setPackaging("war"); - request.setName("Test Project"); - request.setDescription("Test Project Description"); - generateMavenPom(request).hasGroupId("com.example.test") - .hasArtifactId("test-project").hasVersion("1.0.0.TEST-SNAPSHOT") - .hasPackaging("war").hasName("Test Project") - .hasDescription("Test Project Description"); - } - - @Test - void gradleBuildWithProjectVersion() { - ProjectRequest request = createProjectRequest("web"); - request.setVersion("1.0.0.TEST-SNAPSHOT"); - generateGradleBuild(request).hasVersion("1.0.0.TEST-SNAPSHOT"); - verifyProjectSuccessfulEventFor(request); - } - - @Test - void gradleBuildWithJavaVersion() { - ProjectRequest request = createProjectRequest("web"); - request.setJavaVersion("11"); - generateGradleBuild(request).hasJavaVersion("11"); - verifyProjectSuccessfulEventFor(request); - } - - @Test - void noDependencyAddsRootStarter() { - ProjectRequest request = createProjectRequest(); - generateProject(request).isJavaProject().isMavenProject().pomAssert() - .hasSpringBootStarterRootDependency(); - } - - @Test - void mavenPomWithBootSnapshot() { - ProjectRequest request = createProjectRequest("web"); - request.setBootVersion("2.1.1.BUILD-SNAPSHOT"); - generateMavenPom(request).hasSnapshotRepository() - .hasSpringBootParent("2.1.1.BUILD-SNAPSHOT") - .hasSpringBootStarterDependency("web"); - } - - @Test - void mavenPomWithTarDependency() { - Dependency dependency = Dependency.withId("custom-artifact", "org.foo", - "custom-artifact"); - dependency.setType("tar.gz"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("test", dependency).build(); - applyMetadata(metadata); - - ProjectRequest request = createProjectRequest("custom-artifact"); - generateMavenPom(request).hasDependency(dependency).hasDependenciesCount(2); - } - - @Test - void gradleBuildWithTarDependency() { - Dependency dependency = Dependency.withId("custom-artifact", "org.foo", - "custom-artifact"); - dependency.setType("tar.gz"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("test", dependency).build(); - applyMetadata(metadata); - - ProjectRequest request = createProjectRequest("custom-artifact"); - generateGradleBuild(request) - .contains("implementation 'org.foo:custom-artifact@tar.gz'"); - } - - @Test - void mavenPomWithWebFacet() { - Dependency dependency = Dependency.withId("thymeleaf", "org.foo", "thymeleaf"); - dependency.getFacets().add("web"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("core", "web", "security", "data-jpa") - .addDependencyGroup("test", dependency).build(); - applyMetadata(metadata); - - ProjectRequest request = createProjectRequest("thymeleaf"); - generateMavenPom(request).hasDependency("org.foo", "thymeleaf") - .hasDependenciesCount(2); - } - - @Test - void mavenWarWithWebFacet() { - Dependency dependency = Dependency.withId("thymeleaf", "org.foo", "thymeleaf"); - dependency.getFacets().add("web"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("core", "web", "security", "data-jpa") - .addDependencyGroup("test", dependency).build(); - applyMetadata(metadata); - - ProjectRequest request = createProjectRequest("thymeleaf"); - request.setPackaging("war"); - generateProject(request).isJavaWarProject().isMavenProject().pomAssert() - .hasSpringBootStarterTomcat() - // This is tagged as web facet so it brings the web one - .hasDependency("org.foo", "thymeleaf").hasSpringBootStarterTest() - .hasDependenciesCount(3); - } - - @Test - void mavenWarPomWithoutWebFacet() { - ProjectRequest request = createProjectRequest("data-jpa"); - request.setPackaging("war"); - generateMavenPom(request).hasSpringBootStarterTomcat() - .hasSpringBootStarterDependency("data-jpa") - .hasSpringBootStarterDependency("web") // Added by war packaging - .hasSpringBootStarterTest().hasDependenciesCount(4); - } - - @Test - void mavenWarPomWithoutWebFacetAndWithoutWebDependency() { - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("core", "security", "data-jpa").build(); - applyMetadata(metadata); - - ProjectRequest request = createProjectRequest("data-jpa"); - request.setPackaging("war"); - generateMavenPom(request).hasSpringBootStarterTomcat() - .hasSpringBootStarterDependency("data-jpa") - .hasSpringBootStarterDependency("web") // Added by war packaging - .hasSpringBootStarterTest().hasDependenciesCount(4); - } - - @Test - void mavenWarPomWithoutWebFacetAndWithCustomWebDependency() { - Dependency customWebStarter = Dependency.withId("web", "org.acme", "web-starter"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("core", "security", "data-jpa") - .addDependencyGroup("acme", customWebStarter).build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequest("data-jpa"); - request.setPackaging("war"); - generateMavenPom(request).hasSpringBootStarterTomcat() - .hasSpringBootStarterDependency("data-jpa") - .hasDependency(customWebStarter) // Added by war packaging - .hasSpringBootStarterTest().hasDependenciesCount(4); - } - - @Test - void gradleWarWithWebFacet() { - Dependency dependency = Dependency.withId("thymeleaf", "org.foo", "thymeleaf"); - dependency.getFacets().add("web"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("core", "web", "security", "data-jpa") - .addDependencyGroup("test", dependency).build(); - applyMetadata(metadata); - - ProjectRequest request = createProjectRequest("thymeleaf"); - request.setPackaging("war"); - request.setType("gradle-project"); - generateProject(request).isJavaWarProject().isGradleProject().gradleBuildAssert() - // This is tagged as web facet so it brings the web one - .contains("apply plugin: 'war'") - .contains("implementation 'org.foo:thymeleaf'") - .doesNotContain( - "implementation 'org.springframework.boot:spring-boot-starter-web'") - .contains( - "testImplementation 'org.springframework.boot:spring-boot-starter-test'") - .doesNotContain("configurations {") // no need to declare providedRuntime - .contains("providedRuntime").contains( - "providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'"); - } - - @Test - void gradleWarPomWithoutWebFacet() { - ProjectRequest request = createProjectRequest("data-jpa"); - request.setPackaging("war"); - generateGradleBuild(request).contains( - "implementation 'org.springframework.boot:spring-boot-starter-data-jpa'") - // Added by warpackaging - .contains( - "implementation 'org.springframework.boot:spring-boot-starter-web'") - .contains( - "testImplementation 'org.springframework.boot:spring-boot-starter-test'") - .doesNotContain("configurations {") // no need to declare providedRuntime - .contains("providedRuntime").contains( - "providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'"); - } - - @Test - void groupIdAndArtifactIdInferPackageName() { - ProjectRequest request = createProjectRequest("web"); - request.setGroupId("org.acme"); - request.setArtifactId("42foo"); - generateProject(request).isJavaProject("org/acme/foo", "DemoApplication"); - } - - @Test - void cleanPackageNameWithGroupIdAndArtifactIdWithVersion() { - ProjectRequest request = createProjectRequest("web"); - request.setGroupId("org.acme"); - request.setArtifactId("foo-1.4.5"); - assertProjectWithPackageNameWithVersion(request); - } - - @Test - void cleanPackageNameWithInvalidPackageName() { - ProjectRequest request = createProjectRequest("web"); - request.setGroupId("org.acme"); - request.setArtifactId("foo"); - request.setPackageName("org.acme.foo-1.4.5"); - assertProjectWithPackageNameWithVersion(request); - } - - private void assertProjectWithPackageNameWithVersion(ProjectRequest request) { - generateProject(request).isJavaProject("org/acme/foo145", "DemoApplication") - .sourceCodeAssert("src/main/java/org/acme/foo145/DemoApplication.java") - .contains("package org.acme.foo145;"); - } - - @Test - void gradleProjectWithCustomArtifactId() { - ProjectRequest request = createProjectRequest(); - request.setType("gradle-build"); - request.setArtifactId("my-application"); - generateProject(request).isGradleProject().gradleSettingsAssert() - .hasProjectName("my-application"); - verifyProjectSuccessfulEventFor(request); - } - - @Test - void springBootUseSpringBootApplicationJava() { - ProjectRequest request = createProjectRequest("web"); - request.setName("MyDemo"); - request.setPackageName("foo"); - generateProject(request) - .sourceCodeAssert("src/main/java/foo/MyDemoApplication.java") - .hasImports(SpringBootApplication.class.getName()) - .contains("@SpringBootApplication"); - } - - @Test - void springBootUseSpringBootApplicationGroovy() { - ProjectRequest request = createProjectRequest("web"); - request.setLanguage("groovy"); - request.setName("MyDemo"); - request.setPackageName("foo"); - generateProject(request) - .sourceCodeAssert("src/main/groovy/foo/MyDemoApplication.groovy") - .hasImports(SpringBootApplication.class.getName()) - .contains("@SpringBootApplication"); - } - - @Test - void springBootUseSpringBootApplicationKotlin() { - ProjectRequest request = createProjectRequest("web"); - request.setLanguage("kotlin"); - request.setName("MyDemo"); - request.setPackageName("foo"); - - applyMetadata(initializeTestMetadataBuilder().addDependencyGroup("core", "web") - .setKotlinEnv("1.0.0").build()); - generateProject(request) - .sourceCodeAssert("src/main/kotlin/foo/MyDemoApplication.kt") - .hasImports(SpringBootApplication.class.getName()) - .contains("@SpringBootApplication"); - } - - @Test - void springBoot15UseGradle3() { - ProjectRequest request = createProjectRequest("web"); - request.setType("gradle-project"); - request.setBootVersion("1.5.0.RELEASE"); - generateProject(request).isGradleProject("3.5.1"); - } - - @Test - void springBoot20UsesGradle4() { - ProjectRequest request = createProjectRequest("web"); - request.setType("gradle-project"); - request.setBootVersion("2.0.0.RELEASE"); - generateProject(request).isGradleProject("4.10.2"); - } - - @Test - void customBaseDirectory() { - ProjectRequest request = createProjectRequest(); - request.setBaseDir("my-project"); - generateProject(request).hasBaseDir("my-project").isJavaProject() - .isMavenProject(); - } - - @Test - void customBaseDirectoryNested() { - ProjectRequest request = createProjectRequest(); - request.setBaseDir("foo-bar/my-project"); - generateProject(request).hasBaseDir("foo-bar/my-project").isJavaProject() - .isMavenProject(); - } - - @Test - void groovyWithMavenUsesGroovyDir() { - ProjectRequest request = createProjectRequest("web"); - request.setType("maven-project"); - request.setLanguage("groovy"); - generateProject(request).isMavenProject().isGroovyProject(); - } - - @Test - void groovyWithGradleUsesGroovyDir() { - ProjectRequest request = createProjectRequest("web"); - request.setType("gradle-project"); - request.setLanguage("groovy"); - generateProject(request).isGradleProject().isGroovyProject(); - } - - @Test - void mavenPomWithCustomVersion() { - Dependency whatever = Dependency.withId("whatever", "org.acme", "whatever", - "1.2.3"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("core", "web", "security", "data-jpa") - .addDependencyGroup("foo", whatever).build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequest("whatever", "data-jpa", "web"); - generateMavenPom(request).hasDependency(whatever) - .hasSpringBootStarterDependency("data-jpa") - .hasSpringBootStarterDependency("web"); - } - - @Test - void defaultMavenPomHasSpringBootParent() { - ProjectRequest request = createProjectRequest("web"); - generateMavenPom(request).hasSpringBootParent(request.getBootVersion()) - .hasNoProperty("project.build.sourceEncoding") - .hasNoProperty("project.reporting.outputEncoding"); - } - - @Test - void mavenPomWithCustomParentPom() { - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("core", "web", "security", "data-jpa") - .setMavenParent("com.foo", "foo-parent", "1.0.0-SNAPSHOT", false).build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequest("web"); - generateMavenPom(request).hasParent("com.foo", "foo-parent", "1.0.0-SNAPSHOT") - .hasBomsCount(0).hasProperty("project.build.sourceEncoding", "UTF-8") - .hasProperty("project.reporting.outputEncoding", "UTF-8"); - } - - @Test - void mavenPomWithCustomParentPomAndSpringBootBom() { - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("core", "web", "security", "data-jpa") - .setMavenParent("com.foo", "foo-parent", "1.0.0-SNAPSHOT", true).build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequest("web"); - request.setBootVersion("1.5.17.RELEASE"); - generateMavenPom(request).hasParent("com.foo", "foo-parent", "1.0.0-SNAPSHOT") - .hasProperty("spring-boot.version", "1.5.17.RELEASE") - .hasBom("org.springframework.boot", "spring-boot-dependencies", - "${spring-boot.version}") - .hasBomsCount(1).hasProperty("project.build.sourceEncoding", "UTF-8") - .hasProperty("project.reporting.outputEncoding", "UTF-8"); - } - - @Test - void gradleBuildWithCustomParentPomAndSpringBootBom() { - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("core", "web", "security", "data-jpa") - .setMavenParent("com.foo", "foo-parent", "1.0.0-SNAPSHOT", true).build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequest("web"); - request.setBootVersion("1.5.17.RELEASE"); - generateGradleBuild(request) - .doesNotContain("ext['spring-boot.version'] = '1.5.17.RELEASE'") - .doesNotContain( - "mavenBom \"org.springframework.boot:spring-boot-dependencies:1.5.17.RELEASE\""); - } - - @Test - void gradleBuildWithBootSnapshot() { - ProjectRequest request = createProjectRequest("web"); - request.setBootVersion("2.1.1.BUILD-SNAPSHOT"); - generateGradleBuild(request).hasSnapshotRepository(); - } - - @Test - void gradleBuildWithCustomVersion() { - Dependency whatever = Dependency.withId("whatever", "org.acme", "whatever", - "1.2.3"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("core", "web", "security", "data-jpa") - .addDependencyGroup("foo", whatever).build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequest("whatever", "data-jpa", "web"); - generateGradleBuild(request).contains( - "implementation 'org.springframework.boot:spring-boot-starter-web'") - .contains( - "implementation 'org.springframework.boot:spring-boot-starter-data-jpa'") - .contains("implementation 'org.acme:whatever:1.2.3'"); - } - - @Test - void mavenPomWithCustomScope() { - Dependency h2 = Dependency.withId("h2", "org.h2", "h2"); - h2.setScope("runtime"); - Dependency hamcrest = Dependency.withId("hamcrest", "org.hamcrest", "hamcrest"); - hamcrest.setScope("test"); - Dependency servlet = Dependency.withId("servlet-api", "javax.servlet", - "servlet-api"); - servlet.setScope("provided"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("core", "web", "security", "data-jpa") - .addDependencyGroup("database", h2) - .addDependencyGroup("container", servlet) - .addDependencyGroup("test", hamcrest).build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequest("hamcrest", "h2", "servlet-api", - "data-jpa", "web"); - generateMavenPom(request).hasDependency(h2).hasDependency(hamcrest) - .hasDependency(servlet).hasSpringBootStarterDependency("data-jpa") - .hasSpringBootStarterDependency("web"); - } - - @Test - void gradleBuildWithCustomScope() { - Dependency h2 = Dependency.withId("h2", "org.h2", "h2"); - h2.setScope("runtime"); - Dependency hamcrest = Dependency.withId("hamcrest", "org.hamcrest", "hamcrest"); - hamcrest.setScope("test"); - Dependency servlet = Dependency.withId("servlet-api", "javax.servlet", - "servlet-api"); - servlet.setScope("provided"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("core", "web", "security", "data-jpa") - .addDependencyGroup("database", h2) - .addDependencyGroup("container", servlet) - .addDependencyGroup("test", hamcrest).build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequest("hamcrest", "h2", "servlet-api", - "data-jpa", "web"); - generateGradleBuild(request).contains( - "implementation 'org.springframework.boot:spring-boot-starter-web'") - .contains( - "implementation 'org.springframework.boot:spring-boot-starter-data-jpa'") - // declare providedRuntime config for jar-based projects - .contains("runtimeOnly 'org.h2:h2'").contains("configurations {") - .contains("providedRuntime") - .contains("providedRuntime 'javax.servlet:servlet-api'") - .contains("testImplementation 'org.hamcrest:hamcrest'"); - } - - @Test - void gradleBuildWithSpringBoot15() { - ProjectRequest request = createProjectRequest("web"); - request.setBootVersion("1.5.20.BUILD-SNAPSHOT"); - generateGradleBuild(request) - .hasSpringBootBuildScriptPlugin("1.5.20.BUILD-SNAPSHOT") - .contains("apply plugin: 'org.springframework.boot'") - .contains( - "implementation 'org.springframework.boot:spring-boot-starter-web'") - .contains( - "testImplementation 'org.springframework.boot:spring-boot-starter-test'") - .doesNotContain("apply plugin: 'spring-boot'"); - } - - @Test - void gradleBuildWithSpringBoot20() { - ProjectRequest request = createProjectRequest("web"); - request.setBootVersion("2.0.0.RELEASE"); - generateGradleBuild(request).hasSpringBootBuildScriptPlugin("2.0.0.RELEASE") - .contains("apply plugin: 'org.springframework.boot'") - .doesNotContain("apply plugin: 'spring-boot'") - .contains("apply plugin: 'io.spring.dependency-management'") - .contains( - "implementation 'org.springframework.boot:spring-boot-starter-web'") - .contains( - "testImplementation 'org.springframework.boot:spring-boot-starter-test'"); - } - - @Test - void mavenBom() { - Dependency foo = Dependency.withId("foo", "org.acme", "foo"); - foo.setBom("foo-bom"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("foo", foo) - .addBom("foo-bom", "org.acme", "foo-bom", "1.2.3").build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequest("foo"); - generateMavenPom(request).hasDependency(foo).hasBom("org.acme", "foo-bom", - "1.2.3"); - } - - @Test - void mavenBomWithSeveralDependenciesOnSameBom() { - Dependency foo = Dependency.withId("foo", "org.acme", "foo"); - foo.setBom("the-bom"); - Dependency bar = Dependency.withId("bar", "org.acme", "bar"); - bar.setBom("the-bom"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("group", foo, bar) - .addBom("the-bom", "org.acme", "the-bom", "1.2.3").build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequest("foo", "bar"); - generateMavenPom(request).hasDependency(foo) - .hasBom("org.acme", "the-bom", "1.2.3").hasBomsCount(1); - } - - @Test - void mavenBomWithVersionMapping() { - Dependency foo = Dependency.withId("foo", "org.acme", "foo"); - foo.setBom("the-bom"); - BillOfMaterials bom = BillOfMaterials.create("org.acme", "foo-bom"); - bom.getMappings() - .add(BillOfMaterials.Mapping.create("[2.2.0.RELEASE,2.3.0.M1)", "1.0.0")); - bom.getMappings().add(BillOfMaterials.Mapping.create("2.3.0.M1", "1.2.0")); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("foo", foo).addBom("the-bom", bom).build(); - applyMetadata(metadata); - - // First version - ProjectRequest request = createProjectRequest("foo"); - request.setBootVersion("2.2.5.RELEASE"); - generateMavenPom(request).hasDependency(foo).hasSpringBootParent("2.2.5.RELEASE") - .hasBom("org.acme", "foo-bom", "1.0.0"); - - // Second version - ProjectRequest request2 = createProjectRequest("foo"); - request2.setBootVersion("2.3.0.M1"); - generateMavenPom(request2).hasDependency(foo).hasSpringBootParent("2.3.0.M1") - .hasBom("org.acme", "foo-bom", "1.2.0"); - } - - @Test - void mavenBomWithVersionMappingAndExtraRepositories() { - Dependency foo = Dependency.withId("foo", "org.acme", "foo"); - foo.setBom("the-bom"); - BillOfMaterials bom = BillOfMaterials.create("org.acme", "foo-bom"); - bom.getRepositories().add("foo-repo"); - bom.getMappings() - .add(BillOfMaterials.Mapping.create("[2.2.0.RELEASE,2.3.0.M1)", "1.0.0")); - bom.getMappings().add(BillOfMaterials.Mapping.create("2.3.0.M1", "1.2.0", - "foo-repo", "bar-repo")); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("foo", foo).addBom("the-bom", bom) - .addRepository("foo-repo", "repo", "http://example.com/foo", true) - .addRepository("bar-repo", "repo", "http://example.com/bar", false) - .build(); - applyMetadata(metadata); - - // Second version - ProjectRequest request = createProjectRequest("foo"); - request.setBootVersion("2.3.0.RELEASE"); - generateMavenPom(request).hasDependency(foo).hasSpringBootParent("2.3.0.RELEASE") - .hasBom("org.acme", "foo-bom", "1.2.0") - .hasRepository("foo-repo", "repo", "http://example.com/foo", true) - .hasRepository("bar-repo", "repo", "http://example.com/bar", false) - .hasRepositoriesCount(2); - } - - @Test - void gradleBom() { - Dependency foo = Dependency.withId("foo", "org.acme", "foo"); - foo.setBom("foo-bom"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("foo", foo) - .addBom("foo-bom", "org.acme", "foo-bom", "1.2.3").build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequest("foo"); - generateGradleBuild(request).contains("dependencyManagement {") - .contains("imports {").contains("mavenBom \"org.acme:foo-bom:1.2.3\""); - } - - @Test - void mavenRepository() { - Dependency foo = Dependency.withId("foo", "org.acme", "foo"); - foo.setRepository("foo-repo"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("foo", foo) - .addRepository("foo-repo", "foo", "http://example.com/repo", false) - .build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequest("foo"); - generateMavenPom(request).hasDependency(foo).hasRepository("foo-repo", "foo", - "http://example.com/repo", false); - } - - @Test - void mavenRepositoryWithSeveralDependenciesOnSameRepository() { - Dependency foo = Dependency.withId("foo", "org.acme", "foo"); - foo.setRepository("the-repo"); - Dependency bar = Dependency.withId("bar", "org.acme", "bar"); - foo.setRepository("the-repo"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("group", foo, bar) - .addRepository("the-repo", "repo", "http://example.com/repo", true) - .build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequest("foo", "bar"); - generateMavenPom(request).hasDependency(foo) - .hasRepository("the-repo", "repo", "http://example.com/repo", true) - .hasRepositoriesCount(1); - } - - @Test - void gradleRepository() { - Dependency foo = Dependency.withId("foo", "org.acme", "foo"); - foo.setRepository("foo-repo"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("foo", foo) - .addRepository("foo-repo", "foo", "http://example.com/repo", false) - .build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequest("foo"); - generateGradleBuild(request).hasRepository("http://example.com/repo"); - } - - @Test - void projectWithOnlyStarterDependency() { - Dependency foo = Dependency.withId("foo", "org.foo", "custom-my-starter"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("foo", foo).build(); - applyMetadata(metadata); - - ProjectRequest request = createProjectRequest("foo"); - generateMavenPom(request).hasDependency("org.foo", "custom-my-starter") - .hasSpringBootStarterTest().hasDependenciesCount(2); - } - - @Test - void projectWithOnlyNonStarterDependency() { - Dependency foo = Dependency.withId("foo", "org.foo", "foo"); - foo.setStarter(false); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("foo", foo).build(); - applyMetadata(metadata); - - ProjectRequest request = createProjectRequest("foo"); - generateMavenPom(request).hasDependency("org.foo", "foo") - .hasSpringBootStarterRootDependency().hasSpringBootStarterTest() - .hasDependenciesCount(3); - } - - @Test - void buildPropertiesMaven() { - ProjectRequest request = createProjectRequest("web"); - request.getBuildProperties().getMaven().put("name", () -> "test"); - request.getBuildProperties().getVersions().put(VersionProperty.of("foo.version"), - () -> "1.2.3"); - request.getBuildProperties().getGradle().put("ignore.property", () -> "yes"); - - generateMavenPom(request).hasProperty("name", "test") - .hasProperty("foo.version", "1.2.3").hasNoProperty("ignore.property"); - } - - @Test - void buildPropertiesGradle() { - ProjectRequest request = createProjectRequest("web"); - request.getBuildProperties().getGradle().put("name", () -> "test"); - request.getBuildProperties().getVersions() - .put(VersionProperty.of("foo.version", false), () -> "1.2.3"); - request.getBuildProperties().getVersions() - .put(VersionProperty.of("internal.version"), () -> "4.5.6"); - request.getBuildProperties().getMaven().put("ignore.property", () -> "yes"); - - generateGradleBuild(request).contains("name = 'test'") - .hasProperties("foo.version", "1.2.3", "internalVersion", "4.5.6") - .doesNotContain("ignore.property"); - } - - @Test - void versionRangeWithPostProcessor() { - Dependency foo = Dependency.withId("foo", "org.acme", "foo"); - foo.getMappings().add(Dependency.Mapping.create("[2.2.0.RELEASE,2.3.0.M1)", null, - null, "1.0.0")); - foo.getMappings().add(Dependency.Mapping.create("2.3.0.M1", null, null, "1.2.0")); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("foo", foo).build(); - applyMetadata(metadata); - - // First without processor, get the correct version - ProjectRequest request = createProjectRequest("foo"); - request.setBootVersion("2.2.5.RELEASE"); - generateMavenPom(request) - .hasDependency(Dependency.withId("foo", "org.acme", "foo", "1.0.0")); - - // First after processor that flips Spring Boot version - this.projectGenerator.setRequestResolver(new ProjectRequestResolver( - Collections.singletonList(new ProjectRequestPostProcessor() { - @Override - public void postProcessBeforeResolution(ProjectRequest r, - InitializrMetadata m) { - r.setBootVersion("2.3.0.M2"); - } - }))); - generateMavenPom(request) - .hasDependency(Dependency.withId("foo", "org.acme", "foo", "1.2.0")); - } - - @Test - void gitIgnoreMaven() { - ProjectRequest request = createProjectRequest(); - request.setType("maven-project"); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert(".gitignore") - .equalsTo(new ClassPathResource("project/maven/gitignore.gen")); - } - - @Test - void gitIgnoreGradle() { - ProjectRequest request = createProjectRequest(); - request.setType("gradle-project"); - ProjectAssert project = generateProject(request); - project.sourceCodeAssert(".gitignore") - .equalsTo(new ClassPathResource("project/gradle/gitignore.gen")); - } - - @Test - void dependencyOrderSpringBootTakesPrecedence() { - Dependency depOne = Dependency.withId("one", "org.acme", "first", "1.2.3"); - Dependency depTwo = Dependency.withId("two", "com.example", "second", "1.2.3"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("core", "web", "security", "data-jpa") - .addDependencyGroup("sample", depOne, depTwo).build(); - applyMetadata(metadata); - ProjectRequest request = createProjectRequest("one", "web", "two", "data-jpa"); - assertThat(generateGradleBuild(request).getGradleBuild()).containsSubsequence( - "implementation 'org.springframework.boot:spring-boot-starter-data-jpa'", - "implementation 'org.springframework.boot:spring-boot-starter-web'", - "implementation 'com.example:second:1.2.3'", - "implementation 'org.acme:first:1.2.3'"); - } - - @Test - void invalidProjectTypeMavenPom() { - ProjectRequest request = createProjectRequest("web"); - request.setType("gradle-build"); - assertThatExceptionOfType(InvalidProjectRequestException.class) - .isThrownBy(() -> this.projectGenerator.generateMavenPom(request)) - .withMessageContaining("gradle-build"); - } - - @Test - void invalidProjectTypeGradleBuild() { - ProjectRequest request = createProjectRequest("web"); - request.setType("maven-build"); - assertThatExceptionOfType(InvalidProjectRequestException.class) - .isThrownBy(() -> this.projectGenerator.generateGradleBuild(request)) - .withMessageContaining("maven-build"); - } - - @Test - void invalidDependency() { - ProjectRequest request = createProjectRequest("foo-bar"); - try { - generateMavenPom(request); - fail("Should have failed to generate project"); - } - catch (InvalidProjectRequestException ex) { - assertThat(ex.getMessage()).contains("foo-bar"); - verifyProjectFailedEventFor(request, ex); - } - } - - @Test - void invalidType() { - ProjectRequest request = createProjectRequest("web"); - request.setType("foo-bar"); - try { - generateProject(request); - fail("Should have failed to generate project"); - } - catch (InvalidProjectRequestException ex) { - assertThat(ex.getMessage()).contains("foo-bar"); - verifyProjectFailedEventFor(request, ex); - } - } - - @Test - void invalidPackaging() { - ProjectRequest request = createProjectRequest("web"); - request.setPackaging("foo-bar"); - try { - generateGradleBuild(request); - fail("Should have failed to generate project"); - } - catch (InvalidProjectRequestException ex) { - assertThat(ex.getMessage()).contains("foo-bar"); - verifyProjectFailedEventFor(request, ex); - } - } - - @Test - void invalidLanguage() { - ProjectRequest request = createProjectRequest("web"); - request.setLanguage("foo-bar"); - try { - generateProject(request); - fail("Should have failed to generate project"); - } - catch (InvalidProjectRequestException ex) { - assertThat(ex.getMessage()).contains("foo-bar"); - verifyProjectFailedEventFor(request, ex); - } - } - - @Test - void invalidSpringBootVersion() { - ProjectRequest request = createProjectRequest("web"); - request.setType("maven-project"); - request.setBootVersion("1.2.3.M4"); - assertThatExceptionOfType(InvalidProjectRequestException.class) - .isThrownBy(() -> this.projectGenerator.generateMavenPom(request)) - .withMessageContaining("1.2.3.M4"); - } - - @Test - void kotlinWithMavenUseJpaFacetHasJpaKotlinPlugin() { - applyJpaMetadata(true); - ProjectRequest request = createProjectRequest("data-jpa"); - request.setType("maven-project"); - request.setLanguage("kotlin"); - generateMavenPom(request).contains("jpa") - .contains("kotlin-maven-noarg"); - } - - @Test - void kotlinWithMavenWithoutJpaFacetDoesNotHaveJpaKotlinPlugin() { - applyJpaMetadata(false); - ProjectRequest request = createProjectRequest("data-jpa"); - request.setType("maven-project"); - request.setLanguage("kotlin"); - generateMavenPom(request).doesNotContain("jpa") - .doesNotContain("kotlin-maven-noarg"); - } - - @Test - void javaWithMavenUseJpaFacetDoesNotHaveJpaKotlinPlugin() { - applyJpaMetadata(true); - ProjectRequest request = createProjectRequest("data-jpa"); - request.setType("maven-project"); - request.setLanguage("java"); - generateMavenPom(request).doesNotContain("jpa") - .doesNotContain("kotlin-maven-noarg"); - } - - @Test - void kotlinWithGradleUseJpaFacetHasJpaKotlinPlugin() { - applyJpaMetadata(true); - ProjectRequest request = createProjectRequest("data-jpa"); - request.setType("gradle-project"); - request.setLanguage("kotlin"); - generateGradleBuild(request).contains("apply plugin: 'kotlin-jpa'"); - } - - @Test - void kotlinWithGradleWithoutJpaFacetDoesNotHaveJpaKotlinPlugin() { - applyJpaMetadata(false); - ProjectRequest request = createProjectRequest("data-jpa"); - request.setType("gradle-project"); - request.setLanguage("kotlin"); - generateGradleBuild(request).doesNotContain("apply plugin: 'kotlin-jpa'"); - } - - @Test - void javaWithGradleUseJpaFacetDoesNotHaveJpaKotlinPlugin() { - applyJpaMetadata(true); - ProjectRequest request = createProjectRequest("data-jpa"); - request.setType("gradle-project"); - request.setLanguage("java"); - generateGradleBuild(request).doesNotContain("apply plugin: 'kotlin-jpa'"); - } - - private void applyJpaMetadata(boolean enableJpaFacet) { - Dependency jpa = Dependency.withId("data-jpa"); - if (enableJpaFacet) { - jpa.setFacets(Collections.singletonList("jpa")); - } - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("data-jpa", jpa).build(); - applyMetadata(metadata); - } - -} diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/ProjectRequestResolverTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/ProjectRequestResolverTests.java deleted file mode 100755 index 60868aff..00000000 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/ProjectRequestResolverTests.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.generator; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import io.spring.initializr.metadata.InitializrMetadata; -import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.BeanWrapperImpl; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link ProjectRequestResolver}. - * - * @author Stephane Nicoll - */ -class ProjectRequestResolverTests { - - private InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("test", "web", "security", "data-jpa").build(); - - final List postProcessors = new ArrayList<>(); - - final GenericProjectRequestPostProcessor processor = new GenericProjectRequestPostProcessor(); - - @BeforeEach - public void setup() { - this.postProcessors.add(this.processor); - } - - @Test - void beforeResolution() { - this.processor.before.put("javaVersion", "1.2"); - ProjectRequest request = resolve(createMavenProjectRequest(), - this.postProcessors); - assertThat(request.getJavaVersion()).isEqualTo("1.2"); - assertThat(request.getBuildProperties().getMaven().get("java.version").get()) - .isEqualTo("1.2"); - } - - @Test - void afterResolution() { - this.postProcessors.add(new ProjectRequestPostProcessor() { - @Override - public void postProcessAfterResolution(ProjectRequest request, - InitializrMetadata metadata) { - request.getBuildProperties().getMaven().clear(); - request.getBuildProperties().getMaven().put("foo", () -> "bar"); - } - }); - ProjectRequest request = resolve(createMavenProjectRequest(), - this.postProcessors); - assertThat(request.getBuildProperties().getMaven()).hasSize(1); - assertThat(request.getBuildProperties().getMaven().get("foo").get()) - .isEqualTo("bar"); - } - - ProjectRequest resolve(ProjectRequest request, - List processors) { - return new ProjectRequestResolver(processors).resolve(request, this.metadata); - } - - ProjectRequest createMavenProjectRequest(String... styles) { - ProjectRequest request = createProjectRequest(styles); - request.setType("maven-project"); - return request; - } - - ProjectRequest createProjectRequest(String... styles) { - ProjectRequest request = new ProjectRequest(); - request.initialize(this.metadata); - request.getStyle().addAll(Arrays.asList(styles)); - return request; - } - - static class GenericProjectRequestPostProcessor - implements ProjectRequestPostProcessor { - - final Map before = new LinkedHashMap<>(); - - final Map after = new LinkedHashMap<>(); - - @Override - public void postProcessBeforeResolution(ProjectRequest request, - InitializrMetadata metadata) { - BeanWrapperImpl wrapper = new BeanWrapperImpl(request); - this.before.forEach(wrapper::setPropertyValue); - } - - @Override - public void postProcessAfterResolution(ProjectRequest request, - InitializrMetadata metadata) { - BeanWrapperImpl wrapper = new BeanWrapperImpl(request); - this.after.forEach(wrapper::setPropertyValue); - } - - } - -} diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/ProjectRequestTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/ProjectRequestTests.java deleted file mode 100755 index ce0e3be9..00000000 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/ProjectRequestTests.java +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.generator; - -import java.util.Arrays; - -import io.spring.initializr.metadata.BillOfMaterials; -import io.spring.initializr.metadata.Dependency; -import io.spring.initializr.metadata.Dependency.Mapping; -import io.spring.initializr.metadata.InitializrMetadata; -import io.spring.initializr.metadata.InitializrMetadataBuilder; -import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder; -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; - -/** - * @author Stephane Nicoll - */ -class ProjectRequestTests { - - private InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .build(); - - @Test - void initializeGroupIdAndArtifactId() { - this.metadata = InitializrMetadataBuilder.create().build(); - this.metadata.getGroupId().setContent("org.acme"); - this.metadata.getArtifactId().setContent("my-project"); - ProjectRequest request = initProjectRequest(); - assertThat(request.getGroupId()).isEqualTo("org.acme"); - assertThat(request.getArtifactId()).isEqualTo("my-project"); - } - - @Test - void initializeSetsMetadataDefaults() { - ProjectRequest request = initProjectRequest(); - assertThat(request.getName()).isEqualTo(this.metadata.getName().getContent()); - assertThat(request.getType()) - .isEqualTo(this.metadata.getTypes().getDefault().getId()); - assertThat(request.getDescription()) - .isEqualTo(this.metadata.getDescription().getContent()); - assertThat(request.getGroupId()) - .isEqualTo(this.metadata.getGroupId().getContent()); - assertThat(request.getArtifactId()) - .isEqualTo(this.metadata.getArtifactId().getContent()); - assertThat(request.getVersion()) - .isEqualTo(this.metadata.getVersion().getContent()); - assertThat(request.getBootVersion()) - .isEqualTo(this.metadata.getBootVersions().getDefault().getId()); - assertThat(request.getPackaging()) - .isEqualTo(this.metadata.getPackagings().getDefault().getId()); - } - - @Test - void resolve() { - this.metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("code", "web", "security", "spring-data").build(); - ProjectRequest request = initProjectRequest(); - request.setType("maven-project"); - request.getStyle().addAll(Arrays.asList("web", "spring-data")); - request.resolve(this.metadata); - assertThat(request.getBuild()).as("Build type not detected").isEqualTo("maven"); - assertBootStarter(request.getResolvedDependencies().get(0), "web"); - assertBootStarter(request.getResolvedDependencies().get(1), "spring-data"); - } - - @Test - void resolveWithDependencies() { - this.metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("code", "web", "security", "spring-data").build(); - ProjectRequest request = initProjectRequest(); - request.setType("maven-project"); - request.getDependencies().addAll(Arrays.asList("web", "spring-data")); - request.resolve(this.metadata); - assertThat(request.getBuild()).as("Build type not detected").isEqualTo("maven"); - assertBootStarter(request.getResolvedDependencies().get(0), "web"); - assertBootStarter(request.getResolvedDependencies().get(1), "spring-data"); - } - - @Test - void resolveFullMetadata() { - this.metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("code", createDependency("org.foo", "acme", "1.2.0")) - .build(); - ProjectRequest request = initProjectRequest(); - request.getStyle().add("org.foo:acme"); - request.resolve(this.metadata); - assertDependency(request.getResolvedDependencies().get(0), "org.foo", "acme", - "1.2.0"); - } - - @Test - void resolveUnknownSimpleId() { - this.metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("code", "org.foo:bar").build(); - ProjectRequest request = initProjectRequest(); - request.getStyle().addAll(Arrays.asList("org.foo:bar", "foo-bar")); - assertThatExceptionOfType(InvalidProjectRequestException.class) - .isThrownBy(() -> request.resolve(this.metadata)) - .withMessageContaining("foo-bar"); - } - - @Test - void resolveUnknownDependency() { - this.metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("code", "org.foo:bar").build(); - ProjectRequest request = initProjectRequest(); - request.getStyle().add("org.foo:acme"); // does not exist - assertThatExceptionOfType(InvalidProjectRequestException.class) - .isThrownBy(() -> request.resolve(this.metadata)) - .withMessageContaining("org.foo:acme"); - } - - @Test - void resolveDependencyInRange() { - Dependency dependency = createDependency("org.foo", "bar", "1.2.0.RELEASE"); - dependency.setVersionRange("[1.0.1.RELEASE, 1.2.0.RELEASE)"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("code", dependency).build(); - ProjectRequest request = initProjectRequest(); - request.getStyle().add("org.foo:bar"); - request.setBootVersion("1.1.2.RELEASE"); - request.resolve(metadata); - } - - @Test - void resolveDependencyNotInRange() { - Dependency dependency = createDependency("org.foo", "bar", "1.2.0.RELEASE"); - dependency.setVersionRange("[1.0.1.RELEASE, 1.2.0.RELEASE)"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("code", dependency).build(); - ProjectRequest request = initProjectRequest(); - request.getStyle().add("org.foo:bar"); - request.setBootVersion("0.9.9.RELEASE"); - assertThatExceptionOfType(InvalidProjectRequestException.class) - .isThrownBy(() -> request.resolve(metadata)) - .withMessageContaining("org.foo:bar") - .withMessageContaining("0.9.9.RELEASE"); - } - - @Test - void resolveDependencyVersion() { - Dependency dependency = createDependency("org.foo", "bar", "1.2.0.RELEASE"); - dependency.getMappings().add(Mapping.create("[1.0.0.RELEASE, 1.1.0.RELEASE)", - null, null, "0.1.0.RELEASE")); - dependency.getMappings() - .add(Mapping.create("1.1.0.RELEASE", null, null, "0.2.0.RELEASE")); - this.metadata = InitializrMetadataTestBuilder.withDefaults() - .addDependencyGroup("code", dependency).build(); - - ProjectRequest request = initProjectRequest(); - request.setBootVersion("1.0.5.RELEASE"); - request.getStyle().add("org.foo:bar"); - request.resolve(this.metadata); - assertDependency(request.getResolvedDependencies().get(0), "org.foo", "bar", - "0.1.0.RELEASE"); - - ProjectRequest anotherRequest = new ProjectRequest(); - anotherRequest.setBootVersion("1.1.0.RELEASE"); - anotherRequest.getStyle().add("org.foo:bar"); - anotherRequest.resolve(this.metadata); - assertDependency(anotherRequest.getResolvedDependencies().get(0), "org.foo", - "bar", "0.2.0.RELEASE"); - } - - @Test - void resolveBuild() { - ProjectRequest request = initProjectRequest(); - request.setType("gradle-project"); - request.resolve(this.metadata); - assertThat(request.getBuild()).isEqualTo("gradle"); - } - - @Test - void resolveBuildNoTag() { - this.metadata = InitializrMetadataTestBuilder.withDefaults() - .addType("foo", false, "/foo.zip", null, null).build(); - ProjectRequest request = initProjectRequest(); - request.setType("foo"); - request.resolve(this.metadata); - assertThat(request.getBuild()).isNull(); - } - - @Test - void resolveUnknownType() { - ProjectRequest request = initProjectRequest(); - request.setType("foo-project"); - assertThatExceptionOfType(InvalidProjectRequestException.class) - .isThrownBy(() -> request.resolve(this.metadata)) - .withMessageContaining("foo-project"); - } - - @Test - void resolveApplicationNameWithNoName() { - ProjectRequest request = initProjectRequest(); - request.setName(null); - request.resolve(this.metadata); - assertThat(request.getApplicationName()).isEqualTo( - this.metadata.getConfiguration().getEnv().getFallbackApplicationName()); - } - - @Test - void resolveApplicationName() { - ProjectRequest request = initProjectRequest(); - request.setName("Foo2"); - request.resolve(this.metadata); - assertThat(request.getApplicationName()).isEqualTo("Foo2Application"); - } - - @Test - void resolveApplicationNameWithApplicationNameSet() { - ProjectRequest request = initProjectRequest(); - request.setName("Foo2"); - request.setApplicationName("MyApplicationName"); - - request.resolve(this.metadata); - assertThat(request.getApplicationName()).isEqualTo("MyApplicationName"); - } - - @Test - void packageNameInferredByGroupIdAndArtifactId() { - ProjectRequest request = initProjectRequest(); - request.setGroupId("org.acme"); - request.setArtifactId("foo"); - request.resolve(this.metadata); - assertThat(request.getPackageName()).isEqualTo("org.acme.foo"); - } - - @Test - void packageNameInferredByGroupIdAndCompositeArtifactId() { - ProjectRequest request = initProjectRequest(); - request.setGroupId("org.acme"); - request.setArtifactId("foo-bar"); - request.resolve(this.metadata); - assertThat(request.getPackageName()).isEqualTo("org.acme.foobar"); - } - - @Test - void packageNameUseFallbackIfGroupIdNotSet() { - ProjectRequest request = initProjectRequest(); - request.setGroupId(null); - request.setArtifactId("foo"); - request.resolve(this.metadata); - assertThat(request.getPackageName()).isEqualTo("com.example.demo"); - } - - @Test - void packageNameUseFallbackIfArtifactIdNotSet() { - ProjectRequest request = initProjectRequest(); - request.setGroupId("org.acme"); - request.setArtifactId(null); - request.resolve(this.metadata); - assertThat(request.getPackageName()).isEqualTo("com.example.demo"); - } - - @Test - void cleanPackageNameLeadingNumbers() { - ProjectRequest request = new ProjectRequest(); - request.setPackageName("org.foo.42bar"); - InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() - .build(); - - request.resolve(metadata); - assertThat(request.getPackageName()).isEqualTo("org.foo.bar"); - } - - @Test - void cleanPackageNameWithNoName() { - ProjectRequest request = initProjectRequest(); - request.resolve(this.metadata); - assertThat(request.getPackageName()) - .isEqualTo(this.metadata.getPackageName().getContent()); - } - - @Test - void cleanPackageName() { - ProjectRequest request = initProjectRequest(); - request.setPackageName("com:foo bar"); - request.resolve(this.metadata); - assertThat(request.getPackageName()).isEqualTo("com.foo.bar"); - } - - @Test - void resolveAdditionalBoms() { - Dependency dependency = Dependency.withId("foo"); - dependency.setBom("foo-bom"); - BillOfMaterials bom = BillOfMaterials.create("com.example", "foo-bom", "1.0.0"); - bom.getAdditionalBoms().add("bar-bom"); - BillOfMaterials additionalBom = BillOfMaterials.create("com.example", "bar-bom", - "1.1.0"); - this.metadata = InitializrMetadataTestBuilder.withDefaults() - .addBom("foo-bom", bom).addBom("bar-bom", additionalBom) - .addDependencyGroup("test", dependency).build(); - ProjectRequest request = initProjectRequest(); - request.getStyle().add("foo"); - request.resolve(this.metadata); - assertThat(request.getResolvedDependencies()).hasSize(1); - assertThat(request.getBoms()).hasSize(2); - assertThat(request.getBoms().get("foo-bom")).isEqualTo(bom); - assertThat(request.getBoms().get("bar-bom")).isEqualTo(additionalBom); - } - - @Test - void resolveAdditionalBomsDuplicates() { - Dependency dependency = Dependency.withId("foo"); - dependency.setBom("foo-bom"); - Dependency anotherDependency = Dependency.withId("bar"); - anotherDependency.setBom("bar-bom"); - BillOfMaterials bom = BillOfMaterials.create("com.example", "foo-bom", "1.0.0"); - bom.getAdditionalBoms().add("bar-bom"); - BillOfMaterials additionalBom = BillOfMaterials.create("com.example", "bar-bom", - "1.1.0"); - this.metadata = InitializrMetadataTestBuilder.withDefaults() - .addBom("foo-bom", bom).addBom("bar-bom", additionalBom) - .addDependencyGroup("test", dependency, anotherDependency).build(); - ProjectRequest request = initProjectRequest(); - request.getStyle().addAll(Arrays.asList("foo", "bar")); - request.resolve(this.metadata); - assertThat(request.getResolvedDependencies()).hasSize(2); - assertThat(request.getBoms()).hasSize(2); - assertThat(request.getBoms().get("foo-bom")).isEqualTo(bom); - assertThat(request.getBoms().get("bar-bom")).isEqualTo(additionalBom); - } - - @Test - void resolveAdditionalRepositories() { - Dependency dependency = Dependency.withId("foo"); - dependency.setBom("foo-bom"); - dependency.setRepository("foo-repo"); - BillOfMaterials bom = BillOfMaterials.create("com.example", "foo-bom", "1.0.0"); - bom.getRepositories().add("bar-repo"); - this.metadata = InitializrMetadataTestBuilder.withDefaults() - .addBom("foo-bom", bom) - .addRepository("foo-repo", "foo-repo", "http://example.com/foo", false) - .addRepository("bar-repo", "bar-repo", "http://example.com/bar", false) - .addDependencyGroup("test", dependency).build(); - ProjectRequest request = initProjectRequest(); - request.getStyle().add("foo"); - request.resolve(this.metadata); - assertThat(request.getResolvedDependencies()).hasSize(1); - assertThat(request.getBoms()).hasSize(1); - assertThat(request.getRepositories()).hasSize(2); - assertThat(request.getRepositories().get("foo-repo")).isEqualTo(this.metadata - .getConfiguration().getEnv().getRepositories().get("foo-repo")); - assertThat(request.getRepositories().get("bar-repo")).isEqualTo(this.metadata - .getConfiguration().getEnv().getRepositories().get("bar-repo")); - } - - @Test - void resolveAdditionalRepositoriesDuplicates() { - Dependency dependency = Dependency.withId("foo"); - dependency.setBom("foo-bom"); - dependency.setRepository("foo-repo"); - BillOfMaterials bom = BillOfMaterials.create("com.example", "foo-bom", "1.0.0"); - bom.getRepositories().add("bar-repo"); - Dependency anotherDependency = Dependency.withId("bar"); - anotherDependency.setRepository("bar-repo"); - this.metadata = InitializrMetadataTestBuilder.withDefaults() - .addBom("foo-bom", bom) - .addRepository("foo-repo", "foo-repo", "http://example.com/foo", false) - .addRepository("bar-repo", "bar-repo", "http://example.com/bar", false) - .addDependencyGroup("test", dependency, anotherDependency).build(); - ProjectRequest request = initProjectRequest(); - request.getStyle().addAll(Arrays.asList("foo", "bar")); - request.resolve(this.metadata); - assertThat(request.getResolvedDependencies()).hasSize(2); - assertThat(request.getBoms()).hasSize(1); - assertThat(request.getRepositories()).hasSize(2); - assertThat(request.getRepositories().get("foo-repo")).isEqualTo(this.metadata - .getConfiguration().getEnv().getRepositories().get("foo-repo")); - assertThat(request.getRepositories().get("bar-repo")).isEqualTo(this.metadata - .getConfiguration().getEnv().getRepositories().get("bar-repo")); - } - - private ProjectRequest initProjectRequest() { - ProjectRequest request = new ProjectRequest(); - request.initialize(this.metadata); - return request; - } - - private static void assertBootStarter(Dependency actual, String name) { - Dependency expected = new Dependency(); - expected.asSpringBootStarter(name); - assertDependency(actual, expected.getGroupId(), expected.getArtifactId(), - expected.getVersion()); - assertThat(actual.getId()).isEqualTo(name); - } - - private static Dependency createDependency(String groupId, String artifactId, - String version) { - return Dependency.create(groupId, artifactId, version, Dependency.SCOPE_COMPILE); - } - - private static void assertDependency(Dependency actual, String groupId, - String artifactId, String version) { - assertThat(actual.getGroupId()).isEqualTo(groupId); - assertThat(actual.getArtifactId()).isEqualTo(artifactId); - assertThat(actual.getVersion()).isEqualTo(version); - } - -} diff --git a/initializr-generator/src/test/java/io/spring/initializr/test/generator/GradleBuildAssert.java b/initializr-generator/src/test/java/io/spring/initializr/test/generator/GradleBuildAssert.java deleted file mode 100644 index ed0046db..00000000 --- a/initializr-generator/src/test/java/io/spring/initializr/test/generator/GradleBuildAssert.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.test.generator; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Very simple assertions for the gradle build. - * - * @author Stephane Nicoll - */ -public class GradleBuildAssert { - - private final String content; - - public GradleBuildAssert(String content) { - this.content = content; - } - - public GradleBuildAssert hasVersion(String version) { - return contains("version = '" + version + "'"); - } - - public GradleBuildAssert hasSpringBootBuildScriptPlugin(String bootVersion) { - return contains("ext {").contains("springBootVersion = '" + bootVersion + "'") - .contains( - "classpath(\"org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}\")"); - } - - public GradleBuildAssert hasJavaVersion(String javaVersion) { - return contains("sourceCompatibility = '" + javaVersion + "'"); - } - - public GradleBuildAssert hasSnapshotRepository() { - return contains("https://repo.spring.io/snapshot"); - } - - public GradleBuildAssert hasRepository(String url) { - return contains("maven { url '" + url + "' }"); - } - - /** - * Assert the build contains only the specified properties - * @param values the property value pairs - * @return this for method chaining. - */ - public GradleBuildAssert hasProperties(String... values) { - StringBuilder builder = new StringBuilder(String.format("ext {%n")); - if (values.length % 2 == 1) { - throw new IllegalArgumentException( - "Size must be even, it is a set of property=value pairs"); - } - for (int i = 0; i < values.length; i += 2) { - builder.append( - String.format("\tset('%s', '%s')%n", values[i], values[i + 1])); - } - builder.append("}"); - return contains(builder.toString()); - } - - public GradleBuildAssert contains(String expression) { - assertThat(this.content).contains(expression); - return this; - } - - public GradleBuildAssert doesNotContain(String expression) { - assertThat(this.content).doesNotContain(expression); - return this; - } - - public String getGradleBuild() { - return this.content; - } - -} diff --git a/initializr-generator/src/test/java/io/spring/initializr/test/generator/GradleSettingsAssert.java b/initializr-generator/src/test/java/io/spring/initializr/test/generator/GradleSettingsAssert.java deleted file mode 100644 index 9e3c51c3..00000000 --- a/initializr-generator/src/test/java/io/spring/initializr/test/generator/GradleSettingsAssert.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.test.generator; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Very simple assertions for the gradle settings. - * - * @author Stephane Nicoll - */ -public class GradleSettingsAssert { - - private final String content; - - public GradleSettingsAssert(String content) { - this.content = content; - } - - public GradleSettingsAssert hasProjectName(String name) { - return contains(String.format("rootProject.name = '%s'", name)); - } - - public GradleSettingsAssert contains(String expression) { - assertThat(this.content).contains(expression); - return this; - } - -} diff --git a/initializr-generator/src/test/java/io/spring/initializr/test/generator/PomAssert.java b/initializr-generator/src/test/java/io/spring/initializr/test/generator/PomAssert.java deleted file mode 100644 index f3287145..00000000 --- a/initializr-generator/src/test/java/io/spring/initializr/test/generator/PomAssert.java +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.test.generator; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.LinkedHashMap; -import java.util.Map; - -import io.spring.initializr.metadata.BillOfMaterials; -import io.spring.initializr.metadata.Dependency; -import io.spring.initializr.metadata.InitializrConfiguration.Env.Maven.ParentPom; -import io.spring.initializr.metadata.Repository; -import org.custommonkey.xmlunit.SimpleNamespaceContext; -import org.custommonkey.xmlunit.XMLUnit; -import org.custommonkey.xmlunit.XpathEngine; -import org.custommonkey.xmlunit.exceptions.XpathException; -import org.junit.jupiter.api.Assertions; -import org.w3c.dom.DOMException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * XPath assertions that are specific to a standard Maven POM. - * - * @author Stephane Nicoll - */ -public class PomAssert { - - private final String content; - - private final XpathEngine eng; - - private final Document doc; - - private final ParentPom parentPom; - - private final Map properties = new LinkedHashMap<>(); - - private final Map dependencies = new LinkedHashMap<>(); - - private final Map boms = new LinkedHashMap<>(); - - private final Map repositories = new LinkedHashMap<>(); - - public PomAssert(String content) { - this.content = content; - this.eng = XMLUnit.newXpathEngine(); - Map context = new LinkedHashMap<>(); - context.put("pom", "http://maven.apache.org/POM/4.0.0"); - SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext(context); - this.eng.setNamespaceContext(namespaceContext); - try { - this.doc = XMLUnit.buildControlDocument(content); - } - catch (Exception ex) { - throw new IllegalArgumentException("Cannot parse XML", ex); - } - this.parentPom = parseParent(); - parseProperties(); - parseDependencies(); - parseBoms(); - parseRepositories(); - } - - public PomAssert contains(String expression) { - assertThat(this.content).contains(expression); - return this; - } - - public PomAssert doesNotContain(String expression) { - assertThat(this.content).doesNotContain(expression); - return this; - } - - public PomAssert hasGroupId(String groupId) { - try { - assertThat(this.eng.evaluate(createRootNodeXPath("groupId"), this.doc)) - .isEqualTo(groupId); - } - catch (XpathException ex) { - throw new IllegalStateException("Cannot find path", ex); - } - return this; - } - - public PomAssert hasArtifactId(String artifactId) { - try { - assertThat(this.eng.evaluate(createRootNodeXPath("artifactId"), this.doc)) - .isEqualTo(artifactId); - } - catch (XpathException ex) { - throw new IllegalStateException("Cannot find path", ex); - } - return this; - } - - public PomAssert hasVersion(String version) { - try { - assertThat(this.eng.evaluate(createRootNodeXPath("version"), this.doc)) - .isEqualTo(version); - } - catch (XpathException ex) { - throw new IllegalStateException("Cannot find path", ex); - } - return this; - } - - public PomAssert hasPackaging(String packaging) { - try { - String path = createRootNodeXPath("packaging"); - if ("jar".equals(packaging)) { - assertThat(this.eng.getMatchingNodes(path, this.doc).getLength()) - .isEqualTo(0); - } - else { - assertThat(this.eng.evaluate(path, this.doc)).isEqualTo(packaging); - } - } - catch (XpathException ex) { - throw new IllegalStateException("Cannot find path", ex); - } - return this; - } - - public PomAssert hasName(String name) { - try { - assertThat(this.eng.evaluate(createRootNodeXPath("name"), this.doc)) - .isEqualTo(name); - } - catch (XpathException ex) { - throw new IllegalStateException("Cannot find path", ex); - } - return this; - } - - public PomAssert hasDescription(String description) { - try { - assertThat(this.eng.evaluate(createRootNodeXPath("description"), this.doc)) - .isEqualTo(description); - } - catch (XpathException ex) { - throw new IllegalStateException("Cannot find path", ex); - } - return this; - } - - public PomAssert hasJavaVersion(String javaVersion) { - try { - assertThat( - this.eng.evaluate(createPropertyNodeXpath("java.version"), this.doc)) - .isEqualTo(javaVersion); - } - catch (XpathException ex) { - throw new IllegalStateException("Cannot find path", ex); - } - return this; - } - - public PomAssert hasProperty(String name, String value) { - assertThat(this.properties).containsKeys(name); - assertThat(this.properties).containsEntry(name, value); - return this; - } - - public PomAssert hasNoProperty(String name) { - assertThat(this.properties).doesNotContainKeys(name); - return this; - } - - public PomAssert hasDependenciesCount(int count) { - assertThat(this.dependencies).hasSize(count); - return this; - } - - public PomAssert hasSpringBootStarterTomcat() { - return hasDependency( - Dependency.withId("tomcat", "provided").asSpringBootStarter("tomcat")); - } - - public PomAssert hasSpringBootStarterTest() { - return hasDependency( - Dependency.withId("test", "test").asSpringBootStarter("test")); - } - - public PomAssert hasSpringBootStarterDependency(String dependency) { - return hasDependency("org.springframework.boot", - "spring-boot-starter-" + dependency); - } - - public PomAssert hasSpringBootStarterRootDependency() { - return hasDependency("org.springframework.boot", "spring-boot-starter"); - } - - public PomAssert hasDependency(String groupId, String artifactId) { - return hasDependency(groupId, artifactId, null); - } - - public PomAssert hasDependency(String groupId, String artifactId, String version) { - return hasDependency(Dependency.create(groupId, artifactId, version, "compile")); - } - - public PomAssert hasParent(String groupId, String artifactId, String version) { - assertThat(this.parentPom.getGroupId()).isEqualTo(groupId); - assertThat(this.parentPom.getArtifactId()).isEqualTo(artifactId); - assertThat(this.parentPom.getVersion()).isEqualTo(version); - return this; - } - - public PomAssert hasSpringBootParent(String version) { - return hasParent("org.springframework.boot", "spring-boot-starter-parent", - version); - } - - public PomAssert hasDependency(Dependency expected) { - String id = generateDependencyId(expected.getGroupId(), expected.getArtifactId()); - assertThat(this.dependencies).containsKey(id); - Dependency dependency = this.dependencies.get(id); - if (expected.getVersion() != null) { - assertThat(dependency.getVersion()).isEqualTo(expected.getVersion()); - } - if (expected.getScope() != null) { - assertThat(dependency.getScope()).isEqualTo(expected.getScope()); - } - if (expected.getType() != null) { - assertThat(dependency.getType()).isEqualTo(expected.getType()); - } - return this; - } - - public PomAssert hasBom(String groupId, String artifactId, String version) { - String id = generateBomId(groupId, artifactId); - assertThat(this.boms).containsKey(id); - BillOfMaterials bom = this.boms.get(id); - assertThat(bom.getVersion()).isEqualTo(version); - return this; - } - - public PomAssert hasBomsCount(int count) { - assertThat(this.boms).hasSize(count); - return this; - } - - public PomAssert hasNoRepository() { - try { - Assertions.assertEquals(0, this.eng - .getMatchingNodes(createRootNodeXPath("repositories"), this.doc) - .getLength()); - } - catch (XpathException ex) { - throw new IllegalStateException("Cannot find path", ex); - } - return this; - } - - public PomAssert hasSnapshotRepository() { - hasRepository("spring-snapshots", "Spring Snapshots", - "https://repo.spring.io/snapshot", true); - hasPluginRepository("spring-snapshots"); - return this; - } - - public PomAssert hasRepository(String id, String name, String url, - Boolean snapshotsEnabled) { - assertThat(this.repositories).containsKeys(id); - Repository repository = this.repositories.get(id); - if (name != null) { - assertThat(repository.getName()).isEqualTo(name); - } - if (url != null) { - try { - assertThat(repository.getUrl()).isEqualTo(new URL(url)); - } - catch (MalformedURLException ex) { - throw new IllegalArgumentException("Cannot parse URL", ex); - } - } - if (snapshotsEnabled) { - assertThat(repository.isSnapshotsEnabled()).isEqualTo(snapshotsEnabled); - } - return this; - } - - public PomAssert hasRepositoriesCount(int count) { - assertThat(this.repositories).hasSize(count); - return this; - } - - private PomAssert hasPluginRepository(String name) { - NodeList nodes; - try { - nodes = this.eng.getMatchingNodes( - createRootNodeXPath("pluginRepositories/pom:pluginRepository/pom:id"), - this.doc); - } - catch (XpathException ex) { - throw new IllegalStateException("Cannot find path", ex); - } - for (int i = 0; i < nodes.getLength(); i++) { - if (name.equals(nodes.item(i).getTextContent())) { - return this; - } - } - throw new IllegalArgumentException("No plugin repository found with id " + name); - } - - public static String createPropertyNodeXpath(String propertyName) { - return createRootNodeXPath("properties/pom:" + propertyName); - } - - public static String createRootNodeXPath(String node) { - return "/pom:project/pom:" + node; - } - - private ParentPom parseParent() { - ParentPom parent = new ParentPom(); - try { - parent.setGroupId(this.eng.evaluate(createRootNodeXPath("parent/pom:groupId"), - this.doc)); - parent.setArtifactId(this.eng - .evaluate(createRootNodeXPath("parent/pom:artifactId"), this.doc)); - parent.setVersion(this.eng.evaluate(createRootNodeXPath("parent/pom:version"), - this.doc)); - return parent; - } - catch (XpathException ex) { - throw new IllegalStateException("Cannot find path", ex); - } - } - - private void parseProperties() { - NodeList nodes; - try { - nodes = this.eng.getMatchingNodes(createRootNodeXPath("properties/*"), - this.doc); - } - catch (XpathException ex) { - throw new IllegalStateException("Cannot find path", ex); - } - for (int i = 0; i < nodes.getLength(); i++) { - Node item = nodes.item(i); - if (item instanceof Element) { - Element element = (Element) item; - this.properties.put(element.getTagName(), element.getTextContent()); - } - } - } - - private void parseDependencies() { - NodeList nodes; - try { - nodes = this.eng.getMatchingNodes( - createRootNodeXPath("dependencies/pom:dependency"), this.doc); - } - catch (XpathException ex) { - throw new IllegalStateException("Cannot find path", ex); - } - for (int i = 0; i < nodes.getLength(); i++) { - Node item = nodes.item(i); - if (item instanceof Element) { - Dependency dependency = new Dependency(); - Element element = (Element) item; - NodeList groupId = element.getElementsByTagName("groupId"); - if (groupId.getLength() > 0) { - dependency.setGroupId(groupId.item(0).getTextContent()); - } - NodeList artifactId = element.getElementsByTagName("artifactId"); - if (artifactId.getLength() > 0) { - dependency.setArtifactId(artifactId.item(0).getTextContent()); - } - NodeList version = element.getElementsByTagName("version"); - if (version.getLength() > 0) { - dependency.setVersion(version.item(0).getTextContent()); - } - NodeList scope = element.getElementsByTagName("scope"); - if (scope.getLength() > 0) { - dependency.setScope(scope.item(0).getTextContent()); - } - NodeList type = element.getElementsByTagName("type"); - if (type.getLength() > 0) { - dependency.setType(type.item(0).getTextContent()); - } - String id = dependency.generateId(); - assertThat(this.dependencies).doesNotContainKeys(id); - this.dependencies.put(id, dependency); - } - } - } - - private void parseBoms() { - NodeList nodes; - try { - nodes = this.eng.getMatchingNodes( - createRootNodeXPath( - "dependencyManagement/pom:dependencies/pom:dependency"), - this.doc); - } - catch (XpathException ex) { - throw new IllegalStateException("Cannot find path", ex); - } - for (int i = 0; i < nodes.getLength(); i++) { - Node item = nodes.item(i); - if (item instanceof Element) { - Element element = (Element) item; - NodeList type = element.getElementsByTagName("type"); - NodeList scope = element.getElementsByTagName("scope"); - if (isBom(type, scope)) { - BillOfMaterials bom = new BillOfMaterials(); - NodeList groupId = element.getElementsByTagName("groupId"); - if (groupId.getLength() > 0) { - bom.setGroupId(groupId.item(0).getTextContent()); - } - NodeList artifactId = element.getElementsByTagName("artifactId"); - if (artifactId.getLength() > 0) { - bom.setArtifactId(artifactId.item(0).getTextContent()); - } - NodeList version = element.getElementsByTagName("version"); - if (version.getLength() > 0) { - bom.setVersion(version.item(0).getTextContent()); - } - String id = generateBomId(bom.getGroupId(), bom.getArtifactId()); - assertThat(this.boms).doesNotContainKeys(id); - this.boms.put(id, bom); - } - } - } - } - - private void parseRepositories() { - NodeList nodes; - try { - nodes = this.eng.getMatchingNodes( - createRootNodeXPath("repositories/pom:repository"), this.doc); - } - catch (XpathException ex) { - throw new IllegalStateException("Cannot find path", ex); - - } - for (int i = 0; i < nodes.getLength(); i++) { - Node item = nodes.item(i); - if (item instanceof Element) { - Repository repository = new Repository(); - Element element = (Element) item; - NodeList type = element.getElementsByTagName("id"); - String id = type.item(0).getTextContent(); - NodeList name = element.getElementsByTagName("name"); - if (name.getLength() > 0) { - repository.setName(name.item(0).getTextContent()); - } - NodeList url = element.getElementsByTagName("url"); - if (url.getLength() > 0) { - try { - repository.setUrl(new URL(url.item(0).getTextContent())); - } - catch (MalformedURLException | DOMException ex) { - throw new IllegalStateException("Cannot parse URL", ex); - } - } - NodeList snapshots = element.getElementsByTagName("snapshots"); - if (snapshots.getLength() > 0) { - Element snapshotsElement = (Element) snapshots.item(0); - NodeList snapshotsEnabled = snapshotsElement - .getElementsByTagName("enabled"); - if (snapshotsEnabled.getLength() > 0) { - repository.setSnapshotsEnabled( - "true".equals(snapshotsEnabled.item(0).getTextContent())); - } - } - assertThat(this.repositories).doesNotContainKeys(id); - this.repositories.put(id, repository); - } - } - } - - private static boolean isBom(NodeList type, NodeList scope) { - if (type.getLength() == 0 || scope.getLength() == 0) { - return false; - } - String typeValue = type.item(0).getTextContent(); - String scopeValue = scope.item(0).getTextContent(); - return "pom".equals(typeValue) && "import".equals(scopeValue); - } - - private static String generateBomId(String groupId, String artifactId) { - return groupId + ":" + artifactId; - } - - private static String generateDependencyId(String groupId, String artifactId) { - Dependency dependency = new Dependency(); - dependency.setGroupId(groupId); - dependency.setArtifactId(artifactId); - return dependency.generateId(); - } - -} diff --git a/initializr-generator/src/test/java/io/spring/initializr/test/generator/ProjectAssert.java b/initializr-generator/src/test/java/io/spring/initializr/test/generator/ProjectAssert.java deleted file mode 100644 index 933f5328..00000000 --- a/initializr-generator/src/test/java/io/spring/initializr/test/generator/ProjectAssert.java +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.test.generator; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.Properties; - -import org.springframework.core.io.FileSystemResource; -import org.springframework.core.io.support.PropertiesLoaderUtils; -import org.springframework.util.StreamUtils; -import org.springframework.util.StringUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Various project based assertions. - * - * @author Stephane Nicoll - */ -public class ProjectAssert { - - public static final String DEFAULT_PACKAGE_NAME = "com.example.demo"; - - public static final String DEFAULT_APPLICATION_NAME = "DemoApplication"; - - private final File dir; - - private Boolean mavenProject; - - public File getDir() { - return this.dir; - } - - public Boolean getMavenProject() { - return this.mavenProject; - } - - /** - * Create a new instance with the directory holding the generated project. - * @param dir the directory of the project - */ - public ProjectAssert(File dir) { - this.dir = dir; - } - - /** - * Validate that the project contains a base directory with the specified name. - *

- * When extracting such archive, a directory with the specified {@code name} will be - * created with the content of the project instead of extracting it in the directory - * itself. - * @param name the expected name of the base directory - * @return an updated project assert on that base directory - */ - public ProjectAssert hasBaseDir(String name) { - File projectDir = file(name); - assertThat(projectDir).describedAs("No directory %s found in %s", name, - this.dir.getAbsolutePath()).exists(); - assertThat(projectDir).isDirectory(); - // Replacing the root dir so that other assertions match the root - return new ProjectAssert(projectDir); - } - - /** - * Return a {@link PomAssert} for this project. - * @return a POM assert - */ - public PomAssert pomAssert() { - try { - return new PomAssert(StreamUtils.copyToString( - new FileInputStream(file("pom.xml")), Charset.forName("UTF-8"))); - } - catch (IOException ex) { - throw new IllegalArgumentException("Cannot resolve pom.xml", ex); - } - } - - /** - * Return a {@link GradleBuildAssert} for this project. - * @return a gradle assert - */ - public GradleBuildAssert gradleBuildAssert() { - try { - return new GradleBuildAssert(StreamUtils.copyToString( - new FileInputStream(file("build.gradle")), Charset.forName("UTF-8"))); - } - catch (IOException ex) { - throw new IllegalArgumentException("Cannot resolve build.gradle", ex); - } - } - - /** - * Return a {@link GradleSettingsAssert} for this project. - * @return A gradle settings assert - */ - public GradleSettingsAssert gradleSettingsAssert() { - try { - return new GradleSettingsAssert( - StreamUtils.copyToString(new FileInputStream(file("settings.gradle")), - Charset.forName("UTF-8"))); - } - catch (IOException ex) { - throw new IllegalArgumentException("Cannot resolve settings.gradle", ex); - } - } - - /** - * Return a {@link SourceCodeAssert} for the specified source code. - * @param sourceCodePath the source code path - * @return a source assert - */ - public SourceCodeAssert sourceCodeAssert(String sourceCodePath) { - hasFile(sourceCodePath); - try { - return new SourceCodeAssert(sourceCodePath, StreamUtils.copyToString( - new FileInputStream(file(sourceCodePath)), Charset.forName("UTF-8"))); - } - catch (IOException ex) { - throw new IllegalArgumentException("Cannot resolve path: " + sourceCodePath, - ex); - } - } - - public ProjectAssert isMavenProject() { - hasFile("pom.xml").hasNoFile("build.gradle"); - hasFile("mvnw", "mvnw.cmd", ".mvn/wrapper/maven-wrapper.properties", - ".mvn/wrapper/maven-wrapper.jar"); - this.mavenProject = true; - return this; - } - - public ProjectAssert isGradleProject(String version) { - hasFile("build.gradle").hasNoFile("pom.xml"); - hasFile("gradlew", "gradlew.bat", "gradle/wrapper/gradle-wrapper.properties", - "gradle/wrapper/gradle-wrapper.jar"); - this.mavenProject = false; - if (StringUtils.hasText(version)) { - Properties properties = properties( - "gradle/wrapper/gradle-wrapper.properties"); - String distributionUrl = properties.getProperty("distributionUrl"); - assertThat(distributionUrl).contains(version); - } - return this; - } - - public ProjectAssert isGradleProject() { - return isGradleProject(null); - } - - public ProjectAssert isJavaProject(String expectedPackageName, - String expectedApplicationName) { - return isGenericProject(expectedPackageName, expectedApplicationName, "java", - "java"); - } - - public ProjectAssert isJavaProject() { - return isJavaProject(DEFAULT_PACKAGE_NAME, DEFAULT_APPLICATION_NAME); - } - - public ProjectAssert isGroovyProject(String expectedPackageName, - String expectedApplicationName) { - return isGenericProject(expectedPackageName, expectedApplicationName, "groovy", - "groovy"); - } - - public ProjectAssert isKotlinProject(String expectedPackageName, - String expectedApplicationName) { - return isGenericProject(expectedPackageName, expectedApplicationName, "kotlin", - "kt"); - } - - public ProjectAssert isGroovyProject() { - return isGroovyProject(DEFAULT_PACKAGE_NAME, DEFAULT_APPLICATION_NAME); - } - - public ProjectAssert isKotlinProject() { - return isKotlinProject(DEFAULT_PACKAGE_NAME, DEFAULT_APPLICATION_NAME); - } - - public ProjectAssert isGenericProject(String expectedPackageName, - String expectedApplicationName, String codeLocation, String extension) { - String packageName = expectedPackageName.replace(".", "/"); - return hasFile( - "src/main/" + codeLocation + "/" + packageName + "/" - + expectedApplicationName + "." + extension, - "src/test/" + codeLocation + "/" + packageName + "/" - + expectedApplicationName + "Tests." + extension, - "src/main/resources/application.properties"); - } - - public ProjectAssert isJavaWarProject(String expectedApplicationName) { - return isGenericWarProject(DEFAULT_PACKAGE_NAME, expectedApplicationName, "java", - "java"); - } - - public ProjectAssert isJavaWarProject() { - return isJavaWarProject(DEFAULT_APPLICATION_NAME); - } - - public ProjectAssert isGenericWarProject(String expectedPackageName, - String expectedApplicationName, String codeLocation, String extension) { - String packageName = expectedPackageName.replace(".", "/"); - return isGenericProject(expectedPackageName, expectedApplicationName, - codeLocation, extension).hasStaticAndTemplatesResources(true) - .hasFile("src/main/" + codeLocation + "/" + packageName - + "/ServletInitializer." + extension); - } - - public ProjectAssert hasStaticAndTemplatesResources(boolean web) { - assertFile("src/main/resources/templates", web); - return assertFile("src/main/resources/static", web); - } - - public ProjectAssert hasFile(String... localPaths) { - for (String localPath : localPaths) { - assertFile(localPath, true); - } - return this; - } - - public ProjectAssert hasExecutableFile(String... localPaths) { - for (String localPath : localPaths) { - assertFile(localPath, true); - } - return this; - } - - public ProjectAssert hasNoFile(String... localPaths) { - for (String localPath : localPaths) { - assertFile(localPath, false); - } - return this; - } - - public ProjectAssert assertFile(String localPath, boolean exist) { - File candidate = file(localPath); - assertThat(candidate.exists()) - .describedAs("Invalid presence (%s) exist for %s", exist, localPath) - .isEqualTo(exist); - return this; - } - - private File file(String localPath) { - return new File(this.dir, localPath); - } - - private Properties properties(String localPath) { - File f = file(localPath); - try { - return PropertiesLoaderUtils.loadProperties(new FileSystemResource(f)); - } - catch (Exception ex) { - throw new IllegalStateException("Cannot load Properties", ex); - } - } - -} diff --git a/initializr-generator/src/test/java/io/spring/initializr/test/generator/SourceCodeAssert.java b/initializr-generator/src/test/java/io/spring/initializr/test/generator/SourceCodeAssert.java deleted file mode 100644 index 2dd5000a..00000000 --- a/initializr-generator/src/test/java/io/spring/initializr/test/generator/SourceCodeAssert.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.spring.initializr.test.generator; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; - -import org.springframework.core.io.Resource; -import org.springframework.util.StreamUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Source code assertions. - * - * @author Stephane Nicoll - */ -public class SourceCodeAssert { - - private final String name; - - private final String content; - - public SourceCodeAssert(String name, String content) { - this.name = name; - this.content = content.replaceAll("\r\n", "\n"); - } - - public SourceCodeAssert equalsTo(Resource expected) { - try (InputStream stream = expected.getInputStream()) { - String expectedContent = StreamUtils.copyToString(stream, - Charset.forName("UTF-8")); - assertThat(this.content).describedAs("Content for %s", this.name) - .isEqualTo(expectedContent.replaceAll("\r\n", "\n")); - } - catch (IOException ex) { - throw new IllegalStateException("Cannot read file", ex); - } - return this; - } - - public SourceCodeAssert hasImports(String... classNames) { - for (String className : classNames) { - contains("import " + className); - } - return this; - } - - public SourceCodeAssert doesNotHaveImports(String... classNames) { - for (String className : classNames) { - doesNotContain("import " + className); - } - return this; - } - - public SourceCodeAssert contains(String... expressions) { - assertThat(this.content).describedAs("Content for %s", this.name) - .contains(expressions); - return this; - } - - public SourceCodeAssert doesNotContain(String... expressions) { - assertThat(this.content).describedAs("Content for %s", this.name) - .doesNotContain(expressions); - return this; - } - -} diff --git a/initializr-generator/src/test/resources/project/custom/custom.txt b/initializr-generator/src/test/resources/project/custom/custom.txt deleted file mode 100644 index fdccaf98..00000000 --- a/initializr-generator/src/test/resources/project/custom/custom.txt +++ /dev/null @@ -1,4 +0,0 @@ -Custom resources - -com.example.custom -42 \ No newline at end of file diff --git a/initializr-generator/src/test/resources/project/gradle/annotation-processor-dependency-build.gradle.gen b/initializr-generator/src/test/resources/project/gradle/annotation-processor-dependency-build.gradle.gen deleted file mode 100644 index d76a7979..00000000 --- a/initializr-generator/src/test/resources/project/gradle/annotation-processor-dependency-build.gradle.gen +++ /dev/null @@ -1,30 +0,0 @@ -buildscript { - ext { - springBootVersion = '2.1.1.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '1.8' - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.springframework.boot:spring-boot-starter-web' - annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/initializr-generator/src/test/resources/project/gradle/bom-ordering-build.gradle.gen b/initializr-generator/src/test/resources/project/gradle/bom-ordering-build.gradle.gen deleted file mode 100644 index c318d3eb..00000000 --- a/initializr-generator/src/test/resources/project/gradle/bom-ordering-build.gradle.gen +++ /dev/null @@ -1,36 +0,0 @@ -buildscript { - ext { - springBootVersion = '2.1.1.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '1.8' - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.acme:foo' - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} - -dependencyManagement { - imports { - mavenBom "org.acme:bar-bom:1.0" - mavenBom "org.acme:biz-bom:1.0" - mavenBom "org.acme:foo-bom:1.0" - } -} diff --git a/initializr-generator/src/test/resources/project/gradle/bom-property-build.gradle.gen b/initializr-generator/src/test/resources/project/gradle/bom-property-build.gradle.gen deleted file mode 100644 index 2f19c4ba..00000000 --- a/initializr-generator/src/test/resources/project/gradle/bom-property-build.gradle.gen +++ /dev/null @@ -1,38 +0,0 @@ -buildscript { - ext { - springBootVersion = '2.1.1.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '1.8' - -repositories { - mavenCentral() -} - -ext { - set('fooVersion', '1.3.3') -} - -dependencies { - implementation 'org.acme:foo' - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} - -dependencyManagement { - imports { - mavenBom "org.acme:foo-bom:${fooVersion}" - } -} diff --git a/initializr-generator/src/test/resources/project/gradle/compile-only-dependency-build.gradle.gen b/initializr-generator/src/test/resources/project/gradle/compile-only-dependency-build.gradle.gen deleted file mode 100644 index 49b9cddc..00000000 --- a/initializr-generator/src/test/resources/project/gradle/compile-only-dependency-build.gradle.gen +++ /dev/null @@ -1,30 +0,0 @@ -buildscript { - ext { - springBootVersion = '2.1.1.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '1.8' - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - implementation 'org.springframework.boot:spring-boot-starter-web' - compileOnly 'org.acme:foo' - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/initializr-generator/src/test/resources/project/gradle/gitignore.gen b/initializr-generator/src/test/resources/project/gradle/gitignore.gen deleted file mode 100644 index d6819a47..00000000 --- a/initializr-generator/src/test/resources/project/gradle/gitignore.gen +++ /dev/null @@ -1,26 +0,0 @@ -.gradle -/build/ -!gradle/wrapper/gradle-wrapper.jar - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr -/out/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ diff --git a/initializr-generator/src/test/resources/project/gradle/kotlin-java11-build.gradle.gen b/initializr-generator/src/test/resources/project/gradle/kotlin-java11-build.gradle.gen deleted file mode 100644 index 366816f6..00000000 --- a/initializr-generator/src/test/resources/project/gradle/kotlin-java11-build.gradle.gen +++ /dev/null @@ -1,48 +0,0 @@ -buildscript { - ext { - kotlinVersion = '1.1.1' - springBootVersion = '2.1.1.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}") - classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}") - } -} - -apply plugin: 'kotlin' -apply plugin: 'kotlin-spring' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '11' - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter' - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" - implementation "org.jetbrains.kotlin:kotlin-reflect" - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} - -compileKotlin { - kotlinOptions { - freeCompilerArgs = ['-Xjsr305=strict'] - jvmTarget = '1.8' - } -} - -compileTestKotlin { - kotlinOptions { - freeCompilerArgs = ['-Xjsr305=strict'] - jvmTarget = '1.8' - } -} diff --git a/initializr-generator/src/test/resources/project/gradle/repositories-build.gradle.gen b/initializr-generator/src/test/resources/project/gradle/repositories-build.gradle.gen deleted file mode 100644 index 36c2bf40..00000000 --- a/initializr-generator/src/test/resources/project/gradle/repositories-build.gradle.gen +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext { - springBootVersion = '2.1.1.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '1.8' - -repositories { - mavenCentral() - maven { url 'https://example.com/foo' } - maven { url 'https://example.com/bar' } -} - -dependencies { - implementation 'org.acme:bar' - implementation 'org.acme:foo' - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/initializr-generator/src/test/resources/project/gradle/repositories-milestone-build.gradle.gen b/initializr-generator/src/test/resources/project/gradle/repositories-milestone-build.gradle.gen deleted file mode 100644 index 1f15a9cf..00000000 --- a/initializr-generator/src/test/resources/project/gradle/repositories-milestone-build.gradle.gen +++ /dev/null @@ -1,32 +0,0 @@ -buildscript { - ext { - springBootVersion = '2.2.0.M1' - } - repositories { - mavenCentral() - maven { url 'https://repo.spring.io/snapshot' } - maven { url 'https://repo.spring.io/milestone' } - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '1.8' - -repositories { - mavenCentral() - maven { url 'https://repo.spring.io/snapshot' } - maven { url 'https://repo.spring.io/milestone' } -} - -dependencies { - implementation 'org.acme:foo' - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/initializr-generator/src/test/resources/project/gradle/version-override-build.gradle.gen b/initializr-generator/src/test/resources/project/gradle/version-override-build.gradle.gen deleted file mode 100644 index 44c93c64..00000000 --- a/initializr-generator/src/test/resources/project/gradle/version-override-build.gradle.gen +++ /dev/null @@ -1,33 +0,0 @@ -buildscript { - ext { - springBootVersion = '2.1.1.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '1.8' - -repositories { - mavenCentral() -} - -ext { - set('springBarVersion', '0.2.0.RELEASE') - set('spring-foo.version', '0.1.0.RELEASE') -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web' - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/initializr-generator/src/test/resources/project/groovy/previous/DemoApplication.groovy.gen b/initializr-generator/src/test/resources/project/groovy/previous/DemoApplication.groovy.gen deleted file mode 100644 index aea889c4..00000000 --- a/initializr-generator/src/test/resources/project/groovy/previous/DemoApplication.groovy.gen +++ /dev/null @@ -1,14 +0,0 @@ -package com.example.demo - -import org.springframework.boot.SpringApplication -import org.springframework.boot.autoconfigure.SpringBootApplication - -@SpringBootApplication -class DemoApplication { - - static void main(String[] args) { - SpringApplication.run(DemoApplication, args) - } - -} - diff --git a/initializr-generator/src/test/resources/project/groovy/previous/ServletInitializer.groovy.gen b/initializr-generator/src/test/resources/project/groovy/previous/ServletInitializer.groovy.gen deleted file mode 100644 index 44cd9fa0..00000000 --- a/initializr-generator/src/test/resources/project/groovy/previous/ServletInitializer.groovy.gen +++ /dev/null @@ -1,14 +0,0 @@ -package com.example.demo - -import org.springframework.boot.builder.SpringApplicationBuilder -import org.springframework.boot.web.support.SpringBootServletInitializer - -class ServletInitializer extends SpringBootServletInitializer { - - @Override - protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { - application.sources(DemoApplication) - } - -} - diff --git a/initializr-generator/src/test/resources/project/groovy/previous/build.gradle.gen b/initializr-generator/src/test/resources/project/groovy/previous/build.gradle.gen deleted file mode 100644 index 8aa1a1cf..00000000 --- a/initializr-generator/src/test/resources/project/groovy/previous/build.gradle.gen +++ /dev/null @@ -1,28 +0,0 @@ -buildscript { - ext { - springBootVersion = '1.5.18.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - } -} - -apply plugin: 'groovy' -apply plugin: 'org.springframework.boot' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '1.8' - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter' - implementation 'org.codehaus.groovy:groovy' - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/initializr-generator/src/test/resources/project/groovy/previous/pom.xml.gen b/initializr-generator/src/test/resources/project/groovy/previous/pom.xml.gen deleted file mode 100644 index 97819fd3..00000000 --- a/initializr-generator/src/test/resources/project/groovy/previous/pom.xml.gen +++ /dev/null @@ -1,66 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 1.5.18.RELEASE - - - com.example - demo - 0.0.1-SNAPSHOT - demo - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - org.codehaus.groovy - groovy - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - org.codehaus.gmavenplus - gmavenplus-plugin - 1.5 - - - - addSources - addTestSources - generateStubs - compile - testGenerateStubs - testCompile - removeStubs - removeTestStubs - - - - - - - - diff --git a/initializr-generator/src/test/resources/project/groovy/standard/DemoApplication.groovy.gen b/initializr-generator/src/test/resources/project/groovy/standard/DemoApplication.groovy.gen deleted file mode 100644 index aea889c4..00000000 --- a/initializr-generator/src/test/resources/project/groovy/standard/DemoApplication.groovy.gen +++ /dev/null @@ -1,14 +0,0 @@ -package com.example.demo - -import org.springframework.boot.SpringApplication -import org.springframework.boot.autoconfigure.SpringBootApplication - -@SpringBootApplication -class DemoApplication { - - static void main(String[] args) { - SpringApplication.run(DemoApplication, args) - } - -} - diff --git a/initializr-generator/src/test/resources/project/groovy/standard/DemoApplicationTests.groovy.gen b/initializr-generator/src/test/resources/project/groovy/standard/DemoApplicationTests.groovy.gen deleted file mode 100644 index 561dfcbc..00000000 --- a/initializr-generator/src/test/resources/project/groovy/standard/DemoApplicationTests.groovy.gen +++ /dev/null @@ -1,17 +0,0 @@ -package com.example.demo - -import org.junit.Test -import org.junit.runner.RunWith -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.junit4.SpringRunner - -@RunWith(SpringRunner) -@SpringBootTest -class DemoApplicationTests { - - @Test - void contextLoads() { - } - -} - diff --git a/initializr-generator/src/test/resources/project/groovy/standard/DemoApplicationTestsWeb.groovy.gen b/initializr-generator/src/test/resources/project/groovy/standard/DemoApplicationTestsWeb.groovy.gen deleted file mode 100644 index 561dfcbc..00000000 --- a/initializr-generator/src/test/resources/project/groovy/standard/DemoApplicationTestsWeb.groovy.gen +++ /dev/null @@ -1,17 +0,0 @@ -package com.example.demo - -import org.junit.Test -import org.junit.runner.RunWith -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.junit4.SpringRunner - -@RunWith(SpringRunner) -@SpringBootTest -class DemoApplicationTests { - - @Test - void contextLoads() { - } - -} - diff --git a/initializr-generator/src/test/resources/project/groovy/standard/ServletInitializer.groovy.gen b/initializr-generator/src/test/resources/project/groovy/standard/ServletInitializer.groovy.gen deleted file mode 100644 index e759d136..00000000 --- a/initializr-generator/src/test/resources/project/groovy/standard/ServletInitializer.groovy.gen +++ /dev/null @@ -1,14 +0,0 @@ -package com.example.demo - -import org.springframework.boot.builder.SpringApplicationBuilder -import org.springframework.boot.web.servlet.support.SpringBootServletInitializer - -class ServletInitializer extends SpringBootServletInitializer { - - @Override - protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { - application.sources(DemoApplication) - } - -} - diff --git a/initializr-generator/src/test/resources/project/groovy/standard/build.gradle.gen b/initializr-generator/src/test/resources/project/groovy/standard/build.gradle.gen deleted file mode 100644 index 3367352f..00000000 --- a/initializr-generator/src/test/resources/project/groovy/standard/build.gradle.gen +++ /dev/null @@ -1,29 +0,0 @@ -buildscript { - ext { - springBootVersion = '2.1.1.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - } -} - -apply plugin: 'groovy' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '1.8' - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter' - implementation 'org.codehaus.groovy:groovy' - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/initializr-generator/src/test/resources/project/groovy/standard/pom.xml.gen b/initializr-generator/src/test/resources/project/groovy/standard/pom.xml.gen deleted file mode 100644 index 16035658..00000000 --- a/initializr-generator/src/test/resources/project/groovy/standard/pom.xml.gen +++ /dev/null @@ -1,66 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.1.RELEASE - - - com.example - demo - 0.0.1-SNAPSHOT - demo - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - org.codehaus.groovy - groovy - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - org.codehaus.gmavenplus - gmavenplus-plugin - 1.5 - - - - addSources - addTestSources - generateStubs - compile - testGenerateStubs - testCompile - removeStubs - removeTestStubs - - - - - - - - diff --git a/initializr-generator/src/test/resources/project/groovy/standard/war-build.gradle.gen b/initializr-generator/src/test/resources/project/groovy/standard/war-build.gradle.gen deleted file mode 100644 index a6b93b88..00000000 --- a/initializr-generator/src/test/resources/project/groovy/standard/war-build.gradle.gen +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - ext { - springBootVersion = '2.1.1.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - } -} - -apply plugin: 'groovy' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' -apply plugin: 'war' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '1.8' - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.codehaus.groovy:groovy' - providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/initializr-generator/src/test/resources/project/groovy/standard/war-pom.xml.gen b/initializr-generator/src/test/resources/project/groovy/standard/war-pom.xml.gen deleted file mode 100644 index 8524b4e7..00000000 --- a/initializr-generator/src/test/resources/project/groovy/standard/war-pom.xml.gen +++ /dev/null @@ -1,72 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.1.RELEASE - - - com.example - demo - 0.0.1-SNAPSHOT - war - demo - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter-web - - - org.codehaus.groovy - groovy - - - - org.springframework.boot - spring-boot-starter-tomcat - provided - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - org.codehaus.gmavenplus - gmavenplus-plugin - 1.5 - - - - addSources - addTestSources - generateStubs - compile - testGenerateStubs - testCompile - removeStubs - removeTestStubs - - - - - - - - diff --git a/initializr-generator/src/test/resources/project/java/previous/DemoApplication.java.gen b/initializr-generator/src/test/resources/project/java/previous/DemoApplication.java.gen deleted file mode 100644 index 3f3d9f66..00000000 --- a/initializr-generator/src/test/resources/project/java/previous/DemoApplication.java.gen +++ /dev/null @@ -1,14 +0,0 @@ -package com.example.demo; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class DemoApplication { - - public static void main(String[] args) { - SpringApplication.run(DemoApplication.class, args); - } - -} - diff --git a/initializr-generator/src/test/resources/project/java/previous/ServletInitializer.java.gen b/initializr-generator/src/test/resources/project/java/previous/ServletInitializer.java.gen deleted file mode 100644 index 02e2f8b3..00000000 --- a/initializr-generator/src/test/resources/project/java/previous/ServletInitializer.java.gen +++ /dev/null @@ -1,14 +0,0 @@ -package com.example.demo; - -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.web.support.SpringBootServletInitializer; - -public class ServletInitializer extends SpringBootServletInitializer { - - @Override - protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { - return application.sources(DemoApplication.class); - } - -} - diff --git a/initializr-generator/src/test/resources/project/java/previous/build.gradle.gen b/initializr-generator/src/test/resources/project/java/previous/build.gradle.gen deleted file mode 100644 index 7356c408..00000000 --- a/initializr-generator/src/test/resources/project/java/previous/build.gradle.gen +++ /dev/null @@ -1,27 +0,0 @@ -buildscript { - ext { - springBootVersion = '1.5.18.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'org.springframework.boot' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '1.8' - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter' - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/initializr-generator/src/test/resources/project/java/previous/pom.xml.gen b/initializr-generator/src/test/resources/project/java/previous/pom.xml.gen deleted file mode 100644 index 89e1fe8d..00000000 --- a/initializr-generator/src/test/resources/project/java/previous/pom.xml.gen +++ /dev/null @@ -1,43 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 1.5.18.RELEASE - - - com.example - demo - 0.0.1-SNAPSHOT - demo - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/initializr-generator/src/test/resources/project/java/standard/DemoApplication.java.gen b/initializr-generator/src/test/resources/project/java/standard/DemoApplication.java.gen deleted file mode 100644 index 3f3d9f66..00000000 --- a/initializr-generator/src/test/resources/project/java/standard/DemoApplication.java.gen +++ /dev/null @@ -1,14 +0,0 @@ -package com.example.demo; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class DemoApplication { - - public static void main(String[] args) { - SpringApplication.run(DemoApplication.class, args); - } - -} - diff --git a/initializr-generator/src/test/resources/project/java/standard/DemoApplicationTests.java.gen b/initializr-generator/src/test/resources/project/java/standard/DemoApplicationTests.java.gen deleted file mode 100644 index 28762238..00000000 --- a/initializr-generator/src/test/resources/project/java/standard/DemoApplicationTests.java.gen +++ /dev/null @@ -1,17 +0,0 @@ -package com.example.demo; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class DemoApplicationTests { - - @Test - public void contextLoads() { - } - -} - diff --git a/initializr-generator/src/test/resources/project/java/standard/DemoApplicationTestsWeb.java.gen b/initializr-generator/src/test/resources/project/java/standard/DemoApplicationTestsWeb.java.gen deleted file mode 100644 index 28762238..00000000 --- a/initializr-generator/src/test/resources/project/java/standard/DemoApplicationTestsWeb.java.gen +++ /dev/null @@ -1,17 +0,0 @@ -package com.example.demo; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -@RunWith(SpringRunner.class) -@SpringBootTest -public class DemoApplicationTests { - - @Test - public void contextLoads() { - } - -} - diff --git a/initializr-generator/src/test/resources/project/java/standard/ServletInitializer.java.gen b/initializr-generator/src/test/resources/project/java/standard/ServletInitializer.java.gen deleted file mode 100644 index c80d6051..00000000 --- a/initializr-generator/src/test/resources/project/java/standard/ServletInitializer.java.gen +++ /dev/null @@ -1,14 +0,0 @@ -package com.example.demo; - -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; - -public class ServletInitializer extends SpringBootServletInitializer { - - @Override - protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { - return application.sources(DemoApplication.class); - } - -} - diff --git a/initializr-generator/src/test/resources/project/java/standard/build.gradle.gen b/initializr-generator/src/test/resources/project/java/standard/build.gradle.gen deleted file mode 100644 index da6640ab..00000000 --- a/initializr-generator/src/test/resources/project/java/standard/build.gradle.gen +++ /dev/null @@ -1,28 +0,0 @@ -buildscript { - ext { - springBootVersion = '2.1.1.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '1.8' - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter' - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/initializr-generator/src/test/resources/project/java/standard/pom.xml.gen b/initializr-generator/src/test/resources/project/java/standard/pom.xml.gen deleted file mode 100644 index cc70ca31..00000000 --- a/initializr-generator/src/test/resources/project/java/standard/pom.xml.gen +++ /dev/null @@ -1,43 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.1.RELEASE - - - com.example - demo - 0.0.1-SNAPSHOT - demo - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/initializr-generator/src/test/resources/project/java/standard/war-build.gradle.gen b/initializr-generator/src/test/resources/project/java/standard/war-build.gradle.gen deleted file mode 100644 index 7cc8d961..00000000 --- a/initializr-generator/src/test/resources/project/java/standard/war-build.gradle.gen +++ /dev/null @@ -1,30 +0,0 @@ -buildscript { - ext { - springBootVersion = '2.1.1.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' -apply plugin: 'war' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '1.8' - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web' - providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} diff --git a/initializr-generator/src/test/resources/project/java/standard/war-pom.xml.gen b/initializr-generator/src/test/resources/project/java/standard/war-pom.xml.gen deleted file mode 100644 index d41a763d..00000000 --- a/initializr-generator/src/test/resources/project/java/standard/war-pom.xml.gen +++ /dev/null @@ -1,49 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.1.RELEASE - - - com.example - demo - 0.0.1-SNAPSHOT - war - demo - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-tomcat - provided - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/initializr-generator/src/test/resources/project/kotlin/previous/DemoApplication.kt.gen b/initializr-generator/src/test/resources/project/kotlin/previous/DemoApplication.kt.gen deleted file mode 100644 index 7eeb055e..00000000 --- a/initializr-generator/src/test/resources/project/kotlin/previous/DemoApplication.kt.gen +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.demo - -import org.springframework.boot.SpringApplication -import org.springframework.boot.autoconfigure.SpringBootApplication - -@SpringBootApplication -class DemoApplication - -fun main(args: Array) { - SpringApplication.run(DemoApplication::class.java, *args) -} - diff --git a/initializr-generator/src/test/resources/project/kotlin/previous/ServletInitializer.kt.gen b/initializr-generator/src/test/resources/project/kotlin/previous/ServletInitializer.kt.gen deleted file mode 100644 index fbe9d0f4..00000000 --- a/initializr-generator/src/test/resources/project/kotlin/previous/ServletInitializer.kt.gen +++ /dev/null @@ -1,13 +0,0 @@ -package com.example.demo - -import org.springframework.boot.builder.SpringApplicationBuilder -import org.springframework.boot.web.support.SpringBootServletInitializer - -class ServletInitializer : SpringBootServletInitializer() { - - override fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder { - return application.sources(DemoApplication::class.java) - } - -} - diff --git a/initializr-generator/src/test/resources/project/kotlin/previous/build.gradle.gen b/initializr-generator/src/test/resources/project/kotlin/previous/build.gradle.gen deleted file mode 100644 index 1c146386..00000000 --- a/initializr-generator/src/test/resources/project/kotlin/previous/build.gradle.gen +++ /dev/null @@ -1,47 +0,0 @@ -buildscript { - ext { - kotlinVersion = '1.1.1' - springBootVersion = '1.5.18.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}") - classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}") - } -} - -apply plugin: 'kotlin' -apply plugin: 'kotlin-spring' -apply plugin: 'org.springframework.boot' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '1.8' - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter' - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}" - implementation "org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}" - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} - -compileKotlin { - kotlinOptions { - freeCompilerArgs = ['-Xjsr305=strict'] - jvmTarget = '1.8' - } -} - -compileTestKotlin { - kotlinOptions { - freeCompilerArgs = ['-Xjsr305=strict'] - jvmTarget = '1.8' - } -} diff --git a/initializr-generator/src/test/resources/project/kotlin/previous/pom.xml.gen b/initializr-generator/src/test/resources/project/kotlin/previous/pom.xml.gen deleted file mode 100644 index 2c90aecc..00000000 --- a/initializr-generator/src/test/resources/project/kotlin/previous/pom.xml.gen +++ /dev/null @@ -1,93 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 1.5.18.RELEASE - - - com.example - demo - 0.0.1-SNAPSHOT - demo - Demo project for Spring Boot - - - 1.8 - 1.1.1 - - - - - org.springframework.boot - spring-boot-starter - - - org.jetbrains.kotlin - kotlin-reflect - ${kotlin.version} - - - org.jetbrains.kotlin - kotlin-stdlib-jdk8 - ${kotlin.version} - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - ${project.basedir}/src/main/kotlin - ${project.basedir}/src/test/kotlin - - - org.springframework.boot - spring-boot-maven-plugin - - - org.jetbrains.kotlin - kotlin-maven-plugin - ${kotlin.version} - - - -Xjsr305=strict - - - spring - - 1.8 - - - - compile - compile - - compile - - - - test-compile - test-compile - - test-compile - - - - - - org.jetbrains.kotlin - kotlin-maven-allopen - ${kotlin.version} - - - - - - - diff --git a/initializr-generator/src/test/resources/project/kotlin/standard/DemoApplication.kt.gen b/initializr-generator/src/test/resources/project/kotlin/standard/DemoApplication.kt.gen deleted file mode 100644 index 76194b55..00000000 --- a/initializr-generator/src/test/resources/project/kotlin/standard/DemoApplication.kt.gen +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.demo - -import org.springframework.boot.autoconfigure.SpringBootApplication -import org.springframework.boot.runApplication - -@SpringBootApplication -class DemoApplication - -fun main(args: Array) { - runApplication(*args) -} - diff --git a/initializr-generator/src/test/resources/project/kotlin/standard/DemoApplicationTests.kt.gen b/initializr-generator/src/test/resources/project/kotlin/standard/DemoApplicationTests.kt.gen deleted file mode 100644 index 45d1add7..00000000 --- a/initializr-generator/src/test/resources/project/kotlin/standard/DemoApplicationTests.kt.gen +++ /dev/null @@ -1,17 +0,0 @@ -package com.example.demo - -import org.junit.Test -import org.junit.runner.RunWith -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.junit4.SpringRunner - -@RunWith(SpringRunner::class) -@SpringBootTest -class DemoApplicationTests { - - @Test - fun contextLoads() { - } - -} - diff --git a/initializr-generator/src/test/resources/project/kotlin/standard/DemoApplicationTestsWeb.kt.gen b/initializr-generator/src/test/resources/project/kotlin/standard/DemoApplicationTestsWeb.kt.gen deleted file mode 100644 index 45d1add7..00000000 --- a/initializr-generator/src/test/resources/project/kotlin/standard/DemoApplicationTestsWeb.kt.gen +++ /dev/null @@ -1,17 +0,0 @@ -package com.example.demo - -import org.junit.Test -import org.junit.runner.RunWith -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.junit4.SpringRunner - -@RunWith(SpringRunner::class) -@SpringBootTest -class DemoApplicationTests { - - @Test - fun contextLoads() { - } - -} - diff --git a/initializr-generator/src/test/resources/project/kotlin/standard/ServletInitializer.kt.gen b/initializr-generator/src/test/resources/project/kotlin/standard/ServletInitializer.kt.gen deleted file mode 100644 index adca9a84..00000000 --- a/initializr-generator/src/test/resources/project/kotlin/standard/ServletInitializer.kt.gen +++ /dev/null @@ -1,13 +0,0 @@ -package com.example.demo - -import org.springframework.boot.builder.SpringApplicationBuilder -import org.springframework.boot.web.servlet.support.SpringBootServletInitializer - -class ServletInitializer : SpringBootServletInitializer() { - - override fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder { - return application.sources(DemoApplication::class.java) - } - -} - diff --git a/initializr-generator/src/test/resources/project/kotlin/standard/build.gradle.gen b/initializr-generator/src/test/resources/project/kotlin/standard/build.gradle.gen deleted file mode 100644 index d7b0ebfa..00000000 --- a/initializr-generator/src/test/resources/project/kotlin/standard/build.gradle.gen +++ /dev/null @@ -1,48 +0,0 @@ -buildscript { - ext { - kotlinVersion = '1.1.1' - springBootVersion = '2.1.1.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}") - classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}") - } -} - -apply plugin: 'kotlin' -apply plugin: 'kotlin-spring' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '1.8' - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter' - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" - implementation "org.jetbrains.kotlin:kotlin-reflect" - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} - -compileKotlin { - kotlinOptions { - freeCompilerArgs = ['-Xjsr305=strict'] - jvmTarget = '1.8' - } -} - -compileTestKotlin { - kotlinOptions { - freeCompilerArgs = ['-Xjsr305=strict'] - jvmTarget = '1.8' - } -} diff --git a/initializr-generator/src/test/resources/project/kotlin/standard/pom.xml.gen b/initializr-generator/src/test/resources/project/kotlin/standard/pom.xml.gen deleted file mode 100644 index c5365398..00000000 --- a/initializr-generator/src/test/resources/project/kotlin/standard/pom.xml.gen +++ /dev/null @@ -1,73 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.1.RELEASE - - - com.example - demo - 0.0.1-SNAPSHOT - demo - Demo project for Spring Boot - - - 1.8 - 1.1.1 - - - - - org.springframework.boot - spring-boot-starter - - - org.jetbrains.kotlin - kotlin-reflect - - - org.jetbrains.kotlin - kotlin-stdlib-jdk8 - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - ${project.basedir}/src/main/kotlin - ${project.basedir}/src/test/kotlin - - - org.springframework.boot - spring-boot-maven-plugin - - - org.jetbrains.kotlin - kotlin-maven-plugin - - - -Xjsr305=strict - - - spring - - - - - org.jetbrains.kotlin - kotlin-maven-allopen - ${kotlin.version} - - - - - - - diff --git a/initializr-generator/src/test/resources/project/kotlin/standard/war-build.gradle.gen b/initializr-generator/src/test/resources/project/kotlin/standard/war-build.gradle.gen deleted file mode 100644 index d4e929ec..00000000 --- a/initializr-generator/src/test/resources/project/kotlin/standard/war-build.gradle.gen +++ /dev/null @@ -1,50 +0,0 @@ -buildscript { - ext { - kotlinVersion = '1.1.1' - springBootVersion = '2.1.1.RELEASE' - } - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") - classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}") - classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlinVersion}") - } -} - -apply plugin: 'kotlin' -apply plugin: 'kotlin-spring' -apply plugin: 'org.springframework.boot' -apply plugin: 'io.spring.dependency-management' -apply plugin: 'war' - -group = 'com.example' -version = '0.0.1-SNAPSHOT' -sourceCompatibility = '1.8' - -repositories { - mavenCentral() -} - -dependencies { - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" - implementation "org.jetbrains.kotlin:kotlin-reflect" - providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' - testImplementation 'org.springframework.boot:spring-boot-starter-test' -} - -compileKotlin { - kotlinOptions { - freeCompilerArgs = ['-Xjsr305=strict'] - jvmTarget = '1.8' - } -} - -compileTestKotlin { - kotlinOptions { - freeCompilerArgs = ['-Xjsr305=strict'] - jvmTarget = '1.8' - } -} diff --git a/initializr-generator/src/test/resources/project/kotlin/standard/war-pom.xml.gen b/initializr-generator/src/test/resources/project/kotlin/standard/war-pom.xml.gen deleted file mode 100644 index c1697e5a..00000000 --- a/initializr-generator/src/test/resources/project/kotlin/standard/war-pom.xml.gen +++ /dev/null @@ -1,79 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.1.RELEASE - - - com.example - demo - 0.0.1-SNAPSHOT - war - demo - Demo project for Spring Boot - - - 1.8 - 1.1.1 - - - - - org.springframework.boot - spring-boot-starter-web - - - org.jetbrains.kotlin - kotlin-reflect - - - org.jetbrains.kotlin - kotlin-stdlib-jdk8 - - - - org.springframework.boot - spring-boot-starter-tomcat - provided - - - org.springframework.boot - spring-boot-starter-test - test - - - - - ${project.basedir}/src/main/kotlin - ${project.basedir}/src/test/kotlin - - - org.springframework.boot - spring-boot-maven-plugin - - - org.jetbrains.kotlin - kotlin-maven-plugin - - - -Xjsr305=strict - - - spring - - - - - org.jetbrains.kotlin - kotlin-maven-allopen - ${kotlin.version} - - - - - - - diff --git a/initializr-generator/src/test/resources/project/maven/annotation-processor-dependency-pom.xml.gen b/initializr-generator/src/test/resources/project/maven/annotation-processor-dependency-pom.xml.gen deleted file mode 100644 index d02e5c59..00000000 --- a/initializr-generator/src/test/resources/project/maven/annotation-processor-dependency-pom.xml.gen +++ /dev/null @@ -1,52 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.1.RELEASE - - - com.example - demo - 0.0.1-SNAPSHOT - demo - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter-data-jpa - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-configuration-processor - true - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/initializr-generator/src/test/resources/project/maven/bom-ordering-pom.xml.gen b/initializr-generator/src/test/resources/project/maven/bom-ordering-pom.xml.gen deleted file mode 100644 index 55b12130..00000000 --- a/initializr-generator/src/test/resources/project/maven/bom-ordering-pom.xml.gen +++ /dev/null @@ -1,69 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.1.RELEASE - - - com.example - demo - 0.0.1-SNAPSHOT - demo - Demo project for Spring Boot - - - 1.8 - - - - - org.acme - foo - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.acme - foo-bom - 1.0 - pom - import - - - org.acme - biz-bom - 1.0 - pom - import - - - org.acme - bar-bom - 1.0 - pom - import - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/initializr-generator/src/test/resources/project/maven/bom-property-pom.xml.gen b/initializr-generator/src/test/resources/project/maven/bom-property-pom.xml.gen deleted file mode 100644 index 1efe27ad..00000000 --- a/initializr-generator/src/test/resources/project/maven/bom-property-pom.xml.gen +++ /dev/null @@ -1,56 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.1.RELEASE - - - com.example - demo - 0.0.1-SNAPSHOT - demo - Demo project for Spring Boot - - - 1.8 - 1.3.3 - - - - - org.acme - foo - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.acme - foo-bom - ${foo.version} - pom - import - - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/initializr-generator/src/test/resources/project/maven/compile-only-dependency-pom.xml.gen b/initializr-generator/src/test/resources/project/maven/compile-only-dependency-pom.xml.gen deleted file mode 100644 index 3cdf6861..00000000 --- a/initializr-generator/src/test/resources/project/maven/compile-only-dependency-pom.xml.gen +++ /dev/null @@ -1,52 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.1.RELEASE - - - com.example - demo - 0.0.1-SNAPSHOT - demo - Demo project for Spring Boot - - - 1.8 - - - - - org.springframework.boot - spring-boot-starter-data-jpa - - - org.springframework.boot - spring-boot-starter-web - - - - org.acme - foo - true - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/initializr-generator/src/test/resources/project/maven/gitignore.gen b/initializr-generator/src/test/resources/project/maven/gitignore.gen deleted file mode 100644 index c456c4a3..00000000 --- a/initializr-generator/src/test/resources/project/maven/gitignore.gen +++ /dev/null @@ -1,25 +0,0 @@ -/target/ -!.mvn/wrapper/maven-wrapper.jar - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -/build/ diff --git a/initializr-generator/src/test/resources/project/maven/kotlin-java11-pom.xml.gen b/initializr-generator/src/test/resources/project/maven/kotlin-java11-pom.xml.gen deleted file mode 100644 index c73bcd1d..00000000 --- a/initializr-generator/src/test/resources/project/maven/kotlin-java11-pom.xml.gen +++ /dev/null @@ -1,73 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.1.RELEASE - - - com.example - demo - 0.0.1-SNAPSHOT - demo - Demo project for Spring Boot - - - 11 - 1.1.1 - - - - - org.springframework.boot - spring-boot-starter - - - org.jetbrains.kotlin - kotlin-reflect - - - org.jetbrains.kotlin - kotlin-stdlib-jdk8 - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - ${project.basedir}/src/main/kotlin - ${project.basedir}/src/test/kotlin - - - org.springframework.boot - spring-boot-maven-plugin - - - org.jetbrains.kotlin - kotlin-maven-plugin - - - -Xjsr305=strict - - - spring - - - - - org.jetbrains.kotlin - kotlin-maven-allopen - ${kotlin.version} - - - - - - - diff --git a/initializr-generator/src/test/resources/project/maven/repositories-milestone-pom.xml.gen b/initializr-generator/src/test/resources/project/maven/repositories-milestone-pom.xml.gen deleted file mode 100644 index 06d73f11..00000000 --- a/initializr-generator/src/test/resources/project/maven/repositories-milestone-pom.xml.gen +++ /dev/null @@ -1,74 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.2.0.M1 - - - com.example - demo - 0.0.1-SNAPSHOT - demo - Demo project for Spring Boot - - - 1.8 - - - - - org.acme - foo - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - - - - spring-snapshots - Spring Snapshots - https://repo.spring.io/snapshot - - true - - - - spring-milestones - Spring Milestones - https://repo.spring.io/milestone - - - - diff --git a/initializr-generator/src/test/resources/project/maven/repositories-pom.xml.gen b/initializr-generator/src/test/resources/project/maven/repositories-pom.xml.gen deleted file mode 100644 index 82d93405..00000000 --- a/initializr-generator/src/test/resources/project/maven/repositories-pom.xml.gen +++ /dev/null @@ -1,63 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.1.RELEASE - - - com.example - demo - 0.0.1-SNAPSHOT - demo - Demo project for Spring Boot - - - 1.8 - - - - - org.acme - bar - - - org.acme - foo - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - - - foo-repository - foo-repo - https://example.com/foo - - - bar-repository - bar-repo - https://example.com/bar - - true - - - - - diff --git a/initializr-generator/src/test/resources/project/maven/version-override-pom.xml.gen b/initializr-generator/src/test/resources/project/maven/version-override-pom.xml.gen deleted file mode 100644 index 0c72776c..00000000 --- a/initializr-generator/src/test/resources/project/maven/version-override-pom.xml.gen +++ /dev/null @@ -1,45 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.1.1.RELEASE - - - com.example - demo - 0.0.1-SNAPSHOT - demo - Demo project for Spring Boot - - - 1.8 - 0.2.0.RELEASE - 0.1.0.RELEASE - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - - diff --git a/initializr-web/pom.xml b/initializr-web/pom.xml index 64be5727..1649aabf 100644 --- a/initializr-web/pom.xml +++ b/initializr-web/pom.xml @@ -79,6 +79,18 @@ test-jar test + + io.spring.initializr.experimental + initializr-generator + test-jar + test + + + io.spring.initializr.experimental + initializr-generator-spring + test-jar + test + org.springframework.boot spring-boot-starter-web diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/InvalidProjectRequestException.java b/initializr-web/src/main/java/io/spring/initializr/web/InvalidProjectRequestException.java similarity index 91% rename from initializr-generator/src/main/java/io/spring/initializr/generator/InvalidProjectRequestException.java rename to initializr-web/src/main/java/io/spring/initializr/web/InvalidProjectRequestException.java index c94f25eb..3447ab04 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/InvalidProjectRequestException.java +++ b/initializr-web/src/main/java/io/spring/initializr/web/InvalidProjectRequestException.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.spring.initializr.generator; +package io.spring.initializr.web; import io.spring.initializr.InitializrException; diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectResourceLocator.java b/initializr-web/src/main/java/io/spring/initializr/web/ProjectResourceLocator.java similarity index 95% rename from initializr-generator/src/main/java/io/spring/initializr/generator/ProjectResourceLocator.java rename to initializr-web/src/main/java/io/spring/initializr/web/ProjectResourceLocator.java index 51752d65..c6ad87c2 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectResourceLocator.java +++ b/initializr-web/src/main/java/io/spring/initializr/web/ProjectResourceLocator.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.spring.initializr.generator; +package io.spring.initializr.web; import java.io.IOException; import java.io.InputStream; diff --git a/initializr-web/src/main/java/io/spring/initializr/web/autoconfigure/InitializrAutoConfiguration.java b/initializr-web/src/main/java/io/spring/initializr/web/autoconfigure/InitializrAutoConfiguration.java index 346721d2..1eee6fda 100644 --- a/initializr-web/src/main/java/io/spring/initializr/web/autoconfigure/InitializrAutoConfiguration.java +++ b/initializr-web/src/main/java/io/spring/initializr/web/autoconfigure/InitializrAutoConfiguration.java @@ -16,30 +16,30 @@ package io.spring.initializr.web.autoconfigure; -import java.util.ArrayList; -import java.util.List; +import java.nio.file.Files; import javax.cache.configuration.MutableConfiguration; import javax.cache.expiry.CreatedExpiryPolicy; import javax.cache.expiry.Duration; import com.fasterxml.jackson.databind.ObjectMapper; -import io.spring.initializr.generator.ProjectGenerator; -import io.spring.initializr.generator.ProjectRequestPostProcessor; -import io.spring.initializr.generator.ProjectRequestResolver; -import io.spring.initializr.generator.ProjectResourceLocator; +import io.spring.initializr.generator.io.IndentingWriterFactory; +import io.spring.initializr.generator.io.SimpleIndentStrategy; +import io.spring.initializr.generator.project.ProjectDirectoryFactory; import io.spring.initializr.metadata.DependencyMetadataProvider; import io.spring.initializr.metadata.InitializrMetadata; import io.spring.initializr.metadata.InitializrMetadataBuilder; import io.spring.initializr.metadata.InitializrMetadataProvider; import io.spring.initializr.metadata.InitializrProperties; import io.spring.initializr.util.TemplateRenderer; +import io.spring.initializr.web.ProjectResourceLocator; import io.spring.initializr.web.project.MainController; +import io.spring.initializr.web.project.ProjectGenerationInvoker; +import io.spring.initializr.web.project.ProjectRequestToDescriptionConverter; import io.spring.initializr.web.support.DefaultDependencyMetadataProvider; import io.spring.initializr.web.support.DefaultInitializrMetadataProvider; import io.spring.initializr.web.ui.UiController; -import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -50,6 +50,8 @@ import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfigu import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.bind.Binder; import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; @@ -60,9 +62,6 @@ import org.springframework.web.servlet.resource.ResourceUrlProvider; * Auto-configuration} to configure Spring initializr. In a web environment, configures * the necessary controller to serve the applications from the root context. * - *

- * Project generation can be customized by defining a custom {@link ProjectGenerator}. - * * @author Stephane Nicoll */ @Configuration @@ -71,18 +70,16 @@ import org.springframework.web.servlet.resource.ResourceUrlProvider; RestTemplateAutoConfiguration.class }) public class InitializrAutoConfiguration { - private final List postProcessors; - - public InitializrAutoConfiguration( - ObjectProvider> postProcessors) { - List list = postProcessors.getIfAvailable(); - this.postProcessors = (list != null) ? list : new ArrayList<>(); + @Bean + @ConditionalOnMissingBean + public ProjectDirectoryFactory projectDirectoryFactory() { + return (description) -> Files.createTempDirectory("project-"); } @Bean @ConditionalOnMissingBean - public ProjectGenerator projectGenerator() { - return new ProjectGenerator(); + public IndentingWriterFactory indentingWriterFactory() { + return IndentingWriterFactory.create(new SimpleIndentStrategy("\t")); } @Bean @@ -95,12 +92,6 @@ public class InitializrAutoConfiguration { return templateRenderer; } - @Bean - @ConditionalOnMissingBean - public ProjectRequestResolver projectRequestResolver() { - return new ProjectRequestResolver(this.postProcessors); - } - @Bean @ConditionalOnMissingBean public ProjectResourceLocator projectResourceLocator() { @@ -142,10 +133,26 @@ public class InitializrAutoConfiguration { InitializrMetadataProvider metadataProvider, TemplateRenderer templateRenderer, ResourceUrlProvider resourceUrlProvider, - ProjectGenerator projectGenerator, - DependencyMetadataProvider dependencyMetadataProvider) { + DependencyMetadataProvider dependencyMetadataProvider, + ProjectGenerationInvoker projectGenerationInvoker) { return new MainController(metadataProvider, templateRenderer, - resourceUrlProvider, projectGenerator, dependencyMetadataProvider); + resourceUrlProvider, dependencyMetadataProvider, + projectGenerationInvoker); + } + + @Bean + @ConditionalOnMissingBean + public ProjectGenerationInvoker projectGenerationInvoker( + ApplicationContext applicationContext, + ApplicationEventPublisher eventPublisher, + ProjectRequestToDescriptionConverter projectRequestToDescriptionConverter) { + return new ProjectGenerationInvoker(applicationContext, eventPublisher, + projectRequestToDescriptionConverter); + } + + @Bean + public ProjectRequestToDescriptionConverter projectRequestToDescriptionConverter() { + return new ProjectRequestToDescriptionConverter(); } @Bean @@ -177,6 +184,7 @@ public class InitializrAutoConfiguration { CreatedExpiryPolicy.factoryOf(Duration.TEN_MINUTES))); cacheManager.createCache("initializr.dependency-metadata", config()); cacheManager.createCache("initializr.project-resources", config()); + cacheManager.createCache("initializr.templates", config()); }; } diff --git a/initializr-web/src/main/java/io/spring/initializr/web/project/AbstractInitializrController.java b/initializr-web/src/main/java/io/spring/initializr/web/project/AbstractInitializrController.java index 5f644630..efc9d04b 100644 --- a/initializr-web/src/main/java/io/spring/initializr/web/project/AbstractInitializrController.java +++ b/initializr-web/src/main/java/io/spring/initializr/web/project/AbstractInitializrController.java @@ -23,10 +23,10 @@ import java.util.function.Function; import javax.servlet.http.HttpServletResponse; -import io.spring.initializr.generator.InvalidProjectRequestException; import io.spring.initializr.metadata.InitializrMetadata; import io.spring.initializr.metadata.InitializrMetadataProvider; import io.spring.initializr.metadata.TypeCapability; +import io.spring.initializr.web.InvalidProjectRequestException; import org.springframework.beans.BeanWrapperImpl; import org.springframework.http.HttpStatus; diff --git a/initializr-web/src/main/java/io/spring/initializr/web/project/MainController.java b/initializr-web/src/main/java/io/spring/initializr/web/project/MainController.java index 6124c755..145b7d6e 100644 --- a/initializr-web/src/main/java/io/spring/initializr/web/project/MainController.java +++ b/initializr-web/src/main/java/io/spring/initializr/web/project/MainController.java @@ -28,9 +28,6 @@ import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServletRequest; import com.samskivert.mustache.Mustache; -import io.spring.initializr.generator.BasicProjectRequest; -import io.spring.initializr.generator.ProjectGenerator; -import io.spring.initializr.generator.ProjectRequest; import io.spring.initializr.metadata.DependencyMetadata; import io.spring.initializr.metadata.DependencyMetadataProvider; import io.spring.initializr.metadata.InitializrMetadata; @@ -87,26 +84,25 @@ public class MainController extends AbstractInitializrController { public static final MediaType HAL_JSON_CONTENT_TYPE = MediaType .parseMediaType("application/hal+json"); - private final ProjectGenerator projectGenerator; - private final DependencyMetadataProvider dependencyMetadataProvider; private final CommandLineHelpGenerator commandLineHelpGenerator; + private final ProjectGenerationInvoker projectGenerationInvoker; + public MainController(InitializrMetadataProvider metadataProvider, TemplateRenderer templateRenderer, ResourceUrlProvider resourceUrlProvider, - ProjectGenerator projectGenerator, - DependencyMetadataProvider dependencyMetadataProvider) { + DependencyMetadataProvider dependencyMetadataProvider, + ProjectGenerationInvoker projectGenerationInvoker) { super(metadataProvider, resourceUrlProvider); - this.projectGenerator = projectGenerator; this.dependencyMetadataProvider = dependencyMetadataProvider; this.commandLineHelpGenerator = new CommandLineHelpGenerator(templateRenderer); + this.projectGenerationInvoker = projectGenerationInvoker; } @ModelAttribute - public BasicProjectRequest projectRequest( - @RequestHeader Map headers) { - ProjectRequest request = new ProjectRequest(); + public ProjectRequest projectRequest(@RequestHeader Map headers) { + WebProjectRequest request = new WebProjectRequest(); request.getParameters().putAll(headers); request.initialize(this.metadataProvider.get()); return request; @@ -246,32 +242,27 @@ public class MainController extends AbstractInitializrController { @RequestMapping(path = { "/pom", "/pom.xml" }) @ResponseBody - public ResponseEntity pom(BasicProjectRequest request) { + public ResponseEntity pom(ProjectRequest request) { request.setType("maven-build"); - byte[] mavenPom = this.projectGenerator - .generateMavenPom((ProjectRequest) request); + byte[] mavenPom = this.projectGenerationInvoker.invokeBuildGeneration(request); return createResponseEntity(mavenPom, "application/octet-stream", "pom.xml"); } @RequestMapping(path = { "/build", "/build.gradle" }) @ResponseBody - public ResponseEntity gradle(BasicProjectRequest request) { + public ResponseEntity gradle(ProjectRequest request) { request.setType("gradle-build"); - byte[] gradleBuild = this.projectGenerator - .generateGradleBuild((ProjectRequest) request); + byte[] gradleBuild = this.projectGenerationInvoker.invokeBuildGeneration(request); return createResponseEntity(gradleBuild, "application/octet-stream", "build.gradle"); } @RequestMapping("/starter.zip") @ResponseBody - public ResponseEntity springZip(BasicProjectRequest basicRequest) - throws IOException { - ProjectRequest request = (ProjectRequest) basicRequest; - File dir = this.projectGenerator.generateProjectStructure(request); - - File download = this.projectGenerator.createDistributionFile(dir, ".zip"); - + public ResponseEntity springZip(ProjectRequest request) throws IOException { + File dir = this.projectGenerationInvoker + .invokeProjectStructureGeneration(request); + File download = this.projectGenerationInvoker.createDistributionFile(dir, ".zip"); String wrapperScript = getWrapperScript(request); new File(dir, wrapperScript).setExecutable(true); Zip zip = new Zip(); @@ -296,13 +287,11 @@ public class MainController extends AbstractInitializrController { @RequestMapping(path = "/starter.tgz", produces = "application/x-compress") @ResponseBody - public ResponseEntity springTgz(BasicProjectRequest basicRequest) - throws IOException { - ProjectRequest request = (ProjectRequest) basicRequest; - File dir = this.projectGenerator.generateProjectStructure(request); - - File download = this.projectGenerator.createDistributionFile(dir, ".tar.gz"); - + public ResponseEntity springTgz(ProjectRequest request) throws IOException { + File dir = this.projectGenerationInvoker + .invokeProjectStructureGeneration(request); + File download = this.projectGenerationInvoker.createDistributionFile(dir, + ".tar.gz"); String wrapperScript = getWrapperScript(request); new File(dir, wrapperScript).setExecutable(true); Tar zip = new Tar(); @@ -338,7 +327,8 @@ public class MainController extends AbstractInitializrController { } private static String getWrapperScript(ProjectRequest request) { - String script = ("gradle".equals(request.getBuild()) ? "gradlew" : "mvnw"); + String script = (request.getType() != null + && request.getType().startsWith("gradle")) ? "gradlew" : "mvnw"; return (request.getBaseDir() != null) ? request.getBaseDir() + "/" + script : script; } @@ -349,7 +339,7 @@ public class MainController extends AbstractInitializrController { log.info("Uploading: {} ({} bytes)", download, bytes.length); ResponseEntity result = createResponseEntity(bytes, contentType, fileName); - this.projectGenerator.cleanTempFiles(dir); + this.projectGenerationInvoker.cleanTempFiles(dir); return result; } diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectFailedEvent.java b/initializr-web/src/main/java/io/spring/initializr/web/project/ProjectFailedEvent.java similarity index 82% rename from initializr-generator/src/main/java/io/spring/initializr/generator/ProjectFailedEvent.java rename to initializr-web/src/main/java/io/spring/initializr/web/project/ProjectFailedEvent.java index 194a68bc..34f24c3c 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectFailedEvent.java +++ b/initializr-web/src/main/java/io/spring/initializr/web/project/ProjectFailedEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.spring.initializr.generator; +package io.spring.initializr.web.project; import io.spring.initializr.metadata.InitializrMetadata; @@ -27,9 +27,9 @@ public class ProjectFailedEvent extends ProjectRequestEvent { private final Exception cause; - public ProjectFailedEvent(ProjectRequest projectRequest, InitializrMetadata metadata, + public ProjectFailedEvent(ProjectRequest request, InitializrMetadata metadata, Exception cause) { - super(projectRequest, metadata); + super(request, metadata); this.cause = cause; } diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectGeneratedEvent.java b/initializr-web/src/main/java/io/spring/initializr/web/project/ProjectGeneratedEvent.java similarity index 78% rename from initializr-generator/src/main/java/io/spring/initializr/generator/ProjectGeneratedEvent.java rename to initializr-web/src/main/java/io/spring/initializr/web/project/ProjectGeneratedEvent.java index 2859e59b..2718e2f3 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectGeneratedEvent.java +++ b/initializr-web/src/main/java/io/spring/initializr/web/project/ProjectGeneratedEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.spring.initializr.generator; +package io.spring.initializr.web.project; import io.spring.initializr.metadata.InitializrMetadata; @@ -25,9 +25,8 @@ import io.spring.initializr.metadata.InitializrMetadata; */ public class ProjectGeneratedEvent extends ProjectRequestEvent { - public ProjectGeneratedEvent(ProjectRequest projectRequest, - InitializrMetadata metadata) { - super(projectRequest, metadata); + public ProjectGeneratedEvent(ProjectRequest request, InitializrMetadata metadata) { + super(request, metadata); } } diff --git a/initializr-web/src/main/java/io/spring/initializr/web/project/ProjectGenerationInvoker.java b/initializr-web/src/main/java/io/spring/initializr/web/project/ProjectGenerationInvoker.java new file mode 100644 index 00000000..fbbaba2d --- /dev/null +++ b/initializr-web/src/main/java/io/spring/initializr/web/project/ProjectGenerationInvoker.java @@ -0,0 +1,215 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.initializr.web.project; + +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import io.spring.initializr.InitializrException; +import io.spring.initializr.generator.buildsystem.Build; +import io.spring.initializr.generator.buildsystem.BuildItemResolver; +import io.spring.initializr.generator.project.DefaultProjectAssetGenerator; +import io.spring.initializr.generator.project.ProjectAssetGenerator; +import io.spring.initializr.generator.project.ProjectDescription; +import io.spring.initializr.generator.project.ProjectGenerationContext; +import io.spring.initializr.generator.project.ProjectGenerationException; +import io.spring.initializr.generator.project.ProjectGenerator; +import io.spring.initializr.generator.project.ResolvedProjectDescription; +import io.spring.initializr.generator.spring.build.BuildWriter; +import io.spring.initializr.generator.spring.build.MetadataBuildItemResolver; +import io.spring.initializr.metadata.InitializrMetadata; +import io.spring.initializr.metadata.InitializrMetadataProvider; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.util.FileSystemUtils; + +/** + * Invokes the project generation API. This is an intermediate layer that can consume a + * {@link ProjectRequest} and trigger project generation based on the request. + * + * @author Madhura Bhave + */ +public class ProjectGenerationInvoker { + + private final ApplicationContext parentApplicationContext; + + private final ApplicationEventPublisher eventPublisher; + + private final ProjectRequestToDescriptionConverter converter; + + private transient Map> temporaryFiles = new LinkedHashMap<>(); + + public ProjectGenerationInvoker(ApplicationContext parentApplicationContext, + ApplicationEventPublisher eventPublisher, + ProjectRequestToDescriptionConverter converter) { + this.parentApplicationContext = parentApplicationContext; + this.eventPublisher = eventPublisher; + this.converter = converter; + } + + /** + * Invokes the project generation API that generates the entire project structure for + * the specified {@link WebProjectRequest}. Returns a directory containing the + * project. + * @param request the project request + * @return the generated project structure + */ + public File invokeProjectStructureGeneration(ProjectRequest request) { + InitializrMetadata metadata = this.parentApplicationContext + .getBean(InitializrMetadataProvider.class).get(); + try { + ProjectDescription projectDescription = this.converter.convert(request, + metadata); + ProjectGenerator projectGenerator = new ProjectGenerator( + (projectGenerationContext) -> customizeProjectGenerationContext( + projectGenerationContext, metadata)); + Path path = projectGenerator.generate(projectDescription, + generateProject(request)); + File file = path.toFile(); + String name = file.getName(); + addTempFile(name, file); + return file; + } + catch (ProjectGenerationException | InitializrException ex) { + publishProjectFailedEvent(request, metadata, ex); + throw ex; + } + } + + private ProjectAssetGenerator generateProject(ProjectRequest request) { + return (context) -> { + Path projectDir = new DefaultProjectAssetGenerator().generate(context); + publishProjectGeneratedEvent(request, context); + return projectDir; + }; + } + + /** + * Invokes the project generation API that knows how to just write the build file. + * Returns a directory containing the project for the specified + * {@link WebProjectRequest}. + * @param request the project request + * @return the generated build content + */ + public byte[] invokeBuildGeneration(ProjectRequest request) { + InitializrMetadata metadata = this.parentApplicationContext + .getBean(InitializrMetadataProvider.class).get(); + try { + ProjectDescription projectDescription = this.converter.convert(request, + metadata); + ProjectGenerator projectGenerator = new ProjectGenerator( + (projectGenerationContext) -> customizeProjectGenerationContext( + projectGenerationContext, metadata)); + return projectGenerator.generate(projectDescription, generateBuild(request)); + } + catch (ProjectGenerationException | InitializrException ex) { + publishProjectFailedEvent(request, metadata, ex); + throw ex; + } + } + + private ProjectAssetGenerator generateBuild(ProjectRequest request) { + return (context) -> { + byte[] content = generateBuild(context); + publishProjectGeneratedEvent(request, context); + return content; + }; + } + + /** + * Create a file in the same directory as the given directory using the directory name + * and extension. + * @param dir the directory used to determine the path and name of the new file + * @param extension the extension to use for the new file + * @return the newly created file + */ + public File createDistributionFile(File dir, String extension) { + File download = new File(dir.getParent(), dir.getName() + extension); + addTempFile(dir.getName(), download); + return download; + } + + private void addTempFile(String group, File file) { + this.temporaryFiles.computeIfAbsent(group, (key) -> new ArrayList<>()).add(file); + } + + /** + * Clean all the temporary files that are related to this root directory. + * @param dir the directory to clean + * @see #createDistributionFile + */ + public void cleanTempFiles(File dir) { + List tempFiles = this.temporaryFiles.remove(dir.getName()); + if (!tempFiles.isEmpty()) { + tempFiles.forEach((File file) -> { + if (file.isDirectory()) { + FileSystemUtils.deleteRecursively(file); + } + else if (file.exists()) { + file.delete(); + } + }); + } + } + + private byte[] generateBuild(ProjectGenerationContext context) throws IOException { + ResolvedProjectDescription projectDescription = context + .getBean(ResolvedProjectDescription.class); + StringWriter out = new StringWriter(); + BuildWriter buildWriter = context.getBeanProvider(BuildWriter.class) + .getIfAvailable(); + if (buildWriter != null) { + buildWriter.writeBuild(out); + return out.toString().getBytes(); + } + else { + throw new IllegalStateException("No BuildWriter implementation found for " + + projectDescription.getLanguage()); + } + } + + private void customizeProjectGenerationContext( + AnnotationConfigApplicationContext context, InitializrMetadata metadata) { + context.setParent(this.parentApplicationContext); + context.registerBean(InitializrMetadata.class, () -> metadata); + context.registerBean(BuildItemResolver.class, + () -> new MetadataBuildItemResolver(metadata)); + } + + private void publishProjectGeneratedEvent(ProjectRequest request, + ProjectGenerationContext context) { + Build build = context.getBeanProvider(Build.class).getIfAvailable(); + InitializrMetadata metadata = context.getBean(InitializrMetadata.class); + ProjectGeneratedEvent event = new ProjectGeneratedEvent(request, metadata); + this.eventPublisher.publishEvent(event); + } + + private void publishProjectFailedEvent(ProjectRequest request, + InitializrMetadata metadata, Exception cause) { + ProjectFailedEvent event = new ProjectFailedEvent(request, metadata, cause); + this.eventPublisher.publishEvent(event); + } + +} diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/BasicProjectRequest.java b/initializr-web/src/main/java/io/spring/initializr/web/project/ProjectRequest.java similarity index 96% rename from initializr-generator/src/main/java/io/spring/initializr/generator/BasicProjectRequest.java rename to initializr-web/src/main/java/io/spring/initializr/web/project/ProjectRequest.java index d8a3f5a4..fb6480fd 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/BasicProjectRequest.java +++ b/initializr-web/src/main/java/io/spring/initializr/web/project/ProjectRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.spring.initializr.generator; +package io.spring.initializr.web.project; import java.util.ArrayList; import java.util.List; @@ -26,7 +26,7 @@ import org.springframework.util.StringUtils; * * @author Stephane Nicoll */ -public class BasicProjectRequest { +public class ProjectRequest { private List style = new ArrayList<>(); diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectRequestEvent.java b/initializr-web/src/main/java/io/spring/initializr/web/project/ProjectRequestEvent.java similarity index 83% rename from initializr-generator/src/main/java/io/spring/initializr/generator/ProjectRequestEvent.java rename to initializr-web/src/main/java/io/spring/initializr/web/project/ProjectRequestEvent.java index cae4479c..9b28fd62 100644 --- a/initializr-generator/src/main/java/io/spring/initializr/generator/ProjectRequestEvent.java +++ b/initializr-web/src/main/java/io/spring/initializr/web/project/ProjectRequestEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,7 +14,7 @@ * limitations under the License. */ -package io.spring.initializr.generator; +package io.spring.initializr.web.project; import io.spring.initializr.metadata.InitializrMetadata; @@ -27,15 +27,14 @@ import io.spring.initializr.metadata.InitializrMetadata; */ public abstract class ProjectRequestEvent { - private final ProjectRequest projectRequest; + private final ProjectRequest request; private final InitializrMetadata metadata; private final long timestamp; - protected ProjectRequestEvent(ProjectRequest projectRequest, - InitializrMetadata metadata) { - this.projectRequest = projectRequest; + protected ProjectRequestEvent(ProjectRequest request, InitializrMetadata metadata) { + this.request = request; this.metadata = metadata; this.timestamp = System.currentTimeMillis(); } @@ -45,7 +44,7 @@ public abstract class ProjectRequestEvent { * @return the project request */ public ProjectRequest getProjectRequest() { - return this.projectRequest; + return this.request; } /** diff --git a/initializr-web/src/main/java/io/spring/initializr/web/project/ProjectRequestToDescriptionConverter.java b/initializr-web/src/main/java/io/spring/initializr/web/project/ProjectRequestToDescriptionConverter.java new file mode 100644 index 00000000..955bff17 --- /dev/null +++ b/initializr-web/src/main/java/io/spring/initializr/web/project/ProjectRequestToDescriptionConverter.java @@ -0,0 +1,167 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.initializr.web.project; + +import java.util.List; +import java.util.stream.Collectors; + +import io.spring.initializr.generator.buildsystem.BuildSystem; +import io.spring.initializr.generator.buildsystem.gradle.GradleBuildSystem; +import io.spring.initializr.generator.buildsystem.maven.MavenBuildSystem; +import io.spring.initializr.generator.language.Language; +import io.spring.initializr.generator.packaging.Packaging; +import io.spring.initializr.generator.project.ProjectDescription; +import io.spring.initializr.generator.spring.build.MetadataBuildItemMapper; +import io.spring.initializr.metadata.DefaultMetadataElement; +import io.spring.initializr.metadata.Dependency; +import io.spring.initializr.metadata.InitializrMetadata; +import io.spring.initializr.metadata.Type; +import io.spring.initializr.util.Version; +import io.spring.initializr.web.InvalidProjectRequestException; + +import org.springframework.util.StringUtils; + +/** + * Validates a {@link ProjectRequest} and creates a {@link ProjectDescription} from it. + * + * @author Madhura Bhave + */ +public class ProjectRequestToDescriptionConverter { + + private static final Version VERSION_1_5_0 = Version.parse("1.5.0.RELEASE"); + + public ProjectDescription convert(ProjectRequest request, + InitializrMetadata metadata) { + validate(request, metadata); + ProjectDescription description = new ProjectDescription(); + description.setApplicationName(getApplicationName(request, metadata)); + description.setArtifactId(request.getArtifactId()); + description.setBaseDirectory(request.getBaseDir()); + description.setBuildSystem(getBuildSystem(request)); + description.setDescription(request.getDescription()); + description.setGroupId(request.getGroupId()); + description.setLanguage( + Language.forId(request.getLanguage(), request.getJavaVersion())); + description.setName(request.getName()); + description.setPackageName(getPackageName(request, metadata)); + description.setPackaging(Packaging.forId(request.getPackaging())); + String springBootVersion = getSpringBootVersion(request, metadata); + description + .setPlatformVersion(MetadataBuildItemMapper.toVersion(springBootVersion)); + getResolvedDependencies(request, springBootVersion, metadata) + .forEach((dependency) -> description.addDependency(dependency.getId(), + MetadataBuildItemMapper.toDependency(dependency))); + return description; + } + + private void validate(ProjectRequest request, InitializrMetadata metadata) { + validateSpringBootVersion(request); + validateType(request.getType(), metadata); + validateLanguage(request.getLanguage(), metadata); + validatePackaging(request.getPackaging(), metadata); + validateDependencies(request, metadata); + } + + private void validateSpringBootVersion(ProjectRequest request) { + Version bootVersion = Version.safeParse(request.getBootVersion()); + if (bootVersion != null && bootVersion.compareTo(VERSION_1_5_0) < 0) { + throw new InvalidProjectRequestException("Invalid Spring Boot version " + + bootVersion + " must be 1.5.0 or higher"); + } + } + + private void validateType(String type, InitializrMetadata metadata) { + if (type != null) { + Type typeFromMetadata = metadata.getTypes().get(type); + if (typeFromMetadata == null) { + throw new InvalidProjectRequestException( + "Unknown type '" + type + "' check project metadata"); + } + } + } + + private void validateLanguage(String language, InitializrMetadata metadata) { + if (language != null) { + DefaultMetadataElement languageFromMetadata = metadata.getLanguages() + .get(language); + if (languageFromMetadata == null) { + throw new InvalidProjectRequestException( + "Unknown language '" + language + "' check project metadata"); + } + } + } + + private void validatePackaging(String packaging, InitializrMetadata metadata) { + if (packaging != null) { + DefaultMetadataElement packagingFromMetadata = metadata.getPackagings() + .get(packaging); + if (packagingFromMetadata == null) { + throw new InvalidProjectRequestException( + "Unknown packaging '" + packaging + "' check project metadata"); + } + } + } + + private void validateDependencies(ProjectRequest request, + InitializrMetadata metadata) { + List dependencies = (!request.getStyle().isEmpty() ? request.getStyle() + : request.getDependencies()); + dependencies.forEach((dep) -> { + Dependency dependency = metadata.getDependencies().get(dep); + if (dependency == null) { + throw new InvalidProjectRequestException( + "Unknown dependency '" + dep + "' check project metadata"); + } + }); + } + + private BuildSystem getBuildSystem(ProjectRequest request) { + return (request.getType().startsWith("gradle")) ? new GradleBuildSystem() + : new MavenBuildSystem(); + } + + private String getPackageName(ProjectRequest request, InitializrMetadata metadata) { + return metadata.getConfiguration().cleanPackageName(request.getPackageName(), + metadata.getPackageName().getContent()); + } + + private String getApplicationName(ProjectRequest request, + InitializrMetadata metadata) { + if (!StringUtils.hasText(request.getApplicationName())) { + return metadata.getConfiguration().generateApplicationName(request.getName()); + } + return request.getApplicationName(); + } + + private String getSpringBootVersion(ProjectRequest request, + InitializrMetadata metadata) { + return (request.getBootVersion() != null) ? request.getBootVersion() + : metadata.getBootVersions().getDefault().getId(); + } + + private List getResolvedDependencies(ProjectRequest request, + String springBootVersion, InitializrMetadata metadata) { + List depIds = (!request.getStyle().isEmpty() ? request.getStyle() + : request.getDependencies()); + Version requestedVersion = Version.parse(springBootVersion); + return depIds.stream().map((it) -> { + Dependency dependency = metadata.getDependencies().get(it); + return dependency.resolve(requestedVersion); + }).collect(Collectors.toList()); + } + +} diff --git a/initializr-web/src/main/java/io/spring/initializr/web/project/WebProjectRequest.java b/initializr-web/src/main/java/io/spring/initializr/web/project/WebProjectRequest.java new file mode 100644 index 00000000..11fa6ff1 --- /dev/null +++ b/initializr-web/src/main/java/io/spring/initializr/web/project/WebProjectRequest.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.initializr.web.project; + +import java.util.LinkedHashMap; +import java.util.Map; + +import io.spring.initializr.metadata.InitializrMetadata; + +import org.springframework.beans.BeanWrapperImpl; + +/** + * A {@link ProjectRequest} with some additional information to identify the request. + * + * @author Madhura Bhave + */ +public class WebProjectRequest extends ProjectRequest { + + private final Map parameters = new LinkedHashMap<>(); + + /** + * Return the additional parameters that can be used to further identify the request. + * @return the parameters + */ + public Map getParameters() { + return this.parameters; + } + + /** + * Initialize the state of this request with defaults defined in the + * {@link InitializrMetadata metadata}. + * @param metadata the metadata to use + */ + public void initialize(InitializrMetadata metadata) { + BeanWrapperImpl bean = new BeanWrapperImpl(this); + metadata.defaults().forEach((key, value) -> { + if (bean.isWritableProperty(key)) { + // We want to be able to infer a package name if none has been + // explicitly set + if (!key.equals("packageName")) { + bean.setPropertyValue(key, value); + } + } + }); + } + +} diff --git a/initializr-web/src/test/java/io/spring/initializr/web/AbstractInitializrIntegrationTests.java b/initializr-web/src/test/java/io/spring/initializr/web/AbstractInitializrIntegrationTests.java index b04f7d7e..9a7e9357 100755 --- a/initializr-web/src/test/java/io/spring/initializr/web/AbstractInitializrIntegrationTests.java +++ b/initializr-web/src/test/java/io/spring/initializr/web/AbstractInitializrIntegrationTests.java @@ -28,11 +28,11 @@ import java.util.List; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import io.spring.initializr.generator.spring.test.ProjectAssert; import io.spring.initializr.metadata.InitializrMetadata; import io.spring.initializr.metadata.InitializrMetadataBuilder; import io.spring.initializr.metadata.InitializrMetadataProvider; import io.spring.initializr.metadata.InitializrProperties; -import io.spring.initializr.test.generator.ProjectAssert; import io.spring.initializr.web.AbstractInitializrIntegrationTests.Config; import io.spring.initializr.web.mapper.InitializrMetadataVersion; import io.spring.initializr.web.support.DefaultInitializrMetadataProvider; diff --git a/initializr-web/src/test/java/io/spring/initializr/web/autoconfigure/InitializrAutoConfigurationTests.java b/initializr-web/src/test/java/io/spring/initializr/web/autoconfigure/InitializrAutoConfigurationTests.java index 6ed78475..b76df446 100755 --- a/initializr-web/src/test/java/io/spring/initializr/web/autoconfigure/InitializrAutoConfigurationTests.java +++ b/initializr-web/src/test/java/io/spring/initializr/web/autoconfigure/InitializrAutoConfigurationTests.java @@ -16,13 +16,13 @@ package io.spring.initializr.web.autoconfigure; -import io.spring.initializr.generator.ProjectGenerator; -import io.spring.initializr.generator.ProjectRequestResolver; -import io.spring.initializr.generator.ProjectResourceLocator; import io.spring.initializr.metadata.DependencyMetadataProvider; import io.spring.initializr.metadata.InitializrMetadataProvider; import io.spring.initializr.util.TemplateRenderer; +import io.spring.initializr.web.ProjectResourceLocator; import io.spring.initializr.web.project.MainController; +import io.spring.initializr.web.project.ProjectGenerationInvoker; +import io.spring.initializr.web.project.ProjectRequestToDescriptionConverter; import io.spring.initializr.web.ui.UiController; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -58,22 +58,6 @@ class InitializrAutoConfigurationTests { .withConfiguration(AutoConfigurations.of(RestTemplateAutoConfiguration.class, JacksonAutoConfiguration.class, InitializrAutoConfiguration.class)); - @Test - void autoConfigRegistersProjectGenerator() { - this.contextRunner.run( - (context) -> assertThat(context).hasSingleBean(ProjectGenerator.class)); - } - - @Test - void autoConfigWhenProjectGeneratorBeanPresentDoesNotRegisterProjectGenerator() { - this.contextRunner - .withUserConfiguration(CustomProjectGeneratorConfiguration.class) - .run((context) -> { - assertThat(context).hasSingleBean(ProjectGenerator.class); - assertThat(context).hasBean("testProjectGenerator"); - }); - } - @Test void autoConfigRegistersTemplateRenderer() { this.contextRunner.run( @@ -90,22 +74,6 @@ class InitializrAutoConfigurationTests { }); } - @Test - void autoConfigRegistersProjectRequestResolver() { - this.contextRunner.run((context) -> assertThat(context) - .hasSingleBean(ProjectRequestResolver.class)); - } - - @Test - void autoConfigWhenProjectRequestResolverBeanPresentDoesNotRegisterProjectRequestResolver() { - this.contextRunner - .withUserConfiguration(CustomProjectRequestResolverConfiguration.class) - .run((context) -> { - assertThat(context).hasSingleBean(ProjectRequestResolver.class); - assertThat(context).hasBean("testProjectRequestResolver"); - }); - } - @Test void autoConfigRegistersProjectResourceLocator() { this.contextRunner.run((context) -> assertThat(context) @@ -180,6 +148,8 @@ class InitializrAutoConfigurationTests { InitializrAutoConfiguration.class)); webContextRunner.run((context) -> { assertThat(context).hasSingleBean(InitializrWebConfig.class); + assertThat(context).hasSingleBean(ProjectGenerationInvoker.class); + assertThat(context).hasSingleBean(ProjectRequestToDescriptionConverter.class); assertThat(context).hasSingleBean(MainController.class); assertThat(context).hasSingleBean(UiController.class); }); @@ -221,16 +191,6 @@ class InitializrAutoConfigurationTests { } - @Configuration - static class CustomProjectGeneratorConfiguration { - - @Bean - public ProjectGenerator testProjectGenerator() { - return Mockito.mock(ProjectGenerator.class); - } - - } - @Configuration static class CustomTemplateRendererConfiguration { @@ -241,16 +201,6 @@ class InitializrAutoConfigurationTests { } - @Configuration - static class CustomProjectRequestResolverConfiguration { - - @Bean - public ProjectRequestResolver testProjectRequestResolver() { - return Mockito.mock(ProjectRequestResolver.class); - } - - } - @Configuration static class CustomProjectResourceLocatorConfiguration { diff --git a/initializr-web/src/test/java/io/spring/initializr/web/project/CommandLineExampleIntegrationTests.java b/initializr-web/src/test/java/io/spring/initializr/web/project/CommandLineExampleIntegrationTests.java index 96d05094..81d56660 100755 --- a/initializr-web/src/test/java/io/spring/initializr/web/project/CommandLineExampleIntegrationTests.java +++ b/initializr-web/src/test/java/io/spring/initializr/web/project/CommandLineExampleIntegrationTests.java @@ -16,7 +16,7 @@ package io.spring.initializr.web.project; -import io.spring.initializr.test.generator.PomAssert; +import io.spring.initializr.generator.spring.test.build.PomAssert; import io.spring.initializr.web.AbstractInitializrControllerIntegrationTests; import org.junit.jupiter.api.Test; diff --git a/initializr-web/src/test/java/io/spring/initializr/web/project/MainControllerDefaultsIntegrationTests.java b/initializr-web/src/test/java/io/spring/initializr/web/project/MainControllerDefaultsIntegrationTests.java index 3f2f42e6..aa8a231f 100755 --- a/initializr-web/src/test/java/io/spring/initializr/web/project/MainControllerDefaultsIntegrationTests.java +++ b/initializr-web/src/test/java/io/spring/initializr/web/project/MainControllerDefaultsIntegrationTests.java @@ -16,7 +16,7 @@ package io.spring.initializr.web.project; -import io.spring.initializr.test.generator.PomAssert; +import io.spring.initializr.generator.spring.test.build.PomAssert; import io.spring.initializr.web.AbstractInitializrControllerIntegrationTests; import org.junit.jupiter.api.Test; @@ -39,8 +39,8 @@ class MainControllerDefaultsIntegrationTests String.class); PomAssert pomAssert = new PomAssert(content); pomAssert.hasGroupId("org.foo").hasArtifactId("foo-bar") - .hasVersion("1.2.4-SNAPSHOT").hasPackaging("jar").hasName("FooBar") - .hasDescription("FooBar Project"); + .hasVersion("1.2.4-SNAPSHOT").doesNotHaveNode("/project/packaging") + .hasName("FooBar").hasDescription("FooBar Project"); } @Test diff --git a/initializr-web/src/test/java/io/spring/initializr/web/project/MainControllerEnvIntegrationTests.java b/initializr-web/src/test/java/io/spring/initializr/web/project/MainControllerEnvIntegrationTests.java index 53efa23f..76d97a74 100755 --- a/initializr-web/src/test/java/io/spring/initializr/web/project/MainControllerEnvIntegrationTests.java +++ b/initializr-web/src/test/java/io/spring/initializr/web/project/MainControllerEnvIntegrationTests.java @@ -18,7 +18,7 @@ package io.spring.initializr.web.project; import java.net.URI; -import io.spring.initializr.test.generator.ProjectAssert; +import io.spring.initializr.generator.spring.test.ProjectAssert; import io.spring.initializr.web.AbstractInitializrControllerIntegrationTests; import org.junit.jupiter.api.Test; diff --git a/initializr-web/src/test/java/io/spring/initializr/web/project/MainControllerIntegrationTests.java b/initializr-web/src/test/java/io/spring/initializr/web/project/MainControllerIntegrationTests.java index 9a9212f9..1f2fcfde 100755 --- a/initializr-web/src/test/java/io/spring/initializr/web/project/MainControllerIntegrationTests.java +++ b/initializr-web/src/test/java/io/spring/initializr/web/project/MainControllerIntegrationTests.java @@ -69,7 +69,7 @@ class MainControllerIntegrationTests Dependency biz = Dependency.create("org.acme", "biz", "1.3.5", "runtime"); downloadTgz("/starter.tgz?style=org.acme:biz&bootVersion=2.2.1.RELEASE") .isJavaProject().isMavenProject().hasStaticAndTemplatesResources(false) - .pomAssert().hasDependenciesCount(2).hasDependency(biz); + .pomAssert().hasDependenciesCount(3).hasDependency(biz); } @Test diff --git a/initializr-web/src/test/java/io/spring/initializr/web/project/ProjectGenerationPostProcessorTests.java b/initializr-web/src/test/java/io/spring/initializr/web/project/ProjectGenerationDescriptionCustomizerTests.java similarity index 52% rename from initializr-web/src/test/java/io/spring/initializr/web/project/ProjectGenerationPostProcessorTests.java rename to initializr-web/src/test/java/io/spring/initializr/web/project/ProjectGenerationDescriptionCustomizerTests.java index c0fdfe25..1bbdb6af 100755 --- a/initializr-web/src/test/java/io/spring/initializr/web/project/ProjectGenerationPostProcessorTests.java +++ b/initializr-web/src/test/java/io/spring/initializr/web/project/ProjectGenerationDescriptionCustomizerTests.java @@ -16,55 +16,61 @@ package io.spring.initializr.web.project; -import io.spring.initializr.generator.ProjectRequest; -import io.spring.initializr.generator.ProjectRequestPostProcessor; -import io.spring.initializr.metadata.InitializrMetadata; +import io.spring.initializr.generator.language.java.JavaLanguage; +import io.spring.initializr.generator.project.ProjectDescription; +import io.spring.initializr.generator.project.ProjectDescriptionCustomizer; +import io.spring.initializr.generator.version.Version; import io.spring.initializr.web.AbstractInitializrControllerIntegrationTests; -import io.spring.initializr.web.project.ProjectGenerationPostProcessorTests.ProjectRequestPostProcessorConfiguration; +import io.spring.initializr.web.project.ProjectGenerationDescriptionCustomizerTests.ProjectDescriptionCustomizerConfiguration; import org.junit.jupiter.api.Test; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.core.annotation.Order; import org.springframework.test.context.ActiveProfiles; @ActiveProfiles("test-default") -@Import(ProjectRequestPostProcessorConfiguration.class) -class ProjectGenerationPostProcessorTests +@Import(ProjectDescriptionCustomizerConfiguration.class) +class ProjectGenerationDescriptionCustomizerTests extends AbstractInitializrControllerIntegrationTests { @Test - void postProcessorsInvoked() { + void projectDescriptionCustomizersAreInvoked() { downloadZip("/starter.zip?bootVersion=2.0.4.RELEASE&javaVersion=1.8") .isJavaProject().isMavenProject().pomAssert() .hasSpringBootParent("2.2.3.RELEASE").hasProperty("java.version", "1.7"); } @Configuration - static class ProjectRequestPostProcessorConfiguration { + static class ProjectDescriptionCustomizerConfiguration { @Bean - @Order(2) - ProjectRequestPostProcessor secondPostProcessor() { - return new ProjectRequestPostProcessor() { + public ProjectDescriptionCustomizer secondPostProcessor() { + return new ProjectDescriptionCustomizer() { @Override - public void postProcessBeforeResolution(ProjectRequest request, - InitializrMetadata metadata) { - request.setJavaVersion("1.7"); + public void customize(ProjectDescription description) { + description.setLanguage(new JavaLanguage("1.7")); + } + + @Override + public int getOrder() { + return 2; } }; } @Bean - @Order(1) - ProjectRequestPostProcessor firstPostProcessor() { - return new ProjectRequestPostProcessor() { + public ProjectDescriptionCustomizer firstPostProcessor() { + return new ProjectDescriptionCustomizer() { @Override - public void postProcessBeforeResolution(ProjectRequest request, - InitializrMetadata metadata) { - request.setJavaVersion("1.2"); - request.setBootVersion("2.2.3.RELEASE"); + public void customize(ProjectDescription description) { + description.setLanguage(new JavaLanguage("1.2")); + description.setPlatformVersion(Version.parse("2.2.3.RELEASE")); + } + + @Override + public int getOrder() { + return 1; } }; } diff --git a/initializr-web/src/test/java/io/spring/initializr/web/project/ProjectGenerationInvokerTests.java b/initializr-web/src/test/java/io/spring/initializr/web/project/ProjectGenerationInvokerTests.java new file mode 100644 index 00000000..499c5ea2 --- /dev/null +++ b/initializr-web/src/test/java/io/spring/initializr/web/project/ProjectGenerationInvokerTests.java @@ -0,0 +1,253 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.initializr.web.project; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.Map; + +import io.spring.initializr.generator.io.IndentingWriterFactory; +import io.spring.initializr.generator.io.SimpleIndentStrategy; +import io.spring.initializr.generator.project.ProjectDirectoryFactory; +import io.spring.initializr.generator.spring.test.ProjectAssert; +import io.spring.initializr.generator.spring.test.build.GradleBuildAssert; +import io.spring.initializr.generator.spring.test.build.PomAssert; +import io.spring.initializr.metadata.InitializrMetadata; +import io.spring.initializr.metadata.InitializrMetadataProvider; +import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.ArgumentMatcher; + +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.util.ReflectionTestUtils; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +/** + * Tests for {@link ProjectGenerationInvoker}. + * + * @author Madhura Bhave + */ +public class ProjectGenerationInvokerTests { + + private static final InitializrMetadata metadata = InitializrMetadataTestBuilder + .withDefaults().build(); + + private ProjectGenerationInvoker invoker; + + private AnnotationConfigApplicationContext context; + + private final ApplicationEventPublisher eventPublisher = mock( + ApplicationEventPublisher.class); + + @BeforeEach + void setup() { + setupContext(); + ProjectRequestToDescriptionConverter converter = new ProjectRequestToDescriptionConverter(); + this.invoker = new ProjectGenerationInvoker(this.context, this.eventPublisher, + converter); + } + + @AfterEach + void cleanup() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + @SuppressWarnings("unchecked") + void invokeProjectStructureGeneration() { + WebProjectRequest request = new WebProjectRequest(); + request.setType("maven-project"); + request.initialize(metadata); + File file = this.invoker.invokeProjectStructureGeneration(request); + new ProjectAssert(file).isJavaProject(); + Map> tempFiles = (Map>) ReflectionTestUtils + .getField(this.invoker, "temporaryFiles"); + assertThat(tempFiles.get(file.getName())).contains(file); + verifyProjectSuccessfulEventFor(request); + } + + @Test + void invokeProjectStructureGenerationFailureShouldPublishFailureEvent() { + WebProjectRequest request = new WebProjectRequest(); + request.initialize(metadata); + request.setType("foo-bar"); + try { + this.invoker.invokeProjectStructureGeneration(request); + } + catch (Exception ex) { + verifyProjectFailedEventFor(request, ex); + } + } + + @Test + void invokeBuildGenerationForMavenBuild() { + WebProjectRequest request = new WebProjectRequest(); + request.setType("maven-project"); + request.initialize(metadata); + byte[] bytes = this.invoker.invokeBuildGeneration(request); + String content = new String(bytes); + new PomAssert(content).hasGroupId(request.getGroupId()) + .hasArtifactId(request.getArtifactId()).hasVersion(request.getVersion()) + .doesNotHaveNode("/project/packaging").hasName(request.getName()) + .hasDescription(request.getDescription()) + .hasJavaVersion(request.getJavaVersion()) + .hasSpringBootParent(request.getBootVersion()); + verifyProjectSuccessfulEventFor(request); + } + + @Test + void invokeBuildGenerationForGradleBuild() { + WebProjectRequest request = new WebProjectRequest(); + request.initialize(metadata); + request.setType("gradle-project"); + byte[] bytes = this.invoker.invokeBuildGeneration(request); + String content = new String(bytes); + new GradleBuildAssert(content).hasVersion(request.getVersion()) + .hasSpringBootPlugin(request.getBootVersion()) + .hasJavaVersion(request.getJavaVersion()); + verifyProjectSuccessfulEventFor(request); + } + + @Test + void invokeBuildGenerationFailureShouldPublishFailureEvent() { + WebProjectRequest request = new WebProjectRequest(); + request.initialize(metadata); + request.setType("foo-bar"); + try { + this.invoker.invokeBuildGeneration(request); + } + catch (Exception ex) { + verifyProjectFailedEventFor(request, ex); + } + } + + @Test + @SuppressWarnings("unchecked") + void createDistributionDirectory(@TempDir Path tempDir) { + ProjectRequest request = new ProjectRequest(); + request.setType("gradle-project"); + File dir = tempDir.toFile(); + File distributionFile = this.invoker.createDistributionFile(dir, ".zip"); + assertThat(distributionFile.toString()).isEqualTo(dir.toString() + ".zip"); + Map> tempFiles = (Map>) ReflectionTestUtils + .getField(this.invoker, "temporaryFiles"); + assertThat(tempFiles.get(dir.getName())).contains(distributionFile); + } + + @Test + void cleanupTempFilesShouldOnlyCleanupSpecifiedDir() { + WebProjectRequest request = new WebProjectRequest(); + request.initialize(metadata); + request.setType("gradle-project"); + File file = this.invoker.invokeProjectStructureGeneration(request); + this.invoker.cleanTempFiles(file); + assertThat(file.listFiles()).isNull(); + } + + private void setupContext() { + InitializrMetadataProvider metadataProvider = mock( + InitializrMetadataProvider.class); + given(metadataProvider.get()) + .willReturn(InitializrMetadataTestBuilder.withDefaults().build()); + this.context = new AnnotationConfigApplicationContext(); + this.context.register(TestConfiguration.class); + this.context.refresh(); + } + + protected void verifyProjectSuccessfulEventFor(ProjectRequest request) { + verify(this.eventPublisher, times(1)) + .publishEvent(argThat(new ProjectGeneratedEventMatcher(request))); + } + + protected void verifyProjectFailedEventFor(ProjectRequest request, Exception ex) { + verify(this.eventPublisher, times(1)) + .publishEvent(argThat(new ProjectFailedEventMatcher(request, ex))); + } + + @Configuration + static class TestConfiguration { + + @Bean + public IndentingWriterFactory factory() { + return IndentingWriterFactory.create(new SimpleIndentStrategy("\t")); + } + + @Bean + public ProjectDirectoryFactory projectDirectoryFactory() { + return (description) -> Files.createTempDirectory("project-"); + } + + @Bean + public InitializrMetadataProvider initializrMetadataProvider() { + return () -> metadata; + } + + } + + private static class ProjectFailedEventMatcher + implements ArgumentMatcher { + + private final ProjectRequest request; + + private final Exception cause; + + ProjectFailedEventMatcher(ProjectRequest request, Exception cause) { + this.request = request; + this.cause = cause; + } + + @Override + public boolean matches(ProjectFailedEvent event) { + return this.request.equals(event.getProjectRequest()) + && this.cause.equals(event.getCause()); + } + + } + + private static class ProjectGeneratedEventMatcher + implements ArgumentMatcher { + + private final ProjectRequest request; + + ProjectGeneratedEventMatcher(ProjectRequest request) { + this.request = request; + } + + @Override + public boolean matches(ProjectGeneratedEvent event) { + return this.request.equals(event.getProjectRequest()); + } + + } + +} diff --git a/initializr-web/src/test/java/io/spring/initializr/web/project/ProjectGenerationSmokeTests.java b/initializr-web/src/test/java/io/spring/initializr/web/project/ProjectGenerationSmokeTests.java index eb16e1aa..cdff969d 100755 --- a/initializr-web/src/test/java/io/spring/initializr/web/project/ProjectGenerationSmokeTests.java +++ b/initializr-web/src/test/java/io/spring/initializr/web/project/ProjectGenerationSmokeTests.java @@ -21,7 +21,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.nio.file.Path; -import io.spring.initializr.test.generator.ProjectAssert; +import io.spring.initializr.generator.spring.test.ProjectAssert; import io.spring.initializr.web.AbstractFullStackInitializrIntegrationTests; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assumptions; @@ -208,7 +208,7 @@ class ProjectGenerationSmokeTests extends AbstractFullStackInitializrIntegration projectAssert.hasBaseDir("demo").isMavenProject().isJavaWarProject().pomAssert() .hasPackaging("war").hasDependenciesCount(3) .hasSpringBootStarterDependency("web") // Added with war packaging - .hasSpringBootStarterTomcat().hasSpringBootStarterTest(); + .hasSpringBootStarterDependency("tomcat").hasSpringBootStarterTest(); } @Test diff --git a/initializr-web/src/test/java/io/spring/initializr/web/project/ProjectRequestToDescriptionConverterTests.java b/initializr-web/src/test/java/io/spring/initializr/web/project/ProjectRequestToDescriptionConverterTests.java new file mode 100644 index 00000000..f5cded91 --- /dev/null +++ b/initializr-web/src/test/java/io/spring/initializr/web/project/ProjectRequestToDescriptionConverterTests.java @@ -0,0 +1,177 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.spring.initializr.web.project; + +import java.util.Collections; + +import io.spring.initializr.generator.project.ProjectDescription; +import io.spring.initializr.generator.version.Version; +import io.spring.initializr.metadata.InitializrMetadata; +import io.spring.initializr.test.metadata.InitializrMetadataTestBuilder; +import io.spring.initializr.web.InvalidProjectRequestException; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +/** + * Tests for {@link ProjectRequestToDescriptionConverter}. + * + * @author Madhura Bhave + */ +public class ProjectRequestToDescriptionConverterTests { + + private InitializrMetadata metadata = InitializrMetadataTestBuilder.withDefaults() + .build(); + + private final ProjectRequestToDescriptionConverter converter = new ProjectRequestToDescriptionConverter(); + + @Test + public void convertWhenTypeIsInvalidShouldThrowException() { + ProjectRequest request = getProjectRequest(); + request.setType("foo-build"); + assertThatExceptionOfType(InvalidProjectRequestException.class) + .isThrownBy(() -> this.converter.convert(request, this.metadata)) + .withMessage("Unknown type 'foo-build' check project metadata"); + } + + @Test + void convertWhenSpringBootVersionInvalidShouldThrowException() { + ProjectRequest request = getProjectRequest(); + request.setBootVersion("1.2.3.M4"); + assertThatExceptionOfType(InvalidProjectRequestException.class) + .isThrownBy(() -> this.converter.convert(request, this.metadata)) + .withMessage( + "Invalid Spring Boot version 1.2.3.M4 must be 1.5.0 or higher"); + } + + @Test + public void convertWhenPackagingIsInvalidShouldThrowException() { + ProjectRequest request = getProjectRequest(); + request.setPackaging("star"); + assertThatExceptionOfType(InvalidProjectRequestException.class) + .isThrownBy(() -> this.converter.convert(request, this.metadata)) + .withMessage("Unknown packaging 'star' check project metadata"); + } + + @Test + public void convertWhenLanguageIsInvalidShouldThrowException() { + ProjectRequest request = getProjectRequest(); + request.setLanguage("english"); + assertThatExceptionOfType(InvalidProjectRequestException.class) + .isThrownBy(() -> this.converter.convert(request, this.metadata)) + .withMessage("Unknown language 'english' check project metadata"); + } + + @Test + void convertWhenDependencyNotPresentShouldThrowException() { + ProjectRequest request = getProjectRequest(); + request.setDependencies(Collections.singletonList("invalid")); + assertThatExceptionOfType(InvalidProjectRequestException.class) + .isThrownBy(() -> this.converter.convert(request, this.metadata)) + .withMessage("Unknown dependency 'invalid' check project metadata"); + } + + @Test + void convertShouldSetApplicationNameForProjectDescriptionFromRequestWhenPresent() { + ProjectRequest request = getProjectRequest(); + request.setApplicationName("MyApplication"); + ProjectDescription description = this.converter.convert(request, this.metadata); + assertThat(description.getApplicationName()).isEqualTo("MyApplication"); + } + + @Test + void convertShouldSetApplicationNameForProjectDescriptionUsingNameWhenAbsentFromRequest() { + ProjectRequest request = getProjectRequest(); + ProjectDescription description = this.converter.convert(request, this.metadata); + assertThat(description.getApplicationName()).isEqualTo("DemoApplication"); + } + + @Test + void convertShouldSetGroupIdAndArtifactIdFromRequest() { + ProjectRequest request = getProjectRequest(); + request.setArtifactId("foo"); + request.setGroupId("com.example"); + ProjectDescription description = this.converter.convert(request, this.metadata); + assertThat(description.getGroupId()).isEqualTo("com.example"); + assertThat(description.getArtifactId()).isEqualTo("foo"); + } + + @Test + void convertShouldSetBaseDirectoryFromRequest() { + ProjectRequest request = getProjectRequest(); + request.setBaseDir("my-path"); + ProjectDescription description = this.converter.convert(request, this.metadata); + assertThat(description.getBaseDirectory()).isEqualTo("my-path"); + } + + @Test + void convertShouldSetBuildSystemFromRequestType() { + ProjectRequest request = getProjectRequest(); + request.setType("gradle-build"); + ProjectDescription description = this.converter.convert(request, this.metadata); + assertThat(description.getBuildSystem().id()).isEqualTo("gradle"); + } + + @Test + void convertShouldSetDescriptionFromRequest() { + ProjectRequest request = getProjectRequest(); + request.setDescription("This is my demo project"); + ProjectDescription description = this.converter.convert(request, this.metadata); + assertThat(description.getDescription()).isEqualTo("This is my demo project"); + } + + @Test + void convertShouldSetPackagingFromRequest() { + ProjectRequest request = getProjectRequest(); + request.setPackaging("war"); + ProjectDescription description = this.converter.convert(request, this.metadata); + assertThat(description.getPackaging().id()).isEqualTo("war"); + } + + @Test + void convertShouldSetPlatformVersionFromRequest() { + ProjectRequest request = getProjectRequest(); + request.setBootVersion("2.0.3"); + ProjectDescription description = this.converter.convert(request, this.metadata); + assertThat(description.getPlatformVersion()).isEqualTo(Version.parse("2.0.3")); + } + + @Test + void convertShouldUseDefaultPlatformVersionFromMetadata() { + ProjectRequest request = getProjectRequest(); + ProjectDescription description = this.converter.convert(request, this.metadata); + assertThat(description.getPlatformVersion()) + .isEqualTo(Version.parse("2.1.1.RELEASE")); + } + + @Test + void convertShouldSetLanguageForProjectDescriptionFromRequest() { + ProjectRequest request = getProjectRequest(); + request.setJavaVersion("1.8"); + ProjectDescription description = this.converter.convert(request, this.metadata); + assertThat(description.getLanguage().id()).isEqualTo("java"); + assertThat(description.getLanguage().jvmVersion()).isEqualTo("1.8"); + } + + private ProjectRequest getProjectRequest() { + WebProjectRequest request = new WebProjectRequest(); + request.initialize(this.metadata); + return request; + } + +} diff --git a/pom.xml b/pom.xml index 5c0b7854..0e81e7e2 100644 --- a/pom.xml +++ b/pom.xml @@ -83,6 +83,52 @@ ${revision} test-jar + + io.spring.initializr.experimental + initializr-generator + 0.1.0.BUILD-SNAPSHOT + + + io.spring.initializr + initializr-generator + + + + + io.spring.initializr.experimental + initializr-generator + 0.1.0.BUILD-SNAPSHOT + test-jar + + + io.spring.initializr + initializr-generator + + + + + io.spring.initializr.experimental + initializr-generator-spring + 0.1.0.BUILD-SNAPSHOT + + + io.spring.initializr + initializr-generator + + + + + io.spring.initializr.experimental + initializr-generator-spring + 0.1.0.BUILD-SNAPSHOT + test-jar + + + io.spring.initializr + initializr-generator + + + org.junit junit-bom