forked from jenkinsci/junit-plugin
/
JUnitResultsStepExecution.java
129 lines (113 loc) · 5.22 KB
/
JUnitResultsStepExecution.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package hudson.tasks.junit.pipeline;
import hudson.FilePath;
import hudson.Launcher;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.tasks.junit.JUnitResultArchiver;
import hudson.tasks.junit.TestResult;
import hudson.tasks.junit.TestResultAction;
import hudson.tasks.junit.TestResultSummary;
import hudson.tasks.test.PipelineTestDetails;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import org.jenkinsci.plugins.workflow.actions.LabelAction;
import org.jenkinsci.plugins.workflow.actions.ThreadNameAction;
import org.jenkinsci.plugins.workflow.actions.WarningAction;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.graph.StepNode;
import org.jenkinsci.plugins.workflow.steps.StepContext;
import org.jenkinsci.plugins.workflow.steps.StepDescriptor;
import org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution;
public class JUnitResultsStepExecution extends SynchronousNonBlockingStepExecution<TestResultSummary> {
private transient final JUnitResultsStep step;
public JUnitResultsStepExecution(@Nonnull JUnitResultsStep step, StepContext context) {
super(context);
this.step = step;
}
@Override
protected TestResultSummary run() throws Exception {
FilePath workspace = getContext().get(FilePath.class);
workspace.mkdirs();
Run<?,?> run = getContext().get(Run.class);
TaskListener listener = getContext().get(TaskListener.class);
Launcher launcher = getContext().get(Launcher.class);
FlowNode node = getContext().get(FlowNode.class);
String nodeId = node.getId();
List<FlowNode> enclosingBlocks = getEnclosingStagesAndParallels(node);
PipelineTestDetails pipelineTestDetails = new PipelineTestDetails();
pipelineTestDetails.setNodeId(nodeId);
pipelineTestDetails.setEnclosingBlocks(getEnclosingBlockIds(enclosingBlocks));
pipelineTestDetails.setEnclosingBlockNames(getEnclosingBlockNames(enclosingBlocks));
try {
TestResultAction testResultAction = JUnitResultArchiver.parseAndAttach(step, pipelineTestDetails, run, workspace, launcher, listener);
if (testResultAction != null) {
TestResult testResult = testResultAction.getResult().getResultByNode(nodeId);
int testFailures = testResult.getFailCount();
if (testFailures > 0) {
node.addOrReplaceAction(new WarningAction(Result.UNSTABLE).withMessage(testFailures + " tests failed"));
run.setResult(Result.UNSTABLE);
}
return new TestResultSummary(testResult);
}
} catch (Exception e) {
listener.getLogger().println(e.getMessage());
throw e;
}
return new TestResultSummary();
}
/**
* Get the stage and parallel branch start node IDs (not the body nodes) for this node, innermost first.
* @param node A flownode.
* @return A nonnull, possibly empty list of stage/parallel branch start nodes, innermost first.
*/
@Nonnull
public static List<FlowNode> getEnclosingStagesAndParallels(FlowNode node) {
List<FlowNode> enclosingBlocks = new ArrayList<>();
for (FlowNode enclosing : node.getEnclosingBlocks()) {
if (enclosing != null && enclosing.getAction(LabelAction.class) != null) {
if (isStageNode(enclosing) ||
(enclosing.getAction(ThreadNameAction.class) != null)) {
enclosingBlocks.add(enclosing);
}
}
}
return enclosingBlocks;
}
private static boolean isStageNode(@Nonnull FlowNode node) {
if (node instanceof StepNode) {
StepDescriptor d = ((StepNode) node).getDescriptor();
return d != null && d.getFunctionName().equals("stage");
} else {
return false;
}
}
@Nonnull
public static List<String> getEnclosingBlockIds(@Nonnull List<FlowNode> nodes) {
List<String> ids = new ArrayList<>();
for (FlowNode n : nodes) {
ids.add(n.getId());
}
return ids;
}
@Nonnull
public static List<String> getEnclosingBlockNames(@Nonnull List<FlowNode> nodes) {
List<String> names = new ArrayList<>();
for (FlowNode n : nodes) {
ThreadNameAction threadNameAction = n.getPersistentAction(ThreadNameAction.class);
LabelAction labelAction = n.getPersistentAction(LabelAction.class);
if (threadNameAction != null) {
// If we're on a parallel branch with the same name as the previous (inner) node, that generally
// means we're in a Declarative parallel stages situation, so don't add the redundant branch name.
if (names.isEmpty() || !threadNameAction.getThreadName().equals(names.get(names.size()-1))) {
names.add(threadNameAction.getThreadName());
}
} else if (labelAction != null) {
names.add(labelAction.getDisplayName());
}
}
return names;
}
private static final long serialVersionUID = 1L;
}