提交 31a76bc4 编写于 作者: K Kohsuke Kawaguchi

Merge branch 'after-first-release'

... so as to follow the convention of keeping the master branch open for
commits.

* after-first-release:
  noting the changes
  Other languages on JVM may not be able to provide the type information.
  Added autocomplete feature to BuildTrigger
......@@ -52,6 +52,8 @@ Upcoming changes</a>
If the JNLP-connected slave drops out without the master not noticing, allow the reconnection
without rejecting it.
(<a href="http://issues.hudson-ci.org/browse/HUDSON-5055">issue 5055</a>)
<li class=rfe>
Added auto-completion to the build trigger.
</ul>
</div><!--=TRUNK-END=-->
......
......@@ -38,6 +38,7 @@ import hudson.tasks.Publisher.DescriptorExtensionListImpl;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.concurrent.CopyOnWriteArrayList;
import java.lang.reflect.Type;
......@@ -156,13 +157,12 @@ public class DescriptorExtensionList<T extends Describable<T>, D extends Descrip
List<ExtensionComponent<D>> r = new ArrayList<ExtensionComponent<D>>();
for( ExtensionComponent<Descriptor> c : hudson.getExtensionList(Descriptor.class).getComponents() ) {
Descriptor d = c.getInstance();
Type subTyping = Types.getBaseClass(d.getClass(), Descriptor.class);
if (!(subTyping instanceof ParameterizedType)) {
LOGGER.severe(d.getClass()+" doesn't extend Descriptor with a type parameter");
continue; // skip this one
try {
if(d.getT()==describableType)
r.add((ExtensionComponent)c);
} catch (IllegalStateException e) {
LOGGER.log(Level.SEVERE, d.getClass() + " doesn't extend Descriptor with a type parameter", e); // skip this one
}
if(Types.erasure(Types.getTypeArgument(subTyping,0))==(Class)describableType)
r.add((ExtensionComponent)c);
}
return r;
}
......
......@@ -23,6 +23,8 @@
*/
package hudson.model;
import hudson.DescriptorExtensionList;
import hudson.ExtensionComponent;
import hudson.RelativePath;
import hudson.XmlFile;
import hudson.BulkChange;
......@@ -267,6 +269,22 @@ public abstract class Descriptor<T extends Describable<T>> implements Saveable {
return clazz.getName();
}
/**
* Unlike {@link #clazz}, return the parameter type 'T', which determines
* the {@link DescriptorExtensionList} that this goes to.
*
* <p>
* In those situations where subtypes cannot provide the type parameter,
* this method can be overridden to provide it.
*/
public Class<T> getT() {
Type subTyping = Types.getBaseClass(getClass(), Descriptor.class);
if (!(subTyping instanceof ParameterizedType)) {
throw new IllegalStateException(getClass()+" doesn't extend Descriptor with a type parameter.");
}
return Types.erasure(Types.getTypeArgument(subTyping, 0));
}
/**
* Gets the URL that this Descriptor is bound to, relative to the nearest {@link DescriptorByNameOwner}.
* Since {@link Hudson} is a {@link DescriptorByNameOwner}, there's always one such ancestor to any request.
......
/*
* The MIT License
*
*
* Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Brian Westrich, Martin Eigenbrodt
*
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
......@@ -23,14 +23,15 @@
*/
package hudson.tasks;
import hudson.Launcher;
import hudson.Extension;
import hudson.Launcher;
import hudson.Util;
import hudson.security.AccessControlled;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Action;
import hudson.model.AutoCompletionCandidates;
import hudson.model.BuildListener;
import hudson.model.Cause.UpstreamCause;
import hudson.model.DependecyDeclarer;
import hudson.model.DependencyGraph;
import hudson.model.DependencyGraph.Dependency;
......@@ -41,15 +42,16 @@ import hudson.model.Job;
import hudson.model.Project;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.Cause.UpstreamCause;
import hudson.model.TaskListener;
import hudson.model.listeners.ItemListener;
import hudson.security.AccessControlled;
import hudson.util.FormValidation;
import net.sf.json.JSONObject;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.StaplerRequest;
import org.apache.commons.lang.StringUtils;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
import java.io.IOException;
import java.io.PrintStream;
......@@ -67,7 +69,7 @@ import java.util.logging.Logger;
*
* <p>
* Despite what the name suggests, this class doesn't actually trigger other jobs
* as a part of {@link #perform} method. Its main job is to simply augument
* as a part of {@link #perform} method. Its main job is to simply augment
* {@link DependencyGraph}. Jobs are responsible for triggering downstream jobs
* on its own, because dependencies may come from other sources.
*
......@@ -130,7 +132,7 @@ public class BuildTrigger extends Recorder implements DependecyDeclarer {
public BuildStepMonitor getRequiredMonitorService() {
return BuildStepMonitor.NONE;
}
/**
* Checks if this trigger has the exact same set of children as the given list.
*/
......@@ -268,8 +270,12 @@ public class BuildTrigger extends Recorder implements DependecyDeclarer {
@Override
public Publisher newInstance(StaplerRequest req, JSONObject formData) throws FormException {
String childProjectsString = formData.getString("childProjects").trim();
if (childProjectsString.endsWith(",")) {
childProjectsString = childProjectsString.substring(0, childProjectsString.length() - 1).trim();
}
return new BuildTrigger(
formData.getString("childProjects"),
childProjectsString,
formData.has("evenIfUnstable") && formData.getBoolean("evenIfUnstable"));
}
......@@ -279,7 +285,7 @@ public class BuildTrigger extends Recorder implements DependecyDeclarer {
}
public boolean showEvenIfUnstableOption(Class<? extends AbstractProject> jobType) {
// UGLY: for promotion process, this option doesn't make sense.
// UGLY: for promotion process, this option doesn't make sense.
return !jobType.getName().contains("PromotionProcess");
}
......@@ -291,18 +297,38 @@ public class BuildTrigger extends Recorder implements DependecyDeclarer {
if(!subject.hasPermission(Item.CONFIGURE)) return FormValidation.ok();
StringTokenizer tokens = new StringTokenizer(Util.fixNull(value),",");
boolean hasProjects = false;
while(tokens.hasMoreTokens()) {
String projectName = tokens.nextToken().trim();
Item item = Hudson.getInstance().getItemByFullName(projectName,Item.class);
if(item==null)
return FormValidation.error(Messages.BuildTrigger_NoSuchProject(projectName,AbstractProject.findNearest(projectName).getName()));
if(!(item instanceof AbstractProject))
return FormValidation.error(Messages.BuildTrigger_NotBuildable(projectName));
if (StringUtils.isNotBlank(projectName)) {
Item item = Hudson.getInstance().getItemByFullName(projectName,Item.class);
if(item==null)
return FormValidation.error(Messages.BuildTrigger_NoSuchProject(projectName,AbstractProject.findNearest(projectName).getName()));
if(!(item instanceof AbstractProject))
return FormValidation.error(Messages.BuildTrigger_NotBuildable(projectName));
hasProjects = true;
}
}
if (!hasProjects) {
return FormValidation.error(Messages.BuildTrigger_NoProjectSpecified());
}
return FormValidation.ok();
}
public AutoCompletionCandidates doAutoCompleteChildProjects(@QueryParameter String value) {
AutoCompletionCandidates candidates = new AutoCompletionCandidates();
List<Job> jobs = Hudson.getInstance().getItems(Job.class);
for (Job job: jobs) {
if (job.getFullName().startsWith(value)) {
if (job.hasPermission(Item.READ)) {
candidates.add(job.getFullName());
}
}
}
return candidates;
}
@Extension
public static class ItemListenerImpl extends ItemListener {
@Override
......
......@@ -25,7 +25,9 @@ THE SOFTWARE.
<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">
<f:entry title="${%Projects to build}">
<f:textbox name="buildTrigger.childProjects" value="${instance.childProjectsValue}"
checkUrl="'descriptorByName/BuildTrigger/check?value='+encodeURIComponent(this.value)"/>
checkUrl="'descriptorByName/BuildTrigger/check?value='+encodeURIComponent(this.value)"
autoCompleteDelimChar=","
field="childProjects"/>
</f:entry>
<j:if test="${descriptor.showEvenIfUnstableOption(targetType)}">
<f:entry title="">
......
......@@ -44,6 +44,7 @@ BuildTrigger.Disabled={0} is disabled. Triggering skipped
BuildTrigger.DisplayName=Build other projects
BuildTrigger.InQueue={0} is already in the queue
BuildTrigger.NoSuchProject=No such project ''{0}''. Did you mean ''{1}''?
BuildTrigger.NoProjectSpecified=No project specified
BuildTrigger.NotBuildable={0} is not buildable
BuildTrigger.Triggering=Triggering a new build of {0}
......
......@@ -44,6 +44,7 @@ BuildTrigger.Disabled={0} ist deaktiviert. Keine Ausl
BuildTrigger.DisplayName=Weitere Projekte bauen
BuildTrigger.InQueue={0} ist bereits geplant.
BuildTrigger.NoSuchProject=Kein Projekt ''{0}'' gefunden. Meinten Sie ''{1}''?
BuildTrigger.NoProjectSpecified=Kein Projekt angegeben
BuildTrigger.NotBuildable={0} kann nicht gebaut werden.
BuildTrigger.Triggering=L\u00F6se einen neuen Build von {0} aus
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册