Skip to content

Commit 908d8a5

Browse files
authored
Merge pull request #2325 from rnc/BR3
Add notification to pipeline
2 parents d93cece + cfcbd23 commit 908d8a5

File tree

9 files changed

+277
-4
lines changed

9 files changed

+277
-4
lines changed

deploy/pipeline/mw-pipeline-v0.1.yaml

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ spec:
4343
type: string
4444
- name: JVM_BUILD_SERVICE_REQPROCESSOR_IMAGE
4545
type: string
46+
- name: NOTIFICATION_CONTEXT
47+
type: string
48+
default: ""
4649
workspaces:
4750
- name: source
4851
description: Workspace containing the source code
@@ -101,7 +104,7 @@ spec:
101104
resolver: http
102105
params:
103106
- name: url
104-
value: https://raw.githubusercontent.com/redhat-appstudio/jvm-build-service/refs/heads/main/deploy/tasks/pre-build.yaml
107+
value: https://raw.githubusercontent.com/rnc/jvm-build-service/refs/heads/BR3/deploy/tasks/pre-build.yaml
105108
workspaces:
106109
- name: source
107110
workspace: source
@@ -161,3 +164,39 @@ spec:
161164
params:
162165
- name: url
163166
value: https://raw.githubusercontent.com/redhat-appstudio/jvm-build-service/refs/heads/main/deploy/tasks/maven-deployment.yaml
167+
168+
finally:
169+
- name: notification
170+
displayName: "Notify PNC driver"
171+
params:
172+
- name: ACCESS_TOKEN
173+
value: $(params.ACCESS_TOKEN)
174+
- name: JVM_BUILD_SERVICE_REQPROCESSOR_IMAGE
175+
value: $(params.JVM_BUILD_SERVICE_REQPROCESSOR_IMAGE)
176+
- name: NOTIFICATION_CONTEXT
177+
value: $(params.NOTIFICATION_CONTEXT)
178+
- name: STATUS
179+
value: $(tasks.status)
180+
taskSpec:
181+
params:
182+
- name: ACCESS_TOKEN
183+
description: Access token for OAuth.
184+
type: string
185+
default: ""
186+
- name: JVM_BUILD_SERVICE_REQPROCESSOR_IMAGE
187+
description: Name of the processor image. Useful to override for development.
188+
type: string
189+
- name: NOTIFICATION_CONTEXT
190+
description: Notification context
191+
type: string
192+
- name: STATUS
193+
description: Aggregate tasks status
194+
type: string
195+
steps:
196+
- name: notification
197+
image: $(params.JVM_BUILD_SERVICE_REQPROCESSOR_IMAGE)
198+
args:
199+
- notify
200+
- --context=$(params.NOTIFICATION_CONTEXT)
201+
- --status=$(params.STATUS)
202+
- --build-id=$(params.BUILD_ID)

deploy/tasks/pre-build.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,9 +118,11 @@ spec:
118118
- name: create-pre-build-image
119119
image: quay.io/redhat-appstudio/build-trusted-artifacts:latest@sha256:52f1391e6f1c472fd10bb838f64fae2ed3320c636f536014978a5ddbdfc6b3af
120120
script: |
121+
set -x
122+
echo "IMAGE is $(params.IMAGE_URL)"
123+
cat $HOME/.docker/config.json || true
121124
echo "Creating pre-build-image archive"
122125
create-archive --store $(params.IMAGE_URL) $(results.PRE_BUILD_IMAGE_DIGEST.path)=$(workspaces.source.path)/source
123126
env:
124127
- name: IMAGE_URL
125128
value: $(params.IMAGE_URL)
126-

java-components/build-request-processor/pom.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@
5555
<artifactId>quarkus-maven-resolver</artifactId>
5656
</dependency>
5757

58+
<dependency>
59+
<groupId>org.jboss.pnc</groupId>
60+
<artifactId>pnc-api</artifactId>
61+
<version>3.0.0</version>
62+
</dependency>
63+
5864
<dependency>
5965
<groupId>com.google.cloud.tools</groupId>
6066
<artifactId>jib-core</artifactId>
@@ -102,6 +108,13 @@
102108
<artifactId>pom-manipulation-common</artifactId>
103109
</dependency>
104110

111+
<dependency>
112+
<groupId>org.projectlombok</groupId>
113+
<artifactId>lombok</artifactId>
114+
<version>1.18.34</version>
115+
<scope>provided</scope>
116+
</dependency>
117+
105118
<dependency>
106119
<groupId>io.quarkus</groupId>
107120
<artifactId>quarkus-junit5</artifactId>
@@ -122,6 +135,11 @@
122135
<artifactId>assertj-core</artifactId>
123136
<scope>test</scope>
124137
</dependency>
138+
<dependency>
139+
<groupId>org.wiremock</groupId>
140+
<artifactId>wiremock</artifactId>
141+
<scope>test</scope>
142+
</dependency>
125143
</dependencies>
126144
<build>
127145
<plugins>

