Skip to content

Commit 01113dc

Browse files
rockleezLeemalin Moodleytimja
authored
Added support for paused status in stages that are waiting for input (#1068)
Co-authored-by: Leemalin Moodley <leemalin.moodley@aciworldwide.com> Co-authored-by: Tim Jacomb <timjacomb1@gmail.com> Co-authored-by: Tim Jacomb <timjacomb1+github@gmail.com>
1 parent 7330c62 commit 01113dc

File tree

4 files changed

+103
-1
lines changed

4 files changed

+103
-1
lines changed

src/main/frontend/common/components/status-icon.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,8 @@ export function resultToColor(result: Result, skeleton: boolean | undefined) {
252252
return "jenkins-!-accent-color";
253253
case "unstable":
254254
return "jenkins-!-warning-color";
255+
case "paused":
256+
return "jenkins-!-accent-color";
255257
default:
256258
return "jenkins-!-skipped-color";
257259
}

src/main/java/io/jenkins/plugins/pipelinegraphview/utils/PipelineGraphApi.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.jenkinsci.plugins.workflow.graph.FlowNode;
1212
import org.jenkinsci.plugins.workflow.graphanalysis.DepthFirstScanner;
1313
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
14+
import org.jenkinsci.plugins.workflow.support.steps.input.InputAction;
1415
import org.slf4j.Logger;
1516
import org.slf4j.LoggerFactory;
1617

@@ -67,6 +68,17 @@ private PipelineGraph createTree(PipelineGraphBuilderApi builder) {
6768
// these are completely new representations.
6869
List<PipelineStageInternal> stages = getPipelineNodes(builder);
6970

71+
// Get InputAction once for all stages
72+
InputAction inputAction = run.getAction(InputAction.class);
73+
74+
// Set the builder and inputAction on each stage so they can check for paused steps
75+
if (builder instanceof PipelineStepBuilderApi stepBuilder) {
76+
stages.forEach(stage -> {
77+
stage.setBuilder(stepBuilder);
78+
stage.setInputAction(inputAction);
79+
});
80+
}
81+
7082
// id => stage
7183
Map<String, PipelineStageInternal> stageMap = stages.stream()
7284
.collect(Collectors.toMap(

src/main/java/io/jenkins/plugins/pipelinegraphview/utils/PipelineStageInternal.java

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import io.jenkins.plugins.pipelinegraphview.analysis.TimingInfo;
55
import java.util.Collections;
66
import java.util.List;
7+
import org.jenkinsci.plugins.workflow.support.steps.input.InputAction;
78

89
class PipelineStageInternal {
910

@@ -19,6 +20,8 @@ class PipelineStageInternal {
1920
private boolean synthetic;
2021
private TimingInfo timingInfo;
2122
private String agent;
23+
private PipelineStepBuilderApi builder;
24+
private InputAction inputAction;
2225

2326
public PipelineStageInternal(
2427
String id,
@@ -113,12 +116,60 @@ public void setAgent(String aAgent) {
113116
this.agent = aAgent;
114117
}
115118

119+
public void setBuilder(PipelineStepBuilderApi builder) {
120+
this.builder = builder;
121+
}
122+
123+
public void setInputAction(InputAction inputAction) {
124+
this.inputAction = inputAction;
125+
}
126+
127+
/**
128+
* Checks if this stage or any of its children are waiting for input.
129+
* A stage is waiting for input if any of its steps have a non-null inputStep
130+
* and the step state is PAUSED.
131+
* Only performs the check if there is an InputAction attached to the WorkflowRun.
132+
*/
133+
private boolean isWaitingForInput(List<PipelineStage> children) {
134+
// Early exit if there's no InputAction on the run
135+
if (inputAction == null) {
136+
return false;
137+
}
138+
139+
// Check if any child stages are waiting for input
140+
if (children != null && !children.isEmpty()) {
141+
for (PipelineStage child : children) {
142+
if (child.state == PipelineState.PAUSED) {
143+
return true;
144+
}
145+
}
146+
}
147+
148+
// Check steps for this stage
149+
if (builder != null && id != null) {
150+
List<FlowNodeWrapper> steps = builder.getStageSteps(id);
151+
if (steps != null) {
152+
for (FlowNodeWrapper step : steps) {
153+
// Check if step has an input and is paused
154+
if (step.getInputStep() != null && step.getStatus().state == BlueRun.BlueRunState.PAUSED) {
155+
return true;
156+
}
157+
}
158+
}
159+
}
160+
161+
return false;
162+
}
163+
116164
public PipelineStage toPipelineStage(List<PipelineStage> children, String runUrl) {
165+
boolean waitingForInput = isWaitingForInput(children);
166+
PipelineState effectiveState = waitingForInput ? PipelineState.PAUSED : state;
167+
117168
return new PipelineStage(
118169
id,
119170
name,
120171
children,
121-
state,
172+
effectiveState,
122173
type.name(),
123174
title,
124175
seqContainerName,

src/test/java/io/jenkins/plugins/pipelinegraphview/utils/PipelineGraphApiTest.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.jenkins.plugins.pipelinegraphview.utils;
22

3+
import static org.awaitility.Awaitility.await;
34
import static org.hamcrest.MatcherAssert.assertThat;
45
import static org.hamcrest.Matchers.*;
56

@@ -532,4 +533,40 @@ void createTree_branchResult() throws Exception {
532533
"unstable-branch{unstable}",
533534
"]")));
534535
}
536+
537+
@Issue("GH#967")
538+
@Test
539+
void createTree_stageWithInputStepShowsAsPaused() throws Exception {
540+
WorkflowJob job = TestUtils.createJob(j, "pipelineWithInput", "input.jenkinsfile");
541+
QueueTaskFuture<WorkflowRun> futureRun = job.scheduleBuild2(0);
542+
WorkflowRun run = futureRun.waitForStart();
543+
544+
// Wait for the input action to be available and have executions
545+
org.jenkinsci.plugins.workflow.support.steps.input.InputAction inputAction = null;
546+
while (inputAction == null || inputAction.getExecutions().isEmpty()) {
547+
inputAction = run.getAction(org.jenkinsci.plugins.workflow.support.steps.input.InputAction.class);
548+
}
549+
550+
// Check the graph while paused on input
551+
PipelineGraphApi api = new PipelineGraphApi(run);
552+
553+
await().until(
554+
() -> {
555+
PipelineGraph graph = api.createTree();
556+
PipelineStage inputStage = graph.stages.stream()
557+
.filter(s -> s.name.equals("Input"))
558+
.findFirst()
559+
.orElse(null);
560+
return inputStage == null ? null : inputStage.state;
561+
},
562+
equalTo(PipelineState.PAUSED));
563+
564+
// Approve the input and wait for completion
565+
org.jenkinsci.plugins.workflow.support.steps.input.InputStepExecution execution =
566+
inputAction.getExecutions().get(0);
567+
execution.proceed(null);
568+
j.waitForCompletion(run);
569+
570+
assertThat(run.getResult(), equalTo(Result.SUCCESS));
571+
}
535572
}

0 commit comments

Comments
 (0)