From e24f7a3170b846b6205ff5dbb12bf0c31ac9e025 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Wed, 18 Sep 2024 20:23:12 +0300 Subject: [PATCH 01/47] Properly fail when both http and https servers started on port Fixes: #43373 (cherry picked from commit 6036d3c200d298c580d03cc2e8bbbd4abb804451) --- .../java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java index e802519f00101..4de23de77b0d1 100644 --- a/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java +++ b/extensions/vertx-http/runtime/src/main/java/io/quarkus/vertx/http/runtime/VertxHttpRecorder.java @@ -1375,7 +1375,8 @@ public void handle(AsyncResult event) { private void validateHttpPorts(int httpPort, int httpsPort) { if (httpsPort == httpPort) { - throw new IllegalArgumentException("Both http and https servers started on port " + httpPort); + startFuture + .fail(new IllegalArgumentException("Both http and https servers started on port " + httpPort)); } } }); From 61a10b99c4ef949dad83cbcb61e50466ca81783b Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Thu, 19 Sep 2024 10:45:39 +0300 Subject: [PATCH 02/47] Add Javadoc for DevMojo#jvmArgs I had to set this in a sample, and it took me a few tries to come up with the proper syntax for passing multiple parameters as the description of the property was completely absent (cherry picked from commit a417d6f6d8b07859189659ca34d3da4a540e2086) --- devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java | 4 ++++ 1 file changed, 4 insertions(+) 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 99d2c50c54b4e..8879a3e604cab 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java @@ -246,6 +246,10 @@ public class DevMojo extends AbstractMojo { @Parameter private File workingDir; + /** + * Allows configuring arbitrary JVM arguments. Multiple arguments can be specified by delimiting them with a space + * character. + */ @Parameter(defaultValue = "${jvm.args}") private String jvmArgs; From f6710518a8cc293664b888db7617047d30e2b5f8 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Mon, 23 Sep 2024 13:22:23 +0300 Subject: [PATCH 03/47] Make media type optional for InputStream when using multipart in REST Client Fixes: #43364 (cherry picked from commit a6cf385739d92d0d0f0865c0b02d80eeb2946caa) --- .../reactive/deployment/JaxrsClientReactiveProcessor.java | 2 +- .../rest/client/reactive/multipart/MultipartFilenameTest.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java b/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java index 17e5b6853fae9..fff8381b08c3b 100644 --- a/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java +++ b/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java @@ -1870,7 +1870,7 @@ private void addInputStream(BytecodeCreator methodCreator, AssignableResultHandl methodCreator.invokeVirtualMethod(MethodDescriptor.ofMethod(ClientMultipartForm.class, "entity", ClientMultipartForm.class, String.class, String.class, Object.class, String.class, Class.class), multipartForm, formParamResult, partFilenameResult, fieldValue, - methodCreator.load(partType), + methodCreator.load(partType != null ? partType : MediaType.APPLICATION_OCTET_STREAM), // FIXME: doesn't support generics methodCreator.loadClassFromTCCL(type))); } diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/multipart/MultipartFilenameTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/multipart/MultipartFilenameTest.java index 69bec01287d09..f345586162509 100644 --- a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/multipart/MultipartFilenameTest.java +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/multipart/MultipartFilenameTest.java @@ -401,7 +401,6 @@ public static class ClientFormUsingByteArray { public static class ClientFormUsingInputStream { @FormParam("myFile") - @PartType(APPLICATION_OCTET_STREAM) @PartFilename(FILE_NAME) public InputStream file; } From 9463e3bd2d2f6148838bb1f51a2d81ed56079456 Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Mon, 23 Sep 2024 13:22:40 +0200 Subject: [PATCH 04/47] WebSockets Next: ignore non-websocket connections - and proceed to the next route (cherry picked from commit 44ce63e4902d597cd01f2b78ec37045ff80a7518) --- .../NonWebSocketConnectionIgnoredTest.java | 47 +++++++++++++++++++ .../HttpUpgradeRedirectOnFailureTest.java | 2 + .../HttpUpgradeCheckHeaderMergingTest.java | 9 +++- .../next/runtime/WebSocketServerRecorder.java | 9 ++++ 4 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 extensions/websockets-next/deployment/src/test/java/io/quarkus/websockets/next/test/nonwebsocketconnection/NonWebSocketConnectionIgnoredTest.java diff --git a/extensions/websockets-next/deployment/src/test/java/io/quarkus/websockets/next/test/nonwebsocketconnection/NonWebSocketConnectionIgnoredTest.java b/extensions/websockets-next/deployment/src/test/java/io/quarkus/websockets/next/test/nonwebsocketconnection/NonWebSocketConnectionIgnoredTest.java new file mode 100644 index 0000000000000..a4de97f3b17e4 --- /dev/null +++ b/extensions/websockets-next/deployment/src/test/java/io/quarkus/websockets/next/test/nonwebsocketconnection/NonWebSocketConnectionIgnoredTest.java @@ -0,0 +1,47 @@ +package io.quarkus.websockets.next.test.nonwebsocketconnection; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.is; + +import jakarta.enterprise.event.Observes; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.websockets.next.OnTextMessage; +import io.quarkus.websockets.next.WebSocket; +import io.vertx.ext.web.Router; + +public class NonWebSocketConnectionIgnoredTest { + + @RegisterExtension + public static final QuarkusUnitTest test = new QuarkusUnitTest() + .withApplicationRoot(root -> { + root.addClasses(Echo.class); + }); + + @Test + void testNonWebSocketConnection() { + given().when() + .get("/echo") + .then() + .statusCode(200) + .body(is("ok")); + } + + @WebSocket(path = "/echo") + public static class Echo { + + @OnTextMessage + String process(String message) { + return message; + } + + } + + static void registerRoute(@Observes Router router) { + router.route("/echo").handler(rc -> rc.response().end("ok")); + } + +} diff --git a/extensions/websockets-next/deployment/src/test/java/io/quarkus/websockets/next/test/security/HttpUpgradeRedirectOnFailureTest.java b/extensions/websockets-next/deployment/src/test/java/io/quarkus/websockets/next/test/security/HttpUpgradeRedirectOnFailureTest.java index e266e0d97d1ed..167f5d0b9905b 100644 --- a/extensions/websockets-next/deployment/src/test/java/io/quarkus/websockets/next/test/security/HttpUpgradeRedirectOnFailureTest.java +++ b/extensions/websockets-next/deployment/src/test/java/io/quarkus/websockets/next/test/security/HttpUpgradeRedirectOnFailureTest.java @@ -58,6 +58,8 @@ public void testRedirectOnFailure() { // test redirected on failure RestAssured .given() + // without this header the client would receive 404 + .header("Sec-WebSocket-Key", "foo") .redirects() .follow(false) .get(endUri) diff --git a/extensions/websockets-next/deployment/src/test/java/io/quarkus/websockets/next/test/upgrade/HttpUpgradeCheckHeaderMergingTest.java b/extensions/websockets-next/deployment/src/test/java/io/quarkus/websockets/next/test/upgrade/HttpUpgradeCheckHeaderMergingTest.java index cbec099986e8a..67a7aa802e692 100644 --- a/extensions/websockets-next/deployment/src/test/java/io/quarkus/websockets/next/test/upgrade/HttpUpgradeCheckHeaderMergingTest.java +++ b/extensions/websockets-next/deployment/src/test/java/io/quarkus/websockets/next/test/upgrade/HttpUpgradeCheckHeaderMergingTest.java @@ -39,7 +39,14 @@ public class HttpUpgradeCheckHeaderMergingTest { public void testHeadersMultiMap() { // this is a way to test scenario where HttpUpgradeChecks set headers // but the checks itself did not reject upgrade, the upgrade wasn't performed due to incorrect headers - var headers = RestAssured.given().get(headersUri).then().statusCode(400).extract().headers(); + var headers = RestAssured.given() + // without this header the client would receive 404 + .header("Sec-WebSocket-Key", "foo") + .get(headersUri) + .then() + .statusCode(400) + .extract() + .headers(); assertNotNull(headers); assertTrue(headers.size() >= 3); diff --git a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketServerRecorder.java b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketServerRecorder.java index 6deedde0f6409..c1e464e4b0190 100644 --- a/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketServerRecorder.java +++ b/extensions/websockets-next/runtime/src/main/java/io/quarkus/websockets/next/runtime/WebSocketServerRecorder.java @@ -8,6 +8,8 @@ import jakarta.enterprise.inject.Instance; +import org.jboss.logging.Logger; + import io.quarkus.arc.Arc; import io.quarkus.arc.ArcContainer; import io.quarkus.runtime.annotations.Recorder; @@ -16,6 +18,7 @@ import io.quarkus.security.spi.runtime.SecurityCheck; import io.quarkus.vertx.core.runtime.VertxCoreRecorder; import io.quarkus.vertx.http.runtime.security.QuarkusHttpUser; +import io.quarkus.websockets.next.HandshakeRequest; import io.quarkus.websockets.next.HttpUpgradeCheck; import io.quarkus.websockets.next.HttpUpgradeCheck.CheckResult; import io.quarkus.websockets.next.HttpUpgradeCheck.HttpUpgradeContext; @@ -34,6 +37,8 @@ @Recorder public class WebSocketServerRecorder { + private static final Logger LOG = Logger.getLogger(WebSocketServerRecorder.class); + private final WebSocketsServerRuntimeConfig config; public WebSocketServerRecorder(WebSocketsServerRuntimeConfig config) { @@ -95,6 +100,10 @@ public Handler createEndpointHandler(String generatedEndpointCla @Override public void handle(RoutingContext ctx) { + if (!ctx.request().headers().contains(HandshakeRequest.SEC_WEBSOCKET_KEY)) { + LOG.debugf("Non-websocket client request ignored:\n%s", ctx.request().headers()); + ctx.next(); + } if (httpUpgradeChecks != null) { checkHttpUpgrade(ctx, endpointId).subscribe().with(result -> { if (!result.getResponseHeaders().isEmpty()) { From 0b2b02c17b87526ac18aacc05b1e35986f98bf49 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Mon, 23 Sep 2024 14:32:49 +0300 Subject: [PATCH 05/47] Support @HEAD and @OPTIONS in sub-resources This is the same exact support as exists for normal Resource methods Fixes: #43422 (cherry picked from commit 898b038d2d4b1f12da8ae36f68e0135ba08a48b1) --- .../handlers/ResourceLocatorHandler.java | 31 ++++++++++++++++--- .../resource/basic/ParameterSubResTest.java | 14 +++++++++ 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResourceLocatorHandler.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResourceLocatorHandler.java index 0b3529f4f539d..83215887b91af 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResourceLocatorHandler.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/handlers/ResourceLocatorHandler.java @@ -9,6 +9,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; +import jakarta.ws.rs.HttpMethod; import jakarta.ws.rs.WebApplicationException; import jakarta.ws.rs.container.CompletionCallback; import jakarta.ws.rs.core.Response; @@ -58,14 +59,34 @@ public void onComplete(Throwable throwable) { if (target == null) { throw new RuntimeException("Resource locator method returned object that was not a resource: " + locator); } + RequestMapper mapper = target.get(requestContext.getMethod()); boolean hadNullMethodMapper = false; if (mapper == null) { - mapper = target.get(null); //another layer of resource locators maybe - // we set this without checking if we matched, but we only use it after - // we check for a null mapper, so by the time we use it, it must have meant that - // we had a matcher for a null method - hadNullMethodMapper = true; + String requestMethod = requestContext.getMethod(); + if (requestMethod.equals(HttpMethod.HEAD)) { + mapper = target.get(HttpMethod.GET); + } else if (requestMethod.equals(HttpMethod.OPTIONS)) { + Set allowedMethods = new HashSet<>(); + for (String method : target.keySet()) { + if (method == null) { + continue; + } + allowedMethods.add(method); + } + allowedMethods.add(HttpMethod.OPTIONS); + allowedMethods.add(HttpMethod.HEAD); + requestContext.abortWith(Response.ok().allow(allowedMethods).build()); + return; + } + + if (mapper == null) { + mapper = target.get(null); //another layer of resource locators maybe + // we set this without checking if we matched, but we only use it after + // we check for a null mapper, so by the time we use it, it must have meant that + // we had a matcher for a null method + hadNullMethodMapper = true; + } } if (mapper == null) { throw new WebApplicationException(Response.status(Response.Status.METHOD_NOT_ALLOWED.getStatusCode()).build()); diff --git a/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/resource/basic/ParameterSubResTest.java b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/resource/basic/ParameterSubResTest.java index 5f533daa56e6f..e4c8498852242 100644 --- a/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/resource/basic/ParameterSubResTest.java +++ b/independent-projects/resteasy-reactive/server/vertx/src/test/java/org/jboss/resteasy/reactive/server/vertx/test/resource/basic/ParameterSubResTest.java @@ -96,6 +96,20 @@ public void testSubResource() throws Exception { Assertions.assertEquals("Boo! - fred", response.readEntity(String.class), "Wrong content of response"); } + @Test + @DisplayName("Test Sub Resource - HEAD") + public void testSubResourceHead() throws Exception { + Response response = client.target(generateURL("/path/sub/fred")).request().head(); + Assertions.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + } + + @Test + @DisplayName("Test Sub Resource - OPTIONS") + public void testSubResourceOptions() throws Exception { + Response response = client.target(generateURL("/path/sub/fred")).request().options(); + Assertions.assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); + } + @Test @DisplayName("Test Return Sub Resource As Class") public void testReturnSubResourceAsClass() throws Exception { From 10f3ccdc917278d8c85109fe598a480ff10da585 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 24 Sep 2024 13:33:37 +0300 Subject: [PATCH 06/47] Make sure Transfer-Encoding set by a Resource is honored Closes: #42238 (cherry picked from commit 7005ab9d2ea09b02d7bee74cda11d5d59d7a13aa) --- .../server/test/headers/VertxHeadersTest.java | 60 +++++++++++++++++++ .../server/core/ServerSerialisers.java | 6 +- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/headers/VertxHeadersTest.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/headers/VertxHeadersTest.java index 8c7e646778c2a..eb3b76473b2a6 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/headers/VertxHeadersTest.java +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/headers/VertxHeadersTest.java @@ -2,6 +2,7 @@ import static io.restassured.RestAssured.when; import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.CoreMatchers.is; import java.io.IOException; @@ -11,6 +12,7 @@ import jakarta.ws.rs.container.ContainerResponseContext; import jakarta.ws.rs.container.ContainerResponseFilter; import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.Provider; import org.junit.jupiter.api.Test; @@ -18,6 +20,7 @@ import io.quarkus.test.QuarkusUnitTest; import io.quarkus.vertx.web.RouteFilter; +import io.restassured.http.Headers; import io.vertx.ext.web.RoutingContext; public class VertxHeadersTest { @@ -35,6 +38,16 @@ void testVaryHeaderValues() { assertThat(headers.getValues(HttpHeaders.VARY)).containsExactlyInAnyOrder("Origin", "Prefer"); } + @Test + void testTransferEncodingHeaderValues() { + Headers headers = when().get("/test/response") + .then() + .statusCode(200) + .header("Transfer-Encoding", is("chunked")).extract().headers(); + + assertThat(headers.asList()).noneMatch(h -> h.getName().equals("transfer-encoding")); + } + public static class VertxFilter { @RouteFilter void addVary(final RoutingContext rc) { @@ -59,5 +72,52 @@ public static class TestResource { public String test() { return "test"; } + + @GET + @Path("response") + public Response response() { + final String text = "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."; + TestDTO testDTO = new TestDTO(); + for (int i = 0; i < 100; i++) { + testDTO.setText(testDTO.getText() + text); + testDTO.setMoreText(testDTO.getMoreText() + text); + testDTO.setEvenMoreText(testDTO.getEvenMoreText() + text); + } + + //Simulate getting a chunked response from external microservice + Response response = Response.ok().entity("test").header("Transfer-Encoding", "chunked").build(); + //Forwarding the response + return Response.fromResponse(response).build(); + } + } + + public static class TestDTO { + public String text = ""; + public String moreText = ""; + public String evenMoreText = ""; + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public String getMoreText() { + return moreText; + } + + public void setMoreText(String moreText) { + this.moreText = moreText; + } + + public String getEvenMoreText() { + return evenMoreText; + } + + public void setEvenMoreText(String evenMoreText) { + this.evenMoreText = evenMoreText; + } } } diff --git a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ServerSerialisers.java b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ServerSerialisers.java index bc2fb03386e92..e5b51941aa3ff 100644 --- a/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ServerSerialisers.java +++ b/independent-projects/resteasy-reactive/server/runtime/src/main/java/org/jboss/resteasy/reactive/server/core/ServerSerialisers.java @@ -86,6 +86,7 @@ public void accept(ResteasyReactiveRequestContext context) { private static final String LENGTH = "Length"; private static final String LENGTH_LOWER = "length"; private static final String CONTENT_TYPE = CONTENT + "-" + TYPE; // use this instead of the Vert.x constant because the TCK expects upper case + private static final String TRANSFER_ENCODING = "Transfer-Encoding"; public final static List BUILTIN_READERS = List.of( new Serialisers.BuiltinReader(String.class, ServerStringMessageBodyHandler.class, @@ -519,7 +520,7 @@ public static void encodeResponseHeaders(ResteasyReactiveRequestContext requestC vertxResponse.addResponseHeader(header, (CharSequence) HeaderUtil.headerToString(o)); } } - if (header.equalsIgnoreCase("Transfer-Encoding")) { // using both headers together is not allowed + if (header.equalsIgnoreCase(TRANSFER_ENCODING)) { // using both headers together is not allowed vertxResponse.removeResponseHeader("Content-Length"); } } else { @@ -533,7 +534,8 @@ public static void encodeResponseHeaders(ResteasyReactiveRequestContext requestC } private static boolean requireSingleHeader(String header) { - if (!(header.startsWith(CONTENT) || header.startsWith(CONTENT_LOWER) || header.startsWith(LOCATION))) { + if (!(header.startsWith(CONTENT) || header.startsWith(CONTENT_LOWER) || header.startsWith(LOCATION) + || header.equalsIgnoreCase(TRANSFER_ENCODING))) { return false; } if (header.length() < CONTENT.length() + 2) { From e403a2f6ab558ca6f61d1fad87b0c3956f265c9b Mon Sep 17 00:00:00 2001 From: Chris Laprun Date: Tue, 24 Sep 2024 22:11:35 +0200 Subject: [PATCH 07/47] Inherit defaults from Fabric8 kubernetes client defaults Fixes #43474 Signed-off-by: Chris Laprun (cherry picked from commit 243b4d3bc1981f3a749c581f18956a855ae6793e) --- .../runtime/KubernetesClientBuildConfig.java | 19 +++++++----------- .../client/runtime/KubernetesClientUtils.java | 20 +++++++++++++------ 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesClientBuildConfig.java b/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesClientBuildConfig.java index b6a2e71d2b35c..e562bdb748259 100644 --- a/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesClientBuildConfig.java +++ b/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesClientBuildConfig.java @@ -3,6 +3,7 @@ import java.time.Duration; import java.util.List; import java.util.Optional; +import java.util.OptionalInt; import io.quarkus.runtime.annotations.ConfigDocSection; import io.quarkus.runtime.annotations.ConfigPhase; @@ -93,39 +94,33 @@ public interface KubernetesClientBuildConfig { /** * Watch reconnect interval */ - @WithDefault("PT1S") // default lifted from Kubernetes Client - Duration watchReconnectInterval(); + Optional watchReconnectInterval(); /** * Maximum reconnect attempts in case of watch failure * By default there is no limit to the number of reconnect attempts */ - @WithDefault("-1") // default lifted from Kubernetes Client - int watchReconnectLimit(); + OptionalInt watchReconnectLimit(); /** * Maximum amount of time to wait for a connection with the API server to be established */ - @WithDefault("PT10S") // default lifted from Kubernetes Client - Duration connectionTimeout(); + Optional connectionTimeout(); /** * Maximum amount of time to wait for a request to the API server to be completed */ - @WithDefault("PT10S") // default lifted from Kubernetes Client - Duration requestTimeout(); + Optional requestTimeout(); /** * Maximum number of retry attempts for API requests that fail with an HTTP code of >= 500 */ - @WithDefault("0") // default lifted from Kubernetes Client - Integer requestRetryBackoffLimit(); + OptionalInt requestRetryBackoffLimit(); /** * Time interval between retry attempts for API requests that fail with an HTTP code of >= 500 */ - @WithDefault("PT1S") // default lifted from Kubernetes Client - Duration requestRetryBackoffInterval(); + Optional requestRetryBackoffInterval(); /** * HTTP proxy used to access the Kubernetes API server diff --git a/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesClientUtils.java b/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesClientUtils.java index 3dfb15b440fda..534b3796300b4 100644 --- a/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesClientUtils.java +++ b/extensions/kubernetes-client/runtime-internal/src/main/java/io/quarkus/kubernetes/client/runtime/KubernetesClientUtils.java @@ -1,6 +1,7 @@ package io.quarkus.kubernetes.client.runtime; import java.time.Duration; +import java.util.Optional; import org.eclipse.microprofile.config.ConfigProvider; @@ -23,10 +24,11 @@ public static Config createConfig(KubernetesClientBuildConfig buildConfig) { boolean trustAll = buildConfig.trustCerts().isPresent() ? buildConfig.trustCerts().get() : globalTrustAll; return new ConfigBuilder() .withTrustCerts(trustAll) - .withWatchReconnectInterval((int) buildConfig.watchReconnectInterval().toMillis()) - .withWatchReconnectLimit(buildConfig.watchReconnectLimit()) - .withConnectionTimeout((int) buildConfig.connectionTimeout().toMillis()) - .withRequestTimeout((int) buildConfig.requestTimeout().toMillis()) + .withWatchReconnectInterval( + millisAsInt(buildConfig.watchReconnectInterval()).orElse(base.getWatchReconnectInterval())) + .withWatchReconnectLimit(buildConfig.watchReconnectLimit().orElse(base.getWatchReconnectLimit())) + .withConnectionTimeout(millisAsInt(buildConfig.connectionTimeout()).orElse(base.getConnectionTimeout())) + .withRequestTimeout(millisAsInt(buildConfig.requestTimeout()).orElse(base.getRequestTimeout())) .withMasterUrl(buildConfig.apiServerUrl().or(() -> buildConfig.masterUrl()).orElse(base.getMasterUrl())) .withNamespace(buildConfig.namespace().orElse(base.getNamespace())) .withUsername(buildConfig.username().orElse(base.getUsername())) @@ -46,11 +48,17 @@ public static Config createConfig(KubernetesClientBuildConfig buildConfig) { .withProxyPassword(buildConfig.proxyPassword().orElse(base.getProxyPassword())) .withNoProxy(buildConfig.noProxy().map(list -> list.toArray(new String[0])).orElse(base.getNoProxy())) .withHttp2Disable(base.isHttp2Disable()) - .withRequestRetryBackoffInterval((int) buildConfig.requestRetryBackoffInterval().toMillis()) - .withRequestRetryBackoffLimit(buildConfig.requestRetryBackoffLimit()) + .withRequestRetryBackoffInterval(millisAsInt(buildConfig.requestRetryBackoffInterval()) + .orElse(base.getRequestRetryBackoffInterval())) + .withRequestRetryBackoffLimit(buildConfig.requestRetryBackoffLimit().orElse(base.getRequestRetryBackoffLimit())) .build(); } + @SuppressWarnings("OptionalUsedAsFieldOrParameterType") + private static Optional millisAsInt(Optional duration) { + return duration.map(d -> (int) d.toMillis()); + } + public static KubernetesClient createClient(KubernetesClientBuildConfig buildConfig) { return new KubernetesClientBuilder().withConfig(createConfig(buildConfig)).build(); } From 806cfa35f56bb25c5c6af8f1d85da228426dd504 Mon Sep 17 00:00:00 2001 From: Marc Nuri Date: Wed, 25 Sep 2024 11:56:44 +0200 Subject: [PATCH 08/47] deps: Bump kubernetes-client-bom from 6.13.3 to 6.13.4 Signed-off-by: Marc Nuri (cherry picked from commit f1ffb87ba5ba19f0081bce83f80086906ab457f1) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9cd2125ab9c66..99637d79475c4 100644 --- a/pom.xml +++ b/pom.xml @@ -69,7 +69,7 @@ 0.8.12 - 6.13.3 + 6.13.4 5.5.0 6.6.0.Final 4.13.0 From 64862536515f0324db05a524f2ce490081aba1d6 Mon Sep 17 00:00:00 2001 From: Auri Munoz Date: Wed, 25 Sep 2024 17:04:44 +0200 Subject: [PATCH 09/47] Use latest quarkus-spring-api Fixes #42237 (cherry picked from commit 9cf2c8028bbb6a6b061e4c75d7c6e0de2e419194) --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 230430cd23c2f..86a582ef1effd 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -175,7 +175,7 @@ 3.26.1 0.3.0 4.16.2 - 6.1.SP3 + 6.1.SP4 3.2.SP2 6.2 3.2 From 1b40fbff1c84adec4f76e166ada3ef41bcf16c52 Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Wed, 25 Sep 2024 15:59:39 +0200 Subject: [PATCH 10/47] Qute: improve docs/javadoc about value resolvers ordering (cherry picked from commit 2fe1b113bdc89ae83a496d6897ba2dfd2a782044) --- docs/src/main/asciidoc/qute-reference.adoc | 11 ++++++++++- .../java/io/quarkus/qute/TemplateExtension.java | 5 +++++ .../main/java/io/quarkus/qute/ValueResolver.java | 14 +++++++++++++- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/docs/src/main/asciidoc/qute-reference.adoc b/docs/src/main/asciidoc/qute-reference.adoc index ec2baa1116b13..5cdeab97b1833 100644 --- a/docs/src/main/asciidoc/qute-reference.adoc +++ b/docs/src/main/asciidoc/qute-reference.adoc @@ -335,7 +335,7 @@ You can learn more about virtual methods in the <> is used. The first part of the expression is always resolved against the <>. If no result is found for the first part, it's resolved against the parent context object (if available). For an expression that starts with a namespace the current context object is found using all the available ``NamespaceResolver``s. @@ -1451,6 +1451,11 @@ NOTE: The template rendering is divided in two phases. During the first phase, w ==== Value Resolvers Value resolvers are used when evaluating expressions. +First the resolvers that apply to the given `EvalContext` are filtered. +Then the resolver with _highest priority_ is used to resolve the data. +If a `io.quarkus.qute.Results.NotFound` object is returned then the next available resolver is used instead. +However, `null` return value is considered a valid result. + A custom `io.quarkus.qute.ValueResolver` can be registered programmatically via `EngineBuilder.addValueResolver()`. .`ValueResolver` Builder Example @@ -1462,6 +1467,10 @@ engineBuilder.addValueResolver(ValueResolver.builder() .build()); ---- +TIP: In Quarkus, the <> annotation can be used to register a `ValueResolver` implemented as a CDI bean. + +NOTE: Keep in mind that the reflection-based value resolver has priority `-1` and the max priority value for resolvers generated from <> and <> is `10`. + [[template-locator]] ==== Template Locator diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/TemplateExtension.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/TemplateExtension.java index cc2c958ec0df8..5e79e687e7ad6 100644 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/TemplateExtension.java +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/TemplateExtension.java @@ -125,8 +125,13 @@ String matchRegex() default ""; /** + * Value resolvers with higher priority take precedence. + *

