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:
Nicolae Pascu 2018-03-29 16:50:15 +11:00 committed by GitHub
parent e2dda63edc
commit e7de3f1b8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 97 additions and 9 deletions

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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" +

View File

@ -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'
)
])
}
}
}