Skip to content

Commit

Permalink
feat(notifications/cdEvents): added support for customData (#1424)
Browse files Browse the repository at this point in the history
* feat(notifications/cdEvents): added support for customData

* Added validation for expected CDEvents customData

* Updated unit test name

---------

Co-authored-by: spinnakerbot <[email protected]>
Co-authored-by: GARCIA, JOSE <[email protected]>
  • Loading branch information
3 people committed Jul 11, 2024
1 parent d2d30df commit 01ada0c
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 40 deletions.
6 changes: 3 additions & 3 deletions echo-notifications/echo-notifications.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ dependencies {
implementation "org.jsoup:jsoup:1.8.3"
implementation "com.atlassian.commonmark:commonmark:0.9.0"
implementation "org.codehaus.groovy:groovy-json"
implementation "io.cloudevents:cloudevents-http-basic:2.5.0"
implementation "io.cloudevents:cloudevents-json-jackson:2.5.0"
implementation ("dev.cdevents:cdevents-sdk-java:0.1.2")
implementation "io.cloudevents:cloudevents-http-basic:3.0.0"
implementation "io.cloudevents:cloudevents-json-jackson:3.0.0"
implementation ("dev.cdevents:cdevents-sdk-java:0.3.1")
testImplementation("com.icegreen:greenmail:1.5.14") {
exclude group: "com.sun.mail", module: "javax.mail"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import dev.cdevents.CDEvents;
import dev.cdevents.constants.CDEventConstants;
import dev.cdevents.events.PipelineRunFinishedCDEvent;
import dev.cdevents.events.PipelinerunFinishedCDEvent;
import io.cloudevents.CloudEvent;
import java.net.URI;
import lombok.Getter;
Expand All @@ -27,34 +27,37 @@ public class CDEventPipelineRunFinished extends BaseCDEvent {

@Getter private String subjectPipelineName;
@Getter private String subjectError;
@Getter private Object customData;

public CDEventPipelineRunFinished(
String executionId,
String executionUrl,
String executionName,
String spinnakerUrl,
String status) {
String status,
Object customData) {
super(spinnakerUrl, executionId, spinnakerUrl, executionUrl);
this.subjectPipelineName = executionName;
this.subjectError = status;
this.customData = customData;
}

@Override
public CloudEvent createCDEvent() {
PipelineRunFinishedCDEvent cdEvent = new PipelineRunFinishedCDEvent();
PipelinerunFinishedCDEvent cdEvent = new PipelinerunFinishedCDEvent();
cdEvent.setSource(URI.create(getSource()));
cdEvent.setSubjectId(getSubjectId());
cdEvent.setSubjectSource(URI.create(getSubjectSource()));
cdEvent.setSubjectPipelineName(getSubjectPipelineName());
cdEvent.setSubjectUrl(URI.create(getSubjectUrl()));
cdEvent.setSubjectUrl(URI.create(getSubjectUrl()).toString());
cdEvent.setSubjectErrors(getSubjectError());

if ("complete".equals(getSubjectError())) {
cdEvent.setSubjectOutcome(CDEventConstants.Outcome.SUCCESS);
cdEvent.setSubjectOutcome(CDEventConstants.Outcome.SUCCESS.getOutcome());
} else if ("failed".equals(getSubjectError())) {
cdEvent.setSubjectOutcome(CDEventConstants.Outcome.FAILURE);
cdEvent.setSubjectOutcome(CDEventConstants.Outcome.FAILURE.getOutcome());
}

cdEvent.setCustomData(customData);
return CDEvents.cdEventAsCloudEvent(cdEvent);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,36 @@
package com.netflix.spinnaker.echo.cdevents;

import dev.cdevents.CDEvents;
import dev.cdevents.events.PipelineRunQueuedCDEvent;
import dev.cdevents.events.PipelinerunQueuedCDEvent;
import io.cloudevents.CloudEvent;
import java.net.URI;
import lombok.Getter;

public class CDEventPipelineRunQueued extends BaseCDEvent {

@Getter private String subjectPipelineName;
@Getter private Object customData;

public CDEventPipelineRunQueued(
String executionId, String executionUrl, String executionName, String spinnakerUrl) {
String executionId,
String executionUrl,
String executionName,
String spinnakerUrl,
Object customData) {
super(spinnakerUrl, executionId, spinnakerUrl, executionUrl);
this.subjectPipelineName = executionName;
this.customData = customData;
}

@Override
public CloudEvent createCDEvent() {
PipelineRunQueuedCDEvent cdEvent = new PipelineRunQueuedCDEvent();
PipelinerunQueuedCDEvent cdEvent = new PipelinerunQueuedCDEvent();
cdEvent.setSource(URI.create(getSource()));
cdEvent.setSubjectId(getSubjectId());
cdEvent.setSubjectSource(URI.create(getSubjectSource()));
cdEvent.setSubjectPipelineName(getSubjectPipelineName());
cdEvent.setSubjectUrl(URI.create(getSubjectUrl()));

cdEvent.setSubjectUrl(URI.create(getSubjectUrl()).toString());
cdEvent.setCustomData(customData);
return CDEvents.cdEventAsCloudEvent(cdEvent);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,36 @@
package com.netflix.spinnaker.echo.cdevents;

import dev.cdevents.CDEvents;
import dev.cdevents.events.PipelineRunStartedCDEvent;
import dev.cdevents.events.PipelinerunStartedCDEvent;
import io.cloudevents.CloudEvent;
import java.net.URI;
import lombok.Getter;

public class CDEventPipelineRunStarted extends BaseCDEvent {

@Getter private String subjectPipelineName;
@Getter private Object customData;

public CDEventPipelineRunStarted(
String executionId, String executionUrl, String executionName, String spinnakerUrl) {
String executionId,
String executionUrl,
String executionName,
String spinnakerUrl,
Object customData) {
super(spinnakerUrl, executionId, spinnakerUrl, executionUrl);
this.subjectPipelineName = executionName;
this.customData = customData;
}

@Override
public CloudEvent createCDEvent() {
PipelineRunStartedCDEvent cdEvent = new PipelineRunStartedCDEvent();
PipelinerunStartedCDEvent cdEvent = new PipelinerunStartedCDEvent();
cdEvent.setSource(URI.create(getSource()));
cdEvent.setSubjectId(getSubjectId());
cdEvent.setSubjectSource(URI.create(getSubjectSource()));
cdEvent.setSubjectPipelineName(getSubjectPipelineName());
cdEvent.setSubjectUrl(URI.create(getSubjectUrl()));
cdEvent.setSubjectUrl(URI.create(getSubjectUrl()).toString());
cdEvent.setCustomData(customData);

return CDEvents.cdEventAsCloudEvent(cdEvent);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

import dev.cdevents.CDEvents;
import dev.cdevents.constants.CDEventConstants;
import dev.cdevents.events.TaskRunFinishedCDEvent;
import dev.cdevents.events.TaskrunFinishedCDEvent;
import io.cloudevents.CloudEvent;
import java.net.URI;
import lombok.Getter;
Expand All @@ -28,35 +28,38 @@ public class CDEventTaskRunFinished extends BaseCDEvent {
@Getter private String subjectTaskName;
@Getter private String subjectPipelineRunId;
@Getter private String subjectError;
@Getter private Object customData;

public CDEventTaskRunFinished(
String executionId,
String executionUrl,
String executionName,
String spinnakerUrl,
String status) {
String status,
Object customData) {
super(spinnakerUrl, executionId, spinnakerUrl, executionUrl);
this.subjectTaskName = executionName;
this.subjectPipelineRunId = executionId;
this.subjectError = status;
this.customData = customData;
}

@Override
public CloudEvent createCDEvent() {
TaskRunFinishedCDEvent cdEvent = new TaskRunFinishedCDEvent();
TaskrunFinishedCDEvent cdEvent = new TaskrunFinishedCDEvent();
cdEvent.setSource(URI.create(getSource()));
cdEvent.setSubjectId(getSubjectId());
cdEvent.setSubjectSource(URI.create(getSubjectSource()));
cdEvent.setSubjectTaskName(getSubjectTaskName());
cdEvent.setSubjectUrl(URI.create(getSubjectUrl()));
cdEvent.setSubjectUrl(URI.create(getSubjectUrl()).toString());
cdEvent.setSubjectErrors(getSubjectError());
cdEvent.setSubjectPipelineRunId(getSubjectPipelineRunId());
if ("complete".equals(getSubjectError())) {
cdEvent.setSubjectOutcome(CDEventConstants.Outcome.SUCCESS);
cdEvent.setSubjectOutcome(CDEventConstants.Outcome.SUCCESS.getOutcome());
} else if ("failed".equals(getSubjectError())) {
cdEvent.setSubjectOutcome(CDEventConstants.Outcome.FAILURE);
cdEvent.setSubjectOutcome(CDEventConstants.Outcome.FAILURE.getOutcome());
}

cdEvent.setCustomData(customData);
return CDEvents.cdEventAsCloudEvent(cdEvent);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
package com.netflix.spinnaker.echo.cdevents;

import dev.cdevents.CDEvents;
import dev.cdevents.events.TaskRunStartedCDEvent;
import dev.cdevents.events.TaskrunStartedCDEvent;
import io.cloudevents.CloudEvent;
import java.net.URI;
import lombok.Getter;
Expand All @@ -26,24 +26,31 @@ public class CDEventTaskRunStarted extends BaseCDEvent {

@Getter private String subjectTaskName;
@Getter private String subjectPipelineRunId;
@Getter private Object customData;

public CDEventTaskRunStarted(
String executionId, String executionUrl, String executionName, String spinnakerUrl) {
String executionId,
String executionUrl,
String executionName,
String spinnakerUrl,
Object customData) {
super(spinnakerUrl, executionId, spinnakerUrl, executionUrl);
this.subjectTaskName = executionName;
this.subjectPipelineRunId = executionId;
this.customData = customData;
}

@Override
public CloudEvent createCDEvent() {
TaskRunStartedCDEvent cdEvent = new TaskRunStartedCDEvent();
TaskrunStartedCDEvent cdEvent = new TaskrunStartedCDEvent();
cdEvent.setSource(URI.create(getSource()));

cdEvent.setSubjectId(getSubjectId());
cdEvent.setSubjectSource(URI.create(getSubjectSource()));
cdEvent.setSubjectTaskName(getSubjectTaskName());
cdEvent.setSubjectUrl(URI.create(getSubjectUrl()));
cdEvent.setSubjectUrl(URI.create(getSubjectUrl()).toString());
cdEvent.setSubjectPipelineRunId(getSubjectPipelineRunId());
cdEvent.setCustomData(customData);

return CDEvents.cdEventAsCloudEvent(cdEvent);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,24 +71,32 @@ public CloudEvent createCDEvent(
Optional.ofNullable(preference)
.map(p -> (String) p.get("cdEventsType"))
.orElseThrow(() -> new FieldNotFoundException("notifications.cdEventsType"));

Object customData =
Optional.ofNullable(event.content)
.map(e -> (Map) e.get("context"))
.map(e -> e.get("customData"))
.orElse(new Object());

log.info("Event type {} received to create CDEvent.", cdEventsType);
// This map will be updated to add more event types that Spinnaker needs to send
Map<String, BaseCDEvent> cdEventsMap =
Map.of(
CDEventTypes.PipelineRunQueuedEvent.getEventType(),
new CDEventPipelineRunQueued(
executionId, executionUrl, executionName, spinnakerUrl),
executionId, executionUrl, executionName, spinnakerUrl, customData),
CDEventTypes.PipelineRunStartedEvent.getEventType(),
new CDEventPipelineRunStarted(
executionId, executionUrl, executionName, spinnakerUrl),
executionId, executionUrl, executionName, spinnakerUrl, customData),
CDEventTypes.PipelineRunFinishedEvent.getEventType(),
new CDEventPipelineRunFinished(
executionId, executionUrl, executionName, spinnakerUrl, status),
executionId, executionUrl, executionName, spinnakerUrl, status, customData),
CDEventTypes.TaskRunStartedEvent.getEventType(),
new CDEventTaskRunStarted(executionId, executionUrl, executionName, spinnakerUrl),
new CDEventTaskRunStarted(
executionId, executionUrl, executionName, spinnakerUrl, customData),
CDEventTypes.TaskRunFinishedEvent.getEventType(),
new CDEventTaskRunFinished(
executionId, executionUrl, executionName, spinnakerUrl, status));
executionId, executionUrl, executionName, spinnakerUrl, status, customData));

BaseCDEvent cdEvent =
cdEventsMap.keySet().stream()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,18 @@
package com.netflix.spinnaker.echo.notification

import com.netflix.spinnaker.echo.api.events.Event
import com.netflix.spinnaker.echo.cdevents.CDEventTaskRunFinished
import com.netflix.spinnaker.echo.cdevents.CDEventsBuilderService
import com.netflix.spinnaker.echo.cdevents.CDEventsSenderService
import com.netflix.spinnaker.echo.model.trigger.CDEvent
import dev.cdevents.events.TaskrunFinishedCDEvent
import groovy.json.JsonSlurper
import io.cloudevents.CloudEvent
import spock.lang.Specification
import spock.lang.Subject
import spock.lang.Unroll
import spock.util.concurrent.BlockingVariable
import groovy.json.JsonSlurper

class CDEventsNotificationAgentSpec extends Specification {

Expand All @@ -49,11 +54,11 @@ class CDEventsNotificationAgentSpec extends Specification {

where:
cdEventsType || expectedType || status
"dev.cdevents.pipelinerun.queued" || /dev.cdevents.pipelinerun.queued.0.1.0/ || /starting/
"dev.cdevents.pipelinerun.started" || /dev.cdevents.pipelinerun.started.0.1.0/ || /started/
"dev.cdevents.pipelinerun.finished" || /dev.cdevents.pipelinerun.finished.0.1.0/ || /complete/
"dev.cdevents.taskrun.started" || /dev.cdevents.taskrun.started.0.1.0/ || /started/
"dev.cdevents.taskrun.finished" || /dev.cdevents.taskrun.finished.0.1.0/ || /complete/
"dev.cdevents.pipelinerun.queued" || /dev.cdevents.pipelinerun.queued.0.1.1/ || /starting/
"dev.cdevents.pipelinerun.started" || /dev.cdevents.pipelinerun.started.0.1.1/ || /started/
"dev.cdevents.pipelinerun.finished" || /dev.cdevents.pipelinerun.finished.0.1.1/ || /complete/
"dev.cdevents.taskrun.started" || /dev.cdevents.taskrun.started.0.1.1/ || /started/
"dev.cdevents.taskrun.finished" || /dev.cdevents.taskrun.finished.0.1.1/ || /complete/


brokerURL = "http://dev.cdevents.server/default/events-broker"
Expand All @@ -63,4 +68,45 @@ class CDEventsNotificationAgentSpec extends Specification {
])
type = "pipeline"
}

@Unroll
def "sends cdEvent with customData #customData"() {

given:
def cdevent = new BlockingVariable<CloudEvent>()
cdeventsSender.sendCDEvent(*_) >> { ceToSend, eventsBrokerURL ->
cdevent.set(ceToSend)
}

when:
agent.sendNotifications([address: brokerURL, cdEventsType: cdEventsType], application, event, [type: type, link: "link"], status)

then:
convertToMap(cdevent.get().getData().toBytes()).customData == customData
cdevent.get().getType() ==~ expectedType

where:
cdEventsType || expectedType || status || customData
"dev.cdevents.pipelinerun.queued" || /dev.cdevents.pipelinerun.queued.0.1.1/ || /starting/ || [foo: "pipelinerun.queued"]
"dev.cdevents.pipelinerun.started" || /dev.cdevents.pipelinerun.started.0.1.1/ || /started/ || [foo: "pipelinerun.started"]
"dev.cdevents.pipelinerun.finished" || /dev.cdevents.pipelinerun.finished.0.1.1/ || /complete/ || [foo: "pipelinerun.finished"]
"dev.cdevents.taskrun.started" || /dev.cdevents.taskrun.started.0.1.1/ || /started/ || [foo: "taskrun.started"]
"dev.cdevents.taskrun.finished" || /dev.cdevents.taskrun.finished.0.1.1/ || /complete/ || [foo: "taskrun.finished"]


brokerURL = "http://dev.cdevents.server/default/events-broker"
application = "whatever"
event = new Event(content: [
execution: [id: "1", name: "foo-pipeline"],
context: [customData: customData]
])
type = "pipeline"
}

def convertToMap(byte[] data) {
String jsonString = new String(data)
JsonSlurper jsonSlurper = new JsonSlurper()
def parsedData = jsonSlurper.parseText(jsonString)
return parsedData
}
}

0 comments on commit 01ada0c

Please sign in to comment.