Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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,10 +1,7 @@
import { Result } from "../../../pipeline-graph-view/pipeline-graph/main/PipelineGraphModel";

// re-export Result so the relative path exists in one location.
export {
Result,
decodeResultValue,
} from "../../../pipeline-graph-view/pipeline-graph/main/PipelineGraphModel";
export { Result } from "../../../pipeline-graph-view/pipeline-graph/main/PipelineGraphModel";

export type {
StageInfo,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,7 @@ export enum Result {
aborted = "aborted",
not_built = "not_built", // May be pending, or job was ended before this point
skipped = "skipped", // excluded via pipeline "when" clause
unknown = "unknown", // bad data or client code needs updating for new values
}

export function decodeResultValue(resultMaybe: any): Result {
const lcase = String(resultMaybe).toLowerCase();

// TODO: validate this
if ((Object.values(Result) as any).includes(lcase)) {
return lcase as Result;
}

return Result.unknown;
unknown = "unknown", // bad data
}

// Dimensions used for layout, px
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from "react";
import { CSSProperties } from "react";

import {
decodeResultValue,
LayoutInfo,
NodeColumn,
NodeInfo,
Expand All @@ -10,7 +10,6 @@ import {
import StatusIcon, {
resultToColor,
} from "../../../../common/components/status-icon";
import { CSSProperties } from "react";

type SVGChildren = Array<any>; // Fixme: Maybe refine this? Not sure what should go here, we have working code I can't make typecheck

Expand Down Expand Up @@ -40,8 +39,6 @@ export function Node({ node }: NodeProps) {
}

const { title, state, url } = node.stage ?? {};
const resultClean = decodeResultValue(state);

groupChildren.push(
<StatusIcon
key={`icon-${node.id}`}
Expand All @@ -67,7 +64,7 @@ export function Node({ node }: NodeProps) {
} as CSSProperties,
className:
"PWGx-pipeline-node PWGx-pipeline-node--" +
resultClean +
state +
" " +
resultToColor(node.stage.state, node.stage.skeleton),
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package io.jenkins.plugins.pipelinegraphview.utils;

import java.util.Locale;
import org.jenkinsci.plugins.workflow.pipelinegraphanalysis.TimingInfo;

public class AbstractPipelineNode {
private String name;
private String state; // TODO enum
private PipelineState state;
private String type; // TODO enum
private String title;
private String id;
Expand All @@ -14,10 +13,10 @@ public class AbstractPipelineNode {
private TimingInfo timingInfo;

public AbstractPipelineNode(
String id, String name, String state, String type, String title, TimingInfo timingInfo) {
String id, String name, PipelineState state, String type, String title, TimingInfo timingInfo) {
this.id = id;
this.name = name;
this.state = state.toLowerCase(Locale.ROOT);
this.state = state;
this.type = type;
this.title = title;
this.timingInfo = timingInfo;
Expand Down Expand Up @@ -46,7 +45,7 @@ public String getName() {
return name;
}

public String getState() {
public PipelineState getState() {
return state;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,26 +50,19 @@

private List<PipelineStageInternal> getPipelineNodes(PipelineGraphBuilderApi builder) {
return builder.getPipelineNodes().stream()
.map(flowNodeWrapper -> {
String state =
flowNodeWrapper.getStatus().getResult().name().toLowerCase(Locale.ROOT);
if (flowNodeWrapper.getStatus().getState() != BlueRun.BlueRunState.FINISHED) {
state = flowNodeWrapper.getStatus().getState().name().toLowerCase(Locale.ROOT);
}
return new PipelineStageInternal(
flowNodeWrapper.getId(), // TODO no need to parse it BO returns a string even though the
// datatype is number on the frontend
flowNodeWrapper.getDisplayName(),
flowNodeWrapper.getParents().stream()
.map(FlowNodeWrapper::getId)
.collect(Collectors.toList()),
state,
flowNodeWrapper.getType().name(),
flowNodeWrapper.getDisplayName(), // TODO blue ocean uses timing information: "Passed in 0s"
flowNodeWrapper.isSynthetic(),
flowNodeWrapper.getTiming(),
getStageNode(flowNodeWrapper));
})
.map(flowNodeWrapper -> new PipelineStageInternal(
flowNodeWrapper.getId(), // TODO no need to parse it BO returns a string even though the

Check warning on line 54 in src/main/java/io/jenkins/plugins/pipelinegraphview/utils/PipelineGraphApi.java

View check run for this annotation

ci.jenkins.io / Open Tasks Scanner

TODO

NORMAL: no need to parse it BO returns a string even though the
// datatype is number on the frontend
flowNodeWrapper.getDisplayName(),
flowNodeWrapper.getParents().stream()
.map(FlowNodeWrapper::getId)
.collect(Collectors.toList()),
PipelineState.of(flowNodeWrapper.getStatus()),
flowNodeWrapper.getType().name(),
flowNodeWrapper.getDisplayName(), // TODO blue ocean uses timing information: "Passed in 0s"

Check warning on line 62 in src/main/java/io/jenkins/plugins/pipelinegraphview/utils/PipelineGraphApi.java

View check run for this annotation

ci.jenkins.io / Open Tasks Scanner

TODO

NORMAL: blue ocean uses timing information: "Passed in 0s"
flowNodeWrapper.isSynthetic(),
flowNodeWrapper.getTiming(),
getStageNode(flowNodeWrapper)))
.collect(Collectors.toList());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public PipelineStage(
String id,
String name,
List<PipelineStage> children,
String state,
PipelineState state,
String type,
String title,
String seqContainerName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@

import java.util.Collections;
import java.util.List;
import java.util.Locale;
import org.jenkinsci.plugins.workflow.pipelinegraphanalysis.TimingInfo;

public class PipelineStageInternal {
class PipelineStageInternal {

private String name;
private List<String> parents;
private String state; // TODO enum
private PipelineState state;
private String type; // TODO enum
private String title;
private String id;
Expand All @@ -24,7 +23,7 @@ public PipelineStageInternal(
String id,
String name,
List<String> parents,
String state,
PipelineState state,
String type,
String title,
boolean synthetic,
Expand All @@ -33,7 +32,7 @@ public PipelineStageInternal(
this.id = id;
this.name = name;
this.parents = parents;
this.state = state.toLowerCase(Locale.ROOT);
this.state = state;
this.type = type;
this.title = title;
this.synthetic = synthetic;
Expand All @@ -53,7 +52,7 @@ public void setSequential(boolean sequential) {
this.sequential = sequential;
}

public void setState(String state) {
public void setState(PipelineState state) {
this.state = state;
}

Expand Down Expand Up @@ -93,7 +92,7 @@ public List<String> getParents() {
return parents;
}

public String getState() {
public PipelineState getState() {
return state;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package io.jenkins.plugins.pipelinegraphview.utils;

import com.fasterxml.jackson.annotation.JsonValue;
import java.util.Locale;

public enum PipelineState {
// BlueRunState
QUEUED,
RUNNING,
PAUSED,
SKIPPED,
NOT_BUILT,
FINISHED,
// BlueRunResult
SUCCESS,
UNSTABLE,
FAILURE,
UNKNOWN,
ABORTED;

public static PipelineState of(NodeRunStatus status) {
if (status.getState() == BlueRun.BlueRunState.FINISHED) {
return switch (status.getResult()) {
case SUCCESS -> SUCCESS;
case UNSTABLE -> UNSTABLE;
case FAILURE -> FAILURE;
case NOT_BUILT -> NOT_BUILT;
case UNKNOWN -> UNKNOWN;
case ABORTED -> ABORTED;
};
}
return switch (status.getState()) {

Check warning on line 32 in src/main/java/io/jenkins/plugins/pipelinegraphview/utils/PipelineState.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 32 is only partially covered, one branch is missing
case QUEUED -> QUEUED;
case RUNNING -> RUNNING;
case PAUSED -> PAUSED;
case SKIPPED -> SKIPPED;
case NOT_BUILT -> NOT_BUILT;
case FINISHED -> FINISHED; // not reached but required for compiler

Check warning on line 38 in src/main/java/io/jenkins/plugins/pipelinegraphview/utils/PipelineState.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 38 is not covered by tests
};
}

@JsonValue
@Override
public String toString() {
return name().toLowerCase(Locale.ROOT);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,13 @@ public class PipelineStep extends AbstractPipelineNode {
private String stageId;

public PipelineStep(
String id, String name, String state, String type, String title, String stageId, TimingInfo timingInfo) {
String id,
String name,
PipelineState state,
String type,
String title,
String stageId,
TimingInfo timingInfo) {
super(id, name, state, type, title, timingInfo);
this.stageId = stageId;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import io.jenkins.plugins.pipelinegraphview.treescanner.PipelineNodeGraphAdapter;
import io.jenkins.plugins.pipelinegraphview.utils.legacy.PipelineStepVisitor;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
Expand All @@ -24,12 +23,6 @@
}
List<PipelineStep> steps = stepNodes.stream()
.map(flowNodeWrapper -> {
String state =
flowNodeWrapper.getStatus().getResult().name().toLowerCase(Locale.ROOT);
if (flowNodeWrapper.getStatus().getState() != BlueRun.BlueRunState.FINISHED) {
state = flowNodeWrapper.getStatus().getState().name().toLowerCase(Locale.ROOT);
}

String displayName = flowNodeWrapper.getDisplayName();
String title = "";
if (flowNodeWrapper.getType() == FlowNodeWrapper.NodeType.UNHANDLED_EXCEPTION) {
Expand All @@ -55,9 +48,9 @@
return new PipelineStep(
flowNodeWrapper.getId(),
displayName,
state,
PipelineState.of(flowNodeWrapper.getStatus()),
flowNodeWrapper.getType().name(),
title, // TODO blue ocean uses timing information: "Passed in

Check warning on line 53 in src/main/java/io/jenkins/plugins/pipelinegraphview/utils/PipelineStepApi.java

View check run for this annotation

ci.jenkins.io / Open Tasks Scanner

TODO

NORMAL: blue ocean uses timing information: "Passed in
// 0s"
stageId,
flowNodeWrapper.getTiming());
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package io.jenkins.plugins.pipelinegraphview.utils;

import static org.junit.jupiter.api.Assertions.assertEquals;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.MethodSource;

class PipelineStateTest {

@ParameterizedTest
@MethodSource("whenFinished")
void of_usesResultWhenStateIsFinished(BlueRun.BlueRunResult result, PipelineState expected) {
NodeRunStatus runStatus = new NodeRunStatus(result, BlueRun.BlueRunState.FINISHED);

PipelineState status = PipelineState.of(runStatus);

assertEquals(expected, status);
}

private static Stream<Arguments> whenFinished() {
return Stream.of(
Arguments.arguments(BlueRun.BlueRunResult.SUCCESS, PipelineState.SUCCESS),
Arguments.arguments(BlueRun.BlueRunResult.UNSTABLE, PipelineState.UNSTABLE),
Arguments.arguments(BlueRun.BlueRunResult.FAILURE, PipelineState.FAILURE),
Arguments.arguments(BlueRun.BlueRunResult.NOT_BUILT, PipelineState.NOT_BUILT),
Arguments.arguments(BlueRun.BlueRunResult.UNKNOWN, PipelineState.UNKNOWN),
Arguments.arguments(BlueRun.BlueRunResult.ABORTED, PipelineState.ABORTED));
}

@ParameterizedTest
@MethodSource("whenNotFinished")
void of_usesStateWhenStateIsNotFinished(BlueRun.BlueRunState state, PipelineState expected) {
NodeRunStatus runStatus = new NodeRunStatus(null, state);

PipelineState status = PipelineState.of(runStatus);

assertEquals(expected, status);
}

private static Stream<Arguments> whenNotFinished() {
return Stream.of(
Arguments.arguments(BlueRun.BlueRunState.QUEUED, PipelineState.QUEUED),
Arguments.arguments(BlueRun.BlueRunState.RUNNING, PipelineState.RUNNING),
Arguments.arguments(BlueRun.BlueRunState.PAUSED, PipelineState.PAUSED),
Arguments.arguments(BlueRun.BlueRunState.SKIPPED, PipelineState.SKIPPED),
Arguments.arguments(BlueRun.BlueRunState.NOT_BUILT, PipelineState.NOT_BUILT));
}

private static final ObjectMapper MAPPER = new ObjectMapper();

@ParameterizedTest
@CsvSource({
"QUEUED, queued",
"RUNNING, running",
"PAUSED, paused",
"SKIPPED, skipped",
"NOT_BUILT, not_built",
"FINISHED, finished",
"SUCCESS, success",
"UNSTABLE, unstable",
"FAILURE, failure",
"UNKNOWN, unknown",
"ABORTED, aborted"
})
void serialization(String input, String expected) throws JsonProcessingException {
PipelineState status = PipelineState.valueOf(input);

String serialized = MAPPER.writeValueAsString(status);

assertEquals("\"%s\"".formatted(expected), serialized);
}
}