From 3c52f3a5805c4fe26b9459c27a5c73e73f3c9006 Mon Sep 17 00:00:00 2001 From: Andrea La Grotteria Date: Wed, 6 Nov 2024 15:40:58 +0100 Subject: [PATCH] Add files copy to core (#1548) * Adds GuideProjectGenerator to core. * Adds GuideProjectGenerator to core. * Adds FileCopyUtility to core. * Adds test file. * Adds tests. * Fixes tests. * Format code, optimize imports. * Changes order of arguments in transferFiles method. --- .../java/io/micronaut/guides/core/App.java | 30 ++-- .../core/BuildDiffLinkSubstitution.java | 46 +++--- .../guides/core/CliMacroSubstitution.java | 25 +-- .../java/io/micronaut/guides/core/Cloud.java | 2 +- .../core/DefaultCoordinatesProvider.java | 2 +- .../core/DefaultFilesTransferUtility.java | 153 ++++++++++++++++++ .../guides/core/DefaultGuideParser.java | 8 +- .../core/DefaultGuideProjectGenerator.java | 8 +- .../guides/core/DefaultJsonFeedGenerator.java | 5 +- .../guides/core/DefaultLicenseLoader.java | 4 +- .../guides/core/DefaultRssFeedGenerator.java | 14 +- .../guides/core/DefaultVersionLoader.java | 2 +- .../guides/core/DependencyLines.java | 7 +- .../core/DependencyMacroSubstitution.java | 16 +- .../core/FeaturesWordsMacroSubstitution.java | 1 + .../io/micronaut/guides/core/FileType.java | 2 +- .../guides/core/FilesTransferUtility.java | 13 ++ .../java/io/micronaut/guides/core/Guide.java | 41 +++-- .../io/micronaut/guides/core/GuideUtils.java | 51 +++--- .../guides/core/GuidesConfiguration.java | 12 ++ .../core/GuidesConfigurationProperties.java | 38 +++-- .../micronaut/guides/core/GuidesOption.java | 2 +- .../guides/core/JsonFeedConfiguration.java | 1 + .../guides/core/JsonSchemaProvider.java | 3 +- .../micronaut/guides/core/MacroExclusion.java | 6 +- .../guides/core/MacroSubstitution.java | 2 +- .../io/micronaut/guides/core/MacroUtils.java | 19 +-- .../core/PlaceholderMacroSubstitution.java | 5 +- ...laceholderWithTargetMacroSubstitution.java | 1 + .../guides/core/RawTestMacroSubstitution.java | 4 +- .../core/ResourceMacroSubstitution.java | 3 +- .../core/SourceBlockMacroSubstitution.java | 13 +- .../guides/core/SourceMacroSubstitution.java | 4 +- .../guides/core/TestMacroSubstitution.java | 5 +- .../core/TestResourceMacroSubstitution.java | 1 + .../core/ZipIncludeMacroSubstitution.java | 13 +- .../guides/core/asciidoc/Attribute.java | 2 +- .../core/asciidoc/IncludeDirective.java | 26 ++- .../guides/core/FilesTransferUtilityTest.java | 80 +++++++++ .../guides/core/GuideParserTest.java | 4 +- .../core/GuideProjectGeneratorTest.java | 19 ++- .../guides/core/JsonFeedGeneratorTest.java | 21 ++- .../guides/core/RssFeedGenerationTest.java | 2 +- .../creating-your-first-micronaut-app.adoc | 45 ++++++ .../metadata.json | 17 ++ .../example/micronaut/HelloController.groovy | 32 ++++ .../micronaut/HelloControllerSpec.groovy | 41 +++++ .../guides/hello-base/hellocontroller.adoc | 12 ++ .../guides/hello-base/hellotest.adoc | 9 ++ .../example/micronaut/HelloController.java | 30 ++++ .../micronaut/HelloControllerTest.java | 45 ++++++ .../example/micronaut/HelloController.kt | 29 ++++ .../example/micronaut/HelloControllerTest.kt | 37 +++++ .../resources/guides/hello-base/metadata.json | 3 + 54 files changed, 808 insertions(+), 208 deletions(-) create mode 100644 buildSrc/src/main/java/io/micronaut/guides/core/DefaultFilesTransferUtility.java create mode 100644 buildSrc/src/main/java/io/micronaut/guides/core/FilesTransferUtility.java create mode 100644 buildSrc/src/test/java/io/micronaut/guides/core/FilesTransferUtilityTest.java create mode 100644 buildSrc/src/test/resources/guides/creating-your-first-micronaut-app/creating-your-first-micronaut-app.adoc create mode 100644 buildSrc/src/test/resources/guides/creating-your-first-micronaut-app/metadata.json create mode 100644 buildSrc/src/test/resources/guides/hello-base/groovy/src/main/groovy/example/micronaut/HelloController.groovy create mode 100644 buildSrc/src/test/resources/guides/hello-base/groovy/src/test/groovy/example/micronaut/HelloControllerSpec.groovy create mode 100644 buildSrc/src/test/resources/guides/hello-base/hellocontroller.adoc create mode 100644 buildSrc/src/test/resources/guides/hello-base/hellotest.adoc create mode 100644 buildSrc/src/test/resources/guides/hello-base/java/src/main/java/example/micronaut/HelloController.java create mode 100644 buildSrc/src/test/resources/guides/hello-base/java/src/test/java/example/micronaut/HelloControllerTest.java create mode 100644 buildSrc/src/test/resources/guides/hello-base/kotlin/src/main/kotlin/example/micronaut/HelloController.kt create mode 100644 buildSrc/src/test/resources/guides/hello-base/kotlin/src/test/kotlin/example/micronaut/HelloControllerTest.kt create mode 100644 buildSrc/src/test/resources/guides/hello-base/metadata.json diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/App.java b/buildSrc/src/main/java/io/micronaut/guides/core/App.java index 35bc3522e05..e2aff718541 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/App.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/App.java @@ -6,30 +6,30 @@ import io.micronaut.core.util.StringUtils; import io.micronaut.jsonschema.JsonSchema; import io.micronaut.serde.annotation.Serdeable; -import io.micronaut.starter.application.ApplicationType; import io.micronaut.starter.api.TestFramework; +import io.micronaut.starter.application.ApplicationType; import jakarta.validation.constraints.NotBlank; + import java.util.List; /** - * - * @param name The app's name. For single application guides, the application needs to be named default - * @param packageName The app's package name. If you don't specify, the package name example.micronaut is used - * @param applicationType The app type. If you don't specify, default is used - * @param framework The app's framework. Default is Micronaut but Spring Boot is also supported - * @param features The Micronaut Starter features' name that the app requires + * @param name The app's name. For single application guides, the application needs to be named default + * @param packageName The app's package name. If you don't specify, the package name example.micronaut is used + * @param applicationType The app type. If you don't specify, default is used + * @param framework The app's framework. Default is Micronaut but Spring Boot is also supported + * @param features The Micronaut Starter features' name that the app requires * @param invisibleFeatures The app's invisible features - * @param kotlinFeatures The app's Kotlin features - * @param javaFeatures The app's Java features - * @param groovyFeatures The app's Groovy features - * @param testFramework The app's test framework - * @param excludeTest The tests that should not be run - * @param excludeSource The source files that should not be included - * @param validateLicense To enable Spotless code check + * @param kotlinFeatures The app's Kotlin features + * @param javaFeatures The app's Java features + * @param groovyFeatures The app's Groovy features + * @param testFramework The app's test framework + * @param excludeTest The tests that should not be run + * @param excludeSource The source files that should not be included + * @param validateLicense To enable Spotless code check */ @JsonSchema @Serdeable -public record App ( +public record App( @NonNull @NotBlank String name, diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/BuildDiffLinkSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/BuildDiffLinkSubstitution.java index 4888588d504..0d8bce277bf 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/BuildDiffLinkSubstitution.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/BuildDiffLinkSubstitution.java @@ -5,12 +5,17 @@ import io.micronaut.http.uri.UriBuilder; import io.micronaut.starter.application.ApplicationType; import jakarta.inject.Singleton; + import java.net.URI; -import java.util.*; -import static io.micronaut.guides.core.MacroUtils.*; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +import static io.micronaut.guides.core.MacroUtils.findMacroLines; @Singleton public class BuildDiffLinkSubstitution implements MacroSubstitution { + public static final String MACRO_DIFF_LINK = "diffLink"; private static final String QUERY_PARAMLANG = "lang"; private static final String QUERY_PARAM_BUILD = "build"; private static final String QUERY_PARAM_TEST = "test"; @@ -19,7 +24,6 @@ public class BuildDiffLinkSubstitution implements MacroSubstitution { private static final String QUERY_PARAM_PACKAGE = "package"; private static final String QUERY_PARAM_ACTIVITY = "activity"; private static final String QUERY_PARAM_FEATURES = "features"; - public static final String MACRO_DIFF_LINK = "diffLink"; private static final String ATTRIBUTE_FEATURES = "features"; private static final String ATTRIBUTE_EXCLUDE_FEATURES = "featureExcludes"; private final GuidesConfiguration guidesConfiguration; @@ -28,16 +32,32 @@ public BuildDiffLinkSubstitution(GuidesConfiguration config) { this.guidesConfiguration = config; } + private static Set features(App app, AsciidocMacro asciidocMacro, GuidesOption option) { + Set features = new HashSet<>(); + if (app != null) { + features.addAll(GuideUtils.getAppVisibleFeatures(app, option.getLanguage())); + } + asciidocMacro.attributes().stream() + .filter(attribute -> attribute.key().equals(ATTRIBUTE_FEATURES)) + .map(Attribute::values) + .forEach(features::addAll); + asciidocMacro.attributes().stream() + .filter(attribute -> attribute.key().equals(ATTRIBUTE_EXCLUDE_FEATURES)) + .map(Attribute::values) + .forEach(features::removeAll); + return features; + } + @Override public String substitute(String str, Guide guide, GuidesOption option) { - for(String line : findMacroLines(str, MACRO_DIFF_LINK)) { + for (String line : findMacroLines(str, MACRO_DIFF_LINK)) { Optional asciidocMacroOptional = AsciidocMacro.of(MACRO_DIFF_LINK, line); if (asciidocMacroOptional.isEmpty()) { continue; } AsciidocMacro asciidocMacro = asciidocMacroOptional.get(); String res = buildDiffLink(asciidocMacro, guide, option).toString() + "[Diff]"; - str = str.replace(line,res); + str = str.replace(line, res); } return str; } @@ -57,20 +77,4 @@ private URI buildDiffLink(AsciidocMacro asciidocMacro, Guide guide, GuidesOption features.forEach(f -> uriBuilder.queryParam(QUERY_PARAM_FEATURES, f)); return uriBuilder.build(); } - - private static Set features(App app, AsciidocMacro asciidocMacro, GuidesOption option) { - Set features = new HashSet<>(); - if (app != null) { - features.addAll(GuideUtils.getAppVisibleFeatures(app, option.getLanguage())); - } - asciidocMacro.attributes().stream() - .filter(attribute -> attribute.key().equals(ATTRIBUTE_FEATURES)) - .map(Attribute::values) - .forEach(features::addAll); - asciidocMacro.attributes().stream() - .filter(attribute -> attribute.key().equals(ATTRIBUTE_EXCLUDE_FEATURES)) - .map(Attribute::values) - .forEach(features::removeAll); - return features; - } } diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/CliMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/CliMacroSubstitution.java index 2411be50d01..27a555525fa 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/CliMacroSubstitution.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/CliMacroSubstitution.java @@ -2,6 +2,7 @@ import jakarta.inject.Singleton; import org.gradle.api.GradleException; + import java.util.stream.Collectors; @Singleton @@ -12,6 +13,17 @@ public class CliMacroSubstitution extends PlaceholderWithTargetMacroSubstitution private static final String CLI_FUNCTION = "create-function-app"; private static final String CLI_CLI = "create-cli-app"; + private static String cliCommandForApp(App app) { + return switch (app.applicationType()) { + case CLI -> CLI_CLI; + case FUNCTION -> CLI_FUNCTION; + case GRPC -> CLI_GRPC; + case MESSAGING -> CLI_MESSAGING; + case DEFAULT -> CLI_DEFAULT; + default -> throw new IllegalArgumentException("Unknown application type: " + app.applicationType()); + }; + } + @Override protected String getMacroName() { return "cli-command"; @@ -25,19 +37,8 @@ protected String getSubstitution(Guide guide, GuidesOption option, String appNam .orElse(null); if (app != null) { return cliCommandForApp(app); - } else{ + } else { throw new GradleException("No CLI command found for app: " + app + " -- should be one of " + guide.apps().stream().map(el -> "@" + el + ":cli-command@").collect(Collectors.joining(", "))); } } - - private static String cliCommandForApp(App app) { - return switch (app.applicationType()) { - case CLI -> CLI_CLI; - case FUNCTION -> CLI_FUNCTION; - case GRPC -> CLI_GRPC; - case MESSAGING -> CLI_MESSAGING; - case DEFAULT -> CLI_DEFAULT; - default -> throw new IllegalArgumentException("Unknown application type: " + app.applicationType()); - }; - } } diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/Cloud.java b/buildSrc/src/main/java/io/micronaut/guides/core/Cloud.java index 8cce1c598af..01706998758 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/Cloud.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/Cloud.java @@ -4,7 +4,7 @@ public enum Cloud implements Ordered { OCI("Oracle Cloud", "OCI", 1), - AWS("Amazon Web Services", "AWS", 2), + AWS("Amazon Web Services", "AWS", 2), AZURE("Microsoft Azure", "Azure", 3), GCP("Google Cloud Platform", "GCP", 4); diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/DefaultCoordinatesProvider.java b/buildSrc/src/main/java/io/micronaut/guides/core/DefaultCoordinatesProvider.java index 1cf8eb1d44b..e9bab8ce2be 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/DefaultCoordinatesProvider.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/DefaultCoordinatesProvider.java @@ -8,7 +8,7 @@ import java.util.Map; @Singleton -public class DefaultCoordinatesProvider implements CoordinatesProvider{ +public class DefaultCoordinatesProvider implements CoordinatesProvider { @Override public Map getCoordinates() { try (ApplicationContext context = ApplicationContext.run()) { diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/DefaultFilesTransferUtility.java b/buildSrc/src/main/java/io/micronaut/guides/core/DefaultFilesTransferUtility.java new file mode 100644 index 00000000000..9cdb32db349 --- /dev/null +++ b/buildSrc/src/main/java/io/micronaut/guides/core/DefaultFilesTransferUtility.java @@ -0,0 +1,153 @@ +package io.micronaut.guides.core; + +import io.micronaut.core.annotation.NonNull; +import jakarta.inject.Singleton; +import jakarta.validation.constraints.NotNull; +import org.gradle.api.GradleException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.Arrays; +import java.util.List; + +import static io.micronaut.core.util.StringUtils.EMPTY_STRING; + +@Singleton +public class DefaultFilesTransferUtility implements FilesTransferUtility { + private static final Logger LOG = LoggerFactory.getLogger(DefaultFilesTransferUtility.class); + private static final String EXTENSION_JAVA = ".java"; + private static final String EXTENSION_GROOVY = ".groovy"; + private static final String EXTENSION_KT = ".kt"; + + private final LicenseLoader licenseLoader; + private final GuidesConfiguration guidesConfiguration; + + DefaultFilesTransferUtility(LicenseLoader licenseLoader, + GuidesConfiguration guidesConfiguration) { + this.licenseLoader = licenseLoader; + this.guidesConfiguration = guidesConfiguration; + } + + private static boolean fileContainsText(File file, String text) { + try { + return new String(Files.readAllBytes(file.toPath())).contains(text); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + private static void copyGuideSourceFiles(File inputDir, Path destinationPath, + String appName, String language, + boolean ignoreMissingDirectories) throws IOException { + + // look for a common 'src' directory shared by multiple languages and copy those files first + final String srcFolder = "src"; + Path srcPath = Paths.get(inputDir.getAbsolutePath(), appName, srcFolder); + if (Files.exists(srcPath)) { + Files.walkFileTree(srcPath, new CopyFileVisitor(Paths.get(destinationPath.toString(), srcFolder))); + } + + Path sourcePath = Paths.get(inputDir.getAbsolutePath(), appName, language); + if (!Files.exists(sourcePath)) { + sourcePath.toFile().mkdir(); + } + if (Files.exists(sourcePath)) { + // copy source/resource files for the current language + Files.walkFileTree(sourcePath, new CopyFileVisitor(destinationPath)); + } else if (!ignoreMissingDirectories) { + throw new GradleException("source directory " + sourcePath.toFile().getAbsolutePath() + " does not exist"); + } + } + + private static File fileToDelete(File destination, String path) { + return Paths.get(destination.getAbsolutePath(), path).toFile(); + } + + private static void copyFile(File inputDir, File destinationRoot, String filePath) throws IOException { + File sourceFile = new File(inputDir, filePath); + File destinationFile = new File(destinationRoot, filePath); + + File destinationFileDir = destinationFile.getParentFile(); + if (!destinationFileDir.exists()) { + Files.createDirectories(destinationFileDir.toPath()); + } + + Files.copy(sourceFile.toPath(), destinationFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + } + + @Override + public void transferFiles(@NotNull @NonNull File inputDirectory, @NotNull @NonNull File outputDirectory, @NotNull @NonNull Guide guide) throws IOException { + List guidesOptionList = GuideGenerationUtils.guidesOptions(guide, LOG); + for (GuidesOption guidesOption : guidesOptionList) { + for (App app : guide.apps()) { + String appName = app.name().equals(guidesConfiguration.getDefaultAppName()) ? EMPTY_STRING : app.name(); + String folder = MacroUtils.getSourceDir(guide.slug(), guidesOption); + Path destinationPath = Paths.get(outputDirectory.getAbsolutePath(), folder, appName); + File destination = destinationPath.toFile(); + + if (guide.base() != null) { + File baseDir = new File(inputDirectory.getParentFile(), guide.base()); + copyGuideSourceFiles(baseDir, destinationPath, appName, guidesOption.getLanguage().toString(), true); + } + + copyGuideSourceFiles(inputDirectory, destinationPath, appName, guidesOption.getLanguage().toString(), false); + + if (app.excludeSource() != null) { + for (String mainSource : app.excludeSource()) { + File f = fileToDelete(destination, GuideGenerationUtils.mainPath(appName, mainSource, guidesOption, guidesConfiguration)); + if (f.exists()) { + f.delete(); + } + f = fileToDelete(destination, GuideGenerationUtils.mainPath(appName, mainSource, guidesOption, guidesConfiguration)); + if (f.exists()) { + f.delete(); + } + } + } + + if (app.excludeTest() != null) { + for (String testSource : app.excludeTest()) { + File f = fileToDelete(destination, GuideGenerationUtils.testPath(appName, testSource, guidesOption, guidesConfiguration)); + if (f.exists()) { + f.delete(); + } + f = fileToDelete(destination, GuideGenerationUtils.testPath(appName, testSource, guidesOption, guidesConfiguration)); + if (f.exists()) { + f.delete(); + } + } + } + + if (guide.zipIncludes() != null) { + File destinationRoot = new File(outputDirectory.getAbsolutePath(), folder); + for (String zipInclude : guide.zipIncludes()) { + copyFile(inputDirectory, destinationRoot, zipInclude); + } + } + addLicenses(new File(outputDirectory.getAbsolutePath(), folder)); + } + } + } + + void addLicenses(File folder) { + String licenseHeader = licenseLoader.getLicenseHeaderText(); + Arrays.stream(folder.listFiles()).forEach(file -> { + if ((file.getPath().endsWith(EXTENSION_JAVA) || file.getPath().endsWith(EXTENSION_GROOVY) || file.getPath().endsWith(EXTENSION_KT)) + && !fileContainsText(file, "Licensed under")) { + try { + String content = new String(Files.readAllBytes(file.toPath())); + Files.write(file.toPath(), (licenseHeader + content).getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + } + }); + } +} diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/DefaultGuideParser.java b/buildSrc/src/main/java/io/micronaut/guides/core/DefaultGuideParser.java index 8f348cb0059..00d7ae0dd8d 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/DefaultGuideParser.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/DefaultGuideParser.java @@ -39,8 +39,8 @@ public DefaultGuideParser(JsonSchemaProvider jsonSchemaProvider, JsonMapper json public List parseGuidesMetadata(@NonNull @NotNull File guidesDir, @NonNull @NotNull String metadataConfigName) { List metadatas = new ArrayList<>(); - File dirs[] = guidesDir.listFiles(File::isDirectory); - if(dirs == null) { + File[] dirs = guidesDir.listFiles(File::isDirectory); + if (dirs == null) { return metadatas; } for (File dir : dirs) { @@ -69,10 +69,10 @@ public Optional parseGuideMetadata(@NonNull @NotNull File guidesDir, @Non return Optional.empty(); } - Map config = (Map) new JsonSlurper().parse(configFile); + Map config = (Map) new JsonSlurper().parse(configFile); boolean publish = config.get("publish") == null || (Boolean) config.get("publish"); - if(publish) { + if (publish) { Set assertions = jsonSchemaProvider.getSchema().validate(content, InputFormat.JSON); if (!assertions.isEmpty()) { diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/DefaultGuideProjectGenerator.java b/buildSrc/src/main/java/io/micronaut/guides/core/DefaultGuideProjectGenerator.java index 735c8a0a562..8aea98a5f35 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/DefaultGuideProjectGenerator.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/DefaultGuideProjectGenerator.java @@ -19,7 +19,6 @@ import jakarta.inject.Singleton; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; -import org.gradle.api.JavaVersion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -64,7 +63,8 @@ public void generate(@NotNull @NonNull File outputDirectory, @NotNull @NonNull G } return; } - List guidesOptionList = GuideGenerationUtils.guidesOptions(guide,LOG); + + List guidesOptionList = GuideGenerationUtils.guidesOptions(guide, LOG); for (GuidesOption guidesOption : guidesOptionList) { generate(outputDirectory, guide, guidesOption, javaVersion); } @@ -89,10 +89,6 @@ public void generate(@NonNull File outputDirectory, appFeatures.remove("graalvm"); } - if (guidesOption.getTestFramework() == TestFramework.SPOCK) { - appFeatures.remove("mockito"); - } - // typical guides use 'default' as name, multi-project guides have different modules String folder = MacroUtils.getSourceDir(guide.slug(), guidesOption); diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/DefaultJsonFeedGenerator.java b/buildSrc/src/main/java/io/micronaut/guides/core/DefaultJsonFeedGenerator.java index 22926627291..acb03c192fa 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/DefaultJsonFeedGenerator.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/DefaultJsonFeedGenerator.java @@ -19,6 +19,7 @@ public class DefaultJsonFeedGenerator implements JsonFeedGenerator { private final GuidesConfiguration guidesConfiguration; private final JsonFeedConfiguration jsonFeedConfiguration; private final JsonMapper jsonMapper; + public DefaultJsonFeedGenerator(GuidesConfiguration guidesConfiguration, JsonFeedConfiguration jsonFeedConfiguration, JsonMapper jsonMapper) { @@ -57,8 +58,8 @@ private JsonFeedItem jsonFeedItem(Guide metadata) { .contentText(metadata.intro()) .language(RssLanguage.LANG_ENGLISH) .datePublished(ZonedDateTime.of(metadata.publicationDate(), LocalTime.of(0, 0), ZoneOffset.UTC)) - .url(guidesConfiguration.getHomePageUrl() +metadata.slug()); - for (String author: metadata.authors()) { + .url(guidesConfiguration.getHomePageUrl() + metadata.slug()); + for (String author : metadata.authors()) { jsonFeedItemBuilder.author(JsonFeedAuthor.builder().name(author).build()); } for (String t : GuideUtils.getTags(metadata)) { diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/DefaultLicenseLoader.java b/buildSrc/src/main/java/io/micronaut/guides/core/DefaultLicenseLoader.java index 112e37957f6..d44a95c4407 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/DefaultLicenseLoader.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/DefaultLicenseLoader.java @@ -46,5 +46,7 @@ public int getNumberOfLines() { } @Override - public String getLicenseHeaderText() { return this.licenseHeaderText; } + public String getLicenseHeaderText() { + return this.licenseHeaderText; + } } diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/DefaultRssFeedGenerator.java b/buildSrc/src/main/java/io/micronaut/guides/core/DefaultRssFeedGenerator.java index 99ce3a0c86d..dd30975eb95 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/DefaultRssFeedGenerator.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/DefaultRssFeedGenerator.java @@ -23,7 +23,7 @@ public DefaultRssFeedGenerator(GuidesConfiguration guidesConfiguration) { @NonNull public String rssFeed(@NonNull List metadatas) { - RssChannel.Builder rssBuilder = rssBuilder(); + RssChannel.Builder rssBuilder = rssBuilder(); for (Guide metadata : metadatas) { rssBuilder.item(rssFeedElement(metadata)); } @@ -43,12 +43,12 @@ private RssChannel.Builder rssBuilder() { private RssItem rssFeedElement(Guide metadata) { RssItem.Builder rssItemBuilder = RssItem.builder() - .guid(metadata.slug()) - .title(metadata.title()) - .description(metadata.intro()) - .pubDate(ZonedDateTime.of(metadata.publicationDate(), LocalTime.of(0, 0), ZoneOffset.UTC)) - .link(guidesConfiguration.getHomePageUrl() + metadata.slug()); - for (String author: metadata.authors()) { + .guid(metadata.slug()) + .title(metadata.title()) + .description(metadata.intro()) + .pubDate(ZonedDateTime.of(metadata.publicationDate(), LocalTime.of(0, 0), ZoneOffset.UTC)) + .link(guidesConfiguration.getHomePageUrl() + metadata.slug()); + for (String author : metadata.authors()) { rssItemBuilder.author(author); } rssItemBuilder.category(GuideUtils.getTags(metadata)); diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/DefaultVersionLoader.java b/buildSrc/src/main/java/io/micronaut/guides/core/DefaultVersionLoader.java index fdb6a8e13c8..eca6cfe0beb 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/DefaultVersionLoader.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/DefaultVersionLoader.java @@ -10,7 +10,7 @@ import java.util.Optional; @Singleton -public class DefaultVersionLoader implements VersionLoader{ +public class DefaultVersionLoader implements VersionLoader { private final String version; public DefaultVersionLoader(GuidesConfiguration guidesConfiguration, diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/DependencyLines.java b/buildSrc/src/main/java/io/micronaut/guides/core/DependencyLines.java index d8627a05efd..3b1377ba22f 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/DependencyLines.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/DependencyLines.java @@ -4,12 +4,7 @@ import io.micronaut.starter.options.BuildTool; import io.micronaut.starter.options.Language; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import static io.micronaut.starter.options.BuildTool.GRADLE; import static io.micronaut.starter.options.BuildTool.MAVEN; diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/DependencyMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/DependencyMacroSubstitution.java index 456bb371c54..894f57c39ae 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/DependencyMacroSubstitution.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/DependencyMacroSubstitution.java @@ -1,21 +1,23 @@ package io.micronaut.guides.core; import jakarta.inject.Singleton; + import java.util.List; -import static io.micronaut.guides.core.MacroUtils.*; +import static io.micronaut.guides.core.MacroUtils.findMacroGroups; +import static io.micronaut.guides.core.MacroUtils.findMacroLines; @Singleton -public class DependencyMacroSubstitution implements MacroSubstitution{ +public class DependencyMacroSubstitution implements MacroSubstitution { @Override public String substitute(String str, Guide guide, GuidesOption option) { - for(String block : findMacroGroups(str, "dependencies")){ - List lines = DependencyLines.asciidoc(block.replace(":dependencies:","").strip().lines().toList(), option.getBuildTool(), option.getLanguage()); - str = str.replace(block,String.join("\n", lines)); + for (String block : findMacroGroups(str, "dependencies")) { + List lines = DependencyLines.asciidoc(block.replace(":dependencies:", "").strip().lines().toList(), option.getBuildTool(), option.getLanguage()); + str = str.replace(block, String.join("\n", lines)); } - for(String line : findMacroLines(str, "dependency")){ + for (String line : findMacroLines(str, "dependency")) { List lines = DependencyLines.asciidoc(line, option.getBuildTool(), option.getLanguage()); - str = str.replace(line,String.join("\n", lines)); + str = str.replace(line, String.join("\n", lines)); } return str; } diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/FeaturesWordsMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/FeaturesWordsMacroSubstitution.java index 1f954fe2f4a..ea325ee47dd 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/FeaturesWordsMacroSubstitution.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/FeaturesWordsMacroSubstitution.java @@ -1,6 +1,7 @@ package io.micronaut.guides.core; import jakarta.inject.Singleton; + import java.util.List; import java.util.stream.Collectors; diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/FileType.java b/buildSrc/src/main/java/io/micronaut/guides/core/FileType.java index 8403ad87bc0..6c8716330ff 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/FileType.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/FileType.java @@ -2,5 +2,5 @@ public enum FileType { CODE, - RESOURCE; + RESOURCE } diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/FilesTransferUtility.java b/buildSrc/src/main/java/io/micronaut/guides/core/FilesTransferUtility.java new file mode 100644 index 00000000000..8d8908112ba --- /dev/null +++ b/buildSrc/src/main/java/io/micronaut/guides/core/FilesTransferUtility.java @@ -0,0 +1,13 @@ +package io.micronaut.guides.core; + +import io.micronaut.core.annotation.NonNull; +import jakarta.validation.constraints.NotNull; + +import java.io.File; +import java.io.IOException; + +public interface FilesTransferUtility { + void transferFiles(@NotNull @NonNull File inputDirectory, + @NotNull @NonNull File outputDirectory, + @NotNull @NonNull Guide guide) throws IOException; +} diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/Guide.java b/buildSrc/src/main/java/io/micronaut/guides/core/Guide.java index c95177881ab..b9053ec7ac1 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/Guide.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/Guide.java @@ -6,9 +6,9 @@ import io.micronaut.core.util.StringUtils; import io.micronaut.jsonschema.JsonSchema; import io.micronaut.serde.annotation.Serdeable; +import io.micronaut.starter.api.TestFramework; import io.micronaut.starter.options.BuildTool; import io.micronaut.starter.options.Language; -import io.micronaut.starter.api.TestFramework; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; @@ -18,28 +18,27 @@ import java.util.Map; /** - * - * @param title The guide's title - * @param intro The guide introduction - * @param authors The guide's authors - * @param categories The guide's categories - * @param publicationDate The guide publication date. It should follow the format YYYY-MM-DD + * @param title The guide's title + * @param intro The guide introduction + * @param authors The guide's authors + * @param categories The guide's categories + * @param publicationDate The guide publication date. It should follow the format YYYY-MM-DD * @param minimumJavaVersion If the guide needs a minimum Java version, define it here * @param maximumJavaVersion If the guide needs a maximum Java version, define it here - * @param cloud The acronym for the cloud service provider of the guide. For example, OCI for Oracle Cloud Infrastructure - * @param skipGradleTests Set it to true to skip running the tests for the Gradle applications for the guide - * @param skipMavenTests Set it to true to skip running the tests for the Maven applications for the guide - * @param asciidoctor The guide asciidoc file. If not specified, the guide slug followed by the .adoc suffix is used - * @param languages The guide supported languages - * @param tags List of tags added to the guide. features are added automatically as tags. No need to repeat them here - * @param buildTools By default the code in the guide is generated for Gradle and Maven. If a guide is specific only for a build tool, define it here - * @param testFramework The guide's test framework. By default Java and Kotlin applications are tested with JUnit5 and Groovy applications with Spock - * @param zipIncludes List of additional files with a relative path to include in the generated zip file for the guide - * @param slug The guide's slug. If not specified, the guides folder is used - * @param publish Whether the guide should be published, it defaults to true. You can set it to false for draft or base guides - * @param base Defaults to null; if set, indicates directory name of the base guide to copy before copying the current one - * @param env The guide's environment variables - * @param apps Applications created for the guide + * @param cloud The acronym for the cloud service provider of the guide. For example, OCI for Oracle Cloud Infrastructure + * @param skipGradleTests Set it to true to skip running the tests for the Gradle applications for the guide + * @param skipMavenTests Set it to true to skip running the tests for the Maven applications for the guide + * @param asciidoctor The guide asciidoc file. If not specified, the guide slug followed by the .adoc suffix is used + * @param languages The guide supported languages + * @param tags List of tags added to the guide. features are added automatically as tags. No need to repeat them here + * @param buildTools By default the code in the guide is generated for Gradle and Maven. If a guide is specific only for a build tool, define it here + * @param testFramework The guide's test framework. By default Java and Kotlin applications are tested with JUnit5 and Groovy applications with Spock + * @param zipIncludes List of additional files with a relative path to include in the generated zip file for the guide + * @param slug The guide's slug. If not specified, the guides folder is used + * @param publish Whether the guide should be published, it defaults to true. You can set it to false for draft or base guides + * @param base Defaults to null; if set, indicates directory name of the base guide to copy before copying the current one + * @param env The guide's environment variables + * @param apps Applications created for the guide */ @JsonSchema @Serdeable diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/GuideUtils.java b/buildSrc/src/main/java/io/micronaut/guides/core/GuideUtils.java index 7faafa9c656..8d90616cb90 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/GuideUtils.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/GuideUtils.java @@ -1,12 +1,15 @@ package io.micronaut.guides.core; -import com.networknt.schema.*; +import com.networknt.schema.InputFormat; +import com.networknt.schema.JsonSchema; +import com.networknt.schema.ValidationMessage; import groovy.json.JsonSlurper; import io.micronaut.json.JsonMapper; import io.micronaut.starter.options.BuildTool; import io.micronaut.starter.options.Language; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -27,9 +30,9 @@ private GuideUtils() { } public static List parseGuidesMetadata(File guidesDir, - String metadataConfigName, - JsonSchema schema, - JsonMapper jsonMapper) throws Exception { + String metadataConfigName, + JsonSchema schema, + JsonMapper jsonMapper) throws Exception { List metadatas = new ArrayList<>(); for (File dir : guidesDir.listFiles(File::isDirectory)) { @@ -41,9 +44,9 @@ public static List parseGuidesMetadata(File guidesDir, return metadatas; } - private static Optional parseGuideMetadata(File dir, String metadataConfigName, - JsonSchema schema, - JsonMapper jsonMapper) throws Exception { + static Optional parseGuideMetadata(File dir, String metadataConfigName, + JsonSchema schema, + JsonMapper jsonMapper) throws Exception { File configFile = new File(dir, metadataConfigName); if (!configFile.exists()) { LOG.warn("metadata file not found for {}", dir.getName()); @@ -58,10 +61,10 @@ private static Optional parseGuideMetadata(File dir, String metadataConfi return Optional.empty(); } - Map config = (Map) new JsonSlurper().parse(configFile); - boolean publish = config.get("publish") == null ? true : (Boolean) config.get("publish"); + Map config = (Map) new JsonSlurper().parse(configFile); + boolean publish = config.get("publish") == null || (Boolean) config.get("publish"); - if(publish){ + if (publish) { Set assertions = schema.validate(content, InputFormat.JSON); if (!assertions.isEmpty()) { @@ -123,10 +126,10 @@ public static List getTags(Guide guide) { } for (App app : guide.apps()) { List allFeatures = new ArrayList<>(); - addAllSafe(allFeatures,app.features()); - addAllSafe(allFeatures,app.javaFeatures()); - addAllSafe(allFeatures,app.kotlinFeatures()); - addAllSafe(allFeatures,app.groovyFeatures()); + addAllSafe(allFeatures, app.features()); + addAllSafe(allFeatures, app.javaFeatures()); + addAllSafe(allFeatures, app.kotlinFeatures()); + addAllSafe(allFeatures, app.groovyFeatures()); for (String featureName : allFeatures) { String tagToAdd = featureName; for (String prefix : FEATURES_PREFIXES) { @@ -137,7 +140,7 @@ public static List getTags(Guide guide) { tagsList.add(tagToAdd); } } - Set categoriesAsTags = guide.categories().stream().map(String::toLowerCase).map(s -> s.replace(" ","-")).collect(Collectors.toSet()); + Set categoriesAsTags = guide.categories().stream().map(String::toLowerCase).map(s -> s.replace(" ", "-")).collect(Collectors.toSet()); tagsList.addAll(categoriesAsTags); return tagsList.stream().collect(Collectors.toList()); } @@ -158,7 +161,7 @@ public static List getAppFeatures(App app, Language language) { public static List getAppInvisibleFeatures(App app) { if (app.validateLicense()) { List result = new ArrayList<>(); - addAllSafe(result,app.invisibleFeatures()); + addAllSafe(result, app.invisibleFeatures()); result.add(FEATURE_SPOTLESS); return result; } @@ -167,13 +170,13 @@ public static List getAppInvisibleFeatures(App app) { public static List getAppVisibleFeatures(App app, Language language) { if (language == Language.JAVA) { - return mergeLists(app.features(),app.javaFeatures()); + return mergeLists(app.features(), app.javaFeatures()); } if (language == Language.KOTLIN) { - return mergeLists(app.features(),app.kotlinFeatures()); + return mergeLists(app.features(), app.kotlinFeatures()); } if (language == Language.GROOVY) { - return mergeLists(app.features(),app.groovyFeatures()); + return mergeLists(app.features(), app.groovyFeatures()); } return app.features(); } @@ -188,7 +191,7 @@ public static boolean shouldSkip(Guide guide, BuildTool buildTool) { return false; } - public static Set getFrameworks(Guide guide){ + public static Set getFrameworks(Guide guide) { return guide.apps().stream().map(it -> it.framework()).collect(Collectors.toSet()); } @@ -214,7 +217,7 @@ public static Guide merge(Guide base, Guide guide) { guide.publish(), guide.base(), guide.env() == null ? base.env() : guide.env(), - mergeApps(base.apps(),guide.apps()) + mergeApps(base.apps(), guide.apps()) ); return merged; } @@ -287,15 +290,15 @@ private static List mergeLists(Collection... lists) { * Adds all elements from the source collection to the target collection safely. * * @param target The collection where elements will be added. - * @param src The collection whose elements are to be added to the target. + * @param src The collection whose elements are to be added to the target. * @throws NullPointerException If the target collection is null. */ private static void addAllSafe(Collection target, Collection src) { - if(target == null) { + if (target == null) { throw new NullPointerException("Target list cannot be null"); } - if(src != null) { + if (src != null) { target.addAll(src); } } diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/GuidesConfiguration.java b/buildSrc/src/main/java/io/micronaut/guides/core/GuidesConfiguration.java index a9149566902..27d38559191 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/GuidesConfiguration.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/GuidesConfiguration.java @@ -6,16 +6,28 @@ public interface GuidesConfiguration { String getHomePageUrl(); + String getTitle(); + String getLicensePath(); + String getPackageName(); + String getDefaultAppName(); + String getProjectGeneratorUrl(); + int getDefaultMinJdk(); + String getApiUrl(); + String getVersionPath(); + String getEnvJdkVersion(); + List getFilesWithHeader(); + JdkVersion getDefaultJdkVersion(); + List getJdkVersionsSupportedByGraalvm(); } diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/GuidesConfigurationProperties.java b/buildSrc/src/main/java/io/micronaut/guides/core/GuidesConfigurationProperties.java index 7383bbd007c..bb421940c3e 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/GuidesConfigurationProperties.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/GuidesConfigurationProperties.java @@ -2,7 +2,9 @@ import io.micronaut.context.annotation.ConfigurationProperties; import io.micronaut.starter.options.JdkVersion; + import java.util.List; + import static io.micronaut.starter.options.JdkVersion.JDK_17; import static io.micronaut.starter.options.JdkVersion.JDK_21; @@ -10,13 +12,8 @@ public class GuidesConfigurationProperties implements GuidesConfiguration { public static final String PREFIX = "guides"; public static final String GUIDES_URL = "https://guides.micronaut.io/latest/"; - private String title = "Micronaut Guides"; - private String homePageUrl = GUIDES_URL; private static final String DEFAULT_LICENSEHEADER = "classpath:LICENSEHEADER"; private static final String DEFAULT_PACKAGE_NAME = "example.micronaut"; - private String licensePath = DEFAULT_LICENSEHEADER; - private String packageName = DEFAULT_PACKAGE_NAME; - private List sourceFilesExtensions = List.of("java", "kotlin", "groovy"); private static final String DEFAULT_APP_NAME = "default"; private static final String HOMEPAGE_URL = "https://micronaut.io"; private static final String LAUNCHER_URL = HOMEPAGE_URL + "/launch"; @@ -26,12 +23,19 @@ public class GuidesConfigurationProperties implements GuidesConfiguration { private static final String DEFAULT_ENV_JDK_VERSION = "JDK_VERSION"; private static final JdkVersion DEFAULT_JAVA_VERSION = JDK_17; private static final List DEFAULT_JDK_VERSIONS_SUPPORTED_BY_GRAALVM = List.of(JDK_17, JDK_21); + private String title = "Micronaut Guides"; + private String homePageUrl = GUIDES_URL; + private String licensePath = DEFAULT_LICENSEHEADER; + private String packageName = DEFAULT_PACKAGE_NAME; + private List sourceFilesExtensions = List.of("java", "kotlin", "groovy"); private String envJdkVersion = DEFAULT_ENV_JDK_VERSION; private JdkVersion defaulJdkVersion = DEFAULT_JAVA_VERSION; private List jdkVersionsSupportedByGraalvm = DEFAULT_JDK_VERSIONS_SUPPORTED_BY_GRAALVM; @Override - public List getJdkVersionsSupportedByGraalvm() { return jdkVersionsSupportedByGraalvm; } + public List getJdkVersionsSupportedByGraalvm() { + return jdkVersionsSupportedByGraalvm; + } public void setJdkVersionsSupportedByGraalvm(List jdkVersionsSupportedByGraalvm) { this.jdkVersionsSupportedByGraalvm = jdkVersionsSupportedByGraalvm; @@ -83,13 +87,19 @@ public String getDefaultAppName() { } @Override - public String getProjectGeneratorUrl() { return LAUNCHER_URL; } + public String getProjectGeneratorUrl() { + return LAUNCHER_URL; + } @Override public List getFilesWithHeader() { return sourceFilesExtensions; } + public void setFilesWithHeader(List sourceFilesExtensions) { + this.sourceFilesExtensions = sourceFilesExtensions; + } + @Override public int getDefaultMinJdk() { return DEFAULT_MIN_JDK; @@ -106,20 +116,20 @@ public String getVersionPath() { } @Override - public String getEnvJdkVersion() { return envJdkVersion; } + public String getEnvJdkVersion() { + return envJdkVersion; + } public void setEnvJdkVersion(String envJdkVersion) { this.envJdkVersion = envJdkVersion; } @Override - public JdkVersion getDefaultJdkVersion() { return defaulJdkVersion; } - - public void setDefaulJdkVersion(JdkVersion jdkVersion) { - this.defaulJdkVersion = jdkVersion; + public JdkVersion getDefaultJdkVersion() { + return defaulJdkVersion; } - public void setFilesWithHeader(List sourceFilesExtensions) { - this.sourceFilesExtensions = sourceFilesExtensions; + public void setDefaulJdkVersion(JdkVersion jdkVersion) { + this.defaulJdkVersion = jdkVersion; } } diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/GuidesOption.java b/buildSrc/src/main/java/io/micronaut/guides/core/GuidesOption.java index 818331a9dfc..fbc4e1dd64d 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/GuidesOption.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/GuidesOption.java @@ -2,9 +2,9 @@ import io.micronaut.core.annotation.Introspected; import io.micronaut.core.annotation.NonNull; +import io.micronaut.starter.api.TestFramework; import io.micronaut.starter.options.BuildTool; import io.micronaut.starter.options.Language; -import io.micronaut.starter.api.TestFramework; @Introspected public class GuidesOption { diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/JsonFeedConfiguration.java b/buildSrc/src/main/java/io/micronaut/guides/core/JsonFeedConfiguration.java index f3b5d1d6029..f6eba4b8e76 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/JsonFeedConfiguration.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/JsonFeedConfiguration.java @@ -2,5 +2,6 @@ public interface JsonFeedConfiguration { String getFeedUrl(); + String getFilename(); } diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/JsonSchemaProvider.java b/buildSrc/src/main/java/io/micronaut/guides/core/JsonSchemaProvider.java index 4c1c5367b34..9b91bffcd5d 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/JsonSchemaProvider.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/JsonSchemaProvider.java @@ -1,13 +1,12 @@ package io.micronaut.guides.core; -import com.networknt.schema.*; +import com.networknt.schema.JsonSchema; import io.micronaut.core.annotation.NonNull; @FunctionalInterface public interface JsonSchemaProvider { /** - * * @return Provides a JSON Schema used to validate guides. */ @NonNull diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/MacroExclusion.java b/buildSrc/src/main/java/io/micronaut/guides/core/MacroExclusion.java index fed76d3c448..5773e58427b 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/MacroExclusion.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/MacroExclusion.java @@ -14,9 +14,9 @@ public String substitute(String str, Guide guide, GuidesOption option) { for (List group : MacroUtils.findMacroGroupsNested(str, getMacroName())) { List params = MacroUtils.extractMacroGroupParameters(group.get(0), getMacroName()); if (shouldExclude(params, option, guide)) { - str = str.replace(String.join(LINE_BREAK, group)+ LINE_BREAK, ""); - } else{ - str = str.replace(String.join(LINE_BREAK, group), String.join(LINE_BREAK, group.subList(1, group.size()-1))); + str = str.replace(String.join(LINE_BREAK, group) + LINE_BREAK, ""); + } else { + str = str.replace(String.join(LINE_BREAK, group), String.join(LINE_BREAK, group.subList(1, group.size() - 1))); } } return str; diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/MacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/MacroSubstitution.java index 4287b1c712a..f6301903cdd 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/MacroSubstitution.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/MacroSubstitution.java @@ -16,7 +16,7 @@ default App app(Guide guide, AsciidocMacro asciidocMacro) { } default App app(Guide guide, String appName) { - return guide.apps().stream() + return guide.apps().stream() .filter(a -> a.name().equals(appName)) .findFirst() .orElseThrow(() -> new RuntimeException("app not found for app name" + appName)); diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/MacroUtils.java b/buildSrc/src/main/java/io/micronaut/guides/core/MacroUtils.java index 3189c2fa551..44463a43ba1 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/MacroUtils.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/MacroUtils.java @@ -1,6 +1,7 @@ package io.micronaut.guides.core; import io.micronaut.core.annotation.NonNull; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -19,13 +20,13 @@ static String getSourceDir(@NonNull String slug, @NonNull GuidesOption option) { static List findMacroLines(@NonNull String str, @NonNull String macro) { return str.lines() - .filter(line -> line.startsWith(macro+":")) + .filter(line -> line.startsWith(macro + ":")) .toList(); } static List findMacroInstances(@NonNull String str, @NonNull String macro) { List matches = new ArrayList<>(); - Pattern pattern = Pattern.compile("@(?:([\\w-]*):)?"+macro+"@"); + Pattern pattern = Pattern.compile("@(?:([\\w-]*):)?" + macro + "@"); Matcher matcher = pattern.matcher(str); while (matcher.find()) { @@ -37,7 +38,7 @@ static List findMacroInstances(@NonNull String str, @NonNull String macr static List findMacroGroups(@NonNull String str, @NonNull String macro) { List matches = new ArrayList<>(); - String pattern = ":"+macro+":"; + String pattern = ":" + macro + ":"; int startIndex = 0; while (true) { @@ -64,20 +65,20 @@ static List extractMacroGroupParameters(@NonNull String line, @NonNull S @NonNull static List> findMacroGroupsNested(@NonNull String str, @NonNull String macro) { List> matches = new ArrayList<>(); - String pattern = ":"+macro+":"; + String pattern = ":" + macro + ":"; List lines = str.lines().toList(); Stack stack = new Stack<>(); - for (int i=0; i < lines.size(); i++) { + for (int i = 0; i < lines.size(); i++) { String line = lines.get(i); if (isGroupStart(line, pattern)) { stack.push(i); } else if (isGroupEnd(line, pattern)) { if (!stack.isEmpty()) { int start = stack.pop(); - matches.add(lines.subList(start, i+1)); - } else{ + matches.add(lines.subList(start, i + 1)); + } else { throw new UnsupportedOperationException("Unbalanced macro group"); } } @@ -87,11 +88,11 @@ static List> findMacroGroupsNested(@NonNull String str, @NonNull St } private static boolean isGroupStart(@NonNull String line, @NonNull String macro) { - return line.matches(macro+"[a-zA-Z0-9,]+"); + return line.matches(macro + "[a-zA-Z0-9,]+"); } private static boolean isGroupEnd(@NonNull String line, @NonNull String macro) { - return line.matches(macro+"(?![a-zA-Z0-9,]+$)"); + return line.matches(macro + "(?![a-zA-Z0-9,]+$)"); } @NonNull diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/PlaceholderMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/PlaceholderMacroSubstitution.java index 7a1f1ba8a3d..3a269195bfa 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/PlaceholderMacroSubstitution.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/PlaceholderMacroSubstitution.java @@ -21,6 +21,7 @@ public PlaceholderMacroSubstitution(GuidesConfiguration guidesConfiguration, Ver this.versionLoader = versionLoader; this.coordinatesProvider = coordinatesProvider; } + @Override public String substitute(String str, Guide guide, GuidesOption option) { @@ -36,12 +37,12 @@ public String substitute(String str, Guide guide, GuidesOption option) { str = str.replace("@languageextension@", option.getLanguage().getExtension()); str = str.replace("@testsuffix@", option.getTestFramework() == SPOCK ? "Spec" : "Test"); str = str.replace("@sourceDir@", MacroUtils.getSourceDir(guide.slug(), option)); - str = str.replace("@minJdk@", String.valueOf( guide.minimumJavaVersion() != null ? guide.minimumJavaVersion() : guidesConfiguration.getDefaultMinJdk()) ); + str = str.replace("@minJdk@", String.valueOf(guide.minimumJavaVersion() != null ? guide.minimumJavaVersion() : guidesConfiguration.getDefaultMinJdk())); str = str.replace("@api@", guidesConfiguration.getApiUrl()); for (Map.Entry entry : coordinatesProvider.getCoordinates().entrySet()) { if (StringUtils.isNotEmpty(entry.getValue().getVersion())) { - str = str.replace("@"+entry.getKey()+"Version@", entry.getValue().getVersion()); + str = str.replace("@" + entry.getKey() + "Version@", entry.getValue().getVersion()); } } diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/PlaceholderWithTargetMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/PlaceholderWithTargetMacroSubstitution.java index 1779700c8f9..3bcc8dfd712 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/PlaceholderWithTargetMacroSubstitution.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/PlaceholderWithTargetMacroSubstitution.java @@ -2,6 +2,7 @@ import io.micronaut.core.util.StringUtils; import io.micronaut.guides.core.asciidoc.PlacheholderMacro; + import java.util.Optional; abstract class PlaceholderWithTargetMacroSubstitution implements MacroSubstitution { diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/RawTestMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/RawTestMacroSubstitution.java index 16ec20e4bd7..7990b82370b 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/RawTestMacroSubstitution.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/RawTestMacroSubstitution.java @@ -16,12 +16,12 @@ public String getMacroName() { } @Override - protected String getLanguage(GuidesOption option){ + protected String getLanguage(GuidesOption option) { return option.getTestFramework().toTestFramework().getDefaultLanguage().toString(); } @Override - protected String getExtension(GuidesOption option){ + protected String getExtension(GuidesOption option) { return option.getTestFramework().toTestFramework().getDefaultLanguage().getExtension(); } diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/ResourceMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/ResourceMacroSubstitution.java index 3c543d82781..0162110496c 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/ResourceMacroSubstitution.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/ResourceMacroSubstitution.java @@ -4,8 +4,9 @@ import jakarta.inject.Singleton; @Singleton -public class ResourceMacroSubstitution extends SourceBlockMacroSubstitution{ +public class ResourceMacroSubstitution extends SourceBlockMacroSubstitution { private static final String MACRO_RESOURCE = "resource"; + public ResourceMacroSubstitution(GuidesConfiguration guidesConfiguration, LicenseLoader licenseLoader) { super(licenseLoader, guidesConfiguration); } diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/SourceBlockMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/SourceBlockMacroSubstitution.java index 916b2a05926..720b968ace6 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/SourceBlockMacroSubstitution.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/SourceBlockMacroSubstitution.java @@ -4,7 +4,6 @@ import org.jetbrains.annotations.NotNull; import java.nio.file.Path; -import java.util.List; import java.util.Optional; import static io.micronaut.guides.core.MacroUtils.*; @@ -14,7 +13,7 @@ abstract class SourceBlockMacroSubstitution implements MacroSubstitution { private final LicenseLoader licenseLoader; private final GuidesConfiguration guidesConfiguration; - + SourceBlockMacroSubstitution(LicenseLoader licenseLoader, GuidesConfiguration guidesConfiguration) { this.licenseLoader = licenseLoader; @@ -58,14 +57,14 @@ public String substitute(String str, Guide guide, GuidesOption option) { String extension = getExtension(option); if (arr.length == 2) { - language = arr[arr.length-1]; + language = arr[arr.length - 1]; language = resolveAsciidoctorLanguage(language); } else { condensedTarget = condensedTarget + "." + extension; } String target = sourceInclude(slug, appName, condensedTarget, getClasspath(), option, language, getGuidesConfiguration().getPackageName()); - String title = Path.of(target).normalize().toString().replace("{sourceDir}/"+slug+"/", "").replace(getSourceDir(slug, option)+"/", ""); + String title = Path.of(target).normalize().toString().replace("{sourceDir}/" + slug + "/", "").replace(getSourceDir(slug, option) + "/", ""); IncludeDirective.Builder includeDirectiveBuilder = IncludeDirective.builder().attributes(asciidocMacro.attributes()) .target(target); @@ -87,11 +86,11 @@ public String substitute(String str, Guide guide, GuidesOption option) { return str; } - protected String getLanguage(GuidesOption option){ + protected String getLanguage(GuidesOption option) { return option.getLanguage().toString(); } - protected String getExtension(GuidesOption option){ + protected String getExtension(GuidesOption option) { return option.getLanguage().getExtension(); } @@ -114,7 +113,7 @@ protected String sourceInclude( GuidesOption option, String language, String packageName) { - return "{sourceDir}/" + slug + "/" + getSourceDir(slug,option) + "/" + + return "{sourceDir}/" + slug + "/" + getSourceDir(slug, option) + "/" + sourceTitle(appName, condensedTarget, classpath, language, packageName); } diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/SourceMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/SourceMacroSubstitution.java index 002e38cf541..8f68f4b68d2 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/SourceMacroSubstitution.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/SourceMacroSubstitution.java @@ -1,10 +1,10 @@ package io.micronaut.guides.core; -import io.micronaut.guides.core.asciidoc.*; +import io.micronaut.guides.core.asciidoc.Classpath; import jakarta.inject.Singleton; @Singleton -public class SourceMacroSubstitution extends SourceBlockMacroSubstitution{ +public class SourceMacroSubstitution extends SourceBlockMacroSubstitution { private static final String MACRO_SOURCE = "source"; public SourceMacroSubstitution(GuidesConfiguration guidesConfiguration, LicenseLoader licenseLoader) { diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/TestMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/TestMacroSubstitution.java index 1f28f51260f..7c6ba0c9220 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/TestMacroSubstitution.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/TestMacroSubstitution.java @@ -8,10 +8,11 @@ import static io.micronaut.starter.api.TestFramework.SPOCK; @Singleton -public class TestMacroSubstitution extends SourceBlockMacroSubstitution { +public class TestMacroSubstitution extends SourceBlockMacroSubstitution { + public static final String SUFFIX_SPEC = "Spec"; private static final String MACRO_TEST = "test"; private static final String SUFFIX_TEST = "Test"; - public static final String SUFFIX_SPEC = "Spec"; + public TestMacroSubstitution(GuidesConfiguration guidesConfiguration, LicenseLoader licenseLoader) { super(licenseLoader, guidesConfiguration); } diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/TestResourceMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/TestResourceMacroSubstitution.java index 8feca16ba93..84523102d17 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/TestResourceMacroSubstitution.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/TestResourceMacroSubstitution.java @@ -6,6 +6,7 @@ @Singleton public class TestResourceMacroSubstitution extends SourceBlockMacroSubstitution { private static final String MACRO_TESTRESOURCE = "testResource"; + public TestResourceMacroSubstitution(GuidesConfiguration guidesConfiguration, LicenseLoader licenseLoader) { super(licenseLoader, guidesConfiguration); } diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/ZipIncludeMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/ZipIncludeMacroSubstitution.java index ec243a4bd37..f73bd5505d7 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/ZipIncludeMacroSubstitution.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/ZipIncludeMacroSubstitution.java @@ -6,18 +6,25 @@ @Singleton public class ZipIncludeMacroSubstitution extends SourceBlockMacroSubstitution { private static final String MACRO_ZIPINCLUDE = "zipInclude"; + public ZipIncludeMacroSubstitution(GuidesConfiguration guidesConfiguration, LicenseLoader licenseLoader) { super(licenseLoader, guidesConfiguration); } @Override - public String getMacroName() { return MACRO_ZIPINCLUDE; } + public String getMacroName() { + return MACRO_ZIPINCLUDE; + } @Override - protected Classpath getClasspath() { return Classpath.MAIN; } + protected Classpath getClasspath() { + return Classpath.MAIN; + } @Override - protected FileType getFileType() { return FileType.RESOURCE; } + protected FileType getFileType() { + return FileType.RESOURCE; + } @Override protected String sourceTitle( diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/Attribute.java b/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/Attribute.java index 4905e66aa06..f091885fa1b 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/Attribute.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/Attribute.java @@ -13,7 +13,7 @@ public record Attribute(String key, List values) { @NonNull public static List of(@NonNull String str) { List result = new ArrayList<>(); - String arr[] = str.split(ATTRIBUTE_SEPARATOR); + String[] arr = str.split(ATTRIBUTE_SEPARATOR); for (String attributeString : arr) { String[] attributeComponents = attributeString.split(KEY_VALUE_SEPARATOR); if (attributeComponents.length == 2) { diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/IncludeDirective.java b/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/IncludeDirective.java index eea86476243..91a0d21d523 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/IncludeDirective.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/IncludeDirective.java @@ -74,12 +74,12 @@ public class IncludeDirective { private final String opts; IncludeDirective(@NonNull String target, - @Nullable String levelOffset, - @Nullable Range lines, - @Nullable String encoding, - @Nullable List tags, - @Nullable Integer indent, - @Nullable String opts) { + @Nullable String levelOffset, + @Nullable Range lines, + @Nullable String encoding, + @Nullable List tags, + @Nullable Integer indent, + @Nullable String opts) { this.target = target; this.levelOffset = levelOffset; this.lines = lines; @@ -89,8 +89,11 @@ public class IncludeDirective { this.opts = opts; } + public static Builder builder() { + return new Builder(); + } + /** - * * @return Target may be an absolute path, a path relative to the current document, or a URL. */ @NonNull @@ -106,7 +109,6 @@ public String getTarget() { } /** - * * @return ranges of line numbers. */ @Nullable @@ -161,7 +163,7 @@ private List attributes() { } if (CollectionUtils.isNotEmpty(getTags())) { if (getTags().size() > 1) { - attributes.add(ATTRIBUTE_TAGS + "=" + String.join(";", getTags())); + attributes.add(ATTRIBUTE_TAGS + "=" + String.join(";", getTags())); } else if (getTags().size() == 1) { attributes.add(ATTRIBUTE_TAG + "=" + getTags().get(0)); } @@ -175,10 +177,6 @@ private List attributes() { return attributes; } - public static Builder builder() { - return new Builder(); - } - public static class Builder { @NonNull private String target; @@ -237,7 +235,7 @@ public Builder opts(@Nullable String opts) { } public Builder levelOffset(int levelOffset) { - return levelOffset("+" + levelOffset); + return levelOffset("+" + levelOffset); } public Builder tag(String tag) { diff --git a/buildSrc/src/test/java/io/micronaut/guides/core/FilesTransferUtilityTest.java b/buildSrc/src/test/java/io/micronaut/guides/core/FilesTransferUtilityTest.java new file mode 100644 index 00000000000..ec0d3f65d13 --- /dev/null +++ b/buildSrc/src/test/java/io/micronaut/guides/core/FilesTransferUtilityTest.java @@ -0,0 +1,80 @@ +package io.micronaut.guides.core; + +import io.micronaut.json.JsonMapper; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@MicronautTest(startApplication = false) +public class FilesTransferUtilityTest { + + @Inject + FilesTransferUtility filesTransferUtility; + + @Inject + JsonMapper jsonMapper; + + @Inject + JsonSchemaProvider jsonSchemaProvider; + + + @Inject + GuideProjectGenerator guideProjectGenerator; + + @Test + void testTransfer() throws Exception { + String outputPath = "build/tmp/test"; + File outputDirectory = new File(outputPath); + outputDirectory.mkdir(); + List metadatas = new ArrayList<>(); + + String pathBase = "src/test/resources/guides/hello-base"; + File fileBase = new File(pathBase); + GuideUtils.parseGuideMetadata(fileBase, "metadata.json", jsonSchemaProvider.getSchema(), jsonMapper).ifPresent(metadatas::add); + String path = "src/test/resources/guides/creating-your-first-micronaut-app"; + File file = new File(path); + GuideUtils.parseGuideMetadata(file, "metadata.json", jsonSchemaProvider.getSchema(), jsonMapper).ifPresent(metadatas::add); + + guideProjectGenerator.generate(outputDirectory, metadatas.get(0)); + guideProjectGenerator.generate(outputDirectory, metadatas.get(1)); + + filesTransferUtility.transferFiles(fileBase, outputDirectory, metadatas.get(0)); + filesTransferUtility.transferFiles(file, outputDirectory, metadatas.get(1)); + + assertTrue(new File(outputPath + "/creating-your-first-micronaut-app-gradle-groovy").exists()); + assertTrue(new File(outputPath + "/creating-your-first-micronaut-app-gradle-java").exists()); + assertTrue(new File(outputPath + "/creating-your-first-micronaut-app-gradle-kotlin").exists()); + assertTrue(new File(outputPath + "/creating-your-first-micronaut-app-maven-groovy").exists()); + assertTrue(new File(outputPath + "/creating-your-first-micronaut-app-maven-java").exists()); + assertTrue(new File(outputPath + "/creating-your-first-micronaut-app-maven-kotlin").exists()); + + assertFalse(new File(outputPath + "/hello-base-gradle-groovy").exists()); + assertFalse(new File(outputPath + "/hello-base-gradle-java").exists()); + assertFalse(new File(outputPath + "/hello-base-gradle-kotlin").exists()); + assertFalse(new File(outputPath + "/hello-base-maven-groovy").exists()); + assertFalse(new File(outputPath + "/hello-base-maven-java").exists()); + assertFalse(new File(outputPath + "/hello-base-maven-kotlin").exists()); + + assertTrue(new File(outputPath + "/creating-your-first-micronaut-app-gradle-groovy/src/main/groovy/example/micronaut/HelloController.groovy").exists()); + assertTrue(new File(outputPath + "/creating-your-first-micronaut-app-gradle-java/src/main/java/example/micronaut/HelloController.java").exists()); + assertTrue(new File(outputPath + "/creating-your-first-micronaut-app-gradle-kotlin/src/main/kotlin/example/micronaut/HelloController.kt").exists()); + assertTrue(new File(outputPath + "/creating-your-first-micronaut-app-maven-groovy/src/main/groovy/example/micronaut/HelloController.groovy").exists()); + assertTrue(new File(outputPath + "/creating-your-first-micronaut-app-maven-java/src/main/java/example/micronaut/HelloController.java").exists()); + assertTrue(new File(outputPath + "/creating-your-first-micronaut-app-maven-kotlin/src/main/kotlin/example/micronaut/HelloController.kt").exists()); + + assertFalse(new File(outputPath + "/creating-your-first-micronaut-app-gradle-groovy/src/main/groovy/example/micronaut/Application.groovy").exists()); + assertFalse(new File(outputPath + "/creating-your-first-micronaut-app-gradle-java/src/main/java/example/micronaut/Application.java").exists()); + assertFalse(new File(outputPath + "/creating-your-first-micronaut-app-gradle-kotlin/src/main/kotlin/example/micronaut/Application.kt").exists()); + assertFalse(new File(outputPath + "/creating-your-first-micronaut-app-maven-groovy/src/main/groovy/example/micronaut/Application.groovy").exists()); + assertFalse(new File(outputPath + "/creating-your-first-micronaut-app-maven-java/src/main/java/example/micronaut/Application.java").exists()); + assertFalse(new File(outputPath + "/creating-your-first-micronaut-app-maven-kotlin/src/main/kotlin/example/micronaut/Application.kt").exists()); + } + +} diff --git a/buildSrc/src/test/java/io/micronaut/guides/core/GuideParserTest.java b/buildSrc/src/test/java/io/micronaut/guides/core/GuideParserTest.java index 82678016683..e4481630233 100644 --- a/buildSrc/src/test/java/io/micronaut/guides/core/GuideParserTest.java +++ b/buildSrc/src/test/java/io/micronaut/guides/core/GuideParserTest.java @@ -27,7 +27,7 @@ void testParseGuidesMetadata() { List metadatas = guideParser.parseGuidesMetadata(file,"metadata.json"); - assertEquals(3,metadatas.size()); + assertEquals(5,metadatas.size()); Guide guide = metadatas.get(1); assertEquals(List.of("Graeme Rocher"), guide.authors()); @@ -61,7 +61,7 @@ void testParseGuidesMetadata() { app.excludeSource() == null && app.validateLicense())); - guide = metadatas.get(2); + guide = metadatas.get(4); assertEquals(List.of("Sergio del Amo"), guide.authors()); assertEquals("1. Testing Serialization - Spring Boot vs Micronaut Framework - Building a Rest API", guide.title()); assertEquals("This guide compares how to test serialization and deserialization with Micronaut Framework and Spring Boot.", guide.intro()); diff --git a/buildSrc/src/test/java/io/micronaut/guides/core/GuideProjectGeneratorTest.java b/buildSrc/src/test/java/io/micronaut/guides/core/GuideProjectGeneratorTest.java index eb1fa0c3d78..94bd79b7f56 100644 --- a/buildSrc/src/test/java/io/micronaut/guides/core/GuideProjectGeneratorTest.java +++ b/buildSrc/src/test/java/io/micronaut/guides/core/GuideProjectGeneratorTest.java @@ -10,7 +10,10 @@ import org.gradle.api.JavaVersion; import org.junit.jupiter.api.Test; -import java.io.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; import java.nio.file.Paths; import java.time.LocalDate; import java.util.List; @@ -41,7 +44,7 @@ void testGenerate() { "example.micronaut", ApplicationType.CLI, "Micronaut", - List.of("yaml","mqtt"), + List.of("yaml", "mqtt"), List.of(), List.of(), List.of(), @@ -56,7 +59,7 @@ void testGenerate() { "This guide compares how to test serialization and deserialization with Micronaut Framework and Spring Boot.", List.of("Sergio del Amo"), List.of("Boot to Micronaut Building a REST API"), - LocalDate.of(2024,4,24), + LocalDate.of(2024, 4, 24), null, null, null, @@ -138,12 +141,12 @@ void testGenerateMultipleApps() throws Exception { String path = "src/test/resources/guides"; File file = new File(path); - List metadatas = GuideUtils.parseGuidesMetadata(file,"metadata.json", jsonSchemaProvider.getSchema(), jsonMapper); - Guide guide = metadatas.get(2); + List metadatas = GuideUtils.parseGuidesMetadata(file, "metadata.json", jsonSchemaProvider.getSchema(), jsonMapper); + Guide guide = metadatas.get(4); assertDoesNotThrow(() -> guideProjectGenerator.generate(outputDirectory, guide)); - for (App app: guide.apps()) { + for (App app : guide.apps()) { File dest = Paths.get(outputDirectory.getAbsolutePath(), MacroUtils.getSourceDir(guide.slug(), new GuidesOption(BuildTool.GRADLE, Language.JAVA, TestFramework.JUNIT)), app.name()).toFile(); assertTrue(new File(dest, "build.gradle").exists()); assertTrue(new File(dest, "gradlew.bat").exists()); @@ -155,13 +158,13 @@ void testGenerateMultipleApps() throws Exception { File buildGradleFile = new File(dest, "build.gradle"); String result = readFile(buildGradleFile); - for(String feature: app.features()) { + for (String feature : app.features()) { assertTrue(result.contains(feature)); } } } - private String readFile(File file){ + private String readFile(File file) { try (BufferedReader reader = new BufferedReader(new FileReader(file))) { return reader.lines().collect(Collectors.joining("\n")); } catch (IOException e) { diff --git a/buildSrc/src/test/java/io/micronaut/guides/core/JsonFeedGeneratorTest.java b/buildSrc/src/test/java/io/micronaut/guides/core/JsonFeedGeneratorTest.java index 47cc2f54960..18947e09fde 100644 --- a/buildSrc/src/test/java/io/micronaut/guides/core/JsonFeedGeneratorTest.java +++ b/buildSrc/src/test/java/io/micronaut/guides/core/JsonFeedGeneratorTest.java @@ -21,16 +21,16 @@ public class JsonFeedGeneratorTest { @Inject JsonSchemaProvider jsonSchemaProvider; - private List guides; - @Inject JsonFeedGenerator jsonFeedGenerator; + private List guides; + @BeforeEach public void setup() { File file = new File("src/test/resources/guides"); GuideParser guideParser = new DefaultGuideParser(jsonSchemaProvider, jsonMapper); - this.guides = guideParser.parseGuidesMetadata(file,"metadata.json") + this.guides = guideParser.parseGuidesMetadata(file, "metadata.json") .stream().filter(Guide::publish).toList(); } @@ -55,6 +55,21 @@ public void testJsonFeed() throws IOException, JSONException { } ], "tags" : [ "cloud", "database", "Azure", "flyway", "jdbc", "mysql", "micronaut-data", "data-jdbc" ], "language" : "LANG_ENGLISH" + }, { + "id" : "creating-your-first-micronaut-app", + "url" : "https://guides.micronaut.io/latest/creating-your-first-micronaut-app", + "title" : "Creating your first Micronaut application", + "content_text" : "Learn how to create a Hello World Micronaut application with a controller and a functional test.", + "date_published" : "2018-05-23T00:00:00Z", + "authors" : [ { + "name" : "Iván López", + "empty" : false + }, { + "name" : "Sergio del Amo", + "empty" : false + } ], + "tags" : [ "junit", "getting-started", "graalvm" ], + "language" : "LANG_ENGLISH" }, { "id" : "test", "url" : "https://guides.micronaut.io/latest/test", diff --git a/buildSrc/src/test/java/io/micronaut/guides/core/RssFeedGenerationTest.java b/buildSrc/src/test/java/io/micronaut/guides/core/RssFeedGenerationTest.java index e19857a9b91..d84cf217c39 100644 --- a/buildSrc/src/test/java/io/micronaut/guides/core/RssFeedGenerationTest.java +++ b/buildSrc/src/test/java/io/micronaut/guides/core/RssFeedGenerationTest.java @@ -35,7 +35,7 @@ public void setup() { @Test void testRssFeed() { String feed = rssFeedGenerator.rssFeed(guides); - String expected = "Micronaut Guideshttps://guides.micronaut.io/latest/RSS feed for Micronaut GuidesenConnect a Micronaut Data JDBC Application to Azure Database for MySQLhttps://guides.micronaut.io/latest/childLearn how to connect a Micronaut Data JDBC application to a Microsoft Azure Database for MySQLGraeme RocherclouddatabaseAzureflywayjdbcmysqlmicronaut-datadata-jdbcchildThu, 17 Feb 2022 00:00:00 Z1. Testing Serialization - Spring Boot vs Micronaut Framework - Building a Rest APIhttps://guides.micronaut.io/latest/testThis guide compares how to test serialization and deserialization with Micronaut Framework and Spring Boot.Sergio del Amospring-boot-starter-webjackson-databindspring-bootassertjboot-to-micronaut-building-a-rest-apijson-pathtestWed, 24 Apr 2024 00:00:00 Z"; + String expected = "Micronaut Guideshttps://guides.micronaut.io/latest/RSS feed for Micronaut GuidesenConnect a Micronaut Data JDBC Application to Azure Database for MySQLhttps://guides.micronaut.io/latest/childLearn how to connect a Micronaut Data JDBC application to a Microsoft Azure Database for MySQLGraeme RocherclouddatabaseAzureflywayjdbcmysqlmicronaut-datadata-jdbcchildThu, 17 Feb 2022 00:00:00 ZCreating your first Micronaut applicationhttps://guides.micronaut.io/latest/creating-your-first-micronaut-appLearn how to create a Hello World Micronaut application with a controller and a functional test.Sergio del Amojunitgetting-startedgraalvmcreating-your-first-micronaut-appWed, 23 May 2018 00:00:00 Z1. Testing Serialization - Spring Boot vs Micronaut Framework - Building a Rest APIhttps://guides.micronaut.io/latest/testThis guide compares how to test serialization and deserialization with Micronaut Framework and Spring Boot.Sergio del Amospring-boot-starter-webjackson-databindspring-bootassertjboot-to-micronaut-building-a-rest-apijson-pathtestWed, 24 Apr 2024 00:00:00 Z"; assertEquals(expected, feed); } } diff --git a/buildSrc/src/test/resources/guides/creating-your-first-micronaut-app/creating-your-first-micronaut-app.adoc b/buildSrc/src/test/resources/guides/creating-your-first-micronaut-app/creating-your-first-micronaut-app.adoc new file mode 100644 index 00000000000..aaeae9693da --- /dev/null +++ b/buildSrc/src/test/resources/guides/creating-your-first-micronaut-app/creating-your-first-micronaut-app.adoc @@ -0,0 +1,45 @@ +common:header.adoc[] + +common:requirements.adoc[] + +common:completesolution.adoc[] + +common:create-app.adoc[] + +=== Application + +`Application.@languageextension@` is used when running the application via Gradle or via deployment. You can also run the main class directly within your IDE if it is configured correctly. + +source:Application[] + +external:hello-base/hellocontroller.adoc[] + +external:hello-base/hellotest.adoc[] + +common:testApp.adoc[] + +common:runapp.adoc[] + +common:graal-with-plugins.adoc[] + +:exclude-for-languages:groovy + +You can execute the endpoint exposed by the native executable: + +[source, bash] +---- +curl localhost:8080/hello +---- + +[source] +---- +Hello World +---- + +:exclude-for-languages: + +== Next steps + +Read more about https://micronaut-projects.github.io/micronaut-test/latest/guide/[Micronaut testing]. + +common:helpWithMicronaut.adoc[] diff --git a/buildSrc/src/test/resources/guides/creating-your-first-micronaut-app/metadata.json b/buildSrc/src/test/resources/guides/creating-your-first-micronaut-app/metadata.json new file mode 100644 index 00000000000..8272c3b3aa9 --- /dev/null +++ b/buildSrc/src/test/resources/guides/creating-your-first-micronaut-app/metadata.json @@ -0,0 +1,17 @@ +{ + "title": "Creating your first Micronaut application", + "base": "hello-base", + "intro": "Learn how to create a Hello World Micronaut application with a controller and a functional test.", + "authors": ["Iván López", "Sergio del Amo"], + "tags": ["junit"], + "categories": ["Getting Started"], + "publicationDate": "2018-05-23", + "apps": [ + { + "name": "default", + "javaFeatures": ["graalvm"], + "kotlinFeatures": ["graalvm"], + "excludeSource": ["Application"] + } + ] +} diff --git a/buildSrc/src/test/resources/guides/hello-base/groovy/src/main/groovy/example/micronaut/HelloController.groovy b/buildSrc/src/test/resources/guides/hello-base/groovy/src/main/groovy/example/micronaut/HelloController.groovy new file mode 100644 index 00000000000..4083cbea47d --- /dev/null +++ b/buildSrc/src/test/resources/guides/hello-base/groovy/src/main/groovy/example/micronaut/HelloController.groovy @@ -0,0 +1,32 @@ +/* + * Copyright 2017-2024 original 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 + * + * https://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 example.micronaut + +import groovy.transform.CompileStatic +import io.micronaut.http.annotation.Controller +import io.micronaut.http.annotation.Get +import io.micronaut.http.annotation.Produces +import io.micronaut.http.MediaType + +@CompileStatic +@Controller("/hello") // <1> +class HelloController { + @Get // <2> + @Produces(MediaType.TEXT_PLAIN) // <3> + String index() { + "Hello World" // <4> + } +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/guides/hello-base/groovy/src/test/groovy/example/micronaut/HelloControllerSpec.groovy b/buildSrc/src/test/resources/guides/hello-base/groovy/src/test/groovy/example/micronaut/HelloControllerSpec.groovy new file mode 100644 index 00000000000..a0fc3ac926c --- /dev/null +++ b/buildSrc/src/test/resources/guides/hello-base/groovy/src/test/groovy/example/micronaut/HelloControllerSpec.groovy @@ -0,0 +1,41 @@ +/* + * Copyright 2017-2024 original 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 + * + * https://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 example.micronaut + +import io.micronaut.http.HttpRequest +import io.micronaut.http.client.HttpClient +import io.micronaut.http.client.annotation.Client +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import spock.lang.Specification + +import jakarta.inject.Inject + +@MicronautTest // <1> +class HelloControllerSpec extends Specification { + + @Inject + @Client("/") // <2> + HttpClient client + + void "test hello world response"() { + when: + HttpRequest request = HttpRequest.GET('/hello') // <3> + String rsp = client.toBlocking().retrieve(request) + + then: + rsp == "Hello World" + } +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/guides/hello-base/hellocontroller.adoc b/buildSrc/src/test/resources/guides/hello-base/hellocontroller.adoc new file mode 100644 index 00000000000..d2994dc4fb7 --- /dev/null +++ b/buildSrc/src/test/resources/guides/hello-base/hellocontroller.adoc @@ -0,0 +1,12 @@ +=== Controller + +In order to create a microservice that responds with "Hello World" you first need a controller. + +Create a Controller: + +source:HelloController[] + +callout:controller[number=1,arg0=/hello] +callout:get[number=2,arg0=index,arg1=/hello] +callout:text-plain[3] +<4> A String "Hello World" is returned as the result \ No newline at end of file diff --git a/buildSrc/src/test/resources/guides/hello-base/hellotest.adoc b/buildSrc/src/test/resources/guides/hello-base/hellotest.adoc new file mode 100644 index 00000000000..8fee8404a06 --- /dev/null +++ b/buildSrc/src/test/resources/guides/hello-base/hellotest.adoc @@ -0,0 +1,9 @@ +=== Test + +Create a test to verify that when you make a GET request to `/hello` you get `Hello World` as a response: + +test:HelloControllerTest[] + +callout:micronaut-test[1] +callout:http-client[2] +callout:http-request[3] \ No newline at end of file diff --git a/buildSrc/src/test/resources/guides/hello-base/java/src/main/java/example/micronaut/HelloController.java b/buildSrc/src/test/resources/guides/hello-base/java/src/main/java/example/micronaut/HelloController.java new file mode 100644 index 00000000000..c6a5d8cb824 --- /dev/null +++ b/buildSrc/src/test/resources/guides/hello-base/java/src/main/java/example/micronaut/HelloController.java @@ -0,0 +1,30 @@ +/* + * Copyright 2017-2024 original 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 + * + * https://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 example.micronaut; + +import io.micronaut.http.MediaType; +import io.micronaut.http.annotation.Controller; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.Produces; + +@Controller("/hello") // <1> +public class HelloController { + @Get // <2> + @Produces(MediaType.TEXT_PLAIN) // <3> + public String index() { + return "Hello World"; // <4> + } +} diff --git a/buildSrc/src/test/resources/guides/hello-base/java/src/test/java/example/micronaut/HelloControllerTest.java b/buildSrc/src/test/resources/guides/hello-base/java/src/test/java/example/micronaut/HelloControllerTest.java new file mode 100644 index 00000000000..486c8406edf --- /dev/null +++ b/buildSrc/src/test/resources/guides/hello-base/java/src/test/java/example/micronaut/HelloControllerTest.java @@ -0,0 +1,45 @@ +/* + * Copyright 2017-2024 original 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 + * + * https://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 example.micronaut; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import io.micronaut.http.HttpRequest; +import io.micronaut.http.MediaType; +import io.micronaut.http.client.HttpClient; +import io.micronaut.http.client.annotation.Client; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import org.junit.jupiter.api.Test; + +import jakarta.inject.Inject; + +@MicronautTest // <1> +public class HelloControllerTest { + + @Inject + @Client("/") // <2> + HttpClient client; + + @Test + public void testHello() { + HttpRequest request = HttpRequest.GET("/hello").accept(MediaType.TEXT_PLAIN); // <3> + String body = client.toBlocking().retrieve(request); + + assertNotNull(body); + assertEquals("Hello World", body); + } +} diff --git a/buildSrc/src/test/resources/guides/hello-base/kotlin/src/main/kotlin/example/micronaut/HelloController.kt b/buildSrc/src/test/resources/guides/hello-base/kotlin/src/main/kotlin/example/micronaut/HelloController.kt new file mode 100644 index 00000000000..fb726e2dcc1 --- /dev/null +++ b/buildSrc/src/test/resources/guides/hello-base/kotlin/src/main/kotlin/example/micronaut/HelloController.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2017-2024 original 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 + * + * https://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 example.micronaut + +import io.micronaut.http.MediaType +import io.micronaut.http.annotation.Controller +import io.micronaut.http.annotation.Get +import io.micronaut.http.annotation.Produces + +@Controller("/hello") // <1> +class HelloController { + + @Get// <2> + @Produces(MediaType.TEXT_PLAIN) // <3> + fun index() = "Hello World" +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/guides/hello-base/kotlin/src/test/kotlin/example/micronaut/HelloControllerTest.kt b/buildSrc/src/test/resources/guides/hello-base/kotlin/src/test/kotlin/example/micronaut/HelloControllerTest.kt new file mode 100644 index 00000000000..aceb5aab65a --- /dev/null +++ b/buildSrc/src/test/resources/guides/hello-base/kotlin/src/test/kotlin/example/micronaut/HelloControllerTest.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2017-2024 original 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 + * + * https://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 example.micronaut + +import io.micronaut.http.HttpRequest +import io.micronaut.http.client.HttpClient +import io.micronaut.http.client.annotation.Client +import io.micronaut.test.extensions.junit5.annotation.MicronautTest +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNotNull +import org.junit.jupiter.api.Test +import jakarta.inject.Inject + +@MicronautTest // <1> +class HelloControllerTest(@Client("/") val client: HttpClient) { // <2> + + @Test + fun testHello() { + val request: HttpRequest = HttpRequest.GET("/hello") // <3> + val body = client.toBlocking().retrieve(request) + assertNotNull(body) + assertEquals("Hello World", body) + } +} diff --git a/buildSrc/src/test/resources/guides/hello-base/metadata.json b/buildSrc/src/test/resources/guides/hello-base/metadata.json new file mode 100644 index 00000000000..c93676f04d8 --- /dev/null +++ b/buildSrc/src/test/resources/guides/hello-base/metadata.json @@ -0,0 +1,3 @@ +{ + "publish": false +} \ No newline at end of file