diff --git a/initializr-generator-spring/pom.xml b/initializr-generator-spring/pom.xml index d129f251..fc7d0807 100644 --- a/initializr-generator-spring/pom.xml +++ b/initializr-generator-spring/pom.xml @@ -19,6 +19,11 @@ initializr-metadata + + com.samskivert + jmustache + + io.spring.initializr initializr-generator diff --git a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/GettingStartedSection.java b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/GettingStartedSection.java new file mode 100644 index 00000000..e5ed5e53 --- /dev/null +++ b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/GettingStartedSection.java @@ -0,0 +1,116 @@ +/* + * 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.spring.documentation; + +import java.util.ArrayList; +import java.util.List; + +import io.spring.initializr.generator.io.template.MustacheTemplateRenderer; +import io.spring.initializr.generator.io.text.BulletedSection; +import io.spring.initializr.generator.io.text.Section; + +/** + * Section that provides links and other important references to get started. + * + * @author Madhura Bhave + * @author Stephane Nicoll + */ +public final class GettingStartedSection extends PreDefinedSection { + + private final BulletedSection referenceDocs; + + private final BulletedSection guides; + + private final BulletedSection additionalLinks; + + GettingStartedSection(MustacheTemplateRenderer templateRenderer) { + super("Getting Started"); + this.referenceDocs = new BulletedSection<>(templateRenderer, + "documentation/reference-documentation"); + this.guides = new BulletedSection<>(templateRenderer, "documentation/guides"); + this.additionalLinks = new BulletedSection<>(templateRenderer, + "documentation/additional-links"); + } + + @Override + public boolean isEmpty() { + return referenceDocs().isEmpty() && guides().isEmpty() + && additionalLinks().isEmpty() && super.isEmpty(); + } + + @Override + protected List
resolveSubSections(List
sections) { + List
allSections = new ArrayList<>(); + allSections.add(this.referenceDocs); + allSections.add(this.guides); + allSections.add(this.additionalLinks); + allSections.addAll(sections); + return allSections; + } + + public GettingStartedSection addReferenceDocLink(String href, String description) { + this.referenceDocs.addItem(new Link(href, description)); + return this; + } + + public BulletedSection referenceDocs() { + return this.referenceDocs; + } + + public GettingStartedSection addGuideLink(String href, String description) { + this.guides.addItem(new Link(href, description)); + return this; + } + + public BulletedSection guides() { + return this.guides; + } + + public GettingStartedSection addAdditionalLink(String href, String description) { + this.additionalLinks.addItem(new Link(href, description)); + return this; + } + + public BulletedSection additionalLinks() { + return this.additionalLinks; + } + + /** + * Internal representation of a link. + */ + public static class Link { + + private final String href; + + private final String description; + + Link(String href, String description) { + this.href = href; + this.description = description; + } + + public String getHref() { + return this.href; + } + + public String getDescription() { + return this.description; + } + + } + +} diff --git a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/HelpDocument.java b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/HelpDocument.java new file mode 100644 index 00000000..29adb276 --- /dev/null +++ b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/HelpDocument.java @@ -0,0 +1,95 @@ +/* + * 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.spring.documentation; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import io.spring.initializr.generator.io.template.MustacheTemplateRenderer; +import io.spring.initializr.generator.io.text.MustacheSection; +import io.spring.initializr.generator.io.text.Section; + +/** + * Project's help document intended to give additional references to the users. Contains a + * getting started section, additional sections and a next steps section. + * + * @author Stephane Nicoll + * @author Madhura Bhave + */ +public class HelpDocument { + + private final MustacheTemplateRenderer templateRenderer; + + private final GettingStartedSection gettingStarted; + + private final PreDefinedSection nextSteps; + + private final LinkedList
sections = new LinkedList<>(); + + public HelpDocument(MustacheTemplateRenderer templateRenderer) { + this.templateRenderer = templateRenderer; + this.gettingStarted = new GettingStartedSection(templateRenderer); + this.nextSteps = new PreDefinedSection("Next Steps"); + } + + public GettingStartedSection gettingStarted() { + return this.gettingStarted; + } + + public PreDefinedSection nextSteps() { + return this.nextSteps; + } + + public HelpDocument addSection(Section section) { + this.sections.add(section); + return this; + } + + /** + * Add a section rendered by the specified mustache template and model. + * @param templateName the name of the mustache template to render + * @param model the model that should be used for the rendering + * @return this document + */ + public HelpDocument addSection(String templateName, Map model) { + return addSection( + new MustacheSection(this.templateRenderer, templateName, model)); + } + + public List
getSections() { + return Collections.unmodifiableList(this.sections); + } + + public void write(PrintWriter writer) throws IOException { + LinkedList
allSections = new LinkedList<>(this.sections); + allSections.addFirst(this.gettingStarted); + allSections.addLast(this.nextSteps); + for (Section section : allSections) { + section.write(writer); + } + } + + public boolean isEmpty() { + return gettingStarted().isEmpty() && this.sections.isEmpty() + && nextSteps().isEmpty(); + } + +} diff --git a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/HelpDocumentCustomizer.java b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/HelpDocumentCustomizer.java new file mode 100644 index 00000000..5969e726 --- /dev/null +++ b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/HelpDocumentCustomizer.java @@ -0,0 +1,38 @@ +/* + * 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.spring.documentation; + +import org.springframework.core.Ordered; + +/** + * Callback for customizing a project's {@link HelpDocument}. Invoked with an + * {@link Ordered order} of {@code 0} by default, considering overriding + * {@link #getOrder()} to customize this behaviour. + * + * @author Stephane Nicoll + */ +@FunctionalInterface +public interface HelpDocumentCustomizer extends Ordered { + + void customize(HelpDocument document); + + @Override + default int getOrder() { + return 0; + } + +} diff --git a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/HelpDocumentProjectContributor.java b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/HelpDocumentProjectContributor.java new file mode 100644 index 00000000..57cd1de8 --- /dev/null +++ b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/HelpDocumentProjectContributor.java @@ -0,0 +1,51 @@ +/* + * 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.spring.documentation; + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; + +import io.spring.initializr.generator.project.contributor.ProjectContributor; + +/** + * {@link ProjectContributor} for the project's {@code HELP.md} file. + * + * @author Stephane Nicoll + * @author Madhura Bhave + */ +public class HelpDocumentProjectContributor implements ProjectContributor { + + private final HelpDocument helpDocument; + + public HelpDocumentProjectContributor(HelpDocument helpDocument) { + this.helpDocument = helpDocument; + } + + @Override + public void contribute(Path projectRoot) throws IOException { + if (this.helpDocument.isEmpty()) { + return; + } + Path file = Files.createFile(projectRoot.resolve("HELP.md")); + try (PrintWriter writer = new PrintWriter(Files.newBufferedWriter(file))) { + this.helpDocument.write(writer); + } + } + +} diff --git a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/HelpDocumentProjectGenerationConfiguration.java b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/HelpDocumentProjectGenerationConfiguration.java new file mode 100644 index 00000000..4d8fc1b8 --- /dev/null +++ b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/HelpDocumentProjectGenerationConfiguration.java @@ -0,0 +1,45 @@ +/* + * 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.spring.documentation; + +import io.spring.initializr.generator.io.template.MustacheTemplateRenderer; +import io.spring.initializr.generator.project.ProjectGenerationConfiguration; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; + +/** + * Configuration for contributions specific to the help documentation of a project. + * + * @author Stephane Nicoll + */ +@ProjectGenerationConfiguration +@Import(HelpDocumentProjectGenerationDefaultContributorsConfiguration.class) +public class HelpDocumentProjectGenerationConfiguration { + + @Bean + public HelpDocumentProjectContributor helpDocumentProjectContributor( + MustacheTemplateRenderer templateRenderer, + ObjectProvider helpDocumentCustomizers) { + HelpDocument helpDocument = new HelpDocument(templateRenderer); + helpDocumentCustomizers.orderedStream() + .forEach((customizer) -> customizer.customize(helpDocument)); + return new HelpDocumentProjectContributor(helpDocument); + } + +} diff --git a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/HelpDocumentProjectGenerationDefaultContributorsConfiguration.java b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/HelpDocumentProjectGenerationDefaultContributorsConfiguration.java new file mode 100644 index 00000000..d191e948 --- /dev/null +++ b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/HelpDocumentProjectGenerationDefaultContributorsConfiguration.java @@ -0,0 +1,39 @@ +/* + * 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.spring.documentation; + +import io.spring.initializr.generator.project.ResolvedProjectDescription; +import io.spring.initializr.metadata.InitializrMetadata; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Default {@link HelpDocument} contributors. + * + * @author Stephane Nicoll + */ +@Configuration +public class HelpDocumentProjectGenerationDefaultContributorsConfiguration { + + @Bean + public RequestedDependenciesHelpDocumentCustomizer dependenciesHelpDocumentCustomizer( + ResolvedProjectDescription description, InitializrMetadata metadata) { + return new RequestedDependenciesHelpDocumentCustomizer(description, metadata); + } + +} diff --git a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/PreDefinedSection.java b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/PreDefinedSection.java new file mode 100644 index 00000000..73193e33 --- /dev/null +++ b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/PreDefinedSection.java @@ -0,0 +1,71 @@ +/* + * 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.spring.documentation; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +import io.spring.initializr.generator.io.text.Section; + +/** + * Section that is pre-defined and always present in the document. You can only add + * additional sections to pre-defined sections. + * + * @author Madhura Bhave + */ +public class PreDefinedSection implements Section { + + private final String title; + + private final List
subSections = new ArrayList<>(); + + public PreDefinedSection(String title) { + this.title = title; + } + + public PreDefinedSection addSection(Section section) { + this.subSections.add(section); + return this; + } + + @Override + public void write(PrintWriter writer) throws IOException { + if (!isEmpty()) { + writer.println("# " + this.title); + writer.println(""); + for (Section section : resolveSubSections(this.subSections)) { + section.write(writer); + } + } + } + + public boolean isEmpty() { + return this.subSections.isEmpty(); + } + + /** + * Resolve the sections to render based on the current registered sections. + * @param sections the registered sections + * @return the sections to render + */ + protected List
resolveSubSections(List
sections) { + return sections; + } + +} diff --git a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/RequestedDependenciesHelpDocumentCustomizer.java b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/RequestedDependenciesHelpDocumentCustomizer.java new file mode 100644 index 00000000..fcb05553 --- /dev/null +++ b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/RequestedDependenciesHelpDocumentCustomizer.java @@ -0,0 +1,78 @@ +/* + * 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.spring.documentation; + +import io.spring.initializr.generator.project.ResolvedProjectDescription; +import io.spring.initializr.metadata.Dependency; +import io.spring.initializr.metadata.InitializrMetadata; + +import org.springframework.core.Ordered; + +/** + * A {@link HelpDocumentCustomizer} that register links for selected dependencies. + * + * @author Stephane Nicoll + */ +public class RequestedDependenciesHelpDocumentCustomizer + implements HelpDocumentCustomizer { + + private final ResolvedProjectDescription projectDescription; + + private final InitializrMetadata metadata; + + public RequestedDependenciesHelpDocumentCustomizer( + ResolvedProjectDescription projectDescription, InitializrMetadata metadata) { + this.projectDescription = projectDescription; + this.metadata = metadata; + } + + @Override + public void customize(HelpDocument document) { + this.projectDescription.getRequestedDependencies().forEach((id, dependency) -> { + Dependency dependencyMetadata = this.metadata.getDependencies().get(id); + if (dependencyMetadata != null) { + handleDependency(document, dependencyMetadata); + } + }); + } + + @Override + public int getOrder() { + return Ordered.LOWEST_PRECEDENCE; + } + + private void handleDependency(HelpDocument document, Dependency dependency) { + GettingStartedSection gettingStartedSection = document.gettingStarted(); + dependency.getLinks().forEach((link) -> { + if (link.getDescription() != null && link.getRel() != null) { + if ("reference".equals(link.getRel())) { + gettingStartedSection.addReferenceDocLink(link.getHref(), + link.getDescription()); + } + else if ("guide".equals(link.getRel())) { + gettingStartedSection.addGuideLink(link.getHref(), + link.getDescription()); + } + else { + gettingStartedSection.addAdditionalLink(link.getHref(), + link.getDescription()); + } + } + }); + } + +} diff --git a/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/package-info.java b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/package-info.java new file mode 100644 index 00000000..8df4a33c --- /dev/null +++ b/initializr-generator-spring/src/main/java/io/spring/initializr/generator/spring/documentation/package-info.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +/** + * Documentation contributors. Generate a {@code HELP.md} at the root of the project with + * additional information based on requested dependencies. + */ +package io.spring.initializr.generator.spring.documentation; diff --git a/initializr-generator-spring/src/main/resources/META-INF/spring.factories b/initializr-generator-spring/src/main/resources/META-INF/spring.factories index 9abd45d8..3408105c 100644 --- a/initializr-generator-spring/src/main/resources/META-INF/spring.factories +++ b/initializr-generator-spring/src/main/resources/META-INF/spring.factories @@ -7,4 +7,5 @@ io.spring.initializr.generator.spring.code.groovy.GroovyProjectGenerationConfigu io.spring.initializr.generator.spring.code.java.JavaProjectGenerationConfiguration,\ io.spring.initializr.generator.spring.code.kotlin.KotlinProjectGenerationConfiguration,\ io.spring.initializr.generator.spring.configuration.ApplicationConfigurationProjectGenerationConfiguration,\ +io.spring.initializr.generator.spring.documentation.HelpDocumentProjectGenerationConfiguration,\ io.spring.initializr.generator.spring.scm.git.GitProjectGenerationConfiguration \ No newline at end of file diff --git a/initializr-generator-spring/src/main/resources/templates/documentation/additional-links.mustache b/initializr-generator-spring/src/main/resources/templates/documentation/additional-links.mustache new file mode 100644 index 00000000..4ff40a6d --- /dev/null +++ b/initializr-generator-spring/src/main/resources/templates/documentation/additional-links.mustache @@ -0,0 +1,6 @@ +### Additional Links +These additional references should also help you: + +{{#items}} +* [{{description}}]({{href}}) +{{/items}} \ No newline at end of file diff --git a/initializr-generator-spring/src/main/resources/templates/documentation/guides.mustache b/initializr-generator-spring/src/main/resources/templates/documentation/guides.mustache new file mode 100644 index 00000000..c5efe86d --- /dev/null +++ b/initializr-generator-spring/src/main/resources/templates/documentation/guides.mustache @@ -0,0 +1,6 @@ +### Guides +The following guides illustrates how to use certain features concretely: + +{{#items}} +* [{{description}}]({{href}}) +{{/items}} \ No newline at end of file diff --git a/initializr-generator-spring/src/main/resources/templates/documentation/reference-documentation.mustache b/initializr-generator-spring/src/main/resources/templates/documentation/reference-documentation.mustache new file mode 100644 index 00000000..6d6c0352 --- /dev/null +++ b/initializr-generator-spring/src/main/resources/templates/documentation/reference-documentation.mustache @@ -0,0 +1,6 @@ +### Reference Documentation +For further reference, please consider the following sections: + +{{#items}} +* [{{description}}]({{href}}) +{{/items}} \ No newline at end of file diff --git a/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/documentation/GettingStartedSectionTests.java b/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/documentation/GettingStartedSectionTests.java new file mode 100644 index 00000000..3370cc85 --- /dev/null +++ b/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/documentation/GettingStartedSectionTests.java @@ -0,0 +1,71 @@ +/* + * 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.spring.documentation; + +import io.spring.initializr.generator.io.template.MustacheTemplateRenderer; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link GettingStartedSection}. + * + * @author Stephane Nicoll + */ +class GettingStartedSectionTests { + + private final MustacheTemplateRenderer renderer = new MustacheTemplateRenderer(""); + + @Test + void gettingStartedEmpty() { + GettingStartedSection gettingStarted = newGettingStartedSection(); + assertThat(gettingStarted.isEmpty()).isTrue(); + } + + @Test + void gettingStartedWithGuideLinkIsNotEmpty() { + GettingStartedSection gettingStarted = newGettingStartedSection(); + gettingStarted.addGuideLink("https://example.com", "Test"); + assertThat(gettingStarted.isEmpty()).isFalse(); + } + + @Test + void gettingStartedWithReferenceDocLinkIsNotEmpty() { + GettingStartedSection gettingStarted = newGettingStartedSection(); + gettingStarted.addReferenceDocLink("https://example.com", "Test"); + assertThat(gettingStarted.isEmpty()).isFalse(); + } + + @Test + void gettingStartedWithAdditionalLinkIsNotEmpty() { + GettingStartedSection gettingStarted = newGettingStartedSection(); + gettingStarted.addAdditionalLink("https://example.com", "Test"); + assertThat(gettingStarted.isEmpty()).isFalse(); + } + + @Test + void gettingStartedWithSubSectionIsNotEmpty() { + GettingStartedSection gettingStarted = newGettingStartedSection(); + gettingStarted.addSection((writer) -> writer.println("test")); + assertThat(gettingStarted.isEmpty()).isFalse(); + } + + private GettingStartedSection newGettingStartedSection() { + return new GettingStartedSection(this.renderer); + } + +} diff --git a/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/documentation/HelpDocumentProjectContributorTests.java b/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/documentation/HelpDocumentProjectContributorTests.java new file mode 100644 index 00000000..61577c91 --- /dev/null +++ b/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/documentation/HelpDocumentProjectContributorTests.java @@ -0,0 +1,124 @@ +/* + * 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.spring.documentation; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import io.spring.initializr.generator.io.template.MustacheTemplateRenderer; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link HelpDocumentProjectContributor}. + * + * @author Stephane Nicoll + */ +class HelpDocumentProjectContributorTests { + + private Path directory; + + private MustacheTemplateRenderer templateRenderer; + + @BeforeEach + void setup(@TempDir Path directory) { + this.directory = directory; + this.templateRenderer = new MustacheTemplateRenderer("classpath:/templates"); + } + + @Test + void helpDocumentEmptyDoesNotCreateFile() throws IOException { + HelpDocument document = new HelpDocument(this.templateRenderer); + assertThat(document.isEmpty()).isTrue(); + Path projectDir = Files.createTempDirectory(this.directory, "project-"); + new HelpDocumentProjectContributor(document).contribute(projectDir); + Path helpDocument = projectDir.resolve("HELP.md"); + assertThat(helpDocument).doesNotExist(); + } + + @Test + void helpDocumentWithLinksToGuide() throws IOException { + HelpDocument document = new HelpDocument(this.templateRenderer); + document.gettingStarted().addGuideLink("https://test.example.com", "test") + .addGuideLink("https://test2.example.com", "test2"); + List lines = generateDocument(document); + assertThat(lines).containsExactly("# Getting Started", "", "### Guides", + "The following guides illustrates how to use certain features concretely:", + "", "* [test](https://test.example.com)", + "* [test2](https://test2.example.com)", ""); + } + + @Test + void helpDocumentWithLinksToReferenceDoc() throws IOException { + HelpDocument document = new HelpDocument(this.templateRenderer); + document.gettingStarted().addReferenceDocLink("https://test.example.com", "doc") + .addReferenceDocLink("https://test2.example.com", "doc2"); + List lines = generateDocument(document); + assertThat(lines).containsExactly("# Getting Started", "", + "### Reference Documentation", + "For further reference, please consider the following sections:", "", + "* [doc](https://test.example.com)", + "* [doc2](https://test2.example.com)", ""); + } + + @Test + void helpDocumentWithLinksToOtherLinks() throws IOException { + HelpDocument document = new HelpDocument(this.templateRenderer); + document.gettingStarted().addAdditionalLink("https://test.example.com", + "Something"); + List lines = generateDocument(document); + assertThat(lines).containsExactly("# Getting Started", "", "### Additional Links", + "These additional references should also help you:", "", + "* [Something](https://test.example.com)", ""); + } + + @Test + void helpDocumentWithSimpleSection() throws IOException { + HelpDocument document = new HelpDocument(this.templateRenderer); + document.addSection((writer) -> writer + .println(String.format("# My test section%n%n * Test"))); + List lines = generateDocument(document); + assertThat(lines).containsExactly("# My test section", "", " * Test"); + } + + @Test + void helpDocumentWithLinksAndSimpleSection() throws IOException { + HelpDocument document = new HelpDocument(this.templateRenderer); + document.gettingStarted().addGuideLink("https://test.example.com", "test") + .addSection((writer) -> writer + .println(String.format("# My test section%n%n * Test"))); + List lines = generateDocument(document); + assertThat(lines).containsExactly("# Getting Started", "", "### Guides", + "The following guides illustrates how to use certain features concretely:", + "", "* [test](https://test.example.com)", "", "# My test section", "", + " * Test"); + } + + private List generateDocument(HelpDocument document) throws IOException { + Path projectDir = Files.createTempDirectory(this.directory, "project-"); + new HelpDocumentProjectContributor(document).contribute(projectDir); + Path helpDocument = projectDir.resolve("HELP.md"); + assertThat(helpDocument).isRegularFile(); + return Files.readAllLines(helpDocument); + } + +} diff --git a/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/documentation/HelpDocumentProjectGenerationConfigurationTests.java b/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/documentation/HelpDocumentProjectGenerationConfigurationTests.java new file mode 100644 index 00000000..72fb929f --- /dev/null +++ b/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/documentation/HelpDocumentProjectGenerationConfigurationTests.java @@ -0,0 +1,77 @@ +/* + * 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.spring.documentation; + +import java.nio.file.Path; + +import io.spring.initializr.generator.io.template.MustacheTemplateRenderer; +import io.spring.initializr.generator.project.ProjectDescription; +import io.spring.initializr.generator.spring.test.InitializrMetadataTestBuilder; +import io.spring.initializr.generator.test.project.ProjectAssetTester; +import io.spring.initializr.metadata.Dependency; +import io.spring.initializr.metadata.InitializrMetadata; +import io.spring.initializr.metadata.Link; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link HelpDocumentProjectGenerationConfiguration}. + * + * @author Stephane Nicoll + */ +class HelpDocumentProjectGenerationConfigurationTests { + + private ProjectAssetTester projectTester; + + private InitializrMetadataTestBuilder metadataBuilder = InitializrMetadataTestBuilder + .withDefaults(); + + @BeforeEach + void setup(@TempDir Path directory) { + this.projectTester = new ProjectAssetTester() + .withConfiguration(HelpDocumentProjectGenerationConfiguration.class) + .withBean(MustacheTemplateRenderer.class, + () -> new MustacheTemplateRenderer("classpath:/templates")) + .withBean(InitializrMetadata.class, () -> this.metadataBuilder.build()) + .withDirectory(directory); + } + + @Test + void helpDocumentIsNotContributedWithoutLinks() { + assertThat(this.projectTester.generate(new ProjectDescription()) + .getRelativePathsOfProjectFiles()).isEmpty(); + } + + @Test + void helpDocumentIsContributedWithLinks() { + Dependency dependency = Dependency.withId("example", "com.example", "example"); + dependency.getLinks().add( + Link.create("guide", "https://example.com/how-to", "How-to example")); + dependency.getLinks().add(Link.create("reference", "https://example.com/doc", + "Reference doc example")); + this.metadataBuilder.addDependencyGroup("test", dependency); + ProjectDescription description = new ProjectDescription(); + description.addDependency("example", null); + assertThat( + this.projectTester.generate(description).getRelativePathsOfProjectFiles()) + .containsOnly("HELP.md"); + } + +} diff --git a/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/documentation/HelpDocumentTests.java b/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/documentation/HelpDocumentTests.java new file mode 100644 index 00000000..9d02455a --- /dev/null +++ b/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/documentation/HelpDocumentTests.java @@ -0,0 +1,93 @@ +/* + * 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.spring.documentation; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; + +import io.spring.initializr.generator.io.template.MustacheTemplateRenderer; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verifyZeroInteractions; + +/** + * Tests for {@link HelpDocument}. + * + * @author Stephane Nicoll + */ +class HelpDocumentTests { + + private final MustacheTemplateRenderer templateRenderer = new MustacheTemplateRenderer( + "classpath:/templates"); + + @Test + void renderEmptyDocumentDoesNotCallWriter() throws IOException { + HelpDocument document = new HelpDocument(this.templateRenderer); + PrintWriter out = mock(PrintWriter.class); + document.write(out); + verifyZeroInteractions(out); + } + + @Test + void renderSingleSection() { + HelpDocument document = new HelpDocument(this.templateRenderer); + document.addSection((writer) -> writer.println("# Test")); + String out = write(document); + assertThat(out).contains("# Test", ""); + } + + @Test + void renderLinks() { + HelpDocument document = new HelpDocument(this.templateRenderer); + document.gettingStarted().addReferenceDocLink("https://example.com/doc", "Doc"); + document.gettingStarted().addGuideLink("https://example.com/guide-1", "Guide 1"); + document.gettingStarted().addGuideLink("https://example.com/guide-2", "Guide 2"); + String out = write(document); + assertThat(out).contains("# Getting Started", "", "### Reference Documentation", + "For further reference, please consider the following sections:", "", + "* [Doc](https://example.com/doc)", "", "### Guides", + "The following guides illustrates how to use certain features concretely:", + "", "* [Guide 1](https://example.com/guide-1)", + "* [Guide 2](https://example.com/guide-2)", ""); + } + + @Test + void renderOnlyAdditionalLink() { + HelpDocument document = new HelpDocument(this.templateRenderer); + document.gettingStarted().addAdditionalLink("https://example.com/app", + "Test App"); + String out = write(document); + assertThat(out).contains("# Getting Started", "", "### Additional Links", + "These additional references should also help you:", "", + "* [Test App](https://example.com/app)", ""); + } + + private String write(HelpDocument document) { + try { + StringWriter out = new StringWriter(); + document.write(new PrintWriter(out)); + return out.toString(); + } + catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + +} diff --git a/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/documentation/RequestedDependenciesHelpDocumentCustomizerTests.java b/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/documentation/RequestedDependenciesHelpDocumentCustomizerTests.java new file mode 100644 index 00000000..323b4be0 --- /dev/null +++ b/initializr-generator-spring/src/test/java/io/spring/initializr/generator/spring/documentation/RequestedDependenciesHelpDocumentCustomizerTests.java @@ -0,0 +1,113 @@ +/* + * 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.spring.documentation; + +import java.util.List; + +import io.spring.initializr.generator.io.template.MustacheTemplateRenderer; +import io.spring.initializr.generator.project.ProjectDescription; +import io.spring.initializr.generator.project.ResolvedProjectDescription; +import io.spring.initializr.generator.spring.test.InitializrMetadataTestBuilder; +import io.spring.initializr.metadata.Dependency; +import io.spring.initializr.metadata.InitializrMetadata; +import io.spring.initializr.metadata.Link; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link RequestedDependenciesHelpDocumentCustomizer}. + * + * @author Stephane Nicoll + */ +class RequestedDependenciesHelpDocumentCustomizerTests { + + private final InitializrMetadataTestBuilder metadataBuilder = InitializrMetadataTestBuilder + .withDefaults(); + + @Test + void dependencyLinkWithNoDescriptionIsIgnored() { + Dependency dependency = Dependency.withId("example", "com.example", "example"); + dependency.getLinks().add(Link.create("guide", "https://example.com/how-to")); + this.metadataBuilder.addDependencyGroup("test", dependency); + HelpDocument document = customizeHelp("example"); + assertThat(document.gettingStarted().isEmpty()).isTrue(); + } + + @Test + void dependencyWithReferenceDocLink() { + Dependency dependency = Dependency.withId("example", "com.example", "example"); + dependency.getLinks().add(Link.create("reference", "https://example.com/doc", + "Reference doc example")); + this.metadataBuilder.addDependencyGroup("test", dependency); + HelpDocument document = customizeHelp("example"); + assertThat(document.gettingStarted().isEmpty()).isFalse(); + List links = document.gettingStarted().referenceDocs() + .getItems(); + assertThat(links).hasSize(1); + assertLink(links.get(0), "https://example.com/doc", "Reference doc example"); + } + + @Test + void dependencyWithGuideLink() { + Dependency dependency = Dependency.withId("example", "com.example", "example"); + dependency.getLinks().add( + Link.create("guide", "https://example.com/how-to", "How-to example")); + this.metadataBuilder.addDependencyGroup("test", dependency); + HelpDocument document = customizeHelp("example"); + assertThat(document.gettingStarted().isEmpty()).isFalse(); + List links = document.gettingStarted().guides() + .getItems(); + assertThat(links).hasSize(1); + assertLink(links.get(0), "https://example.com/how-to", "How-to example"); + } + + @Test + void dependencyWithAdditionalLink() { + Dependency dependency = Dependency.withId("example", "com.example", "example"); + dependency.getLinks() + .add(Link.create("something", "https://example.com/test", "Test App")); + this.metadataBuilder.addDependencyGroup("test", dependency); + HelpDocument document = customizeHelp("example"); + assertThat(document.gettingStarted().isEmpty()).isFalse(); + List links = document.gettingStarted() + .additionalLinks().getItems(); + assertThat(links).hasSize(1); + assertLink(links.get(0), "https://example.com/test", "Test App"); + } + + private void assertLink(GettingStartedSection.Link link, String href, + String description) { + assertThat(link.getHref()).isEqualTo(href); + assertThat(link.getDescription()).isEqualTo(description); + } + + private HelpDocument customizeHelp(String... requestedDependencies) { + ProjectDescription description = new ProjectDescription(); + for (String requestedDependency : requestedDependencies) { + description.addDependency(requestedDependency, null); + } + InitializrMetadata metadata = this.metadataBuilder.build(); + HelpDocument document = new HelpDocument( + new MustacheTemplateRenderer("classpath:/templates")); + new RequestedDependenciesHelpDocumentCustomizer( + new ResolvedProjectDescription(description), metadata) + .customize(document); + return document; + } + +} diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/io/text/BulletedSection.java b/initializr-generator/src/main/java/io/spring/initializr/generator/io/text/BulletedSection.java new file mode 100644 index 00000000..927adcd1 --- /dev/null +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/io/text/BulletedSection.java @@ -0,0 +1,78 @@ +/* + * 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.io.text; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.spring.initializr.generator.io.template.TemplateRenderer; + +/** + * {@link Section} for list of items using a {@link TemplateRenderer}. + * + * @param the type of the item in the bullets + * @author Madhura Bhave + */ +public class BulletedSection implements Section { + + private final TemplateRenderer templateRenderer; + + private final String templateName; + + private final String itemName; + + private List items = new ArrayList<>(); + + public BulletedSection(TemplateRenderer templateRenderer, String templateName) { + this(templateRenderer, templateName, "items"); + } + + public BulletedSection(TemplateRenderer templateRenderer, String templateName, + String itemName) { + this.templateRenderer = templateRenderer; + this.templateName = templateName; + this.itemName = itemName; + } + + public BulletedSection addItem(T item) { + this.items.add(item); + return this; + } + + public boolean isEmpty() { + return this.items.isEmpty(); + } + + public List getItems() { + return Collections.unmodifiableList(this.items); + } + + @Override + public void write(PrintWriter writer) throws IOException { + if (!isEmpty()) { + Map model = new HashMap<>(); + model.put(this.itemName, this.items); + writer.println(this.templateRenderer.render(this.templateName, model)); + } + } + +} diff --git a/initializr-generator/src/main/java/io/spring/initializr/generator/io/text/MustacheSection.java b/initializr-generator/src/main/java/io/spring/initializr/generator/io/text/MustacheSection.java new file mode 100644 index 00000000..aaba4458 --- /dev/null +++ b/initializr-generator/src/main/java/io/spring/initializr/generator/io/text/MustacheSection.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.generator.io.text; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Map; + +import io.spring.initializr.generator.io.template.MustacheTemplateRenderer; + +/** + * {@link Section} that uses a {@link MustacheTemplateRenderer}. Renders the content with + * a newline at the end. + * + * @author Madhura Bhave + */ +public class MustacheSection implements Section { + + private final MustacheTemplateRenderer templateRenderer; + + private final String templateName; + + private final Map model; + + public MustacheSection(MustacheTemplateRenderer templateRenderer, String templateName, + Map model) { + this.templateRenderer = templateRenderer; + this.templateName = templateName; + this.model = model; + } + + @Override + public void write(PrintWriter writer) throws IOException { + writer.println(this.templateRenderer.render(this.templateName, + resolveModel(this.model))); + } + + /** + * Resolve the {@code model} prior to render the section. + * @param model the current model + * @return the model to use to render this section (never null) + */ + protected Map resolveModel(Map model) { + return model; + } + +} diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/io/text/BulletedSectionTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/io/text/BulletedSectionTests.java new file mode 100644 index 00000000..20e9fe9a --- /dev/null +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/io/text/BulletedSectionTests.java @@ -0,0 +1,101 @@ +/* + * 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.io.text; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Collections; +import java.util.Map; + +import io.spring.initializr.generator.io.template.TemplateRenderer; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +/** + * Tests for {@link BulletedSection}. + * + * @author Stephane Nicoll + */ +@ExtendWith(MockitoExtension.class) +class BulletedSectionTests { + + @Mock + private TemplateRenderer renderer; + + @Captor + private ArgumentCaptor> modelCaptor; + + @Test + void bulletedSectionEmpty() { + assertThat(new BulletedSection(this.renderer, "test").isEmpty()).isTrue(); + } + + @Test + void bulletedSectionEmptyDoesNotInvokeRender() throws IOException { + BulletedSection section = new BulletedSection<>(this.renderer, "test"); + PrintWriter writer = mock(PrintWriter.class); + section.write(writer); + verifyNoMoreInteractions(writer, this.renderer); + } + + @Test + void bulletedSectionWithItem() { + BulletedSection section = new BulletedSection<>(this.renderer, "test"); + section.addItem("test"); + assertThat(section.isEmpty()).isFalse(); + } + + @Test + void bulletedSectionWithDefaultItemName() throws IOException { + given(this.renderer.render(eq("template"), any())).willReturn("output"); + BulletedSection section = new BulletedSection<>(this.renderer, + "template"); + section.addItem("test"); + section.write(new PrintWriter(new StringWriter())); + verify(this.renderer).render(eq("template"), this.modelCaptor.capture()); + Map model = this.modelCaptor.getValue(); + assertThat(model).containsOnly(entry("items", Collections.singletonList("test"))); + } + + @Test + void bulletedSectionWithCustomItemName() throws IOException { + given(this.renderer.render(eq("template"), any())).willReturn("output"); + BulletedSection section = new BulletedSection<>(this.renderer, "template", + "elements"); + section.addItem("test"); + section.write(new PrintWriter(new StringWriter())); + verify(this.renderer).render(eq("template"), this.modelCaptor.capture()); + Map model = this.modelCaptor.getValue(); + assertThat(model) + .containsOnly(entry("elements", Collections.singletonList("test"))); + } + +} diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/io/text/MustacheSectionTests.java b/initializr-generator/src/test/java/io/spring/initializr/generator/io/text/MustacheSectionTests.java new file mode 100644 index 00000000..c4025907 --- /dev/null +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/io/text/MustacheSectionTests.java @@ -0,0 +1,73 @@ +/* + * 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.io.text; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Collections; +import java.util.Map; + +import com.samskivert.mustache.MustacheException; +import io.spring.initializr.generator.io.template.MustacheTemplateRenderer; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +/** + * Tests for {@link MustacheSection}. + * + * @author Stephane Nicoll + */ +class MustacheSectionTests { + + private final MustacheTemplateRenderer renderer = new MustacheTemplateRenderer( + "classpath:/templates/mustache"); + + @Test + void renderSection() throws IOException { + MustacheSection section = new MustacheSection(this.renderer, "test", + Collections.singletonMap("key", "hello")); + StringWriter writer = new StringWriter(); + section.write(new PrintWriter(writer)); + assertThat(writer.toString()).isEqualTo(String.format("hello%n")); + } + + @Test + void renderSectionWithMissingKey() { + MustacheSection section = new MustacheSection(this.renderer, "test", + Collections.singletonMap("another", "hello")); + assertThatThrownBy(() -> section.write(new PrintWriter(new StringWriter()))) + .isInstanceOf(MustacheException.class).hasMessageContaining("key"); + } + + @Test + void renderSectionWithCustomModelResolution() throws IOException { + MustacheSection section = new MustacheSection(this.renderer, "test", + Collections.emptyMap()) { + @Override + protected Map resolveModel(Map model) { + return Collections.singletonMap("key", "custom"); + } + }; + StringWriter writer = new StringWriter(); + section.write(new PrintWriter(writer)); + assertThat(writer.toString()).isEqualTo(String.format("custom%n")); + } + +} diff --git a/initializr-generator/src/test/java/io/spring/initializr/generator/test/project/ProjectGeneratorTester.java b/initializr-generator/src/test/java/io/spring/initializr/generator/test/project/ProjectGeneratorTester.java index a5a2ef4b..6eaa62de 100644 --- a/initializr-generator/src/test/java/io/spring/initializr/generator/test/project/ProjectGeneratorTester.java +++ b/initializr-generator/src/test/java/io/spring/initializr/generator/test/project/ProjectGeneratorTester.java @@ -17,13 +17,14 @@ package io.spring.initializr.generator.test.project; import java.nio.file.Path; -import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; import io.spring.initializr.generator.io.IndentingWriterFactory; import io.spring.initializr.generator.io.SimpleIndentStrategy; +import io.spring.initializr.generator.io.template.MustacheTemplateRenderer; import io.spring.initializr.generator.project.DefaultProjectAssetGenerator; import io.spring.initializr.generator.project.ProjectAssetGenerator; import io.spring.initializr.generator.project.ProjectDescription; @@ -49,8 +50,12 @@ public class ProjectGeneratorTester } private static Map, Supplier> defaultBeans() { - return Collections.singletonMap(IndentingWriterFactory.class, + Map, Supplier> beans = new HashMap<>(); + beans.put(IndentingWriterFactory.class, () -> IndentingWriterFactory.create(new SimpleIndentStrategy(" "))); + beans.put(MustacheTemplateRenderer.class, + () -> new MustacheTemplateRenderer("classpath:/templates")); + return beans; } @Override 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 d5153792..2897c060 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 @@ -89,8 +89,8 @@ public class InitializrAutoConfiguration { } @Bean - @ConditionalOnMissingBean - public TemplateRenderer templateRenderer(Environment environment, + @ConditionalOnMissingBean(TemplateRenderer.class) + public MustacheTemplateRenderer templateRenderer(Environment environment, ObjectProvider cacheManager) { return new MustacheTemplateRenderer("classpath:/templates", determineCache(environment, cacheManager.getIfAvailable())); 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 index f3a70d2c..bd999d7d 100644 --- 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 @@ -24,6 +24,7 @@ import java.util.Map; import io.spring.initializr.generator.io.IndentingWriterFactory; import io.spring.initializr.generator.io.SimpleIndentStrategy; +import io.spring.initializr.generator.io.template.MustacheTemplateRenderer; import io.spring.initializr.generator.project.ProjectDirectoryFactory; import io.spring.initializr.generator.spring.test.InitializrMetadataTestBuilder; import io.spring.initializr.generator.spring.test.ProjectAssert; @@ -206,6 +207,11 @@ public class ProjectGenerationInvokerTests { return IndentingWriterFactory.create(new SimpleIndentStrategy("\t")); } + @Bean + public MustacheTemplateRenderer templateRenderer() { + return new MustacheTemplateRenderer("classpath:/templates"); + } + @Bean public ProjectDirectoryFactory projectDirectoryFactory() { return (description) -> Files.createTempDirectory("project-");