package hudson.plugins.batch_task;
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.CauseAction;
import hudson.model.Hudson;
import hudson.model.Result;
import hudson.model.Run;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.Publisher;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Notifier;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.StaplerRequest;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
/**
* {@link Publisher} that triggers batch tasks of other projects.
*
* @author Kohsuke Kawaguchi
*/
public class BatchTaskInvoker extends Notifier {
/**
* What task to invoke?
*/
public static final class Config {
public final String project;
public final String task;
public Config(String project, String task) {
this.project = project;
this.task = task;
}
public Config(JSONObject source) {
this(source.getString("project").trim(), source.getString("task").trim());
}
/**
* Finds the target {@link BatchTaskProperty}.
*/
public BatchTaskProperty resolveProperty() {
AbstractProject<?,?> p = Hudson.getInstance().getItemByFullName(project, AbstractProject.class);
if(p==null) return null;
return p.getProperty(BatchTaskProperty.class);
}
/**
* Finds the target {@link BatchTask} that this configuration points to,
* or null if not found.
*/
public BatchTask resolve() {
BatchTaskProperty bp = resolveProperty();
if(bp==null) return null;
return bp.getTask(this.task);
}
public boolean invoke(AbstractBuild<?,?> build, BuildListener listener, HashSet<String> seenJobs) {
PrintStream logger = listener.getLogger();
AbstractProject<?,?> p = Hudson.getInstance().getItemByFullName(project, AbstractProject.class);
if(p==null) {
listener.error(Messages.BatchTaskInvoker_NoSuchProject(project));
return false;
}
BatchTaskProperty bp = p.getProperty(BatchTaskProperty.class);
if(bp==null) {
listener.error(Messages.BatchTaskInvoker_NoBatchTaskExists(task));
return false;
}
BatchTask taskObj = bp.getTask(task);
if(taskObj==null) {
listener.error(Messages.BatchTaskInvoker_NoSuchTask(task,bp.findNearestTask(task).name));
return false;
}
// Only report nextBuildNumber once per project
String buildNum = "";
if (!seenJobs.contains(project)) {
buildNum = " #" + taskObj.getNextBuildNumber();
seenJobs.add(project);
}
logger.println(Messages.BatchTaskInvoker_Invoking(project,task,buildNum));
Hudson.getInstance().getQueue().schedule(taskObj,0,
new CauseAction(new UpstreamCause((Run)build)));
return true;
}
}
private final Config[] configs;
private /*almost final*/ Result threshold;
private Object readResolve() {
if (threshold==null) threshold = Result.UNSTABLE;
return this;
}
public BatchTaskInvoker(Config[] configs, Result threshold) {
this.configs = configs;
this.threshold = threshold;
}
public BatchTaskInvoker(JSONObject source) {
List<Config> configList = new ArrayList<Config>();
for( Object o : JSONArray.fromObject(source.get("config")) )
configList.add(new Config((JSONObject)o));
this.configs = configList.toArray(new Config[configList.size()]);
this.threshold = source.getBoolean("evenIfUnstable") ? Result.UNSTABLE : Result.SUCCESS;
}
public List<Config> getConfigs() {
return Collections.unmodifiableList(Arrays.asList(configs));
}
public Result getThreshold() {
return threshold;
}
@Override
public boolean perform(AbstractBuild<?,?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
HashSet<String> seenJobs = new HashSet<String>();
if (build.getResult().isBetterOrEqualTo(threshold)) {
for (Config config : configs)
config.invoke(build, listener, seenJobs);
}
return true;
}
public BuildStepMonitor getRequiredMonitorService() {
return BuildStepMonitor.NONE;
}
@Override
public Collection<? extends Action> getProjectActions(AbstractProject<?, ?> project) {
return Collections.singletonList(new DownstreamTasksAction(this));
}
@Override
public BuildStepDescriptor<Publisher> getDescriptor() {
return DescriptorImpl.INSTANCE;
}
public static final class DescriptorImpl extends BuildStepDescriptor<Publisher> {
private DescriptorImpl() {
super(BatchTaskInvoker.class);
}
public String getDisplayName() {
return Messages.BatchTaskInvoker_DisplayName();
}
@Override
public BatchTaskInvoker newInstance(StaplerRequest req, JSONObject formData) throws FormException {
return new BatchTaskInvoker(formData);
}
@Override
public boolean isApplicable(Class<? extends AbstractProject> jobType) {
return true;
}
@Extension
public static final DescriptorImpl INSTANCE = new DescriptorImpl();
}
}