Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
package io.jenkins.plugins.pipelinegraphview.consoleview;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import hudson.Plugin;
import hudson.console.AnnotatedLargeText;
import hudson.model.Action;
import hudson.model.BallColor;
import hudson.model.Item;
import hudson.model.ParametersDefinitionProperty;
import hudson.model.Queue;
import hudson.model.Result;
import hudson.security.Permission;
import hudson.util.HttpResponses;
import io.jenkins.plugins.pipelinegraphview.Messages;
import io.jenkins.plugins.pipelinegraphview.PipelineGraphViewConfiguration;
import io.jenkins.plugins.pipelinegraphview.cards.RunDetailsCard;
import io.jenkins.plugins.pipelinegraphview.cards.RunDetailsItem;
Expand All @@ -14,7 +24,8 @@
import io.jenkins.plugins.pipelinegraphview.cards.items.TimingRunDetailsItems;
import io.jenkins.plugins.pipelinegraphview.cards.items.UpstreamCauseRunDetailsItem;
import io.jenkins.plugins.pipelinegraphview.cards.items.UserIdCauseRunDetailsItem;
import io.jenkins.plugins.pipelinegraphview.utils.AbstractPipelineViewAction;
import io.jenkins.plugins.pipelinegraphview.utils.PipelineGraph;
import io.jenkins.plugins.pipelinegraphview.utils.PipelineGraphApi;
import io.jenkins.plugins.pipelinegraphview.utils.PipelineNodeUtil;
import io.jenkins.plugins.pipelinegraphview.utils.PipelineStep;
import io.jenkins.plugins.pipelinegraphview.utils.PipelineStepApi;
Expand All @@ -23,32 +34,40 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutionException;
import jenkins.model.Jenkins;
import net.sf.json.JSONObject;
import org.jenkins.ui.icon.IconSpec;
import org.jenkinsci.plugins.pipeline.modeldefinition.actions.RestartDeclarativePipelineAction;
import org.jenkinsci.plugins.workflow.cps.replay.ReplayAction;
import org.jenkinsci.plugins.workflow.flow.FlowExecution;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.StaplerRequest2;
import org.kohsuke.stapler.StaplerResponse2;
import org.kohsuke.stapler.WebMethod;
import org.kohsuke.stapler.bind.JavaScriptMethod;
import org.kohsuke.stapler.interceptor.RequirePOST;
import org.kohsuke.stapler.verb.GET;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PipelineConsoleViewAction extends AbstractPipelineViewAction {
public class PipelineConsoleViewAction implements Action, IconSpec {
public static final long LOG_THRESHOLD = 150 * 1024; // 150KB
public static final String URL_NAME = "pipeline-overview";

private static final Logger logger = LoggerFactory.getLogger(PipelineConsoleViewAction.class);
private final WorkflowRun target;
private final PipelineStepApi stepApi;

private static final ObjectMapper MAPPER = new ObjectMapper();

private final transient PipelineGraphApi graphApi;
private final transient WorkflowRun run;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do these need to be transient? they were in the base but the PipelineStepApi isn't and the other copy of the field, target, wasn't originally

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as long as the action isn't persisted then no they don't need to be transient, should be fine to remove.

private final PipelineStepApi stepApi;

public PipelineConsoleViewAction(WorkflowRun target) {
super(target);
this.target = target;
this.stepApi = new PipelineStepApi(target);
this.run = target;
this.graphApi = new PipelineGraphApi(this.run);
this.stepApi = new PipelineStepApi(this.run);
}

@Override
Expand All @@ -61,23 +80,6 @@
return URL_NAME;
}

@Override
public String getIconClassName() {
return "symbol-git-network-outline plugin-ionicons-api";
}

public String getDurationString() {
return run.getDurationString();
}

public String getStartTimeString() {
return run.getTimestampString();
}

public String getUrl() {
return target.getUrl();
}

// Legacy - leave in case we want to update a sub section of steps (e.g. if a stage is still
// running).
@GET
Expand Down Expand Up @@ -110,8 +112,7 @@
return HttpResponses.okJSON(getAllSteps());
}

