Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #42 from zregvart/master
[JENKINS-28147] Perform Environment tearDown if BuildWrapper fails
  • Loading branch information
zregvart committed Nov 24, 2015
2 parents fbafb4d + dd65300 commit f3f1f11
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 87 deletions.
190 changes: 103 additions & 87 deletions src/main/java/hudson/maven/MavenBuild.java
Expand Up @@ -778,116 +778,132 @@ protected Lease decideWorkspace(Node n, WorkspaceList wsl) throws InterruptedExc
}

protected Result doRun(BuildListener listener) throws Exception {
SplittableBuildListener slistener = new SplittableBuildListener(listener);

// pick up a list of reporters to run
reporters = getProject().createReporters();
MavenModuleSet mms = getProject().getParent();
if(debug)
listener.getLogger().println("Reporters="+reporters);

for (BuildWrapper w : mms.getBuildWrappersList()) {
Environment e = w.setUp(MavenBuild.this, launcher, listener);
if (e == null) {
return Result.FAILURE;
AbstractMavenBuilder builder = null;
ProcessCache.MavenProcess process = null;
boolean normalExit = false;

final SplittableBuildListener slistener = new SplittableBuildListener(listener);

try {
// pick up a list of reporters to run
reporters = getProject().createReporters();
MavenModuleSet mms = getProject().getParent();
if(debug)
listener.getLogger().println("Reporters="+reporters);

for (BuildWrapper w : mms.getBuildWrappersList()) {
Environment e = w.setUp(MavenBuild.this, launcher, listener);
if (e == null) {
return Result.FAILURE;
}
buildEnvironments.add(e);
}
buildEnvironments.add(e);
}

EnvVars envVars = getEnvironment(listener); // buildEnvironments should be set up first

MavenInstallation mvn = getProject().getParent().getMaven();

mvn = mvn.forEnvironment(envVars).forNode(Computer.currentComputer().getNode(), listener);

MavenInformation mavenInformation = getModuleRoot().act( new MavenVersionCallable( mvn.getHome() ));

String mavenVersion = mavenInformation.getVersion();
EnvVars envVars = getEnvironment(listener); // buildEnvironments should be set up first

LOGGER.fine(getFullDisplayName()+" is building with mavenVersion " + mavenVersion + " from file " + mavenInformation.getVersionResourcePath());
MavenInstallation mvn = getProject().getParent().getMaven();

MavenBuildInformation mavenBuildInformation = new MavenBuildInformation( mavenVersion );
mvn = mvn.forEnvironment(envVars).forNode(Computer.currentComputer().getNode(), listener);

MavenUtil.MavenVersion mavenVersionType = MavenUtil.getMavenVersion( mavenVersion );
MavenInformation mavenInformation = getModuleRoot().act( new MavenVersionCallable( mvn.getHome() ));

final ProcessCache.Factory factory;
String mavenVersion = mavenInformation.getVersion();

switch ( mavenVersionType ){
case MAVEN_2:
LOGGER.fine( "using maven 2 " + mavenVersion );
factory = new MavenProcessFactory( getParent().getParent(), MavenBuild.this, launcher, envVars, getMavenOpts(listener, envVars), null );
break;
case MAVEN_3_0_X:
LOGGER.fine( "using maven 3 " + mavenVersion );
factory = new Maven3ProcessFactory( getParent().getParent(), MavenBuild.this, launcher, envVars, getMavenOpts(listener, envVars), null );
break;
case MAVEN_3_1:
LOGGER.fine( "using maven 3 " + mavenVersion );
factory = new Maven31ProcessFactory( getParent().getParent(), MavenBuild.this, launcher, envVars, getMavenOpts(listener, envVars), null );
break;
default:
LOGGER.fine( "using maven 3 " + mavenVersion );
factory = new Maven32ProcessFactory( getParent().getParent(), MavenBuild.this, launcher, envVars, getMavenOpts(listener, envVars), null );
LOGGER.fine(getFullDisplayName()+" is building with mavenVersion " + mavenVersion + " from file " + mavenInformation.getVersionResourcePath());

}
MavenBuildInformation mavenBuildInformation = new MavenBuildInformation( mavenVersion );

ProcessCache.MavenProcess process = MavenBuild.mavenProcessCache.get( launcher.getChannel(), slistener, factory);
MavenUtil.MavenVersion mavenVersionType = MavenUtil.getMavenVersion( mavenVersion );

ArgumentListBuilder margs = new ArgumentListBuilder("-N","-B");
FilePath localRepo = mms.getLocalRepository().locate(MavenBuild.this);
if(localRepo!=null)
// the workspace must be on this node, so getRemote() is safe.
margs.add("-Dmaven.repo.local="+localRepo.getRemote());

String settingsPath = SettingsProvider.getSettingsRemotePath(mms.getSettings(), MavenBuild.this, listener);
if (settingsPath != null) {
margs.add("-s").add(settingsPath);
}
final ProcessCache.Factory factory;

margs.add("-f",getModuleRoot().child("pom.xml").getRemote());
margs.addTokenized(getProject().getGoals());

Map<String,String> systemProps = new HashMap<String, String>(envVars);
// backward compatibility
systemProps.put("hudson.build.number",String.valueOf(getNumber()));

ProxyImpl proxy;
AbstractMavenBuilder builder;
if (mavenBuildInformation.isMaven3OrLater())
{
ProxyImpl2 proxy2 = new ProxyImpl2(mms.getLastCompletedBuild(), slistener);
proxy2.setBlockBuildEvents(true);
proxy = proxy2;
builder = new Maven3Builder(createRequest(proxy2,
getProject(), margs.toList(), systemProps,
mavenBuildInformation));
}
else {
proxy = new ProxyImpl();
builder = new Builder(
listener, proxy,
getProject(), margs.toList(), systemProps);
}
boolean normalExit = false;
try {
switch ( mavenVersionType ){
case MAVEN_2:
LOGGER.fine( "using maven 2 " + mavenVersion );
factory = new MavenProcessFactory( getParent().getParent(), MavenBuild.this, launcher, envVars, getMavenOpts(listener, envVars), null );
break;
case MAVEN_3_0_X:
LOGGER.fine( "using maven 3 " + mavenVersion );
factory = new Maven3ProcessFactory( getParent().getParent(), MavenBuild.this, launcher, envVars, getMavenOpts(listener, envVars), null );
break;
case MAVEN_3_1:
LOGGER.fine( "using maven 3 " + mavenVersion );
factory = new Maven31ProcessFactory( getParent().getParent(), MavenBuild.this, launcher, envVars, getMavenOpts(listener, envVars), null );
break;
default:
LOGGER.fine( "using maven 3 " + mavenVersion );
factory = new Maven32ProcessFactory( getParent().getParent(), MavenBuild.this, launcher, envVars, getMavenOpts(listener, envVars), null );

}

process = MavenBuild.mavenProcessCache.get( launcher.getChannel(), slistener, factory);

ArgumentListBuilder margs = new ArgumentListBuilder("-N","-B");
FilePath localRepo = mms.getLocalRepository().locate(MavenBuild.this);
if(localRepo!=null)
// the workspace must be on this node, so getRemote() is safe.
margs.add("-Dmaven.repo.local="+localRepo.getRemote());

String settingsPath = SettingsProvider.getSettingsRemotePath(mms.getSettings(), MavenBuild.this, listener);
if (settingsPath != null) {
margs.add("-s").add(settingsPath);
}

margs.add("-f",getModuleRoot().child("pom.xml").getRemote());
margs.addTokenized(getProject().getGoals());

Map<String,String> systemProps = new HashMap<String, String>(envVars);
// backward compatibility
systemProps.put("hudson.build.number",String.valueOf(getNumber()));

ProxyImpl proxy;
if (mavenBuildInformation.isMaven3OrLater())
{
ProxyImpl2 proxy2 = new ProxyImpl2(mms.getLastCompletedBuild(), slistener);
proxy2.setBlockBuildEvents(true);
proxy = proxy2;
builder = new Maven3Builder(createRequest(proxy2,
getProject(), margs.toList(), systemProps,
mavenBuildInformation));
}
else {
proxy = new ProxyImpl();
builder = new Builder(
listener, proxy,
getProject(), margs.toList(), systemProps);
}
Result r = process.call(builder);
proxy.performArchiving(launcher, listener);
normalExit = true;
return r;
} finally {
builder.end(launcher);
if(normalExit) process.recycle();
else process.discard();

if (builder != null) {
builder.end(launcher);
}

if (process != null) {
if(normalExit) process.recycle();
else process.discard();
}

// tear down in reverse order
boolean failed=false;
for( int i=buildEnvironments.size()-1; i>=0; i-- ) {
if (!buildEnvironments.get(i).tearDown(MavenBuild.this,slistener)) {
final Environment environment = buildEnvironments.get(i);
try {
if (!environment.tearDown(MavenBuild.this,slistener)) {
failed=true;
}
} catch (Throwable inTearDown) {
failed=true;

// exceptions are ignored to give a chance to all environments to tear down
listener.error("Unable to tear down: " + inTearDown.getMessage());
inTearDown.printStackTrace(listener.getLogger());
}
}
// WARNING The return in the finally clause will trump any return before
if (failed) return Result.FAILURE;
if (!normalExit && failed) return Result.FAILURE;
}
}

Expand Down
48 changes: 48 additions & 0 deletions src/test/java/hudson/maven/MavenBuildTest.java
Expand Up @@ -4,8 +4,10 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotNull;
import hudson.Extension;
import hudson.Launcher;
import hudson.maven.MavenBuildProxy.BuildCallable;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Action;
import hudson.model.BallColor;
Expand All @@ -14,28 +16,36 @@
import hudson.model.ParametersDefinitionProperty;
import hudson.model.Result;
import hudson.model.StringParameterDefinition;
import hudson.tasks.BuildWrapper;
import hudson.tasks.BuildWrapperDescriptor;
import hudson.tasks.Builder;
import hudson.tasks.BuildWrapper.Environment;
import hudson.tasks.Maven.MavenInstallation;
import hudson.tasks.test.AbstractTestResultAction;
import hudson.tasks.test.AggregatedTestResultAction;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;

import net.sf.json.JSONObject;

import org.apache.maven.project.MavenProject;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Bug;
import org.jvnet.hudson.test.Email;
import org.jvnet.hudson.test.ExtractResourceSCM;
import org.jvnet.hudson.test.JenkinsRule;
import org.jvnet.hudson.test.JenkinsRule.TestBuildWrapper;
import org.jvnet.hudson.test.SingleFileSCM;
import org.kohsuke.stapler.StaplerRequest;

/**
* @author Kohsuke Kawaguchi
Expand Down Expand Up @@ -357,6 +367,23 @@ public void testActionsOfPreAndPostBuildersMustBeExposed() throws Exception {
final List<TestAction> actions = m.getActions(TestAction.class);
assertEquals(2, actions.size());
}

@Test
public void testBuildWrappersTeardown() throws Exception {
j.configureDefaultMaven();
MavenModuleSet m = j.createMavenProject();
m.setScm(new ExtractResourceSCM(getClass().getResource("multimodule-maven.zip")));
m.setGoals("initialize");

TearingDownBuildWrapper testBuild1Wrapper = new TearingDownBuildWrapper();
TearingDownBuildWrapper testBuild2Wrapper = new TearingDownBuildWrapper();
m.getBuildWrappersList().addAll(Arrays.asList(testBuild1Wrapper, testBuild2Wrapper, new FailingBuildWrapper()));

j.assertBuildStatus(Result.FAILURE, m.scheduleBuild2(0).get());

assertTrue(testBuild1Wrapper.tearDown);
assertTrue(testBuild2Wrapper.tearDown);
}

private static class TestBuilder extends Builder {

Expand All @@ -380,4 +407,25 @@ public boolean projectActionsGotRequested() {
private static class TestAction extends InvisibleAction{
}

private static class FailingBuildWrapper extends BuildWrapper {
@Override
public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException {
return null;
}
}

private static class TearingDownBuildWrapper extends BuildWrapper {
public boolean tearDown;

@Override
public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException {
return new Environment() {
public boolean tearDown(AbstractBuild build, BuildListener listener) {
tearDown = true;

return true;
}
};
}
}
}

0 comments on commit f3f1f11

Please sign in to comment.