From 6ee347c19362ed3aea05490ccf2fd31bbe787d76 Mon Sep 17 00:00:00 2001 From: Andrea La Grotteria Date: Mon, 18 Nov 2024 16:03:55 +0100 Subject: [PATCH] Add asciidoc converter to core (#1555) --- buildSrc/build.gradle | 1 + .../guides/core/CalloutMacroSubstitution.java | 21 + .../guides/core/CommonMacroSubstitution.java | 22 + .../core/ExternalMacroSubstitution.java | 22 + .../ExternalTemplateMacroSubstitution.java | 21 + .../core/GuideLinkMacroSubstitution.java | 34 + .../guides/core/LineMacroSubstitution.java | 45 + .../io/micronaut/guides/core/MacroUtils.java | 3 +- ...laceholderWithTargetMacroSubstitution.java | 4 +- .../guides/core/asciidoc/Argument.java | 30 + .../core/asciidoc/AsciidocConfiguration.java | 41 + .../AsciidocConfigurationProperties.java | 199 +++ .../core/asciidoc/AsciidocConverter.java | 15 + .../asciidoc/DefaultAsciidocConverter.java | 52 + .../core/CalloutMacroSubstitutionTest.java | 25 + .../core/CommonMacroSubstitutionTest.java | 22 + .../core/ExternalMacroSubstitutionTest.java | 22 + ...ExternalTemplateMacroSubstitutionTest.java | 23 + .../core/GuideLinkMacroSubstitutionTest.java | 22 + .../micronaut/guides/core/MacroUtilsTest.java | 82 +- .../core/asciidoc/AsciidocConverterTest.java | 207 ++++ .../adding-commit-info-expected.html | 668 ++++++++++ ...ding-commit-info-gradle-java-expected.html | 1081 +++++++++++++++++ .../adding-commit-info-gradle-java.adoc | 334 +++++ .../src/test/resources/application-test.yml | 5 + .../src/test/resources/asciidoc/callout.adoc | 1 + .../asciidoc/common-docker-mysql-arm.adoc | 1 + .../resources/asciidoc/common-header-top.adoc | 9 + .../asciidoc/common-run-mysql-container.adoc | 14 + .../resources/asciidoc/export-repository.adoc | 6 + .../adding-commit-info.adoc | 50 + .../groovy/src/main/resources/application.yml | 11 + .../groovy/example/micronaut/InfoSpec.groovy | 57 + .../java/example/micronaut/Application.java | 27 + .../native-image/resource-config.json | 5 + .../java/src/main/resources/application.yml | 11 + .../test/java/example/micronaut/InfoTest.java | 56 + .../kotlin/example/micronaut/Application.kt | 33 + .../native-image/resource-config.json | 5 + .../kotlin/src/main/resources/application.yml | 11 + .../test/kotlin/example/micronaut/InfoTest.kt | 42 + .../adding-commit-info/metadata.json | 14 + .../resources/other-guides/test/test.adoc | 1 + 43 files changed, 3314 insertions(+), 41 deletions(-) create mode 100644 buildSrc/src/main/java/io/micronaut/guides/core/CalloutMacroSubstitution.java create mode 100644 buildSrc/src/main/java/io/micronaut/guides/core/CommonMacroSubstitution.java create mode 100644 buildSrc/src/main/java/io/micronaut/guides/core/ExternalMacroSubstitution.java create mode 100644 buildSrc/src/main/java/io/micronaut/guides/core/ExternalTemplateMacroSubstitution.java create mode 100644 buildSrc/src/main/java/io/micronaut/guides/core/GuideLinkMacroSubstitution.java create mode 100644 buildSrc/src/main/java/io/micronaut/guides/core/LineMacroSubstitution.java create mode 100644 buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/Argument.java create mode 100644 buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/AsciidocConfiguration.java create mode 100644 buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/AsciidocConfigurationProperties.java create mode 100644 buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/AsciidocConverter.java create mode 100644 buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/DefaultAsciidocConverter.java create mode 100644 buildSrc/src/test/java/io/micronaut/guides/core/CalloutMacroSubstitutionTest.java create mode 100644 buildSrc/src/test/java/io/micronaut/guides/core/CommonMacroSubstitutionTest.java create mode 100644 buildSrc/src/test/java/io/micronaut/guides/core/ExternalMacroSubstitutionTest.java create mode 100644 buildSrc/src/test/java/io/micronaut/guides/core/ExternalTemplateMacroSubstitutionTest.java create mode 100644 buildSrc/src/test/java/io/micronaut/guides/core/GuideLinkMacroSubstitutionTest.java create mode 100644 buildSrc/src/test/java/io/micronaut/guides/core/asciidoc/AsciidocConverterTest.java create mode 100644 buildSrc/src/test/resources/adding-commit-info-expected.html create mode 100644 buildSrc/src/test/resources/adding-commit-info-gradle-java-expected.html create mode 100644 buildSrc/src/test/resources/adding-commit-info-gradle-java.adoc create mode 100644 buildSrc/src/test/resources/application-test.yml create mode 100644 buildSrc/src/test/resources/asciidoc/callout.adoc create mode 100644 buildSrc/src/test/resources/asciidoc/common-docker-mysql-arm.adoc create mode 100644 buildSrc/src/test/resources/asciidoc/common-header-top.adoc create mode 100644 buildSrc/src/test/resources/asciidoc/common-run-mysql-container.adoc create mode 100644 buildSrc/src/test/resources/asciidoc/export-repository.adoc create mode 100644 buildSrc/src/test/resources/other-guides/adding-commit-info/adding-commit-info.adoc create mode 100644 buildSrc/src/test/resources/other-guides/adding-commit-info/groovy/src/main/resources/application.yml create mode 100644 buildSrc/src/test/resources/other-guides/adding-commit-info/groovy/src/test/groovy/example/micronaut/InfoSpec.groovy create mode 100644 buildSrc/src/test/resources/other-guides/adding-commit-info/java/src/main/java/example/micronaut/Application.java create mode 100644 buildSrc/src/test/resources/other-guides/adding-commit-info/java/src/main/resources/META-INF/native-image/resource-config.json create mode 100644 buildSrc/src/test/resources/other-guides/adding-commit-info/java/src/main/resources/application.yml create mode 100644 buildSrc/src/test/resources/other-guides/adding-commit-info/java/src/test/java/example/micronaut/InfoTest.java create mode 100644 buildSrc/src/test/resources/other-guides/adding-commit-info/kotlin/src/main/kotlin/example/micronaut/Application.kt create mode 100644 buildSrc/src/test/resources/other-guides/adding-commit-info/kotlin/src/main/resources/META-INF/native-image/resource-config.json create mode 100644 buildSrc/src/test/resources/other-guides/adding-commit-info/kotlin/src/main/resources/application.yml create mode 100644 buildSrc/src/test/resources/other-guides/adding-commit-info/kotlin/src/test/kotlin/example/micronaut/InfoTest.kt create mode 100644 buildSrc/src/test/resources/other-guides/adding-commit-info/metadata.json create mode 100644 buildSrc/src/test/resources/other-guides/test/test.adoc diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index 04a11b24020..616eb9c9698 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -38,6 +38,7 @@ dependencies { } implementation("com.networknt:json-schema-validator") implementation("io.micronaut.rss:micronaut-rss") + implementation("org.asciidoctor:asciidoctorj:3.0.0") testImplementation("org.skyscreamer:jsonassert:1.5.3") } diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/CalloutMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/CalloutMacroSubstitution.java new file mode 100644 index 00000000000..c299d8dfe7a --- /dev/null +++ b/buildSrc/src/main/java/io/micronaut/guides/core/CalloutMacroSubstitution.java @@ -0,0 +1,21 @@ +package io.micronaut.guides.core; + +import jakarta.inject.Singleton; + +@Singleton +public class CalloutMacroSubstitution extends LineMacroSubstitution { + @Override + protected String getMacroName() { + return "callout"; + } + + @Override + protected String getBaseDirectory() { + return "{calloutsDir}"; + } + + @Override + protected String getPrefix() { + return "callout-"; + } +} diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/CommonMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/CommonMacroSubstitution.java new file mode 100644 index 00000000000..bc89f42c4af --- /dev/null +++ b/buildSrc/src/main/java/io/micronaut/guides/core/CommonMacroSubstitution.java @@ -0,0 +1,22 @@ +package io.micronaut.guides.core; + +import jakarta.inject.Singleton; + +@Singleton +public class CommonMacroSubstitution extends LineMacroSubstitution { + + @Override + protected String getMacroName() { + return "common"; + } + + @Override + protected String getBaseDirectory() { + return "{commonsDir}"; + } + + @Override + protected String getPrefix() { + return "common-"; + } +} diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/ExternalMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/ExternalMacroSubstitution.java new file mode 100644 index 00000000000..162b481246c --- /dev/null +++ b/buildSrc/src/main/java/io/micronaut/guides/core/ExternalMacroSubstitution.java @@ -0,0 +1,22 @@ +package io.micronaut.guides.core; + +import jakarta.inject.Singleton; + +@Singleton +public class ExternalMacroSubstitution extends LineMacroSubstitution { + + @Override + protected String getMacroName() { + return "external"; + } + + @Override + protected String getBaseDirectory() { + return "{guidesDir}"; + } + + @Override + protected String getPrefix() { + return ""; + } +} diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/ExternalTemplateMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/ExternalTemplateMacroSubstitution.java new file mode 100644 index 00000000000..57908ddeb93 --- /dev/null +++ b/buildSrc/src/main/java/io/micronaut/guides/core/ExternalTemplateMacroSubstitution.java @@ -0,0 +1,21 @@ +package io.micronaut.guides.core; + +import jakarta.inject.Singleton; + +@Singleton +public class ExternalTemplateMacroSubstitution extends LineMacroSubstitution { + @Override + protected String getMacroName() { + return "external-template"; + } + + @Override + protected String getBaseDirectory() { + return "{guidesDir}"; + } + + @Override + protected String getPrefix() { + return ""; + } +} diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/GuideLinkMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/GuideLinkMacroSubstitution.java new file mode 100644 index 00000000000..4041b04e3a3 --- /dev/null +++ b/buildSrc/src/main/java/io/micronaut/guides/core/GuideLinkMacroSubstitution.java @@ -0,0 +1,34 @@ +package io.micronaut.guides.core; + +import jakarta.inject.Singleton; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static io.micronaut.guides.core.MacroUtils.findMacroInstances; + +@Singleton +public class GuideLinkMacroSubstitution implements MacroSubstitution { + private static final Pattern GUIDE_LINK_REGEX = Pattern.compile("guideLink:(.*?)\\[(.*?)]"); + + private static String processGuideLink(String line) { + Matcher matcher = GUIDE_LINK_REGEX.matcher(line); + if (matcher.find()) { + String slug = matcher.group(1).trim(); + String text = matcher.group(2); + return "link:" + slug + ".html[" + text + "]"; + } + return line; + } + + @Override + public String substitute(String str, Guide guide, GuidesOption option) { + for (String instance : findMacroInstances(str, GUIDE_LINK_REGEX)) { + String res = processGuideLink(instance); + str = str.replace(instance, res); + } + + return str; + } + +} diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/LineMacroSubstitution.java b/buildSrc/src/main/java/io/micronaut/guides/core/LineMacroSubstitution.java new file mode 100644 index 00000000000..6a19bc8a77d --- /dev/null +++ b/buildSrc/src/main/java/io/micronaut/guides/core/LineMacroSubstitution.java @@ -0,0 +1,45 @@ +package io.micronaut.guides.core; + +import io.micronaut.guides.core.asciidoc.Argument; +import io.micronaut.guides.core.asciidoc.AsciidocMacro; +import io.micronaut.guides.core.asciidoc.Attribute; +import io.micronaut.guides.core.asciidoc.IncludeDirective; + +import java.nio.file.Path; +import java.util.Optional; + +import static io.micronaut.guides.core.MacroUtils.findMacroLines; + +abstract class LineMacroSubstitution implements MacroSubstitution { + protected abstract String getMacroName(); + + protected abstract String getBaseDirectory(); + + protected abstract String getPrefix(); + + @Override + public String substitute(String str, Guide guide, GuidesOption option) { + for (String line : findMacroLines(str, getMacroName())) { + Optional asciidocMacroOptional = AsciidocMacro.of(getMacroName(), line); + if (asciidocMacroOptional.isEmpty()) { + continue; + } + + AsciidocMacro macro = asciidocMacroOptional.get(); + StringBuilder builder = new StringBuilder(); + + for (Attribute attribute : macro.attributes()) { + Argument argument = new Argument(attribute.key(), attribute.values().get(0)); + builder.append(argument).append("\n"); + } + + Path target = Path.of(getBaseDirectory(), getPrefix() + macro.target()); + + IncludeDirective.Builder includeDirectiveBuilder = IncludeDirective.builder().target(target.toString()); + builder.append(includeDirectiveBuilder.build()); + + str = str.replace(line, builder.toString()); + } + return str; + } +} 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 44463a43ba1..3477e818522 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/MacroUtils.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/MacroUtils.java @@ -24,9 +24,8 @@ static List findMacroLines(@NonNull String str, @NonNull String macro) { .toList(); } - static List findMacroInstances(@NonNull String str, @NonNull String macro) { + static List findMacroInstances(@NonNull String str, @NonNull Pattern pattern) { List matches = new ArrayList<>(); - Pattern pattern = Pattern.compile("@(?:([\\w-]*):)?" + macro + "@"); Matcher matcher = pattern.matcher(str); while (matcher.find()) { 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 3bcc8dfd712..e4760214c1f 100644 --- a/buildSrc/src/main/java/io/micronaut/guides/core/PlaceholderWithTargetMacroSubstitution.java +++ b/buildSrc/src/main/java/io/micronaut/guides/core/PlaceholderWithTargetMacroSubstitution.java @@ -4,6 +4,7 @@ import io.micronaut.guides.core.asciidoc.PlacheholderMacro; import java.util.Optional; +import java.util.regex.Pattern; abstract class PlaceholderWithTargetMacroSubstitution implements MacroSubstitution { @@ -12,7 +13,8 @@ abstract class PlaceholderWithTargetMacroSubstitution implements MacroSubstituti protected abstract String getSubstitution(Guide guide, GuidesOption option, String app); public String substitute(String str, Guide guide, GuidesOption option) { - for (String instance : MacroUtils.findMacroInstances(str, getMacroName())) { + Pattern pattern = Pattern.compile("@(?:([\\w-]*):)?" + getMacroName() + "@"); + for (String instance : MacroUtils.findMacroInstances(str, pattern)) { Optional macroOptional = PlacheholderMacro.of(getMacroName(), instance); if (macroOptional.isEmpty()) { continue; diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/Argument.java b/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/Argument.java new file mode 100644 index 00000000000..a0655294310 --- /dev/null +++ b/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/Argument.java @@ -0,0 +1,30 @@ +package io.micronaut.guides.core.asciidoc; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.util.StringUtils; + +import java.util.Optional; + +public record Argument(String key, String value) { + private static final String ARGUMENT_DELIMITATOR = ":"; + + @NonNull + public static Optional of(@NonNull String str) { + if (StringUtils.isEmpty(str)) { + return Optional.empty(); + } + + String[] parts = str.split("=", 2); + if (parts.length == 2 && !parts[0].isBlank() && !parts[1].isBlank()) { + return Optional.of(new Argument(parts[0], parts[1])); + } + + return Optional.empty(); + } + + @Override + public String toString() { + return ARGUMENT_DELIMITATOR + key + ARGUMENT_DELIMITATOR + " " + value; + } +} + diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/AsciidocConfiguration.java b/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/AsciidocConfiguration.java new file mode 100644 index 00000000000..562ebefe0e2 --- /dev/null +++ b/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/AsciidocConfiguration.java @@ -0,0 +1,41 @@ +package io.micronaut.guides.core.asciidoc; + +import org.asciidoctor.Placement; + +import java.io.File; + +public interface AsciidocConfiguration { + String getSourceDir(); + + String getSourceHighlighter(); + + Placement getToc(); + + int getToclevels(); + + boolean getSectnums(); + + String getIdprefix(); + + String getIdseparator(); + + String getIcons(); + + String getImagesdir(); + + boolean isNofooter(); + + String getDocType(); + + String getRuby(); + + File getTemplateDirs(); + + String getCommonsDir(); + + String getBaseDir(); + + String getGuidesDir(); + + String getCalloutsDir(); +} diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/AsciidocConfigurationProperties.java b/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/AsciidocConfigurationProperties.java new file mode 100644 index 00000000000..fb1dee05e13 --- /dev/null +++ b/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/AsciidocConfigurationProperties.java @@ -0,0 +1,199 @@ +package io.micronaut.guides.core.asciidoc; + +import io.micronaut.context.annotation.ConfigurationProperties; +import org.asciidoctor.Placement; + +import java.io.File; + +@ConfigurationProperties(AsciidocConfigurationProperties.PREFIX) +public class AsciidocConfigurationProperties implements AsciidocConfiguration { + public static final String PREFIX = "asciidoc"; + private static final String DEFAULT_SOURCEDIR = "build/code"; + private static final String DEFAULT_SOURCE_HIGHLIGHTER = "coderay"; + private static final Placement DEFAULT_TOC = Placement.LEFT; + private static final int DEFAULT_TOCLEVELS = 2; + private static final boolean DEFAULT_SECTNUMS = true; + private static final String DEFAULT_IDPREFIX = ""; + private static final String DEFAULT_IDSEPARATOR = "-"; + private static final String DEFAULT_ICONS = "font"; + private static final String DEFAULT_IMAGESDIR = "images"; + private static final boolean DEFAULT_NOFOOTER = true; + private static final String DEFAULT_DOCTYPE = "book"; + private static final String DEFAULT_RUBY = "erubis"; + private static final String DEFAULT_TEMPLATE_DIRS = "src/docs/asciidoc"; + private static final String DEFAULT_COMMONS_DIR = "src/docs/asciidoc/common"; + private static final String DEFAULT_CALLOUTS_DIR = "src/docs/asciidoc/callouts"; + private static final String DEFAULT_BASE_DIR = "."; + private static final String DEFAULT_GUIDES_DIR = "guides"; + + private String sourcedir = DEFAULT_SOURCEDIR; + private String sourceHighlighter = DEFAULT_SOURCE_HIGHLIGHTER; + private Placement toc = DEFAULT_TOC; + private int toclevels = DEFAULT_TOCLEVELS; + private boolean sectnums = DEFAULT_SECTNUMS; + private String idprefix = DEFAULT_IDPREFIX; + private String idseparator = DEFAULT_IDSEPARATOR; + private String icons = DEFAULT_ICONS; + private String imagesdir = DEFAULT_IMAGESDIR; + private boolean nofooter = DEFAULT_NOFOOTER; + private String docType = DEFAULT_DOCTYPE; + private String ruby = DEFAULT_RUBY; + private File templateDirs = new File(DEFAULT_TEMPLATE_DIRS); + private String commonsDir = DEFAULT_COMMONS_DIR; + private String baseDir = DEFAULT_BASE_DIR; + private String guidesDir = DEFAULT_GUIDES_DIR; + private String calloutsDir = DEFAULT_CALLOUTS_DIR; + + @Override + public String getSourceDir() { + return sourcedir; + } + + public void setSourceDir(String sourcedir) { + this.sourcedir = sourcedir; + } + + @Override + public String getSourceHighlighter() { + return sourceHighlighter; + } + + public void setSourceHighlighter(String sourceHighlighter) { + this.sourceHighlighter = sourceHighlighter; + } + + @Override + public Placement getToc() { + return toc; + } + + public void setToc(Placement toc) { + this.toc = toc; + } + + @Override + public int getToclevels() { + return toclevels; + } + + public void setToclevels(int toclevels) { + this.toclevels = toclevels; + } + + @Override + public boolean getSectnums() { + return sectnums; + } + + public void setSectnums(boolean sectnums) { + this.sectnums = sectnums; + } + + @Override + public String getIdprefix() { + return idprefix; + } + + public void setIdprefix(String idprefix) { + this.idprefix = idprefix; + } + + @Override + public String getIdseparator() { + return idseparator; + } + + public void setIdseparator(String idseparator) { + this.idseparator = idseparator; + } + + @Override + public String getIcons() { + return icons; + } + + public void setIcons(String icons) { + this.icons = icons; + } + + @Override + public String getImagesdir() { + return imagesdir; + } + + public void setImagesdir(String imagesdir) { + this.imagesdir = imagesdir; + } + + @Override + public boolean isNofooter() { + return nofooter; + } + + public void setNofooter(boolean nofooter) { + this.nofooter = nofooter; + } + + @Override + public String getDocType() { + return docType; + } + + public void setDocType(String docType) { + this.docType = docType; + } + + @Override + public String getRuby() { + return ruby; + } + + public void setRuby(String ruby) { + this.ruby = ruby; + } + + @Override + public File getTemplateDirs() { + return templateDirs; + } + + public void setTemplateDirs(File templateDirs) { + this.templateDirs = templateDirs; + } + + @Override + public String getCommonsDir() { + return commonsDir; + } + + public void setCommonsDir(String commonsDir) { + this.commonsDir = commonsDir; + } + + @Override + public String getBaseDir() { + return baseDir; + } + + public void setBaseDir(String baseDir) { + this.baseDir = baseDir; + } + + @Override + public String getGuidesDir() { + return guidesDir; + } + + public void setGuidesDir(String guidesDir) { + this.guidesDir = guidesDir; + } + + @Override + public String getCalloutsDir() { + return calloutsDir; + } + + public void setCalloutsDir(String calloutsDir) { + this.calloutsDir = calloutsDir; + } +} \ No newline at end of file diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/AsciidocConverter.java b/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/AsciidocConverter.java new file mode 100644 index 00000000000..6bafe53d986 --- /dev/null +++ b/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/AsciidocConverter.java @@ -0,0 +1,15 @@ +package io.micronaut.guides.core.asciidoc; + +import io.micronaut.core.annotation.NonNull; +import io.micronaut.core.annotation.Nullable; +import jakarta.validation.constraints.NotNull; + +import java.io.File; + +public interface AsciidocConverter { + + void convert(@NotNull @NonNull File source, @NotNull @NonNull File destination); + + @Nullable + String convert(@NotNull @NonNull File source); +} diff --git a/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/DefaultAsciidocConverter.java b/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/DefaultAsciidocConverter.java new file mode 100644 index 00000000000..9dd1b0bde82 --- /dev/null +++ b/buildSrc/src/main/java/io/micronaut/guides/core/asciidoc/DefaultAsciidocConverter.java @@ -0,0 +1,52 @@ +package io.micronaut.guides.core.asciidoc; + +import jakarta.inject.Singleton; +import org.asciidoctor.*; + +import java.io.File; + +@Singleton +public class DefaultAsciidocConverter implements AsciidocConverter { + + OptionsBuilder optionsBuilder; + + Asciidoctor asciidoctor; + + DefaultAsciidocConverter(AsciidocConfiguration asciidocConfiguration) { + Attributes attributes = Attributes.builder() + .attribute("sourcedir", asciidocConfiguration.getSourceDir()) + .attribute("commonsDir", asciidocConfiguration.getCommonsDir()) + .attribute("calloutsDir", asciidocConfiguration.getCalloutsDir()) + .attribute("guidesDir", asciidocConfiguration.getGuidesDir()) + .sourceHighlighter(asciidocConfiguration.getSourceHighlighter()) + .tableOfContents(asciidocConfiguration.getToc()) + .attribute("toclevels", asciidocConfiguration.getToclevels()) + .sectionNumbers(asciidocConfiguration.getSectnums()) + .attribute("idprefix", asciidocConfiguration.getIdprefix()) + .attribute("idseparator", asciidocConfiguration.getIdseparator()) + .icons(asciidocConfiguration.getIcons()) + .imagesDir(asciidocConfiguration.getImagesdir()) + .noFooter(asciidocConfiguration.isNofooter()) + .build(); + + optionsBuilder = Options.builder() + .docType(asciidocConfiguration.getDocType()) + .eruby(asciidocConfiguration.getRuby()) + .templateDirs(asciidocConfiguration.getTemplateDirs()) + .attributes(attributes) + .safe(SafeMode.UNSAFE) + .baseDir(new File(asciidocConfiguration.getBaseDir())); + + asciidoctor = Asciidoctor.Factory.create(); + } + + @Override + public void convert(File source, File destination) { + asciidoctor.convertFile(source, optionsBuilder.toFile(destination).build()); + } + + @Override + public String convert(File source) { + return asciidoctor.convertFile(source, optionsBuilder.toFile(false).build()); + } +} diff --git a/buildSrc/src/test/java/io/micronaut/guides/core/CalloutMacroSubstitutionTest.java b/buildSrc/src/test/java/io/micronaut/guides/core/CalloutMacroSubstitutionTest.java new file mode 100644 index 00000000000..8bf35df512c --- /dev/null +++ b/buildSrc/src/test/java/io/micronaut/guides/core/CalloutMacroSubstitutionTest.java @@ -0,0 +1,25 @@ +package io.micronaut.guides.core; + +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@MicronautTest(startApplication = false) +public class CalloutMacroSubstitutionTest { + + @Inject + CalloutMacroSubstitution calloutMacro; + + @Test + void testSubstitute() { + String line = "callout:get[arg0=index,arg1=/hello]"; + String result = calloutMacro.substitute(line, null, null); + String exptected = """ + :arg0: index + :arg1: /hello + include::{calloutsDir}/callout-get[]"""; + assertEquals(exptected, result); + } +} diff --git a/buildSrc/src/test/java/io/micronaut/guides/core/CommonMacroSubstitutionTest.java b/buildSrc/src/test/java/io/micronaut/guides/core/CommonMacroSubstitutionTest.java new file mode 100644 index 00000000000..851f8ce3af2 --- /dev/null +++ b/buildSrc/src/test/java/io/micronaut/guides/core/CommonMacroSubstitutionTest.java @@ -0,0 +1,22 @@ +package io.micronaut.guides.core; + +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@MicronautTest(startApplication = false) +public class CommonMacroSubstitutionTest { + + @Inject + CommonMacroSubstitution commonMacroSubstitution; + + @Test + void testSubstitute() { + String line = "common:header-top.adoc[]"; + String result = commonMacroSubstitution.substitute(line, null, null); + String exptected = "include::{commonsDir}/common-header-top.adoc[]"; + assertEquals(exptected, result); + } +} diff --git a/buildSrc/src/test/java/io/micronaut/guides/core/ExternalMacroSubstitutionTest.java b/buildSrc/src/test/java/io/micronaut/guides/core/ExternalMacroSubstitutionTest.java new file mode 100644 index 00000000000..63017e50d90 --- /dev/null +++ b/buildSrc/src/test/java/io/micronaut/guides/core/ExternalMacroSubstitutionTest.java @@ -0,0 +1,22 @@ +package io.micronaut.guides.core; + +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@MicronautTest(startApplication = false) +public class ExternalMacroSubstitutionTest { + + @Inject + ExternalMacroSubstitution externalMacroSubstitution; + + @Test + void testSubstitute() { + String line = "external:micronaut-k8s/requirements.adoc[]"; + String result = externalMacroSubstitution.substitute(line, null, null); + String exptected = "include::{guidesDir}/micronaut-k8s/requirements.adoc[]"; + assertEquals(exptected, result); + } +} diff --git a/buildSrc/src/test/java/io/micronaut/guides/core/ExternalTemplateMacroSubstitutionTest.java b/buildSrc/src/test/java/io/micronaut/guides/core/ExternalTemplateMacroSubstitutionTest.java new file mode 100644 index 00000000000..9c0771aae11 --- /dev/null +++ b/buildSrc/src/test/java/io/micronaut/guides/core/ExternalTemplateMacroSubstitutionTest.java @@ -0,0 +1,23 @@ +package io.micronaut.guides.core; + +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@MicronautTest(startApplication = false) +public class ExternalTemplateMacroSubstitutionTest { + @Inject + private ExternalTemplateMacroSubstitution externalTemplateMacroSubstitution; + + @Test + public void testSubstitute() { + String line = "external-template:micronaut-k8s-oci/k8s-microservice.adoc[arg0=users]"; + String result = externalTemplateMacroSubstitution.substitute(line, null, null); + String exptected = """ + :arg0: users + include::{guidesDir}/micronaut-k8s-oci/k8s-microservice.adoc[]"""; + assertEquals(exptected, result); + } +} diff --git a/buildSrc/src/test/java/io/micronaut/guides/core/GuideLinkMacroSubstitutionTest.java b/buildSrc/src/test/java/io/micronaut/guides/core/GuideLinkMacroSubstitutionTest.java new file mode 100644 index 00000000000..3d79dbbda4a --- /dev/null +++ b/buildSrc/src/test/java/io/micronaut/guides/core/GuideLinkMacroSubstitutionTest.java @@ -0,0 +1,22 @@ +package io.micronaut.guides.core; + +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@MicronautTest(startApplication = false) +public class GuideLinkMacroSubstitutionTest { + + @Inject + GuideLinkMacroSubstitution guideLinkMacroSubstitution; + + @Test + void testSubstitute() { + String str = "Deploy the _auth.yml_ file that we created in the guideLink:micronaut-k8s[Kubernetes and the Micronaut Framework] guide guideLink:micronaut-k8s[Kubernetes and the Micronaut Framework] and guideLink:micronaut-cli-jwkgen[JWK generation with a Micronaut command line application]."; + String result = guideLinkMacroSubstitution.substitute(str, null, null); + String expected = "Deploy the _auth.yml_ file that we created in the link:micronaut-k8s.html[Kubernetes and the Micronaut Framework] guide link:micronaut-k8s.html[Kubernetes and the Micronaut Framework] and link:micronaut-cli-jwkgen.html[JWK generation with a Micronaut command line application]."; + assertEquals(expected, result); + } +} diff --git a/buildSrc/src/test/java/io/micronaut/guides/core/MacroUtilsTest.java b/buildSrc/src/test/java/io/micronaut/guides/core/MacroUtilsTest.java index 01f89147ef7..3b6af2daac2 100644 --- a/buildSrc/src/test/java/io/micronaut/guides/core/MacroUtilsTest.java +++ b/buildSrc/src/test/java/io/micronaut/guides/core/MacroUtilsTest.java @@ -5,22 +5,25 @@ import io.micronaut.starter.options.Language; import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.*; import java.util.List; +import java.util.regex.Pattern; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; @MicronautTest(startApplication = false) class MacroUtilsTest { @Test - void testGetSourceDir(){ - GuidesOption option = new GuidesOption(BuildTool.GRADLE,Language.JAVA, TestFramework.JUNIT); + void testGetSourceDir() { + GuidesOption option = new GuidesOption(BuildTool.GRADLE, Language.JAVA, TestFramework.JUNIT); String result = MacroUtils.getSourceDir("slug", option); assertEquals("slug-gradle-java", result); } @Test - void testFindMacroGroups(){ + void testFindMacroGroups() { String str = """ https://micronaut-projects.github.io/micronaut-validation/snapshot/guide/[Micronaut validation] is built on the standard framework – https://www.jcp.org/en/jsr/detail?id=380[JSR 380], also known as Bean Validation 2.0. Micronaut Validation has built-in support for validation of beans that are annotated with `jakarta.validation` annotations. @@ -35,7 +38,7 @@ void testFindMacroGroups(){ Alternatively, you can use https://micronaut-projects.github.io/micronaut-hibernate-validator/latest/guide/[Micronaut Hibernate Validator], which uses https://hibernate.org/validator/[Hibernate Validator]; a reference implementation of the validation API. """; - List result = MacroUtils.findMacroGroups(str,"dependencies"); + List result = MacroUtils.findMacroGroups(str, "dependencies"); List expected = List.of(""" :dependencies: @@ -47,7 +50,7 @@ void testFindMacroGroups(){ } @Test - void testFindMacroGroupsMultiple(){ + void testFindMacroGroupsMultiple() { String str = """ https://micronaut-projects.github.io/micronaut-validation/snapshot/guide/[Micronaut validation] is built on the standard framework – https://www.jcp.org/en/jsr/detail?id=380[JSR 380], also known as Bean Validation 2.0. Micronaut Validation has built-in support for validation of beans that are annotated with `jakarta.validation` annotations. @@ -71,7 +74,7 @@ void testFindMacroGroupsMultiple(){ Test """; - List result = MacroUtils.findMacroGroups(str,"dependencies"); + List result = MacroUtils.findMacroGroups(str, "dependencies"); List expected = List.of(""" :dependencies: @@ -89,7 +92,7 @@ void testFindMacroGroupsMultiple(){ } @Test - void findMacroGroupsNested(){ + void findMacroGroupsNested() { String str = """ :exclude-for-build:gradle @@ -129,7 +132,7 @@ void findMacroGroupsNested(){ TestTest :exclude-for-build:"""; - List result = MacroUtils.findMacroGroupsNested(str,"exclude-for-build").stream().map(el -> String.join("\n", el)).toList(); + List result = MacroUtils.findMacroGroupsNested(str, "exclude-for-build").stream().map(el -> String.join("\n", el)).toList(); List expected = List.of(""" :exclude-for-build:gradle @@ -139,7 +142,7 @@ void findMacroGroupsNested(){ ./mvnw test ---- - :exclude-for-build:""",""" + :exclude-for-build:""", """ :exclude-for-build:maven [source, bash] @@ -149,28 +152,28 @@ void findMacroGroupsNested(){ ---- :exclude-for-build:""", """ - :exclude-for-build:gradle + :exclude-for-build:gradle - [source, bash] - .users - ---- - MICRONAUT_ENVIRONMENTS=dev ./mvnw mn:run - ---- - - Test - - :exclude-for-build:maven - - [source, bash] - .users - ---- - MICRONAUT_ENVIRONMENTS=dev ./gradlew run - ---- - - :exclude-for-build: - TestTest - - :exclude-for-build:"""); + [source, bash] + .users + ---- + MICRONAUT_ENVIRONMENTS=dev ./mvnw mn:run + ---- + + Test + + :exclude-for-build:maven + + [source, bash] + .users + ---- + MICRONAUT_ENVIRONMENTS=dev ./gradlew run + ---- + + :exclude-for-build: + TestTest + + :exclude-for-build:"""); assertEquals(expected, result); } @@ -178,7 +181,8 @@ void findMacroGroupsNested(){ void testFindMacroInstances() { String input = "Some text @cli-command@ more text @another-example:cli-command@ end @example-cli-command@."; String macro = "cli-command"; - List result = MacroUtils.findMacroInstances(input, macro); + Pattern pattern = Pattern.compile("@(?:([\\w-]*):)?" + macro + "@"); + List result = MacroUtils.findMacroInstances(input, pattern); List expected = List.of("@cli-command@", "@another-example:cli-command@"); assertEquals(expected, result); } @@ -187,7 +191,8 @@ void testFindMacroInstances() { void testFindMacroInstancesNoMatch() { String input = "Some text without the pattern."; String macro = "cli-command"; - List result = MacroUtils.findMacroInstances(input, macro); + Pattern pattern = Pattern.compile("@(?:([\\w-]*):)?" + macro + "@"); + List result = MacroUtils.findMacroInstances(input, pattern); assertTrue(result.isEmpty()); } @@ -195,26 +200,27 @@ void testFindMacroInstancesNoMatch() { void testFindMacroInstancesDifferentMacro() { String input = "Some text @example-cli-command@ more text @another-example:cli-command@ end."; String macro = "different-command"; - List result = MacroUtils.findMacroInstances(input, macro); + Pattern pattern = Pattern.compile("@(?:([\\w-]*):)?" + macro + "@"); + List result = MacroUtils.findMacroInstances(input, pattern); assertTrue(result.isEmpty()); } @Test - void extractMacroGroupParametersTest(){ + void extractMacroGroupParametersTest() { String line = ":exclude-for-languages:groovy"; String macro = "exclude-for-languages"; - List result = MacroUtils.extractMacroGroupParameters(line,macro); + List result = MacroUtils.extractMacroGroupParameters(line, macro); assertEquals("groovy", result.get(0)); line = ":exclude-for-languages:groovy,java"; macro = "exclude-for-languages"; - result = MacroUtils.extractMacroGroupParameters(line,macro); + result = MacroUtils.extractMacroGroupParameters(line, macro); assertEquals("groovy", result.get(0)); assertEquals("java", result.get(1)); line = ":exclude-for-languages:"; macro = "exclude-for-languages"; - result = MacroUtils.extractMacroGroupParameters(line,macro); + result = MacroUtils.extractMacroGroupParameters(line, macro); assertEquals(0, result.size()); } } diff --git a/buildSrc/src/test/java/io/micronaut/guides/core/asciidoc/AsciidocConverterTest.java b/buildSrc/src/test/java/io/micronaut/guides/core/asciidoc/AsciidocConverterTest.java new file mode 100644 index 00000000000..ccefdd86ffe --- /dev/null +++ b/buildSrc/src/test/java/io/micronaut/guides/core/asciidoc/AsciidocConverterTest.java @@ -0,0 +1,207 @@ +package io.micronaut.guides.core.asciidoc; + +import io.micronaut.guides.core.*; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@MicronautTest(startApplication = false) +public class AsciidocConverterTest { + + @Inject + AsciidocConverter asciidocConverter; + + @Inject + GuideParser guideParser; + + @Inject + GuideProjectGenerator guideProjectGenerator; + + @Inject + FilesTransferUtility filesTransferUtility; + + @Test + void testConvert() throws IOException { + String outputPath = "build/tmp/test/adding-commit-info"; + File outputDirectory = new File(outputPath); + outputDirectory.mkdir(); + + String path = "src/test/resources/other-guides/adding-commit-info"; + File file = new File(path); + Guide guide = guideParser.parseGuideMetadata(file, "metadata.json").orElseThrow(); + + guideProjectGenerator.generate(outputDirectory, guide); + + filesTransferUtility.transferFiles(file, outputDirectory, guide); + + File sourceFile = new File("src/test/resources/adding-commit-info-gradle-java.adoc"); + + Path tempDirectory = Files.createTempDirectory("micronaut-guides"); + File destinationFile = new File(tempDirectory.toFile(), "adding-commit-info-gradle-java.html"); + asciidocConverter.convert(sourceFile, destinationFile); + String expected = TestUtils.readFile(new File("src/test/resources/adding-commit-info-gradle-java-expected.html")); + String result = TestUtils.readFile(destinationFile); + assertEquals(expected, result); + } + + @Test + void testConvertIncludeAdoc() throws IOException { + Path tempDirectory = Files.createTempDirectory("micronaut-guides"); + File destinationFile = new File(tempDirectory.toFile(), "adding-commit-info.html"); + File sourceFile = new File("src/test/resources/other-guides/adding-commit-info/adding-commit-info.adoc"); + asciidocConverter.convert(sourceFile, destinationFile); + File expectedFile = new File("src/test/resources/adding-commit-info-expected.html"); + String expected = TestUtils.readFile(expectedFile); + String result = TestUtils.readFile(destinationFile); + assertEquals(expected, result); + } + + @Test + void testConvertRawHtml() { + File sourceFile = new File("src/test/resources/other-guides/adding-commit-info/adding-commit-info.adoc"); + String result = asciidocConverter.convert(sourceFile); + String expected = """ +
+
Table of Contents
+ +
+
+
+
+

@guideIntro@

+
+
+

Authors: @authors@

+
+
+

Micronaut Version: @micronaut@

+
+
+

Execute the following command to run a MySQL container:

+
+
+
+
docker run -it --rm \\
+                    -p 3306:3306 \\
+                    -e MYSQL_DATABASE=db \\
+                    -e MYSQL_USER=sherlock \\
+                    -e MYSQL_PASSWORD=elementary \\
+                    -e MYSQL_ALLOW_EMPTY_PASSWORD=true \\
+                    mysql:8
+
+
+
+ + + + + +
+ + + If you are using macOS on Apple Silicon – e.g. M1, M1 Pro, etc. – Docker might fail to pull an image for mysql:8. In that case substitute mysql:oracle. +
+
+
+

Export users microservice image repository to the USERS_REPOSITORY environment variable.

+
+
+
+
export USERS_REPOSITORY="gcr.io/$GCP_PROJECT_ID/users"
+
+
+
+ + + + + + + + + + + + + +
1The class is defined as a controller with the @api@/io/micronaut/http/annotation/Controller.html[@Controller] annotation mapped to the path dir/path/example.txt.
2The class is defined as a controller with the @api@/io/micronaut/http/annotation/Controller.html[@Controller] annotation mapped to the path dir/path/example.txt.
3The class is defined as a controller with the @api@/io/micronaut/http/annotation/Controller.html[@Controller] annotation mapped to the path dir/path/example.txt.
+
+
+

Test

+
+
+

In this guide, we will add git commit info to your Micronaut build artifacts and running application. + There are many benefits of keeping your commit info handy:

+
+
+
    +
  • +

    Commit info is encapsulated within the built artifacts

    +
  • +
  • +

    Fast authoritative means of identifying what specific code is running in an environment

    +
  • +
  • +

    This solution doesn’t rely on external tracking mechanisms

    +
  • +
  • +

    Transparency and reproducibility when investigating issues

    +
  • +
+
+
+ + + + + +
+ + + Before running the downloaded project, follow the steps described in the Initialize Git Repository section below. +
+
+
+
+
+

1. Initialize Git Repository

+
+
+

The project aims to demonstrate how to provide Git commit information to the + /info endpoint and in order for that to work the project needs to be in a Git repository. + After creating the project, initialize a Git repository from the root of the newly created project:

+
+
+
+
cd micronautguide
+                git init
+                git add .
+                git commit -am "Initial project"
+
+
+
+
+
+

2. Management

+
+
+

Inspired by Spring Boot and Grails, the Micronaut management dependency adds support for monitoring of your application via endpoints: special URIs that return details about the health and state of your application.

+
+
+

To use the management features described in this section, add the dependency on your classpath.

+
+
+
"""; + assertEquals(expected, result); + } +} diff --git a/buildSrc/src/test/resources/adding-commit-info-expected.html b/buildSrc/src/test/resources/adding-commit-info-expected.html new file mode 100644 index 00000000000..da02123f1d3 --- /dev/null +++ b/buildSrc/src/test/resources/adding-commit-info-expected.html @@ -0,0 +1,668 @@ + + + + + + + +@guideTitle@ + + + + + + + +
+
+
+
+

@guideIntro@

+
+
+

Authors: @authors@

+
+
+

Micronaut Version: @micronaut@

+
+
+

Execute the following command to run a MySQL container:

+
+
+
+
docker run -it --rm \
+    -p 3306:3306 \
+    -e MYSQL_DATABASE=db \
+    -e MYSQL_USER=sherlock \
+    -e MYSQL_PASSWORD=elementary \
+    -e MYSQL_ALLOW_EMPTY_PASSWORD=true \
+    mysql:8
+
+
+
+ + + + + +
+ + +If you are using macOS on Apple Silicon – e.g. M1, M1 Pro, etc. – Docker might fail to pull an image for mysql:8. In that case substitute mysql:oracle. +
+
+
+

Export users microservice image repository to the USERS_REPOSITORY environment variable.

+
+
+
+
export USERS_REPOSITORY="gcr.io/$GCP_PROJECT_ID/users"
+
+
+
+ + + + + + + + + + + + + +
1The class is defined as a controller with the @api@/io/micronaut/http/annotation/Controller.html[@Controller] annotation mapped to the path dir/path/example.txt.
2The class is defined as a controller with the @api@/io/micronaut/http/annotation/Controller.html[@Controller] annotation mapped to the path dir/path/example.txt.
3The class is defined as a controller with the @api@/io/micronaut/http/annotation/Controller.html[@Controller] annotation mapped to the path dir/path/example.txt.
+
+
+

Test

+
+
+

In this guide, we will add git commit info to your Micronaut build artifacts and running application. +There are many benefits of keeping your commit info handy:

+
+
+
    +
  • +

    Commit info is encapsulated within the built artifacts

    +
  • +
  • +

    Fast authoritative means of identifying what specific code is running in an environment

    +
  • +
  • +

    This solution doesn’t rely on external tracking mechanisms

    +
  • +
  • +

    Transparency and reproducibility when investigating issues

    +
  • +
+
+
+ + + + + +
+ + +Before running the downloaded project, follow the steps described in the Initialize Git Repository section below. +
+
+
+
+
+

1. Initialize Git Repository

+
+
+

The project aims to demonstrate how to provide Git commit information to the +/info endpoint and in order for that to work the project needs to be in a Git repository. +After creating the project, initialize a Git repository from the root of the newly created project:

+
+
+
+
cd micronautguide
+git init
+git add .
+git commit -am "Initial project"
+
+
+
+
+
+

2. Management

+
+
+

Inspired by Spring Boot and Grails, the Micronaut management dependency adds support for monitoring of your application via endpoints: special URIs that return details about the health and state of your application.

+
+
+

To use the management features described in this section, add the dependency on your classpath.

+
+
+
+
+ + \ No newline at end of file diff --git a/buildSrc/src/test/resources/adding-commit-info-gradle-java-expected.html b/buildSrc/src/test/resources/adding-commit-info-gradle-java-expected.html new file mode 100644 index 00000000000..addf4d53165 --- /dev/null +++ b/buildSrc/src/test/resources/adding-commit-info-gradle-java-expected.html @@ -0,0 +1,1081 @@ + + + + + + + +Adding Commit Info to your Micronaut Application + + + + + + + +
+
+
+
+

Expose the exact version of code that your application is running.

+
+
+

Authors: Sergio del Amo

+
+
+

Micronaut Version: 4.6.3

+
+
+

In this guide, we will add git commit info to your Micronaut build artifacts and running application. There are many benefits of keeping your commit info handy:

+
+
+
    +
  • +

    Commit info is encapsulated within the built artifacts

    +
  • +
  • +

    Fast authoritative means of identifying what specific code is running in an environment

    +
  • +
  • +

    This solution doesn’t rely on external tracking mechanisms

    +
  • +
  • +

    Transparency and reproducibility when investigating issues

    +
  • +
+
+
+
+
+

1. Getting Started

+
+
+

In this guide, we will create a Micronaut application written in Java.

+
+
+
+
+

2. What you will need

+
+
+

To complete this guide, you will need the following:

+
+
+ +
+
+
+
+

3. Solution

+
+
+

We recommend that you follow the instructions in the next sections and create the application step by step. However, you can go right to the completed example.

+
+
+ +
+
+ + + + + +
+ + +Before running the downloaded project, follow the steps described in the Initialize Git Repository section below. +
+
+
+
+
+

4. Writing the Application

+
+
+

Create an application using the Micronaut Command Line Interface or with Micronaut Launch.

+
+
+
+
mn create-app example.micronaut.micronautguide --build=gradle --lang=java
+
+
+
+ + + + + +
+ + +If you don’t specify the --build argument, Gradle with the Kotlin DSL is used as the build tool.
If you don’t specify the --lang argument, Java is used as the language.
If you don’t specify the --test argument, JUnit is used for Java and Kotlin, and Spock is used for Groovy. +
+
+
+

The previous command creates a Micronaut application with the default package example.micronaut in a directory named micronautguide.

+
+ +
+
+
+

5. Initialize Git Repository

+
+
+

The project aims to demonstrate how to provide Git commit information to the +/info endpoint and in order for that to work the project needs to be in a Git repository. After creating the project, initialize a Git repository from the root of the newly created project:

+
+
+
+
cd micronautguide
+git init
+git add .
+git commit -am "Initial project"
+
+
+
+
+
+

6. Management

+
+
+

Inspired by Spring Boot and Grails, the Micronaut management dependency adds support for monitoring of your application via endpoints: special URIs that return details about the health and state of your application.

+
+
+

To use the management features described in this section, add the dependency on your classpath.

+
+
+
build.gradle
+
+
implementation("io.micronaut:micronaut-management")
+
+
+
+
+
+

7. Info endpoint

+
+
+
+
+

The info endpoint returns static information from the state of the application. The info exposed can be provided by any number of "info sources".

+
+
+
+
+

Enable the info endpoint:

+
+ +
+
src/main/resources/application.yml
+
+
endpoints:
+  info:
+    enabled: true
+    sensitive: false
+
+
+
+
+
+

8. Gradle Git Properties Plugin

+
+
+

If a git.properties file is available on the classpath, the GitInfoSource will expose the values in that file under the git key. Generation of a git.properties file will need to be configured as part of your build.

+
+
+

For example, you may choose to use the Gradle Git Properties plugin. The plugin provides a task named generateGitProperties responsible for the git.properties file generation. It is automatically invoked upon the execution of the classes task. You can find the generated file in the directory build/resources/main.

+
+
+

Modify build.gradle file to add the plugin:

+
+
+
build.gradle
+
+
plugins {
+  id "com.gorylenko.gradle-git-properties" version "2.3.2"
+}
+
+
+
+
+
+

9. Test

+
+
+

Create a JUnit test to verify that when you make a GET request to /info you get a payload such as:

+
+
+
+
{
+  "git": {
+    "dirty": "true",
+    "commit": {
+      "id": "7368906193527fbf2b45f1ed5b08c56631f5b155",
+      "describe": "7368906-dirty",
+      "time": "1527429126",
+      "message": {
+        "short": "Initial version",
+        "full": "Initial version"
+      },
+      "user": {
+        "name": "sdelamo",
+        "email": "sergio.delamo@softamo.com"
+      }
+    },
+    "branch": "master"
+  }
+}
+
+
+
+

Create a JUnit test to verify the behaviour:

+
+
+
src/test/java/example/micronaut/InfoTest.java
+
+
package example.micronaut;
+
+import io.micronaut.http.HttpRequest;
+import io.micronaut.http.HttpResponse;
+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;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+@MicronautTest (1)
+public class InfoTest {
+
+    @Inject
+    @Client("/")
+    HttpClient client; (2)
+
+    @Test
+    public void testGitComitInfoAppearsInJson() {
+        HttpRequest request = HttpRequest.GET("/info"); (3)
+
+        HttpResponse<Map> rsp = client.toBlocking().exchange(request, Map.class);
+
+        assertEquals(200, rsp.status().getCode());
+
+        Map json = rsp.body(); (4)
+
+        assertNotNull(json.get("git"));
+        assertNotNull(((Map) json.get("git")).get("commit"));
+        assertNotNull(((Map) ((Map) json.get("git")).get("commit")).get("message"));
+        assertNotNull(((Map) ((Map) json.get("git")).get("commit")).get("time"));
+        assertNotNull(((Map) ((Map) json.get("git")).get("commit")).get("id"));
+        assertNotNull(((Map) ((Map) json.get("git")).get("commit")).get("user"));
+        assertNotNull(((Map) json.get("git")).get("branch"));
+    }
+}
+
+
+
+ + + + + + + + + + + + + + + + + +
1Annotate the class with @MicronautTest so the Micronaut framework will initialize the application context and the embedded server. More info.
2Inject the HttpClient bean and point it to the embedded server.
3Creating HTTP Requests is easy thanks to the Micronaut framework fluid API.
4Use .body() to retrieve the parsed payload.
+
+
+
+
+

10. Testing the Application

+
+
+

To run the tests:

+
+
+
+
./gradlew test
+
+
+
+

Then open build/reports/tests/test/index.html in a browser to see the results.

+
+
+
+
+

11. Running the Application

+
+
+

To run the application, use the ./gradlew run command, which starts the application on port 8080.

+
+
+
+
+

12. Generate a Micronaut Application Native Executable with GraalVM

+
+
+

We will use GraalVM, the polyglot embeddable virtual machine, to generate a native executable of our Micronaut application.

+
+
+

Compiling native executables ahead of time with GraalVM improves startup time and reduces the memory footprint of JVM-based applications.

+
+
+ + + + + +
+ + +Only Java and Kotlin projects support using GraalVM’s native-image tool. Groovy relies heavily on reflection, which is only partially supported by GraalVM. +
+
+
+

12.1. GraalVM installation

+
+

The easiest way to install GraalVM on Linux or Mac is to use SDKMan.io.

+
+
+
Java 17
+
+
sdk install java 17.0.12-graal
+
+
+
+
Java 17
+
+
sdk use java 17.0.12-graal
+
+
+
+

For installation on Windows, or for manual installation on Linux or Mac, see the GraalVM Getting Started documentation.

+
+
+

The previous command installs Oracle GraalVM, which is free to use in production and free to redistribute, at no cost, under the GraalVM Free Terms and Conditions.

+
+
+

Alternatively, you can use the GraalVM Community Edition:

+
+
+
Java 17
+
+
sdk install java 17.0.9-graalce
+
+
+
+
Java 17
+
+
sdk use java 17.0.9-graalce
+
+
+
+
+

12.2. Native executable generation

+
+

To generate a native executable using Gradle, run:

+
+
+
+
./gradlew nativeCompile
+
+
+
+

The native executable is created in build/native/nativeCompile directory and can be run with build/native/nativeCompile/micronautguide.

+
+
+

It is possible to customize the name of the native executable or pass additional parameters to GraalVM:

+
+
+
build.gradle
+
+
graalvmNative {
+    binaries {
+        main {
+            imageName.set('mn-graalvm-application') (1)
+            buildArgs.add('--verbose') (2)
+        }
+    }
+}
+
+
+
+ + + + + + + + + +
1The native executable name will now be mn-graalvm-application
2It is possible to pass extra arguments to build the native executable
+
+
+

Annotate the Application class with @Introspected. This won’t be necessary in a real world application because there +will be Micronaut beans defined (something annotated with @Singleton, @Controller,…​), but for this case we need to +annotate a class so the visitor that generates the GraalVM resource-config.json file is triggered:

+
+
+
src/main/java/example/micronaut/Application.java
+
+
package example.micronaut;
+
+import io.micronaut.core.annotation.Introspected;
+import io.micronaut.runtime.Micronaut;
+
+@Introspected
+public class Application {
+
+    public static void main(String[] args) {
+        Micronaut.run(Application.class, args);
+    }
+}
+
+
+
+

The git.properties file that is generated by the gradle-git-properties plugin +will not be accessible from the native executable unless access to the file is +configured in resource-config.json:

+
+
+
src/main/resources/META-INF/native-image/resource-config.json
+
+
{
+  "resources": [
+    {"pattern":"\\Qgit.properties\\E"}
+  ]
+}
+
+
+
+

You can execute the info endpoint exposed by the native executable:

+
+
+
+
curl localhost:8080/info
+
+
+
+
+
{"git":{"dirty":"true","total":{"commit":{"count":"45"}},"build":{"host":"Sergios-iMac-Pro.local","time":"2019-12-09T09:35:30+0100","user":{"name":"Sergio del Amo","email":"sergio.delamo@softamo.com"},"version":"0.1"},"commit":{"time":"2019-12-09T09:30:41+0100","id":"af3cff433d247fd4c2d8c54ae200108e98adfb2a","message":{"short":"add help section","full":"add help section\n"},"user":{"name":"Sergio del Amo","email":"sergio.delamo@softamo.com"}},"remote":{"origin":{"url":"git@github.com:micronaut-guides/adding-commit-info.git"}},"branch":"master"}}
+
+
+
+
+
+
+

13. Next steps

+
+
+

Explore more features with Micronaut Guides.

+
+
+
+
+

14. Help with the Micronaut Framework

+
+
+

The Micronaut Foundation sponsored the creation of this Guide. A variety of consulting and support services are available.

+
+
+
+
+

15. License

+
+
+ + + + + +
+ + +All guides are released with an Apache license 2.0 license for the code and a Creative Commons Attribution 4.0 license for the writing and media (images…​). +
+
+
+
+
+ + \ No newline at end of file diff --git a/buildSrc/src/test/resources/adding-commit-info-gradle-java.adoc b/buildSrc/src/test/resources/adding-commit-info-gradle-java.adoc new file mode 100644 index 00000000000..9e3f85bd39e --- /dev/null +++ b/buildSrc/src/test/resources/adding-commit-info-gradle-java.adoc @@ -0,0 +1,334 @@ +// Start: src/docs/common/snippets/common-header-top.adoc += Adding Commit Info to your Micronaut Application + +Expose the exact version of code that your application is running. + +Authors: Sergio del Amo + +Micronaut Version: 4.6.3 +// End: src/docs/common/snippets/common-header-top.adoc + +In this guide, we will add git commit info to your Micronaut build artifacts and running application. There are many benefits of keeping your commit info handy: + +* Commit info is encapsulated within the built artifacts + +* Fast authoritative means of identifying what specific code is running in an environment + +* This solution doesn't rely on external tracking mechanisms + +* Transparency and reproducibility when investigating issues + +// Start: src/docs/common/snippets/common-gettingStarted.adoc +== Getting Started + +In this guide, we will create a Micronaut application written in Java. +// End: src/docs/common/snippets/common-gettingStarted.adoc + +// Start: src/docs/common/snippets/common-requirements.adoc +== What you will need + +To complete this guide, you will need the following: + +* Some time on your hands +* A decent text editor or IDE (e.g. https://guides.micronaut.io/latest/micronaut-intellij-idea-ide-setup.html[IntelliJ IDEA]) +* JDK 17 or greater installed with `JAVA_HOME` https://www.baeldung.com/java-home-on-windows-7-8-10-mac-os-x-linux[configured appropriately] +// End: src/docs/common/snippets/common-requirements.adoc + +// Start: src/docs/common/snippets/common-completesolution.adoc +== Solution + +We recommend that you follow the instructions in the next sections and create the application step by step. However, you can go right to the **completed example**. + +* link:adding-commit-info-gradle-java.zip[Download] and unzip the source +// End: src/docs/common/snippets/common-completesolution.adoc + +NOTE: Before running the downloaded project, follow the steps described in the *Initialize Git Repository* section below. + +// Start: src/docs/common/snippets/common-create-app.adoc +== Writing the Application + +// Start: src/docs/common/snippets/common-cli-or-launch.adoc +Create an application using the https://docs.micronaut.io/latest/guide/#cli[Micronaut Command Line Interface] or with https://launch.micronaut.io[Micronaut Launch]. +// End: src/docs/common/snippets/common-cli-or-launch.adoc + +[source,bash] +---- +mn create-app example.micronaut.micronautguide --build=gradle --lang=java +---- + +// Start: src/docs/common/snippets/common-build-lang-arguments.adoc +NOTE: If you don't specify the `--build` argument, Gradle with the https://docs.gradle.org/current/userguide/kotlin_dsl.html[Kotlin DSL] is used as the build tool. +++
+++ If you don't specify the `--lang` argument, Java is used as the language.+++
+++ If you don't specify the `--test` argument, JUnit is used for Java and Kotlin, and Spock is used for Groovy. +// End: src/docs/common/snippets/common-build-lang-arguments.adoc + +// Start: src/docs/common/snippets/common-default-package.adoc +The previous command creates a Micronaut application with the default package `example.micronaut` in a directory named `micronautguide`. +// End: src/docs/common/snippets/common-default-package.adoc + +https://guides.micronaut.io/latest/micronaut-intellij-idea-ide-setup.html[Setup IntelliJ IDEA to develop Micronaut Applications]. +// End: src/docs/common/snippets/common-create-app.adoc + +== Initialize Git Repository + +The project aims to demonstrate how to provide Git commit information to the +`/info` endpoint and in order for that to work the project needs to be in a Git repository. After creating the project, initialize a Git repository from the root of the newly created project: + +[source,bash] +---- +cd micronautguide +git init +git add . +git commit -am "Initial project" +---- + +== Management + +Inspired by Spring Boot and Grails, the Micronaut management dependency adds support for monitoring of your application via endpoints: special URIs that return details about the health and state of your application. + +To use the management features described in this section, add the dependency on your classpath. + +[source, groovy] +.build.gradle +---- +implementation("io.micronaut:micronaut-management") +---- + +== Info endpoint + +> The info endpoint returns static information from the state of the application. The info exposed can be provided by any number of "info sources". + +Enable the info endpoint: + +// Start: src/docs/common/snippets/common-yaml-dependency.adoc +WARNING: https://micronaut.io/2023/02/19/micronaut-framework-4-0-and-snakeyaml-transitive-dependency/[Since Micronaut Framework 4.0, to use YAML configuration, you have to add the YAML dependency]. +// End: src/docs/common/snippets/common-yaml-dependency.adoc + +[source,yaml] +.src/main/resources/application.yml +---- +include::{sourceDir}/adding-commit-info/adding-commit-info-gradle-java/src/main/resources/application.yml[tag=endpoints] + +---- + + +== Gradle Git Properties Plugin + + +If a `git.properties` file is available on the classpath, the https://docs.micronaut.io/latest/api/io/micronaut/management/endpoint/info/source/GitInfoSource.html[GitInfoSource] will expose the values in that file under the `git` key. Generation of a `git.properties` file will need to be configured as part of your build. + + +For example, you may choose to use the https://plugins.gradle.org/plugin/com.gorylenko.gradle-git-properties[Gradle Git Properties] plugin. The plugin provides a task named `generateGitProperties` responsible for the `git.properties` file generation. It is automatically invoked upon the execution of the `classes` task. You can find the generated file in the directory `build/resources/main`. + +Modify `build.gradle` file to add the plugin: + +[source,groovy] +.build.gradle +---- +plugins { + id "com.gorylenko.gradle-git-properties" version "2.3.2" +} +---- + + + +== Test + +Create a JUnit test to verify that when you make a GET request to `/info` you get a payload such as: + +[source, json] +---- +{ + "git": { + "dirty": "true", + "commit": { + "id": "7368906193527fbf2b45f1ed5b08c56631f5b155", + "describe": "7368906-dirty", + "time": "1527429126", + "message": { + "short": "Initial version", + "full": "Initial version" + }, + "user": { + "name": "sdelamo", + "email": "sergio.delamo@softamo.com" + } + }, + "branch": "master" + } +} +---- + +Create a JUnit test to verify the behaviour: + +[source,java] +.src/test/java/example/micronaut/InfoTest.java +---- +include::{sourceDir}/adding-commit-info/adding-commit-info-gradle-java/src/test/java/example/micronaut/InfoTest.java[lines=16..-1] +---- + +<1> Annotate the class with `@MicronautTest` so the Micronaut framework will initialize the application context and the embedded server. https://micronaut-projects.github.io/micronaut-test/latest/guide/[More info]. +<2> Inject the `HttpClient` bean and point it to the embedded server. +<3> Creating HTTP Requests is easy thanks to the Micronaut framework fluid API. +<4> Use `.body()` to retrieve the parsed payload. + +// Start: src/docs/common/snippets/common-testApp.adoc +== Testing the Application + +// Start: src/docs/common/snippets/common-testApp-noheader.adoc +To run the tests: + + +[source, bash] +---- +./gradlew test +---- + +Then open `build/reports/tests/test/index.html` in a browser to see the results. + + +// End: src/docs/common/snippets/common-testApp-noheader.adoc +// End: src/docs/common/snippets/common-testApp.adoc + +// Start: src/docs/common/snippets/common-runapp.adoc +== Running the Application + +// Start: src/docs/common/snippets/common-runapp-instructions.adoc + +To run the application, use the `./gradlew run` command, which starts the application on port 8080. + + +// End: src/docs/common/snippets/common-runapp-instructions.adoc +// End: src/docs/common/snippets/common-runapp.adoc + +// Start: src/docs/common/snippets/common-graal-with-plugins.adoc + +== Generate a Micronaut Application Native Executable with GraalVM + +We will use https://www.graalvm.org/[GraalVM], the polyglot embeddable virtual machine, to generate a native executable of our Micronaut application. + +Compiling native executables ahead of time with GraalVM improves startup time and reduces the memory footprint of JVM-based applications. + +NOTE: Only Java and Kotlin projects support using GraalVM's `native-image` tool. Groovy relies heavily on reflection, which is only partially supported by GraalVM. + +=== GraalVM installation + +// Start: src/docs/common/snippets/common-install-graalvm-sdkman.adoc +The easiest way to install https://www.graalvm.org[GraalVM] on Linux or Mac is to use https://sdkman.io/[SDKMan.io]. + +[source, bash] +.Java 17 +---- +sdk install java 17.0.12-graal +---- + +[source, bash] +.Java 17 +---- +sdk use java 17.0.12-graal +---- + +For installation on Windows, or for manual installation on Linux or Mac, see the https://www.graalvm.org/latest/docs/getting-started/[GraalVM Getting Started] documentation. + + +The previous command installs Oracle GraalVM, which is free to use in production and free to redistribute, at no cost, under the https://www.oracle.com/downloads/licenses/graal-free-license.html[GraalVM Free Terms and Conditions]. + +Alternatively, you can use the https://github.com/graalvm/graalvm-ce-builds/releases/[GraalVM Community Edition]: + +[source, bash] +.Java 17 +---- +sdk install java 17.0.9-graalce +---- + +[source, bash] +.Java 17 +---- +sdk use java 17.0.9-graalce +---- + + +// End: src/docs/common/snippets/common-install-graalvm-sdkman.adoc + +=== Native executable generation + + +To generate a native executable using Gradle, run: + +[source, bash] +---- +./gradlew nativeCompile +---- + +The native executable is created in `build/native/nativeCompile` directory and can be run with `build/native/nativeCompile/micronautguide`. + +It is possible to customize the name of the native executable or pass additional parameters to GraalVM: + +.build.gradle +[source,groovy] +---- +graalvmNative { + binaries { + main { + imageName.set('mn-graalvm-application') // <1> + buildArgs.add('--verbose') // <2> + } + } +} +---- +<1> The native executable name will now be `mn-graalvm-application` +<2> It is possible to pass extra arguments to build the native executable + + + +// End: src/docs/common/snippets/common-graal-with-plugins.adoc + + +Annotate the `Application` class with `@Introspected`. This won't be necessary in a real world application because there +will be Micronaut beans defined (something annotated with `@Singleton`, `@Controller`,...), but for this case we need to +annotate a class so the visitor that generates the GraalVM `resource-config.json` file is triggered: + +[source,java] +.src/main/java/example/micronaut/Application.java +---- +include::{sourceDir}/adding-commit-info/adding-commit-info-gradle-java/src/main/java/example/micronaut/Application.java[lines=16..-1] +---- + +The `git.properties` file that is generated by the `gradle-git-properties` plugin +will not be accessible from the native executable unless access to the file is +configured in `resource-config.json`: + +[source,json] +.src/main/resources/META-INF/native-image/resource-config.json +---- +include::{sourceDir}/adding-commit-info/adding-commit-info-gradle-java/src/main/resources/META-INF/native-image/resource-config.json[] +---- + +You can execute the `info` endpoint exposed by the native executable: + +[source, bash] +---- +curl localhost:8080/info +---- + +[source,json] +---- +{"git":{"dirty":"true","total":{"commit":{"count":"45"}},"build":{"host":"Sergios-iMac-Pro.local","time":"2019-12-09T09:35:30+0100","user":{"name":"Sergio del Amo","email":"sergio.delamo@softamo.com"},"version":"0.1"},"commit":{"time":"2019-12-09T09:30:41+0100","id":"af3cff433d247fd4c2d8c54ae200108e98adfb2a","message":{"short":"add help section","full":"add help section\n"},"user":{"name":"Sergio del Amo","email":"sergio.delamo@softamo.com"}},"remote":{"origin":{"url":"git@github.com:micronaut-guides/adding-commit-info.git"}},"branch":"master"}} +---- + + +// Start: src/docs/common/snippets/common-next.adoc +== Next steps + +Explore more features with https://micronaut.io/guides/[Micronaut Guides]. +// End: src/docs/common/snippets/common-next.adoc + +// Start: src/docs/common/snippets/common-helpWithMicronaut.adoc +== Help with the Micronaut Framework + +The https://micronaut.io/foundation/[Micronaut Foundation] sponsored the creation of this Guide. A variety of https://micronaut.io/commercial-support/[consulting and support services] are available. +// End: src/docs/common/snippets/common-helpWithMicronaut.adoc + +// Start: src/docs/common/snippets/common-license.adoc +== License + +NOTE: All guides are released with an https://www.apache.org/licenses/LICENSE-2.0[Apache license 2.0 license] for the code and a https://creativecommons.org/licenses/by/4.0/deed.en[Creative Commons Attribution 4.0] license for the writing and media (images...). +// End: src/docs/common/snippets/common-license.adoc \ No newline at end of file diff --git a/buildSrc/src/test/resources/application-test.yml b/buildSrc/src/test/resources/application-test.yml new file mode 100644 index 00000000000..62d70460bec --- /dev/null +++ b/buildSrc/src/test/resources/application-test.yml @@ -0,0 +1,5 @@ +asciidoc: + source-dir: "build/tmp/test" + commons-dir: "src/test/resources/asciidoc" + base-dir: "." + guides-dir: "src/test/resources/other-guides" \ No newline at end of file diff --git a/buildSrc/src/test/resources/asciidoc/callout.adoc b/buildSrc/src/test/resources/asciidoc/callout.adoc new file mode 100644 index 00000000000..c92583d4b65 --- /dev/null +++ b/buildSrc/src/test/resources/asciidoc/callout.adoc @@ -0,0 +1 @@ +<.> The class is defined as a controller with the @api@/io/micronaut/http/annotation/Controller.html[@Controller] annotation mapped to the path `{0}`. diff --git a/buildSrc/src/test/resources/asciidoc/common-docker-mysql-arm.adoc b/buildSrc/src/test/resources/asciidoc/common-docker-mysql-arm.adoc new file mode 100644 index 00000000000..a82d74d9fc8 --- /dev/null +++ b/buildSrc/src/test/resources/asciidoc/common-docker-mysql-arm.adoc @@ -0,0 +1 @@ +TIP: If you are using macOS on Apple Silicon – e.g. M1, M1 Pro, etc. – Docker might fail to pull an image for `mysql:8`. In that case substitute `mysql:oracle`. diff --git a/buildSrc/src/test/resources/asciidoc/common-header-top.adoc b/buildSrc/src/test/resources/asciidoc/common-header-top.adoc new file mode 100644 index 00000000000..dc6e61f6678 --- /dev/null +++ b/buildSrc/src/test/resources/asciidoc/common-header-top.adoc @@ -0,0 +1,9 @@ += @guideTitle@ + +@guideIntro@ + +Authors: @authors@ + +Micronaut Version: @micronaut@ + +include::common-run-mysql-container.adoc[] \ No newline at end of file diff --git a/buildSrc/src/test/resources/asciidoc/common-run-mysql-container.adoc b/buildSrc/src/test/resources/asciidoc/common-run-mysql-container.adoc new file mode 100644 index 00000000000..feb5335a8da --- /dev/null +++ b/buildSrc/src/test/resources/asciidoc/common-run-mysql-container.adoc @@ -0,0 +1,14 @@ +Execute the following command to run a MySQL container: + +[source,bash] +---- +docker run -it --rm \ + -p 3306:3306 \ + -e MYSQL_DATABASE=db \ + -e MYSQL_USER=sherlock \ + -e MYSQL_PASSWORD=elementary \ + -e MYSQL_ALLOW_EMPTY_PASSWORD=true \ + mysql:8 +---- + +include::common-docker-mysql-arm.adoc[] diff --git a/buildSrc/src/test/resources/asciidoc/export-repository.adoc b/buildSrc/src/test/resources/asciidoc/export-repository.adoc new file mode 100644 index 00000000000..4941d0fa23f --- /dev/null +++ b/buildSrc/src/test/resources/asciidoc/export-repository.adoc @@ -0,0 +1,6 @@ +Export {arg} microservice image repository to the `{arg_U}_REPOSITORY` environment variable. + +[source,bash,subs="attributes+"] +---- +export {arg_U}_REPOSITORY="gcr.io/$GCP_PROJECT_ID/{arg}" +---- diff --git a/buildSrc/src/test/resources/other-guides/adding-commit-info/adding-commit-info.adoc b/buildSrc/src/test/resources/other-guides/adding-commit-info/adding-commit-info.adoc new file mode 100644 index 00000000000..1b51435dfa7 --- /dev/null +++ b/buildSrc/src/test/resources/other-guides/adding-commit-info/adding-commit-info.adoc @@ -0,0 +1,50 @@ +// equivalent of common: +include::{commonsDir}/common-header-top.adoc[] + +// equivalent of external-template: +:arg: users +:arg_U: USERS +include::{commonsDir}/export-repository.adoc[] + +// equivalent of callout: +:0: dir/path/example.txt +include::{commonsDir}/callout.adoc[] +include::{commonsDir}/callout.adoc[] +include::{commonsDir}/callout.adoc[] + +// equivalent of external: +include::{guidesDir}/test/test.adoc[] + +In this guide, we will add git commit info to your Micronaut build artifacts and running application. +There are many benefits of keeping your commit info handy: + +* Commit info is encapsulated within the built artifacts + +* Fast authoritative means of identifying what specific code is running in an environment + +* This solution doesn't rely on external tracking mechanisms + +* Transparency and reproducibility when investigating issues + +NOTE: Before running the downloaded project, follow the steps described in the *Initialize Git Repository* section below. + +== Initialize Git Repository + +The project aims to demonstrate how to provide Git commit information to the +`/info` endpoint and in order for that to work the project needs to be in a Git repository. +After creating the project, initialize a Git repository from the root of the newly created project: + +[source,bash] +---- +cd micronautguide +git init +git add . +git commit -am "Initial project" +---- + +== Management + +Inspired by Spring Boot and Grails, the Micronaut management dependency adds support for monitoring of your application via endpoints: special URIs that return details about the health and state of your application. + +To use the management features described in this section, add the dependency on your classpath. + diff --git a/buildSrc/src/test/resources/other-guides/adding-commit-info/groovy/src/main/resources/application.yml b/buildSrc/src/test/resources/other-guides/adding-commit-info/groovy/src/main/resources/application.yml new file mode 100644 index 00000000000..4de862c19fe --- /dev/null +++ b/buildSrc/src/test/resources/other-guides/adding-commit-info/groovy/src/main/resources/application.yml @@ -0,0 +1,11 @@ +micronaut: + application: + name: micronautguide +--- +#tag::endpoints[] +endpoints: + info: + enabled: true + sensitive: false +#end::endpoints[] + diff --git a/buildSrc/src/test/resources/other-guides/adding-commit-info/groovy/src/test/groovy/example/micronaut/InfoSpec.groovy b/buildSrc/src/test/resources/other-guides/adding-commit-info/groovy/src/test/groovy/example/micronaut/InfoSpec.groovy new file mode 100644 index 00000000000..6de773a87a6 --- /dev/null +++ b/buildSrc/src/test/resources/other-guides/adding-commit-info/groovy/src/test/groovy/example/micronaut/InfoSpec.groovy @@ -0,0 +1,57 @@ +/* + * 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.HttpResponse +import io.micronaut.http.client.HttpClient +import io.micronaut.http.client.annotation.Client +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import spock.lang.Shared +import spock.lang.Specification +import jakarta.inject.Inject + +@MicronautTest // <1> +class InfoSpec extends Specification { + + @Shared + @Client("/") + @Inject + HttpClient client // <2> + + void 'test git commit info appears in JSON'() { + given: + HttpRequest request = HttpRequest.GET('/info') // <3> + + when: + HttpResponse rsp = client.toBlocking().exchange(request, Map) + + then: + rsp.status().code == 200 + + when: + Map json = rsp.body() // <4> + + then: + json.git + json.git.commit + json.git.commit.message + json.git.commit.time + json.git.commit.id + json.git.commit.user + json.git.branch + } +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/other-guides/adding-commit-info/java/src/main/java/example/micronaut/Application.java b/buildSrc/src/test/resources/other-guides/adding-commit-info/java/src/main/java/example/micronaut/Application.java new file mode 100644 index 00000000000..9adbc4df99d --- /dev/null +++ b/buildSrc/src/test/resources/other-guides/adding-commit-info/java/src/main/java/example/micronaut/Application.java @@ -0,0 +1,27 @@ +/* + * 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.core.annotation.Introspected; +import io.micronaut.runtime.Micronaut; + +@Introspected +public class Application { + + public static void main(String[] args) { + Micronaut.run(Application.class, args); + } +} diff --git a/buildSrc/src/test/resources/other-guides/adding-commit-info/java/src/main/resources/META-INF/native-image/resource-config.json b/buildSrc/src/test/resources/other-guides/adding-commit-info/java/src/main/resources/META-INF/native-image/resource-config.json new file mode 100644 index 00000000000..b96fbfa673c --- /dev/null +++ b/buildSrc/src/test/resources/other-guides/adding-commit-info/java/src/main/resources/META-INF/native-image/resource-config.json @@ -0,0 +1,5 @@ +{ + "resources": [ + {"pattern":"\\Qgit.properties\\E"} + ] +} diff --git a/buildSrc/src/test/resources/other-guides/adding-commit-info/java/src/main/resources/application.yml b/buildSrc/src/test/resources/other-guides/adding-commit-info/java/src/main/resources/application.yml new file mode 100644 index 00000000000..4de862c19fe --- /dev/null +++ b/buildSrc/src/test/resources/other-guides/adding-commit-info/java/src/main/resources/application.yml @@ -0,0 +1,11 @@ +micronaut: + application: + name: micronautguide +--- +#tag::endpoints[] +endpoints: + info: + enabled: true + sensitive: false +#end::endpoints[] + diff --git a/buildSrc/src/test/resources/other-guides/adding-commit-info/java/src/test/java/example/micronaut/InfoTest.java b/buildSrc/src/test/resources/other-guides/adding-commit-info/java/src/test/java/example/micronaut/InfoTest.java new file mode 100644 index 00000000000..687ca35e921 --- /dev/null +++ b/buildSrc/src/test/resources/other-guides/adding-commit-info/java/src/test/java/example/micronaut/InfoTest.java @@ -0,0 +1,56 @@ +/* + * 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.HttpResponse; +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; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@MicronautTest // <1> +public class InfoTest { + + @Inject + @Client("/") + HttpClient client; // <2> + + @Test + public void testGitComitInfoAppearsInJson() { + HttpRequest request = HttpRequest.GET("/info"); // <3> + + HttpResponse rsp = client.toBlocking().exchange(request, Map.class); + + assertEquals(200, rsp.status().getCode()); + + Map json = rsp.body(); // <4> + + assertNotNull(json.get("git")); + assertNotNull(((Map) json.get("git")).get("commit")); + assertNotNull(((Map) ((Map) json.get("git")).get("commit")).get("message")); + assertNotNull(((Map) ((Map) json.get("git")).get("commit")).get("time")); + assertNotNull(((Map) ((Map) json.get("git")).get("commit")).get("id")); + assertNotNull(((Map) ((Map) json.get("git")).get("commit")).get("user")); + assertNotNull(((Map) json.get("git")).get("branch")); + } +} diff --git a/buildSrc/src/test/resources/other-guides/adding-commit-info/kotlin/src/main/kotlin/example/micronaut/Application.kt b/buildSrc/src/test/resources/other-guides/adding-commit-info/kotlin/src/main/kotlin/example/micronaut/Application.kt new file mode 100644 index 00000000000..606bf8e4ac9 --- /dev/null +++ b/buildSrc/src/test/resources/other-guides/adding-commit-info/kotlin/src/main/kotlin/example/micronaut/Application.kt @@ -0,0 +1,33 @@ +/* + * 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.core.annotation.Introspected +import io.micronaut.runtime.Micronaut.* + +@Introspected +class ApplicationKt { + + companion object { + @JvmStatic + fun main(args: Array) { + build() + .args(*args) + .packages("example.micronaut") + .start() + } + } +} diff --git a/buildSrc/src/test/resources/other-guides/adding-commit-info/kotlin/src/main/resources/META-INF/native-image/resource-config.json b/buildSrc/src/test/resources/other-guides/adding-commit-info/kotlin/src/main/resources/META-INF/native-image/resource-config.json new file mode 100644 index 00000000000..b96fbfa673c --- /dev/null +++ b/buildSrc/src/test/resources/other-guides/adding-commit-info/kotlin/src/main/resources/META-INF/native-image/resource-config.json @@ -0,0 +1,5 @@ +{ + "resources": [ + {"pattern":"\\Qgit.properties\\E"} + ] +} diff --git a/buildSrc/src/test/resources/other-guides/adding-commit-info/kotlin/src/main/resources/application.yml b/buildSrc/src/test/resources/other-guides/adding-commit-info/kotlin/src/main/resources/application.yml new file mode 100644 index 00000000000..4de862c19fe --- /dev/null +++ b/buildSrc/src/test/resources/other-guides/adding-commit-info/kotlin/src/main/resources/application.yml @@ -0,0 +1,11 @@ +micronaut: + application: + name: micronautguide +--- +#tag::endpoints[] +endpoints: + info: + enabled: true + sensitive: false +#end::endpoints[] + diff --git a/buildSrc/src/test/resources/other-guides/adding-commit-info/kotlin/src/test/kotlin/example/micronaut/InfoTest.kt b/buildSrc/src/test/resources/other-guides/adding-commit-info/kotlin/src/test/kotlin/example/micronaut/InfoTest.kt new file mode 100644 index 00000000000..1691566b056 --- /dev/null +++ b/buildSrc/src/test/resources/other-guides/adding-commit-info/kotlin/src/test/kotlin/example/micronaut/InfoTest.kt @@ -0,0 +1,42 @@ +/* + * 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 InfoTest { + @Inject + @field:Client("/") + lateinit var client : HttpClient // <2> + + @Test + fun testGitComitInfoAppearsInJson() { + val request: HttpRequest<*> = HttpRequest.GET("/info") // <3> + val rsp = client.toBlocking().exchange(request, Map::class.java) + assertEquals(200, rsp.status().code) + val info = rsp.body() // <4> + assertNotNull(info) + assertNotNull(info.get("git")) + } +} \ No newline at end of file diff --git a/buildSrc/src/test/resources/other-guides/adding-commit-info/metadata.json b/buildSrc/src/test/resources/other-guides/adding-commit-info/metadata.json new file mode 100644 index 00000000000..8b56672fc2c --- /dev/null +++ b/buildSrc/src/test/resources/other-guides/adding-commit-info/metadata.json @@ -0,0 +1,14 @@ +{ + "title": "Adding Commit Info to your Micronaut Application", + "intro": "Expose the exact version of code that your application is running.", + "authors": ["Sergio del Amo"], + "tags": ["git"], + "categories": ["Development"], + "publicationDate": "2018-05-24", + "apps": [ + { + "name": "default", + "features": ["yaml", "management","git-properties"] + } + ] +} diff --git a/buildSrc/src/test/resources/other-guides/test/test.adoc b/buildSrc/src/test/resources/other-guides/test/test.adoc new file mode 100644 index 00000000000..8318c86b357 --- /dev/null +++ b/buildSrc/src/test/resources/other-guides/test/test.adoc @@ -0,0 +1 @@ +Test \ No newline at end of file