package hudson.plugins.build_publisher; import hudson.Extension; import hudson.Launcher; import hudson.matrix.MatrixAggregatable; import hudson.matrix.MatrixAggregator; import hudson.matrix.MatrixBuild; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.BuildListener; import hudson.model.Descriptor; import hudson.model.Hudson; import hudson.model.Result; import hudson.tasks.BuildStepDescriptor; import hudson.tasks.BuildStepMonitor; import hudson.tasks.LogRotator; import hudson.tasks.Notifier; import hudson.tasks.Publisher; import org.kohsuke.stapler.StaplerRequest; import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Vector; import net.sf.json.JSONObject; /** * {@link Publisher} responsible for submitting build results to public Hudson * instance. * * @author dvrzalik@redhat.com * */ public class BuildPublisher extends Notifier implements MatrixAggregatable { private String serverName; private String notificationRecipients; private boolean publishUnstableBuilds; private boolean publishFailedBuilds; private List<BuildPublisherPostAction> postActions = new Vector<BuildPublisherPostAction>(); private LogRotator logRotator; private transient HudsonInstance publicHudsonInstance; @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { // don't send failed/unstable builds unless user wishes to do so if ((!publishUnstableBuilds && (Result.UNSTABLE == build.getResult())) || (!publishFailedBuilds && (Result.FAILURE == build .getResult()))) { return true; } //MatrixRun and MavenBuild can be published only after its parent build if(build.getProject().getParent() != Hudson.getInstance()) { return true; } publicHudsonInstance = BuildPublisher.DESCRIPTOR .getHudsonInstanceForName(getServerName()); if (publicHudsonInstance == null) { listener .getLogger() .println( "There is no public Hudson instance configured for this project"); return true; } listener.getLogger().println( "Build was marked for publishing on " + publicHudsonInstance.getUrl()); publicHudsonInstance.publishNewBuild(build); return true; } public MatrixAggregator createAggregator(final MatrixBuild matrixBuild, Launcher launcher, BuildListener listener) { // Publishing of a matrix project is a little bit tricky. When MatrixRun is published, // parent MatrixProject has to be already created on the public side. Since MatrixRuns // run independently (~ danger of collision) and it would be difficult to make the creation // operation atomic, only MatrixBuilds are allowed to do it. return new MatrixAggregator(matrixBuild, launcher, listener) { @Override public boolean endBuild() throws InterruptedException, IOException { return perform(matrixBuild, launcher, listener); } }; } /*---------------------------------*/ /* ----- Descriptor stuff -------- */ /*---------------------------------*/ @Override public BuildStepDescriptor<Publisher> getDescriptor() { return DESCRIPTOR; } @Extension public static final BuildPublisherDescriptor DESCRIPTOR = new BuildPublisherDescriptor(); public static final class BuildPublisherDescriptor extends BuildStepDescriptor<Publisher> { private HudsonInstance[] publicInstances = new HudsonInstance[0]; private boolean removeTriggers; protected BuildPublisherDescriptor() { super(BuildPublisher.class); load(); } @Override protected void convert(Map<String, Object> oldPropertyBag) { if (oldPropertyBag.containsKey("publicInstances")) publicInstances = (HudsonInstance[]) oldPropertyBag .get("publicInstances"); } @Override public String getDisplayName() { return "Publish build"; } public void setRemoveTriggers(boolean removeTriggers) { this.removeTriggers = removeTriggers; } public boolean getRemoveTriggers() { return removeTriggers; } @Override public Publisher newInstance(StaplerRequest req, JSONObject formData) throws FormException { //TODO post-actions BuildPublisher bp = new BuildPublisher(); req.bindParameters(bp, "bp."); if (req.getParameter("publicLogrotate") != null) { bp.logRotator = LogRotator.DESCRIPTOR.newInstance(req,formData); } else { bp.logRotator = null; } return bp; } @Override public boolean configure(StaplerRequest req, JSONObject formData) throws FormException { int i; String[] names = req.getParameterValues("bp.name"); String[] urls = req.getParameterValues("bp.url"); String[] logins = req.getParameterValues("bp.login"); String[] passwords = req.getParameterValues("bp.password"); int len; if (names != null && urls != null) len = Math.min(names.length, urls.length); else len = 0; HudsonInstance[] servers = new HudsonInstance[len]; for (i = 0; i < len; i++) { if (urls[i].length() == 0) { continue; } if (names[i].length() == 0) { names[i] = urls[i]; } servers[i] = new HudsonInstance(names[i], urls[i], logins[i], passwords[i]); } this.publicInstances = servers; req.bindParameters(this, "bp.server."); save(); return true; } public HudsonInstance[] getPublicInstances() { return publicInstances; } public HudsonInstance getHudsonInstanceForName(String name) { for (HudsonInstance server : publicInstances) { if (server.getName().equals(name)) { return server; } } return null; } @Override public boolean isApplicable(Class<? extends AbstractProject> jobType) { return true; } @Override public String getHelpFile() { return "/plugin/build-publisher/help/config/publish.html"; } } public String getServerName() { if(serverName==null) { // pick up the default instance HudsonInstance[] instances = DESCRIPTOR.getPublicInstances(); if((instances != null) && (instances.length==1)) return instances[0].getName(); } return serverName; } @Override public boolean needsToRunAfterFinalized() { return true; } @Override public BuildStepMonitor getRequiredMonitorService() { return BuildStepMonitor.BUILD; } public String getNotificationRecipients() { return notificationRecipients; } public void setNotificationRecipients(String notificationRecipients) { this.notificationRecipients = notificationRecipients; } public void setPublishUnstableBuilds(boolean publishUnstableBuilds) { this.publishUnstableBuilds = publishUnstableBuilds; } public void setPublishFailedBuilds(boolean publishFailedBuilds) { this.publishFailedBuilds = publishFailedBuilds; } public boolean isPublishUnstableBuilds() { return publishUnstableBuilds; } public boolean isPublishFailedBuilds() { return publishFailedBuilds; } public void setServerName(String name) { this.serverName = name; } public HudsonInstance getPublicHudsonInstance() { return BuildPublisher.DESCRIPTOR.getHudsonInstanceForName(getServerName()); //transient attribute, it's not sure, that is set-up, when called } public Map<Descriptor<BuildPublisherPostAction>,BuildPublisherPostAction> getPostActions() { return Descriptor.toMap(postActions); } public LogRotator getLogRotator() { return logRotator; } public void setLogRotator(LogRotator logRotator) { this.logRotator = logRotator; } }