package jenkins.scm; import hudson.ExtensionPoint; import hudson.Launcher; import hudson.model.AbstractBuild; import hudson.model.AbstractBuild.AbstractBuildExecution; import hudson.model.AbstractDescribableImpl; import hudson.model.AbstractProject; import hudson.model.BuildListener; import hudson.model.BuildableItemWithBuildWrappers; import hudson.model.Executor; import hudson.scm.SCM; import hudson.tasks.BuildWrapper; import java.io.File; import java.io.IOException; /** * Controls the check out behavior in {@link AbstractBuild}. * * <p> * While this can work with any {@link AbstractBuild}, the primary motivation of this extension point * is to control the check out behaviour in matrix projects. The intended use cases include situations like: * * <ul> * <li>Check out will only happen once in {@code MatrixBuild}, and its state will be then sent * to {@code MatrixRun}s by other means such as rsync. * <li>{@code MatrixBuild} does no check out of its own, and check out is only done on {@code MatrixRun}s * </ul> * * <h2>Hook Semantics</h2> * There are currently two hooks defined on this class: * * <h3>pre checkout</h3> * <p> * The default implementation calls into {@link BuildWrapper#preCheckout(AbstractBuild, Launcher, BuildListener)} calls. * You can override this method to do something before/after this, but you must still call into the {@code super.preCheckout} * so that matrix projects can satisfy the contract with {@link BuildWrapper}s. * * <h3>checkout</h3> * <p> * The default implementation uses {@link AbstractProject#checkout(AbstractBuild, Launcher, BuildListener, File)} to * let {@link SCM} do check out, but your {@link SCMCheckoutStrategy} impls can substitute this call with other * operations that substitutes this semantics. * * <h2>State and concurrency</h2> * <p> * An instance of this object gets created for a project for which this strategy is configured, so * the subtype needs to avoid using instance variables to refer to build-specific state (such as {@link BuildListener}s.) * Similarly, methods can be invoked concurrently. The code executes on the master, even if builds are running remotely. */ public abstract class SCMCheckoutStrategy extends AbstractDescribableImpl<SCMCheckoutStrategy> implements ExtensionPoint { /* Default behavior is defined in AbstractBuild.AbstractRunner, which is the common implementation for not just matrix projects but all sorts of other project types. */ /** * Performs the pre checkout step. * * This method is called by the {@link Executor} that's carrying out the build. * * @param build * Build being in progress. Never null. * @param launcher * Allows you to launch process on the node where the build is actually running. Never null. * @param listener * Allows you to write to console output and report errors. Never null. */ public void preCheckout(AbstractBuild<?,?> build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { AbstractProject<?, ?> project = build.getProject(); if (project instanceof BuildableItemWithBuildWrappers) { BuildableItemWithBuildWrappers biwbw = (BuildableItemWithBuildWrappers) project; for (BuildWrapper bw : biwbw.getBuildWrappersList()) bw.preCheckout(build,launcher,listener); } } /** * Performs the checkout step. * * See {@link #preCheckout(AbstractBuild, Launcher, BuildListener)} for the semantics of the parameters. */ public void checkout(AbstractBuildExecution execution) throws IOException, InterruptedException { execution.defaultCheckout(); } @Override public SCMCheckoutStrategyDescriptor getDescriptor() { return (SCMCheckoutStrategyDescriptor)super.getDescriptor(); } }