Skip to content

Commit bfcd047

Browse files
Pull Request: Choose status which abort the flow build
1 parent ae2d74c commit bfcd047

File tree

8 files changed

+246
-42
lines changed

8 files changed

+246
-42
lines changed

src/main/groovy/com/cloudbees/plugins/flow/FlowDSL.groovy

100644100755
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import java.util.logging.Logger
4343

4444
import static hudson.model.Result.FAILURE
4545
import static hudson.model.Result.SUCCESS
46+
import hudson.model.Result
4647

4748
public class FlowDSL {
4849

@@ -201,7 +202,8 @@ public class FlowDelegate {
201202
* Check flow status and stop if unexpected failure is detected
202203
*/
203204
private void statusCheck() {
204-
if (flowRun.state.result.isWorseThan(SUCCESS)) {
205+
if (flowRun.state.result.isWorseThan(Result.fromString(flowRun.getAbortWhenWorseThan()))) {
206+
println("Abort execution, because one of the last builds is worse than " + flowRun.getAbortWhenWorseThan())
205207
fail()
206208
}
207209
}

src/main/java/com/cloudbees/plugins/flow/BuildFlow.java

100644100755
Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,12 @@
2828
import hudson.model.*;
2929
import hudson.model.Descriptor.FormException;
3030
import hudson.model.Queue.FlyweightTask;
31-
import hudson.tasks.BuildStep;
32-
import hudson.tasks.BuildStepDescriptor;
33-
import hudson.tasks.Fingerprinter;
34-
import hudson.tasks.Publisher;
3531
import hudson.Util;
3632
import hudson.util.AlternativeUiTextProvider;
37-
import hudson.util.DescribableList;
3833
import hudson.util.FormValidation;
3934
import jenkins.model.Jenkins;
4035

4136
import java.io.IOException;
42-
import java.util.List;
43-
import java.util.Map;
44-
import java.util.Set;
45-
import java.util.HashSet;
4637

4738
import javax.servlet.ServletException;
4839

@@ -65,7 +56,8 @@ public class BuildFlow extends Project<BuildFlow, FlowRun> implements TopLevelIt
6556

6657
private String dsl;
6758
private String dslFile;
68-
59+
private String abortWhenWorseThan;
60+
private boolean useAbortWhenWorseThan;
6961
private boolean buildNeedsWorkspace;
7062

7163

@@ -97,11 +89,29 @@ public void setDslFile(String dslFile) {
9789
this.dslFile = dslFile;
9890
}
9991

92+
public String getAbortWhenWorseThan() {
93+
return abortWhenWorseThan;
94+
}
95+
96+
public void setAbortWhenWorseThan(String abortWhenWorseThan) {
97+
this.abortWhenWorseThan = abortWhenWorseThan;
98+
}
99+
100+
public boolean isUseAbortWhenWorseThan() {
101+
return useAbortWhenWorseThan;
102+
}
103+
104+
public void setUseAbortWhenWorseThan(boolean useAbortWhenWorseThan) {
105+
this.useAbortWhenWorseThan = useAbortWhenWorseThan;
106+
}
107+
100108
@Override
101109
protected void submit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
102110
super.submit(req, rsp);
103111
JSONObject json = req.getSubmittedForm();
104112
this.buildNeedsWorkspace = json.containsKey("buildNeedsWorkspace");
113+
this.useAbortWhenWorseThan = json.containsKey("useAbortWhenWorseThan");
114+
this.abortWhenWorseThan = (useAbortWhenWorseThan && json.containsKey("abortWhenWorseThan")) ? json.getString("abortWhenWorseThan") : "SUCCESS";
105115
if (Jenkins.getInstance().hasPermission(Jenkins.RUN_SCRIPTS)) {
106116
this.dsl = json.getString("dsl");
107117
if (this.buildNeedsWorkspace) {

src/main/java/com/cloudbees/plugins/flow/FlowRun.java

100644100755
Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626

2727
import static hudson.model.Result.FAILURE;
2828
import static hudson.model.Result.SUCCESS;
29-
import hudson.Util;
29+
3030
import hudson.model.Action;
3131
import hudson.model.Build;
3232
import hudson.model.BuildListener;
@@ -35,9 +35,6 @@
3535

3636
import java.io.File;
3737
import java.io.IOException;
38-
import java.util.Collections;
39-
import java.util.Comparator;
40-
import java.util.LinkedList;
4138
import java.util.List;
4239
import java.util.concurrent.ExecutionException;
4340
import java.util.concurrent.atomic.AtomicInteger;
@@ -60,8 +57,9 @@ public class FlowRun extends Build<BuildFlow, FlowRun> {
6057

6158
private String dsl;
6259
private String dslFile;
63-
6460
private boolean buildNeedsWorkspace;
61+
private boolean useAbortWhenWorseThan;
62+
private String abortWhenWorseThan;
6563

6664
private JobInvocation.Start startJob;
6765

@@ -91,6 +89,8 @@ private void setup(BuildFlow job) {
9189
this.dsl = job.getDsl();
9290
this.dslFile = job.getDslFile();
9391
this.buildNeedsWorkspace = job.getBuildNeedsWorkspace();
92+
this.useAbortWhenWorseThan = job.isUseAbortWhenWorseThan();
93+
this.abortWhenWorseThan = (useAbortWhenWorseThan && job.getAbortWhenWorseThan() != null) ? job.getAbortWhenWorseThan() : SUCCESS.toString();
9494
startJob.buildStarted(this);
9595
jobsGraph.addVertex(startJob);
9696
state.set(new FlowState(SUCCESS, startJob));
@@ -103,16 +103,28 @@ private void setup(BuildFlow job) {
103103

104104
/* package */ Run waitForCompletion(JobInvocation job) throws ExecutionException, InterruptedException {
105105
job.waitForCompletion();
106-
getState().setResult(job.getResult());
106+
if(useCustomAbortAndStateResultIsBetterOrEqualJobResult(job)) {
107+
getState().setResult(job.getResult());
108+
} else if(!useAbortWhenWorseThan) {
109+
getState().setResult(job.getResult());
110+
}
107111
return job.getBuild();
108112
}
109113

110114
/* package */ Run waitForFinalization(JobInvocation job) throws ExecutionException, InterruptedException {
111115
job.waitForFinalization();
112-
getState().setResult(job.getResult());
116+
if(useCustomAbortAndStateResultIsBetterOrEqualJobResult(job)) {
117+
getState().setResult(job.getResult());
118+
} else if(!useAbortWhenWorseThan) {
119+
getState().setResult(job.getResult());
120+
}
113121
return job.getBuild();
114122
}
115123

124+
private boolean useCustomAbortAndStateResultIsBetterOrEqualJobResult(JobInvocation job) throws ExecutionException, InterruptedException {
125+
return useAbortWhenWorseThan && getState().getResult().isBetterOrEqualTo(job.getResult());
126+
}
127+
116128
/* package */ FlowState getState() {
117129
return state.get();
118130
}
@@ -156,6 +168,10 @@ public void run() {
156168
}
157169
}
158170

171+
public String getAbortWhenWorseThan() {
172+
return abortWhenWorseThan;
173+
}
174+
159175
protected class BuildWithWorkspaceRunnerImpl extends AbstractRunner {
160176

161177
private final String dsl;

src/main/resources/com/cloudbees/plugins/flow/BuildFlow/configure-entries.jelly

100644100755
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,25 @@
4242
<j:getStatic var="permission" className="hudson.model.Hudson" field="RUN_SCRIPTS"/>
4343
<f:textarea class="fixed-width" readonly="${h.hasPermission(it,permission) ? null : 'readonly'}" codemirror-mode="clike" codemirror-config="mode: 'text/x-groovy', lineNumbers: true, matchBrackets: true, onBlur: function(editor){editor.save()}" checkMethod="POST" />
4444
</f:entry>
45+
<f:optionalBlock field="useAbortWhenWorseThan" title="${%Change sub build abort state}" checked="${instance.useAbortWhenWorseThan}">
46+
<f:entry field="abortWhenWorseThan" title="${%Stop process, when sub build is worse than:}">
47+
<j:getStatic var="permission" className="hudson.model.Hudson" field="RUN_SCRIPTS"/>
48+
<select name="abortWhenWorseThan" readonly="${h.hasPermission(it,permission) ? null : 'readonly'}">
49+
<j:choose>
50+
<j:when test="${it.abortWhenWorseThan.equals('SUCCESS')}"><option value="SUCCESS" selected="selected">SUCCESS</option></j:when>
51+
<j:otherwise><option value="SUCCESS">SUCCESS</option></j:otherwise>
52+
</j:choose>
53+
<j:choose>
54+
<j:when test="${it.abortWhenWorseThan.equals('UNSTABLE')}"><option value="UNSTABLE" selected="selected">UNSTABLE</option></j:when>
55+
<j:otherwise><option value="UNSTABLE">UNSTABLE</option></j:otherwise>
56+
</j:choose>
57+
<j:choose>
58+
<j:when test="${it.abortWhenWorseThan.equals('FAILURE')}"><option value="FAILURE" selected="selected">FAILURE</option></j:when>
59+
<j:otherwise><option value="FAILURE">FAILURE</option></j:otherwise>
60+
</j:choose>
61+
</select>
62+
</f:entry>
63+
</f:optionalBlock>
4564
</f:section>
4665

4766
<p:config-publishers2 />
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?jelly escape-by-default='true'?>
2+
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt" xmlns:p="/lib/hudson/project">
3+
<div>
4+
<div>
5+
The order is SUCCESS &lt; UNSTABLE &lt; FAILURE &lt; ABORT
6+
</div>
7+
<j:forEach items="${app.getExtensionList('com.cloudbees.plugins.flow.BuildFlowDSLExtension')}" var="ext">
8+
<st:include page="help-dsl" from="${ext}" optional="true"/>
9+
</j:forEach>
10+
</div>
11+
</j:jelly>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?jelly escape-by-default='true'?>
2+
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form" xmlns:i="jelly:fmt" xmlns:p="/lib/hudson/project">
3+
<div>
4+
<div>
5+
Abort the build, when one single step in the build process is worse than your value.
6+
</div>
7+
<j:forEach items="${app.getExtensionList('com.cloudbees.plugins.flow.BuildFlowDSLExtension')}" var="ext">
8+
<st:include page="help-dsl" from="${ext}" optional="true"/>
9+
</j:forEach>
10+
</div>
11+
</j:jelly>

src/test/groovy/com/cloudbees/plugins/flow/BuildTest.groovy

100644100755
Lines changed: 130 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,13 @@
2525

2626
package com.cloudbees.plugins.flow
2727

28-
import hudson.model.Result
2928
import org.jvnet.hudson.test.Bug
3029

3130
import static hudson.model.Result.SUCCESS
3231
import static hudson.model.Result.FAILURE
3332
import jenkins.model.Jenkins
3433
import hudson.model.Job
35-
import hudson.model.Action
36-
import hudson.model.ParametersAction
37-
import hudson.model.ParameterValue
38-
import hudson.model.StringParameterValue
3934
import hudson.model.ParametersDefinitionProperty
40-
import hudson.model.ParameterDefinition
4135
import hudson.model.StringParameterDefinition
4236
import hudson.model.FreeStyleProject
4337

@@ -131,20 +125,146 @@ class BuildTest extends DSLTestCase {
131125
println flow.jobsGraph.edgeSet()
132126
}
133127

134-
public void testSequentialBuildsWithFailure() {
128+
public void testSequentialBuildsExpectFailureWithDefaultSettings() {
135129
def jobs = createJobs(["job1", "job2", "job3"])
136130
def willFail = createFailJob("willFail")
137-
def notRan = createJob("notRan")
131+
def willNotRun = createJob("willNotRun")
138132
def flow = run("""
139133
build("job1")
140134
build("job2")
141135
build("job3")
142136
build("willFail")
143-
build("notRan")
137+
build("willNotRun")
138+
""")
139+
assertAllSuccess(jobs)
140+
assertFailure(willFail)
141+
assertDidNotRun(willNotRun)
142+
assert FAILURE == flow.result
143+
println flow.jobsGraph.edgeSet()
144+
}
145+
146+
public void testSequentialBuildsExpectUnstableWithDefaultSettings() {
147+
def jobs = createJobs(["job1", "job2", "job3"])
148+
def willBeUnstable = createUnstableJob("willBeUnstable")
149+
def willNotRun = createJob("willNotRun")
150+
def flow = run("""
151+
build("job1")
152+
build("job2")
153+
build("job3")
154+
build("willBeUnstable")
155+
build("willNotRun")
156+
""")
157+
assertAllSuccess(jobs)
158+
assertUnstable(willBeUnstable)
159+
assertDidNotRun(willNotRun)
160+
assert UNSTABLE == flow.result
161+
println flow.jobsGraph.edgeSet()
162+
}
163+
164+
public void testSequentialBuildsExpectUnstableWithSuccessSet() {
165+
def jobs = createJobs(["job1", "job2", "job3"])
166+
def willBeUnstable = createUnstableJob("willBeUnstable")
167+
def willNotRun = createJob("willNotRun")
168+
def flow = runWithAbortWhenWorseThanSuccess("""
169+
build("job1")
170+
build("job2")
171+
build("job3")
172+
build("willBeUnstable")
173+
build("willNotRun")
174+
""")
175+
assertAllSuccess(jobs)
176+
assertUnstable(willBeUnstable)
177+
assertDidNotRun(willNotRun)
178+
assert UNSTABLE == flow.result
179+
println flow.jobsGraph.edgeSet()
180+
}
181+
182+
public void testSequentialBuildsExpectFailureWithSuccessSet() {
183+
def jobs = createJobs(["job1", "job2", "job3"])
184+
def willFail = createFailJob("willFail")
185+
def willNotRun = createJob("willNotRun")
186+
def flow = runWithAbortWhenWorseThanSuccess("""
187+
build("job1")
188+
build("job2")
189+
build("job3")
190+
build("willFail")
191+
build("willNotRun")
192+
""")
193+
assertAllSuccess(jobs)
194+
assertFailure(willFail)
195+
assertDidNotRun(willNotRun)
196+
assert FAILURE == flow.result
197+
println flow.jobsGraph.edgeSet()
198+
}
199+
200+
public void testSequentialBuildsExpectUnstableWithUnstableSet() {
201+
def jobs = createJobs(["job1", "job2", "job3"])
202+
def willBeUnstable = createUnstableJob("willBeUnstable")
203+
def willRun = createJob("willRun")
204+
def flow = runWithAbortWhenWorseThanUnstable("""
205+
build("job1")
206+
build("job2")
207+
build("job3")
208+
build("willBeUnstable")
209+
build("willRun")
210+
""")
211+
assertAllSuccess(jobs)
212+
assertUnstable(willBeUnstable)
213+
assertRan(willRun)
214+
assert UNSTABLE == flow.result
215+
println flow.jobsGraph.edgeSet()
216+
}
217+
218+
public void testSequentialBuildsExpectFailureWithUnstableSet() {
219+
def jobs = createJobs(["job1", "job2", "job3"])
220+
def willFail = createFailJob("willFail")
221+
def willNotRun = createJob("willNotRun")
222+
def flow = runWithAbortWhenWorseThanUnstable("""
223+
build("job1")
224+
build("job2")
225+
build("job3")
226+
build("willFail")
227+
build("willNotRun")
228+
""")
229+
assertAllSuccess(jobs)
230+
assertFailure(willFail)
231+
assertDidNotRun(willNotRun)
232+
assert FAILURE == flow.result
233+
println flow.jobsGraph.edgeSet()
234+
}
235+
236+
public void testSequentialBuildsExpectUnstableWithFailureSet() {
237+
def jobs = createJobs(["job1", "job2", "job3"])
238+
def willBeUnstable = createUnstableJob("willBeUnstable")
239+
def willRun = createJob("willRun")
240+
def flow = runWithAbortWhenWorseThanFailure("""
241+
build("job1")
242+
build("job2")
243+
build("job3")
244+
build("willBeUnstable")
245+
build("willRun")
246+
""")
247+
assertAllSuccess(jobs)
248+
assertUnstable(willBeUnstable)
249+
assertRan(willRun)
250+
assert UNSTABLE == flow.result
251+
println flow.jobsGraph.edgeSet()
252+
}
253+
254+
public void testSequentialBuildsExpectFailureWithFailureSet() {
255+
def jobs = createJobs(["job1", "job2", "job3"])
256+
def willFail = createFailJob("willFail")
257+
def willRun = createJob("willRun")
258+
def flow = runWithAbortWhenWorseThanFailure("""
259+
build("job1")
260+
build("job2")
261+
build("job3")
262+
build("willFail")
263+
build("willRun")
144264
""")
145265
assertAllSuccess(jobs)
146266
assertFailure(willFail)
147-
assertDidNotRun(notRan)
267+
assertRan(willRun)
148268
assert FAILURE == flow.result
149269
println flow.jobsGraph.edgeSet()
150270
}

0 commit comments

Comments
 (0)