Skip to content

Commit

Permalink
Merge pull request #13 from fidelity-contributions/feature/use-cdeven…
Browse files Browse the repository at this point in the history
…ts-012

Use CDEvents SDK v0.1.2
  • Loading branch information
rorybakerfmr authored Mar 26, 2024
2 parents 5999e16 + 1dda2b4 commit 6412b91
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 122 deletions.
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ Early adopters and testers are welcome to try out the plugin and provide feedbac
```shell
mvn clean hpi:run
```

You may need to add `-Dhost=0.0.0.0` to the command if you are running Jenkins in a container or virtual machine.

3. To access your local instance, open a browser to http://localhost:8080/jenkins

Expand Down
12 changes: 6 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>4.61</version>
<version>4.78</version>
<relativePath/>
</parent>
<groupId>io.jenkins.plugins</groupId>
Expand Down Expand Up @@ -36,12 +36,12 @@
<!-- revision: Maps Jenkins plugin release to the cdevents SDK version in use. See VERSIONING.MD -->
<revision>1</revision>
<changelist>999999-SNAPSHOT</changelist>
<cdevents.version>v0.1.0-draft6</cdevents.version>
<cdevents.version>0.1.2</cdevents.version>
<gitHubRepo>jenkinsci/cdevents-plugin</gitHubRepo>
<!-- https://www.jenkins.io/doc/developer/plugin-development/choosing-jenkins-baseline/ -->
<!-- Baseline Jenkins version you use to build the plugin. Users must have this version or
newer to run. -->
<jenkins.version>2.375.4</jenkins.version>
<jenkins.version>2.401.3</jenkins.version>
<spotbugs.effort>Max</spotbugs.effort>
<spotbugs.threshold>Low</spotbugs.threshold>
</properties>
Expand All @@ -51,7 +51,7 @@
<dependency>
<groupId>io.jenkins.tools.bom</groupId>
<artifactId>bom-2.401.x</artifactId>
<version>2143.ve4c3c9ec790a</version>
<version>2745.vc7b_fe4c876fa_</version>
<type>pom</type>
<scope>import</scope>
</dependency>
Expand Down Expand Up @@ -81,12 +81,12 @@
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>aws-java-sdk</artifactId>
<version>1.12.447-382.vda_68e2007233</version>
<version>1.12.633-430.vf9a_e567a_244f</version>
<optional>true</optional>
</dependency>

<dependency>
<groupId>dev.cdevents.sdk-java</groupId>
<groupId>dev.cdevents</groupId>
<artifactId>cdevents-sdk-java</artifactId>
<version>${cdevents.version}</version>
<exclusions>
Expand Down
142 changes: 75 additions & 67 deletions src/main/java/io/jenkins/plugins/cdevents/BuildCDEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@

