JENKINS-48884 Fix parallel stages not rendering properly if skipped by failed previous stage (#1702)
* fix stage statuses and steps in post directive if previous stage was skipped * Skipped stages are handled correctly hence changed assertions
This commit is contained in:
parent
e2dda63edc
commit
e7de3f1b8d
|
@ -96,13 +96,18 @@ public class PipelineNodeUtil {
|
|||
if(node == null){
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Action action : node.getActions()) {
|
||||
if (action instanceof TagsAction && ((TagsAction) action).getTagValue(StageStatus.TAG_NAME) != null) {
|
||||
TagsAction tagsAction = (TagsAction) action;
|
||||
String value = tagsAction.getTagValue(StageStatus.TAG_NAME);
|
||||
return value != null && value.equals(StageStatus.getSkippedForConditional());
|
||||
return value != null && (value.equals(StageStatus.getSkippedForConditional()) ||
|
||||
value.equals(StageStatus.getSkippedForFailure()) ||
|
||||
value.equals(StageStatus.getSkippedForUnstable())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ public class PipelineStepVisitor extends StandardChunkVisitor {
|
|||
|
||||
private FlowNode currentStage;
|
||||
|
||||
private ArrayDeque<String> stages = new ArrayDeque<>();
|
||||
private ArrayDeque<FlowNode> stages = new ArrayDeque<>();
|
||||
private InputAction inputAction;
|
||||
private StepEndNode closestEndNode;
|
||||
private StepStartNode agentNode = null;
|
||||
|
@ -94,7 +94,7 @@ public class PipelineStepVisitor extends StandardChunkVisitor {
|
|||
public void chunkStart(@Nonnull FlowNode startNode, @CheckForNull FlowNode beforeBlock, @Nonnull ForkScanner scanner) {
|
||||
super.chunkStart(startNode, beforeBlock, scanner);
|
||||
if(PipelineNodeUtil.isStage(startNode) && !PipelineNodeUtil.isSyntheticStage(startNode)){
|
||||
stages.push(startNode.getId());
|
||||
stages.push(startNode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,18 +217,18 @@ public class PipelineStepVisitor extends StandardChunkVisitor {
|
|||
if(PipelineNodeUtil.isSkippedStage(node)){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
String first=null;
|
||||
String last=null;
|
||||
FlowNode first=null;
|
||||
FlowNode last=null;
|
||||
if(!stages.isEmpty()) {
|
||||
first = stages.getFirst();
|
||||
last = stages.getLast();
|
||||
}
|
||||
|
||||
if(first!= null && node.getId().equals(first)){
|
||||
if(first!= null && node.equals(first)){
|
||||
s.addAll(preSteps);
|
||||
}
|
||||
s.addAll(steps);
|
||||
if(last!= null && node.getId().equals(last)){
|
||||
if(last!= null && (node.equals(last) || PipelineNodeUtil.isSkippedStage(last))){
|
||||
s.addAll(postSteps);
|
||||
}
|
||||
|
||||
|
|
|
@ -1769,10 +1769,10 @@ public class PipelineNodeTest extends PipelineBaseTest {
|
|||
Assert.assertEquals("FINISHED", nodes.get(0).get("state"));
|
||||
|
||||
Assert.assertEquals("NOT_BUILT",nodes.get(1).get("result"));
|
||||
Assert.assertEquals("NOT_BUILT",nodes.get(1).get("state"));
|
||||
Assert.assertEquals("SKIPPED",nodes.get(1).get("state"));
|
||||
|
||||
Assert.assertEquals("NOT_BUILT",nodes.get(2).get("result"));
|
||||
Assert.assertEquals("NOT_BUILT",nodes.get(2).get("state"));
|
||||
Assert.assertEquals("SKIPPED",nodes.get(2).get("state"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -2301,6 +2301,39 @@ public class PipelineNodeTest extends PipelineBaseTest {
|
|||
assertEquals("Wait for interactive input", steps.get(2).get("displayName"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Issue("JENKINS-48884")
|
||||
public void submitInputPostBlockWithParallelStages() throws Exception {
|
||||
WorkflowJob job = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
|
||||
URL resource = Resources.getResource(getClass(), "parallelStepsFromPost.jenkinsfile");
|
||||
String jenkinsFile = Resources.toString(resource, Charsets.UTF_8);
|
||||
job.setDefinition(new CpsFlowDefinition(jenkinsFile, true));
|
||||
QueueTaskFuture<WorkflowRun> buildTask = job.scheduleBuild2(0);
|
||||
WorkflowRun run = buildTask.getStartCondition().get();
|
||||
CpsFlowExecution e = (CpsFlowExecution) run.getExecutionPromise().get();
|
||||
|
||||
while (run.getAction(InputAction.class) == null) {
|
||||
e.waitForSuspension();
|
||||
}
|
||||
|
||||
List<Map> nodes = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/", List.class);
|
||||
|
||||
assertEquals(6, nodes.size());
|
||||
|
||||
List<Map> steps = get("/organizations/jenkins/pipelines/pipeline1/runs/1/nodes/"+nodes.get(0).get("id")+"/steps/", List.class);
|
||||
|
||||
assertEquals(4, steps.size());
|
||||
|
||||
assertEquals("15", steps.get(0).get("id"));
|
||||
assertEquals("exit 1", steps.get(0).get("displayDescription"));
|
||||
assertEquals("17", steps.get(1).get("id"));
|
||||
assertEquals("hello stable", steps.get(1).get("displayDescription"));
|
||||
assertEquals("47", steps.get(2).get("id"));
|
||||
assertEquals("Hello World from post", steps.get(2).get("displayDescription"));
|
||||
assertEquals("48", steps.get(3).get("id"));
|
||||
assertEquals("Wait for interactive input", steps.get(3).get("displayName"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pipelineLogError() throws Exception {
|
||||
String script = "def foo = null\n" +
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
pipeline {
|
||||
agent any
|
||||
stages {
|
||||
stage('First') {
|
||||
parallel {
|
||||
stage('Fail Step') {
|
||||
steps {
|
||||
bat 'exit 1'
|
||||
}
|
||||
}
|
||||
stage('Success Step') {
|
||||
steps {
|
||||
echo 'hello stable'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Second') {
|
||||
parallel {
|
||||
stage('Fail Step') {
|
||||
steps {
|
||||
bat 'exit 1'
|
||||
}
|
||||
}
|
||||
stage('Success Step') {
|
||||
steps {
|
||||
echo 'hello stable'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
post {
|
||||
always {
|
||||
echo 'Hello World from post'
|
||||
input(message: 'User input required', ok: 'Engage!', parameters: [
|
||||
string(name: 'STRING', description: 'String Param', defaultValue: 'Hello'),
|
||||
text(name: 'TEXT', description: 'Text Param', defaultValue: 'This is a\nmulti line string'),
|
||||
password(name: 'PASSWORD', description: 'Password Param', defaultValue: 'foo'),
|
||||
booleanParam(name: 'BOOLEAN', description: 'Boolean Param', defaultValue: false),
|
||||
choice(
|
||||
name: 'CHOICE',
|
||||
description: 'Choice Param',
|
||||
choices: 'master\ndevelop\nrelease-1.0\nrelease-2.0'
|
||||
)
|
||||
])
|
||||
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue