/******************************************************************************* * * Copyright (c) 2004-2009 Oracle Corporation. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * * Kohsuke Kawaguchi * * *******************************************************************************/ package hudson.tasks; import hudson.Launcher; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.Action; import hudson.model.BuildListener; import hudson.model.Descriptor; import hudson.util.DescriptorList; import java.io.IOException; import java.util.AbstractList; import java.util.Collection; import java.util.Iterator; import java.util.List; 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); } } }