/* * The MIT License * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi * * 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 hudson.tasks; import hudson.Launcher; import hudson.Extension; import hudson.ExtensionList; import hudson.util.DescriptorList; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.Action; import hudson.model.Build; import hudson.model.BuildListener; import hudson.model.Descriptor; import hudson.model.Project; import hudson.model.Hudson; import hudson.model.CheckPoint; import hudson.model.Run; import java.io.IOException; import java.util.Collection; import java.util.List; import java.util.AbstractList; import java.util.Iterator; import java.util.WeakHashMap; /** * One step of the whole build process. * * <h2>Persistence</h2> * <p> * These objects are persisted as a part of {@link Project} by XStream. * The save operation happens without any notice, and the restore operation * happens without calling the constructor, just like Java serialization. * * <p> * So generally speaking, derived classes should use instance variables * only for keeping configuration. You can still store objects you use * for processing, like a parser of some sort, but they need to be marked * as <tt>transient</tt>, and the code needs to be aware that they might * be null (which is the case when you access the field for the first time * the object is restored.) * * @author Kohsuke Kawaguchi */ public interface BuildStep { /** * Runs before the build begins. * * @return * true if the build can continue, false if there was an error * and the build needs to be aborted. */ boolean prebuild( AbstractBuild<?,?> build, BuildListener listener ); /** * Runs the step over the given build and reports the progress to the listener. * * <p> * A plugin can contribute the action object to {@link Build#getActions()} * so that a 'report' becomes a part of the persisted data of {@link Build}. * This is how JUnit plugin attaches the test report to a build page, for example. * * @return * true if the build can continue, false if there was an error * and the build needs to be aborted. * * @throws InterruptedException * If the build is interrupted by the user (in an attempt to abort the build.) * Normally the {@link BuildStep} implementations may simply forward the exception * it got from its lower-level functions. * @throws IOException * If the implementation wants to abort the processing when an {@link IOException} * happens, it can simply propagate the exception to the caller. This will cause * the build to fail, with the default error message. * Implementations are encouraged to catch {@link IOException} on its own to * provide a better error message, if it can do so, so that users have better * understanding on why it failed. */ boolean perform(AbstractBuild<?,?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException; /** * @deprecated as of 1.341. * Use {@link #getProjectActions(AbstractProject)} instead. */ Action getProjectAction(AbstractProject<?,?> project); /** * Returns action objects if this {@link BuildStep} has actions * to contribute to a {@link Project}. * * <p> * {@link Project} calls this method for every {@link BuildStep} that * it owns when the rendering is requested. * * <p> * This action can have optional <tt>jobMain.jelly</tt> view, which will be * aggregated into the main panel of the job top page. The jelly file * should have an <h2> tag that shows the section title, followed by some * block elements to render the details of the section. * * @param project * {@link Project} that owns this build step, * since {@link BuildStep} object doesn't usually have this "parent" pointer. * * @return * can be empty but never null. */ Collection<? extends Action> getProjectActions(AbstractProject<?,?> project); /** * Declares the scope of the synchronization monitor this {@link BuildStep} expects from outside. * * <p> * This method is introduced for preserving compatibility with plugins written for earlier versions of Hudson, * which never run multiple builds of the same job in parallel. Such plugins often assume that the outcome * of the previous build is completely available, which is no longer true when we do concurrent builds. * * <p> * To minimize the necessary code change for such plugins, {@link BuildStep} implementations can request * Hudson to externally perform synchronization before executing them. This behavior is as follows: * * <dl> * <dt>{@link BuildStepMonitor#BUILD} * <dd> * This {@link BuildStep} is only executed after the previous build is fully * completed (thus fully restoring the earlier semantics of one build at a time.) * * <dt>{@link BuildStepMonitor#STEP} * <dd> * This {@link BuildStep} is only executed after the same step in the previous build is completed. * For build steps that use a weaker assumption and only rely on the output from the same build step of * the early builds, this improves the concurrency. * * <dt>{@link BuildStepMonitor#NONE} * <dd> * No external synchronization is performed on this build step. This is the most efficient, and thus * <b>the recommended value for newer plugins</b>. Wherever necessary, you can directly use {@link CheckPoint}s * to perform necessary synchronizations. * </dl> * * <h2>Migrating Older Implementation</h2> * <p> * If you are migrating {@link BuildStep} implementations written for earlier versions of Hudson, * here's what you can do: * * <ul> * <li> * Just return {@link BuildStepMonitor#BUILD} to demand the backward compatible behavior from Hudson, * and make no other changes to the code. This will prevent users from reaping the benefits of concurrent * builds, but at least your plugin will work correctly, and therefore this is a good easy first step. * <li> * If your build step doesn't use anything from a previous build (for example, if you don't even call * {@link Run#getPreviousBuild()}), then you can return {@link BuildStepMonitor#NONE} without making further * code changes and you are done with migration. * <li> * If your build step only depends on {@link Action}s that you added in the previous build by yourself, * then you only need {@link BuildStepMonitor#STEP} scope synchronization. Return it from this method * ,and you are done with migration without any further code changes. * <li> * If your build step makes more complex assumptions, return {@link BuildStepMonitor#NONE} and use * {@link CheckPoint}s directly in your code. The general idea is to call {@link CheckPoint#block()} before * you try to access the state from the previous build. * </ul> * * <h2>Note to caller</h2> * <p> * For plugins written against earlier versions of Hudson, calling this method results in * {@link AbstractMethodError}. * * @since 1.319 */ BuildStepMonitor getRequiredMonitorService(); /** * List of all installed builders. * * Builders are invoked to perform the build itself. * * @deprecated as of 1.286. * Use {@link Builder#all()} for read access, and use * {@link Extension} for registration. */ public static final List<Descriptor<Builder>> BUILDERS = new DescriptorList<Builder>(Builder.class); /** * List of all installed publishers. * * Publishers are invoked after the build is completed, normally to perform * some post-actions on build results, such as sending notifications, collecting * results, etc. * * @see PublisherList#addNotifier(Descriptor) * @see PublisherList#addRecorder(Descriptor) * * @deprecated as of 1.286. * Use {@link Publisher#all()} for read access, and use * {@link Extension} for registration. */ public static final PublisherList PUBLISHERS = new PublisherList(); /** * List of publisher descriptor. */ public static final class PublisherList extends AbstractList<Descriptor<Publisher>> { /** * {@link Descriptor}s are actually stored in here. * Since {@link PublisherList} lives longer than {@link Hudson} we cannot directly use {@link ExtensionList}. */ private final DescriptorList<Publisher> core = new DescriptorList<Publisher>(Publisher.class); /** * For descriptors that are manually registered, remember what kind it was since * older plugins don't extend from neither {@link Recorder} nor {@link Notifier}. */ /*package*/ static final WeakHashMap<Descriptor<Publisher>,Class<? extends Publisher>/*either Recorder.class or Notifier.class*/> KIND = new WeakHashMap<Descriptor<Publisher>, Class<? extends Publisher>>(); private PublisherList() { } /** * Adds a new publisher descriptor, which (generally speaking) * shouldn't alter the build result, but just report the build result * by some means, such as e-mail, IRC, etc. * * <p> * This method adds the descriptor after all the "recorders". * * @see #addRecorder(Descriptor) */ public void addNotifier( Descriptor<Publisher> d ) { KIND.put(d,Notifier.class); core.add(d); } /** * Adds a new publisher descriptor, which (generally speaking) * alter the build result based on some artifacts of the build. * * <p> * This method adds the descriptor before all the "notifiers". * * @see #addNotifier(Descriptor) */ public void addRecorder( Descriptor<Publisher> d ) { KIND.put(d,Recorder.class); core.add(d); } @Override public boolean add(Descriptor<Publisher> d) { return !contains(d) && core.add(d); } @Override public void add(int index, Descriptor<Publisher> d) { if(!contains(d)) core.add(d); } public Descriptor<Publisher> get(int index) { return core.get(index); } public int size() { return core.size(); } @Override public Iterator<Descriptor<Publisher>> iterator() { return core.iterator(); } @Override public boolean remove(Object o) { return core.remove(o); } } }