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"));
+ }
+
}