/*
* The MIT License
*
* Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, Yahoo! Inc.
*
* 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.ExtensionPoint;
import hudson.Launcher;
import hudson.DescriptorExtensionList;
import hudson.LauncherDecorator;
import hudson.model.*;
import hudson.model.Run.RunnerAbortedException;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
/**
* Pluggability point for performing pre/post actions for the build process.
*
* <p>
* This extension point enables a plugin to set up / tear down additional
* services needed to perform a build, such as setting up local X display,
* or launching and stopping application servers for testing.
*
* <p>
* An instance of {@link BuildWrapper} is associated with a {@link Project}
* with configuration information as its state. An instance is persisted
* along with {@link Project}.
*
* <p>
* The {@link #setUp(Build,Launcher,BuildListener)} method is invoked for each build.
*
* @author Kohsuke Kawaguchi
*/
public abstract class BuildWrapper extends AbstractDescribableImpl<BuildWrapper> implements ExtensionPoint {
/**
* Represents the environment set up by {@link BuildWrapper#setUp(Build,Launcher,BuildListener)}.
*
* <p>
* It is expected that the subclasses of {@link BuildWrapper} extends this
* class and implements its own semantics.
*/
public abstract class Environment extends hudson.model.Environment {
/**
* Runs after the {@link Builder} completes, and performs a tear down.
*
* <p>
* This method is invoked even when the build failed, so that the
* clean up operation can be performed regardless of the build result
* (for example, you'll want to stop application server even if a build
* fails.) {@link Build#getResult} in this case will return Result.FAILURE
* (since 1.339), and a null result indicates SUCCESS-so-far (post-build
* actions may still affect the final result).
*
* @param build
* The same {@link Build} object given to the set up method.
* @param listener
* The same {@link BuildListener} object given to the set up method.
* @return
* true if the build can continue, false if there was an error
* and the build needs to be aborted.
* @throws IOException
* terminates the build abnormally. Hudson will handle the exception
* and reports a nice error message.
* @since 1.150
*/
public boolean tearDown( AbstractBuild build, BuildListener listener ) throws IOException, InterruptedException {
if (build instanceof Build)
return tearDown((Build)build, listener);
else
return true;
}
/**
* @deprecated since 2007-10-28.
* Use {@link #tearDown(AbstractBuild, BuildListener)} instead.
*/
@Deprecated
public boolean tearDown( Build build, BuildListener listener ) throws IOException, InterruptedException {
return true;
}
}
/**
* Runs before the {@link Builder} runs, and performs a set up.
*
* @param build
* The build in progress for which an {@link Environment} object is created.
* Never null.
* @param launcher
* This launcher can be used to launch processes for this build.
* If the build runs remotely, launcher will also run a job on that remote machine.
* Never null.
* @param listener
* Can be used to send any message.
* @return
* non-null if the build can continue, null if there was an error
* and the build needs to be aborted.
* @throws IOException
* terminates the build abnormally. Hudson will handle the exception
* and reports a nice error message.
* @since 1.150
*/
public Environment setUp( AbstractBuild build, Launcher launcher, BuildListener listener ) throws IOException, InterruptedException {
if (build instanceof Build)
return setUp((Build)build,launcher,listener);
else
throw new AssertionError("The plugin '" + this.getClass().getName() + "' still uses " +
"deprecated setUp(Build,Launcher,BuildListener) method. " +
"Update the plugin to use setUp(AbstractBuild, Launcher, BuildListener) instead.");
}
/**
* @deprecated since 2007-10-28.
* Use {@link #setUp(AbstractBuild, Launcher, BuildListener)} instead.
*/
@Deprecated
public Environment setUp( Build build, Launcher launcher, BuildListener listener ) throws IOException, InterruptedException {
throw new UnsupportedOperationException(getClass()+" needs to implement the setUp method");
}
/**
* Provides an opportunity for a {@link BuildWrapper} to decorate a {@link Launcher} to be used in the build.
*
* <p>
* This hook is called very early on in the build (even before {@link #setUp(AbstractBuild, Launcher, BuildListener)} is invoked.)
* The typical use of {@link Launcher} decoration involves in modifying the environment that processes run,
* such as the use of sudo/pfexec/chroot, or manipulating environment variables.
*
* <p>
* The default implementation is no-op, which just returns the {@code launcher} parameter as-is.
*
* @param build
* The build in progress for which this {@link BuildWrapper} is called. Never null.
* @param launcher
* The default launcher. Never null. This method is expected to wrap this launcher.
* This makes sure that when multiple {@link BuildWrapper}s attempt to decorate the same launcher
* it will sort of work. But if you are developing a plugin where such collision is not a concern,
* you can also simply discard this {@link Launcher} and create an entirely different {@link Launcher}
* and return it, too.
* @param listener
* Connected to the build output. Never null. Can be used for error reporting.
* @return
* Must not be null. If a fatal error happens, throw an exception.
* @throws RunnerAbortedException
* If a fatal error is detected but the implementation handled it gracefully, throw this exception
* to suppress stack trace.
* @since 1.280
* @see LauncherDecorator
*/
public Launcher decorateLauncher(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException, RunnerAbortedException {
return launcher;
}
/**
* Provides an opportunity for a {@link BuildWrapper} to decorate the {@link BuildListener} logger to be used by the build.
*
* <p>
* This hook is called very early on in the build (even before {@link #setUp(AbstractBuild, Launcher, BuildListener)} is invoked.)
*
* <p>
* The default implementation is no-op, which just returns the {@code logger} parameter as-is.
*
* @param build
* The build in progress for which this {@link BuildWrapper} is called. Never null.
* @param logger
* The default logger. Never null. This method is expected to wrap this logger.
* This makes sure that when multiple {@link BuildWrapper}s attempt to decorate the same logger
* it will sort of work.
* @return
* Must not be null. If a fatal error happens, throw an exception.
* @throws RunnerAbortedException
* If a fatal error is detected but the implementation handled it gracefully, throw this exception
* to suppress stack trace.
* @since 1.374
*/
public OutputStream decorateLogger(AbstractBuild build, OutputStream logger) throws IOException, InterruptedException, RunnerAbortedException {
return logger;
}
/**
* {@link Action} to be displayed in the job page.
*
* @param job
* This object owns the {@link BuildWrapper}. The returned action will be added to this object.
* @return
* null if there's no such action.
* @since 1.226
* @deprecated
* Use {@link #getProjectActions(AbstractProject)} instead.
*/
public Action getProjectAction(AbstractProject job) {
return null;
}
/**
* {@link Action}s to be displayed in the job page.
*
* @param job
* This object owns the {@link BuildWrapper}. The returned action will be added to this object.
* @return
* can be empty but never null
* @since 1.341
*/
public Collection<? extends Action> getProjectActions(AbstractProject job) {
// delegate to getJobAction (singular) for backward compatible behavior
Action a = getProjectAction(job);
if (a==null) return Collections.emptyList();
return Collections.singletonList(a);
}
/**
* Called to define {@linkplain AbstractBuild#getBuildVariables()}.
*
* This provides an opportunity for a BuildWrapper to append any additional
* build variables defined for the current build.
*
* @param build
* The build in progress for which this {@link BuildWrapper} is called. Never null.
* @param variables
* Contains existing build variables. Add additional build variables that you contribute
* to this map.
*/
public void makeBuildVariables(AbstractBuild build, Map<String,String> variables) {
// noop
}
/**
* Called to define sensitive build variables. This provides an opportunity
* for a BuildWrapper to denote the names of variables that are sensitive in
* nature and should not be exposed in output.
*
* @param build
* The build in progress for which this {@link BuildWrapper} is called. Never null.
* @param sensitiveVariables
* Contains names of sensitive build variables. Names of sensitive variables
* that were added with {@link #makeBuildVariables(hudson.model.AbstractBuild, java.util.Map)}
* @since 1.378
*/
public void makeSensitiveBuildVariables(AbstractBuild build, Set<String> sensitiveVariables) {
// noop
}
/**
* Returns all the registered {@link BuildWrapper} descriptors.
*/
// for compatibility we can't use BuildWrapperDescriptor
public static DescriptorExtensionList<BuildWrapper,Descriptor<BuildWrapper>> all() {
// use getDescriptorList and not getExtensionList to pick up legacy instances
return Hudson.getInstance().<BuildWrapper,Descriptor<BuildWrapper>>getDescriptorList(BuildWrapper.class);
}
}