diff --git a/bom/application/pom.xml b/bom/application/pom.xml index da639f1df03f1..2f9bbc899fe89 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -90,7 +90,8 @@ 3.12.0 1.15 1.5.1 - 5.6.5.Final + 5.6.5.Final + 1.12.7 1.1.2.Final 6.2.1.Final 6.1.0.Final @@ -117,7 +118,7 @@ 9.1.6 2.3.2 1.4.197 - 42.3.1 + 42.3.2 2.7.5 8.0.28 7.2.2.jre8 @@ -787,6 +788,16 @@ quarkus-oidc-token-propagation-deployment ${project.version} + + io.quarkus + quarkus-oidc-token-propagation-reactive + ${project.version} + + + io.quarkus + quarkus-oidc-token-propagation-reactive-deployment + ${project.version} + io.quarkus quarkus-oidc-common @@ -2683,6 +2694,15 @@ + + + net.bytebuddy + byte-buddy + ${bytebuddy.version} + + com.google.code.findbugs diff --git a/core/deployment/src/main/java/io/quarkus/deployment/Feature.java b/core/deployment/src/main/java/io/quarkus/deployment/Feature.java index 6ee0fb5649785..037e6627a74a3 100644 --- a/core/deployment/src/main/java/io/quarkus/deployment/Feature.java +++ b/core/deployment/src/main/java/io/quarkus/deployment/Feature.java @@ -68,6 +68,7 @@ public enum Feature { OIDC_CLIENT_FILTER, OIDC_CLIENT_REACTIVE_FILTER, OIDC_TOKEN_PROPAGATION, + OIDC_TOKEN_PROPAGATION_REACTIVE, OPENSHIFT_CLIENT, OPENTELEMETRY, OPENTELEMETRY_JAEGER_EXPORTER, diff --git a/core/runtime/src/main/java/io/quarkus/runtime/MockedThroughWrapper.java b/core/runtime/src/main/java/io/quarkus/runtime/MockedThroughWrapper.java new file mode 100644 index 0000000000000..1cf124ccb6f20 --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/MockedThroughWrapper.java @@ -0,0 +1,11 @@ +package io.quarkus.runtime; + +/** + * Usually, QuarkusMock mocking replaces a "delegating instance" of a client proxy. + * + * In some cases, e.g. for REST Client Reactive, a CDI bean is a wrapper over a delegate. + * This interface allows to replace the delegate instead of the delegating instance of the proxy. + */ +public interface MockedThroughWrapper { + void setMock(Object mock); +} diff --git a/devtools/bom-descriptor-json/pom.xml b/devtools/bom-descriptor-json/pom.xml index 475c041b7053b..818ab4968bd3e 100644 --- a/devtools/bom-descriptor-json/pom.xml +++ b/devtools/bom-descriptor-json/pom.xml @@ -1475,6 +1475,19 @@ + + io.quarkus + quarkus-oidc-token-propagation-reactive + ${project.version} + pom + test + + + * + * + + + io.quarkus quarkus-openshift diff --git a/devtools/cli/distribution/jreleaser.yml b/devtools/cli/distribution/jreleaser.yml index 8ee5a9c853574..45836bd4e85a4 100644 --- a/devtools/cli/distribution/jreleaser.yml +++ b/devtools/cli/distribution/jreleaser.yml @@ -8,6 +8,7 @@ project: authors: - Quarkus Community license: Apache-2.0 + licenseUrl: https://github.com/quarkusio/quarkus/blob/main/LICENSE.txt copyright: Quarkus contributors java: groupId: io.quarkus diff --git a/devtools/cli/distribution/release-cli.sh b/devtools/cli/distribution/release-cli.sh index 9b3eef5129879..ae02ef50e1971 100755 --- a/devtools/cli/distribution/release-cli.sh +++ b/devtools/cli/distribution/release-cli.sh @@ -6,6 +6,13 @@ then exit 1 fi +BRANCH=$2 +if [ -z "$BRANCH" ] +then + echo "Must specify Quarkus branch" + exit 1 +fi + DIST_DIR="$( dirname "${BASH_SOURCE[0]}" )" pushd ${DIST_DIR} @@ -35,9 +42,10 @@ tar -zcf ${JAVA_BINARY_DIR}.tar.gz ${JAVA_BINARY_DIR} popd export JRELEASER_PROJECT_VERSION=${VERSION} -export JRELEASER_BRANCH=main +export JRELEASER_BRANCH=${BRANCH} +export JRELEASER_CHOCOLATEY_GITHUB_BRANCH=${BRANCH} -jbang jreleaser@jreleaser full-release \ +jbang org.jreleaser:jreleaser:1.0.0-M1 full-release \ --git-root-search \ -od target diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/QuarkusPlugin.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/QuarkusPlugin.java index 2a801469594d4..a914d10adea28 100644 --- a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/QuarkusPlugin.java +++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/QuarkusPlugin.java @@ -205,7 +205,10 @@ public void execute(Task test) { quarkusGenerateCodeTests); task.setQuarkusDevConfiguration(devModeConfiguration); }); - quarkusRemoteDev.configure(task -> task.dependsOn(classesTask, resourcesTask)); + quarkusRemoteDev.configure(task -> { + task.dependsOn(classesTask, resourcesTask); + task.setQuarkusDevConfiguration(devModeConfiguration); + }); quarkusTest.configure(task -> { task.dependsOn(classesTask, resourcesTask, testClassesTask, testResourcesTask, quarkusGenerateCode, diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusDev.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusDev.java index 4bafefa782f24..f63a7a69bbd78 100644 --- a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusDev.java +++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusDev.java @@ -19,7 +19,6 @@ import org.gradle.api.GradleException; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.ProjectDependency; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.plugins.JavaPluginExtension; @@ -28,8 +27,6 @@ import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputDirectory; import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.SourceSet; -import org.gradle.api.tasks.SourceSetContainer; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.compile.JavaCompile; import org.gradle.api.tasks.options.Option; @@ -39,11 +36,15 @@ import org.gradle.util.GradleVersion; import io.quarkus.bootstrap.BootstrapConstants; +import io.quarkus.bootstrap.devmode.DependenciesFilter; import io.quarkus.bootstrap.model.ApplicationModel; +import io.quarkus.bootstrap.workspace.ArtifactSources; +import io.quarkus.bootstrap.workspace.SourceDir; import io.quarkus.deployment.dev.DevModeContext; import io.quarkus.deployment.dev.QuarkusDevModeLauncher; import io.quarkus.gradle.tooling.ToolingUtils; -import io.quarkus.maven.dependency.GACT; +import io.quarkus.maven.dependency.ArtifactKey; +import io.quarkus.maven.dependency.ResolvedDependency; import io.quarkus.paths.PathList; import io.quarkus.runtime.LaunchMode; @@ -261,8 +262,11 @@ private QuarkusDevModeLauncher newLauncher() throws Exception { builder.sourceEncoding(getSourceEncoding()); final ApplicationModel appModel = extension().getApplicationModel(LaunchMode.DEVELOPMENT); - final Set projectDependencies = new HashSet<>(); - addSelfWithLocalDeps(project, builder, new HashSet<>(), projectDependencies, true); + final Set projectDependencies = new HashSet<>(); + for (ResolvedDependency localDep : DependenciesFilter.getReloadableModules(appModel)) { + addLocalProject(localDep, builder, projectDependencies, appModel.getAppArtifact().getWorkspaceModule().getId() + .equals(localDep.getWorkspaceModule().getId())); + } for (io.quarkus.maven.dependency.ResolvedDependency artifact : appModel.getDependencies()) { //we only use the launcher for launching from the IDE, we need to exclude it @@ -270,8 +274,7 @@ private QuarkusDevModeLauncher newLauncher() throws Exception { && artifact.getArtifactId().equals("quarkus-ide-launcher")) { continue; } - if (!projectDependencies - .contains(new GACT(artifact.getGroupId(), artifact.getArtifactId()))) { + if (!projectDependencies.contains(artifact.getKey())) { artifact.getResolvedPaths().forEach(p -> { if (Files.exists(p)) { if (artifact.getGroupId().equals("io.quarkus") @@ -324,143 +327,120 @@ protected void modifyDevModeContext(GradleDevModeLauncher.Builder builder) { } - private void addSelfWithLocalDeps(Project project, GradleDevModeLauncher.Builder builder, Set visited, - Set addedDeps, boolean root) { - if (!visited.add(project.getPath())) { - return; - } - final Configuration compileCp = project.getConfigurations().findByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME); - if (compileCp != null) { - compileCp.getIncoming().getDependencies().forEach(d -> { - if (d instanceof ProjectDependency) { - addSelfWithLocalDeps(((ProjectDependency) d).getDependencyProject(), builder, visited, addedDeps, false); - } - }); - } - - addLocalProject(project, builder, addedDeps, root); - } + private void addLocalProject(ResolvedDependency project, GradleDevModeLauncher.Builder builder, Set addeDeps, + boolean root) { + addeDeps.add(project.getKey()); - private void addLocalProject(Project project, GradleDevModeLauncher.Builder builder, Set addeDeps, boolean root) { - final GACT key = new GACT(project.getGroup().toString(), project.getName(), "", "jar"); - if (addeDeps.contains(key)) { - return; - } - final JavaPluginConvention javaConvention = project.getConvention().findPlugin(JavaPluginConvention.class); - if (javaConvention == null) { + final ArtifactSources sources = project.getSources(); + if (sources == null) { return; } - SourceSetContainer sourceSets = javaConvention.getSourceSets(); - SourceSet mainSourceSet = sourceSets.findByName(SourceSet.MAIN_SOURCE_SET_NAME); - if (mainSourceSet == null) { - return; - } Set sourcePaths = new LinkedHashSet<>(); Set sourceParentPaths = new LinkedHashSet<>(); - for (File sourceDir : mainSourceSet.getAllJava().getSrcDirs()) { - if (sourceDir.exists()) { - sourcePaths.add(sourceDir.toPath().toAbsolutePath()); - sourceParentPaths.add(sourceDir.toPath().getParent().toAbsolutePath()); + Path classesDir = null; + for (SourceDir src : sources.getSourceDirs()) { + if (Files.exists(src.getDir())) { + sourcePaths.add(src.getDir()); + sourceParentPaths.add(src.getDir().getParent()); + if (classesDir == null) { + classesDir = src.getOutputDir(); + } } } + final Set resourcesSrcDirs = new LinkedHashSet<>(); - for (File resourcesSrcDir : mainSourceSet.getResources().getSourceDirectories().getFiles()) { - resourcesSrcDirs.add(resourcesSrcDir.toPath().toAbsolutePath()); - } // resourcesSrcDir may exist but if it's empty the resources output dir won't be created - final File resourcesOutputDir = mainSourceSet.getOutput().getResourcesDir(); - - if (sourcePaths.isEmpty() && !resourcesOutputDir.exists()) { - return; + Path resourcesOutputDir = null; + for (SourceDir resource : sources.getResourceDirs()) { + resourcesSrcDirs.add(resource.getDir()); + if (resourcesOutputDir == null) { + resourcesOutputDir = resource.getOutputDir(); + } } - String classesDir = QuarkusGradleUtils.getClassesDir(mainSourceSet, project.getBuildDir(), false); - if (classesDir == null) { + if (sourcePaths.isEmpty() && (resourcesOutputDir == null || !Files.exists(resourcesOutputDir)) || classesDir == null) { return; - } else { - File classesDirFile = new File(classesDir); - if (!classesDirFile.exists()) { - return; - } } final String resourcesOutputPath; - if (resourcesOutputDir.exists()) { - resourcesOutputPath = resourcesOutputDir.getAbsolutePath(); - if (!Files.exists(Paths.get(classesDir))) { + if (resourcesOutputDir != null && Files.exists(resourcesOutputDir)) { + resourcesOutputPath = resourcesOutputDir.toString(); + if (!Files.exists(classesDir)) { // currently classesDir can't be null and is expected to exist - classesDir = resourcesOutputPath; + classesDir = resourcesOutputDir; } } else { // currently resources dir should exist - resourcesOutputPath = classesDir; + resourcesOutputPath = classesDir.toString(); } DevModeContext.ModuleInfo.Builder moduleBuilder = new DevModeContext.ModuleInfo.Builder() - .setArtifactKey(key) - .setName(project.getName()) - .setProjectDirectory(project.getProjectDir().getAbsolutePath()) + .setArtifactKey(project.getKey()) + .setName(project.getArtifactId()) + .setProjectDirectory(project.getWorkspaceModule().getModuleDir().getAbsolutePath()) .setSourcePaths(PathList.from(sourcePaths)) - .setClassesPath(classesDir) + .setClassesPath(classesDir.toString()) .setResourcePaths(PathList.from(resourcesSrcDirs)) .setResourcesOutputPath(resourcesOutputPath) .setSourceParents(PathList.from(sourceParentPaths)) - .setPreBuildOutputDir(project.getBuildDir().toPath().resolve("generated-sources").toAbsolutePath().toString()) - .setTargetDir(project.getBuildDir().toString()); - - SourceSet testSourceSet = sourceSets.findByName(SourceSet.TEST_SOURCE_SET_NAME); - if (testSourceSet != null) { + .setPreBuildOutputDir(project.getWorkspaceModule().getBuildDir().toPath().resolve("generated-sources") + .toAbsolutePath().toString()) + .setTargetDir(project.getWorkspaceModule().getBuildDir().toString()); + final ArtifactSources testSources = project.getWorkspaceModule().getTestSources(); + if (testSources != null) { Set testSourcePaths = new LinkedHashSet<>(); Set testSourceParentPaths = new LinkedHashSet<>(); - - for (File sourceDir : testSourceSet.getAllJava().getSrcDirs()) { - if (sourceDir.exists()) { - testSourcePaths.add(sourceDir.toPath().toAbsolutePath()); - testSourceParentPaths.add(sourceDir.toPath().getParent().toAbsolutePath()); + Path testClassesDir = null; + + for (SourceDir src : testSources.getSourceDirs()) { + if (Files.exists(src.getDir())) { + testSourcePaths.add(src.getDir()); + testSourceParentPaths.add(src.getDir().getParent()); + if (testClassesDir == null && src.getOutputDir() != null) { + testClassesDir = src.getOutputDir(); + } } } + final Set testResourcesSrcDirs = new LinkedHashSet<>(); - for (File testResourcesSrcDir : testSourceSet.getResources().getSourceDirectories().getFiles()) { - testResourcesSrcDirs.add(testResourcesSrcDir.toPath().toAbsolutePath()); - } // resourcesSrcDir may exist but if it's empty the resources output dir won't be created - final File testResourcesOutputDir = testSourceSet.getOutput().getResourcesDir(); - - if (!testSourcePaths.isEmpty() || (testResourcesOutputDir != null && testResourcesOutputDir.exists())) { - String testClassesDir = QuarkusGradleUtils.getClassesDir(testSourceSet, project.getBuildDir(), true); - if (testClassesDir != null) { - File testClassesDirFile = new File(testClassesDir); - if (testClassesDirFile.exists()) { - final String testResourcesOutputPath; - if (testResourcesOutputDir.exists()) { - testResourcesOutputPath = testResourcesOutputDir.getAbsolutePath(); - if (!Files.exists(Paths.get(testClassesDir))) { - // currently classesDir can't be null and is expected to exist - testClassesDir = testResourcesOutputPath; - } - } else { - // currently resources dir should exist - testResourcesOutputPath = testClassesDir; - } - moduleBuilder.setTestSourcePaths(PathList.from(testSourcePaths)) - .setTestClassesPath(testClassesDir) - .setTestResourcePaths(PathList.from(testResourcesSrcDirs)) - .setTestResourcesOutputPath(testResourcesOutputPath); + Path testResourcesOutputDir = null; + for (SourceDir resource : testSources.getResourceDirs()) { + testResourcesSrcDirs.add(resource.getDir()); + if (testResourcesOutputDir == null) { + testResourcesOutputDir = resource.getOutputDir(); + } + } + + if (testClassesDir != null && (!testSourcePaths.isEmpty() + || (testResourcesOutputDir != null && Files.exists(testResourcesOutputDir)))) { + final String testResourcesOutputPath; + if (Files.exists(testResourcesOutputDir)) { + testResourcesOutputPath = testResourcesOutputDir.toString(); + if (!Files.exists(testClassesDir)) { + // currently classesDir can't be null and is expected to exist + testClassesDir = testResourcesOutputDir; } + } else { + // currently resources dir should exist + testResourcesOutputPath = testClassesDir.toString(); } + moduleBuilder.setTestSourcePaths(PathList.from(testSourcePaths)) + .setTestClassesPath(testClassesDir.toString()) + .setTestResourcePaths(PathList.from(testResourcesSrcDirs)) + .setTestResourcesOutputPath(testResourcesOutputPath); } } - DevModeContext.ModuleInfo wsModuleInfo = moduleBuilder.build(); + final DevModeContext.ModuleInfo wsModuleInfo = moduleBuilder.build(); if (root) { builder.mainModule(wsModuleInfo); } else { builder.dependency(wsModuleInfo); } - addeDeps.add(key); } private String getSourceEncoding() { diff --git a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/GradleApplicationModelBuilder.java b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/GradleApplicationModelBuilder.java index ef27532c48a39..dec21995e8c78 100644 --- a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/GradleApplicationModelBuilder.java +++ b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/GradleApplicationModelBuilder.java @@ -70,6 +70,12 @@ public class GradleApplicationModelBuilder implements ParameterizedToolingModelB private static final String DEPLOYMENT_CONFIGURATION = "quarkusDeploymentConfiguration"; private static final String CLASSPATH_CONFIGURATION = "quarkusClasspathConfiguration"; + /* @formatter:off */ + private static final byte COLLECT_TOP_EXTENSION_RUNTIME_NODES = 0b001; + private static final byte COLLECT_DIRECT_DEPS = 0b010; + private static final byte COLLECT_RELOADABLE_MODULES = 0b100; + /* @formatter:on */ + private static Configuration classpathConfig(Project project, LaunchMode mode) { if (LaunchMode.TEST.equals(mode)) { return project.getConfigurations().getByName(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME); @@ -210,48 +216,6 @@ private static void collectDestinationDirs(Collection sources, final } } - private static void processQuarkusDir(ResolvedDependencyBuilder artifactBuilder, Path quarkusDir, - ApplicationModelBuilder modelBuilder) { - if (!Files.exists(quarkusDir)) { - return; - } - final Path quarkusDescr = quarkusDir.resolve(BootstrapConstants.DESCRIPTOR_FILE_NAME); - if (!Files.exists(quarkusDescr)) { - return; - } - final Properties extProps = readDescriptor(quarkusDescr); - if (extProps == null) { - return; - } - artifactBuilder.setRuntimeExtensionArtifact(); - if (artifactBuilder.isFlagSet(DependencyFlags.DIRECT)) { - artifactBuilder.setFlags(DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); - } - final String extensionCoords = artifactBuilder.toGACTVString(); - modelBuilder.handleExtensionProperties(extProps, extensionCoords); - - final String providesCapabilities = extProps.getProperty(BootstrapConstants.PROP_PROVIDES_CAPABILITIES); - if (providesCapabilities != null) { - modelBuilder - .addExtensionCapabilities(CapabilityContract.providesCapabilities(extensionCoords, providesCapabilities)); - } - } - - private static Properties readDescriptor(final Path path) { - final Properties rtProps; - if (!Files.exists(path)) { - // not a platform artifact - return null; - } - rtProps = new Properties(); - try (BufferedReader reader = Files.newBufferedReader(path)) { - rtProps.load(reader); - } catch (IOException e) { - throw new UncheckedIOException("Failed to load extension description " + path, e); - } - return rtProps; - } - private PlatformImports resolvePlatformImports(Project project, List deploymentDeps) { final Configuration boms = project.getConfigurations() @@ -306,11 +270,13 @@ private void collectExtensionDependencies(Project project, Configuration deploym toAppDependenciesKey(a.getModuleVersion().getId().getGroup(), a.getName(), a.getClassifier()), k -> toDependency(a, mainSourceSet)); dep.setDeploymentCp(); + dep.clearFlag(DependencyFlags.RELOADABLE); } else if (isDependency(a)) { final ResolvedDependencyBuilder dep = appDependencies.computeIfAbsent( toAppDependenciesKey(a.getModuleVersion().getId().getGroup(), a.getName(), a.getClassifier()), k -> toDependency(a)); dep.setDeploymentCp(); + dep.clearFlag(DependencyFlags.RELOADABLE); } } } @@ -329,7 +295,8 @@ private void collectDependencies(ResolvedConfiguration configuration, configuration.getFirstLevelModuleDependencies() .forEach(d -> { collectDependencies(d, mode, project, appDependencies, artifactFiles, new HashSet<>(), modelBuilder, - wsModule); + wsModule, + (byte) (COLLECT_TOP_EXTENSION_RUNTIME_NODES | COLLECT_DIRECT_DEPS | COLLECT_RELOADABLE_MODULES)); }); if (artifactFiles != null) { @@ -370,7 +337,8 @@ private void collectDependencies(ResolvedConfiguration configuration, private void collectDependencies(org.gradle.api.artifacts.ResolvedDependency resolvedDep, LaunchMode mode, Project project, Map appDependencies, Set artifactFiles, - Set processedModules, ApplicationModelBuilder modelBuilder, DefaultWorkspaceModule parentModule) { + Set processedModules, ApplicationModelBuilder modelBuilder, DefaultWorkspaceModule parentModule, + byte flags) { DefaultWorkspaceModule projectModule = null; for (ResolvedArtifact a : resolvedDep.getModuleArtifacts()) { @@ -382,8 +350,11 @@ private void collectDependencies(org.gradle.api.artifacts.ResolvedDependency res final ArtifactCoords depCoords = toArtifactCoords(a); final ResolvedDependencyBuilder depBuilder = ResolvedDependencyBuilder.newInstance() .setCoords(depCoords) - .setDirect(processedModules.isEmpty()) .setRuntimeCp(); + if (isFlagOn(flags, COLLECT_DIRECT_DEPS)) { + depBuilder.setDirect(true); + flags = clearFlag(flags, COLLECT_DIRECT_DEPS); + } if (parentModule != null) { parentModule.addDirectDependency(new ArtifactDependency(depCoords)); } @@ -427,7 +398,16 @@ private void collectDependencies(org.gradle.api.artifacts.ResolvedDependency res depBuilder.setResolvedPaths(paths == null ? PathList.of(a.getFile().toPath()) : paths) .setWorkspaceModule(projectModule); - processQuarkusDependency(depBuilder, modelBuilder); + if (processQuarkusDependency(depBuilder, modelBuilder)) { + if (isFlagOn(flags, COLLECT_TOP_EXTENSION_RUNTIME_NODES)) { + depBuilder.setFlags(DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); + flags = clearFlag(flags, COLLECT_TOP_EXTENSION_RUNTIME_NODES); + } + flags = clearFlag(flags, COLLECT_RELOADABLE_MODULES); + } + if (!isFlagOn(flags, COLLECT_RELOADABLE_MODULES)) { + depBuilder.clearFlag(DependencyFlags.RELOADABLE); + } appDependencies.put(depBuilder.getKey(), depBuilder); if (artifactFiles != null) { @@ -439,7 +419,7 @@ private void collectDependencies(org.gradle.api.artifacts.ResolvedDependency res for (org.gradle.api.artifacts.ResolvedDependency child : resolvedDep.getChildren()) { if (!processedModules.contains(new GACT(child.getModuleGroup(), child.getModuleName()))) { collectDependencies(child, mode, project, appDependencies, artifactFiles, processedModules, modelBuilder, - projectModule); + projectModule, flags); } } } @@ -473,21 +453,62 @@ private DefaultWorkspaceModule initProjectModuleAndBuildPaths(final Project proj return projectModule; } - private void processQuarkusDependency(ResolvedDependencyBuilder artifactBuilder, ApplicationModelBuilder modelBuilder) { - artifactBuilder.getResolvedPaths().forEach(artifactPath -> { + private boolean processQuarkusDependency(ResolvedDependencyBuilder artifactBuilder, ApplicationModelBuilder modelBuilder) { + for (Path artifactPath : artifactBuilder.getResolvedPaths()) { if (!Files.exists(artifactPath) || !artifactBuilder.getType().equals(ArtifactCoords.TYPE_JAR)) { - return; + break; } if (Files.isDirectory(artifactPath)) { - processQuarkusDir(artifactBuilder, artifactPath.resolve(BootstrapConstants.META_INF), modelBuilder); + return processQuarkusDir(artifactBuilder, artifactPath.resolve(BootstrapConstants.META_INF), modelBuilder); } else { try (FileSystem artifactFs = ZipUtils.newFileSystem(artifactPath)) { - processQuarkusDir(artifactBuilder, artifactFs.getPath(BootstrapConstants.META_INF), modelBuilder); + return processQuarkusDir(artifactBuilder, artifactFs.getPath(BootstrapConstants.META_INF), modelBuilder); } catch (IOException e) { throw new RuntimeException("Failed to process " + artifactPath, e); } } - }); + } + return false; + } + + private static boolean processQuarkusDir(ResolvedDependencyBuilder artifactBuilder, Path quarkusDir, + ApplicationModelBuilder modelBuilder) { + if (!Files.exists(quarkusDir)) { + return false; + } + final Path quarkusDescr = quarkusDir.resolve(BootstrapConstants.DESCRIPTOR_FILE_NAME); + if (!Files.exists(quarkusDescr)) { + return false; + } + final Properties extProps = readDescriptor(quarkusDescr); + if (extProps == null) { + return false; + } + artifactBuilder.setRuntimeExtensionArtifact(); + final String extensionCoords = artifactBuilder.toGACTVString(); + modelBuilder.handleExtensionProperties(extProps, extensionCoords); + + final String providesCapabilities = extProps.getProperty(BootstrapConstants.PROP_PROVIDES_CAPABILITIES); + if (providesCapabilities != null) { + modelBuilder + .addExtensionCapabilities(CapabilityContract.providesCapabilities(extensionCoords, providesCapabilities)); + } + return true; + } + + private static Properties readDescriptor(final Path path) { + final Properties rtProps; + if (!Files.exists(path)) { + // not a platform artifact + return null; + } + rtProps = new Properties(); + try (BufferedReader reader = Files.newBufferedReader(path)) { + rtProps.load(reader); + } catch (IOException e) { + throw new UncheckedIOException("Failed to load extension description " + path, e); + } + return rtProps; } private static void initProjectModule(Project project, DefaultWorkspaceModule module, SourceSet sourceSet, @@ -584,6 +605,22 @@ private void addSubstitutedProject(PathList.Builder paths, File projectFile) { } } + private static byte setFlag(byte flags, byte flag) { + flags |= flag; + return flags; + } + + private static boolean isFlagOn(byte walkingFlags, byte flag) { + return (walkingFlags & flag) > 0; + } + + private static byte clearFlag(byte flags, byte flag) { + if ((flags & flag) > 0) { + flags ^= flag; + } + return flags; + } + private static boolean isDependency(ResolvedArtifact a) { return ArtifactCoords.TYPE_JAR.equalsIgnoreCase(a.getExtension()) || "exe".equalsIgnoreCase(a.getExtension()) || a.getFile().isDirectory(); diff --git a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java index 9039b20dad2b4..9997a3cf03c21 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java @@ -81,8 +81,10 @@ import org.fusesource.jansi.internal.WindowsSupport; import io.quarkus.bootstrap.BootstrapConstants; +import io.quarkus.bootstrap.app.QuarkusBootstrap; import io.quarkus.bootstrap.devmode.DependenciesFilter; import io.quarkus.bootstrap.model.ApplicationModel; +import io.quarkus.bootstrap.model.PathsCollection; import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.bootstrap.resolver.maven.options.BootstrapMavenOptions; @@ -993,11 +995,20 @@ private QuarkusDevModeLauncher newLauncher() throws Exception { } addQuarkusDevModeDeps(builder); + //look for an application.properties + Set resourceDirs = new HashSet<>(); + for (Resource resource : project.getResources()) { + String dir = resource.getDirectory(); + Path path = Paths.get(dir); + resourceDirs.add(path); + } + Set configuredParentFirst = QuarkusBootstrap.createClassLoadingConfig(PathsCollection.from(resourceDirs), + QuarkusBootstrap.Mode.DEV, Collections.emptyList()).parentFirstArtifacts; //in most cases these are not used, however they need to be present for some //parent-first cases such as logging //first we go through and get all the parent first artifacts - Set parentFirstArtifacts = new HashSet<>(); + Set parentFirstArtifacts = new HashSet<>(configuredParentFirst); for (Artifact appDep : project.getArtifacts()) { if (appDep.getArtifactHandler().getExtension().equals("jar") && appDep.getFile().isFile()) { try (ZipFile file = new ZipFile(appDep.getFile())) { diff --git a/docs/pom.xml b/docs/pom.xml index 24ca4c204ba5c..fe773cde89e36 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -1435,6 +1435,19 @@ + + io.quarkus + quarkus-oidc-token-propagation-reactive-deployment + ${project.version} + pom + test + + + * + * + + + io.quarkus quarkus-openshift-deployment @@ -2727,6 +2740,7 @@ ${quickstarts-base-url}/tree/main + https://quarkiverse.github.io/quarkiverse-docs/quarkus-amazon-services/dev/index.html https://quarkiverse.github.io/quarkiverse-docs/quarkus-config-extensions/dev/consul.html https://quarkiverse.github.io/quarkiverse-docs/quarkus-hibernate-search-extras/dev/index.html https://quarkiverse.github.io/quarkiverse-docs/quarkus-neo4j/dev/index.html diff --git a/docs/src/main/asciidoc/amazon-lambda-http.adoc b/docs/src/main/asciidoc/amazon-lambda-http.adoc index 3f7bf6ade2f60..8e9dca8abfaa4 100644 --- a/docs/src/main/asciidoc/amazon-lambda-http.adoc +++ b/docs/src/main/asciidoc/amazon-lambda-http.adoc @@ -7,6 +7,7 @@ https://github.com/quarkusio/quarkus/tree/main/docs/src/main/asciidoc :extension-status: preview include::./attributes.adoc[] +:devtools-no-gradle: With Quarkus you can deploy your favorite Java HTTP frameworks as Amazon Lambda's using either the https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api.html[AWS Gateway HTTP API] or https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html[AWS Gateway REST API]. This means that you can deploy your microservices written with RESTEasy (JAX-RS), @@ -25,11 +26,8 @@ include::./status-include.adoc[] == Prerequisites -To complete this guide, you need: - -* less than 30 minutes -* JDK 11 (AWS requires JDK 8 or 11) -* Apache Maven {maven-version} +:prerequisites-time: 30 minutes +include::includes/devtools/prerequisites.adoc[] * https://aws.amazon.com[An Amazon AWS account] * https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html[AWS SAM CLI] @@ -68,12 +66,9 @@ mvn archetype:generate \ == Build and Deploy -Build the project using Maven. +Build the project: -[source,bash,subs=attributes+] ----- -./mvnw clean install ----- +include::includes/devtools/build.adoc[] This will compile the code and run the unit tests included within the generated project. Unit testing is the same as any other Java project and does not require running on Amazon. Quarkus dev mode is also @@ -82,20 +77,13 @@ available with this extension. If you want to build a native executable, make sure you have GraalVM installed correctly and just add a `native` property to the build -[source,bash,subs=attributes+] ----- -./mvnw clean install -Dnative ----- +include::includes/devtools/build-native.adoc[] NOTE: If you are building on a non-Linux system, you will need to also pass in a property instructing quarkus to use a Docker build as Amazon -Lambda requires Linux binaries. You can do this by passing `-Dquarkus.native.container-build=true` to your Maven build -(or xref:gradle-tooling.adoc#building-a-native-executable[for Gradle]). +Lambda requires Linux binaries. You can do this by passing `-Dquarkus.native.container-build=true` to your build command. This requires you to have Docker installed locally, however. -[source,bash,subs=attributes+] ----- -./mvnw clean install -Dnative -Dquarkus.native.container-build=true ----- +include::includes/devtools/build-native-container.adoc[] == Extra Build Generated Files @@ -228,10 +216,7 @@ you may need to manually manage that encoding. To deploy a native executable, you must build it with GraalVM. -[source,bash,subs=attributes+] ----- -./mvnw clean install -Dnative ----- +include::includes/devtools/build-native-container.adoc[] You can then test the executable locally with sam local diff --git a/docs/src/main/asciidoc/amazon-lambda.adoc b/docs/src/main/asciidoc/amazon-lambda.adoc index bdbcfaf8b25af..2f9d2dfde5de4 100644 --- a/docs/src/main/asciidoc/amazon-lambda.adoc +++ b/docs/src/main/asciidoc/amazon-lambda.adoc @@ -18,11 +18,8 @@ bring up your Quarkus lambda project in dev or test mode and code on your projec == Prerequisites -To complete this guide, you need: - -* less than 30 minutes -* JDK 11 (AWS requires JDK 1.8 or 11) -* Apache Maven {maven-version} +:prerequisites-time: 30 minutes +include::includes/devtools/prerequisites.adoc[] * https://aws.amazon.com[An Amazon AWS account] * https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html[AWS CLI] * https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html[AWS SAM CLI], for local testing @@ -112,17 +109,9 @@ create, update, delete, and invoke your lambdas for pure Java and native deploym == Build and Deploy -Build the project using maven. - -[source,bash,subs=attributes+] ----- -./mvnw clean package ----- +Build the project: -or, if using Gradle: ----- -./gradlew clean assemble ----- +include::includes/devtools/build.adoc[] This will compile and package your code. @@ -241,33 +230,15 @@ sh target/manage.sh update If you want a lower memory footprint and faster initialization times for your lambda, you can compile your Java code to a native executable. Just make sure to rebuild your project with the `-Pnative` switch. -For Linux hosts execute: +For Linux hosts, execute: -[source,bash,subs=attributes+] ----- -mvn package -Pnative ----- +include::includes/devtools/build-native.adoc[] -or, if using Gradle: -[source,bash,subs=attributes+] ----- -./gradlew build -Dquarkus.package.type=native ----- - -NOTE: If you are building on a non-Linux system, you will need to also pass in a property instructing quarkus to use a docker build as Amazon -Lambda requires linux binaries. You can do this by passing this property to your Maven build: -`-Dquarkus.native.container-build=true`, or for Gradle: `--docker-build=true`. This requires you to have docker installed locally, however. +NOTE: If you are building on a non-Linux system, you will need to also pass in a property instructing Quarkus to use a docker build as Amazon +Lambda requires linux binaries. You can do this by passing this property to your build: +`-Dquarkus.native.container-build=true`. This requires you to have Docker installed locally, however. -[source,bash,subs=attributes+] ----- -./mvnw clean install -Pnative -Dquarkus.native.container-build=true ----- - -or, if using Gradle: -[source,bash,subs=attributes+] ----- -./gradlew build -Dquarkus.package.type=native -Dquarkus.native.container-build=true ----- +include::includes/devtools/build-native-container.adoc[] Either of these commands will compile and create a native executable image. It also generates a zip file `target/function.zip`. This zip file contains your native executable image renamed to `bootstrap`. This is a requirement of the AWS Lambda @@ -334,10 +305,10 @@ While running in Quarkus Dev Mode, you can feed events to it by doing an HTTP PO The mock event server will receive the events and your lambda will be invoked. You can perform live coding on your lambda and changes will automatically be recompiled and available the next invocation you make. Here's an example: +include::includes/devtools/dev.adoc[] + [source,bash] ---- -$ mvn clean quarkus:dev - $ curl -d "{\"name\":\"John\"}" -X POST http://localhost:8080 ---- @@ -472,7 +443,8 @@ quarkus.ssl.native=true [[aws-sdk-v2]] == Using the AWS Java SDK v2 -NOTE: Quarkus now has extensions for DynamoDB, S3, SNS and SQS (more coming). Please check those guides on how to use the various AWS Services with Quarkus, as opposed to wiring manually like below. +NOTE: Quarkus now has extensions for DynamoDB, S3, SNS and SQS (more coming). +Please check link:{amazon-services-guide}[those guides] on how to use the various AWS Services with Quarkus, as opposed to wiring manually like below. With minimal integration, it is possible to leverage the AWS Java SDK v2, which can be used to invoke services such as SQS, SNS, S3 and DynamoDB. @@ -556,7 +528,6 @@ For Maven, add the following to your `pom.xml`. org.jboss.logging commons-logging-jboss-logging - 1.0.0.Final ---- @@ -566,7 +537,7 @@ there is some additional work to bundle the `function.zip`, as below. For more == Additional requirements for client SSL -The native executable requires some additional steps to enable client ssl that S3 and other aws libraries need. +The native executable requires some additional steps to enable client SSL that S3 and other AWS libraries need. 1. A custom `bootstrap` script 2. `libsunec.so` must be added to `function.zip` diff --git a/docs/src/main/asciidoc/amqp-reference.adoc b/docs/src/main/asciidoc/amqp-reference.adoc index d492f55976f08..790d9c48bef8d 100644 --- a/docs/src/main/asciidoc/amqp-reference.adoc +++ b/docs/src/main/asciidoc/amqp-reference.adoc @@ -24,21 +24,26 @@ To use the connector, you need to add the `quarkus-smallrye-reactive-messaging-a You can add the extension to your project using: -[source, bash] ----- -> ./mvnw quarkus:add-extensions -Dextensions="quarkus-smallrye-reactive-messaging-amqp" ----- +:add-extension-extensions: quarkus-smallrye-reactive-messaging-amqp +include::includes/devtools/extension-add.adoc[] Or just add the following dependency to your project: -[source, xml] +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] +.pom.xml ---- io.quarkus - quarkus-quarkus-smallrye-reactive-messaging-amqp + quarkus-smallrye-reactive-messaging-amqp ---- +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.build.gradle +---- +implementation("io.quarkus:quarkus-smallrye-reactive-messaging-amqp") +---- + Once added to your project, you can map _channels_ to AMQP addresses by configuring the `connector` attribute: [source, properties] diff --git a/docs/src/main/asciidoc/amqp.adoc b/docs/src/main/asciidoc/amqp.adoc index b767dd4ae313c..e102e328961a3 100644 --- a/docs/src/main/asciidoc/amqp.adoc +++ b/docs/src/main/asciidoc/amqp.adoc @@ -18,14 +18,8 @@ documentation. == Prerequisites -To complete this guide, you need: - -* less than 15 minutes -* an IDE -* JDK 11+ installed with `JAVA_HOME` configured appropriately -* Apache Maven {maven-version} -* docker and docker-compose -* GraalVM installed if you want to run in native mode. +:prerequisites-docker-compose: +include::includes/devtools/prerequisites.adoc[] == Architecture @@ -62,30 +56,22 @@ First, we need to create two projects: the _producer_ and the _processor_. To create the _producer_ project, in a terminal run: -[source,bash,subs=attributes+] ----- -mvn io.quarkus.platform:quarkus-maven-plugin:{quarkus-version}:create \ - -DprojectGroupId=org.acme \ - -DprojectArtifactId=amqp-quickstart-producer \ - -DnoCode=true \ - -Dextensions=resteasy-reactive-jackson,smallrye-reactive-messaging-amqp ----- +:create-app-artifact-id: amqp-quickstart-producer +:create-app-extensions: resteasy-reactive-jackson,smallrye-reactive-messaging-amqp +:create-app-post-command: +include::includes/devtools/create-app.adoc[] This command creates the project structure and select the two Quarkus extensions we will be using: -1. RESTEasy Reactive and it's Jackson support to handle JSON payloads +1. RESTEasy Reactive and its Jackson support to handle JSON payloads 2. The Reactive Messaging AMQP connector To create the _processor_ project, from the same directory, run: -[source,bash,subs=attributes+] ----- -mvn io.quarkus.platform:quarkus-maven-plugin:{quarkus-version}:create \ - -DprojectGroupId=org.acme \ - -DprojectArtifactId=amqp-quickstart-processor \ - -DnoCode=true \ - -Dextensions=smallrye-reactive-messaging-amqp ----- +:create-app-artifact-id: amqp-quickstart-processor +:create-app-extensions: smallrye-reactive-messaging-amqp +:create-app-post-command: +include::includes/devtools/create-app.adoc[] At that point you should have the following structure: diff --git a/docs/src/main/asciidoc/azure-functions-http.adoc b/docs/src/main/asciidoc/azure-functions-http.adoc index b0f0f8e8c462b..2426a42c994ce 100644 --- a/docs/src/main/asciidoc/azure-functions-http.adoc +++ b/docs/src/main/asciidoc/azure-functions-http.adoc @@ -19,11 +19,7 @@ NOTE: Only text based media types are supported at the moment as Azure Functions == Prerequisites -To complete this guide, you need: - -* less than 15 minutes -* JDK 11 (Azure requires JDK 1.8 or 11) -* Apache Maven {maven-version} +include::includes/devtools/prerequisites.adoc[] * https://azure.microsoft.com[An Azure Account]. Free accounts work. * https://docs.microsoft.com/en-us/cli/azure/install-azure-cli[Azure CLI Installed] @@ -35,7 +31,7 @@ to Azure. == Creating the Maven Deployment Project -Create the azure maven project for your Quarkus application using our Maven Archetype. +Create the Azure Maven project for your Quarkus application using our Maven Archetype. [source,bash,subs=attributes+] diff --git a/docs/src/main/asciidoc/blaze-persistence.adoc b/docs/src/main/asciidoc/blaze-persistence.adoc index 36dcca430fd76..219aaf7592b26 100644 --- a/docs/src/main/asciidoc/blaze-persistence.adoc +++ b/docs/src/main/asciidoc/blaze-persistence.adoc @@ -38,21 +38,26 @@ Add the following dependencies to your project: - `blaze-persistence-integration-jaxrs` for link:https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#jaxrs-integration[JAX-RS] -[source,xml] +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] .Example dependencies using Maven ---- - - - - com.blazebit - blaze-persistence-integration-quarkus - - - com.blazebit - blaze-persistence-integration-hibernate-5.6 - runtime - - + + + com.blazebit + blaze-persistence-integration-quarkus + + + com.blazebit + blaze-persistence-integration-hibernate-5.6 + runtime + +---- + +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.Using Gradle +---- +implementation("com.blazebit:blaze-persistence-integration-quarkus") +runtimeOnly("com.blazebit:blaze-persistence-integration-hibernate-5.6") ---- The use in native images requires a dependency on the entity view annotation processor that may be extracted into a separate `native` profile: diff --git a/docs/src/main/asciidoc/building-my-first-extension.adoc b/docs/src/main/asciidoc/building-my-first-extension.adoc index 9fab099d91aae..761cbf2147bc9 100644 --- a/docs/src/main/asciidoc/building-my-first-extension.adoc +++ b/docs/src/main/asciidoc/building-my-first-extension.adoc @@ -23,12 +23,9 @@ Keep in mind it's not representative of the power of moving things to build time == Prerequisites -To complete this guide, you need: - -* less than 30 minutes -* an IDE -* JDK 11+ installed with `JAVA_HOME` configured appropriately -* Apache Maven {maven-version} +:prerequisites-time: 30 minutes +:prerequisites-no-graalvm: +include::includes/devtools/prerequisites.adoc[] == Basic Concepts diff --git a/docs/src/main/asciidoc/building-native-image.adoc b/docs/src/main/asciidoc/building-native-image.adoc index 5c1edac535b1c..d26b9002e75f1 100644 --- a/docs/src/main/asciidoc/building-native-image.adoc +++ b/docs/src/main/asciidoc/building-native-image.adoc @@ -50,14 +50,10 @@ and https://github.com/graalvm/mandrel/releases[Mandrel releases]. == Prerequisites -To complete this guide using Oracle GraalVM CE/EE, you need: - -* less than 15 minutes -* an IDE -* JDK 11 installed with `JAVA_HOME` configured appropriately +:prerequisites-docker: +:prerequisites-graalvm-mandatory: +include::includes/devtools/prerequisites.adoc[] * A xref:configuring-c-development[working C development environment] -* Mandrel or Oracle GraalVM CE/EE version {graalvm-version} installed and xref:configuring-graalvm[configured appropriately] -* A working container runtime (Docker, podman) * The code of the application developed in the xref:getting-started.adoc[Getting Started Guide]. .Supporting native compilation in C @@ -199,7 +195,9 @@ We use a profile because, you will see very soon, packaging the native executabl just pass -Dquarkus.package.type=native as a property on the command line, however it is better to use a profile as this allows native image tests to also be run. -Create a native executable using: `./mvnw package -Pnative`. +Create a native executable using: + +include::includes/devtools/build-native.adoc[] [[graal-and-windows]] [NOTE] @@ -369,22 +367,24 @@ to install as little software as possible). To this end, Quarkus provides a very convenient way of creating a native Linux executable by leveraging a container runtime such as Docker or podman. The easiest way of accomplishing this task is to execute: -[source,bash] ----- -./mvnw package -Pnative -Dquarkus.native.container-build=true ----- +include::includes/devtools/build-native-container.adoc[] [TIP] ==== By default Quarkus automatically detects the container runtime. If you want to explicitely select the container runtime, you can do it with: -[source,bash] ----- -# Docker -./mvnw package -Pnative -Dquarkus.native.container-build=true -Dquarkus.native.container-runtime=docker -# Podman -./mvnw package -Pnative -Dquarkus.native.container-build=true -Dquarkus.native.container-runtime=podman ----- + +For Docker: + +:build-additional-parameters: -Dquarkus.native.container-runtime=docker +include::includes/devtools/build-native-container-parameters.adoc[] +:!build-additional-parameters: + +For podman: + +:build-additional-parameters: -Dquarkus.native.container-runtime=podman +include::includes/devtools/build-native-container-parameters.adoc[] +:!build-additional-parameters: These are normal Quarkus config properties, so if you always want to build in a container it is recommended you add these to your `application.properties` in order to avoid specifying them every time. @@ -405,10 +405,10 @@ The reason for this is that the local build driver invoked through `-Dquarkus.na [TIP] ==== Building with Mandrel requires a custom builder image parameter to be passed additionally: -[source,bash,subs=attributes+] ----- -./mvnw package -Pnative -Dquarkus.native.container-build=true -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-mandrel:{mandrel-flavor} ----- + +:build-additional-parameters: -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-mandrel:{mandrel-flavor} +include::includes/devtools/build-native-container-parameters.adoc[] +:!build-additional-parameters: Please note that the above command points to a floating tag. It is highly recommended to use the floating tag, diff --git a/docs/src/main/asciidoc/cache.adoc b/docs/src/main/asciidoc/cache.adoc index 0f278c9a66edc..5c0c42ce648ba 100644 --- a/docs/src/main/asciidoc/cache.adoc +++ b/docs/src/main/asciidoc/cache.adoc @@ -14,12 +14,7 @@ include::./status-include.adoc[] == Prerequisites -To complete this guide, you need: - -* less than 15 minutes -* an IDE -* JDK 11+ installed with `JAVA_HOME` configured appropriately -* Apache Maven {maven-version} +include::includes/devtools/prerequisites.adoc[] == Scenario @@ -40,31 +35,24 @@ The solution is located in the `cache-quickstart` {quickstarts-tree-url}/cache-q == Creating the Maven project -First, we need to create a new Quarkus project using Maven with the following command: +First, we need to create a new Quarkus project with the following command: -[source,bash,subs=attributes+] ----- -mvn io.quarkus.platform:quarkus-maven-plugin:{quarkus-version}:create \ - -DprojectGroupId=org.acme \ - -DprojectArtifactId=cache-quickstart \ - -DclassName="org.acme.cache.WeatherForecastResource" \ - -Dpath="/weather" \ - -Dextensions="resteasy,cache,resteasy-jackson" ----- +:create-app-artifact-id: cache-quickstart +:create-app-extensions: resteasy,cache,resteasy-jackson +include::includes/devtools/create-app.adoc[] -This command generates the Maven project with a REST endpoint and imports the `cache` and `resteasy-jackson` extensions. +This command generates the project and imports the `cache` and `resteasy-jackson` extensions. If you already have your Quarkus project configured, you can add the `cache` extension to your project by running the following command in your project base directory: -[source,bash] ----- -./mvnw quarkus:add-extension -Dextensions="cache" ----- +:add-extension-extensions: cache +include::includes/devtools/extension-add.adoc[] -This will add the following to your `pom.xml`: +This will add the following to your build file: -[source,xml] +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] +.pom.xml ---- io.quarkus @@ -72,6 +60,12 @@ This will add the following to your `pom.xml`: ---- +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.build.gradle +---- +implementation("io.quarkus:quarkus-cache") +---- + == Creating the REST API Let's start by creating a service that will simulate an extremely slow call to the external meteorological service. @@ -145,7 +139,8 @@ public class WeatherForecast { } ---- -Now, we just need to update the generated `WeatherForecastResource` class to use the service and response: +Now, we just need to create the REST resource. +Create the `src/main/java/org/acme/cache/WeatherForecastResource.java` file with this content: [source,java] ---- @@ -186,7 +181,9 @@ Otherwise, it will start from the current day plus the `daysInFuture` value. We're all done! Let's check if everything's working. -First, run the application using `./mvnw compile quarkus:dev` from the project directory. +First, run the application using dev mode from the project directory: + +include::includes/devtools/dev.adoc[] Then, call `http://localhost:8080/weather?city=Raleigh` from a browser. After six long seconds, the application will answer something like this: diff --git a/docs/src/main/asciidoc/cassandra.adoc b/docs/src/main/asciidoc/cassandra.adoc index bac46e7bb7e85..649eac9dfb469 100644 --- a/docs/src/main/asciidoc/cassandra.adoc +++ b/docs/src/main/asciidoc/cassandra.adoc @@ -17,14 +17,7 @@ include::./platform-include.adoc[] == Prerequisites -To complete this quickstart guide, you need: - -* an IDE; -* JDK 11+ installed with `JAVA_HOME` configured appropriately; -* link:https://www.graalvm.org/[GraalVM] installed with the `GRAALVM_HOME` environment variable -configured appropriately, if you want to -link:https://quarkus.io/guides/building-native-image[use the native mode]; -* Apache Maven {maven-version} +include::includes/devtools/prerequisites.adoc[] * A running link:https://cassandra.apache.org[Apache Cassandra], link:https://www.datastax.fr/products/datastax-enterprise[DataStax Enterprise] (DSE) or link:https://astra.datastax.com[DataStax Astra] database; or alternatively, a fresh Docker diff --git a/docs/src/main/asciidoc/centralized-log-management.adoc b/docs/src/main/asciidoc/centralized-log-management.adoc index c966efc47ee3d..9c299942ba182 100644 --- a/docs/src/main/asciidoc/centralized-log-management.adoc +++ b/docs/src/main/asciidoc/centralized-log-management.adoc @@ -17,33 +17,31 @@ In this guide, we will expose how to send them to an external tool using the `qu The `quarkus-logging-gelf` extension will add a GELF log handler to the underlying logging backend that Quarkus uses (jboss-logmanager). By default, it is disabled, if you enable it but still use another handler (by default the console handler is enabled), your logs will be sent to both handlers. +== Prerequisites + +:prerequisites-docker-compose: +include::includes/devtools/prerequisites.adoc[] + == Example application The following examples will all be based on the same example application that you can create with the following steps. -Create an application with the `quarkus-logging-gelf` extension. You can use the following Maven command to create it: +Create an application with the `quarkus-logging-gelf` extension. You can use the following command to create it: -[source,bash,subs=attributes+] ----- -mvn io.quarkus.platform:quarkus-maven-plugin:{quarkus-version}:create \ - -DprojectGroupId=org.acme \ - -DprojectArtifactId=gelf-logging \ - -DclassName="org.acme.quickstart.GelfLoggingResource" \ - -Dpath="/gelf-logging" \ - -Dextensions="resteasy,logging-gelf" ----- +:create-app-artifact-id: gelf-logging +:create-app-extensions: resteasy,logging-gelf +include::includes/devtools/create-app.adoc[] If you already have your Quarkus project configured, you can add the `logging-gelf` extension to your project by running the following command in your project base directory: -[source,bash] ----- -./mvnw quarkus:add-extension -Dextensions="logging-gelf" ----- +:add-extension-extensions: logging-gelf +include::includes/devtools/extension-add.adoc[] -This will add the following to your `pom.xml`: +This will add the following dependency to your build file: -[source,xml] +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] +.pom.xml ---- io.quarkus @@ -51,6 +49,12 @@ This will add the following to your `pom.xml`: ---- +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.build.gradle +---- +implementation("io.quarkus:quarkus-logging-gelf") +---- + For demonstration purposes, we create an endpoint that does nothing but log a sentence. You don't need to do this inside your application. [source,java] diff --git a/docs/src/main/asciidoc/config-yaml.adoc b/docs/src/main/asciidoc/config-yaml.adoc index ad9d1d1c4fb40..dd358371c6ff6 100644 --- a/docs/src/main/asciidoc/config-yaml.adoc +++ b/docs/src/main/asciidoc/config-yaml.adoc @@ -16,17 +16,15 @@ Quarkus offers the possibility to use YAML in addition to the standard Java Prop == Enabling YAML Configuration -To enable YAML configuration add the `quarkus-config-yaml` extension: +To enable YAML configuration, add the `quarkus-config-yaml` extension: -[source, bash] ----- -> ./mvnw quarkus:add-extension -Dextensions="io.quarkus:quarkus-config-yaml" # Maven -> ./gradlew addExtension --extensions="io.quarkus:quarkus-config-yaml" # Gradle ----- +:add-extension-extensions: quarkus-config-yaml +include::includes/devtools/extension-add.adoc[] You can also just add the following dependency into your project: -[source, xml] +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] +.pom.xml ---- io.quarkus @@ -34,12 +32,18 @@ You can also just add the following dependency into your project: ---- +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.build.gradle +---- +implementation("io.quarkus:quarkus-config-yaml") +---- + Remove the `src/main/resources/application.properties` and create a `src/main/resources/application.yaml` file. NOTE: If both are present, Quarkus prioritizes configuration properties from the YAML file first and then from the Properties file. However, to avoid confusion, we recommend removing the Properties file. -TIP: Supports both the `yml` or `yaml` file extensions. +TIP: Quarkus supports both the `yml` and `yaml` file extensions. === Example diff --git a/docs/src/main/asciidoc/config.adoc b/docs/src/main/asciidoc/config.adoc index 95c87ed2ae320..47f5697c14ee8 100644 --- a/docs/src/main/asciidoc/config.adoc +++ b/docs/src/main/asciidoc/config.adoc @@ -17,12 +17,7 @@ In this guide, we will learn how to configure a Quarkus application. == Prerequisites -To complete this guide, you need: - -* between 5 and 10 minutes -* an IDE -* JDK 11+ installed with `JAVA_HOME` configured appropriately -* Apache Maven {maven-version} +include::includes/devtools/prerequisites.adoc[] == Solution @@ -46,6 +41,9 @@ mvn io.quarkus.platform:quarkus-maven-plugin:{quarkus-version}:create \ -Dpath="/greeting" cd config-quickstart ---- +:create-app-artifact-id: org.acme +:create-app-extensions: config-quickstart +include::includes/devtools/create-app.adoc[] It generates: @@ -53,8 +51,6 @@ It generates: * a landing page accessible on `http://localhost:8080` * example `Dockerfile` files for both `native` and `jvm` modes * the application configuration file -* an `org.acme.config.GreetingResource` resource -* an associated test == Create the configuration @@ -73,6 +69,30 @@ greeting.message = hello greeting.name = quarkus ---- +== Create a REST resource + +Create the `org.acme.config.GreetingResource` REST resource with the following content: + +[source,java] +---- +package org.acme.config; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +@Path("/greeting") +public class GreetingResource { + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String hello() { + return "Hello RESTEasy"; + } +} +---- + == Inject the configuration Quarkus uses https://microprofile.io/project/eclipse/microprofile-config[MicroProfile Config] annotations to inject the @@ -116,21 +136,13 @@ public String hello() { } ---- -Once set, check the application with: - -[source,shell] ----- -$ curl http://localhost:8080/greeting -hello quarkus! ----- - TIP: Use `@io.smallrye.config.ConfigMapping` annotation to group multiple configurations in a single interface. Please, check the https://smallrye.io/docs/smallrye-config/main/mapping/mapping.html[Config Mappings] documentation. == Update the test We also need to update the functional test to reflect the changes made to the endpoint. -Edit the `src/test/java/org/acme/config/GreetingResourceTest.java` file and change the content of the `testHelloEndpoint` method to: +Create the `src/test/java/org/acme/config/GreetingResourceTest.java` file with the following content: [source,java] ---- @@ -159,14 +171,24 @@ public class GreetingResourceTest { == Package and run the application -Run the application with: `./mvnw compile quarkus:dev`. +Run the application with: + +include::includes/devtools/dev.adoc[] + Open your browser to http://localhost:8080/greeting. Changing the configuration file is immediately reflected. You can add the `greeting.suffix`, remove the other properties, change the values, etc. -As usual, the application can be packaged using `./mvnw clean package` and executed using the `target/quarkus-app/quarkus-run.jar` file. -You can also generate the native executable with `./mvnw clean package -Pnative`. +As usual, the application can be packaged using: + +include::includes/devtools/build.adoc[] + +and executed using `java -jar target/quarkus-app/quarkus-run.jar`. + +You can also generate the native executable with: + +include::includes/devtools/build-native.adoc[] == Programmatically access the configuration diff --git a/docs/src/main/asciidoc/container-image.adoc b/docs/src/main/asciidoc/container-image.adoc index 3b60fec137fd9..2aea44b2e6930 100644 --- a/docs/src/main/asciidoc/container-image.adoc +++ b/docs/src/main/asciidoc/container-image.adoc @@ -26,10 +26,8 @@ when all that is needed is the ability to push to a container image registry. To use this feature, add the following extension to your project: -[source,bash] ----- -./mvnw quarkus:add-extension -Dextensions="container-image-jib" ----- +:add-extension-extensions: container-image-jib +include::includes/devtools/extension-add.adoc[] WARNING: In situations where all that is needed to build a container image and no push to a registry is necessary (essentially by having set `quarkus.container-image.build=true` and left `quarkus.container-image.push` unset - it defaults to `false`), then this extension creates a container image and registers it with the Docker daemon. This means that although Docker isn't used to build the image, it is nevertheless necessary. Also note that using this mode, the built container image *will* @@ -75,10 +73,8 @@ The extension `quarkus-container-image-docker` is using the Docker binary and th To use this feature, add the following extension to your project. -[source,bash] ----- -./mvnw quarkus:add-extension -Dextensions="container-image-docker" ----- +:add-extension-extensions: container-image-docker +include::includes/devtools/extension-add.adoc[] [#s2i] === S2I @@ -90,10 +86,8 @@ The benefit of this approach, is that it can be combined with OpenShift's `Deplo To use this feature, add the following extension to your project. -[source,xml] ----- -./mvnw quarkus:add-extension -Dextensions="container-image-s2i" ----- +:add-extension-extensions: container-image-s2i +include::includes/devtools/extension-add.adoc[] S2I builds require creating a `BuildConfig` and two `ImageStream` resources, one for the builder image and one for the output image. The creation of such objects is being taken care of by the Quarkus Kubernetes extension. @@ -102,8 +96,9 @@ The creation of such objects is being taken care of by the Quarkus Kubernetes ex [#buildpack] === Buildpack -The extension `quarkus-container-image-buildpack` is using the buildpacks in order to perfrom container image builds. -Under the hood buildpacks will use a docker daemon for the actual build. While buildpacks support alternatives to docker, this extension will only work with docker. +The extension `quarkus-container-image-buildpack` is using buildpacks in order to perform container image builds. +Under the hood buildpacks will use a Docker daemon for the actual build. +While buildpacks support alternatives to Docker, this extension will only work with Docker. Additionally, the user will have to configure which build image to use (no default image is provided). For example: @@ -114,30 +109,23 @@ quarkus.buildpack.jvm-builder-image= or for native: - [source,properties] ---- quarkus.buildpack.jvm-builder-image= ---- - - To use this feature, add the following extension to your project. -[source,bash] ----- -./mvnw quarkus:add-extension -Dextensions="container-image-buildpack" ----- - +:add-extension-extensions: container-image-buildpack +include::includes/devtools/extension-add.adoc[] == Building To build a container image for your project, `quarkus.container-image.build=true` needs to be set using any of the ways that Quarkus supports. -[source,bash,subs=attributes+] ----- -./mvnw clean package -Dquarkus.container-image.build=true ----- +:build-additional-parameters: -Dquarkus.container-image.build=true +include::includes/devtools/build.adoc[] +:!build-additional-parameters: NOTE: If you ever want to build a native container image and already have an existing native image you can set `-Dquarkus.native.reuse-existing=true` and the native image build will not be re-run. @@ -145,10 +133,9 @@ NOTE: If you ever want to build a native container image and already have an exi To push a container image for your project, `quarkus.container-image.push=true` needs to be set using any of the ways that Quarkus supports. -[source,bash,subs=attributes+] ----- -./mvnw clean package -Dquarkus.container-image.push=true ----- +:build-additional-parameters: -Dquarkus.container-image.push=true +include::includes/devtools/build.adoc[] +:!build-additional-parameters: NOTE: If no registry is set (using `quarkus.container-image.registry`) then `docker.io` will be used as the default. diff --git a/docs/src/main/asciidoc/context-propagation.adoc b/docs/src/main/asciidoc/context-propagation.adoc index 72222008ef089..fcfa1129b53a3 100644 --- a/docs/src/main/asciidoc/context-propagation.adoc +++ b/docs/src/main/asciidoc/context-propagation.adoc @@ -39,24 +39,28 @@ the `quarkus-smallrye-context-propagation` extension to enable context propagati In other words, add the following dependencies to your `pom.xml`: -[source,xml] +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] +.pom.xml ---- - - - - io.quarkus - quarkus-mutiny - - - io.quarkus - quarkus-resteasy-mutiny - - - - io.quarkus - quarkus-smallrye-context-propagation - - + + + io.quarkus + quarkus-resteasy-mutiny + + + + io.quarkus + quarkus-smallrye-context-propagation + +---- + +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.build.gradle +---- +// RESTEasy support extensions if not already included +implementation("io.quarkus:quarkus-resteasy-mutiny") +// Context Propagation extension +implementation("io.quarkus:quarkus-smallrye-context-propagation") ---- With this, you will get context propagation for ArC, RESTEasy and transactions, if you are using them. @@ -270,35 +274,6 @@ You can also inject a custom-built `ThreadContext` using the https://javadoc.io/ } ---- - -== Adding support for RxJava2 - -You need to include the following modules to get RxJava2 support: - -[source,xml] ----- - - - - io.smallrye - smallrye-context-propagation-propagators-rxjava2 - - - - io.smallrye.reactive - smallrye-reactive-converter-rxjava2 - - - - org.jboss.resteasy - resteasy-rxjava2 - - ----- - == Context Propagation for CDI In terms of CDI, `@RequestScoped`, `@ApplicationScoped` and `@Singleton` beans get propagated and are available in other threads. diff --git a/docs/src/main/asciidoc/continuous-testing.adoc b/docs/src/main/asciidoc/continuous-testing.adoc index 81b3f7bcca0dc..1e0c1cffd4f13 100644 --- a/docs/src/main/asciidoc/continuous-testing.adoc +++ b/docs/src/main/asciidoc/continuous-testing.adoc @@ -21,12 +21,7 @@ Learn how to use continuous testing in your Quarkus Application. == Prerequisites -To complete this guide, you need: - -* less than 15 minutes -* an IDE -* JDK 11+ installed with `JAVA_HOME` configured appropriately -* Apache Maven {maven-version} +include::includes/devtools/prerequisites.adoc[] * The completed greeter application from the xref:getting-started.adoc[Getting Started Guide] == Introduction @@ -37,8 +32,11 @@ only run the relevant tests when code is changed. == Solution -Start the xref:getting-started.adoc[Getting Started] application (or any other application) using `mvn quarkus:dev`. Quarkus -will start in development mode as normal, but down the bottom of the screen you should see the following: +Start the xref:getting-started.adoc[Getting Started] application (or any other application) using: + +include::includes/devtools/dev.adoc[] + +Quarkus will start in development mode as normal, but down the bottom of the screen you should see the following: [source] ---- diff --git a/docs/src/main/asciidoc/credentials-provider.adoc b/docs/src/main/asciidoc/credentials-provider.adoc index d01c87da51097..7ee769c83efac 100644 --- a/docs/src/main/asciidoc/credentials-provider.adoc +++ b/docs/src/main/asciidoc/credentials-provider.adoc @@ -47,16 +47,6 @@ considerations regarding implementing a `Credentials Provider` in a new extensio include::./status-include.adoc[] -== Prerequisites - -To complete this guide, you need: - -* roughly 20 minutes -* an IDE -* JDK 11+ installed with `JAVA_HOME` configured appropriately -* Apache Maven {maven-version} -* Docker installed - == Vault Credentials Provider To configure a `Vault Credentials Provider` you need to provide the following properties: diff --git a/docs/src/main/asciidoc/deploying-to-azure-cloud.adoc b/docs/src/main/asciidoc/deploying-to-azure-cloud.adoc index 0ec8dd2534286..174fe868afd6a 100644 --- a/docs/src/main/asciidoc/deploying-to-azure-cloud.adoc +++ b/docs/src/main/asciidoc/deploying-to-azure-cloud.adoc @@ -18,10 +18,10 @@ This guide covers: == Prerequisites -For this guide you need: - -* roughly 2 hours for all modalities -* having access to an Azure subscription. https://azure.microsoft.com/free/?WT.mc_id=opensource-quarkus-brborges[Get a free one here] +:prerequisites-time: 2 hours for all modalities +:prerequisites-no-graalvm: +include::includes/devtools/prerequisites.adoc[] +* Having access to an Azure subscription. https://azure.microsoft.com/free/?WT.mc_id=opensource-quarkus-brborges[Get a free one here] This guide will take as input a native application developed in the xref:building-native-image.adoc[building native image guide]. diff --git a/docs/src/main/asciidoc/deploying-to-google-cloud.adoc b/docs/src/main/asciidoc/deploying-to-google-cloud.adoc index 5d765a2f99417..2ddb1976d4e38 100644 --- a/docs/src/main/asciidoc/deploying-to-google-cloud.adoc +++ b/docs/src/main/asciidoc/deploying-to-google-cloud.adoc @@ -18,11 +18,9 @@ This guide covers: == Prerequisites -For this guide you need: - -* Roughly 1 hour for all modalities -* JDK 11 -* Apache Maven {maven-version} +:prerequisites-time: 1 hour for all modalities +:prerequisites-no-graalvm: +include::includes/devtools/prerequisites.adoc[] * https://cloud.google.com/[A Google Cloud Account]. Free accounts work. * https://cloud.google.com/sdk[Cloud SDK CLI Installed] diff --git a/docs/src/main/asciidoc/deploying-to-heroku.adoc b/docs/src/main/asciidoc/deploying-to-heroku.adoc index d7f5430687e9d..d9fb6868da98d 100644 --- a/docs/src/main/asciidoc/deploying-to-heroku.adoc +++ b/docs/src/main/asciidoc/deploying-to-heroku.adoc @@ -18,11 +18,9 @@ This guide covers: == Prerequisites -For this guide you need: - -* Roughly 1 hour for all modalities -* JDK 11 -* Apache Maven {maven-version} +:prerequisites-time: 1 hour for all modalities +:prerequisites-no-graalvm: +include::includes/devtools/prerequisites.adoc[] * https://www.heroku.com/[A Heroku Account]. Free accounts work. * https://devcenter.heroku.com/articles/heroku-cli[Heroku CLI installed] @@ -50,19 +48,6 @@ This guide will take as input an application developed in the xref:getting-start Make sure you have the getting-started application at hand, or clone the Git repository: `git clone {quickstarts-clone-url}`, or download an {quickstarts-archive-url}[archive]. The solution is located in the `getting-started` directory. -Or, just generate a fresh project: - -[source,bash,subs=attributes+] ----- -mvn io.quarkus.platform:quarkus-maven-plugin:{quarkus-version}:create \ - -DprojectGroupId=org.acme \ - -DprojectArtifactId=code-with-quarkus-on-heroku \ - -DclassName="org.acme.getting.started.GreetingResource" \ - -Dpath="/hello" -cd code-with-quarkus-on-heroku -git init && git add . && git commit -am "Create initial project." ----- - Heroku can react on changes in your repository, run CI and redeploy your application when your code changes. Therefore we start with a valid repository already. diff --git a/docs/src/main/asciidoc/deploying-to-kubernetes.adoc b/docs/src/main/asciidoc/deploying-to-kubernetes.adoc index 07f54b9591eb9..5b674f8cf50a0 100644 --- a/docs/src/main/asciidoc/deploying-to-kubernetes.adoc +++ b/docs/src/main/asciidoc/deploying-to-kubernetes.adoc @@ -14,46 +14,52 @@ Finally, when either one of container image extensions is present (see the xref: == Prerequisites -To complete this guide, you need: - -* roughly 10 minutes -* an IDE -* JDK 11+ installed with `JAVA_HOME` configured appropriately -* Apache Maven {maven-version} -* access to a Kubernetes cluster (Minikube is a viable option) +:prerequisites-no-graalvm: +include::includes/devtools/prerequisites.adoc[] +* Access to a Kubernetes cluster (Minikube is a viable option) [#kubernetes] == Kubernetes Let's create a new project that contains both the Kubernetes and Jib extensions: -[source,bash,subs=attributes+] +:create-app-artifact-id: kubernetes-quickstart +:create-app-extensions: resteasy,kubernetes,jib +include::includes/devtools/create-app.adoc[] + +This added the following dependencies to the build file: + +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] +.pom.xml ---- -mvn io.quarkus.platform:quarkus-maven-plugin:{quarkus-version}:create \ - -DprojectGroupId=org.acme \ - -DprojectArtifactId=kubernetes-quickstart \ - -DclassName="org.acme.rest.GreetingResource" \ - -Dpath="/greeting" \ - -Dextensions="resteasy,kubernetes,jib" -cd kubernetes-quickstart + + io.quarkus + quarkus-resteasy + + + io.quarkus + quarkus-kubernetes + + + io.quarkus + quarkus-container-image-jib + ---- -This added the following dependencies to the `pom.xml` - -[source,xml] +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.build.gradle ---- - - io.quarkus - quarkus-kubernetes - - - io.quarkus - quarkus-container-image-jib - +implementation("io.quarkus:quarkus-resteasy") +implementation("io.quarkus:quarkus-kubernetes") +implementation("io.quarkus:quarkus-container-image-jib") ---- By adding these dependencies, we enable the generation of Kubernetes manifests each time we perform a build while also enabling the build of a container image using Jib. -For example, following the execution of `./mvnw package`, you will notice amongst the other files that are created, two files named +For example, following the execution of: + +include::includes/devtools/build.adoc[] + +you will notice amongst the other files that are created, two files named `kubernetes.json` and `kubernetes.yml` in the `target/kubernetes/` directory. If you look at either file you will see that it contains both a Kubernetes `Deployment` and a `Service`. @@ -497,12 +503,19 @@ quarkus.kubernetes.replicas=3 By default, the Kubernetes resources do not contain readiness and liveness probes in the generated `Deployment`. Adding them however is just a matter of adding the SmallRye Health extension like so: -[source,xml] +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] +.pom.xml +---- + + io.quarkus + quarkus-smallrye-health + +---- + +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.build.gradle ---- - - io.quarkus - quarkus-smallrye-health - +implementation("io.quarkus:quarkus-smallrye-health") ---- The values of the generated probes will be determined by the configured health properties: `quarkus.smallrye-health.root-path`, `quarkus.smallrye-health.liveness-path` and `quarkus.smallrye-health.readiness-path`. @@ -570,12 +583,19 @@ containers: Applications that are deployed to Kubernetes and need to access the API server will usually make use of the `kubernetes-client` extension: -[source,xml] +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] +.pom.xml ---- - - io.quarkus - quarkus-kubernetes-client - + + io.quarkus + quarkus-kubernetes-client + +---- + +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.build.gradle +---- +implementation("io.quarkus:quarkus-kubernetes-client") ---- To access the API server from within a Kubernetes cluster, some RBAC related resources are required (e.g. a ServiceAccount, a RoleBinding etc.). @@ -587,7 +607,8 @@ If more roles are required, they will have to be added manually. https://github.com/kubernetes/minikube[Minikube] is quite popular when a Kubernetes cluster is needed for development purposes. To make the deployment to Minikube experience as frictionless as possible, Quarkus provides the `quarkus-minikube` extension. This extension can be added to a project like so: -[source,xml] +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] +.pom.xml ---- io.quarkus @@ -595,6 +616,12 @@ experience as frictionless as possible, Quarkus provides the `quarkus-minikube` ---- +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.build.gradle +---- +implementation("io.quarkus:quarkus-minikube") +---- + The purpose of this extension is to generate Kubernetes manifests (`minikube.yaml` and `minikube.json`) that are tailored to Minikube. This extension assumes a couple things: @@ -834,7 +861,23 @@ Allowed values: `cluster-ip`, `node-port`, `load-balancer`, `external-name` One way to deploy an application to OpenShift is to use s2i (source to image) to create an image stream from the source and then deploy the image stream: -[source,bash] +[source,bash,role="primary asciidoc-tabs-sync-cli"] +.CLI +---- +quarkus extension remove kubernetes,jib +quarkus extension add openshift + +oc new-project quarkus-project +quarkus build -Dquarkus.container-image.build=true + +oc new-app --name=greeting quarkus-project/kubernetes-quickstart:1.0.0-SNAPSHOT +oc expose svc/greeting +oc get route +curl /greeting +---- + +[source,bash,role="secondary asciidoc-tabs-sync-maven"] +.Maven ---- ./mvnw quarkus:remove-extension -Dextensions="kubernetes, jib" ./mvnw quarkus:add-extension -Dextensions="openshift" @@ -848,6 +891,21 @@ oc get route curl /greeting ---- +[source,bash,role="secondary asciidoc-tabs-sync-gradle"] +.Gradle +---- +./gradlew removeExtension --extensions="kubernetes, jib" +./gradlew addExtension --extensions="openshift" + +oc new-project quarkus-project +./gradlew build -Dquarkus.container-image.build=true + +oc new-app --name=greeting quarkus-project/kubernetes-quickstart:1.0.0-SNAPSHOT +oc expose svc/greeting +oc get route +curl /greeting +---- + See further information in xref:deploying-to-openshift.adoc[Deploying to OpenShift]. A description of OpenShift resources and customisable properties is given below alongside Kubernetes resources to show similarities where applicable. This includes an alternative to `oc new-app ...` above, i.e. `oc apply -f target/kubernetes/openshift.json` . @@ -1238,22 +1296,33 @@ To enable Service Binding support, in addition to one of the currently supported If the Kubernetes cluster in which your Quarkus application runs supports provisioning a PostgreSQL database, one could use the following dependencies to take advantage of the Service Binding feature: -[source,xml] ----- - - io.quarkus - quarkus-jdbc-postgresql - - - io.quarkus - quarkus-kubernetes-service-binding - - - - - io.quarkus - quarkus-hibernate-orm - +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] +.pom.xml +---- + + io.quarkus + quarkus-jdbc-postgresql + + + io.quarkus + quarkus-kubernetes-service-binding + + + + + io.quarkus + quarkus-hibernate-orm + +---- + +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.build.gradle +---- +implementation("io.quarkus:quarkus-jdbc-postgresql") +implementation("io.quarkus:quarkus-kubernetes-service-binding") + +// Hibernate isn't necessary for Service Binding, but most relational database access will benefit from using it +implementation("io.quarkus:quarkus-hibernate-orm") ---- The configuration of the application could be as simple as: diff --git a/docs/src/main/asciidoc/deploying-to-openshift.adoc b/docs/src/main/asciidoc/deploying-to-openshift.adoc index 5b8eca9289f71..293efb0710476 100644 --- a/docs/src/main/asciidoc/deploying-to-openshift.adoc +++ b/docs/src/main/asciidoc/deploying-to-openshift.adoc @@ -12,30 +12,19 @@ This guide covers generating and deploying OpenShift resources based on sane def == Prerequisites -To complete this guide, you need: - -* roughly 5 minutes -* an IDE -* JDK 11+ installed with `JAVA_HOME` configured appropriately -* Apache Maven {maven-version} -* access to an OpenShift cluster (Minishift is a viable option) +:prerequisites-no-graalvm: +include::includes/devtools/prerequisites.adoc[] +* Access to an OpenShift cluster (Minishift is a viable option) * OpenShift CLI (Optional, only required for manual deployment) == Bootstrapping the project First, we need a new project that contains the OpenShift extension. This can be done using the following command: -[source,bash,subs=attributes+] ----- -mvn io.quarkus.platform:quarkus-maven-plugin:{quarkus-version}:create \ - -DprojectGroupId=org.acme \ - -DprojectArtifactId=openshift-quickstart \ - -DclassName="org.acme.rest.GreetingResource" \ - -Dpath="/greeting" \ - -Dextensions="resteasy,openshift" - -cd openshift-quickstart ----- +:create-app-artifact-id: openshift-quickstart +:create-app-extensions: resteasy,openshift +:create-app-code: +include::includes/devtools/create-app.adoc[] Quarkus offers the ability to automatically generate OpenShift resources based on sane defaults and user supplied configuration. The OpenShift extension is actually a wrapper extension that brings together the xref:deploying-to-kubernetes.adoc[kubernetes] and xref:container-image.adoc#s2i[container-image-s2i] @@ -43,12 +32,19 @@ extensions with sensible defaults so that it's easier for the user to get starte When we added the OpenShift extension to the command line invocation above, the following dependency was added to the `pom.xml` -[source,xml] +[source,xml,role="primary asciidoc-tabs-target-sync-cli asciidoc-tabs-target-sync-maven"] +.pom.xml +---- + + io.quarkus + quarkus-openshift + +---- + +[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"] +.build.gradle ---- - - io.quarkus - quarkus-openshift - +implementation("io.quarkus:quarkus-openshift") ---- == Log Into the OpenShift Cluster @@ -74,13 +70,11 @@ oc login --token=myToken --server=myServerUrl TIP: You can request the token via the _Copy Login Command_ link in the OpenShift web console. Finally, you don't need to use the OpenShift CLI at all. -Instead, set the `quarkus.kubernetes-client.master-url` config property and authenticate with the `quarkus.kubernetes-client.token`, or `quarkus.kubernetes-client.username` and `quarkus.kubernetes-client.password` respectively. +Instead, set the `quarkus.kubernetes-client.master-url` config property and authenticate with the `quarkus.kubernetes-client.token`, or `quarkus.kubernetes-client.username` and `quarkus.kubernetes-client.password` respectively: -.Log In - Configuration Properties Example -[source,bash] ----- -./mvnw clean package -Dquarkus.kubernetes-client.master-url=myServerUrl -Dquarkus.kubernetes-client.token=myToken ----- +:build-additional-parameters: -Dquarkus.kubernetes-client.master-url=myServerUrl -Dquarkus.kubernetes-client.token=myToken +include::includes/devtools/build.adoc[] +:!build-additional-parameters: == Build and Deployment @@ -88,10 +82,9 @@ You can trigger a build and deployment in a single step or build the container i To trigger a build and deployment in a single step: -[source,bash,subs=attributes+] ----- -./mvnw clean package -Dquarkus.kubernetes.deploy=true ----- +:build-additional-parameters: -Dquarkus.kubernetes.deploy=true +include::includes/devtools/build.adoc[] +:!build-additional-parameters: TIP: If you want to test your application immediately then set the `quarkus.openshift.route.expose` config property to `true` to <>, e.g. add `-Dquarkus.openshift.route.expose=true` to the command above. diff --git a/docs/src/main/asciidoc/dev-mode-differences.adoc b/docs/src/main/asciidoc/dev-mode-differences.adoc index 206875ce5018c..244edb3c453d6 100644 --- a/docs/src/main/asciidoc/dev-mode-differences.adoc +++ b/docs/src/main/asciidoc/dev-mode-differences.adoc @@ -101,6 +101,6 @@ the minimum amount of jars in memory. Perhaps the most important reason why dev-mode applications should not be run in production is that the dev-mode allows reading information that could be confidential (via the Dev-UI) while also giving access to operations that could be destructive (either by exposing endpoints that should not be available in production application or via the Dev-UI). -== Native binary +== Native executable -When a native binary is created (explained in detail xref:building-native-image.adoc[here]), it is *always* built from a production application. +When a native executable is created (explained in detail xref:building-native-image.adoc[here]), it is *always* built from a production application. diff --git a/docs/src/main/asciidoc/docinfo.html b/docs/src/main/asciidoc/docinfo.html index 2adbf012872ba..cae91e61d3362 100644 --- a/docs/src/main/asciidoc/docinfo.html +++ b/docs/src/main/asciidoc/docinfo.html @@ -6,11 +6,14 @@ href="https://cdnjs.cloudflare.com/ajax/libs/patternfly/3.24.0/css/patternfly-additions.min.css"> + +