java-components/build-request-processor/src/main/java/com/redhat/hacbs/container/EntryPoint.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.redhat.hacbs.container.deploy.CopyArtifactsCommand;
1212
import com.redhat.hacbs.container.deploy.DeployCommand;
1313
import com.redhat.hacbs.container.deploy.DeployPreBuildSourceCommand;
14+
import com.redhat.hacbs.container.notification.NotifyCommand;
1415
import com.redhat.hacbs.container.verifier.VerifyBuiltArtifactsCommand;
1516

1617
import io.quarkus.picocli.runtime.annotations.TopCommand;
@@ -27,6 +28,7 @@
2728
LookupBuildInfoCommand.class,
2829
LookupScmLocationCommand.class,
2930
DeployCommand.class,
31+
NotifyCommand.class,
3032
MavenPrepareCommand.class,
3133
SBTPrepareCommand.class,
3234
VerifyBuiltArtifactsCommand.class

java-components/build-request-processor/src/main/java/com/redhat/hacbs/container/build/preprocessor/AbstractPreprocessor.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,6 @@ private String getContainerFile() {
221221
""";
222222
}
223223

224-
Log.warnf("### containerFile is\n%s", containerFile);
225-
226224
return containerFile;
227225
}
228226

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.redhat.hacbs.container.notification;
2+
3+
import static org.apache.commons.lang3.StringUtils.isEmpty;
4+
5+
import java.net.http.HttpClient;
6+
import java.net.http.HttpRequest;
7+
import java.net.http.HttpResponse;
8+
import java.time.Duration;
9+
import java.util.Optional;
10+
11+
import jakarta.inject.Inject;
12+
13+
import org.eclipse.microprofile.config.inject.ConfigProperty;
14+
import org.jboss.pnc.api.dto.Request;
15+
16+
import com.fasterxml.jackson.databind.ObjectMapper;
17+
18+
import io.quarkus.logging.Log;
19+
import picocli.CommandLine;
20+
21+
@CommandLine.Command(name = "notify")
22+
public class NotifyCommand implements Runnable {
23+
24+
@CommandLine.Option(names = "--build-id", required = true)
25+
String buildId;
26+
27+
@CommandLine.Option(names = "--status", required = true)
28+
String status;
29+
30+
@CommandLine.Option(names = "--context", required = true)
31+
String context;
32+
33+
@CommandLine.Option(names = "--request-timeout")
34+
int requestTimeout = 15;
35+
36+
// TODO: do we need this...
37+
@ConfigProperty(name = "access.token")
38+
Optional<String> accessToken;
39+
40+
@Inject
41+
ObjectMapper objectMapper;
42+
43+
public void run() {
44+
try {
45+
46+
if (isEmpty(context)) {
47+
Log.infof("No callback configured ; unable to notify.");
48+
return;
49+
}
50+
51+
Request callback = objectMapper.readValue(context, Request.class );
52+
53+
Log.infof("Notification for build %s with status %s and callback %s", buildId, status, callback);
54+
PipelineNotification notification = PipelineNotification.builder().buildId(buildId).status(status).completionCallback((Request) callback.getAttachment()).build();
55+
String body = objectMapper.writeValueAsString(notification);
56+
57+
HttpRequest.Builder builder = HttpRequest.newBuilder()
58+
.uri(callback.getUri())
59+
.method(callback.getMethod().name(), HttpRequest.BodyPublishers.ofString(body))
60+
.timeout(Duration.ofSeconds(requestTimeout));
61+
callback.getHeaders().forEach(h -> builder.header(h.getName(), h.getValue()));
62+
63+
64+
HttpRequest request = builder.build();
65+
// TODO: Retry? Send async? Some useful mutiny examples from quarkus in https://gist.github.com/cescoffier/e9abce907a1c3d05d70bea3dae6dc3d5
66+
HttpResponse<String> response;
67+
try (HttpClient httpClient = HttpClient.newHttpClient()) {
68+
response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
69+
}
70+
Log.infof("Response %s", response);
71+
72+
} catch (Exception e) {
73+
Log.error("Notification failed", e);
74+
throw new RuntimeException(e);
75+
}
76+
}
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.redhat.hacbs.container.notification;
2+
3+
import org.jboss.pnc.api.dto.Request;
4+
5+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
6+
7+
import lombok.Builder;
8+
9+
// TODO: This is a direct copy of the same class in konflux-build-driver. Both need moved to pnc-api to
10+
// avoid clashes and duplication. For instance, we can't depend upon konflux-build-driver as that
11+
// then leads to oidc client issues.
12+
@Builder(builderClassName = "Builder")
13+
@JsonIgnoreProperties(ignoreUnknown = true)
14+
public record PipelineNotification(
15+
String status,
16+
String buildId,
17+
Request completionCallback) {
18+
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package com.redhat.hacbs.container.notification;
2+
3+
import static org.junit.jupiter.api.Assertions.assertTrue;
4+
5+
import java.io.IOException;
6+
import java.net.URI;
7+
import java.net.URISyntaxException;
8+
import java.util.List;
9+
import java.util.logging.LogRecord;
10+
11+
import javax.ws.rs.core.MediaType;
12+
13+
import org.jboss.pnc.api.constants.HttpHeaders;
14+
import org.jboss.pnc.api.dto.Request;
15+
import org.junit.jupiter.api.BeforeEach;
16+
import org.junit.jupiter.api.Test;
17+
18+
import com.fasterxml.jackson.databind.ObjectMapper;
19+
import com.github.tomakehurst.wiremock.WireMockServer;
20+
21+
import io.quarkus.test.LogCollectingTestResource;
22+
import io.quarkus.test.common.QuarkusTestResource;
23+
import io.quarkus.test.common.ResourceArg;
24+
import io.quarkus.test.junit.QuarkusTest;
25+
26+
@QuarkusTest
27+
@QuarkusTestResource(value = LogCollectingTestResource.class, restrictToAnnotatedClass = true, initArgs = @ResourceArg(name = LogCollectingTestResource.LEVEL, value = "FINE"))
28+
@QuarkusTestResource(WireMockExtensions.class)
29+
public class NotificationTest {
30+
31+
private WireMockServer wireMockServer;
32+
33+
@BeforeEach
34+
public void clearLogs() {
35+
LogCollectingTestResource.current().clear();
36+
}
37+
38+
@Test
39+
public void testNoNotify() {
40+
NotifyCommand notifyCommand = new NotifyCommand();
41+
notifyCommand.status = "Succeeded";
42+
notifyCommand.buildId = "1234";
43+
notifyCommand.run();
44+
List<LogRecord> logRecords = LogCollectingTestResource.current().getRecords();
45+
assertTrue(logRecords.stream()
46+
.anyMatch(r -> LogCollectingTestResource.format(r).contains("No callback configured ; unable to notify")));
47+
}
48+
49+
@Test
50+
public void testNotify() throws IOException, URISyntaxException {
51+
52+
Request request = Request.builder()
53+
.method(Request.Method.PUT)
54+
.header(new Request.Header(HttpHeaders.CONTENT_TYPE_STRING, MediaType.APPLICATION_JSON))
55+
.attachment(null)
56+
.uri(new URI(wireMockServer.baseUrl() + "/internal/completed"))
57+
.build();
58+
59+
System.err.println("### wiremock uri: " + wireMockServer.baseUrl());
60+
// {"method":"PUT","uri":"http://localhost:8081/internal/completed","headers":[{"name":"Content-Type","value":"application/json"}],"attachment":null}
61+
62+
NotifyCommand notifyCommand = new NotifyCommand();
63+
notifyCommand.status = "Succeeded";
64+
notifyCommand.buildId = "1234";
65+
notifyCommand.objectMapper = new ObjectMapper();
66+
notifyCommand.context = notifyCommand.objectMapper.writeValueAsString(request);
67+
notifyCommand.run();
68+
69+
List<LogRecord> logRecords = LogCollectingTestResource.current().getRecords();
70+
assertTrue(logRecords.stream()
71+
.anyMatch(r -> LogCollectingTestResource.format(r).contains("Response (PUT http://localhost:8080/internal/completed) 200")));
72+
}
73+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.redhat.hacbs.container.notification;
2+
3+
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
4+
import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson;
5+
import static com.github.tomakehurst.wiremock.client.WireMock.put;
6+
import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
7+
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
8+
9+
import java.util.Map;
10+
11+
import com.github.tomakehurst.wiremock.WireMockServer;
12+
import com.github.tomakehurst.wiremock.common.ConsoleNotifier;
13+
14+
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
15+
16+
public class WireMockExtensions implements QuarkusTestResourceLifecycleManager {
17+
private WireMockServer wireMockServer;
18+
19+
@Override
20+
public Map<String, String> start() {
21+
wireMockServer = new WireMockServer(wireMockConfig().notifier(new ConsoleNotifier(true)));
22+
wireMockServer.start();
23+
24+
wireMockServer.stubFor(
25+
put(urlEqualTo("/internal/completed"))
26+
.withRequestBody(
27+
equalToJson("{\"status\":\"Succeeded\",\"buildId\":\"1234\",\"completionCallback\":null}"))
28+
.willReturn(aResponse()
29+
.withStatus(200)));
30+
31+
return Map.of("quarkus.rest-client.wiremockextensions.url", wireMockServer.baseUrl());
32+
}
33+
34+
@Override
35+
public void stop() {
36+
if (wireMockServer != null) {
37+
wireMockServer.stop();
38+
}
39+
}
40+
41+
@Override
42+
public void inject(TestInjector testInjector) {
43+
testInjector.injectIntoFields(wireMockServer, new TestInjector.MatchesType(WireMockServer.class));
44+
}
45+
}

0 commit comments

Comments
 (0)