提交 1782e10d 编写于 作者: M mdonohue

Fix HUDSON-291

We now add a CauseAction to each job, and a summary.jelly file which renders
the cause on any job with an explanation.


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@15150 71c3de6d-444a-0410-be80-ed276b4c234a
上级 81c16190
......@@ -33,6 +33,7 @@ import hudson.model.JobProperty;
import hudson.model.ParametersAction;
import hudson.model.Queue;
import hudson.model.Result;
import hudson.model.Cause.UpstreamCause;
import hudson.tasks.Publisher;
import java.io.File;
......@@ -172,9 +173,9 @@ public class MatrixBuild extends AbstractBuild<MatrixProject,MatrixBuild> {
logger.println(Messages.MatrixBuild_Triggering(c.getDisplayName()));
ParametersAction parameters = getAction(ParametersAction.class);
if (parameters != null) {
c.scheduleBuild(parameters);
c.scheduleBuild(parameters, new UpstreamCause(MatrixBuild.this));
} else {
c.scheduleBuild();
c.scheduleBuild(new UpstreamCause(MatrixBuild.this));
}
}
......
......@@ -25,6 +25,7 @@ package hudson.matrix;
import hudson.FilePath;
import hudson.model.AbstractBuild;
import hudson.model.Cause;
import hudson.model.DependencyGraph;
import hudson.model.Descriptor;
import hudson.model.Hudson;
......@@ -32,6 +33,7 @@ import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.JDK;
import hudson.model.Label;
import hudson.model.Cause.LegacyCodeCause;
import hudson.model.Node;
import hudson.model.ParameterValue;
import hudson.model.ParameterizedProjectTask;
......@@ -282,9 +284,17 @@ public class MatrixConfiguration extends Project<MatrixConfiguration,MatrixRun>
*/
public static boolean useShortWorkspaceName = Boolean.getBoolean(MatrixConfiguration.class.getName()+".useShortWorkspaceName");
public boolean scheduleBuild(ParametersAction parameters) {
/**
* @deprecated
* Use {@link #scheduleBuild(ParametersAction, Cause)}. Since 1.283
*/
public boolean scheduleBuild(ParametersAction parameters) {
return scheduleBuild(parameters, new LegacyCodeCause());
}
public boolean scheduleBuild(ParametersAction parameters, Cause c) {
return Hudson.getInstance().getQueue().add(
new ParameterizedProjectTask(this, parameters.getParameters()), getQuietPeriod());
new ParameterizedProjectTask(this, parameters.getParameters(), c), getQuietPeriod());
}
}
......@@ -33,6 +33,7 @@ import hudson.model.DependencyGraph;
import hudson.model.Hudson;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.Cause.UpstreamCause;
import hudson.remoting.Channel;
import hudson.scm.ChangeLogSet;
import hudson.scm.ChangeLogSet.Entry;
......@@ -577,7 +578,7 @@ public class MavenBuild extends AbstractBuild<MavenModule,MavenBuild> {
if(trigger) {
listener.getLogger().println(Messages.MavenBuild_Triggering(down.getName()));
downstreams.add(down);
down.scheduleBuild();
down.scheduleBuild(new UpstreamCause(this));
}
}
}
......
......@@ -41,6 +41,7 @@ import hudson.model.Fingerprint;
import hudson.model.Hudson;
import hudson.model.Result;
import hudson.model.ParametersAction;
import hudson.model.Cause.UpstreamCause;
import hudson.remoting.Channel;
import hudson.remoting.VirtualChannel;
import hudson.util.ArgumentListBuilder;
......@@ -309,7 +310,7 @@ public final class MavenModuleSetBuild extends AbstractBuild<MavenModuleSet,Mave
if(!project.isAggregatorStyleBuild()) {
// start module builds
logger.println("Triggering "+project.getRootModule().getModuleName());
project.getRootModule().scheduleBuild();
project.getRootModule().scheduleBuild(new UpstreamCause(MavenModuleSetBuild.this));
} else {
// do builds here
try {
......@@ -492,7 +493,7 @@ public final class MavenModuleSetBuild extends AbstractBuild<MavenModuleSet,Mave
if(getResult().isBetterOrEqualTo(Result.SUCCESS)) {
for(AbstractProject down : getProject().getDownstreamProjects()) {
listener.getLogger().println(Messages.MavenBuild_Triggering(down.getName()));
down.scheduleBuild();
down.scheduleBuild(new UpstreamCause(MavenModuleSetBuild.this));
}
}
}
......
......@@ -28,6 +28,8 @@ import hudson.FeedAdapter;
import hudson.FilePath;
import hudson.Launcher;
import hudson.maven.MavenModule;
import hudson.model.Cause.UserCause;
import hudson.model.Cause.LegacyCodeCause;
import hudson.model.Descriptor.FormException;
import hudson.model.Fingerprint.RangeSet;
import hudson.model.RunMap.Constructor;
......@@ -415,6 +417,22 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
Hudson.getInstance().rebuildDependencyGraph();
}
/**
* @deprecated
* Use {@link #scheduleBuild(Cause)}. Since 1.283
*/
public boolean scheduleBuild() {
return scheduleBuild(new LegacyCodeCause());
}
/**
* @deprecated
* Use {@link #scheduleBuild(int, Cause)}. Since 1.283
*/
public boolean scheduleBuild(int quietPeriod) {
return scheduleBuild(quietPeriod, new LegacyCodeCause());
}
/**
* Schedules a build of this project.
*
......@@ -423,19 +441,19 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
* false if the queue contained it and therefore the add()
* was noop
*/
public boolean scheduleBuild() {
return scheduleBuild(getQuietPeriod());
public boolean scheduleBuild(Cause c) {
return scheduleBuild(getQuietPeriod(), c);
}
public boolean scheduleBuild(int quietPeriod) {
public boolean scheduleBuild(int quietPeriod, Cause c) {
if (isDisabled())
return false;
if (isParameterized())
return Hudson.getInstance().getQueue().add(
new ParameterizedProjectTask(this, getDefaultParametersValues()), quietPeriod);
new ParameterizedProjectTask(this, getDefaultParametersValues(), c), quietPeriod);
else
return Hudson.getInstance().getQueue().add(this, quietPeriod);
return Hudson.getInstance().getQueue().add(new ParameterizedProjectTask(this, c), quietPeriod);
}
private List<ParameterValue> getDefaultParametersValues() {
......@@ -460,11 +478,19 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
return defValues;
}
/**
* @deprecated
* Use {@link #scheduleBuild2(int, Cause)}. Since 1.283
*/
public Future<R> scheduleBuild2(int quietPeriod) {
return scheduleBuild2(quietPeriod, new LegacyCodeCause());
}
/**
* Schedules a build of this project, and returns a {@link Future} object
* to wait for the completion of the build.
*/
public Future<R> scheduleBuild2(int quietPeriod) {
public Future<R> scheduleBuild2(int quietPeriod, Cause c) {
R lastBuild = getLastBuild();
final int n;
if(lastBuild!=null) n = lastBuild.getNumber();
......@@ -483,7 +509,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
{ r.register(); }
};
scheduleBuild(quietPeriod);
scheduleBuild(quietPeriod, c);
return f;
}
......@@ -990,13 +1016,16 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
// TODO: more unit handling
if(delay.endsWith("sec")) delay=delay.substring(0,delay.length()-3);
if(delay.endsWith("secs")) delay=delay.substring(0,delay.length()-4);
Hudson.getInstance().getQueue().add(this, Integer.parseInt(delay));
Hudson.getInstance().getQueue().add(
new ParameterizedProjectTask(this, new UserCause()),
Integer.parseInt(delay)
);
} catch (NumberFormatException e) {
throw new ServletException("Invalid delay parameter value: "+delay);
}
}
} else {
scheduleBuild();
scheduleBuild(new UserCause());
}
rsp.forwardToPreviousPage(req);
}
......
......@@ -35,6 +35,16 @@ import hudson.model.Queue.Task;
* @author Kohsuke Kawaguchi
*/
public interface BuildableItem extends Item, Task {
/**
* @deprecated
* Use {@link #scheduleBuild(Cause)}. Since 1.283
*/
boolean scheduleBuild();
boolean scheduleBuild(int quietPeriod);
boolean scheduleBuild(Cause c);
/**
* @deprecated
* Use {@link #scheduleBuild(int, Cause)}. Since 1.283
*/
boolean scheduleBuild(int quietPeriod);
boolean scheduleBuild(int quietPeriod, Cause c);
}
package hudson.model;
import hudson.triggers.Trigger;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;
/**
* Cause object base class. This class hierarchy is used to keep track of why
* a given build was started. The Cause object is connected to a build via the
* CauseAction object.
*
* @author Michael Donohue
*/
public abstract class Cause {
abstract public String getShortDescription();
@ExportedBean
public static class LegacyCodeCause extends Cause {
private StackTraceElement [] stackTrace;
public LegacyCodeCause() {
stackTrace = new Exception().getStackTrace();
}
@Override
@Exported
public String getShortDescription() {
return "Legacy code started this job. No cause information is available";
}
}
@ExportedBean
public static class UpstreamCause extends Cause {
private String upstreamProject;
private int upstreamBuild;
private Cause upstreamCause;
public UpstreamCause(AbstractBuild<?, ?> up) {
upstreamBuild = up.getNumber();
upstreamProject = up.getProject().getName();
CauseAction ca = up.getAction(CauseAction.class);
upstreamCause = ca == null ? null : ca.getCause();
}
@Override
@Exported
public String getShortDescription() {
return "Started by upstream project \"" + upstreamProject + "\" build number " + upstreamBuild;
}
}
@ExportedBean
public static class UserCause extends Cause {
private String authenticationName;
public UserCause() {
this.authenticationName = Hudson.getAuthentication().getName();
}
@Override
@Exported
public String getShortDescription() {
return "Started by user " + authenticationName;
}
}
}
package hudson.model;
public class CauseAction implements Action {
private Cause cause;
public Cause getCause() {
return cause;
}
public String getShortDescription() {
return cause.getShortDescription();
}
public CauseAction(Cause c) {
this.cause = c;
}
public String getDisplayName() {
return "Cause";
}
public String getIconFileName() {
// no icon
return null;
}
public String getUrlName() {
return "cause";
}
}
......@@ -42,7 +42,8 @@ public class ParameterizedProjectTask extends QueueTaskFilter {
private final AbstractProject<?,?> project;
private final List<ParameterValue> parameters;
private final Cause cause;
private static long COUNTER = System.currentTimeMillis();
/**
......@@ -50,12 +51,25 @@ public class ParameterizedProjectTask extends QueueTaskFilter {
*/
private final String key = Long.toString(COUNTER++);
/**
* @deprecated
* Use {@link #ParameterizedProjectTask(AbstractProject, List, Cause)}. Since 1.283
*/
public ParameterizedProjectTask(AbstractProject<?,?> project, List<ParameterValue> parameters) {
this(project, parameters, new Cause.LegacyCodeCause());
}
public ParameterizedProjectTask(AbstractProject<?,?> project, List<ParameterValue> parameters, Cause c) {
super(project);
this.project = project;
this.parameters = parameters;
this.cause = c;
}
public ParameterizedProjectTask(AbstractProject<?,?> project, Cause c) {
this(project, null, c);
}
public AbstractProject<?, ?> getProject() {
return project;
}
......@@ -67,8 +81,9 @@ public class ParameterizedProjectTask extends QueueTaskFilter {
@Override
public Executable createExecutable() throws IOException {
AbstractBuild<?, ?> build = project.createExecutable();
build.addAction(new ParametersAction(parameters, build));
if(parameters != null)
build.addAction(new ParametersAction(parameters, build));
build.addAction(new CauseAction(cause));
return build;
}
......@@ -85,6 +100,7 @@ public class ParameterizedProjectTask extends QueueTaskFilter {
@Override
public int hashCode() {
// cause is NOT included so distinct causes won't schedule duplicate builds
final int prime = 31;
int result = 1;
result = prime * result
......@@ -95,6 +111,7 @@ public class ParameterizedProjectTask extends QueueTaskFilter {
@Override
public boolean equals(Object obj) {
// cause is NOT included so distinct causes won't schedule duplicate builds
if (this == obj)
return true;
if (obj == null)
......
......@@ -98,7 +98,7 @@ public class ParametersDefinitionProperty extends JobProperty<AbstractProject<?,
}
Hudson.getInstance().getQueue().add(
new ParameterizedProjectTask(owner, values), 0);
new ParameterizedProjectTask(owner, values, new Cause.UserCause()), 0);
// send the user back to the job top page.
rsp.sendRedirect(".");
......@@ -116,7 +116,7 @@ public class ParametersDefinitionProperty extends JobProperty<AbstractProject<?,
}
Hudson.getInstance().getQueue().add(
new ParameterizedProjectTask(owner, values), 0);
new ParameterizedProjectTask(owner, values, new Cause.UserCause()), 0);
// send the user back to the job top page.
rsp.sendRedirect(".");
......
......@@ -40,6 +40,7 @@ import hudson.model.Items;
import hudson.model.Job;
import hudson.model.Project;
import hudson.model.Result;
import hudson.model.Cause.UpstreamCause;
import hudson.model.listeners.ItemListener;
import hudson.util.FormFieldValidator;
import net.sf.json.JSONObject;
......@@ -164,7 +165,7 @@ public class BuildTrigger extends Publisher implements DependecyDeclarer, Matrix
// this is not completely accurate, as a new build might be triggered
// between these calls
String name = p.getName()+" #"+p.getNextBuildNumber();
if(p.scheduleBuild()) {
if(p.scheduleBuild(new UpstreamCause(build))) {
logger.println(Messages.BuildTrigger_Triggering(name));
} else {
logger.println(Messages.BuildTrigger_InQueue(name));
......
......@@ -27,6 +27,7 @@ import antlr.ANTLRException;
import hudson.Util;
import hudson.model.AbstractProject;
import hudson.model.Action;
import hudson.model.Cause;
import hudson.model.Hudson;
import hudson.model.Item;
import hudson.model.Project;
......@@ -36,6 +37,8 @@ import hudson.util.StreamTaskListener;
import hudson.util.TimeUnit2;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;
import java.io.File;
import java.io.IOException;
......@@ -435,7 +438,7 @@ public class SCMTrigger extends Trigger<SCMedItem> {
if(foundChanges) {
String name = " #"+job.asProject().getNextBuildNumber();
if(job.scheduleBuild()) {
if(job.scheduleBuild(new SCMTriggerCause())) {
LOGGER.info("SCM changes detected in "+ job.getName()+". Triggering "+name);
} else {
LOGGER.info("SCM changes detected in "+ job.getName()+". Job is already in the queue");
......@@ -448,6 +451,17 @@ public class SCMTrigger extends Trigger<SCMedItem> {
}
}
@ExportedBean
public static class SCMTriggerCause extends Cause {
@Override
@Exported
public String getShortDescription() {
return "A SCM change trigger started this job";
}
}
/**
* How long is too long for a polling activity to be in the queue?
*/
......
......@@ -25,6 +25,7 @@ package hudson.triggers;
import static hudson.Util.fixNull;
import hudson.model.BuildableItem;
import hudson.model.Cause;
import hudson.model.Item;
import hudson.scheduler.CronTabList;
import hudson.util.FormFieldValidator;
......@@ -36,6 +37,8 @@ import javax.servlet.ServletException;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.export.Exported;
import org.kohsuke.stapler.export.ExportedBean;
import antlr.ANTLRException;
......@@ -52,7 +55,7 @@ public class TimerTrigger extends Trigger<BuildableItem> {
}
public void run() {
job.scheduleBuild(0);
job.scheduleBuild(0, new TimerTriggerCause());
}
public TriggerDescriptor getDescriptor() {
......@@ -95,4 +98,15 @@ public class TimerTrigger extends Trigger<BuildableItem> {
}.process();
}
}
@ExportedBean
public static class TimerTriggerCause extends Cause {
@Override
@Exported
public String getShortDescription() {
return "A timer trigger started this job";
}
}
}
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form">
<t:summary icon="orange-square.gif">
<p>${it.shortDescription}</p>
</t:summary>
</j:jelly>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册