提交 6296bad3 编写于 作者: K kohsuke

changed the Trigger design so that it can be applied to different kind of Jobs selectively.


git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@2095 71c3de6d-444a-0410-be80-ed276b4c234a
上级 95955521
......@@ -14,6 +14,7 @@ import hudson.model.Job;
import hudson.model.TaskListener;
import hudson.model.TopLevelItem;
import hudson.model.TopLevelItemDescriptor;
import hudson.model.SCMedItem;
import hudson.util.CopyOnWriteMap;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
......@@ -37,7 +38,7 @@ import java.util.Set;
*
* @author Kohsuke Kawaguchi
*/
public final class MavenModuleSet extends AbstractProject<MavenModuleSet,MavenModuleSetBuild> implements TopLevelItem, ItemGroup<MavenModule> {
public final class MavenModuleSet extends AbstractProject<MavenModuleSet,MavenModuleSetBuild> implements TopLevelItem, ItemGroup<MavenModule>, SCMedItem {
/**
* All {@link MavenModule}s, keyed by their {@link MavenModule#getModuleName()} module name}s.
*/
......@@ -219,6 +220,10 @@ public final class MavenModuleSet extends AbstractProject<MavenModuleSet,MavenMo
return rootPOM;
}
public AbstractProject<?,?> asProject() {
return this;
}
/**
* Gets the list of goals to execute.
*/
......
......@@ -12,6 +12,7 @@ import hudson.scm.SCM;
import hudson.scm.SCMS;
import hudson.triggers.Trigger;
import hudson.triggers.Triggers;
import hudson.triggers.TriggerDescriptor;
import hudson.util.EditDistance;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
......@@ -94,7 +95,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
/**
* List of all {@link Trigger}s for this project.
*/
protected List<Trigger> triggers = new Vector<Trigger>();
protected List<Trigger<?>> triggers = new Vector<Trigger<?>>();
protected AbstractProject(ItemGroup parent, String name) {
super(parent,name);
......@@ -119,7 +120,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
if(triggers==null)
// it didn't exist in < 1.28
triggers = new Vector<Trigger>();
triggers = new Vector<Trigger<?>>();
for (Trigger t : triggers)
t.start(this,false);
}
......@@ -314,11 +315,11 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
/**
* Adds a new {@link Trigger} to this {@link Project} if not active yet.
*/
public void addTrigger(Trigger trigger) throws IOException {
public void addTrigger(Trigger<?> trigger) throws IOException {
addToList(trigger,triggers);
}
public void removeTrigger(Descriptor<Trigger> trigger) throws IOException {
public void removeTrigger(TriggerDescriptor trigger) throws IOException {
removeFromList(trigger,triggers);
}
......@@ -349,8 +350,8 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
}
}
public synchronized Map<Descriptor<Trigger>,Trigger> getTriggers() {
return Descriptor.toMap(triggers);
public synchronized Map<TriggerDescriptor,Trigger> getTriggers() {
return (Map)Descriptor.toMap(triggers);
}
//
......@@ -474,7 +475,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
for (Trigger t : triggers)
t.stop();
buildDescribable(req, Triggers.TRIGGERS, triggers, "trigger");
buildDescribable(req, Triggers.getApplicableTriggers(this), triggers, "trigger");
for (Trigger t : triggers)
t.start(this,true);
} catch (FormException e) {
......@@ -482,7 +483,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
}
}
protected final <T extends Describable<T>> void buildDescribable(StaplerRequest req, List<Descriptor<T>> descriptors, List<T> result, String prefix)
protected final <T extends Describable<T>> void buildDescribable(StaplerRequest req, List<? extends Descriptor<T>> descriptors, List<T> result, String prefix)
throws FormException {
result.clear();
......
......@@ -30,6 +30,7 @@ import hudson.tasks.Mailer;
import hudson.tasks.Publisher;
import hudson.triggers.Trigger;
import hudson.triggers.Triggers;
import hudson.triggers.TriggerDescriptor;
import hudson.util.CopyOnWriteList;
import hudson.util.CopyOnWriteMap;
import hudson.util.FormFieldValidator;
......@@ -238,15 +239,15 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node
/**
* Gets the trigger descriptor by name. Primarily used for making them web-visible.
*/
public Descriptor<Trigger> getTrigger(String shortClassName) {
return findDescriptor(shortClassName, Triggers.TRIGGERS);
public TriggerDescriptor getTrigger(String shortClassName) {
return (TriggerDescriptor)findDescriptor(shortClassName, Triggers.TRIGGERS);
}
/**
* Finds a descriptor that has the specified name.
*/
private <T extends Describable<T>>
Descriptor<T> findDescriptor(String shortClassName, Collection<Descriptor<T>> descriptors) {
Descriptor<T> findDescriptor(String shortClassName, Collection<? extends Descriptor<T>> descriptors) {
String name = '.'+shortClassName;
for (Descriptor<T> d : descriptors) {
if(d.clazz.getName().endsWith(name))
......@@ -905,7 +906,7 @@ public final class Hudson extends View implements ItemGroup<TopLevelItem>, Node
for( Descriptor<SCM> scmd : SCMS.SCMS )
result &= scmd.configure(req);
for( Descriptor<Trigger> d : Triggers.TRIGGERS )
for( TriggerDescriptor d : Triggers.TRIGGERS )
result &= d.configure(req);
for( JobPropertyDescriptor d : Jobs.PROPERTIES )
......
......@@ -29,7 +29,7 @@ import java.util.Vector;
*
* @author Kohsuke Kawaguchi
*/
public class Project extends AbstractProject<Project,Build> implements TopLevelItem {
public class Project extends AbstractProject<Project,Build> implements TopLevelItem, SCMedItem {
/**
* List of active {@link Builder}s configured for this project.
......@@ -72,6 +72,10 @@ public class Project extends AbstractProject<Project,Build> implements TopLevelI
updateTransientActions();
}
public AbstractProject<?, ?> asProject() {
return this;
}
@Override
public Hudson getParent() {
return Hudson.getInstance();
......
package hudson.model;
import hudson.scm.SCM;
import hudson.triggers.SCMTrigger;
/**
* {@link Item}s that has associated SCM.
*
* @author Kohsuke Kawaguchi
* @see SCMTrigger
*/
public interface SCMedItem extends BuildableItem {
/**
* Gets the {@link SCM} for this item.
*
* @return
* may return null for indicating "no SCM".
*/
SCM getScm();
/**
* {@link SCMedItem} needs to be an instance of
* {@link AbstractProject}.
*
* This method does {@code (AbstractProject)this} but emphasizes
* the fact that this cast must be doable.
*/
AbstractProject<?,?> asProject();
/**
* Checks if there's any update in SCM, and returns true if any is found.
*
* <p>
* The caller is responsible for coordinating the mutual exclusion between
* a build and polling, as both touches the workspace.
*/
boolean pollSCMChanges( TaskListener listener );
}
......@@ -5,8 +5,9 @@ import hudson.Util;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Action;
import hudson.model.Descriptor;
import hudson.model.Item;
import hudson.model.Project;
import hudson.model.SCMedItem;
import hudson.model.TaskListener;
import hudson.util.StreamTaskListener;
import org.kohsuke.stapler.StaplerRequest;
......@@ -30,7 +31,7 @@ import java.util.logging.Logger;
*
* @author Kohsuke Kawaguchi
*/
public class SCMTrigger extends Trigger {
public class SCMTrigger extends Trigger<SCMedItem> {
/**
* If we'd like to run another polling run, this is set to true.
*
......@@ -96,7 +97,7 @@ public class SCMTrigger extends Trigger {
* Start polling if it's scheduled.
*/
public synchronized void startPolling() {
AbstractBuild b = (AbstractBuild)project.getLastBuild();
AbstractBuild b = job.asProject().getLastBuild();
if(b!=null && b.isBuilding())
return; // build in progress
......@@ -115,16 +116,16 @@ public class SCMTrigger extends Trigger {
* Returns the file that records the last/current polling activity.
*/
public File getLogFile() {
return new File(project.getRootDir(),"scm-polling.log");
return new File(job.getRootDir(),"scm-polling.log");
}
public Descriptor<Trigger> getDescriptor() {
public TriggerDescriptor getDescriptor() {
return DESCRIPTOR;
}
public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl();
public static final class DescriptorImpl extends Descriptor<Trigger> {
public static final class DescriptorImpl extends TriggerDescriptor {
/**
* Used to control the execution of the polling tasks.
*/
......@@ -143,6 +144,10 @@ public class SCMTrigger extends Trigger {
update();
}
public boolean isApplicable(Item item) {
return item instanceof SCMedItem;
}
public ExecutorService getExecutor() {
return executor;
}
......@@ -209,7 +214,7 @@ public class SCMTrigger extends Trigger {
*/
public final class SCMAction implements Action {
public AbstractProject<?,?> getOwner() {
return project;
return job.asProject();
}
public String getIconFileName() {
......@@ -217,7 +222,7 @@ public class SCMTrigger extends Trigger {
}
public String getDisplayName() {
return project.getScm().getDescriptor().getDisplayName()+" Polling Log";
return job.getScm().getDescriptor().getDisplayName()+" Polling Log";
}
public String getUrlName() {
......@@ -243,12 +248,12 @@ public class SCMTrigger extends Trigger {
TaskListener listener = new StreamTaskListener(fos);
try {
LOGGER.info("Polling SCM changes of "+project.getName());
LOGGER.info("Polling SCM changes of "+ job.getName());
PrintStream logger = listener.getLogger();
long start = System.currentTimeMillis();
logger.println("Started on "+new Date().toLocaleString());
boolean result = project.pollSCMChanges(listener);
boolean result = job.pollSCMChanges(listener);
logger.println("Done. Took "+ Util.getTimeSpanString(System.currentTimeMillis()-start));
if(result)
logger.println("Changes found");
......@@ -266,8 +271,8 @@ public class SCMTrigger extends Trigger {
public void run() {
if(runPolling()) {
LOGGER.info("SCM changes detected in "+project.getName());
project.scheduleBuild();
LOGGER.info("SCM changes detected in "+ job.getName());
job.scheduleBuild();
}
synchronized(SCMTrigger.this) {
......
......@@ -3,6 +3,8 @@ package hudson.triggers;
import antlr.ANTLRException;
import static hudson.Util.fixNull;
import hudson.model.Descriptor;
import hudson.model.BuildableItem;
import hudson.model.Item;
import hudson.scheduler.CronTabList;
import hudson.util.FormFieldValidator;
import org.kohsuke.stapler.StaplerRequest;
......@@ -16,26 +18,30 @@ import java.io.IOException;
*
* @author Kohsuke Kawaguchi
*/
public class TimerTrigger extends Trigger {
public class TimerTrigger extends Trigger<BuildableItem> {
public TimerTrigger(String cronTabSpec) throws ANTLRException {
super(cronTabSpec);
}
protected void run() {
project.scheduleBuild();
job.scheduleBuild();
}
public Descriptor<Trigger> getDescriptor() {
public TriggerDescriptor getDescriptor() {
return DESCRIPTOR;
}
public static final Descriptor<Trigger> DESCRIPTOR = new DescriptorImpl();
public static final TriggerDescriptor DESCRIPTOR = new DescriptorImpl();
public static class DescriptorImpl extends Descriptor<Trigger> {
public static class DescriptorImpl extends TriggerDescriptor {
public DescriptorImpl() {
super(TimerTrigger.class);
}
public boolean isApplicable(Item item) {
return item instanceof BuildableItem;
}
public String getDisplayName() {
return "Build periodically";
}
......
......@@ -10,6 +10,7 @@ import hudson.model.FingerprintCleanupThread;
import hudson.model.Hudson;
import hudson.model.Project;
import hudson.model.WorkspaceCleanupThread;
import hudson.model.Item;
import hudson.scheduler.CronTab;
import hudson.scheduler.CronTabList;
......@@ -32,7 +33,7 @@ import java.util.logging.Logger;
*
* @author Kohsuke Kawaguchi
*/
public abstract class Trigger implements Describable<Trigger>, ExtensionPoint {
public abstract class Trigger<J extends Item> implements Describable<Trigger<?>>, ExtensionPoint {
/**
* Called when a {@link Trigger} is loaded into memory and started.
......@@ -43,8 +44,8 @@ public abstract class Trigger implements Describable<Trigger>, ExtensionPoint {
* True if this is a newly created trigger first attached to the {@link Project}.
* False if this is invoked for a {@link Project} loaded from disk.
*/
public void start(AbstractProject<?,?> project, boolean newInstance) {
this.project = project;
public void start(J project, boolean newInstance) {
this.job = project;
}
/**
......@@ -74,11 +75,13 @@ public abstract class Trigger implements Describable<Trigger>, ExtensionPoint {
return null;
}
public abstract TriggerDescriptor getDescriptor();
protected final String spec;
protected transient CronTabList tabs;
protected transient AbstractProject<?,?> project;
protected transient J job;
/**
* Creates a new {@link Trigger} that gets {@link #run() run}
......
package hudson.triggers;
import hudson.model.Descriptor;
import hudson.model.Item;
/**
* {@link Descriptor} for Trigger.
* @author Kohsuke Kawaguchi
*/
public abstract class TriggerDescriptor extends Descriptor<Trigger<?>> {
protected TriggerDescriptor(Class<? extends Trigger<?>> clazz) {
super(clazz);
}
/**
* Returns true if this trigger is applicable to the
* given {@link Item}.
*
* @return
* true to allow user to configure a trigger for this item.
*/
public abstract boolean isApplicable(Item item);
}
package hudson.triggers;
import hudson.model.Descriptor;
import hudson.model.Item;
import java.util.List;
import java.util.ArrayList;
/**
* List of all installed {@link Trigger}s.
......@@ -10,8 +12,20 @@ import java.util.List;
* @author Kohsuke Kawaguchi
*/
public class Triggers {
public static final List<Descriptor<Trigger>> TRIGGERS = Descriptor.toList(
public static final List<TriggerDescriptor> TRIGGERS = Descriptor.toList(
SCMTrigger.DESCRIPTOR,
TimerTrigger.DESCRIPTOR
);
/**
* Returns a subset of {@link TriggerDescriptor}s that applys to the given item.
*/
public static List<TriggerDescriptor> getApplicableTriggers(Item i) {
List<TriggerDescriptor> r = new ArrayList<TriggerDescriptor>();
for (TriggerDescriptor t : TRIGGERS) {
if(t.isApplicable(i))
r.add(t);
}
return r;
}
}
......@@ -6,25 +6,10 @@
<!-- build triggers config pane -->
<j:getStatic var="triggers" className="hudson.triggers.Triggers" field="TRIGGERS" />
<f:descriptorList title="Build Triggers"
descriptors="${triggers}"
instances="${it.triggers}"
varName="trigger">
<f:triggerDescriptorList>
<!-- pseudo-trigger to configure URL to trigger builds remotely. -->
<j:if test="${app.useSecurity}">
<f:optionalBlock name="pseudoRemoteTrigger"
help="/help/project-config/triggerRemotely.html"
title="Trigger builds remotely (e.g., from scripts)"
checked="${it.enableRemoteTrigger}">
<f:entry title="Authentication Token">
<f:textbox class="setting-input" name="authToken" value="${it.authToken}" />
Use the following URL to trigger build remotely:
<tt>HUDSON_URL</tt>/${it.url}build?token=<tt>TOKEN_NAME</tt>
</f:entry>
</f:optionalBlock>
</j:if>
</f:descriptorList>
<st:include page="/hudson/model/BuildAuthorizationToken/config.jelly" />
</f:triggerDescriptorList>
<f:section title="Build">
<f:entry title="Goals" help="/help/maven/module-goals.html">
......
......@@ -16,11 +16,11 @@
<st:include page="configure-common.jelly" />
<!-- TODO: move this to the appropriate place -->
<f:section title="Build Triggers">
<!-- build triggers config pane -->
<f:triggerDescriptorList>
<!-- pseudo-trigger to configure URL to trigger builds remotely. -->
<st:include page="/hudson/model/BuildAuthorizationToken/config.jelly" />
</f:section>
</f:triggerDescriptorList>
<f:section title="Build">
<f:entry title="root POM" help="/help/maven/root-pom.html">
......
......@@ -6,11 +6,7 @@
<!-- build triggers config pane -->
<j:getStatic var="triggers" className="hudson.triggers.Triggers" field="TRIGGERS" />
<f:descriptorList title="Build Triggers"
descriptors="${triggers}"
instances="${it.triggers}"
varName="trigger">
<f:triggerDescriptorList>
<!-- pseudo-trigger to list upstream projects. -->
<j:set var="up" value="${it.upstreamProjects}" />
<f:optionalBlock name="pseudoUpstreamTrigger"
......@@ -26,7 +22,7 @@
</f:optionalBlock>
<!-- pseudo-trigger to configure URL to trigger builds remotely. -->
<st:include page="/hudson/model/BuildAuthorizationToken/config.jelly" />
</f:descriptorList>
</f:triggerDescriptorList>
<!-- build wrapper config pane -->
......
<!-- display a list of trigger configurations applicable to "it" -->
<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">
<!-- build triggers config pane -->
<j:invokeStatic var="triggers" className="hudson.triggers.Triggers" method="getApplicableTriggers">
<j:arg value="${it}" type="hudson.model.Item" />
</j:invokeStatic>
<f:descriptorList title="Build Triggers"
descriptors="${triggers}"
instances="${it.triggers}"
varName="trigger">
<d:invokeBody />
</f:descriptorList>
</j:jelly>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册