diff --git a/deploy/pipeline/mw-pipeline-v0.1.yaml b/deploy/pipeline/mw-pipeline-v0.1.yaml
index ee61b9262..aedfd2f38 100644
--- a/deploy/pipeline/mw-pipeline-v0.1.yaml
+++ b/deploy/pipeline/mw-pipeline-v0.1.yaml
@@ -43,6 +43,9 @@ spec:
type: string
- name: JVM_BUILD_SERVICE_REQPROCESSOR_IMAGE
type: string
+ - name: NOTIFICATION_CONTEXT
+ type: string
+ default: ""
workspaces:
- name: source
description: Workspace containing the source code
@@ -101,7 +104,7 @@ spec:
resolver: http
params:
- name: url
- value: https://raw.githubusercontent.com/redhat-appstudio/jvm-build-service/refs/heads/main/deploy/tasks/pre-build.yaml
+ value: https://raw.githubusercontent.com/rnc/jvm-build-service/refs/heads/BR3/deploy/tasks/pre-build.yaml
workspaces:
- name: source
workspace: source
@@ -161,3 +164,39 @@ spec:
params:
- name: url
value: https://raw.githubusercontent.com/redhat-appstudio/jvm-build-service/refs/heads/main/deploy/tasks/maven-deployment.yaml
+
+ finally:
+ - name: notification
+ displayName: "Notify PNC driver"
+ params:
+ - name: ACCESS_TOKEN
+ value: $(params.ACCESS_TOKEN)
+ - name: JVM_BUILD_SERVICE_REQPROCESSOR_IMAGE
+ value: $(params.JVM_BUILD_SERVICE_REQPROCESSOR_IMAGE)
+ - name: NOTIFICATION_CONTEXT
+ value: $(params.NOTIFICATION_CONTEXT)
+ - name: STATUS
+ value: $(tasks.status)
+ taskSpec:
+ params:
+ - name: ACCESS_TOKEN
+ description: Access token for OAuth.
+ type: string
+ default: ""
+ - name: JVM_BUILD_SERVICE_REQPROCESSOR_IMAGE
+ description: Name of the processor image. Useful to override for development.
+ type: string
+ - name: NOTIFICATION_CONTEXT
+ description: Notification context
+ type: string
+ - name: STATUS
+ description: Aggregate tasks status
+ type: string
+ steps:
+ - name: notification
+ image: $(params.JVM_BUILD_SERVICE_REQPROCESSOR_IMAGE)
+ args:
+ - notify
+ - --context=$(params.NOTIFICATION_CONTEXT)
+ - --status=$(params.STATUS)
+ - --build-id=$(params.BUILD_ID)
diff --git a/deploy/tasks/pre-build.yaml b/deploy/tasks/pre-build.yaml
index 717b2da8f..ca98b22b3 100644
--- a/deploy/tasks/pre-build.yaml
+++ b/deploy/tasks/pre-build.yaml
@@ -118,9 +118,11 @@ spec:
- name: create-pre-build-image
image: quay.io/redhat-appstudio/build-trusted-artifacts:latest@sha256:52f1391e6f1c472fd10bb838f64fae2ed3320c636f536014978a5ddbdfc6b3af
script: |
+ set -x
+ echo "IMAGE is $(params.IMAGE_URL)"
+ cat $HOME/.docker/config.json || true
echo "Creating pre-build-image archive"
create-archive --store $(params.IMAGE_URL) $(results.PRE_BUILD_IMAGE_DIGEST.path)=$(workspaces.source.path)/source
env:
- name: IMAGE_URL
value: $(params.IMAGE_URL)
-
diff --git a/java-components/build-request-processor/pom.xml b/java-components/build-request-processor/pom.xml
index a92e92bff..637ddd63c 100644
--- a/java-components/build-request-processor/pom.xml
+++ b/java-components/build-request-processor/pom.xml
@@ -55,6 +55,12 @@
quarkus-maven-resolver
+
+ org.jboss.pnc
+ pnc-api
+ 3.0.0
+
+
com.google.cloud.tools
jib-core
@@ -102,6 +108,13 @@
pom-manipulation-common
+
+ org.projectlombok
+ lombok
+ 1.18.34
+ provided
+
+
io.quarkus
quarkus-junit5
@@ -122,6 +135,11 @@
assertj-core
test
+
+ org.wiremock
+ wiremock
+ test
+
diff --git a/java-components/build-request-processor/src/main/java/com/redhat/hacbs/container/EntryPoint.java b/java-components/build-request-processor/src/main/java/com/redhat/hacbs/container/EntryPoint.java
index e484b64a8..8fb3325f2 100644
--- a/java-components/build-request-processor/src/main/java/com/redhat/hacbs/container/EntryPoint.java
+++ b/java-components/build-request-processor/src/main/java/com/redhat/hacbs/container/EntryPoint.java
@@ -11,6 +11,7 @@
import com.redhat.hacbs.container.deploy.CopyArtifactsCommand;
import com.redhat.hacbs.container.deploy.DeployCommand;
import com.redhat.hacbs.container.deploy.DeployPreBuildSourceCommand;
+import com.redhat.hacbs.container.notification.NotifyCommand;
import com.redhat.hacbs.container.verifier.VerifyBuiltArtifactsCommand;
import io.quarkus.picocli.runtime.annotations.TopCommand;
@@ -27,6 +28,7 @@
LookupBuildInfoCommand.class,
LookupScmLocationCommand.class,
DeployCommand.class,
+ NotifyCommand.class,
MavenPrepareCommand.class,
SBTPrepareCommand.class,
VerifyBuiltArtifactsCommand.class
diff --git a/java-components/build-request-processor/src/main/java/com/redhat/hacbs/container/build/preprocessor/AbstractPreprocessor.java b/java-components/build-request-processor/src/main/java/com/redhat/hacbs/container/build/preprocessor/AbstractPreprocessor.java
index 9a3076f9a..6c620a4f6 100644
--- a/java-components/build-request-processor/src/main/java/com/redhat/hacbs/container/build/preprocessor/AbstractPreprocessor.java
+++ b/java-components/build-request-processor/src/main/java/com/redhat/hacbs/container/build/preprocessor/AbstractPreprocessor.java
@@ -212,8 +212,6 @@ private String getContainerFile() {
""";
}
- Log.warnf("### containerFile is\n%s", containerFile);
-
return containerFile;
}
diff --git a/java-components/build-request-processor/src/main/java/com/redhat/hacbs/container/notification/NotifyCommand.java b/java-components/build-request-processor/src/main/java/com/redhat/hacbs/container/notification/NotifyCommand.java
new file mode 100644
index 000000000..ca9592d26
--- /dev/null
+++ b/java-components/build-request-processor/src/main/java/com/redhat/hacbs/container/notification/NotifyCommand.java
@@ -0,0 +1,77 @@
+package com.redhat.hacbs.container.notification;
+
+import static org.apache.commons.lang3.StringUtils.isEmpty;
+
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.time.Duration;
+import java.util.Optional;
+
+import jakarta.inject.Inject;
+
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+import org.jboss.pnc.api.dto.Request;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import io.quarkus.logging.Log;
+import picocli.CommandLine;
+
+@CommandLine.Command(name = "notify")
+public class NotifyCommand implements Runnable {
+
+ @CommandLine.Option(names = "--build-id", required = true)
+ String buildId;
+
+ @CommandLine.Option(names = "--status", required = true)
+ String status;
+
+ @CommandLine.Option(names = "--context", required = true)
+ String context;
+
+ @CommandLine.Option(names = "--request-timeout")
+ int requestTimeout = 15;
+
+ // TODO: do we need this...
+ @ConfigProperty(name = "access.token")
+ Optional accessToken;
+
+ @Inject
+ ObjectMapper objectMapper;
+
+ public void run() {
+ try {
+
+ if (isEmpty(context)) {
+ Log.infof("No callback configured ; unable to notify.");
+ return;
+ }
+
+ Request callback = objectMapper.readValue(context, Request.class );
+
+ Log.infof("Notification for build %s with status %s and callback %s", buildId, status, callback);
+ PipelineNotification notification = PipelineNotification.builder().buildId(buildId).status(status).completionCallback((Request) callback.getAttachment()).build();
+ String body = objectMapper.writeValueAsString(notification);
+
+ HttpRequest.Builder builder = HttpRequest.newBuilder()
+ .uri(callback.getUri())
+ .method(callback.getMethod().name(), HttpRequest.BodyPublishers.ofString(body))
+ .timeout(Duration.ofSeconds(requestTimeout));
+ callback.getHeaders().forEach(h -> builder.header(h.getName(), h.getValue()));
+
+
+ HttpRequest request = builder.build();
+ // TODO: Retry? Send async? Some useful mutiny examples from quarkus in https://gist.github.com/cescoffier/e9abce907a1c3d05d70bea3dae6dc3d5
+ HttpResponse response;
+ try (HttpClient httpClient = HttpClient.newHttpClient()) {
+ response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
+ }
+ Log.infof("Response %s", response);
+
+ } catch (Exception e) {
+ Log.error("Notification failed", e);
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/java-components/build-request-processor/src/main/java/com/redhat/hacbs/container/notification/PipelineNotification.java b/java-components/build-request-processor/src/main/java/com/redhat/hacbs/container/notification/PipelineNotification.java
new file mode 100644
index 000000000..f4526df59
--- /dev/null
+++ b/java-components/build-request-processor/src/main/java/com/redhat/hacbs/container/notification/PipelineNotification.java
@@ -0,0 +1,19 @@
+package com.redhat.hacbs.container.notification;
+
+import org.jboss.pnc.api.dto.Request;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+import lombok.Builder;
+
+// TODO: This is a direct copy of the same class in konflux-build-driver. Both need moved to pnc-api to
+// avoid clashes and duplication. For instance, we can't depend upon konflux-build-driver as that
+// then leads to oidc client issues.
+@Builder(builderClassName = "Builder")
+@JsonIgnoreProperties(ignoreUnknown = true)
+public record PipelineNotification(
+ String status,
+ String buildId,
+ Request completionCallback) {
+
+}
diff --git a/java-components/build-request-processor/src/test/java/com/redhat/hacbs/container/notification/NotificationTest.java b/java-components/build-request-processor/src/test/java/com/redhat/hacbs/container/notification/NotificationTest.java
new file mode 100644
index 000000000..90723f93f
--- /dev/null
+++ b/java-components/build-request-processor/src/test/java/com/redhat/hacbs/container/notification/NotificationTest.java
@@ -0,0 +1,73 @@
+package com.redhat.hacbs.container.notification;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+import java.util.logging.LogRecord;
+
+import javax.ws.rs.core.MediaType;
+
+import org.jboss.pnc.api.constants.HttpHeaders;
+import org.jboss.pnc.api.dto.Request;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.tomakehurst.wiremock.WireMockServer;
+
+import io.quarkus.test.LogCollectingTestResource;
+import io.quarkus.test.common.QuarkusTestResource;
+import io.quarkus.test.common.ResourceArg;
+import io.quarkus.test.junit.QuarkusTest;
+
+@QuarkusTest
+@QuarkusTestResource(value = LogCollectingTestResource.class, restrictToAnnotatedClass = true, initArgs = @ResourceArg(name = LogCollectingTestResource.LEVEL, value = "FINE"))
+@QuarkusTestResource(WireMockExtensions.class)
+public class NotificationTest {
+
+ private WireMockServer wireMockServer;
+
+ @BeforeEach
+ public void clearLogs() {
+ LogCollectingTestResource.current().clear();
+ }
+
+ @Test
+ public void testNoNotify() {
+ NotifyCommand notifyCommand = new NotifyCommand();
+ notifyCommand.status = "Succeeded";
+ notifyCommand.buildId = "1234";
+ notifyCommand.run();
+ List logRecords = LogCollectingTestResource.current().getRecords();
+ assertTrue(logRecords.stream()
+ .anyMatch(r -> LogCollectingTestResource.format(r).contains("No callback configured ; unable to notify")));
+ }
+
+ @Test
+ public void testNotify() throws IOException, URISyntaxException {
+
+ Request request = Request.builder()
+ .method(Request.Method.PUT)
+ .header(new Request.Header(HttpHeaders.CONTENT_TYPE_STRING, MediaType.APPLICATION_JSON))
+ .attachment(null)
+ .uri(new URI(wireMockServer.baseUrl() + "/internal/completed"))
+ .build();
+
+ System.err.println("### wiremock uri: " + wireMockServer.baseUrl());
+ // {"method":"PUT","uri":"http://localhost:8081/internal/completed","headers":[{"name":"Content-Type","value":"application/json"}],"attachment":null}
+
+ NotifyCommand notifyCommand = new NotifyCommand();
+ notifyCommand.status = "Succeeded";
+ notifyCommand.buildId = "1234";
+ notifyCommand.objectMapper = new ObjectMapper();
+ notifyCommand.context = notifyCommand.objectMapper.writeValueAsString(request);
+ notifyCommand.run();
+
+ List logRecords = LogCollectingTestResource.current().getRecords();
+ assertTrue(logRecords.stream()
+ .anyMatch(r -> LogCollectingTestResource.format(r).contains("Response (PUT http://localhost:8080/internal/completed) 200")));
+ }
+}
diff --git a/java-components/build-request-processor/src/test/java/com/redhat/hacbs/container/notification/WireMockExtensions.java b/java-components/build-request-processor/src/test/java/com/redhat/hacbs/container/notification/WireMockExtensions.java
new file mode 100644
index 000000000..0deacb517
--- /dev/null
+++ b/java-components/build-request-processor/src/test/java/com/redhat/hacbs/container/notification/WireMockExtensions.java
@@ -0,0 +1,45 @@
+package com.redhat.hacbs.container.notification;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson;
+import static com.github.tomakehurst.wiremock.client.WireMock.put;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
+
+import java.util.Map;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+import com.github.tomakehurst.wiremock.common.ConsoleNotifier;
+
+import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
+
+public class WireMockExtensions implements QuarkusTestResourceLifecycleManager {
+ private WireMockServer wireMockServer;
+
+ @Override
+ public Map start() {
+ wireMockServer = new WireMockServer(wireMockConfig().notifier(new ConsoleNotifier(true)));
+ wireMockServer.start();
+
+ wireMockServer.stubFor(
+ put(urlEqualTo("/internal/completed"))
+ .withRequestBody(
+ equalToJson("{\"status\":\"Succeeded\",\"buildId\":\"1234\",\"completionCallback\":null}"))
+ .willReturn(aResponse()
+ .withStatus(200)));
+
+ return Map.of("quarkus.rest-client.wiremockextensions.url", wireMockServer.baseUrl());
+ }
+
+ @Override
+ public void stop() {
+ if (wireMockServer != null) {
+ wireMockServer.stop();
+ }
+ }
+
+ @Override
+ public void inject(TestInjector testInjector) {
+ testInjector.injectIntoFields(wireMockServer, new TestInjector.MatchesType(WireMockServer.class));
+ }
+}