Skip to content

Commit 1fec530

Browse files
stuartroweolamy
andauthored
Mark pipeline waitForBuild step with the downstream build result (#112)
* Add a WarningAction to the waitForBuild step flownode for unsuccessful builds * Log the result of the completed build * Only add WarningAction when propagate: true Update test * Fix spotbugs error NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE --------- Co-authored-by: Olivier Lamy <[email protected]>
1 parent 7df200b commit 1fec530

File tree

2 files changed

+65
-5
lines changed

2 files changed

+65
-5
lines changed

src/main/java/org/jenkinsci/plugins/workflow/support/steps/build/WaitForBuildListener.java

+19-3
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22

33
import edu.umd.cs.findbugs.annotations.NonNull;
44
import hudson.Extension;
5+
import hudson.console.ModelHyperlinkNote;
56
import hudson.model.Result;
67
import hudson.model.Run;
78
import hudson.model.TaskListener;
89
import hudson.model.listeners.RunListener;
910
import java.util.logging.Level;
1011
import java.util.logging.Logger;
12+
import org.jenkinsci.plugins.workflow.actions.WarningAction;
13+
import org.jenkinsci.plugins.workflow.graph.FlowNode;
1114
import org.jenkinsci.plugins.workflow.steps.FlowInterruptedException;
1215
import org.jenkinsci.plugins.workflow.steps.StepContext;
1316

@@ -21,11 +24,24 @@ public void onCompleted(Run<?,?> run, @NonNull TaskListener listener) {
2124
for (WaitForBuildAction action : run.getActions(WaitForBuildAction.class)) {
2225
StepContext context = action.context;
2326
LOGGER.log(Level.FINE, "completing {0} for {1}", new Object[] {run, context});
24-
if (!action.propagate || run.getResult() == Result.SUCCESS) {
27+
28+
Result result = run.getResult();
29+
if (result == null) { /* probably impossible */
30+
result = Result.FAILURE;
31+
}
32+
try {
33+
context.get(TaskListener.class).getLogger().println("Build " + ModelHyperlinkNote.encodeTo("/" + run.getUrl(), run.getFullDisplayName()) + " completed: " + result.toString());
34+
if (action.propagate && result.isWorseThan(Result.SUCCESS)) {
35+
context.get(FlowNode.class).addOrReplaceAction(new WarningAction(result));
36+
}
37+
} catch (Exception e) {
38+
LOGGER.log(Level.WARNING, null, e);
39+
}
40+
41+
if (!action.propagate || result == Result.SUCCESS) {
2542
context.onSuccess(new RunWrapper(run, false));
2643
} else {
27-
Result result = run.getResult();
28-
context.onFailure(new FlowInterruptedException(result != null ? result : /* probably impossible */ Result.FAILURE, false, new DownstreamFailureCause(run)));
44+
context.onFailure(new FlowInterruptedException(result, false, new DownstreamFailureCause(run)));
2945
}
3046
}
3147
run.removeActions(WaitForBuildAction.class);

src/test/java/org/jenkinsci/plugins/workflow/support/steps/build/WaitForBuildStepTest.java

+46-2
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,27 @@
66
import hudson.model.Run;
77
import hudson.tasks.Builder;
88
import hudson.util.DescribableList;
9+
import org.jenkinsci.plugins.workflow.actions.WarningAction;
910
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
11+
import org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode;
12+
import org.jenkinsci.plugins.workflow.flow.FlowExecution;
13+
import org.jenkinsci.plugins.workflow.graph.FlowGraphWalker;
14+
import org.jenkinsci.plugins.workflow.graph.FlowNode;
1015
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
16+
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
1117
import org.junit.ClassRule;
1218
import org.junit.Rule;
1319
import org.junit.Test;
1420
import org.jvnet.hudson.test.BuildWatcher;
1521
import org.jvnet.hudson.test.FailureBuilder;
16-
import org.jvnet.hudson.test.SleepBuilder;
17-
import org.jvnet.hudson.test.JenkinsRule;
22+
import org.jvnet.hudson.test.Issue;
1823
import org.jvnet.hudson.test.LoggerRule;
24+
import org.jvnet.hudson.test.JenkinsRule;
25+
import org.jvnet.hudson.test.SleepBuilder;
26+
import org.jvnet.hudson.test.UnstableBuilder;
1927

2028
import static org.junit.Assert.assertEquals;
29+
import static org.junit.Assert.assertNotNull;
2130

2231
public class WaitForBuildStepTest {
2332

@@ -63,4 +72,39 @@ public class WaitForBuildStepTest {
6372
us.setDefinition(new CpsFlowDefinition("waitForBuild runId: 'ds#1'", true));
6473
j.assertLogContains("is already complete", j.buildAndAssertSuccess(us));
6574
}
75+
76+
@Issue("JENKINS-70983")
77+
@Test public void waitForUnstableBuildWithWarningAction() throws Exception {
78+
FreeStyleProject ds = j.createFreeStyleProject("ds");
79+
DescribableList<Builder, Descriptor<Builder>> buildersList = ds.getBuildersList();
80+
buildersList.add(new SleepBuilder(500));
81+
buildersList.add(new UnstableBuilder());
82+
WorkflowJob us = j.jenkins.createProject(WorkflowJob.class, "us");
83+
us.setDefinition(new CpsFlowDefinition(
84+
"def ds = build job: 'ds', waitForStart: true\n" +
85+
"def dsRunId = \"${ds.getFullProjectName()}#${ds.getNumber()}\"\n" +
86+
"try {\n" +
87+
" waitForBuild runId: dsRunId, propagate: true\n" +
88+
"} finally {\n" +
89+
" echo \"'ds' completed with status ${ds.getResult()}\"\n" +
90+
"}", true));
91+
j.assertLogContains("'ds' completed with status UNSTABLE", j.buildAndAssertStatus(Result.UNSTABLE, us));
92+
WorkflowRun lastUpstreamRun = us.getLastBuild();
93+
FlowNode buildTriggerNode = findFirstNodeWithDescriptor(lastUpstreamRun.getExecution(), WaitForBuildStep.DescriptorImpl.class);
94+
WarningAction action = buildTriggerNode.getAction(WarningAction.class);
95+
assertNotNull(action);
96+
assertEquals(action.getResult(), Result.UNSTABLE);
97+
}
98+
99+
private static FlowNode findFirstNodeWithDescriptor(FlowExecution execution, Class<WaitForBuildStep.DescriptorImpl> cls) {
100+
for (FlowNode node : new FlowGraphWalker(execution)) {
101+
if (node instanceof StepAtomNode) {
102+
StepAtomNode stepAtomNode = (StepAtomNode) node;
103+
if (cls.isInstance(stepAtomNode.getDescriptor())) {
104+
return stepAtomNode;
105+
}
106+
}
107+
}
108+
return null;
109+
}
66110
}

0 commit comments

Comments
 (0)