package hudson.plugins.parameterizedtrigger; import com.google.common.collect.ImmutableList; import hudson.Extension; import hudson.Launcher; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.Action; import hudson.model.BuildListener; import hudson.model.Cause.UpstreamCause; import hudson.model.Hudson; import hudson.model.Job; import hudson.model.Node; import hudson.model.Run; import jenkins.model.ParameterizedJobMixIn; import org.kohsuke.stapler.DataBoundConstructor; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.concurrent.Future; /** * {@link BuildTriggerConfig} that supports blocking of the execution. * @author Kohsuke Kawaguchi */ public class BlockableBuildTriggerConfig extends BuildTriggerConfig { private final BlockingBehaviour block; public boolean buildAllNodesWithLabel; public BlockableBuildTriggerConfig(String projects, BlockingBehaviour block, List<AbstractBuildParameters> configs) { super(projects, ResultCondition.ALWAYS, false, configs); this.block = block; } @DataBoundConstructor public BlockableBuildTriggerConfig(String projects, BlockingBehaviour block, List<AbstractBuildParameterFactory> configFactories,List<AbstractBuildParameters> configs) { super(projects, ResultCondition.ALWAYS, false, configFactories, configs); this.block = block; } public BlockingBehaviour getBlock() { return block; } @Override public List<Future<AbstractBuild>> perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { List<Future<AbstractBuild>> r = super.perform(build, launcher, listener); if (block==null) return Collections.emptyList(); return r; } @Override public ListMultimap<AbstractProject, Future<AbstractBuild>> perform2(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { ListMultimap<AbstractProject, Future<AbstractBuild>> futures = super.perform2(build, launcher, listener); if(block==null) return ArrayListMultimap.create(); return futures; } @Override public ListMultimap<Job, Future<Run>> perform3(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { ListMultimap<Job, Future<Run>> futures = super.perform3(build, launcher, listener); if(block==null) return ArrayListMultimap.create(); return futures; } @Override protected Future schedule(AbstractBuild<?, ?> build, Job project, List<Action> list) throws InterruptedException, IOException { if (block!=null) { while (true) { // add DifferentiatingAction to make sure this doesn't get merged with something else, // which is most likely unintended. Might make sense to do it at BuildTriggerConfig for all. list = ImmutableList.<Action>builder().addAll(list).add(new DifferentiatingAction()).build(); // if we fail to add the item to the queue, wait and retry. // it also means we have to force quiet period = 0, or else it'll never leave the queue Future f = schedule(build, project, 0, list); // When a project is disabled or the configuration is not yet saved f will always be null and we're caught in a loop, therefore we need to check for it if (f!=null || (f==null && !project.isBuildable())){ return f; } Thread.sleep(1000); } } else { return super.schedule(build,project,list); } } public Collection<Node> getNodes() { return Hudson.getInstance().getLabel("asrt").getNodes(); } @Extension public static class DescriptorImpl extends BuildTriggerConfig.DescriptorImpl { } }