package io.jenkins.plugins.cdevents;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import dev.cdevents.CDEventTypes;
import dev.cdevents.CDEvents;
import dev.cdevents.constants.CDEventConstants;
import dev.cdevents.models.PipelineRun;
import dev.cdevents.events.*;
import hudson.model.Queue;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.TaskListener;
import io.cloudevents.CloudEvent;
import io.jenkins.plugins.cdevents.models.JobModel;
import io.jenkins.plugins.cdevents.models.QueuedJobModel;
import io.jenkins.plugins.cdevents.models.StageModel;
import io.jenkins.plugins.cdevents.util.ModelBuilder;
import io.jenkins.plugins.cdevents.util.OutcomeMapper;
import org.jenkinsci.plugins.workflow.actions.ErrorAction;
Expand All @@ -29,110 +30,117 @@ public class BuildCDEvent {

private static final Logger LOGGER = Logger.getLogger("BuildCDEvent");

private static final ObjectMapper objectMapper = new ObjectMapper();

public static String convertToJson(Object object) {
String convertedJson = "";
try {
convertedJson = objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
LOGGER.log(Level.WARNING,
"Failed to convert the build object into JSON with the following error " + e.getMessage());
e.printStackTrace();
}
return convertedJson;
}

public static CloudEvent buildPipelineRunStartedModel(Run run, TaskListener listener)
throws IOException, InterruptedException {
public static CloudEvent buildPipelineRunStartedModel(Run run,
TaskListener listener) throws IOException,
InterruptedException {
String pipelineFullName = run.getParent().getFullDisplayName();
Object pipelineData = ModelBuilder.buildJobModel(run.getParent(), run, listener);
JobModel pipelineData = ModelBuilder.buildJobModel(run.getParent(), run, listener);
LOGGER.log(Level.INFO, "Building PipelineRunStarted model for " + pipelineFullName);
return CDEventTypes.createPipelineRunStartedEvent(
CDEventConstants.CDEventTypes.PipelineRunStartedEvent.getEventType(), run.getId(),
URI.create(run.getParent().getUrl().replaceAll(pipelineFullName, "").replaceAll("//", "/")),
pipelineFullName, URI.create(run.getUrl()), convertToJson(pipelineData));

PipelineRunStartedCDEvent event = new PipelineRunStartedCDEvent();
event.setSubjectId(run.getId());
event.setSource(URI.create(run.getUrl()));
event.setSubjectPipelineName(pipelineFullName);
event.setSubjectUrl(URI.create(run.getUrl()));
event.setCustomData(pipelineData);
event.setCustomDataContentType("application/json");

return CDEvents.cdEventAsCloudEvent(event);
}

public static CloudEvent buildPipelineRunFinishedModel(Run run, TaskListener listener)
throws IOException, InterruptedException {
public static CloudEvent buildPipelineRunFinishedModel(Run run,
TaskListener listener) throws IOException,
InterruptedException {
String pipelineFullName = run.getParent().getFullDisplayName();
Object pipelineData = ModelBuilder.buildJobModel(run.getParent(), run, listener);
JobModel pipelineData = ModelBuilder.buildJobModel(run.getParent(), run, listener);
LOGGER.log(Level.INFO, "Building PipelineRunFinished model for " + pipelineFullName);

String errors;
CDEventConstants.Outcome outcome;
Result runResult = run.getResult();
if (runResult != null) {
outcome = OutcomeMapper
.mapResultToOutcome(runResult);
errors = outcome == CDEventConstants.Outcome.OutcomeSuccess ? ""
: run.getBuildStatusSummary().toString();
outcome = OutcomeMapper.mapResultToOutcome(runResult);
errors = outcome == CDEventConstants.Outcome.SUCCESS ? "" : run.getBuildStatusSummary().toString();
} else {
outcome = CDEventConstants.Outcome.OutcomeError;
outcome = CDEventConstants.Outcome.ERROR;
errors = "Run was not able to produce a result.";
}

return CDEventTypes.createPipelineRunFinishedEvent(
CDEventConstants.CDEventTypes.PipelineRunFinishedEvent.getEventType(), run.getId(),
URI.create(run.getParent().getUrl().replaceAll(pipelineFullName, "").replaceAll("//", "/")),
pipelineFullName, URI.create(run.getUrl()), outcome, errors, convertToJson(pipelineData));
PipelineRunFinishedCDEvent event = new PipelineRunFinishedCDEvent();

event.setSubjectId(run.getId());
event.setSource(URI.create(run.getUrl()));
event.setSubjectPipelineName(pipelineFullName);
event.setCustomData(pipelineData);
event.setCustomDataContentType("application/json");
event.setSubjectOutcome(outcome);
event.setSubjectErrors(errors);

return CDEvents.cdEventAsCloudEvent(event);
}

public static CloudEvent buildPipelineRunQueuedModel(Queue.WaitingItem item) {
String pipelineFullName = item.task.getFullDisplayName();
Object pipelineData = ModelBuilder.buildQueuedJobModel(item);
QueuedJobModel pipelineData = ModelBuilder.buildQueuedJobModel(item);
LOGGER.log(Level.INFO, "Building PipelineRunQueued model for " + pipelineFullName);
// String eventType, String id, URI source, String pipelineName, URI url, String
// pipelineRunData
return CDEventTypes.createPipelineRunQueuedEvent(
CDEventConstants.CDEventTypes.PipelineRunQueuedEvent.getEventType(), String.valueOf(item.getId()),
URI.create(item.task.getUrl()), pipelineFullName, URI.create(item.task.getUrl()),
convertToJson(pipelineData));

PipelineRunQueuedCDEvent event = new PipelineRunQueuedCDEvent();
event.setSubjectId(String.valueOf(item.getId()));
event.setSource(URI.create(item.task.getUrl()));
event.setSubjectPipelineName(pipelineFullName);
event.setCustomData(pipelineData);
event.setCustomDataContentType("application/json");

return CDEvents.cdEventAsCloudEvent(event);
}

public static CloudEvent buildTaskRunStartedModel(Run run, FlowNode node) {
String displayName = run.getParent().getFullDisplayName();
Object taskRunData = ModelBuilder.buildTaskModel(run, node);
StageModel taskRunData = ModelBuilder.buildTaskModel(run, node);
LOGGER.info("Building TaskRunStarted model for " + displayName);

return CDEventTypes.createTaskRunStartedEvent(
CDEventConstants.CDEventTypes.TaskRunStartedEvent.getEventType(),
run.getId(),
URI.create(run.getParent().getUrl().replaceAll(displayName, "").replaceAll("//", "/")),
displayName,
new PipelineRun(), // TODO - implement this
URI.create(run.getUrl()),
convertToJson(taskRunData));
TaskRunStartedCDEvent event = new TaskRunStartedCDEvent();

event.setSource(URI.create(run.getUrl()));
event.setSubjectId(run.getId());
event.setSubjectTaskName(displayName);
event.setSubjectPipelineRunId(run.getId());
event.setSubjectPipelineRunSource(URI.create(run.getUrl()));
event.setCustomData(taskRunData);
event.setCustomDataContentType("application/json");

return CDEvents.cdEventAsCloudEvent(event);
}

public static CloudEvent buildTaskRunFinishedModel(Run run, FlowNode node) {
String displayName = run.getParent().getFullDisplayName();
Object taskRunData = ModelBuilder.buildTaskModel(run, node);
StageModel taskRunData = ModelBuilder.buildTaskModel(run, node);

String errors;
CDEventConstants.Outcome outcome;
ErrorAction nodeError = node.getError();
if (nodeError != null) {
outcome = OutcomeMapper.mapResultToOutcome(nodeError);
errors = outcome == CDEventConstants.Outcome.OutcomeSuccess ? ""
: nodeError.getDisplayName();
errors = outcome == CDEventConstants.Outcome.SUCCESS ? "" : nodeError.getDisplayName();
} else {
outcome = CDEventConstants.Outcome.OutcomeError;
outcome = CDEventConstants.Outcome.ERROR;
errors = "Unable to get Display Name of the Node Error.";
}

LOGGER.info("Building TaskRunFinished model for " + displayName);

return CDEventTypes.createTaskRunFinishedEvent(
CDEventConstants.CDEventTypes.TaskRunFinishedEvent.getEventType(),
run.getId(),
URI.create(run.getParent().getUrl().replaceAll(displayName, "").replaceAll("//", "/")),
displayName,
new PipelineRun(), // TODO - implement this
URI.create(run.getUrl()),
outcome,
errors,
convertToJson(taskRunData));
TaskRunFinishedCDEvent event = new TaskRunFinishedCDEvent();
event.setSource(URI.create(run.getUrl()));
event.setSubjectId(run.getId());
event.setSubjectTaskName(displayName);
event.setSubjectPipelineRunId(run.getId());
event.setSubjectPipelineRunSource(URI.create(run.getUrl()));
event.setCustomData(taskRunData);
event.setCustomDataContentType("application/json");

event.setSubjectOutcome(outcome);
event.setSubjectErrors(errors);

return CDEvents.cdEventAsCloudEvent(event);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ public FormValidation doCheckKinesisRegion(@QueryParameter("kinesisRegion") Stri
return FormValidation.ok();
}

public FormValidation doCheckKinesisEndpoint(@QueryParameter("kinesisEndpoint") String kinesisEndpoint, @QueryParameter("kinesisRegion") String kinesisRegion) {
public FormValidation doCheckKinesisEndpoint(@QueryParameter("kinesisEndpoint") String kinesisEndpoint, @QueryParameter("kinesisRegion") String kinesisRegion) throws FormValidation {
if (!isNullOrEmpty(kinesisEndpoint) && isNullOrEmpty(kinesisRegion)) {
FormValidation.error("Kinesis requires a defined region for a custom endpoint");
throw FormValidation.error("Kinesis requires a defined region for a custom endpoint");
}
return FormValidation.ok();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
public class KinesisSink extends CDEventsSink {

public static final Logger LOGGER = Logger.getLogger(KinesisSink.class.getName());
public volatile static AmazonKinesis kinesis;
public volatile static String streamName;
public volatile static String region;
public volatile static String endpoint;
private volatile static AmazonKinesis kinesis;
private volatile static String streamName;
private volatile static String region;
private volatile static String endpoint;

public KinesisSink() {
if (Jenkins.get().getPlugin("aws-java-sdk") == null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,20 @@ public static CDEventConstants.Outcome mapResultToOutcome(Result result) {
switch (result.toString().toUpperCase()) {
case "SUCCESS":
case "UNSTABLE":
return CDEventConstants.Outcome.OutcomeSuccess;
return CDEventConstants.Outcome.SUCCESS;
case "NOT_BUILT":
case "ABORTED":
return CDEventConstants.Outcome.OutcomeFailure;
return CDEventConstants.Outcome.FAILURE;
default: // Jenkins status FAILURE and all others
return CDEventConstants.Outcome.OutcomeError;
return CDEventConstants.Outcome.ERROR;
}
}

public static CDEventConstants.Outcome mapResultToOutcome(ErrorAction error) {
if (error != null) {
return CDEventConstants.Outcome.OutcomeError;
return CDEventConstants.Outcome.ERROR;
} else {
return CDEventConstants.Outcome.OutcomeSuccess;
return CDEventConstants.Outcome.SUCCESS;
}
}
}
11 changes: 8 additions & 3 deletions src/test/java/io/jenkins/plugins/cdevents/BuildCDEvent.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.jenkins.plugins.cdevents;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import hudson.model.Job;
import hudson.model.Run;
import hudson.model.TaskListener;
Expand Down Expand Up @@ -52,14 +54,17 @@ void buildPipelineRunStartedModel() throws IOException, InterruptedException {
try (MockedStatic<ModelBuilder> modelBuilder = getMockedModelBuilder()) {
modelBuilder.when(() -> ModelBuilder.buildJobModel(job, run, taskListener)).thenReturn(new JobModel());
when(run.getParent().getFullDisplayName()).thenReturn("TestJob1");
when(run.getParent().getUrl()).thenReturn("http://localhost/job/1");
when(run.getUrl()).thenReturn("http://localhost/job/1/stage/1");
when(run.getId()).thenReturn("1");

CloudEvent cloudEvent = BuildCDEvent.buildPipelineRunStartedModel(run, taskListener);

assertEquals(Set.of("specversion", "id", "source", "time", "type"), cloudEvent.getAttributeNames());
assertEquals(Set.of("datacontenttype", "specversion", "id", "source", "time", "type"), cloudEvent.getAttributeNames());
assertEquals("dev.cdevents.pipelinerun.started.0.1.0", cloudEvent.getType());
assertEquals("TestJob1", cloudEvent.getExtension("pipelinename"));
// assert that the JSON string returned by cloudEvent.getData().toString() contains "pipelineName": "TestJob1" in its key-value pairs
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(cloudEvent.getData().toBytes());
assertEquals("TestJob1", jsonNode.get("subject").get("content").get("pipelineName").asText());
}
}
}
Loading

0 comments on commit 6412b91

Please sign in to comment.