/*******************************************************************************
*
* 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);
}
}
}