Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Implement waitForBuild step * Add a 500ms sleep to 'ds' test job to make tests less flaky
- Loading branch information
1 parent
d08f550
commit a823138
Showing
10 changed files
with
270 additions
and
0 deletions.
There are no files selected for viewing
15 changes: 15 additions & 0 deletions
15
src/main/java/org/jenkinsci/plugins/workflow/support/steps/build/WaitForBuildAction.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package org.jenkinsci.plugins.workflow.support.steps.build; | ||
|
||
import hudson.model.InvisibleAction; | ||
import org.jenkinsci.plugins.workflow.steps.StepContext; | ||
|
||
public class WaitForBuildAction extends InvisibleAction { | ||
|
||
final StepContext context; | ||
final boolean propagate; | ||
|
||
WaitForBuildAction(StepContext context, boolean propagate) { | ||
this.context = context; | ||
this.propagate = propagate; | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
src/main/java/org/jenkinsci/plugins/workflow/support/steps/build/WaitForBuildListener.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package org.jenkinsci.plugins.workflow.support.steps.build; | ||
|
||
import edu.umd.cs.findbugs.annotations.NonNull; | ||
import hudson.Extension; | ||
import hudson.model.Result; | ||
import hudson.model.Run; | ||
import hudson.model.TaskListener; | ||
import hudson.model.listeners.RunListener; | ||
import java.util.logging.Level; | ||
import java.util.logging.Logger; | ||
import org.jenkinsci.plugins.workflow.steps.FlowInterruptedException; | ||
import org.jenkinsci.plugins.workflow.steps.StepContext; | ||
|
||
@Extension | ||
public class WaitForBuildListener extends RunListener<Run<?,?>> { | ||
|
||
private static final Logger LOGGER = Logger.getLogger(WaitForBuildListener.class.getName()); | ||
|
||
@Override | ||
public void onCompleted(Run<?,?> run, @NonNull TaskListener listener) { | ||
for (WaitForBuildAction action : run.getActions(WaitForBuildAction.class)) { | ||
StepContext context = action.context; | ||
LOGGER.log(Level.FINE, "completing {0} for {1}", new Object[] {run, context}); | ||
if (!action.propagate || run.getResult() == Result.SUCCESS) { | ||
context.onSuccess(new RunWrapper(run, false)); | ||
} else { | ||
Result result = run.getResult(); | ||
context.onFailure(new FlowInterruptedException(result != null ? result : /* probably impossible */ Result.FAILURE, false, new DownstreamFailureCause(run))); | ||
} | ||
} | ||
run.removeActions(WaitForBuildAction.class); | ||
} | ||
} |
83 changes: 83 additions & 0 deletions
83
src/main/java/org/jenkinsci/plugins/workflow/support/steps/build/WaitForBuildStep.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package org.jenkinsci.plugins.workflow.support.steps.build; | ||
|
||
import edu.umd.cs.findbugs.annotations.NonNull; | ||
import hudson.Extension; | ||
import hudson.model.ItemGroup; | ||
import hudson.model.Run; | ||
import hudson.model.TaskListener; | ||
import hudson.util.FormValidation; | ||
import java.util.Collections; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
import org.apache.commons.lang.StringUtils; | ||
import org.jenkinsci.plugins.workflow.graph.FlowNode; | ||
import org.jenkinsci.plugins.workflow.steps.Step; | ||
import org.jenkinsci.plugins.workflow.steps.StepContext; | ||
import org.jenkinsci.plugins.workflow.steps.StepDescriptor; | ||
import org.jenkinsci.plugins.workflow.steps.StepExecution; | ||
import org.kohsuke.stapler.AncestorInPath; | ||
import org.kohsuke.stapler.DataBoundConstructor; | ||
import org.kohsuke.stapler.DataBoundSetter; | ||
import org.kohsuke.stapler.QueryParameter; | ||
|
||
public class WaitForBuildStep extends Step { | ||
|
||
private final String runId; | ||
private boolean propagate = false; | ||
|
||
@DataBoundConstructor | ||
public WaitForBuildStep(String runId) { | ||
this.runId = runId; | ||
} | ||
|
||
public String getRunId() { | ||
return runId; | ||
} | ||
|
||
public boolean isPropagate() { | ||
return propagate; | ||
} | ||
|
||
@DataBoundSetter public void setPropagate(boolean propagate) { | ||
this.propagate = propagate; | ||
} | ||
|
||
@Override | ||
public StepExecution start(StepContext context) throws Exception { | ||
return new WaitForBuildStepExecution(this, context); | ||
} | ||
|
||
@Extension | ||
public static class DescriptorImpl extends StepDescriptor { | ||
|
||
@Override | ||
public String getFunctionName() { | ||
return "waitForBuild"; | ||
} | ||
|
||
@NonNull | ||
@Override | ||
public String getDisplayName() { | ||
return "Wait for build to complete"; | ||
} | ||
|
||
@Override | ||
public Set<? extends Class<?>> getRequiredContext() { | ||
Set<Class<?>> context = new HashSet<>(); | ||
Collections.addAll(context, FlowNode.class, Run.class, TaskListener.class); | ||
return Collections.unmodifiableSet(context); | ||
} | ||
} | ||
|
||
@SuppressWarnings("rawtypes") | ||
public FormValidation doCheckRunId(@AncestorInPath ItemGroup<?> context, @QueryParameter String value) { | ||
if (StringUtils.isBlank(value)) { | ||
return FormValidation.warning(Messages.WaitForBuildStep_no_run_configured()); | ||
} | ||
Run run = Run.fromExternalizableId(value); | ||
if (run == null) { | ||
return FormValidation.error(Messages.WaitForBuildStep_cannot_find(value)); | ||
} | ||
return FormValidation.ok(); | ||
} | ||
} |
43 changes: 43 additions & 0 deletions
43
...in/java/org/jenkinsci/plugins/workflow/support/steps/build/WaitForBuildStepExecution.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package org.jenkinsci.plugins.workflow.support.steps.build; | ||
|
||
import edu.umd.cs.findbugs.annotations.NonNull; | ||
import hudson.AbortException; | ||
import hudson.console.ModelHyperlinkNote; | ||
import hudson.model.Run; | ||
import hudson.model.TaskListener; | ||
import org.jenkinsci.plugins.workflow.steps.AbstractStepExecutionImpl; | ||
import org.jenkinsci.plugins.workflow.steps.StepContext; | ||
|
||
public class WaitForBuildStepExecution extends AbstractStepExecutionImpl { | ||
|
||
private static final long serialVersionUID = 1L; | ||
|
||
private final transient WaitForBuildStep step; | ||
|
||
public WaitForBuildStepExecution(WaitForBuildStep step, @NonNull StepContext context) { | ||
super(context); | ||
this.step = step; | ||
} | ||
|
||
@SuppressWarnings("rawtypes") | ||
@Override | ||
public boolean start() throws Exception { | ||
Run run = Run.fromExternalizableId(step.getRunId()); | ||
if (run == null) { | ||
throw new AbortException("No build exists with runId " + step.getRunId()); | ||
} | ||
|
||
String runHyperLink = ModelHyperlinkNote.encodeTo("/" + run.getUrl(), run.getFullDisplayName()); | ||
TaskListener taskListener = getContext().get(TaskListener.class); | ||
if (run.isBuilding()) { | ||
run.addAction(new WaitForBuildAction(getContext(), step.isPropagate())); | ||
taskListener.getLogger().println("Waiting for " + runHyperLink + " to complete"); | ||
return false; | ||
} else { | ||
taskListener.getLogger().println(runHyperLink + " is already complete"); | ||
getContext().onSuccess(null); | ||
return true; | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
...esources/org/jenkinsci/plugins/workflow/support/steps/build/WaitForBuildStep/config.jelly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
|
||
<?jelly escape-by-default='true'?> | ||
<j:jelly xmlns:j="jelly:core" xmlns:f="/lib/form" xmlns:st="jelly:stapler"> | ||
<f:entry field="runId" title="Build to wait on"> | ||
<f:textbox/> | ||
</f:entry> | ||
<f:entry field="propagate"> | ||
<f:checkbox default="false" title="Propagate errors"/> | ||
</f:entry> | ||
</j:jelly> |
6 changes: 6 additions & 0 deletions
6
...s/org/jenkinsci/plugins/workflow/support/steps/build/WaitForBuildStep/help-propagate.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<p> | ||
If enabled, then the result of this step is that of the downstream build being waited on (e.g., | ||
success, unstable, failure, not built, or aborted). | ||
If disabled (default state), then this step succeeds even if the downstream build is unstable, failed, etc.; | ||
use the <code>result</code> property of the return value as needed. | ||
</p> |
3 changes: 3 additions & 0 deletions
3
...urces/org/jenkinsci/plugins/workflow/support/steps/build/WaitForBuildStep/help-runId.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
<p> | ||
The externalizableId of the build to wait on. | ||
</p> |
8 changes: 8 additions & 0 deletions
8
...n/resources/org/jenkinsci/plugins/workflow/support/steps/build/WaitForBuildStep/help.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
<div> | ||
<p> | ||
Wait on a build to complete. | ||
</p> | ||
<p> | ||
Use the <a href="https://www.jenkins.io/redirect/pipeline-snippet-generator">Pipeline Snippet Generator</a> to generate a sample pipeline script for the waitforBuild step. | ||
</p> | ||
</div> |
66 changes: 66 additions & 0 deletions
66
src/test/java/org/jenkinsci/plugins/workflow/support/steps/build/WaitForBuildStepTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package org.jenkinsci.plugins.workflow.support.steps.build; | ||
|
||
import hudson.model.Descriptor; | ||
import hudson.model.FreeStyleProject; | ||
import hudson.model.Result; | ||
import hudson.model.Run; | ||
import hudson.tasks.Builder; | ||
import hudson.util.DescribableList; | ||
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition; | ||
import org.jenkinsci.plugins.workflow.job.WorkflowJob; | ||
import org.junit.ClassRule; | ||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.jvnet.hudson.test.BuildWatcher; | ||
import org.jvnet.hudson.test.FailureBuilder; | ||
import org.jvnet.hudson.test.SleepBuilder; | ||
import org.jvnet.hudson.test.JenkinsRule; | ||
import org.jvnet.hudson.test.LoggerRule; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
|
||
public class WaitForBuildStepTest { | ||
|
||
@ClassRule public static BuildWatcher buildWatcher = new BuildWatcher(); | ||
@Rule public JenkinsRule j = new JenkinsRule(); | ||
@Rule public LoggerRule logging = new LoggerRule(); | ||
|
||
@Test public void waitForBuild() throws Exception { | ||
FreeStyleProject ds = j.createFreeStyleProject("ds"); | ||
DescribableList<Builder, Descriptor<Builder>> buildersList = ds.getBuildersList(); | ||
buildersList.add(new SleepBuilder(500)); | ||
buildersList.add(new FailureBuilder()); | ||
WorkflowJob us = j.jenkins.createProject(WorkflowJob.class, "us"); | ||
us.setDefinition(new CpsFlowDefinition( | ||
"def ds = build job: 'ds', waitForStart: true\n" + | ||
"def dsRunId = \"${ds.getFullProjectName()}#${ds.getNumber()}\"\n" + | ||
"def completeDs = waitForBuild runId: dsRunId\n" + | ||
"echo \"'ds' completed with status ${completeDs.getResult()}\"", true)); | ||
j.assertLogContains("'ds' completed with status FAILURE", j.buildAndAssertSuccess(us)); | ||
} | ||
|
||
@Test public void waitForBuildPropagte() throws Exception { | ||
FreeStyleProject ds = j.createFreeStyleProject("ds"); | ||
DescribableList<Builder, Descriptor<Builder>> buildersList = ds.getBuildersList(); | ||
buildersList.add(new SleepBuilder(500)); | ||
buildersList.add(new FailureBuilder()); | ||
WorkflowJob us = j.jenkins.createProject(WorkflowJob.class, "us"); | ||
us.setDefinition(new CpsFlowDefinition( | ||
"def ds = build job: 'ds', waitForStart: true\n" + | ||
"def dsRunId = \"${ds.getFullProjectName()}#${ds.getNumber()}\"\n" + | ||
"waitForBuild runId: dsRunId, propagate: true", true)); | ||
j.assertLogContains("completed with status FAILURE", j.buildAndAssertStatus(Result.FAILURE, us)); | ||
} | ||
|
||
@SuppressWarnings("rawtypes") | ||
@Test public void waitForBuildAlreadyComplete() throws Exception { | ||
FreeStyleProject ds = j.createFreeStyleProject("ds"); | ||
ds.getBuildersList().add(new FailureBuilder()); | ||
Run ds1 = ds.scheduleBuild2(0).waitForStart(); | ||
assertEquals(1, ds1.getNumber()); | ||
j.waitForCompletion(ds1); | ||
WorkflowJob us = j.jenkins.createProject(WorkflowJob.class, "us"); | ||
us.setDefinition(new CpsFlowDefinition("waitForBuild runId: 'ds#1'", true)); | ||
j.assertLogContains("is already complete", j.buildAndAssertSuccess(us)); | ||
} | ||
} |