+ * Keep in mind that the reflection-based value resolver has priority {@code -1} and the max priority value for + * resolvers generated from {@link TemplateData} and type-safe expressions is {@code 10}. * * @return the priority used by the generated value resolver + * @see ValueResolver#getPriority() */ int priority() default DEFAULT_PRIORITY; diff --git a/independent-projects/qute/core/src/main/java/io/quarkus/qute/ValueResolver.java b/independent-projects/qute/core/src/main/java/io/quarkus/qute/ValueResolver.java index 918b82f31f496..9ea4cc57dd866 100644 --- a/independent-projects/qute/core/src/main/java/io/quarkus/qute/ValueResolver.java +++ b/independent-projects/qute/core/src/main/java/io/quarkus/qute/ValueResolver.java @@ -4,7 +4,9 @@ * Value resolvers are used when evaluating expressions. *

* First the resolvers that apply to the given {@link EvalContext} are filtered. Then the resolver with highest priority is used - * to resolve the data. If {@link Results#isNotFound(Object)} is returned the next available resolver is tried. + * to resolve the data. If a {@link io.quarkus.qute.Results.NotFound} object is returned then the next available resolver is + * used instead. However, + * {@code null} return value is considered a valid result. * * @see EvalContext * @see EngineBuilder#addValueResolver(ValueResolver) @@ -12,6 +14,16 @@ */ public interface ValueResolver extends Resolver, WithPriority { + /** + * Value resolvers with higher priority take precedence. + * + * @return the priority value + */ + @Override + default int getPriority() { + return WithPriority.super.getPriority(); + } + /** * * @param context From a548dff030f10126ccf59efd7c4967b8c5abe514 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Thu, 26 Sep 2024 12:47:23 +0300 Subject: [PATCH 11/47] Quiet down logs of observability DevResources (cherry picked from commit 97d1454250cdb3742ab071a98dbc7aa307741e10) --- .../io/quarkus/observability/devresource/DevResources.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/observability-devservices/testlibs/devresource-common/src/main/java/io/quarkus/observability/devresource/DevResources.java b/extensions/observability-devservices/testlibs/devresource-common/src/main/java/io/quarkus/observability/devresource/DevResources.java index 0dbd79ed0579e..b94090c40e64b 100644 --- a/extensions/observability-devservices/testlibs/devresource-common/src/main/java/io/quarkus/observability/devresource/DevResources.java +++ b/extensions/observability-devservices/testlibs/devresource-common/src/main/java/io/quarkus/observability/devresource/DevResources.java @@ -25,7 +25,7 @@ public class DevResources { */ public static synchronized List resources() { if (resources == null) { - log.info("Activating dev resources"); + log.debug("Activating dev resources"); resources = ServiceLoader .load(DevResourceLifecycleManager.class, Thread.currentThread().getContextClassLoader()) @@ -34,7 +34,7 @@ public static synchronized List resources() { .sorted(Comparator.comparing(DevResourceLifecycleManager::order)) .collect(Collectors.toList()); - log.infof("Found dev resources: %s", resources); + log.debugf("Found dev resources: %s", resources); } return resources; } From a4ce46ec19976cc2e849286a90192e2876d6edba Mon Sep 17 00:00:00 2001 From: Alexey Loubyansky Date: Thu, 26 Sep 2024 10:20:07 +0200 Subject: [PATCH 12/47] Check whether a dependency has resolved paths before setting a component path (cherry picked from commit 84baf7c77274706b059830d8f143c9d12a0ba516) --- .../java/io/quarkus/sbom/ApplicationManifestConfig.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/sbom/ApplicationManifestConfig.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/sbom/ApplicationManifestConfig.java index f350cd7e7c6b0..703945f056b8e 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/sbom/ApplicationManifestConfig.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/sbom/ApplicationManifestConfig.java @@ -41,10 +41,11 @@ private Builder() { public Builder setApplicationModel(ApplicationModel model) { setMainComponent(ApplicationComponent.builder().setResolvedDependency(model.getAppArtifact()).build()); for (var d : model.getDependencies()) { - addComponent(ApplicationComponent.builder() - .setResolvedDependency(d) - .setPath(d.getResolvedPaths().iterator().next()) - .build()); + final ApplicationComponent.Builder comp = ApplicationComponent.builder().setResolvedDependency(d); + if (!d.getResolvedPaths().isEmpty()) { + comp.setPath(d.getResolvedPaths().iterator().next()); + } + addComponent(comp.build()); } return this; } From 6530b761d3d92a9c9dfa9e94732b67e358e7cdb1 Mon Sep 17 00:00:00 2001 From: Marek Skacelik Date: Thu, 26 Sep 2024 14:52:07 +0200 Subject: [PATCH 13/47] Fixed trust all option after reload (TlsRegistry) (cherry picked from commit 47e000c41b296a9b22eadee0ab97c0d65e19904e) --- .../java/io/quarkus/tls/runtime/VertxCertificateHolder.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/VertxCertificateHolder.java b/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/VertxCertificateHolder.java index c71b45168bfab..2c3ae411f890d 100644 --- a/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/VertxCertificateHolder.java +++ b/extensions/tls-registry/runtime/src/main/java/io/quarkus/tls/runtime/VertxCertificateHolder.java @@ -18,6 +18,7 @@ import io.quarkus.tls.TlsConfiguration; import io.quarkus.tls.runtime.config.TlsBucketConfig; import io.quarkus.tls.runtime.config.TlsConfigUtils; +import io.quarkus.tls.runtime.keystores.TrustAllOptions; import io.vertx.core.Vertx; import io.vertx.core.buffer.Buffer; import io.vertx.core.net.KeyCertOptions; @@ -167,6 +168,8 @@ public boolean reload() { } catch (Exception e) { return false; } + } else if (config.trustAll()) { + trustStoreUpdateResult = new TrustStoreAndTrustOptions(null, TrustAllOptions.INSTANCE); } if (keyStoreUpdateResult == null && trustStoreUpdateResult == null) { From d7f1a786234b0575ebac61c2f3588163137c6c96 Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Fri, 27 Sep 2024 11:45:10 +0200 Subject: [PATCH 14/47] WebSockets Next: fix Dev UI for nested endpoint class - fixes #43534 (cherry picked from commit 03a514d337dbe9f3948a838822cc7058460d0416) --- .../deployment/src/main/resources/dev-ui/qwc-wsn-endpoints.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/websockets-next/deployment/src/main/resources/dev-ui/qwc-wsn-endpoints.js b/extensions/websockets-next/deployment/src/main/resources/dev-ui/qwc-wsn-endpoints.js index b18e57b0665d1..57ade7ec90e0a 100644 --- a/extensions/websockets-next/deployment/src/main/resources/dev-ui/qwc-wsn-endpoints.js +++ b/extensions/websockets-next/deployment/src/main/resources/dev-ui/qwc-wsn-endpoints.js @@ -248,7 +248,7 @@ export class QwcWebSocketNextEndpoints extends LitElement { } _renderPath(endpoint) { - const inputId = endpoint.clazz.replaceAll("\.","_"); + const inputId = endpoint.clazz.replaceAll("\.","_").replaceAll("\$","_"); const hasPathParam = endpoint.path.indexOf('{') != -1; var inputPath; var resetButton; From 45cdce9a8fd398720745ed4116ce9041c44d70b5 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Sat, 28 Sep 2024 19:21:22 +0200 Subject: [PATCH 15/47] Update Maven Archetype Plugin to 3.3.0 (cherry picked from commit 97d2614a53a1d5388d062d499f607e09e8a97fd4) --- extensions/amazon-lambda-http/maven-archetype/pom.xml | 3 +-- extensions/amazon-lambda-rest/maven-archetype/pom.xml | 3 +-- extensions/amazon-lambda/maven-archetype/pom.xml | 3 +-- .../funqy/funqy-amazon-lambda/maven-archetype/pom.xml | 3 +-- independent-projects/parent/pom.xml | 6 ++++++ 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/extensions/amazon-lambda-http/maven-archetype/pom.xml b/extensions/amazon-lambda-http/maven-archetype/pom.xml index 46d08e54ec6a3..b51116d6bf26e 100644 --- a/extensions/amazon-lambda-http/maven-archetype/pom.xml +++ b/extensions/amazon-lambda-http/maven-archetype/pom.xml @@ -34,7 +34,7 @@ org.apache.maven.archetype archetype-packaging - 3.0.1 + ${version.archetype.plugin} @@ -49,7 +49,6 @@ org.apache.maven.plugins maven-archetype-plugin - 3.0.1 diff --git a/extensions/amazon-lambda-rest/maven-archetype/pom.xml b/extensions/amazon-lambda-rest/maven-archetype/pom.xml index 2e5548c2e40a2..edabafedd4f02 100644 --- a/extensions/amazon-lambda-rest/maven-archetype/pom.xml +++ b/extensions/amazon-lambda-rest/maven-archetype/pom.xml @@ -34,7 +34,7 @@ org.apache.maven.archetype archetype-packaging - 3.0.1 + ${version.archetype.plugin} @@ -49,7 +49,6 @@ org.apache.maven.plugins maven-archetype-plugin - 3.0.1 diff --git a/extensions/amazon-lambda/maven-archetype/pom.xml b/extensions/amazon-lambda/maven-archetype/pom.xml index 12c99d24e3957..48bf4153e32f5 100644 --- a/extensions/amazon-lambda/maven-archetype/pom.xml +++ b/extensions/amazon-lambda/maven-archetype/pom.xml @@ -41,7 +41,7 @@ org.apache.maven.archetype archetype-packaging - 3.0.1 + ${version.archetype.plugin} @@ -56,7 +56,6 @@ org.apache.maven.plugins maven-archetype-plugin - 3.0.1 diff --git a/extensions/funqy/funqy-amazon-lambda/maven-archetype/pom.xml b/extensions/funqy/funqy-amazon-lambda/maven-archetype/pom.xml index 0534177ec9f3c..fc8d842bcf22e 100644 --- a/extensions/funqy/funqy-amazon-lambda/maven-archetype/pom.xml +++ b/extensions/funqy/funqy-amazon-lambda/maven-archetype/pom.xml @@ -34,7 +34,7 @@ org.apache.maven.archetype archetype-packaging - 3.0.1 + ${version.archetype.plugin} @@ -49,7 +49,6 @@ org.apache.maven.plugins maven-archetype-plugin - 3.0.1 diff --git a/independent-projects/parent/pom.xml b/independent-projects/parent/pom.xml index 8f1931f64ae5f..0ef76c2087629 100644 --- a/independent-projects/parent/pom.xml +++ b/independent-projects/parent/pom.xml @@ -17,6 +17,7 @@ + 3.3.0 3.6.0 3.0.0 3.2.0 @@ -221,6 +222,11 @@ + + org.apache.maven.plugins + maven-archetype-plugin + ${version.archetype.plugin} + org.apache.maven.plugins maven-compiler-plugin From 13893f36acd80c1842c1872648afab8a97230a1b Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Mon, 30 Sep 2024 13:40:28 +0300 Subject: [PATCH 16/47] Add note about ExceptionMapper in validation guide Relates to: #12006 (cherry picked from commit fa187a7dd57293c36032aa528b1d389b5f4ff2b2) --- docs/src/main/asciidoc/validation.adoc | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/docs/src/main/asciidoc/validation.adoc b/docs/src/main/asciidoc/validation.adoc index 425d97b01fc7b..921c5e81de8c8 100644 --- a/docs/src/main/asciidoc/validation.adoc +++ b/docs/src/main/asciidoc/validation.adoc @@ -199,6 +199,42 @@ As you can see, we don't have to manually validate the provided `Book` anymore a If a validation error is triggered, a violation report is generated and serialized as JSON as our end point produces a JSON output. It can be extracted and manipulated to display a proper error message. +An example of such a report could be: + +[source, json] +---- +{ + "title": "Constraint Violation", + "status": 400, + "violations": [ + { + "field": "tryMeEndPointMethodValidation.book.title", + "message": "Title cannot be blank" + } + ] +} +---- + +This response is produced by Quarkus via a builtin implementation of `jakarta.ws.rs.ext.ExceptionMapper`. If the application code needs to handle `ValidationException` in some custom way, +it can provide an implementation of `jakarta.ws.rs.ext.ExceptionMapper` like so: + +[source, java] +---- +import jakarta.validation.ValidationException; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; +import jakarta.ws.rs.ext.Provider; + +@Provider +public class ResteasyReactiveViolationExceptionMapper implements ExceptionMapper { + + @Override + public Response toResponse(ValidationException exception) { + // TODO: implement + } +} +---- + == Service method validation It might not always be handy to have the validation rules declared at the end point level as it could duplicate some business validation. From 90c729a5a55348b45d01b936519d827a65694660 Mon Sep 17 00:00:00 2001 From: xstefank Date: Thu, 26 Sep 2024 14:53:24 +0200 Subject: [PATCH 17/47] Remove deprecated RunOptions mention in the transactions docs (cherry picked from commit 901489ff779ad400abe60e4c43536b39ac6e1205) --- docs/src/main/asciidoc/transaction.adoc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/src/main/asciidoc/transaction.adoc b/docs/src/main/asciidoc/transaction.adoc index e1a79bd5e1da4..efed7ffa0cff6 100644 --- a/docs/src/main/asciidoc/transaction.adoc +++ b/docs/src/main/asciidoc/transaction.adoc @@ -164,7 +164,6 @@ a functional approach that allows you to run a lambda within the scope of a tran [source,java] ---- import io.quarkus.narayana.jta.QuarkusTransaction; -import io.quarkus.narayana.jta.RunOptions; public class TransactionExample { @@ -191,7 +190,7 @@ public class TransactionExample { .timeout(10) .exceptionHandler((throwable) -> { if (throwable instanceof SomeException) { - return RunOptions.ExceptionResult.COMMIT; + return TransactionExceptionResult.COMMIT; } return TransactionExceptionResult.ROLLBACK; }) From 1c6b589a2b025e11cf859e8046d8c7b9f6e536f7 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Fri, 13 Sep 2024 17:49:31 -0300 Subject: [PATCH 18/47] Using reusable workflows in Quarkiverse release process (cherry picked from commit cc224d39029e4579982f4c424ef7b0d2a86c5719) --- .../.github/workflows/release.tpl.qute.yml | 72 ++++--------------- ...rkiverse-ext_.github_workflows_release.yml | 72 ++++--------------- 2 files changed, 28 insertions(+), 116 deletions(-) diff --git a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release.tpl.qute.yml b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release.tpl.qute.yml index bb3d54d2768ba..fb96ae2c77d22 100644 --- a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release.tpl.qute.yml +++ b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release.tpl.qute.yml @@ -2,7 +2,7 @@ name: Quarkiverse Release on: pull_request: - types: [closed] + types: [ closed ] paths: - '.github/project.yml' @@ -10,61 +10,17 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -defaults: - run: - shell: bash - jobs: - release: - runs-on: ubuntu-latest - name: release - if: ${{github.event.pull_request.merged == true}} - - steps: - - uses: radcortez/project-metadata-action@main - name: Retrieve project metadata - id: metadata - with: - github-token: ${{secrets.GITHUB_TOKEN}} - metadata-file-path: '.github/project.yml' - - - uses: actions/checkout@v4 - - - name: Set up JDK {java.version} - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: {java.version} - cache: 'maven' - server-id: ossrh - server-username: MAVEN_USERNAME - server-password: MAVEN_PASSWORD - gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} - gpg-passphrase: MAVEN_GPG_PASSPHRASE - - - name: Configure Git author - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - - - name: Update latest release version in docs - run: | - mvn -B -ntp -pl docs -am package -DskipTests -DskipITs -Denforcer.skip -Dformatter.skip -Dimpsort.skip - if ! git diff --quiet docs/modules/ROOT/pages/includes; then - git add docs/modules/ROOT/pages/includes - git commit -m "Update the latest release version ${{steps.metadata.outputs.current-version}} in documentation" - fi - - - name: Maven release ${{steps.metadata.outputs.current-version}} - run: | - mvn -B release:prepare -Prelease -DreleaseVersion=${{steps.metadata.outputs.current-version}} -DdevelopmentVersion=${{steps.metadata.outputs.next-version}} - mvn -B release:perform -Darguments=-DperformRelease -DperformRelease -Prelease - env: - MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} - MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} - MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} - - - name: Push changes to ${{github.base_ref}} branch - run: | - git push - git push origin ${{steps.metadata.outputs.current-version}} + prepare-release: + name: Prepare Release + if: ${{ github.event.pull_request.merged == true}} + uses: quarkiverse/.github/.github/workflows/prepare-release.yml@main + secrets: inherit + + perform-release: + name: Perform Release + needs: prepare-release + uses: quarkiverse/.github/.github/workflows/perform-release.yml@main + secrets: inherit + with: + version: ${{needs.prepare-release.outputs.release-version}} diff --git a/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release.yml b/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release.yml index b43c1ee0f931d..fb96ae2c77d22 100644 --- a/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release.yml +++ b/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release.yml @@ -2,7 +2,7 @@ name: Quarkiverse Release on: pull_request: - types: [closed] + types: [ closed ] paths: - '.github/project.yml' @@ -10,61 +10,17 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -defaults: - run: - shell: bash - jobs: - release: - runs-on: ubuntu-latest - name: release - if: ${{github.event.pull_request.merged == true}} - - steps: - - uses: radcortez/project-metadata-action@main - name: Retrieve project metadata - id: metadata - with: - github-token: ${{secrets.GITHUB_TOKEN}} - metadata-file-path: '.github/project.yml' - - - uses: actions/checkout@v4 - - - name: Set up JDK 17 - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: 17 - cache: 'maven' - server-id: ossrh - server-username: MAVEN_USERNAME - server-password: MAVEN_PASSWORD - gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} - gpg-passphrase: MAVEN_GPG_PASSPHRASE - - - name: Configure Git author - run: | - git config --local user.email "action@github.com" - git config --local user.name "GitHub Action" - - - name: Update latest release version in docs - run: | - mvn -B -ntp -pl docs -am package -DskipTests -DskipITs -Denforcer.skip -Dformatter.skip -Dimpsort.skip - if ! git diff --quiet docs/modules/ROOT/pages/includes; then - git add docs/modules/ROOT/pages/includes - git commit -m "Update the latest release version ${{steps.metadata.outputs.current-version}} in documentation" - fi - - - name: Maven release ${{steps.metadata.outputs.current-version}} - run: | - mvn -B release:prepare -Prelease -DreleaseVersion=${{steps.metadata.outputs.current-version}} -DdevelopmentVersion=${{steps.metadata.outputs.next-version}} - mvn -B release:perform -Darguments=-DperformRelease -DperformRelease -Prelease - env: - MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} - MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} - MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} - - - name: Push changes to ${{github.base_ref}} branch - run: | - git push - git push origin ${{steps.metadata.outputs.current-version}} + prepare-release: + name: Prepare Release + if: ${{ github.event.pull_request.merged == true}} + uses: quarkiverse/.github/.github/workflows/prepare-release.yml@main + secrets: inherit + + perform-release: + name: Perform Release + needs: prepare-release + uses: quarkiverse/.github/.github/workflows/perform-release.yml@main + secrets: inherit + with: + version: ${{needs.prepare-release.outputs.release-version}} From f8d9d542464460d3583f6a391d852582380dcb8c Mon Sep 17 00:00:00 2001 From: Martin Kouba Date: Mon, 30 Sep 2024 11:59:23 +0200 Subject: [PATCH 19/47] Qute: fix reload of templates backed by build item (cherry picked from commit 35ecc2f341268be390cc2ec9f3d4e86c138e35ee) --- .../builditemtemplate/AdditionalTemplatePathTest.java | 5 +++++ .../main/java/io/quarkus/qute/runtime/EngineProducer.java | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/builditemtemplate/AdditionalTemplatePathTest.java b/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/builditemtemplate/AdditionalTemplatePathTest.java index 24e4306532a16..989a5fc5ed5ad 100644 --- a/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/builditemtemplate/AdditionalTemplatePathTest.java +++ b/extensions/qute/deployment/src/test/java/io/quarkus/qute/deployment/builditemtemplate/AdditionalTemplatePathTest.java @@ -54,6 +54,11 @@ public void testTemplate() { assertEquals("Hello M!", engine.getTemplate("foo/hello.txt").data("name", "M").render()); assertEquals("Hello M!", engine.getTemplate("foo/hello").data("name", "M").render()); assertEquals("And... Hello M!", engine.getTemplate("include").data("name", "M").render()); + + // Test that reload works for additional content-based paths + engine.clearTemplates(); + assertEquals("Hello M!", engine.getTemplate("foo/hello").data("name", "M").render()); + assertEquals("Hello M!", engine.getTemplate("foo/hello.txt").data("name", "M").render()); } } diff --git a/extensions/qute/runtime/src/main/java/io/quarkus/qute/runtime/EngineProducer.java b/extensions/qute/runtime/src/main/java/io/quarkus/qute/runtime/EngineProducer.java index bc3d9c95225df..f6bbc3957396d 100644 --- a/extensions/qute/runtime/src/main/java/io/quarkus/qute/runtime/EngineProducer.java +++ b/extensions/qute/runtime/src/main/java/io/quarkus/qute/runtime/EngineProducer.java @@ -369,7 +369,7 @@ private Optional locate(String path) { // Then try the template contents LOGGER.debugf("Locate template contents for %s", path); String content = templateContents.get(path); - if (path == null) { + if (content == null) { // Try path with suffixes for (String suffix : suffixes) { String pathWithSuffix = path + "." + suffix; From f51efc064b09a9b469cf5de7b9b6b78690de66c0 Mon Sep 17 00:00:00 2001 From: Rostislav Svoboda Date: Mon, 30 Sep 2024 13:00:34 +0200 Subject: [PATCH 20/47] Reference MicroProfile OpenAPI Core configuration (cherry picked from commit 17c870c799e5801f08199262520ae8bedbe423de) --- docs/src/main/asciidoc/openapi-swaggerui.adoc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/src/main/asciidoc/openapi-swaggerui.adoc b/docs/src/main/asciidoc/openapi-swaggerui.adoc index ab660bbb6b9a0..89f41ea22eae7 100644 --- a/docs/src/main/asciidoc/openapi-swaggerui.adoc +++ b/docs/src/main/asciidoc/openapi-swaggerui.adoc @@ -573,6 +573,11 @@ If you plan to consume this application from a Single Page Application running o == Configuration Reference +=== MicroProfile OpenAPI + +MicroProfile OpenAPI Core configuration is defined in https://download.eclipse.org/microprofile/microprofile-open-api-3.1.1/microprofile-openapi-spec-3.1.1.html#_core_configurations[MicroProfile OpenAPI Specification]. +More information about the MicroProfile OpenAPI annotations can be found in the https://download.eclipse.org/microprofile/microprofile-open-api-3.1.1/apidocs/org/eclipse/microprofile/openapi/annotations/package-summary.html[MicroProfile OpenAPI API Javadoc]. + === OpenAPI include::{generated-dir}/config/quarkus-smallrye-openapi.adoc[opts=optional, leveloffset=+1] From 8ce93085aef751a5fc788857c3e187f8fc404c5f Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Fri, 27 Sep 2024 17:27:02 +0200 Subject: [PATCH 21/47] Do not save the .m2 cache for pull requests We use the ones coming from the push events. Related to #43559 (cherry picked from commit e788d0eb5176a84b30a08b0e0b7c80b1798ff272) --- .github/workflows/ci-actions-incremental.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/ci-actions-incremental.yml b/.github/workflows/ci-actions-incremental.yml index d21679c6d275f..e099aabddf481 100644 --- a/.github/workflows/ci-actions-incremental.yml +++ b/.github/workflows/ci-actions-incremental.yml @@ -144,6 +144,8 @@ jobs: - name: Cache Maven Repository id: cache-maven uses: actions/cache@v4 + # if it's not a pull request, we restore and save the cache + if: github.event_name != 'pull_request' with: path: ~/.m2/repository # A new cache will be stored daily. After that first store of the day, cache save actions will fail because the cache is immutable but it's not a problem. @@ -153,6 +155,16 @@ jobs: restore-keys: | ${{ steps.cache-key.outputs.m2-monthly-branch-cache-key }}- ${{ steps.cache-key.outputs.m2-monthly-cache-key }}- + - name: Restore Maven Repository + uses: actions/cache/restore@v4 + # if it a pull request, we restore the cache but we don't save it + if: github.event_name == 'pull_request' + with: + path: ~/.m2/repository + key: ${{ steps.cache-key.outputs.m2-cache-key }} + restore-keys: | + ${{ steps.cache-key.outputs.m2-monthly-branch-cache-key }}- + ${{ steps.cache-key.outputs.m2-monthly-cache-key }}- - name: Populate the cache run: | ./mvnw -T2C $COMMON_MAVEN_ARGS dependency:go-offline From 09404a6f1c8ef14cf3c0cee55f3277ea32531b5c Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Fri, 27 Sep 2024 17:59:20 +0200 Subject: [PATCH 22/47] Experiment with caching the Develocity local cache This can be useful when pushing small iterations to a pull request. It is limited to pull requests only and only for the Initial JDK build. We will check if it improves things and the size of the cache. Related to #43559 (cherry picked from commit 287ce49c1366d4fc33721bb774702da74d2d2e6d) --- .github/workflows/ci-actions-incremental.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci-actions-incremental.yml b/.github/workflows/ci-actions-incremental.yml index e099aabddf481..945358ff440c9 100644 --- a/.github/workflows/ci-actions-incremental.yml +++ b/.github/workflows/ci-actions-incremental.yml @@ -165,6 +165,14 @@ jobs: restore-keys: | ${{ steps.cache-key.outputs.m2-monthly-branch-cache-key }}- ${{ steps.cache-key.outputs.m2-monthly-cache-key }}- + - name: Cache Develocity local cache + uses: actions/cache@v4 + if: github.event_name == 'pull_request' + with: + path: ~/.m2/.develocity/build-cache + key: develocity-cache-Initial JDK 17 Build-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }} + restore-keys: | + develocity-cache-Initial JDK 17 Build-${{ github.event.pull_request.number }}- - name: Populate the cache run: | ./mvnw -T2C $COMMON_MAVEN_ARGS dependency:go-offline From c76dade304a72abfd8269ce65a2ae504c73184b1 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Sat, 28 Sep 2024 17:44:33 +0200 Subject: [PATCH 23/47] Also implement Develocity cache for JVM tests jobs (cherry picked from commit 03538c0d96a0093b4105fa5aaff9b20306f1b80d) --- .github/workflows/ci-actions-incremental.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/ci-actions-incremental.yml b/.github/workflows/ci-actions-incremental.yml index 945358ff440c9..4e347414f502e 100644 --- a/.github/workflows/ci-actions-incremental.yml +++ b/.github/workflows/ci-actions-incremental.yml @@ -409,6 +409,14 @@ jobs: path: . - name: Extract .m2/repository/io/quarkus run: tar -xzf m2-io-quarkus.tgz -C ~ + - name: Cache Develocity local cache + uses: actions/cache@v4 + if: github.event_name == 'pull_request' + with: + path: ~/.m2/.develocity/build-cache + key: develocity-cache-JVM Tests - JDK ${{matrix.java.name}}-${{ github.event.pull_request.number }}-${{ github.event.pull_request.head.sha }} + restore-keys: | + develocity-cache-JVM Tests - JDK ${{matrix.java.name}}-${{ github.event.pull_request.number }}- - name: Setup Develocity Build Scan capture uses: gradle/develocity-actions/maven-setup@v1 with: From 59670a015e28db528df17a200fc02b124f440a9b Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Mon, 30 Sep 2024 13:14:35 +0200 Subject: [PATCH 24/47] Also push the Develocity cache to subsequent jobs (cherry picked from commit e7c2f567fc5d53fe0835e00e38daf27054b28e0c) --- .github/workflows/ci-actions-incremental.yml | 82 ++++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/.github/workflows/ci-actions-incremental.yml b/.github/workflows/ci-actions-incremental.yml index 4e347414f502e..e5a30896a4f1c 100644 --- a/.github/workflows/ci-actions-incremental.yml +++ b/.github/workflows/ci-actions-incremental.yml @@ -236,13 +236,13 @@ jobs: echo 'impacted_modules<> $GITHUB_OUTPUT echo "${GIB_IMPACTED}" >> $GITHUB_OUTPUT echo 'EOF' >> $GITHUB_OUTPUT - - name: Tar .m2/repository/io/quarkus - run: tar -czf m2-io-quarkus.tgz -C ~ .m2/repository/io/quarkus - - name: Upload .m2/repository/io/quarkus + - name: Tar .m2 content pushed to subsequent jobs + run: tar -czf m2-content.tgz -C ~ .m2/repository/io/quarkus .m2/.develocity/build-cache + - name: Upload .m2 content pushed to subsequent jobs uses: actions/upload-artifact@v4 with: - name: m2-io-quarkus - path: m2-io-quarkus.tgz + name: m2-content + path: m2-content.tgz retention-days: 7 - name: Delete snapshots artifacts from cache run: find ~/.m2 -name \*-SNAPSHOT -type d -exec rm -rf {} + @@ -402,13 +402,13 @@ jobs: restore-keys: | ${{ needs.build-jdk17.outputs.m2-monthly-branch-cache-key }}- ${{ needs.build-jdk17.outputs.m2-monthly-cache-key }}- - - name: Download .m2/repository/io/quarkus + - name: Download previously uploaded .m2 content uses: actions/download-artifact@v4 with: - name: m2-io-quarkus + name: m2-content path: . - - name: Extract .m2/repository/io/quarkus - run: tar -xzf m2-io-quarkus.tgz -C ~ + - name: Extract previously uploaded .m2 content + run: tar -xzf m2-content.tgz -C ~ - name: Cache Develocity local cache uses: actions/cache@v4 if: github.event_name == 'pull_request' @@ -517,13 +517,13 @@ jobs: restore-keys: | ${{ needs.build-jdk17.outputs.m2-monthly-branch-cache-key }}- ${{ needs.build-jdk17.outputs.m2-monthly-cache-key }}- - - name: Download .m2/repository/io/quarkus + - name: Download previously uploaded .m2 content uses: actions/download-artifact@v4 with: - name: m2-io-quarkus + name: m2-content path: . - - name: Extract .m2/repository/io/quarkus - run: tar -xzf m2-io-quarkus.tgz -C ~ + - name: Extract previously uploaded .m2 content + run: tar -xzf m2-content.tgz -C ~ - name: Set up JDK ${{ matrix.java.java-version }} uses: actions/setup-java@v4 with: @@ -619,13 +619,13 @@ jobs: restore-keys: | ${{ needs.build-jdk17.outputs.m2-monthly-branch-cache-key }}- ${{ needs.build-jdk17.outputs.m2-monthly-cache-key }}- - - name: Download .m2/repository/io/quarkus + - name: Download previously uploaded .m2 content uses: actions/download-artifact@v4 with: - name: m2-io-quarkus + name: m2-content path: . - - name: Extract .m2/repository/io/quarkus - run: tar -xzf m2-io-quarkus.tgz -C ~ + - name: Extract previously uploaded .m2 content + run: tar -xzf m2-content.tgz -C ~ - name: Set up JDK ${{ matrix.java.java-version }} uses: actions/setup-java@v4 with: @@ -711,13 +711,13 @@ jobs: restore-keys: | ${{ needs.build-jdk17.outputs.m2-monthly-branch-cache-key }}- ${{ needs.build-jdk17.outputs.m2-monthly-cache-key }}- - - name: Download .m2/repository/io/quarkus + - name: Download previously uploaded .m2 content uses: actions/download-artifact@v4 with: - name: m2-io-quarkus + name: m2-content path: . - - name: Extract .m2/repository/io/quarkus - run: tar -xzf m2-io-quarkus.tgz -C ~ + - name: Extract previously uploaded .m2 content + run: tar -xzf m2-content.tgz -C ~ - name: Set up JDK ${{ matrix.java.java-version }} uses: actions/setup-java@v4 with: @@ -807,13 +807,13 @@ jobs: restore-keys: | ${{ needs.build-jdk17.outputs.m2-monthly-branch-cache-key }}- ${{ needs.build-jdk17.outputs.m2-monthly-cache-key }}- - - name: Download .m2/repository/io/quarkus + - name: Download previously uploaded .m2 content uses: actions/download-artifact@v4 with: - name: m2-io-quarkus + name: m2-content path: . - - name: Extract .m2/repository/io/quarkus - run: tar -xzf m2-io-quarkus.tgz -C ~ + - name: Extract previously uploaded .m2 content + run: tar -xzf m2-content.tgz -C ~ - name: Set up JDK ${{ matrix.java.java-version }} uses: actions/setup-java@v4 with: @@ -890,13 +890,13 @@ jobs: restore-keys: | ${{ needs.build-jdk17.outputs.m2-monthly-branch-cache-key }}- ${{ needs.build-jdk17.outputs.m2-monthly-cache-key }}- - - name: Download .m2/repository/io/quarkus + - name: Download previously uploaded .m2 content uses: actions/download-artifact@v4 with: - name: m2-io-quarkus + name: m2-content path: . - - name: Extract .m2/repository/io/quarkus - run: tar -xzf m2-io-quarkus.tgz -C ~ + - name: Extract previously uploaded .m2 content + run: tar -xzf m2-content.tgz -C ~ - name: Set up JDK ${{ matrix.java.java-version }} uses: actions/setup-java@v4 with: @@ -979,13 +979,13 @@ jobs: restore-keys: | ${{ needs.build-jdk17.outputs.m2-monthly-branch-cache-key }}- ${{ needs.build-jdk17.outputs.m2-monthly-cache-key }}- - - name: Download .m2/repository/io/quarkus + - name: Download previously uploaded .m2 content uses: actions/download-artifact@v4 with: - name: m2-io-quarkus + name: m2-content path: . - - name: Extract .m2/repository/io/quarkus - run: tar -xzf m2-io-quarkus.tgz -C ~ + - name: Extract previously uploaded .m2 content + run: tar -xzf m2-content.tgz -C ~ - name: Set up JDK 21 uses: actions/setup-java@v4 with: @@ -1063,13 +1063,13 @@ jobs: restore-keys: | ${{ needs.build-jdk17.outputs.m2-monthly-branch-cache-key }}- ${{ needs.build-jdk17.outputs.m2-monthly-cache-key }}- - - name: Download .m2/repository/io/quarkus + - name: Download previously uploaded .m2 content uses: actions/download-artifact@v4 with: - name: m2-io-quarkus + name: m2-content path: . - - name: Extract .m2/repository/io/quarkus - run: tar -xzf m2-io-quarkus.tgz -C ~ + - name: Extract previously uploaded .m2 content + run: tar -xzf m2-content.tgz -C ~ - name: Setup Develocity Build Scan capture uses: gradle/develocity-actions/maven-setup@v1 with: @@ -1176,13 +1176,13 @@ jobs: restore-keys: | ${{ needs.build-jdk17.outputs.m2-monthly-branch-cache-key }}- ${{ needs.build-jdk17.outputs.m2-monthly-cache-key }}- - - name: Download .m2/repository/io/quarkus + - name: Download previously uploaded .m2 content uses: actions/download-artifact@v4 with: - name: m2-io-quarkus + name: m2-content path: . - - name: Extract .m2/repository/io/quarkus - run: tar -xzf m2-io-quarkus.tgz -C ~ + - name: Extract previously uploaded .m2 content + run: tar -xzf m2-content.tgz -C ~ - name: Setup Develocity Build Scan capture uses: gradle/develocity-actions/maven-setup@v1 with: From 4a6c2e37d7c7d7d16603c97bd5973a0d53e29072 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 1 Oct 2024 14:47:17 +0300 Subject: [PATCH 25/47] Properly test for existence of OtlpMeterRegistry The existing method leads to a "Failed to index" warning being printed when the class doesn't exist (cherry picked from commit c69e206b9804b0adbfb2d754bc3dad2d1b6b98f3) --- .../ObservabilityDevServiceProcessor.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/extensions/observability-devservices/deployment/src/main/java/io/quarkus/observability/deployment/ObservabilityDevServiceProcessor.java b/extensions/observability-devservices/deployment/src/main/java/io/quarkus/observability/deployment/ObservabilityDevServiceProcessor.java index 3a72da825d07a..ebe08b6f889e6 100644 --- a/extensions/observability-devservices/deployment/src/main/java/io/quarkus/observability/deployment/ObservabilityDevServiceProcessor.java +++ b/extensions/observability-devservices/deployment/src/main/java/io/quarkus/observability/deployment/ObservabilityDevServiceProcessor.java @@ -12,11 +12,10 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; import org.jboss.logging.Logger; -import io.quarkus.arc.deployment.BeanArchiveIndexBuildItem; +import io.quarkus.bootstrap.classloading.QuarkusClassLoader; import io.quarkus.deployment.Capabilities; import io.quarkus.deployment.Capability; import io.quarkus.deployment.Feature; @@ -84,7 +83,6 @@ public void startContainers(LaunchModeBuildItem launchMode, LoggingSetupBuildItem loggingSetupBuildItem, GlobalDevServicesConfig devServicesConfig, BuildProducer services, - BeanArchiveIndexBuildItem indexBuildItem, Capabilities capabilities, Optional metricsConfiguration) { @@ -119,7 +117,7 @@ public void startContainers(LaunchModeBuildItem launchMode, configuration, new ExtensionsCatalog( capabilities.isPresent(Capability.OPENTELEMETRY_TRACER), - hasMicrometerOtlp(metricsConfiguration, indexBuildItem))); + hasMicrometerOtlp(metricsConfiguration))); if (devService != null) { ContainerConfig capturedDevServicesConfiguration = capturedDevServicesConfigurations.get(devId); @@ -192,14 +190,10 @@ public void run() { }); } - private static boolean hasMicrometerOtlp(Optional metricsConfiguration, - BeanArchiveIndexBuildItem indexBuildItem) { + private static boolean hasMicrometerOtlp(Optional metricsConfiguration) { if (metricsConfiguration.isPresent() && metricsConfiguration.get().metricsSupported(MetricsFactory.MICROMETER)) { - ClassInfo clazz = indexBuildItem.getIndex().getClassByName(OTLP_REGISTRY); - if (clazz != null) { - return true; - } + return QuarkusClassLoader.isClassPresentAtRuntime(OTLP_REGISTRY.toString()); } return false; } From 8eceb1828b8d78dbc514254cfa65535e53c530a2 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Tue, 1 Oct 2024 14:48:11 +0300 Subject: [PATCH 26/47] Make OTLP_REGISTRY field private (cherry picked from commit 0b4d729dafb2a318ace9e4d99f789aa8f478609c) --- .../deployment/ObservabilityDevServiceProcessor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/observability-devservices/deployment/src/main/java/io/quarkus/observability/deployment/ObservabilityDevServiceProcessor.java b/extensions/observability-devservices/deployment/src/main/java/io/quarkus/observability/deployment/ObservabilityDevServiceProcessor.java index ebe08b6f889e6..db8664f45cc70 100644 --- a/extensions/observability-devservices/deployment/src/main/java/io/quarkus/observability/deployment/ObservabilityDevServiceProcessor.java +++ b/extensions/observability-devservices/deployment/src/main/java/io/quarkus/observability/deployment/ObservabilityDevServiceProcessor.java @@ -53,7 +53,7 @@ class ObservabilityDevServiceProcessor { private static final Map devServices = new ConcurrentHashMap<>(); private static final Map capturedDevServicesConfigurations = new ConcurrentHashMap<>(); private static final Map firstStart = new ConcurrentHashMap<>(); - public static final DotName OTLP_REGISTRY = DotName.createSimple("io.micrometer.registry.otlp.OtlpMeterRegistry"); + private static final DotName OTLP_REGISTRY = DotName.createSimple("io.micrometer.registry.otlp.OtlpMeterRegistry"); public static class IsEnabled implements BooleanSupplier { ObservabilityConfiguration config; From f373db1be703b14bfcad5b89e269c7ac050b5905 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Barto=C5=A1?= Date: Mon, 30 Sep 2024 16:58:48 +0200 Subject: [PATCH 27/47] Keycloak container consumes too much memory in devmode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #41813 Signed-off-by: Martin Bartoš (cherry picked from commit 4c49feb2f1020dfe04ebbaf060f5ce5032b38878) --- .../devservices/keycloak/DevServicesConfig.java | 14 ++++++++++++-- .../keycloak/KeycloakDevServicesProcessor.java | 13 ++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java index ab18a1cad3c45..d7e1f4ee101fc 100644 --- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java +++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/DevServicesConfig.java @@ -10,6 +10,7 @@ import io.quarkus.runtime.annotations.ConfigDocMapKey; import io.quarkus.runtime.annotations.ConfigGroup; import io.quarkus.runtime.annotations.ConfigItem; +import io.quarkus.runtime.configuration.MemorySize; @ConfigGroup public class DevServicesConfig { @@ -230,6 +231,14 @@ public String getGrantType() { @ConfigDocMapKey("environment-variable-name") public Map containerEnv; + /** + * Memory limit for Keycloak container + *

+ * If not specified, 750MiB is the default memory limit. + */ + @ConfigItem(defaultValue = "750M") + public MemorySize containerMemoryLimit; + @Override public boolean equals(Object o) { if (this == o) @@ -247,11 +256,12 @@ public boolean equals(Object o) { && Objects.equals(users, that.users) && Objects.equals(javaOpts, that.javaOpts) && Objects.equals(roles, that.roles) - && Objects.equals(containerEnv, that.containerEnv); + && Objects.equals(containerEnv, that.containerEnv) + && Objects.equals(containerMemoryLimit, that.containerMemoryLimit); } @Override public int hashCode() { - return Objects.hash(enabled, imageName, port, realmPath, realmName, users, roles, containerEnv); + return Objects.hash(enabled, imageName, port, realmPath, realmName, users, roles, containerEnv, containerMemoryLimit); } } diff --git a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java index 9086c453f4e27..32c130233f128 100644 --- a/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java +++ b/extensions/oidc/deployment/src/main/java/io/quarkus/oidc/deployment/devservices/keycloak/KeycloakDevServicesProcessor.java @@ -65,6 +65,7 @@ import io.quarkus.oidc.runtime.devui.OidcDevServicesUtils; import io.quarkus.runtime.LaunchMode; import io.quarkus.runtime.configuration.ConfigUtils; +import io.quarkus.runtime.configuration.MemorySize; import io.smallrye.mutiny.TimeoutException; import io.smallrye.mutiny.Uni; import io.vertx.core.Vertx; @@ -375,6 +376,7 @@ private RunningDevService startContainer(DockerStatusBuildItem dockerStatusBuild capturedDevServicesConfiguration.javaOpts, capturedDevServicesConfiguration.startCommand, capturedDevServicesConfiguration.showLogs, + capturedDevServicesConfiguration.containerMemoryLimit, errors); timeout.ifPresent(oidcContainer::withStartupTimeout); @@ -447,12 +449,13 @@ private static class QuarkusOidcContainer extends GenericContainer realmReps = new LinkedList<>(); private final Optional startCommand; private final boolean showLogs; + private final MemorySize containerMemoryLimit; private final List errors; public QuarkusOidcContainer(DockerImageName dockerImageName, OptionalInt fixedExposedPort, boolean useSharedNetwork, List realmPaths, Map resources, String containerLabelValue, boolean sharedContainer, Optional javaOpts, Optional startCommand, boolean showLogs, - List errors) { + MemorySize containerMemoryLimit, List errors) { super(dockerImageName); this.useSharedNetwork = useSharedNetwork; @@ -473,6 +476,7 @@ public QuarkusOidcContainer(DockerImageName dockerImageName, OptionalInt fixedEx this.fixedExposedPort = fixedExposedPort; this.startCommand = startCommand; this.showLogs = showLogs; + this.containerMemoryLimit = containerMemoryLimit; this.errors = errors; super.setWaitStrategy(Wait.forLogMessage(".*Keycloak.*started.*", 1)); @@ -547,6 +551,13 @@ protected void configure() { }); } + super.withCreateContainerCmdModifier((container) -> Optional.ofNullable(container.getHostConfig()) + .ifPresent(hostConfig -> { + final var limit = containerMemoryLimit.asLongValue(); + hostConfig.withMemory(limit); + LOG.debug("Set container memory limit (bytes): " + limit); + })); + LOG.infof("Using %s powered Keycloak distribution", keycloakX ? "Quarkus" : "WildFly"); } From f5d0e40fdc598f7a68d9f7709e0488a593f799e2 Mon Sep 17 00:00:00 2001 From: Katia Aresti Date: Fri, 27 Sep 2024 08:50:41 +0200 Subject: [PATCH 28/47] Updates Infinispan to 15.0.9.Final (cherry picked from commit fcc95de1d583d7906c254f600b4a5a36c808d065) --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 86a582ef1effd..7a70edbb1b8d1 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -133,7 +133,7 @@ 1.2.6 2.2 5.10.3 - 15.0.8.Final + 15.0.9.Final 5.0.8.Final 3.1.5 4.1.111.Final From 38d63a19a0403c96b8e7e19f271f1628db9d702b Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Thu, 26 Sep 2024 16:26:20 +0200 Subject: [PATCH 29/47] Quarkus Update - Replace \ by / in rewriteFile path on Windows Fixes #43473 (cherry picked from commit b15f758d4b974eec9662a7797f48e0ee8fc80918) --- .../project/update/rewrite/QuarkusUpdateCommand.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/update/rewrite/QuarkusUpdateCommand.java b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/update/rewrite/QuarkusUpdateCommand.java index 674bffe72d8cb..54aac48c192e4 100644 --- a/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/update/rewrite/QuarkusUpdateCommand.java +++ b/independent-projects/tools/devtools-common/src/main/java/io/quarkus/devtools/project/update/rewrite/QuarkusUpdateCommand.java @@ -80,9 +80,15 @@ private static void runGradleUpdate(MessageWriter log, Path baseDir, String rewr new InputStreamReader(inputStream, StandardCharsets.UTF_8)) .lines() .collect(Collectors.joining("\n")); + + String rewriteFile = recipe.toAbsolutePath().toString(); + if (OS.WINDOWS.isCurrent()) { + rewriteFile = rewriteFile.replace('\\', '/'); + } + Files.writeString(tempInit, Qute.fmt(template, Map.of( - "rewriteFile", recipe.toAbsolutePath().toString(), + "rewriteFile", rewriteFile, "pluginVersion", rewritePluginVersion, "recipesGAV", recipesGAV, "activeRecipe", RECIPE_IO_QUARKUS_OPENREWRITE_QUARKUS, From e9452f7d5f76365eaedec37cf8294d5ea2e9fd8e Mon Sep 17 00:00:00 2001 From: brunobat Date: Wed, 2 Oct 2024 09:19:20 +0100 Subject: [PATCH 30/47] Bump Micrometer (cherry picked from commit e9fa0c9c33fab5289df9eee88ce86f490399c6a2) --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 7a70edbb1b8d1..9099f68e7f13e 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -36,7 +36,7 @@ 2.5.0-alpha 1.26.0-alpha 5.3.2 - 1.13.3 + 1.13.5 2.2.2 0.22.0 22.1 From 8a43c424b8b6b79af285b50af688b85ccf075ffc Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Tue, 1 Oct 2024 12:30:27 -0300 Subject: [PATCH 31/47] Split Quarkiverse release into two workflows (cherry picked from commit 56d61ffb90f60a3ddb4a2834b00dcfac4824ad12) --- .../.github/workflows/release-perform.yml | 28 +++++++++++++++++++ ...lease.tpl.qute.yml => release-prepare.yml} | 10 +------ .../maven/it/CreateExtensionMojoIT.java | 3 +- .../dir-tree.snapshot | 3 +- ...-ext_.github_workflows_release-perform.yml | 28 +++++++++++++++++++ ...ext_.github_workflows_release-prepare.yml} | 10 +------ 6 files changed, 62 insertions(+), 20 deletions(-) create mode 100644 independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release-perform.yml rename independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/{release.tpl.qute.yml => release-prepare.yml} (58%) create mode 100644 integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release-perform.yml rename integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/{quarkus-my-quarkiverse-ext_.github_workflows_release.yml => quarkus-my-quarkiverse-ext_.github_workflows_release-prepare.yml} (58%) diff --git a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release-perform.yml b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release-perform.yml new file mode 100644 index 0000000000000..88f9437f199e6 --- /dev/null +++ b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release-perform.yml @@ -0,0 +1,28 @@ +name: Quarkiverse Perform Release +run-name: Perform ${{github.event.inputs.tag || github.ref_name}} Release +on: + push: + tags: + - '*' + workflow_dispatch: + inputs: + tag: + description: 'Tag to release' + required: true + +permissions: + attestations: write + id-token: write + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + perform-release: + name: Perform Release + uses: quarkiverse/.github/.github/workflows/perform-release.yml@main + secrets: inherit + with: + version: ${{github.event.inputs.tag || github.ref_name}} diff --git a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release.tpl.qute.yml b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release-prepare.yml similarity index 58% rename from independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release.tpl.qute.yml rename to independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release-prepare.yml index fb96ae2c77d22..aedad9370a2dc 100644 --- a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release.tpl.qute.yml +++ b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/release-prepare.yml @@ -1,4 +1,4 @@ -name: Quarkiverse Release +name: Quarkiverse Prepare Release on: pull_request: @@ -16,11 +16,3 @@ jobs: if: ${{ github.event.pull_request.merged == true}} uses: quarkiverse/.github/.github/workflows/prepare-release.yml@main secrets: inherit - - perform-release: - name: Perform Release - needs: prepare-release - uses: quarkiverse/.github/.github/workflows/perform-release.yml@main - secrets: inherit - with: - version: ${{needs.prepare-release.outputs.release-version}} diff --git a/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateExtensionMojoIT.java b/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateExtensionMojoIT.java index de7207f63ad26..2ecb6fea9c009 100644 --- a/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateExtensionMojoIT.java +++ b/integration-tests/maven/src/test/java/io/quarkus/maven/it/CreateExtensionMojoIT.java @@ -118,7 +118,8 @@ public void testCreateQuarkiverseExtension(TestInfo testInfo) throws Throwable { assertThatMatchSnapshot(testInfo, testDirPath, "quarkus-my-quarkiverse-ext/.github/workflows/build.yml"); assertThatMatchSnapshot(testInfo, testDirPath, "quarkus-my-quarkiverse-ext/.github/workflows/pre-release.yml"); assertThatMatchSnapshot(testInfo, testDirPath, "quarkus-my-quarkiverse-ext/.github/workflows/quarkus-snapshot.yaml"); - assertThatMatchSnapshot(testInfo, testDirPath, "quarkus-my-quarkiverse-ext/.github/workflows/release.yml"); + assertThatMatchSnapshot(testInfo, testDirPath, "quarkus-my-quarkiverse-ext/.github/workflows/release-perform.yml"); + assertThatMatchSnapshot(testInfo, testDirPath, "quarkus-my-quarkiverse-ext/.github/workflows/release-prepare.yml"); assertThatMatchSnapshot(testInfo, testDirPath, "quarkus-my-quarkiverse-ext/docs/pom.xml"); assertThatMatchSnapshot(testInfo, testDirPath, "quarkus-my-quarkiverse-ext/docs/antora.yml"); assertThatMatchSnapshot(testInfo, testDirPath, "quarkus-my-quarkiverse-ext/docs/modules/ROOT/nav.adoc"); diff --git a/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/dir-tree.snapshot b/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/dir-tree.snapshot index dbfb3fa654e29..5b7c91c9acf74 100644 --- a/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/dir-tree.snapshot +++ b/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/dir-tree.snapshot @@ -9,7 +9,8 @@ quarkus-my-quarkiverse-ext/.github/workflows/build.yml quarkus-my-quarkiverse-ext/.github/workflows/deploy-snapshots.yml.disabled quarkus-my-quarkiverse-ext/.github/workflows/pre-release.yml quarkus-my-quarkiverse-ext/.github/workflows/quarkus-snapshot.yaml -quarkus-my-quarkiverse-ext/.github/workflows/release.yml +quarkus-my-quarkiverse-ext/.github/workflows/release-perform.yml +quarkus-my-quarkiverse-ext/.github/workflows/release-prepare.yml quarkus-my-quarkiverse-ext/.gitignore quarkus-my-quarkiverse-ext/LICENSE quarkus-my-quarkiverse-ext/README.md diff --git a/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release-perform.yml b/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release-perform.yml new file mode 100644 index 0000000000000..88f9437f199e6 --- /dev/null +++ b/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release-perform.yml @@ -0,0 +1,28 @@ +name: Quarkiverse Perform Release +run-name: Perform ${{github.event.inputs.tag || github.ref_name}} Release +on: + push: + tags: + - '*' + workflow_dispatch: + inputs: + tag: + description: 'Tag to release' + required: true + +permissions: + attestations: write + id-token: write + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + perform-release: + name: Perform Release + uses: quarkiverse/.github/.github/workflows/perform-release.yml@main + secrets: inherit + with: + version: ${{github.event.inputs.tag || github.ref_name}} diff --git a/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release.yml b/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release-prepare.yml similarity index 58% rename from integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release.yml rename to integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release-prepare.yml index fb96ae2c77d22..aedad9370a2dc 100644 --- a/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release.yml +++ b/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_release-prepare.yml @@ -1,4 +1,4 @@ -name: Quarkiverse Release +name: Quarkiverse Prepare Release on: pull_request: @@ -16,11 +16,3 @@ jobs: if: ${{ github.event.pull_request.merged == true}} uses: quarkiverse/.github/.github/workflows/prepare-release.yml@main secrets: inherit - - perform-release: - name: Perform Release - needs: prepare-release - uses: quarkiverse/.github/.github/workflows/perform-release.yml@main - secrets: inherit - with: - version: ${{needs.prepare-release.outputs.release-version}} From 6c401472c37e7223d7246bb1b935548344702046 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Tue, 1 Oct 2024 12:53:59 -0300 Subject: [PATCH 32/47] Update pre-release workflow (cherry picked from commit 23e2cdde16f2af2d266dcf17874f6c38ef3ea945) --- .../java/.github/workflows/pre-release.yml | 25 +++---------------- ...erse-ext_.github_workflows_pre-release.yml | 25 +++---------------- 2 files changed, 8 insertions(+), 42 deletions(-) diff --git a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/pre-release.yml b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/pre-release.yml index 0a9e64eaa882f..afe17b3094bf7 100644 --- a/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/pre-release.yml +++ b/independent-projects/tools/base-codestarts/src/main/resources/codestarts/quarkus-extension/code/quarkiverse/java/.github/workflows/pre-release.yml @@ -9,25 +9,8 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -defaults: - run: - shell: bash - jobs: - release: - runs-on: ubuntu-latest - name: pre release - - steps: - - uses: radcortez/project-metadata-action@master - name: retrieve project metadata - id: metadata - with: - github-token: ${{secrets.GITHUB_TOKEN}} - metadata-file-path: '.github/project.yml' - - - name: Validate version - if: contains(steps.metadata.outputs.current-version, 'SNAPSHOT') - run: | - echo '::error::Cannot release a SNAPSHOT version.' - exit 1 \ No newline at end of file + pre-release: + name: Pre-Release + uses: quarkiverse/.github/.github/workflows/pre-release.yml@main + secrets: inherit diff --git a/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_pre-release.yml b/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_pre-release.yml index 0a9e64eaa882f..afe17b3094bf7 100644 --- a/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_pre-release.yml +++ b/integration-tests/maven/src/test/resources/__snapshots__/CreateExtensionMojoIT/testCreateQuarkiverseExtension/quarkus-my-quarkiverse-ext_.github_workflows_pre-release.yml @@ -9,25 +9,8 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -defaults: - run: - shell: bash - jobs: - release: - runs-on: ubuntu-latest - name: pre release - - steps: - - uses: radcortez/project-metadata-action@master - name: retrieve project metadata - id: metadata - with: - github-token: ${{secrets.GITHUB_TOKEN}} - metadata-file-path: '.github/project.yml' - - - name: Validate version - if: contains(steps.metadata.outputs.current-version, 'SNAPSHOT') - run: | - echo '::error::Cannot release a SNAPSHOT version.' - exit 1 \ No newline at end of file + pre-release: + name: Pre-Release + uses: quarkiverse/.github/.github/workflows/pre-release.yml@main + secrets: inherit From 44df756ef4dc2d1a7dc25126dc543fe00c71c17e Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Thu, 3 Oct 2024 16:36:05 +0300 Subject: [PATCH 33/47] Bump to Quarkus HTTP 5.3.3 Fixes: #43628 (cherry picked from commit 2fb684409502e13b69d917401ef30903a45fd4c0) --- bom/application/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 9099f68e7f13e..e2993497b00c2 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -35,7 +35,7 @@ 1.39.0 2.5.0-alpha 1.26.0-alpha - 5.3.2 + 5.3.3 1.13.5 2.2.2 0.22.0 From cff4148abcd42f3bf5fc34c49cb77d582887b02c Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Wed, 9 Oct 2024 11:54:27 +0300 Subject: [PATCH 34/47] Move rocksdb native library resource registration to a feature Always registers the correct native library as the logic runs on the same architecture we are targeting (even when using containers). Closes https://github.com/quarkusio/quarkus/issues/43319 (cherry picked from commit 53d2635e984aad063423bf71f2bc9e5e3cd28eaf) --- .../deployment/KafkaStreamsProcessor.java | 28 ++++++------------- .../runtime/graal/KafkaStreamsFeature.java | 15 ++++++++++ 2 files changed, 23 insertions(+), 20 deletions(-) create mode 100644 extensions/kafka-streams/runtime/src/main/java/io/quarkus/kafka/streams/runtime/graal/KafkaStreamsFeature.java diff --git a/extensions/kafka-streams/deployment/src/main/java/io/quarkus/kafka/streams/deployment/KafkaStreamsProcessor.java b/extensions/kafka-streams/deployment/src/main/java/io/quarkus/kafka/streams/deployment/KafkaStreamsProcessor.java index ebb06368d0ed8..71ff4ebc25cf9 100644 --- a/extensions/kafka-streams/deployment/src/main/java/io/quarkus/kafka/streams/deployment/KafkaStreamsProcessor.java +++ b/extensions/kafka-streams/deployment/src/main/java/io/quarkus/kafka/streams/deployment/KafkaStreamsProcessor.java @@ -2,7 +2,6 @@ import static io.quarkus.kafka.streams.runtime.KafkaStreamsPropertiesUtil.buildKafkaStreamsProperties; -import java.io.IOException; import java.util.Properties; import jakarta.inject.Singleton; @@ -16,7 +15,6 @@ import org.apache.kafka.streams.processor.internals.StreamsPartitionAssignor; import org.rocksdb.RocksDBException; import org.rocksdb.Status; -import org.rocksdb.util.Environment; import io.quarkus.arc.deployment.AdditionalBeanBuildItem; import io.quarkus.arc.deployment.SyntheticBeanBuildItem; @@ -28,16 +26,16 @@ import io.quarkus.deployment.annotations.Record; import io.quarkus.deployment.builditem.FeatureBuildItem; import io.quarkus.deployment.builditem.LaunchModeBuildItem; +import io.quarkus.deployment.builditem.NativeImageFeatureBuildItem; import io.quarkus.deployment.builditem.nativeimage.JniRuntimeAccessBuildItem; -import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; import io.quarkus.deployment.builditem.nativeimage.RuntimeReinitializedClassBuildItem; -import io.quarkus.deployment.pkg.builditem.NativeImageRunnerBuildItem; import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild; import io.quarkus.kafka.streams.runtime.KafkaStreamsProducer; import io.quarkus.kafka.streams.runtime.KafkaStreamsRecorder; import io.quarkus.kafka.streams.runtime.KafkaStreamsRuntimeConfig; import io.quarkus.kafka.streams.runtime.KafkaStreamsSupport; +import io.quarkus.kafka.streams.runtime.graal.KafkaStreamsFeature; import io.quarkus.smallrye.health.deployment.spi.HealthBuildItem; class KafkaStreamsProcessor { @@ -53,12 +51,9 @@ FeatureBuildItem feature() { void build(BuildProducer reflectiveClasses, BuildProducer jniRuntimeAccessibleClasses, BuildProducer reinitialized, - BuildProducer nativeLibs, - LaunchModeBuildItem launchMode, - NativeImageRunnerBuildItem nativeImageRunner) throws IOException { + LaunchModeBuildItem launchMode) { registerClassesThatAreLoadedThroughReflection(reflectiveClasses, launchMode); registerClassesThatAreAccessedViaJni(jniRuntimeAccessibleClasses); - addSupportForRocksDbLib(nativeLibs, nativeImageRunner); enableLoadOfNativeLibs(reinitialized); } @@ -174,18 +169,6 @@ private void registerClassesThatAreAccessedViaJni(BuildProducer nativeLibs, - NativeImageRunnerBuildItem nativeImageRunnerFactory) { - // for RocksDB, either add linux64 native lib when targeting containers - if (nativeImageRunnerFactory.isContainerBuild()) { - nativeLibs.produce(new NativeImageResourceBuildItem("librocksdbjni-linux64.so")); - } - // otherwise the native lib of the platform this build runs on - else { - nativeLibs.produce(new NativeImageResourceBuildItem(Environment.getJniLibraryFileName("rocksdb"))); - } - } - private void enableLoadOfNativeLibs(BuildProducer reinitialized) { reinitialized.produce(new RuntimeReinitializedClassBuildItem("org.rocksdb.RocksDB")); } @@ -236,4 +219,9 @@ void addHealthChecks(KafkaStreamsBuildTimeConfig buildTimeConfig, BuildProducer< "io.quarkus.kafka.streams.runtime.health.KafkaStreamsStateHealthCheck", buildTimeConfig.healthEnabled)); } + + @BuildStep + NativeImageFeatureBuildItem kafkaStreamsFeature() { + return new NativeImageFeatureBuildItem(KafkaStreamsFeature.class.getName()); + } } diff --git a/extensions/kafka-streams/runtime/src/main/java/io/quarkus/kafka/streams/runtime/graal/KafkaStreamsFeature.java b/extensions/kafka-streams/runtime/src/main/java/io/quarkus/kafka/streams/runtime/graal/KafkaStreamsFeature.java new file mode 100644 index 0000000000000..6fee5bc96b238 --- /dev/null +++ b/extensions/kafka-streams/runtime/src/main/java/io/quarkus/kafka/streams/runtime/graal/KafkaStreamsFeature.java @@ -0,0 +1,15 @@ +package io.quarkus.kafka.streams.runtime.graal; + +import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.hosted.RuntimeResourceAccess; +import org.rocksdb.util.Environment; + +public class KafkaStreamsFeature implements Feature { + + @Override + public void afterRegistration(AfterRegistrationAccess access) { + String libraryFileName = Environment.getJniLibraryFileName("rocksdb"); + RuntimeResourceAccess.addResource(Environment.class.getModule(), libraryFileName); + } + +} From c2ba9b4489676c87ad62e2595844aec119d90027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Vav=C5=99=C3=ADk?= Date: Thu, 10 Oct 2024 00:43:59 +0200 Subject: [PATCH 35/47] Add equals and hashcode method to MemorySize (cherry picked from commit 44e1b1493934dd78cc671f8429ba2be4ef8dfcac) --- .../runtime/configuration/MemorySize.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/core/runtime/src/main/java/io/quarkus/runtime/configuration/MemorySize.java b/core/runtime/src/main/java/io/quarkus/runtime/configuration/MemorySize.java index d1120f11da580..ebacf8020b948 100644 --- a/core/runtime/src/main/java/io/quarkus/runtime/configuration/MemorySize.java +++ b/core/runtime/src/main/java/io/quarkus/runtime/configuration/MemorySize.java @@ -1,6 +1,7 @@ package io.quarkus.runtime.configuration; import java.math.BigInteger; +import java.util.Objects; /** * A type representing data sizes. @@ -25,4 +26,19 @@ public long asLongValue() { public BigInteger asBigInteger() { return value; } + + @Override + public boolean equals(Object object) { + if (this == object) + return true; + if (object == null || getClass() != object.getClass()) + return false; + MemorySize that = (MemorySize) object; + return Objects.equals(value, that.value); + } + + @Override + public int hashCode() { + return Objects.hashCode(value); + } } From 58cbfdcaf2519813807b658658283641e9e24afd Mon Sep 17 00:00:00 2001 From: Jan Martiska Date: Wed, 9 Oct 2024 10:36:53 +0200 Subject: [PATCH 36/47] Manage angus-mail in the bom (cherry picked from commit 436dae0c061c33fe7fd471cc6735efbc41ea2dd3) --- bom/application/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index e2993497b00c2..cacd03293f797 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -15,6 +15,7 @@ 2.0.2 + 2.0.3 1.78.1 1.0.2.5 1.0.19 @@ -3613,6 +3614,11 @@ angus-activation ${angus-activation.version} + + org.eclipse.angus + angus-mail + ${angus-mail.version} + com.h2database h2 From e8d46166c2bf3e38d58c92f1af161216337d8025 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Wed, 9 Oct 2024 15:09:40 -0300 Subject: [PATCH 37/47] Remove extra brace Fix broken link Update docs/src/main/asciidoc/extension-writing-dev-service.adoc Co-authored-by: Guillaume Smet (cherry picked from commit d3c69b0a5e88df5c94682c26f2e7906453d42d49) --- docs/src/main/asciidoc/extension-writing-dev-service.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/src/main/asciidoc/extension-writing-dev-service.adoc b/docs/src/main/asciidoc/extension-writing-dev-service.adoc index 7f9e18f3ba469..27d96ce380787 100644 --- a/docs/src/main/asciidoc/extension-writing-dev-service.adoc +++ b/docs/src/main/asciidoc/extension-writing-dev-service.adoc @@ -23,11 +23,11 @@ include::_attributes.adoc[] If your extension provides APIs for connecting to an external service, it's a good idea to provide a xref:dev-services.adoc[Dev Service] implementation. To create a Dev Service, add a new build step into the extension processor class that returns a `DevServicesResultBuildItem`. -Here, the link:https://hub.docker.com/_/hello-world`hello-world` image is used, but you should set up the right image for your service. +Here, the https://hub.docker.com/_/hello-world[`hello-world`] image is used, but you should set up the right image for your service. [source%nowrap,java] ---- - @BuildStep(onlyIfNot = IsNormal.class, onlyIf = GlobalDevServicesConfig.Enabled.class) { + @BuildStep(onlyIfNot = IsNormal.class, onlyIf = GlobalDevServicesConfig.Enabled.class) public DevServicesResultBuildItem createContainer() { DockerImageName dockerImageName = DockerImageName.parse("hello-world"); GenericContainer container = new GenericContainer<>(dockerImageName) @@ -89,7 +89,7 @@ For example, [source%nowrap,java] ---- - @BuildStep(onlyIfNot = IsNormal.class, onlyIf = GlobalDevServicesConfig.Enabled.class) { + @BuildStep(onlyIfNot = IsNormal.class, onlyIf = GlobalDevServicesConfig.Enabled.class) public DevServicesResultBuildItem createContainer(MyConfig config) { ---- From bf747663d4264ccc37996d5ecbbbf145ac9047b4 Mon Sep 17 00:00:00 2001 From: Ozan Gunalp Date: Thu, 10 Oct 2024 14:10:37 +0200 Subject: [PATCH 38/47] Add io.netty.versions.properties to native image resources (cherry picked from commit 158780a82a099e3a06a1fed7e73d2fc6d7b5c443) --- .../java/io/quarkus/netty/deployment/NettyProcessor.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java b/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java index 361033561c391..2b6e1ee211bb7 100644 --- a/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java +++ b/extensions/netty/deployment/src/main/java/io/quarkus/netty/deployment/NettyProcessor.java @@ -25,6 +25,7 @@ import io.quarkus.deployment.annotations.Record; import io.quarkus.deployment.builditem.SystemPropertyBuildItem; import io.quarkus.deployment.builditem.nativeimage.NativeImageConfigBuildItem; +import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBuildItem; import io.quarkus.deployment.builditem.nativeimage.NativeImageSystemPropertyBuildItem; import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; import io.quarkus.deployment.builditem.nativeimage.RuntimeInitializedClassBuildItem; @@ -281,6 +282,14 @@ LogCleanupFilterBuildItem cleanupMacDNSInLog() { "Can not find io.netty.resolver.dns.macos.MacOSDnsServerAddressStreamProvider in the classpath"); } + /** + * `Version.identify()` in netty-common uses the resource to determine the version of netty. + */ + @BuildStep + NativeImageResourceBuildItem nettyVersions() { + return new NativeImageResourceBuildItem("META-INF/io.netty.versions.properties"); + } + private String calculateMaxOrder(OptionalInt userConfig, List minMaxOrderBuildItems, boolean shouldWarn) { int result = DEFAULT_NETTY_ALLOCATOR_MAX_ORDER; From 7bf488de443232a41f73d1c6f5d986c65cd459f6 Mon Sep 17 00:00:00 2001 From: Georgios Andrianakis Date: Mon, 14 Oct 2024 10:59:03 +0300 Subject: [PATCH 39/47] Properly handle Map of form params in REST Client Fixes: #43784 (cherry picked from commit 95d49209936ae3df866c7b78dd979bc15b512b99) --- .../JaxrsClientReactiveProcessor.java | 56 +++++++++++-- .../rest/client/reactive/FormMapTest.java | 83 +++++++++++++++++++ 2 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/FormMapTest.java diff --git a/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java b/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java index fff8381b08c3b..2348d3fcc3171 100644 --- a/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java +++ b/extensions/resteasy-reactive/rest-client-jaxrs/deployment/src/main/java/io/quarkus/jaxrs/client/reactive/deployment/JaxrsClientReactiveProcessor.java @@ -1058,7 +1058,7 @@ A more full example of generated client (with sub-resource) can is at the bottom formParams = createFormDataIfAbsent(methodCreator, formParams, multipart); // NOTE: don't use type here, because we're not going through the collection converters and stuff Type parameterType = jandexMethod.parameterType(paramIdx); - addFormParam(methodCreator, param.name, methodCreator.getMethodParam(paramIdx), + addFormParam(jandexMethod, methodCreator, param.name, methodCreator.getMethodParam(paramIdx), parameterType, param.signature, index, restClientInterface.getClassName(), methodCreator.getThis(), formParams, getGenericTypeFromArray(methodCreator, methodGenericParametersField, paramIdx), @@ -2566,7 +2566,7 @@ private void addSubBeanParamData(MethodInfo jandexMethod, int paramIndex, Byteco break; case FORM_PARAM: FormParamItem formParam = (FormParamItem) item; - addFormParam(creator, formParam.getFormParamName(), formParam.extract(creator, param), + addFormParam(jandexMethod, creator, formParam.getFormParamName(), formParam.extract(creator, param), formParam.getParamType(), formParam.getParamSignature(), index, restClientInterfaceClassName, client, @@ -2835,7 +2835,7 @@ private void addPathParam(BytecodeCreator methodCreator, AssignableResultHandle methodCreator.load(paramName), handle)); } - private void addFormParam(BytecodeCreator methodCreator, + private void addFormParam(MethodInfo jandexMethod, BytecodeCreator methodCreator, String paramName, ResultHandle formParamHandle, Type parameterType, @@ -2870,10 +2870,56 @@ private void addFormParam(BytecodeCreator methodCreator, ResultHandle convertedParamArray = creator.invokeVirtualMethod( MethodDescriptor.ofMethod(RestClientBase.class, "convertParamArray", Object[].class, Object[].class, Class.class, java.lang.reflect.Type.class, Annotation[].class), - client, paramArray, creator.loadClassFromTCCL(componentType), genericType, creator.newArray( - Annotation.class, 0)); + client, paramArray, creator.loadClassFromTCCL(componentType), genericType, + creator.newArray(Annotation.class, 0)); creator.invokeInterfaceMethod(MULTIVALUED_MAP_ADD_ALL, formParams, creator.load(paramName), convertedParamArray); + } else if (isMap(parameterType, index)) { + var resolvesTypes = resolveMapTypes(parameterType, index, jandexMethod); + var keyType = resolvesTypes.getKey(); + if (!ResteasyReactiveDotNames.STRING.equals(keyType.name())) { + throw new IllegalArgumentException( + "Map parameter types must have String keys. Offending method is: " + jandexMethod); + } + // Loop through the keys + ResultHandle keySet = creator.invokeInterfaceMethod(ofMethod(Map.class, "keySet", Set.class), + formParamHandle); + ResultHandle keysIterator = creator.invokeInterfaceMethod( + ofMethod(Set.class, "iterator", Iterator.class), keySet); + BytecodeCreator loopCreator = creator.whileLoop(c -> iteratorHasNext(c, keysIterator)).block(); + ResultHandle key = loopCreator.invokeInterfaceMethod( + ofMethod(Iterator.class, "next", Object.class), keysIterator); + // get the value and convert + ResultHandle value = loopCreator.invokeInterfaceMethod(ofMethod(Map.class, "get", Object.class, Object.class), + formParamHandle, key); + var valueType = resolvesTypes.getValue(); + String componentType = valueType.name().toString(); + ResultHandle paramArray; + if (isCollection(valueType, index)) { + if (valueType.kind() == PARAMETERIZED_TYPE) { + Type paramType = valueType.asParameterizedType().arguments().get(0); + if ((paramType.kind() == CLASS) || (paramType.kind() == PARAMETERIZED_TYPE)) { + componentType = paramType.name().toString(); + } + } + if (componentType == null) { + componentType = DotNames.OBJECT.toString(); + } + paramArray = loopCreator.invokeStaticMethod( + MethodDescriptor.ofMethod(ToObjectArray.class, "collection", Object[].class, Collection.class), + value); + } else { + paramArray = loopCreator + .invokeStaticMethod(ofMethod(ToObjectArray.class, "value", Object[].class, Object.class), + value); + } + ResultHandle convertedParamArray = loopCreator.invokeVirtualMethod( + MethodDescriptor.ofMethod(RestClientBase.class, "convertParamArray", Object[].class, Object[].class, + Class.class, java.lang.reflect.Type.class, Annotation[].class), + client, paramArray, loopCreator.loadClassFromTCCL(componentType), genericType, + loopCreator.newArray(Annotation.class, 0)); + loopCreator.invokeInterfaceMethod(MULTIVALUED_MAP_ADD_ALL, formParams, + key, convertedParamArray); } else { ResultHandle convertedFormParam = convertParamToString(creator, client, formParamHandle, parameterType.name().toString(), diff --git a/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/FormMapTest.java b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/FormMapTest.java new file mode 100644 index 0000000000000..96ef295b74973 --- /dev/null +++ b/extensions/resteasy-reactive/rest-client/deployment/src/test/java/io/quarkus/rest/client/reactive/FormMapTest.java @@ -0,0 +1,83 @@ +package io.quarkus.rest.client.reactive; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.MultivaluedMap; + +import org.eclipse.microprofile.rest.client.RestClientBuilder; +import org.jboss.resteasy.reactive.RestForm; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.QuarkusUnitTest; +import io.quarkus.test.common.http.TestHTTPResource; + +public class FormMapTest { + + @RegisterExtension + static final QuarkusUnitTest config = new QuarkusUnitTest() + .withApplicationRoot((jar) -> jar.addClasses(Resource.class, Client.class)); + + @TestHTTPResource + URI baseUri; + + @Test + void test() { + Client client = RestClientBuilder.newBuilder().baseUri(baseUri).build(Client.class); + String response = client.call(Map.of("foo", "bar", "k1", "v1", "k2", "v2"), new Holder(Collections.emptyMap())); + assertThat(response).isEqualTo("foo=bar-k1=v1-k2=v2"); + + String response2 = client.call(Collections.emptyMap(), new Holder(Map.of("foo", List.of("bar"), "k1", List.of("v1")))); + assertThat(response2).isEqualTo("foo=bar-k1=v1"); + + String response3 = client.call(Map.of("foo", "bar"), new Holder(Map.of("k", List.of("v1", "v2")))); + assertThat(response3).isEqualTo("foo=bar-k=v1,v2"); + } + + @Path("/test") + public static class Resource { + + @POST + @Consumes("application/x-www-form-urlencoded") + public String response(MultivaluedMap all) { + StringBuilder sb = new StringBuilder(); + boolean isFirst = true; + List keys = new ArrayList<>(all.keySet()); + Collections.sort(keys); + for (var key : keys) { + if (!isFirst) { + sb.append("-"); + } + isFirst = false; + sb.append(key).append("=").append(String.join(",", all.get(key))); + } + return sb.toString(); + } + } + + @Path("/test") + public interface Client { + + @POST + String call(@RestForm Map formParams, @BeanParam Holder holder); + } + + public static class Holder { + @RestForm + public Map> more; + + public Holder(Map> more) { + this.more = more; + } + } +} From 56c4e2e61cbfad9003cb91a37cdc7b41760f9396 Mon Sep 17 00:00:00 2001 From: Katia Aresti Date: Mon, 14 Oct 2024 12:22:36 +0200 Subject: [PATCH 40/47] Updates to Infinispan 15.0.10.Final (cherry picked from commit c6cc581b9350f0ee101cd04012c4bcb8e62be82b) --- bom/application/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bom/application/pom.xml b/bom/application/pom.xml index cacd03293f797..63bc8a99fea34 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -134,8 +134,8 @@ 1.2.6 2.2 5.10.3 - 15.0.9.Final - 5.0.8.Final + 15.0.10.Final + 5.0.12.Final 3.1.5 4.1.111.Final 1.16.0 From c7a23fa7e30d26a566042443ad81cbdf3ec2fc91 Mon Sep 17 00:00:00 2001 From: Peter Palaga Date: Wed, 16 Oct 2024 12:39:14 +0200 Subject: [PATCH 41/47] Use the correct event type CertificateUpdatedEvent in TLS Registry reference (cherry picked from commit 7f56ac6531011d759a32e5749626651efb17e98a) --- docs/src/main/asciidoc/tls-registry-reference.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/tls-registry-reference.adoc b/docs/src/main/asciidoc/tls-registry-reference.adoc index 297cfa50f1356..c0694366fd3ab 100644 --- a/docs/src/main/asciidoc/tls-registry-reference.adoc +++ b/docs/src/main/asciidoc/tls-registry-reference.adoc @@ -656,7 +656,7 @@ quarkus.tls.http.key-store.pem.0.cert=tls.crt quarkus.tls.http.key-store.pem.0.key=tls.key ---- -IMPORTANT: Impacted server and client may need to listen to the `CertificateReloadedEvent` to apply the new certificates. +IMPORTANT: Impacted server and client may need to listen to the `CertificateUpdatedEvent` to apply the new certificates. This is automatically done for the Quarkus HTTP server, including the management interface if it is enabled. ifndef::no-kubernetes-secrets-or-cert-manager[] From a032bd8758a04daf993839bba6bb4bc7f4f2e0a1 Mon Sep 17 00:00:00 2001 From: Foivos Zakkak Date: Wed, 16 Oct 2024 11:16:51 +0300 Subject: [PATCH 42/47] Update Google Cloud SQL guide Closes https://github.com/quarkusio/quarkus/issues/43876 (cherry picked from commit 489f9198747fe094f8e5954e0205a8ffcbef17ef) --- docs/src/main/asciidoc/deploying-to-google-cloud.adoc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/deploying-to-google-cloud.adoc b/docs/src/main/asciidoc/deploying-to-google-cloud.adoc index 40cc488577a3a..4c22e86d39cb6 100644 --- a/docs/src/main/asciidoc/deploying-to-google-cloud.adoc +++ b/docs/src/main/asciidoc/deploying-to-google-cloud.adoc @@ -291,13 +291,20 @@ WARNING: This only works when your application is running inside a Google Cloud === Using Cloud SQL with native executables -When generating native executables, you must also mark `jnr.ffi.provider.jffi.NativeFinalizer$SingletonHolder` as runtime initialized. +When generating native executables, you must mark `jnr.ffi.provider.jffi.NativeFinalizer$SingletonHolder` as runtime initialized. [source,properties] ---- quarkus.native.additional-build-args=--initialize-at-run-time=jnr.ffi.provider.jffi.NativeFinalizer$SingletonHolder ---- +Additionally, starting with `com.google.cloud.sql:postgres-socket-factory:1.17.0`, you must also mark `com.kenai.jffi.internal.Cleaner` as runtime initialized. + +[source,properties] +---- +quarkus.native.additional-build-args=--initialize-at-run-time=jnr.ffi.provider.jffi.NativeFinalizer$SingletonHolder\\,com.kenai.jffi.internal.Cleaner +---- + == Going further You can find a set of extensions to access various Google Cloud Services in the Quarkiverse (a GitHub organization for Quarkus extensions maintained by the community), From 9244536dc22df43016acba3a80796ab28d61d6db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mal=C3=A9=C5=99?= Date: Tue, 15 Oct 2024 13:45:22 +0200 Subject: [PATCH 43/47] Adding-additional-conditionals-for-the-TLS-guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Maléř (cherry picked from commit 2ff9f1e3f248203dd4366e928aaeba697bb89ae6) --- docs/src/main/asciidoc/tls-registry-reference.adoc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/tls-registry-reference.adoc b/docs/src/main/asciidoc/tls-registry-reference.adoc index c0694366fd3ab..fe53ae60e1258 100644 --- a/docs/src/main/asciidoc/tls-registry-reference.adoc +++ b/docs/src/main/asciidoc/tls-registry-reference.adoc @@ -27,7 +27,15 @@ ifndef::no-reactive-routes[] endif::no-reactive-routes[] . As a result, applications that use the TLS Registry can be ready to handle secure communications out of the box. -TLS Registry also provides features like automatic certificate reloading, Let's Encrypt (ACME) integration, Kubernetes Cert-Manager support, and compatibility with various keystore formats, such as PKCS12, PEM, and JKS. + +TLS Registry also provides automatic certificate reloading +ifndef::no-lets-encrypt[] +, integration with Let's Encrypt (ACME) +endif::no-lets-encrypt[] +ifndef::no-kubernetes-secrets-or-cert-manager[] +, support for Kubernetes Cert-Manager, +endif::no-kubernetes-secrets-or-cert-manager[] +and compatibility with various keystore formats, such as PKCS12, PEM, and JKS. [[using-the-tls-registry]] == Using the TLS registry From 975566e7b634baae74f0269292f50791774611cb Mon Sep 17 00:00:00 2001 From: Holly Cummins Date: Fri, 11 Oct 2024 12:07:14 +0200 Subject: [PATCH 44/47] Prefer hosting-independent URL for quarkiverse docs (cherry picked from commit 438e4b19a7213925322362f41abcf4b7a4961716) --- .github/ISSUE_TEMPLATE/extension_proposal.yml | 2 +- docs/src/main/asciidoc/_attributes.adoc | 14 +++++++------- docs/src/main/asciidoc/container-image.adoc | 2 +- docs/src/main/asciidoc/datasource.adoc | 2 +- .../main/asciidoc/deploying-to-google-cloud.adoc | 2 +- docs/src/main/asciidoc/extension-codestart.adoc | 2 +- docs/src/main/asciidoc/jms.adoc | 2 +- docs/src/main/asciidoc/mailer-reference.adoc | 2 +- .../security-authentication-mechanisms.adoc | 2 +- .../security-openid-connect-providers.adoc | 2 +- docs/src/main/asciidoc/web.adoc | 4 ++-- .../codestart.tpl.qute.yml | 2 +- .../quarkus/devtools/commands/CreateExtension.java | 2 +- ..._main_resources_META-INF_quarkus-extension.yaml | 2 +- 14 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/extension_proposal.yml b/.github/ISSUE_TEMPLATE/extension_proposal.yml index 790fc49a02943..ea50b4a5b8280 100644 --- a/.github/ISSUE_TEMPLATE/extension_proposal.yml +++ b/.github/ISSUE_TEMPLATE/extension_proposal.yml @@ -41,7 +41,7 @@ body: description: >- A URL with more information about the technology this extension promotes (defaults to the Quarkiverse Docs repository) value: - https://quarkiverse.github.io/quarkiverse-docs//dev/ + https://docs.quarkiverse.io//dev/ - type: textarea id: repository_topics diff --git a/docs/src/main/asciidoc/_attributes.adoc b/docs/src/main/asciidoc/_attributes.adoc index c1a16046ae649..c92e26a18e931 100644 --- a/docs/src/main/asciidoc/_attributes.adoc +++ b/docs/src/main/asciidoc/_attributes.adoc @@ -55,13 +55,13 @@ :hibernate-orm-dialect-docs-url: https://docs.jboss.org/hibernate/orm/{hibernate-orm-version-major-minor}/dialect/dialect.html :hibernate-search-docs-url: https://docs.jboss.org/hibernate/search/{hibernate-search-version-major-minor}/reference/en-US/html_single/ // . -:amazon-services-guide: https://quarkiverse.github.io/quarkiverse-docs/quarkus-amazon-services/dev/index.html -:config-consul-guide: https://quarkiverse.github.io/quarkiverse-docs/quarkus-config-extensions/dev/consul.html -:hibernate-search-orm-elasticsearch-aws-guide: https://quarkiverse.github.io/quarkiverse-docs/quarkus-hibernate-search-extras/dev/index.html -:neo4j-guide: https://quarkiverse.github.io/quarkiverse-docs/quarkus-neo4j/dev/index.html -:vault-guide: https://quarkiverse.github.io/quarkiverse-docs/quarkus-vault/dev/index.html -:vault-datasource-guide: https://quarkiverse.github.io/quarkiverse-docs/quarkus-vault/dev/vault-datasource.html -:micrometer-registry-guide: https://quarkiverse.github.io/quarkiverse-docs/quarkus-micrometer-registry/dev/index.html +:amazon-services-guide: https://docs.quarkiverse.io/quarkus-amazon-services/dev/index.html +:config-consul-guide: https://docs.quarkiverse.io/quarkus-config-extensions/dev/consul.html +:hibernate-search-orm-elasticsearch-aws-guide: https://docs.quarkiverse.io/quarkus-hibernate-search-extras/dev/index.html +:neo4j-guide: https://docs.quarkiverse.io/quarkus-neo4j/dev/index.html +:vault-guide: https://docs.quarkiverse.io/quarkus-vault/dev/index.html +:vault-datasource-guide: https://docs.quarkiverse.io/quarkus-vault/dev/vault-datasource.html +:micrometer-registry-guide: https://docs.quarkiverse.io/quarkus-micrometer-registry/dev/index.html :quarkus-migration-guide: https://github.com/quarkusio/quarkus/wiki/Migration-Guides[Migration Guides] :quarkus-tls-registry-reference-guide: TLS registry reference // . diff --git a/docs/src/main/asciidoc/container-image.adoc b/docs/src/main/asciidoc/container-image.adoc index 3d24d1b2a7aeb..8fd7785a8e19b 100644 --- a/docs/src/main/asciidoc/container-image.adoc +++ b/docs/src/main/asciidoc/container-image.adoc @@ -239,7 +239,7 @@ quarkus.container-image.builder=docker == Integrating with `systemd-notify` -If you are building a container image in order to deploy your Quarkus application as a Linux service with Podman and Systemd, you might want to consider including the https://quarkiverse.github.io/quarkiverse-docs/quarkus-systemd-notify/dev/index.html[Quarkus Systemd Notify Extension] as part of your application, with: +If you are building a container image in order to deploy your Quarkus application as a Linux service with Podman and Systemd, you might want to consider including the https://docs.quarkiverse.io/quarkus-systemd-notify/dev/index.html[Quarkus Systemd Notify Extension] as part of your application, with: :add-extension-extensions: io.quarkiverse.systemd.notify:quarkus-systemd-notify include::{includes}/devtools/extension-add.adoc[] diff --git a/docs/src/main/asciidoc/datasource.adoc b/docs/src/main/asciidoc/datasource.adoc index 3d55c0d07e141..d4a4582c82574 100644 --- a/docs/src/main/asciidoc/datasource.adoc +++ b/docs/src/main/asciidoc/datasource.adoc @@ -216,7 +216,7 @@ Read <> for suggestions re * MySQL - `quarkus-jdbc-mysql` * Oracle - `quarkus-jdbc-oracle` * PostgreSQL - `quarkus-jdbc-postgresql` -* Other JDBC extensions, such as link:https://github.com/quarkiverse/quarkus-jdbc-sqlite[SQLite] and its link:https://quarkiverse.github.io/quarkiverse-docs/quarkus-jdbc-sqlite/dev/index.html[documentation], can be found in the https://github.com/quarkiverse[Quarkiverse]. +* Other JDBC extensions, such as link:https://github.com/quarkiverse/quarkus-jdbc-sqlite[SQLite] and its link:https://docs.quarkiverse.io/quarkus-jdbc-sqlite/dev/index.html[documentation], can be found in the https://github.com/quarkiverse[Quarkiverse]. + For example, to add the PostgreSQL driver dependency: + diff --git a/docs/src/main/asciidoc/deploying-to-google-cloud.adoc b/docs/src/main/asciidoc/deploying-to-google-cloud.adoc index 4c22e86d39cb6..f51d3f76131ef 100644 --- a/docs/src/main/asciidoc/deploying-to-google-cloud.adoc +++ b/docs/src/main/asciidoc/deploying-to-google-cloud.adoc @@ -310,4 +310,4 @@ quarkus.native.additional-build-args=--initialize-at-run-time=jnr.ffi.provider.j You can find a set of extensions to access various Google Cloud Services in the Quarkiverse (a GitHub organization for Quarkus extensions maintained by the community), including PubSub, BigQuery, Storage, Spanner, Firestore, Secret Manager (visit the repository for an accurate list of supported services). -You can find some documentation about them in the link:https://quarkiverse.github.io/quarkiverse-docs/quarkus-google-cloud-services/main/index.html[Quarkiverse Google Cloud Services documentation]. +You can find some documentation about them in the link:https://docs.quarkiverse.io/quarkus-google-cloud-services/main/index.html[Quarkiverse Google Cloud Services documentation]. diff --git a/docs/src/main/asciidoc/extension-codestart.adoc b/docs/src/main/asciidoc/extension-codestart.adoc index 3d5dba084ee1d..3853c0962788d 100644 --- a/docs/src/main/asciidoc/extension-codestart.adoc +++ b/docs/src/main/asciidoc/extension-codestart.adoc @@ -194,7 +194,7 @@ tags: extension-codestart metadata: title: Aloha description: Start to code with the Aloha extension. - related-guide-section: https://quarkiverse.github.io/quarkiverse-docs/quarkus-aloha/dev/ + related-guide-section: https://docs.quarkiverse.io/quarkus-aloha/dev/ path: /aloha # (optional) for web extensions providing HTTP resources ---- diff --git a/docs/src/main/asciidoc/jms.adoc b/docs/src/main/asciidoc/jms.adoc index c1f285e5c3384..ba8b26979874f 100644 --- a/docs/src/main/asciidoc/jms.adoc +++ b/docs/src/main/asciidoc/jms.adoc @@ -390,5 +390,5 @@ With the Artemis properties configured, you can resume the steps above from < Date: Thu, 17 Oct 2024 12:50:00 +0200 Subject: [PATCH 45/47] Application of the QE feedback for the Datasource guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Michal Maléř (cherry picked from commit 733cf6ee670393d46a3ea751dc5c521fe60f403c) --- docs/src/main/asciidoc/datasource.adoc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/src/main/asciidoc/datasource.adoc b/docs/src/main/asciidoc/datasource.adoc index d4a4582c82574..3fbed5f3d536d 100644 --- a/docs/src/main/asciidoc/datasource.adoc +++ b/docs/src/main/asciidoc/datasource.adoc @@ -168,7 +168,7 @@ endif::note-quarkus-derby[] + [NOTE] ==== -You can use any JDBC driver in a Quarkus app in JVM mode as described in <>. +You can use any JDBC driver in a Quarkus app in JVM mode as described in <>. However, using a non-built-in database kind is unlikely to work when compiling your application to a native executable. For native executable builds, it is recommended to either use the available JDBC Quarkus extensions or contribute a custom extension for your specific driver. @@ -216,7 +216,9 @@ Read <> for suggestions re * MySQL - `quarkus-jdbc-mysql` * Oracle - `quarkus-jdbc-oracle` * PostgreSQL - `quarkus-jdbc-postgresql` +ifndef::no-quarkiverse[] * Other JDBC extensions, such as link:https://github.com/quarkiverse/quarkus-jdbc-sqlite[SQLite] and its link:https://docs.quarkiverse.io/quarkus-jdbc-sqlite/dev/index.html[documentation], can be found in the https://github.com/quarkiverse[Quarkiverse]. +ifndef::no-quarkiverse[] + For example, to add the PostgreSQL driver dependency: + @@ -566,7 +568,7 @@ If your transaction involves non-datasource resources, be aware that they might If XA cannot be enabled for one of your datasources: -* Be aware that enabling XA for all datasources _except one_ (and only one) is still supported through https://www.narayana.io/docs/project/index.html#d5e857[Last Resource Commit Optimization (LRCO)]. +* Be aware that enabling XA for all datasources _except one_ (and only one) is still supported through link:https://www.narayana.io/docs/project/index.html#_last_resource_commit_optimization_lrco[Last Resource Commit Optimization (LRCO)]. * If you do not need a rollback for one datasource to trigger a rollback for other datasources, consider splitting your code into multiple transactions. To do so, use xref:transaction.adoc#programmatic-approach[`QuarkusTransaction.requiringNew()`]/xref:transaction.adoc#declarative-approach[`@Transactional(REQUIRES_NEW)`] (preferably) or xref:transaction.adoc#legacy-api-approach[`UserTransaction`] (for more complex use cases). From 0dac9da42ad8209becb217dc733d5bd89ee973de Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Wed, 16 Oct 2024 19:26:32 +0200 Subject: [PATCH 46/47] CI - Do not populate the cache for PRs as we won't store it (cherry picked from commit 583ef95194b562c149f6560763a430aca7b80848) --- .github/workflows/ci-actions-incremental.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci-actions-incremental.yml b/.github/workflows/ci-actions-incremental.yml index e5a30896a4f1c..1a38851917271 100644 --- a/.github/workflows/ci-actions-incremental.yml +++ b/.github/workflows/ci-actions-incremental.yml @@ -174,6 +174,8 @@ jobs: restore-keys: | develocity-cache-Initial JDK 17 Build-${{ github.event.pull_request.number }}- - name: Populate the cache + # only populate the cache if it's not a pull request as we only store the cache in this case + if: github.event_name != 'pull_request' run: | ./mvnw -T2C $COMMON_MAVEN_ARGS dependency:go-offline - name: Verify native-tests.json From c3e5d45ec1a0bec13428ba3ca05cbca675683055 Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Mon, 21 Oct 2024 10:01:31 +0200 Subject: [PATCH 47/47] Config Doc - Expand enums even if tooltip is not supported This was an oversight. Fixes #43307 --- .../maven/config/doc/AsciidocFormatter.java | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/devtools/config-doc-maven-plugin/src/main/java/io/quarkus/maven/config/doc/AsciidocFormatter.java b/devtools/config-doc-maven-plugin/src/main/java/io/quarkus/maven/config/doc/AsciidocFormatter.java index 211e27875de24..321bb627d2d80 100644 --- a/devtools/config-doc-maven-plugin/src/main/java/io/quarkus/maven/config/doc/AsciidocFormatter.java +++ b/devtools/config-doc-maven-plugin/src/main/java/io/quarkus/maven/config/doc/AsciidocFormatter.java @@ -44,19 +44,25 @@ String formatDescription(ConfigProperty configProperty) { String formatTypeDescription(ConfigProperty configProperty) { String typeContent = ""; - if (configProperty.isEnum() && enableEnumTooltips) { - typeContent = configProperty.getEnumAcceptedValues().values().entrySet().stream() - .map(e -> { - Optional javadocElement = javadocRepository.getElement(configProperty.getType(), - e.getKey()); - if (javadocElement.isEmpty()) { - return "`" + e.getValue().configValue() + "`"; - } - - return String.format(TOOLTIP_MACRO, e.getValue().configValue(), - cleanTooltipContent(javadocElement.get().description())); - }) - .collect(Collectors.joining(", ")); + if (configProperty.isEnum()) { + if (enableEnumTooltips) { + typeContent = configProperty.getEnumAcceptedValues().values().entrySet().stream() + .map(e -> { + Optional javadocElement = javadocRepository.getElement(configProperty.getType(), + e.getKey()); + if (javadocElement.isEmpty()) { + return "`" + e.getValue().configValue() + "`"; + } + + return String.format(TOOLTIP_MACRO, e.getValue().configValue(), + cleanTooltipContent(javadocElement.get().description())); + }) + .collect(Collectors.joining(", ")); + } else { + typeContent = configProperty.getEnumAcceptedValues().values().values().stream() + .map(v -> v.configValue()) + .collect(Collectors.joining("`, `", "`", "`")); + } } else { typeContent = configProperty.getTypeDescription(); if (configProperty.getJavadocSiteLink() != null) {