diff --git a/pom.xml b/pom.xml index b9b9bc08..3f80b310 100644 --- a/pom.xml +++ b/pom.xml @@ -165,5 +165,10 @@ pipeline-build-step test + + org.jenkins-ci.plugins + pipeline-stage-step + test + diff --git a/src/main/java/org/jenkinsci/plugins/workflow/support/visualization/table/FlowGraphTable.java b/src/main/java/org/jenkinsci/plugins/workflow/support/visualization/table/FlowGraphTable.java index 1683b7ff..9496a4f1 100644 --- a/src/main/java/org/jenkinsci/plugins/workflow/support/visualization/table/FlowGraphTable.java +++ b/src/main/java/org/jenkinsci/plugins/workflow/support/visualization/table/FlowGraphTable.java @@ -21,6 +21,7 @@ import org.jenkinsci.plugins.workflow.graph.FlowNode; import org.jenkinsci.plugins.workflow.graph.StepNode; import org.jenkinsci.plugins.workflow.graphanalysis.DepthFirstScanner; +import org.jenkinsci.plugins.workflow.graphanalysis.LinearBlockHoppingScanner; import org.jenkinsci.plugins.workflow.visualization.table.FlowNodeViewColumn; import org.jenkinsci.plugins.workflow.visualization.table.FlowNodeViewColumnDescriptor; @@ -290,9 +291,9 @@ public String getDisplayName() { } else if (node instanceof StepNode && node instanceof BlockStartNode) { if (node.getAction(BodyInvocationAction.class) != null) { // TODO cannot access StepAtomNode.effectiveFunctionName from here - List parents = node.getParents(); - if (parents.size() == 1) { - FlowNode start = parents.get(0); + LinearBlockHoppingScanner scanner = new LinearBlockHoppingScanner(); + scanner.setup(node); + for (FlowNode start : scanner) { if (start instanceof StepNode && start instanceof BlockStartNode && start.getPersistentAction(BodyInvocationAction.class) == null) { String base = start.getDisplayFunctionName() + " block"; LabelAction a = node.getPersistentAction(LabelAction.class); diff --git a/src/test/java/org/jenkinsci/plugins/workflow/support/visualization/table/FlowGraphTableTest.java b/src/test/java/org/jenkinsci/plugins/workflow/support/visualization/table/FlowGraphTableTest.java index 87270e12..8afc7691 100644 --- a/src/test/java/org/jenkinsci/plugins/workflow/support/visualization/table/FlowGraphTableTest.java +++ b/src/test/java/org/jenkinsci/plugins/workflow/support/visualization/table/FlowGraphTableTest.java @@ -23,20 +23,22 @@ */ package org.jenkinsci.plugins.workflow.support.visualization.table; +import org.apache.commons.lang.StringUtils; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.arrayContaining; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; import org.jenkinsci.plugins.workflow.job.WorkflowJob; import org.jenkinsci.plugins.workflow.job.WorkflowRun; +import org.jenkinsci.plugins.workflow.test.steps.SemaphoreStep; +import static org.junit.Assert.fail; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.recipes.LocalData; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasSize; -import static org.junit.Assert.fail; - public class FlowGraphTableTest { @Rule @@ -95,4 +97,53 @@ public void corruptedFlowGraph() throws Exception { } } + @Test + public void rowDisplayName() throws Exception { + WorkflowJob p = r.createProject(WorkflowJob.class); + p.setDefinition(new CpsFlowDefinition( + "stage('start') {\n" + + " echo 'some message'\n" + + " def i = 0; retry(3) {\n" + + " if (++i < 3) error 'oops'\n" + + " node {\n" + + " isUnix()\n" + + " }\n" + + " }\n" + + "}\n" + + "stage('main') {\n" + + " parallel quick: {\n" + + " echo 'done'\n" + + " }, slow: {\n" + + " semaphore 'wait'\n" + + " }\n" + + "}", true)); + WorkflowRun b = p.scheduleBuild2(0).waitForStart(); + SemaphoreStep.waitForStart("wait/1", b); + FlowGraphTable t = new FlowGraphTable(b.getExecution()); + t.build(); + SemaphoreStep.success("wait/1", null); + r.waitForCompletion(b); + assertThat(t.getRows().stream().map(r -> StringUtils.repeat(" ", r.getTreeDepth()) + r.getDisplayName()).toArray(String[]::new), arrayContaining( + "Start of Pipeline", + " stage", + " stage block (start)", + " echo", + " retry", + " retry block", + " error", + " retry block", + " error", + " retry block", + " node", + " node block", + " isUnix", + " stage", + " stage block (main)", + " parallel", + " parallel block (Branch: quick)", + " echo", + " parallel block (Branch: slow)", + " semaphore")); + } + }