// Private method for testing.
protected JSONObject getAllSteps() throws IOException {
private JSONObject getAllSteps() throws IOException {
PipelineStepList steps = stepApi.getAllSteps();
String stepsJson = MAPPER.writeValueAsString(steps);
if (logger.isDebugEnabled()) {
Expand Down Expand Up @@ -204,7 +205,7 @@
}

protected JSONObject getConsoleOutputJson(String nodeId, Long requestStartByte) throws IOException {
Long startByte = 0L;
long startByte = 0L;
long endByte = 0L;
long textLength;
String text = "";
Expand Down Expand Up @@ -253,7 +254,7 @@
}

private AnnotatedLargeText<? extends FlowNode> getLogForNode(String nodeId) throws IOException {
FlowExecution execution = target.getExecution();
FlowExecution execution = run.getExecution();
if (execution != null) {
logger.debug("getLogForNode found execution.");
return PipelineNodeUtil.getLogText(execution.getNode(nodeId));
Expand All @@ -262,7 +263,7 @@
}

private String getNodeExceptionText(String nodeId) throws IOException {
FlowExecution execution = target.getExecution();
FlowExecution execution = run.getExecution();
if (execution != null) {
logger.debug("getNodeException found execution.");
return PipelineNodeUtil.getExceptionText(execution.getNode(nodeId));
Expand All @@ -271,7 +272,7 @@
}

private boolean isUnhandledException(String nodeId) throws IOException {
FlowExecution execution = target.getExecution();
FlowExecution execution = run.getExecution();
if (execution != null) {
return PipelineNodeUtil.isUnhandledException(execution.getNode(nodeId));
}
Expand Down Expand Up @@ -312,4 +313,146 @@
public boolean isShowGraphOnBuildPage() {
return PipelineGraphViewConfiguration.get().isShowGraphOnBuildPage();
}

public boolean isBuildable() {
return run.getParent().isBuildable();
}

public boolean isBuildInProgress() {
return run.isBuilding();
}

public Permission getPermission() {
return Item.BUILD;
}

public Permission getCancelPermission() {
return Item.CANCEL;
}

public Permission getConfigurePermission() {
return Item.CONFIGURE;
}

public String getBuildDisplayName() {
return run.getDisplayName();
}

public String getBuildFullDisplayName() {
return run.getFullDisplayName();
}

public boolean isRebuildAvailable() {
Plugin rebuildPlugin = Jenkins.get().getPlugin("rebuild");
if (rebuildPlugin != null && rebuildPlugin.getWrapper().isEnabled()) {

Check warning on line 347 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 347 is only partially covered, 2 branches are missing
// limit rebuild to parameterized jobs otherwise it duplicates rerun's behaviour
return run.getParent().getProperty(ParametersDefinitionProperty.class) != null;
}
return false;

Check warning on line 351 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 351 is not covered by tests
}

public boolean isRestartFromStageAvailable() {
RestartDeclarativePipelineAction action = run.getAction(RestartDeclarativePipelineAction.class);
if (action != null) {

Check warning on line 356 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 356 is only partially covered, one branch is missing
return action.isRestartEnabled();
}
return false;

Check warning on line 359 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 359 is not covered by tests
}

/**
* Handles the rerun request using ReplayAction feature
*/
@RequirePOST
@JavaScriptMethod
public boolean doRerun() throws IOException, ExecutionException {
if (run != null) {

Check warning on line 368 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 368 is only partially covered, one branch is missing
run.checkAnyPermission(Item.BUILD);
ReplayAction replayAction = run.getAction(ReplayAction.class);
Queue.Item item =
replayAction.run2(replayAction.getOriginalScript(), replayAction.getOriginalLoadedScripts());

if (item == null) {

Check warning on line 374 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 374 is only partially covered, one branch is missing
return false;

Check warning on line 375 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 375 is not covered by tests
}
return true;
}
return false;

Check warning on line 379 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 379 is not covered by tests
}

/**
* Handles the cancel request.
*/
@RequirePOST
@JavaScriptMethod
public HttpResponse doCancel() throws IOException, ExecutionException {
if (run != null) {

Check warning on line 388 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 388 is only partially covered, one branch is missing
run.checkPermission(getCancelPermission());
if (run.isBuilding()) {

Check warning on line 390 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 390 is only partially covered, one branch is missing
run.doStop();
return HttpResponses.okJSON();
} else {
String message = Result.ABORTED.equals(run.getResult())
? Messages.run_alreadyCancelled()
: Messages.run_isFinished();
return HttpResponses.errorJSON(message);
}
}
return HttpResponses.errorJSON("No run to cancel");

Check warning on line 400 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered lines

Lines 394-400 are not covered by tests
}

public String getFullProjectDisplayName() {
return run.getParent().getFullDisplayName();
}

private String getBuildNumber(WorkflowRun run) {
if (run != null) {

Check warning on line 408 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 408 is only partially covered, one branch is missing
return String.valueOf(run.getNumber());

Check warning on line 409 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 409 is not covered by tests
}
return null;
}

public String getBuildUrl() {
return run.getUrl();
}

public String getPreviousBuildNumber() {
return getBuildNumber(run.getPreviousBuild());
}

public String getPreviousBuildUrl() {
WorkflowRun previousBuild = run.getPreviousBuild();
return previousBuild == null ? null : previousBuild.getUrl();

Check warning on line 424 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 424 is only partially covered, one branch is missing
}

public String getNextBuildNumber() {
return getBuildNumber(run.getNextBuild());
}

@WebMethod(name = "tree")
public HttpResponse getTree() throws JsonProcessingException {
PipelineGraph tree = graphApi.createTree();
String graph = MAPPER.writeValueAsString(tree);
return HttpResponses.okJSON(JSONObject.fromObject(graph));
}

// Icon related methods these may appear as unused but are used by /lib/hudson/buildCaption.jelly
@SuppressWarnings("unused")
public String getUrl() {
return run.getUrl();
}

@SuppressWarnings("unused")
public BallColor getIconColor() {
return run.getIconColor();
}

@Override
public String getIconClassName() {
return "symbol-git-network-outline plugin-ionicons-api";
}

@Override
public String getIconFileName() {
return null;

Check warning on line 456 in src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 456 is not covered by tests
}
}
Loading