提交 9ecc4a9a 编写于 作者: K kohsuke

Fixed #980. added one more phase to the build, namely the cleanUp method. This...

Fixed #980. added one more phase to the build, namely the cleanUp method. This is where you can perform things after the build is marked as completed.


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@5745 71c3de6d-444a-0410-be80-ed276b4c234a
上级 400dc7ab
...@@ -290,6 +290,9 @@ public class MavenBuild extends AbstractBuild<MavenModule,MavenBuild> { ...@@ -290,6 +290,9 @@ public class MavenBuild extends AbstractBuild<MavenModule,MavenBuild> {
public void post(BuildListener listener) { public void post(BuildListener listener) {
} }
public void cleanUp(BuildListener listener) {
}
}); });
} }
} }
...@@ -347,7 +350,9 @@ public class MavenBuild extends AbstractBuild<MavenModule,MavenBuild> { ...@@ -347,7 +350,9 @@ public class MavenBuild extends AbstractBuild<MavenModule,MavenBuild> {
public void post2(BuildListener listener) throws Exception { public void post2(BuildListener listener) throws Exception {
for (MavenReporter reporter : reporters) for (MavenReporter reporter : reporters)
reporter.end(MavenBuild.this,launcher,listener); reporter.end(MavenBuild.this,launcher,listener);
}
public void cleanUp(BuildListener listener) throws Exception {
if(getResult().isBetterOrEqualTo(Result.SUCCESS)) if(getResult().isBetterOrEqualTo(Result.SUCCESS))
scheduleDownstreamBuilds(listener,new HashSet<AbstractProject>()); scheduleDownstreamBuilds(listener,new HashSet<AbstractProject>());
} }
......
...@@ -333,7 +333,12 @@ public final class MavenModuleSetBuild extends AbstractBuild<MavenModuleSet,Mave ...@@ -333,7 +333,12 @@ public final class MavenModuleSetBuild extends AbstractBuild<MavenModuleSet,Mave
} }
} }
public void post2(BuildListener listener) throws Exception { protected void post2(BuildListener listener) throws Exception {
// no op
}
@Override
public void cleanUp(BuildListener listener) throws Exception {
if(project.isAggregatorStyleBuild()) { if(project.isAggregatorStyleBuild()) {
// schedule downstream builds. for non aggregator style builds, // schedule downstream builds. for non aggregator style builds,
// this is done by each module // this is done by each module
......
...@@ -260,6 +260,10 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs ...@@ -260,6 +260,10 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
culprits = r; culprits = r;
} }
} }
public void cleanUp(BuildListener listener) throws Exception {
// default is no-op
}
} }
/** /**
......
...@@ -4,6 +4,7 @@ import hudson.tasks.BuildStep; ...@@ -4,6 +4,7 @@ import hudson.tasks.BuildStep;
import hudson.tasks.BuildWrapper; import hudson.tasks.BuildWrapper;
import hudson.tasks.BuildWrapper.Environment; import hudson.tasks.BuildWrapper.Environment;
import hudson.tasks.Builder; import hudson.tasks.Builder;
import hudson.tasks.Publisher;
import hudson.triggers.SCMTrigger; import hudson.triggers.SCMTrigger;
import java.io.File; import java.io.File;
...@@ -133,11 +134,21 @@ public abstract class Build <P extends Project<P,B>,B extends Build<P,B>> ...@@ -133,11 +134,21 @@ public abstract class Build <P extends Project<P,B>,B extends Build<P,B>>
} }
public void post2(BuildListener listener) throws IOException, InterruptedException { public void post2(BuildListener listener) throws IOException, InterruptedException {
// run all of them even if one of them failed performAllBuildStep(listener, project.getPublishers(),true);
for( BuildStep bs : project.getPublishers().values() ) performAllBuildStep(listener, project.getProperties(),true);
bs.perform(Build.this, launcher, listener); }
for( BuildStep bs : project.getProperties().values() )
bs.perform(Build.this, launcher, listener); public void cleanUp(BuildListener listener) throws Exception {
performAllBuildStep(listener, project.getPublishers(),false);
performAllBuildStep(listener, project.getProperties(),false);
}
// run all of them even if one of them failed
private void performAllBuildStep(BuildListener listener, Map<?, ? extends BuildStep> buildSteps, boolean phase) throws InterruptedException, IOException {
for( BuildStep bs : buildSteps.values() ) {
if( (bs instanceof Publisher && ((Publisher)bs).needsToRunAfterFinalized()) ^ phase)
bs.perform(Build.this, launcher, listener);
}
} }
private boolean build(BuildListener listener, Map<?, Builder> steps) throws IOException, InterruptedException { private boolean build(BuildListener listener, Map<?, Builder> steps) throws IOException, InterruptedException {
......
...@@ -45,6 +45,10 @@ public class ExternalRun extends Run<ExternalJob,ExternalRun> { ...@@ -45,6 +45,10 @@ public class ExternalRun extends Run<ExternalJob,ExternalRun> {
public void post(BuildListener listener) { public void post(BuildListener listener) {
// do nothing // do nothing
} }
public void cleanUp(BuildListener listener) {
// do nothing
}
}); });
} }
...@@ -94,6 +98,10 @@ public class ExternalRun extends Run<ExternalJob,ExternalRun> { ...@@ -94,6 +98,10 @@ public class ExternalRun extends Run<ExternalJob,ExternalRun> {
public void post(BuildListener listener) { public void post(BuildListener listener) {
// do nothing // do nothing
} }
public void cleanUp(BuildListener listener) {
// do nothing
}
}); });
if(duration[0]!=0) { if(duration[0]!=0) {
......
...@@ -569,7 +569,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run ...@@ -569,7 +569,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
/** /**
* Performs the post-build action. * Performs the post-build action.
* * <p>
* This method is called after the status of the build is determined. * This method is called after the status of the build is determined.
* This is a good opportunity to do notifications based on the result * This is a good opportunity to do notifications based on the result
* of the build. When this method is called, the build is not really * of the build. When this method is called, the build is not really
...@@ -578,6 +578,18 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run ...@@ -578,6 +578,18 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* by {@link Job#getLastSuccessfulBuild()}. * by {@link Job#getLastSuccessfulBuild()}.
*/ */
void post( BuildListener listener ) throws Exception; void post( BuildListener listener ) throws Exception;
/**
* Performs final clean up action.
* <p>
* This method is called after {@link #post(BuildListener)},
* after the build result is fully finalized. This is the point
* where the build is already considered completed.
* <p>
* Among other things, this is often a necessary pre-condition
* before invoking other builds that depend on this build.
*/
void cleanUp(BuildListener listener) throws Exception;
} }
/** /**
...@@ -591,14 +603,15 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run ...@@ -591,14 +603,15 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
if(result!=null) if(result!=null)
return; // already built. return; // already built.
BuildListener listener=null;
PrintStream log = null;
onStartBuilding(); onStartBuilding();
try { try {
// to set the state to COMPLETE in the end, even if the thread dies abnormally. // to set the state to COMPLETE in the end, even if the thread dies abnormally.
// otherwise the queue state becomes inconsistent // otherwise the queue state becomes inconsistent
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
BuildListener listener=null;
PrintStream log = null;
try { try {
try { try {
...@@ -633,21 +646,35 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run ...@@ -633,21 +646,35 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
handleFatalBuildProblem(listener,e); handleFatalBuildProblem(listener,e);
result = Result.FAILURE; result = Result.FAILURE;
} finally { } finally {
RunListener.fireCompleted(this,listener); long end = System.currentTimeMillis();
} duration = end-start;
// mark the state as completed.
// the significance of doing this is that Hudson
// will now see this build as completed.
// things like triggering other builds requires this as pre-condition.
// see issue #980.
state = State.COMPLETED;
try {
job.cleanUp(listener);
} catch (Exception e) {
handleFatalBuildProblem(listener,e);
// too late to update the result now
}
long end = System.currentTimeMillis(); RunListener.fireCompleted(this,listener);
duration = end-start;
if(listener!=null) if(listener!=null)
listener.finished(result); listener.finished(result);
if(log!=null) if(log!=null)
log.close(); log.close();
try { try {
save(); save();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
}
} }
try { try {
......
...@@ -108,6 +108,11 @@ public class BuildTrigger extends Publisher { ...@@ -108,6 +108,11 @@ public class BuildTrigger extends Publisher {
return true; return true;
} }
@Override
public boolean needsToRunAfterFinalized() {
return true;
}
/** /**
* Called from {@link Job#renameTo(String)} when a job is renamed. * Called from {@link Job#renameTo(String)} when a job is renamed.
* *
......
package hudson.tasks; package hudson.tasks;
import hudson.ExtensionPoint; import hudson.ExtensionPoint;
import hudson.Launcher;
import hudson.model.Action; import hudson.model.Action;
import hudson.model.Build; import hudson.model.Build;
import hudson.model.BuildListener; import hudson.model.BuildListener;
import hudson.model.Describable; import hudson.model.Describable;
import hudson.model.Project; import hudson.model.Project;
import hudson.model.AbstractBuild;
/** /**
* {@link BuildStep}s that run after the build is completed. * {@link BuildStep}s that run after the build is completed.
...@@ -33,4 +35,32 @@ public abstract class Publisher extends BuildStepCompatibilityLayer implements B ...@@ -33,4 +35,32 @@ public abstract class Publisher extends BuildStepCompatibilityLayer implements B
public Action getProjectAction(Project project) { public Action getProjectAction(Project project) {
return null; return null;
} }
/**
* Returne true if this {@link Publisher} needs to run after the build result is
* fully finalized.
*
* <p>
* The execution of normal {@link Publisher}s are considered within a part
* of the build. This allows publishers to mark the build as a failure, or
* to include their execution time in the total build time.
*
* <p>
* So normally, that is the preferrable behavior, but in a few cases
* this is problematic. One of such cases is when a publisher needs to
* trigger other builds, whcih in turn need to see this build as a
* completed build. Those plugins that need to do this can return true
* from this method, so that the {@link #perform(AbstractBuild, Launcher, BuildListener)}
* method is called after the build is marked as completed.
*
* <p>
* When {@link Publisher} behaves this way, note that they can no longer
* change the build status anymore.
*
* @author Kohsuke Kawaguchi
* @since 1.153
*/
public boolean needsToRunAfterFinalized() {
return false;
}
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册