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

au.com.centrumsystems.hudson.plugin.buildpipeline.trigger.BuildPipelineTrigger Maven / Gradle / Ivy

Go to download

This plugin provides build pipeline functionality to Hudson and Jenkins. This allows a chain of jobs to be visualised in a new view. Manual jobs in the pipeline can be triggered by a user with the appropriate permissions manually confirming.

There is a newer version: 1.2.3
Show newest version
/*
 * The MIT License
 *
 * Copyright (c) 2011, Centrum Systems Pty Ltd
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 */
package au.com.centrumsystems.hudson.plugin.buildpipeline.trigger;

import hudson.Extension;
import hudson.Launcher;
import hudson.Util;
import hudson.model.BuildListener;
import hudson.model.DependecyDeclarer;
import hudson.model.DependencyGraph;
import hudson.model.Item;
import hudson.model.Items;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Hudson;
import hudson.model.Project;
import hudson.model.listeners.ItemListener;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Messages;
import hudson.tasks.Notifier;
import hudson.tasks.Publisher;
import hudson.util.FormValidation;

import java.io.IOException;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

import net.sf.json.JSONObject;

import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;

/**
 * The build pipeline trigger allows the creation of downstream jobs which aren't triggered automatically. This allows us to have manual
 * "approval" steps in the process where jobs are manually promoted along the pipeline by a user pressing a button on the view.
 * 
 * @author Centrum Systems
 * 
 */
@SuppressWarnings("unchecked")
public class BuildPipelineTrigger extends Notifier implements DependecyDeclarer {

    /** downstream project name */
    private String downstreamProjectNames;

    public String getDownstreamProjectNames() {
        return downstreamProjectNames;
    }

    public void setDownstreamProjectNames(final String downstreamProjectNames) {
        this.downstreamProjectNames = downstreamProjectNames;
    }

    /**
     * Construct the trigger setting the project name and manual build promotion option
     * 
     * @param downstreamProjectNames
     *            - the job name of the downstream build
     */
    @DataBoundConstructor
    public BuildPipelineTrigger(final String downstreamProjectNames) {
        if (downstreamProjectNames == null) {
            throw new IllegalArgumentException();
        }

        setDownstreamProjectNames(downstreamProjectNames);
    }

    /**
     * this method is required to rebuild the dependency graph of the downstream project
     * 
     * @param owner
     *            owner
     * @param graph
     *            graph
     */
    @SuppressWarnings("rawtypes")
    public void buildDependencyGraph(final AbstractProject owner, final DependencyGraph graph) {
        if (downstreamProjectNames != null && downstreamProjectNames.length() > 0) {
            for (final Object o : Items.fromNameList(downstreamProjectNames, AbstractProject.class)) {
                final AbstractProject downstream = (AbstractProject) o;

                graph.addDependency(createDownstreamDependency(owner, downstream));
            }
        }
    }

    /**
     * Create a new DownstreamDependency
     * 
     * @param owner
     *            - upstream project
     * @param downstream
     *            - downstream project
     * @return downstream dependency
     */
    private DownstreamDependency createDownstreamDependency(final AbstractProject owner, final AbstractProject downstream) {
        return new DownstreamDependency(owner, downstream);
    }

    @Override
    public boolean needsToRunAfterFinalized() {
        return true;
    }

    public BuildStepMonitor getRequiredMonitorService() {
        return BuildStepMonitor.NONE;
    }

    @Override
    public boolean perform(final AbstractBuild build, final Launcher launcher, final BuildListener listener)
        throws InterruptedException, IOException {
        return true;
    }

    /**
     * Renames a project contained in downstreamProjectNames
     * 
     * @param oldName
     *            - The old name of the project
     * @param newName
     *            - The new name of the project
     * @return - true: A downstream project has been renamed; false No downstream projects were renamed
     */
    public boolean onDownstreamProjectRenamed(final String oldName, final String newName) {
        boolean changed = false;
        final String[] existingDownstreamProjects = this.getDownstreamProjectNames().split(",");
        for (int i = 0; i < existingDownstreamProjects.length; i++) {
            if (existingDownstreamProjects[i].trim().equals(oldName)) {
                existingDownstreamProjects[i] = newName;
                changed = true;
            }
        }
        if (changed) {
            final StringBuilder newDownstreamProjects = new StringBuilder();
            for (int i = 0; i < existingDownstreamProjects.length; i++) {
                if (existingDownstreamProjects[i] == null) {
                    continue;
                }
                if (newDownstreamProjects.length() > 0) {
                    newDownstreamProjects.append(',');
                }
                newDownstreamProjects.append(existingDownstreamProjects[i].trim());
            }
            this.setDownstreamProjectNames(newDownstreamProjects.toString());
        }
        return changed;
    }

