All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hudson.plugins.promoted_builds.conditions.DownstreamPassCondition Maven / Gradle / Ivy

There is a newer version: 1.11
Show newest version
package hudson.plugins.promoted_builds.conditions;

import hudson.CopyOnWrite;
import hudson.Extension;
import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Cause.UpstreamCause;
import hudson.model.Fingerprint;
import hudson.model.Fingerprint.BuildPtr;
import hudson.model.Hudson;
import hudson.model.InvisibleAction;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.model.listeners.RunListener;
import hudson.plugins.promoted_builds.JobPropertyImpl;
import hudson.plugins.promoted_builds.PromotionBadge;
import hudson.plugins.promoted_builds.PromotionCondition;
import hudson.plugins.promoted_builds.PromotionConditionDescriptor;
import hudson.plugins.promoted_builds.PromotionProcess;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.StaplerRequest;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * {@link PromotionCondition} that tests if certain downstream projects have passed.
 * 
 * @author Kohsuke Kawaguchi
 */
public class DownstreamPassCondition extends PromotionCondition {
    /**
     * List of downstream jobs that are used as the promotion criteria.
     * 
     * Every job has to have at least one successful build for us to promote a build.
     */
    private final String jobs;

    public DownstreamPassCondition(String jobs) {
        this.jobs = jobs;
    }

    public String getJobs() {
        return jobs;
    }

    @Override
    public PromotionBadge isMet(AbstractBuild build) {
        Badge badge = new Badge();

        PseudoDownstreamBuilds pdb = build.getAction(PseudoDownstreamBuilds.class);

        OUTER:
        for (AbstractProject j : getJobList()) {
            for( AbstractBuild b : build.getDownstreamBuilds(j) ) {
                if(b.getResult()== Result.SUCCESS) {
                    badge.add(b);
                    continue OUTER;
                }
            }

            if (pdb!=null) {// if fingerprint doesn't have any, try the pseudo-downstream
                for (AbstractBuild b : pdb.listBuilds(j)) {
                    if(b.getResult()== Result.SUCCESS) {
                        badge.add(b);
                        continue OUTER;
                    }
                }
            }

            // none of the builds of this job passed.
            return null;
        }
        
        return badge;
    }

    /**
     * List of downstream jobs that we need to monitor.
     *
     * @return never null.
     */
    public List> getJobList() {
        List> r = new ArrayList>();
        for (String name : Util.tokenize(jobs,",")) {
            AbstractProject job = Hudson.getInstance().getItemByFullName(name.trim(),AbstractProject.class);
            if(job!=null)   r.add(job);
        }
        return r;
    }

    /**
     * Short-cut for {@code getJobList().contains(job)}.
     */
    public boolean contains(AbstractProject job) {
        if(!jobs.contains(job.getFullName()))    return false;   // quick rejection test

        for (String name : Util.tokenize(jobs,",")) {
            if(name.trim().equals(job.getFullName()))
                return true;
        }
        return false;
    }

    public static final class Badge extends PromotionBadge {
        /**
         * Downstream builds that certified this build. Should be considered read-only.
         */
        public final List builds = new ArrayList();

        void add(AbstractBuild b) {
           builds.add(new Fingerprint.BuildPtr(b));
        }
    }

    @Extension
    public static final class DescriptorImpl extends PromotionConditionDescriptor {
        public boolean isApplicable(AbstractProject item) {
            return true;
        }

        public String getDisplayName() {
            return "When the following downstream projects build successfully";
        }

        public String getHelpFile() {
            return "/plugin/promoted-builds/conditions/downstream.html";
        }
        
        public PromotionCondition newInstance(StaplerRequest req, JSONObject formData) throws FormException {
            return new DownstreamPassCondition(formData.getString("jobs"));
        }

        public static final DescriptorImpl INSTANCE = new DescriptorImpl();
    }

    /**
     * {@link RunListener} to pick up completions of downstream builds.
     *
     * 

* This is a single instance that receives all the events everywhere in the system. * @author Kohsuke Kawaguchi */ @Extension public static final class RunListenerImpl extends RunListener> { public RunListenerImpl() { super((Class)AbstractBuild.class); } @Override public void onCompleted(AbstractBuild build, TaskListener listener) { // this is not terribly efficient, for(AbstractProject j : Hudson.getInstance().getAllItems(AbstractProject.class)) { boolean warned = false; // used to avoid warning for the same project more than once. JobPropertyImpl jp = j.getProperty(JobPropertyImpl.class); if(jp!=null) { for (PromotionProcess p : jp.getItems()) { boolean considerPromotion = false; for (PromotionCondition cond : p.conditions) { if (cond instanceof DownstreamPassCondition) { DownstreamPassCondition dpcond = (DownstreamPassCondition) cond; if(dpcond.contains(build.getParent())) { considerPromotion = true; break; } } } if(considerPromotion) { try { AbstractBuild u = build.getUpstreamRelationshipBuild(j); if (u==null) { // if the fingerprint doesn't tell us, perhaps the cause would tell us? for (UpstreamCause uc : Util.filter(build.getCauses(), UpstreamCause.class)) { if (uc.getUpstreamProject().equals(j.getFullName())) { u = j.getBuildByNumber(uc.getUpstreamBuild()); if (u!=null) { // remember that this build is a pseudo-downstream of the discovered build. PseudoDownstreamBuilds pdb = u.getAction(PseudoDownstreamBuilds.class); if (pdb==null) u.addAction(pdb=new PseudoDownstreamBuilds()); pdb.add(build); u.save(); break; } } } } if (u==null) { // no upstream build. perhaps a configuration problem? if(build.getResult()==Result.SUCCESS && !warned) { listener.getLogger().println("WARNING: "+j.getFullDisplayName()+" appears to use this job as a promotion criteria, " + "but no fingerprint is recorded. Fingerprint needs to be enabled on both this job and "+j.getFullDisplayName()+". " + "See http://hudson.gotdns.com/wiki/display/HUDSON/Fingerprint for more details"); warned = true; } } if(u!=null && p.considerPromotion(u)) listener.getLogger().println("Promoted "+u); } catch (IOException e) { e.printStackTrace(listener.error("Failed to promote a build")); } } } } } } /** * List of downstream jobs that we are interested in. */ @CopyOnWrite private static volatile Set DOWNSTREAM_JOBS = Collections.emptySet(); /** * Called whenever some {@link JobPropertyImpl} changes to update {@link #DOWNSTREAM_JOBS}. */ public static void rebuildCache() { DOWNSTREAM_JOBS = new HashSet(); } } /** * Remembers those downstream jobs that are not related by fingerprint but by the triggering relationship. * This is a weaker form of the relationship and less reliable, but often people don't understand * the notion of fingerprints, in which case this works. */ public static class PseudoDownstreamBuilds extends InvisibleAction { final List builds = new ArrayList(); public void add(AbstractBuild run) { builds.add(new BuildPtr(run)); } public List> listBuilds(AbstractProject job) { List> list = new ArrayList>(); for (BuildPtr b : builds) { if (b.is(job)) { Run r = b.getRun(); if (r instanceof AbstractBuild) // mainly null check, plus a defensive measure caused by a possible rename. list.add((AbstractBuild)r); } } return list; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy