提交 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> {
public void post(BuildListener listener) {
}
public void cleanUp(BuildListener listener) {
}
});
}
}
......@@ -347,7 +350,9 @@ public class MavenBuild extends AbstractBuild<MavenModule,MavenBuild> {
public void post2(BuildListener listener) throws Exception {
for (MavenReporter reporter : reporters)
reporter.end(MavenBuild.this,launcher,listener);
}
public void cleanUp(BuildListener listener) throws Exception {
if(getResult().isBetterOrEqualTo(Result.SUCCESS))
scheduleDownstreamBuilds(listener,new HashSet<AbstractProject>());
}
......
......@@ -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()) {
// schedule downstream builds. for non aggregator style builds,
// this is done by each module
......
......@@ -260,6 +260,10 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
culprits = r;
}
}
public void cleanUp(BuildListener listener) throws Exception {
// default is no-op
}
}
/**
......
......@@ -4,6 +4,7 @@ import hudson.tasks.BuildStep;
import hudson.tasks.BuildWrapper;
import hudson.tasks.BuildWrapper.Environment;
import hudson.tasks.Builder;
import hudson.tasks.Publisher;
import hudson.triggers.SCMTrigger;
import java.io.File;
......@@ -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 {
// run all of them even if one of them failed
for( BuildStep bs : project.getPublishers().values() )
bs.perform(Build.this, launcher, listener);
for( BuildStep bs : project.getProperties().values() )
bs.perform(Build.this, launcher, listener);
performAllBuildStep(listener, project.getPublishers(),true);
performAllBuildStep(listener, project.getProperties(),true);
}
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 {
......
......@@ -45,6 +45,10 @@ public class ExternalRun extends Run<ExternalJob,ExternalRun> {
public void post(BuildListener listener) {
// do nothing
}
public void cleanUp(BuildListener listener) {
// do nothing
}
});
}
......@@ -94,6 +98,10 @@ public class ExternalRun extends Run<ExternalJob,ExternalRun> {
public void post(BuildListener listener) {
// do nothing
}
public void cleanUp(BuildListener listener) {
// do nothing
}
});
if(duration[0]!=0) {
......
......@@ -569,7 +569,7 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
/**
* Performs the post-build action.
*
* <p>
* This method is called after the status of the build is determined.
* 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
......@@ -578,6 +578,18 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* by {@link Job#getLastSuccessfulBuild()}.
*/
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
if(result!=null)
return; // already built.
BuildListener listener=null;
PrintStream log = null;
onStartBuilding();
try {
// to set the state to COMPLETE in the end, even if the thread dies abnormally.
// otherwise the queue state becomes inconsistent
long start = System.currentTimeMillis();
BuildListener listener=null;
PrintStream log = null;
try {
try {
......@@ -633,21 +646,35 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
handleFatalBuildProblem(listener,e);
result = Result.FAILURE;
} 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();
duration = end-start;
RunListener.fireCompleted(this,listener);
if(listener!=null)
listener.finished(result);
if(log!=null)
log.close();
if(listener!=null)
listener.finished(result);
if(log!=null)
log.close();
try {
save();
} catch (IOException e) {
e.printStackTrace();
try {
save();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
......
......@@ -108,6 +108,11 @@ public class BuildTrigger extends Publisher {
return true;
}
@Override
public boolean needsToRunAfterFinalized() {
return true;
}
/**
* Called from {@link Job#renameTo(String)} when a job is renamed.
*
......
package hudson.tasks;
import hudson.ExtensionPoint;
import hudson.Launcher;
import hudson.model.Action;
import hudson.model.Build;
import hudson.model.BuildListener;
import hudson.model.Describable;
import hudson.model.Project;
import hudson.model.AbstractBuild;
/**
* {@link BuildStep}s that run after the build is completed.
......@@ -33,4 +35,32 @@ public abstract class Publisher extends BuildStepCompatibilityLayer implements B
public Action getProjectAction(Project project) {
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.
先完成此消息的编辑!
想要评论请 注册