Skip to content

Commit 352ca26

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

File tree

11 files changed

+417
-9
lines changed

11 files changed

+417
-9
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 & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ public class BuildFlow extends Project<BuildFlow, FlowRun> implements TopLevelIt
6565

6666
private String dsl;
6767
private String dslFile;
68-
68+
private String abortWhenWorseThan;
69+
private boolean useAbortWhenWorseThan;
6970
private boolean buildNeedsWorkspace;
7071

7172

@@ -97,11 +98,29 @@ public void setDslFile(String dslFile) {
9798
this.dslFile = dslFile;
9899
}
99100

101+
public String getAbortWhenWorseThan() {
102+
return abortWhenWorseThan;
103+
}
104+
105+
public void setAbortWhenWorseThan(String abortWhenWorseThan) {
106+
this.abortWhenWorseThan = abortWhenWorseThan;
107+
}
108+
109+
public boolean isUseAbortWhenWorseThan() {
110+
return useAbortWhenWorseThan;
111+
}
112+
113+
public void setUseAbortWhenWorseThan(boolean useAbortWhenWorseThan) {
114+
this.useAbortWhenWorseThan = useAbortWhenWorseThan;
115+
}
116+
100117
@Override
101118
protected void submit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
102119
super.submit(req, rsp);
103120
JSONObject json = req.getSubmittedForm();
104121
this.buildNeedsWorkspace = json.containsKey("buildNeedsWorkspace");
122+
this.useAbortWhenWorseThan = json.containsKey("useAbortWhenWorseThan");
123+
this.abortWhenWorseThan = (useAbortWhenWorseThan && json.containsKey("abortWhenWorseThan")) ? json.getString("abortWhenWorseThan") : "SUCCESS";
105124
if (Jenkins.getInstance().hasPermission(Jenkins.RUN_SCRIPTS)) {
106125
this.dsl = json.getString("dsl");
107126
if (this.buildNeedsWorkspace) {

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

100644100755
Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,9 @@ public class FlowRun extends Build<BuildFlow, FlowRun> {
6060

6161
private String dsl;
6262
private String dslFile;
63-
6463
private boolean buildNeedsWorkspace;
64+
private boolean useAbortWhenWorseThan;
65+
private String abortWhenWorseThan;
6566

6667
private JobInvocation.Start startJob;
6768

@@ -91,6 +92,8 @@ private void setup(BuildFlow job) {
9192
this.dsl = job.getDsl();
9293
this.dslFile = job.getDslFile();
9394
this.buildNeedsWorkspace = job.getBuildNeedsWorkspace();
95+
this.useAbortWhenWorseThan = job.isUseAbortWhenWorseThan();
96+
this.abortWhenWorseThan = (useAbortWhenWorseThan && job.getAbortWhenWorseThan() != null) ? job.getAbortWhenWorseThan() : SUCCESS.toString();
9497
startJob.buildStarted(this);
9598
jobsGraph.addVertex(startJob);
9699
state.set(new FlowState(SUCCESS, startJob));
@@ -103,16 +106,28 @@ private void setup(BuildFlow job) {
103106

104107
/* package */ Run waitForCompletion(JobInvocation job) throws ExecutionException, InterruptedException {
105108
job.waitForCompletion();
106-
getState().setResult(job.getResult());
109+
if(useCustomAbortAndStateResultIsBetterOrEqualJobResult(job)) {
110+
getState().setResult(job.getResult());
111+
} else if(!useAbortWhenWorseThan) {
112+
getState().setResult(job.getResult());
113+
}
107114
return job.getBuild();
108115
}
109116

110117
/* package */ Run waitForFinalization(JobInvocation job) throws ExecutionException, InterruptedException {
111118
job.waitForFinalization();
112-
getState().setResult(job.getResult());
119+
if(useCustomAbortAndStateResultIsBetterOrEqualJobResult(job)) {
120+
getState().setResult(job.getResult());
121+
} else if(!useAbortWhenWorseThan) {
122+
getState().setResult(job.getResult());
123+
}
113124
return job.getBuild();
114125
}
115126

127+
private boolean useCustomAbortAndStateResultIsBetterOrEqualJobResult(JobInvocation job) throws ExecutionException, InterruptedException {
128+
return useAbortWhenWorseThan && getState().getResult().isBetterOrEqualTo(job.getResult());
129+
}
130+
116131
/* package */ FlowState getState() {
117132
return state.get();
118133
}
@@ -156,6 +171,10 @@ public void run() {
156171
}
157172
}
158173

174+
public String getAbortWhenWorseThan() {
175+
return abortWhenWorseThan;
176+
}
177+
159178
protected class BuildWithWorkspaceRunnerImpl extends AbstractRunner {
160179

161180
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 & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,20 +131,146 @@ class BuildTest extends DSLTestCase {
131131
println flow.jobsGraph.edgeSet()
132132
}
133133

134-
public void testSequentialBuildsWithFailure() {
134+
public void testSequentialBuildsExpectFailureWithDefaultSettings() {
135135
def jobs = createJobs(["job1", "job2", "job3"])
136136
def willFail = createFailJob("willFail")
137-
def notRan = createJob("notRan")
137+
def willNotRun = createJob("willNotRun")
138138
def flow = run("""
139139
build("job1")
140140
build("job2")
141141
build("job3")
142142
build("willFail")
143-
build("notRan")
143+
build("willNotRun")
144+
""")
145+
assertAllSuccess(jobs)
146+
assertFailure(willFail)
147+
assertDidNotRun(willNotRun)
148+
assert FAILURE == flow.result
149+
println flow.jobsGraph.edgeSet()
150+
}
151+
152+
public void testSequentialBuildsExpectUnstableWithDefaultSettings() {
153+
def jobs = createJobs(["job1", "job2", "job3"])
154+
def willBeUnstable = createUnstableJob("willBeUnstable")
155+
def willNotRun = createJob("willNotRun")
156+
def flow = run("""
157+
build("job1")
158+
build("job2")
159+
build("job3")
160+
build("willBeUnstable")
161+
build("willNotRun")
144162
""")
145163
assertAllSuccess(jobs)
164+
assertUnstable(willBeUnstable)
165+
assertDidNotRun(willNotRun)
166+
assert UNSTABLE == flow.result
167+
println flow.jobsGraph.edgeSet()
168+
}
169+
170+
public void testSequentialBuildsExpectUnstableWithSuccessSet() {
171+
def jobs = createJobs(["job1", "job2", "job3"])
172+
def willBeUnstable = createUnstableJob("willBeUnstable")
173+
def willNotRun = createJob("willNotRun")
174+
def flow = runWithAbortWhenWorseThan("""
175+
build("job1")
176+
build("job2")
177+
build("job3")
178+
build("willBeUnstable")
179+
build("willNotRun")
180+
""", SUCCESS)
181+
assertAllSuccess(jobs)
182+
assertUnstable(willBeUnstable)
183+
assertDidNotRun(willNotRun)
184+
assert UNSTABLE == flow.result
185+
println flow.jobsGraph.edgeSet()
186+
}
187+
188+
public void testSequentialBuildsExpectFailureWithSuccessSet() {
189+
def jobs = createJobs(["job1", "job2", "job3"])
190+
def willFail = createFailJob("willFail")
191+
def willNotRun = createJob("willNotRun")
192+
def flow = runWithAbortWhenWorseThan("""
193+
build("job1")
194+
build("job2")
195+
build("job3")
196+
build("willFail")
197+
build("willNotRun")
198+
""", SUCCESS)
199+
assertAllSuccess(jobs)
200+
assertFailure(willFail)
201+
assertDidNotRun(willNotRun)
202+
assert FAILURE == flow.result
203+
println flow.jobsGraph.edgeSet()
204+
}
205+
206+
public void testSequentialBuildsExpectUnstableWithUnstableSet() {
207+
def jobs = createJobs(["job1", "job2", "job3"])
208+
def willBeUnstable = createUnstableJob("willBeUnstable")
209+
def willRun = createJob("willRun")
210+
def flow = runWithAbortWhenWorseThan("""
211+
build("job1")
212+
build("job2")
213+
build("job3")
214+
build("willBeUnstable")
215+
build("willRun")
216+
""", UNSTABLE)
217+
assertAllSuccess(jobs)
218+
assertUnstable(willBeUnstable)
219+
assertRan(willRun)
220+
assert UNSTABLE == flow.result
221+
println flow.jobsGraph.edgeSet()
222+
}
223+
224+
public void testSequentialBuildsExpectFailureWithUnstableSet() {
225+
def jobs = createJobs(["job1", "job2", "job3"])
226+
def willFail = createFailJob("willFail")
227+
def willNotRun = createJob("willNotRun")
228+
def flow = runWithAbortWhenWorseThan("""
229+
build("job1")
230+
build("job2")
231+
build("job3")
232+
build("willFail")
233+
build("willNotRun")
234+
""", UNSTABLE)
235+
assertAllSuccess(jobs)
236+
assertFailure(willFail)
237+
assertDidNotRun(willNotRun)
238+
assert FAILURE == flow.result
239+
println flow.jobsGraph.edgeSet()
240+
}
241+
242+
public void testSequentialBuildsExpectUnstableWithFailureSet() {
243+
def jobs = createJobs(["job1", "job2", "job3"])
244+
def willBeUnstable = createUnstableJob("willBeUnstable")
245+
def willRun = createJob("willRun")
246+
def flow = runWithAbortWhenWorseThan("""
247+
build("job1")
248+
build("job2")
249+
build("job3")
250+
build("willBeUnstable")
251+
build("willRun")
252+
""", FAILURE)
253+
assertAllSuccess(jobs)
254+
assertUnstable(willBeUnstable)
255+
assertRan(willRun)
256+
assert UNSTABLE == flow.result
257+
println flow.jobsGraph.edgeSet()
258+
}
259+
260+
public void testSequentialBuildsExpectFailureWithFailureSet() {
261+
def jobs = createJobs(["job1", "job2", "job3"])
262+
def willFail = createFailJob("willFail")
263+
def willRun = createJob("willRun")
264+
def flow = runWithAbortWhenWorseThan("""
265+
build("job1")
266+
build("job2")
267+
build("job3")
268+
build("willFail")
269+
build("willRun")
270+
""", FAILURE)
271+
assertAllSuccess(jobs)
146272
assertFailure(willFail)
147-
assertDidNotRun(notRan)
273+
assertRan(willRun)
148274
assert FAILURE == flow.result
149275
println flow.jobsGraph.edgeSet()
150276
}

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

100644100755
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ abstract class DSLTestCase extends HudsonTestCase {
9191
return flow.scheduleBuild2(0).get()
9292
}
9393

94+
def runWithAbortWhenWorseThan = { script, abortWhenWorseThan ->
95+
BuildFlow flow = new BuildFlow(Jenkins.instance, getName())
96+
flow.dsl = script
97+
flow.abortWhenWorseThan = abortWhenWorseThan.toString()
98+
flow.useAbortWhenWorseThan = true
99+
return flow.scheduleBuild2(0).get()
100+
}
101+
94102
def runWithWorkspace = { script ->
95103
BuildFlow flow = new BuildFlow(Jenkins.instance, getName())
96104
flow.dsl = script
@@ -120,6 +128,10 @@ abstract class DSLTestCase extends HudsonTestCase {
120128
assert 0 == job.builds.size()
121129
}
122130

131+
def assertRan = { job ->
132+
assert 0 < job.builds.size()
133+
}
134+
123135
def assertAllSuccess = { jobs ->
124136
jobs.each {
125137
assertNotNull("job ${it.name} didn't run", it.builds.lastBuild)

0 commit comments

Comments
 (0)