    /**
     * Deletes a project from downstreamProjectNames.
     * 
     * @param oldName
     *            - Project to be deleted
     * @return - true; project deleted: false; project not deleted {@link #onDownstreamProjectRenamed(String, String)}
     */
    public boolean onDownstreamProjectDeleted(final String oldName) {
        return onDownstreamProjectRenamed(oldName, null);
    }

    /**
     * Set the descriptor for build pipeline trigger class This descriptor is only attached to Build Trigger Post Build action in JOB
     * configuration page
     * 
     * @author Centrum Systems
     * 
     */
    @Extension
    public static class DescriptorImpl extends BuildStepDescriptor {

        @Override
        public boolean isApplicable(final Class jobType) {
            return true;
        }

        /**
         * set the display name in post build action section of the job configuration page
         * 
         * @return display name
         */
        @Override
        public String getDisplayName() {
            return "Build Pipeline Plugin -> Manually Execute Downstream Project";
        }

        /**
         * Set help text to "Build Pipeline Plugin -> Manually Execute Downstream Project" Post Build action in JOB configuration page
         * 
         * @return location of the help file
         */
        @Override
        public String getHelpFile() {
            return "/descriptor/au.com.centrumsystems.hudson.plugin.buildpipeline.trigger.BuildPipelineTrigger/help/buildPipeline.html";
        }

        @Override
        public Publisher newInstance(final StaplerRequest req, final JSONObject formData) throws FormException {
            return new BuildPipelineTrigger(formData.getString("downstreamProjectNames"));
        }

        /**
         * Validates that the downstream project names entered are valid projects.
         * 
         * @param value
         *            - The entered project names
         * @return hudson.util.FormValidation
         */
        public FormValidation doCheckDownstreamProjectNames(@QueryParameter("downstreamProjectNames") final String value) {
            final StringTokenizer tokens = new StringTokenizer(Util.fixNull(value), ",");
            while (tokens.hasMoreTokens()) {
                final String projectName = tokens.nextToken().trim();
                final Item item = Hudson.getInstance().getItemByFullName(projectName, Item.class);
                if (item == null) {
                    return FormValidation.error(Messages.BuildTrigger_NoSuchProject(projectName, AbstractProject.findNearest(projectName)
                        .getName()));
                }
                if (!(item instanceof AbstractProject)) {
                    return FormValidation.error(Messages.BuildTrigger_NotBuildable(projectName));
                }
            }

            return FormValidation.ok();
        }

        /**
         * If a job is renamed, update all BuildPipelineTriggers with the new name.
         */
        @Extension
        public static final class ItemListenerImpl extends ItemListener {
            @Override
            public void onRenamed(final Item item, final String oldName, final String newName) {
                for (final Project p : Hudson.getInstance().getProjects()) {
                    final BuildPipelineTrigger bpTrigger = p.getPublishersList().get(BuildPipelineTrigger.class);
                    if (bpTrigger != null) {
                        boolean changed = false;
                        changed = bpTrigger.onDownstreamProjectRenamed(oldName, newName);

                        if (changed) {
                            try {
                                p.save();
                            } catch (final IOException e) {
                                Logger.getLogger(ItemListenerImpl.class.getName()).log(
                                    Level.WARNING,
                                    "Failed to persist project BuildPipelineTrigger setting during rename from " + oldName + " to "
                                        + newName, e);
                            }
                        }
                    }
                }
            }

            @Override
            public void onDeleted(final Item item) {
                for (final Project p : Hudson.getInstance().getProjects()) {
                    final String oldName = item.getName();
                    final BuildPipelineTrigger bpTrigger = p.getPublishersList().get(BuildPipelineTrigger.class);
                    if (bpTrigger != null) {
                        boolean changed = false;

                        if (bpTrigger.onDownstreamProjectDeleted(oldName)) {
                            changed = true;
                        }

                        if (changed) {
                            try {
                                if (bpTrigger.getDownstreamProjectNames().isEmpty()) {
                                    p.getPublishersList().remove(bpTrigger);
                                }
                                p.save();
                            } catch (final IOException e) {
                                Logger.getLogger(ItemListenerImpl.class.getName()).log(Level.WARNING,
                                    "Failed to persist project BuildPipelineTrigger setting during remove of " + oldName, e);
                            }
                        }
                    }
                }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy