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 13, 2015
1 parent ae2d74c commit bfcd047
Show file tree
Hide file tree
Showing 8 changed files with 246 additions and 42 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
30 changes: 20 additions & 10 deletions src/main/java/com/cloudbees/plugins/flow/BuildFlow.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,12 @@
import hudson.model.*;
import hudson.model.Descriptor.FormException;
import hudson.model.Queue.FlyweightTask;
import hudson.tasks.BuildStep;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Fingerprinter;
import hudson.tasks.Publisher;
import hudson.Util;
import hudson.util.AlternativeUiTextProvider;
import hudson.util.DescribableList;
import hudson.util.FormValidation;
import jenkins.model.Jenkins;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;

import javax.servlet.ServletException;

Expand All @@ -65,7 +56,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 +89,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
30 changes: 23 additions & 7 deletions src/main/java/com/cloudbees/plugins/flow/FlowRun.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

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

import hudson.model.Action;
import hudson.model.Build;
import hudson.model.BuildListener;
Expand All @@ -35,9 +35,6 @@

import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
Expand All @@ -60,8 +57,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 +89,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 +103,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 +168,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>
140 changes: 130 additions & 10 deletions src/test/groovy/com/cloudbees/plugins/flow/BuildTest.groovy
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,13 @@

package com.cloudbees.plugins.flow

import hudson.model.Result
import org.jvnet.hudson.test.Bug

import static hudson.model.Result.SUCCESS
import static hudson.model.Result.FAILURE
import jenkins.model.Jenkins
import hudson.model.Job
import hudson.model.Action
import hudson.model.ParametersAction
import hudson.model.ParameterValue
import hudson.model.StringParameterValue
import hudson.model.ParametersDefinitionProperty
import hudson.model.ParameterDefinition
import hudson.model.StringParameterDefinition
import hudson.model.FreeStyleProject

Expand Down Expand Up @@ -131,20 +125,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 = runWithAbortWhenWorseThanSuccess("""
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 testSequentialBuildsExpectFailureWithSuccessSet() {
def jobs = createJobs(["job1", "job2", "job3"])
def willFail = createFailJob("willFail")
def willNotRun = createJob("willNotRun")
def flow = runWithAbortWhenWorseThanSuccess("""
build("job1")
build("job2")
build("job3")
build("willFail")
build("willNotRun")
""")
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 = runWithAbortWhenWorseThanUnstable("""
build("job1")
build("job2")
build("job3")
build("willBeUnstable")
build("willRun")
""")
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 = runWithAbortWhenWorseThanUnstable("""
build("job1")
build("job2")
build("job3")
build("willFail")
build("willNotRun")
""")
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 = runWithAbortWhenWorseThanFailure("""
build("job1")
build("job2")
build("job3")
build("willBeUnstable")
build("willRun")
""")
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 = runWithAbortWhenWorseThanFailure("""
build("job1")
build("job2")
build("job3")
build("willFail")
build("willRun")
""")
assertAllSuccess(jobs)
assertFailure(willFail)
assertDidNotRun(notRan)
assertRan(willRun)
assert FAILURE == flow.result
println flow.jobsGraph.edgeSet()
}
Expand Down
Loading

0 comments on commit bfcd047

Please sign in to comment.