Skip to content

Commit

Permalink
Pull Request: Choose status which abort the flow build
Browse files Browse the repository at this point in the history
  • Loading branch information
ueberhammDesign committed Oct 20, 2015
1 parent ae2d74c commit 352ca26
Show file tree
Hide file tree
Showing 11 changed files with 417 additions and 9 deletions.
4 changes: 3 additions & 1 deletion src/main/groovy/com/cloudbees/plugins/flow/FlowDSL.groovy
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import java.util.logging.Logger

import static hudson.model.Result.FAILURE
import static hudson.model.Result.SUCCESS
import hudson.model.Result

public class FlowDSL {

Expand Down Expand Up @@ -201,7 +202,8 @@ public class FlowDelegate {
* Check flow status and stop if unexpected failure is detected
*/
private void statusCheck() {
if (flowRun.state.result.isWorseThan(SUCCESS)) {
if (flowRun.state.result.isWorseThan(Result.fromString(flowRun.getAbortWhenWorseThan()))) {
println("Abort execution, because one of the last builds is worse than " + flowRun.getAbortWhenWorseThan())
fail()
}
}
Expand Down
21 changes: 20 additions & 1 deletion src/main/java/com/cloudbees/plugins/flow/BuildFlow.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ public class BuildFlow extends Project<BuildFlow, FlowRun> implements TopLevelIt

private String dsl;
private String dslFile;

private String abortWhenWorseThan;
private boolean useAbortWhenWorseThan;
private boolean buildNeedsWorkspace;


Expand Down Expand Up @@ -97,11 +98,29 @@ public void setDslFile(String dslFile) {
this.dslFile = dslFile;
}

public String getAbortWhenWorseThan() {
return abortWhenWorseThan;
}

public void setAbortWhenWorseThan(String abortWhenWorseThan) {
this.abortWhenWorseThan = abortWhenWorseThan;
}

public boolean isUseAbortWhenWorseThan() {
return useAbortWhenWorseThan;
}

public void setUseAbortWhenWorseThan(boolean useAbortWhenWorseThan) {
this.useAbortWhenWorseThan = useAbortWhenWorseThan;
}

@Override
protected void submit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
super.submit(req, rsp);
JSONObject json = req.getSubmittedForm();
this.buildNeedsWorkspace = json.containsKey("buildNeedsWorkspace");
this.useAbortWhenWorseThan = json.containsKey("useAbortWhenWorseThan");
this.abortWhenWorseThan = (useAbortWhenWorseThan && json.containsKey("abortWhenWorseThan")) ? json.getString("abortWhenWorseThan") : "SUCCESS";
if (Jenkins.getInstance().hasPermission(Jenkins.RUN_SCRIPTS)) {
this.dsl = json.getString("dsl");
if (this.buildNeedsWorkspace) {
Expand Down
25 changes: 22 additions & 3 deletions src/main/java/com/cloudbees/plugins/flow/FlowRun.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,9 @@ public class FlowRun extends Build<BuildFlow, FlowRun> {

private String dsl;
private String dslFile;

private boolean buildNeedsWorkspace;
private boolean useAbortWhenWorseThan;
private String abortWhenWorseThan;

private JobInvocation.Start startJob;

Expand Down Expand Up @@ -91,6 +92,8 @@ private void setup(BuildFlow job) {
this.dsl = job.getDsl();
this.dslFile = job.getDslFile();
this.buildNeedsWorkspace = job.getBuildNeedsWorkspace();
this.useAbortWhenWorseThan = job.isUseAbortWhenWorseThan();
this.abortWhenWorseThan = (useAbortWhenWorseThan && job.getAbortWhenWorseThan() != null) ? job.getAbortWhenWorseThan() : SUCCESS.toString();
startJob.buildStarted(this);
jobsGraph.addVertex(startJob);
state.set(new FlowState(SUCCESS, startJob));
Expand All @@ -103,16 +106,28 @@ private void setup(BuildFlow job) {

/* package */ Run waitForCompletion(JobInvocation job) throws ExecutionException, InterruptedException {
job.waitForCompletion();
getState().setResult(job.getResult());
if(useCustomAbortAndStateResultIsBetterOrEqualJobResult(job)) {
getState().setResult(job.getResult());
} else if(!useAbortWhenWorseThan) {
getState().setResult(job.getResult());
}
return job.getBuild();
}

/* package */ Run waitForFinalization(JobInvocation job) throws ExecutionException, InterruptedException {
job.waitForFinalization();
getState().setResult(job.getResult());
if(useCustomAbortAndStateResultIsBetterOrEqualJobResult(job)) {
getState().setResult(job.getResult());
} else if(!useAbortWhenWorseThan) {
getState().setResult(job.getResult());
}
return job.getBuild();
}

private boolean useCustomAbortAndStateResultIsBetterOrEqualJobResult(JobInvocation job) throws ExecutionException, InterruptedException {
return useAbortWhenWorseThan && getState().getResult().isBetterOrEqualTo(job.getResult());
}

/* package */ FlowState getState() {
return state.get();
}
Expand Down Expand Up @@ -156,6 +171,10 @@ public void run() {
}
}

public String getAbortWhenWorseThan() {
return abortWhenWorseThan;
}

protected class BuildWithWorkspaceRunnerImpl extends AbstractRunner {

private final String dsl;
Expand Down
19 changes: 19 additions & 0 deletions src/main/resources/com/cloudbees/plugins/flow/BuildFlow/configure-entries.jelly
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,25 @@
<j:getStatic var="permission" className="hudson.model.Hudson" field="RUN_SCRIPTS"/>
<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" />
</f:entry>
<f:optionalBlock field="useAbortWhenWorseThan" title="${%Change sub build abort state}" checked="${instance.useAbortWhenWorseThan}">
<f:entry field="abortWhenWorseThan" title="${%Stop process, when sub build is worse than:}">
<j:getStatic var="permission" className="hudson.model.Hudson" field="RUN_SCRIPTS"/>
<select name="abortWhenWorseThan" readonly="${h.hasPermission(it,permission) ? null : 'readonly'}">
<j:choose>
<j:when test="${it.abortWhenWorseThan.equals('SUCCESS')}"><option value="SUCCESS" selected="selected">SUCCESS</option></j:when>
<j:otherwise><option value="SUCCESS">SUCCESS</option></j:otherwise>
</j:choose>
<j:choose>
<j:when test="${it.abortWhenWorseThan.equals('UNSTABLE')}"><option value="UNSTABLE" selected="selected">UNSTABLE</option></j:when>
<j:otherwise><option value="UNSTABLE">UNSTABLE</option></j:otherwise>
</j:choose>
<j:choose>
<j:when test="${it.abortWhenWorseThan.equals('FAILURE')}"><option value="FAILURE" selected="selected">FAILURE</option></j:when>
<j:otherwise><option value="FAILURE">FAILURE</option></j:otherwise>
</j:choose>
</select>
</f:entry>
</f:optionalBlock>
</f:section>

<p:config-publishers2 />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?jelly escape-by-default='true'?>
<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">
<div>
<div>
The order is SUCCESS &lt; UNSTABLE &lt; FAILURE &lt; ABORT
</div>
<j:forEach items="${app.getExtensionList('com.cloudbees.plugins.flow.BuildFlowDSLExtension')}" var="ext">
<st:include page="help-dsl" from="${ext}" optional="true"/>
</j:forEach>
</div>
</j:jelly>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?jelly escape-by-default='true'?>
<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">
<div>
<div>
Abort the build, when one single step in the build process is worse than your value.
</div>
<j:forEach items="${app.getExtensionList('com.cloudbees.plugins.flow.BuildFlowDSLExtension')}" var="ext">
<st:include page="help-dsl" from="${ext}" optional="true"/>
</j:forEach>
</div>
</j:jelly>
134 changes: 130 additions & 4 deletions src/test/groovy/com/cloudbees/plugins/flow/BuildTest.groovy
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -131,20 +131,146 @@ class BuildTest extends DSLTestCase {
println flow.jobsGraph.edgeSet()
}

public void testSequentialBuildsWithFailure() {
public void testSequentialBuildsExpectFailureWithDefaultSettings() {
def jobs = createJobs(["job1", "job2", "job3"])
def willFail = createFailJob("willFail")
def notRan = createJob("notRan")
def willNotRun = createJob("willNotRun")
def flow = run("""
build("job1")
build("job2")
build("job3")
build("willFail")
build("notRan")
build("willNotRun")
""")
assertAllSuccess(jobs)
assertFailure(willFail)
assertDidNotRun(willNotRun)
assert FAILURE == flow.result
println flow.jobsGraph.edgeSet()
}

public void testSequentialBuildsExpectUnstableWithDefaultSettings() {
def jobs = createJobs(["job1", "job2", "job3"])
def willBeUnstable = createUnstableJob("willBeUnstable")
def willNotRun = createJob("willNotRun")
def flow = run("""
build("job1")
build("job2")
build("job3")
build("willBeUnstable")
build("willNotRun")
""")
assertAllSuccess(jobs)
assertUnstable(willBeUnstable)
assertDidNotRun(willNotRun)
assert UNSTABLE == flow.result
println flow.jobsGraph.edgeSet()
}

public void testSequentialBuildsExpectUnstableWithSuccessSet() {
def jobs = createJobs(["job1", "job2", "job3"])
def willBeUnstable = createUnstableJob("willBeUnstable")
def willNotRun = createJob("willNotRun")
def flow = runWithAbortWhenWorseThan("""
build("job1")
build("job2")
build("job3")
build("willBeUnstable")
build("willNotRun")
""", SUCCESS)
assertAllSuccess(jobs)
assertUnstable(willBeUnstable)
assertDidNotRun(willNotRun)
assert UNSTABLE == flow.result
println flow.jobsGraph.edgeSet()
}

public void testSequentialBuildsExpectFailureWithSuccessSet() {
def jobs = createJobs(["job1", "job2", "job3"])
def willFail = createFailJob("willFail")
def willNotRun = createJob("willNotRun")
def flow = runWithAbortWhenWorseThan("""
build("job1")
build("job2")
build("job3")
build("willFail")
build("willNotRun")
""", SUCCESS)
assertAllSuccess(jobs)
assertFailure(willFail)
assertDidNotRun(willNotRun)
assert FAILURE == flow.result
println flow.jobsGraph.edgeSet()
}

public void testSequentialBuildsExpectUnstableWithUnstableSet() {
def jobs = createJobs(["job1", "job2", "job3"])
def willBeUnstable = createUnstableJob("willBeUnstable")
def willRun = createJob("willRun")
def flow = runWithAbortWhenWorseThan("""
build("job1")
build("job2")
build("job3")
build("willBeUnstable")
build("willRun")
""", UNSTABLE)
assertAllSuccess(jobs)
assertUnstable(willBeUnstable)
assertRan(willRun)
assert UNSTABLE == flow.result
println flow.jobsGraph.edgeSet()
}

public void testSequentialBuildsExpectFailureWithUnstableSet() {
def jobs = createJobs(["job1", "job2", "job3"])
def willFail = createFailJob("willFail")
def willNotRun = createJob("willNotRun")
def flow = runWithAbortWhenWorseThan("""
build("job1")
build("job2")
build("job3")
build("willFail")
build("willNotRun")
""", UNSTABLE)
assertAllSuccess(jobs)
assertFailure(willFail)
assertDidNotRun(willNotRun)
assert FAILURE == flow.result
println flow.jobsGraph.edgeSet()
}

public void testSequentialBuildsExpectUnstableWithFailureSet() {
def jobs = createJobs(["job1", "job2", "job3"])
def willBeUnstable = createUnstableJob("willBeUnstable")
def willRun = createJob("willRun")
def flow = runWithAbortWhenWorseThan("""
build("job1")
build("job2")
build("job3")
build("willBeUnstable")
build("willRun")
""", FAILURE)
assertAllSuccess(jobs)
assertUnstable(willBeUnstable)
assertRan(willRun)
assert UNSTABLE == flow.result
println flow.jobsGraph.edgeSet()
}

public void testSequentialBuildsExpectFailureWithFailureSet() {
def jobs = createJobs(["job1", "job2", "job3"])
def willFail = createFailJob("willFail")
def willRun = createJob("willRun")
def flow = runWithAbortWhenWorseThan("""
build("job1")
build("job2")
build("job3")
build("willFail")
build("willRun")
""", FAILURE)
assertAllSuccess(jobs)
assertFailure(willFail)
assertDidNotRun(notRan)
assertRan(willRun)
assert FAILURE == flow.result
println flow.jobsGraph.edgeSet()
}
Expand Down
12 changes: 12 additions & 0 deletions src/test/groovy/com/cloudbees/plugins/flow/DSLTestCase.groovy
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ abstract class DSLTestCase extends HudsonTestCase {
return flow.scheduleBuild2(0).get()
}

def runWithAbortWhenWorseThan = { script, abortWhenWorseThan ->
BuildFlow flow = new BuildFlow(Jenkins.instance, getName())
flow.dsl = script
flow.abortWhenWorseThan = abortWhenWorseThan.toString()
flow.useAbortWhenWorseThan = true
return flow.scheduleBuild2(0).get()
}

def runWithWorkspace = { script ->
BuildFlow flow = new BuildFlow(Jenkins.instance, getName())
flow.dsl = script
Expand Down Expand Up @@ -120,6 +128,10 @@ abstract class DSLTestCase extends HudsonTestCase {
assert 0 == job.builds.size()
}

def assertRan = { job ->
assert 0 < job.builds.size()
}

def assertAllSuccess = { jobs ->
jobs.each {
assertNotNull("job ${it.name} didn't run", it.builds.lastBuild)
Expand Down
Loading

0 comments on commit 352ca26

Please sign in to comment.