提交 9194d14c 编写于 作者: S Stephen Connolly

Merge branch 'oss' of github.com:cloudbees/hudson into oss

......@@ -58,10 +58,11 @@ Upcoming changes</a>
<!-- Record your changes in the trunk here. -->
<div id="trunk" style="display:none"><!--=TRUNK-BEGIN=-->
<ul class=image>
<li class=>
<li class=bug>
PAM authentication fails to restore group membership information on "remember me" tokens.
(<a href="http://issues.jenkins-ci.org/browse/JENKINS-9094">issue 9094</a>)
<li class=rfe>
Actions can now override their rendering in the parent model object.
</ul>
</div><!--=TRUNK-END=-->
......
......@@ -121,6 +121,9 @@ public class CLI {
return Integer.parseInt(p);
}
/**
* Shuts down the channel and closes the underlying connection.
*/
public void close() throws IOException, InterruptedException {
channel.close();
channel.join();
......
......@@ -185,7 +185,7 @@ public class EnvVars extends TreeMap<String,String> {
* when we later kill the processes.
*/
public static EnvVars createCookie() {
return new EnvVars("HUDSON_COOKIE", UUID.randomUUID().toString());
return new EnvVars("JENKINS_COOKIE", UUID.randomUUID().toString());
}
/**
......
......@@ -39,6 +39,7 @@ import hudson.tasks.test.TestResultProjectAction;
* while others do the former without the latter (for example, to just draw some graphs in <tt>floatingBox.jelly</tt>),
* and still some others do both.
*
* <h2>Views</h2>
* <p>
* If an action has a view named <tt>floatingBox.jelly</tt>,
* it will be displayed as a floating box on the top page of
......@@ -46,6 +47,19 @@ import hudson.tasks.test.TestResultProjectAction;
* the JUnit test result trend shows up in the project top page.
* See {@link TestResultProjectAction}.
*
* <p>
* On the target {@link ModelObject} page, actions are rendered as an item in the side panel
* by the "/lib/hudson:actions" jelly tag, but you can override this for your action by
* writing {@code action.jelly}. See the "actions" tag for what the default handling is and
* tweak from there. One of the use cases of this is to show nested actions, like where
* Jenkins show the option to wipe out the workspace inside the workspace link:
*
* <pre>
* &lt;l:task icon="images/24x24/folder.gif" href="${url}/ws/" title="${%Workspace}">
* &lt;l:task icon="images/24x24/folder-delete.gif" href="${url}/wipeOutWorkspace" title="${%Wipe Out Workspace}" />
* &lt;/l:task>
* </pre>
*
* <h2>Persistence</h2>
* <p>
* Actions are often persisted as a part of {@link Actionable}
......
......@@ -2388,9 +2388,12 @@ public final class Hudson extends Node implements ItemGroup<TopLevelItem>, Stapl
}
public Object getDynamic(String token) {
for (Action a : getActions())
if(a.getUrlName().equals(token) || a.getUrlName().equals('/'+token))
for (Action a : getActions()) {
String url = a.getUrlName();
if (url==null) continue;
if (url.equals(token) || url.equals('/' + token))
return a;
}
for (Action a : getManagementLinks())
if(a.getUrlName().equals(token))
return a;
......
......@@ -101,7 +101,8 @@ public class CommandLauncher extends ComputerLauncher {
{// system defined variables
String rootUrl = Hudson.getInstance().getRootUrl();
if (rootUrl!=null) {
pb.environment().put("HUDSON_URL", rootUrl);
pb.environment().put("HUDSON_URL", rootUrl); // for backward compatibility
pb.environment().put("JENKINS_URL", rootUrl);
pb.environment().put("SLAVEJAR_URL", rootUrl+"/jnlpJars/slave.jar");
}
}
......
......@@ -308,7 +308,9 @@ public class JDKInstaller extends ToolInstaller {
IOUtils.copy(new RetryableHttpStream(src) {
@Override
protected HttpURLConnection connect() throws IOException {
return (HttpURLConnection) ProxyConfiguration.open(url);
HttpURLConnection con = (HttpURLConnection) ProxyConfiguration.open(url);
con.setReadTimeout(60*1000); // don't block forever, but don't let the slow client fail with false positives either
return con;
}
}, out);
} finally {
......
......@@ -27,9 +27,12 @@ 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">
<j:forEach var="action" items="${it.actions}">
<j:if test="${action.iconFileName!=null}">
<l:task icon="${h.getIconFilePath(action)}" title="${action.displayName}"
href="${h.getActionUrl(it.url,action)}" />
</j:if>
<!-- allow the action to take over the rendering, but otherwise fall back to the default -->
<st:include page="action.jelly" from="${action}" optional="true">
<j:if test="${action.iconFileName!=null}">
<l:task icon="${h.getIconFilePath(action)}" title="${action.displayName}"
href="${h.getActionUrl(it.url,action)}" />
</j:if>
</st:include>
</j:forEach>
</j:jelly>
\ No newline at end of file
......@@ -241,9 +241,9 @@ THE SOFTWARE.
Since some developers try to run hudson-dev:run from main, define it here so that at least the plugin resolves.
This enables us to report a better error message.
-->
<groupId>org.jvnet.hudson.tools</groupId>
<artifactId>maven-hudson-dev-plugin</artifactId>
<version>6.1.7</version>
<groupId>org.jenkins-ci.tools</groupId>
<artifactId>maven-jenkins-dev-plugin</artifactId>
<version>6.1.26-jenkins-1</version>
</plugin>
<!--<plugin>
......
......@@ -305,6 +305,10 @@ public class Channel implements VirtualChannel, IChannel {
this(name,exec,mode,is,os,header,false);
}
public Channel(String name, ExecutorService exec, Mode mode, InputStream is, OutputStream os, OutputStream header, boolean restricted) throws IOException {
this(name,exec,mode,is,os,header,restricted,null);
}
/**
* Creates a new channel.
*
......@@ -325,6 +329,12 @@ public class Channel implements VirtualChannel, IChannel {
* the data goes into the "binary mode". This is useful
* when the established communication channel might include some data that might
* be useful for debugging/trouble-shooting.
* @param base
* Specify the classloader used for deserializing remote commands.
* This is primarily related to {@link #getRemoteProperty(Object)}. Sometimes two parties
* communicate over a channel and pass objects around as properties, but those types might not be
* visible from the classloader loading the {@link Channel} class. In such a case, specify a classloader
* so that those classes resolve. If null, {@code Channel.class.getClassLoader()} is used.
* @param restricted
* If true, this channel won't accept {@link Command}s that allow the remote end to execute arbitrary closures
* --- instead they can only call methods on objects that are exported by this channel.
......@@ -334,15 +344,18 @@ public class Channel implements VirtualChannel, IChannel {
* (provided that all the classes are already available in this JVM), so exactly how
* safe the resulting behavior is is up to discussion.
*/
public Channel(String name, ExecutorService exec, Mode mode, InputStream is, OutputStream os, OutputStream header, boolean restricted) throws IOException {
this(name,exec,mode,is,os,header,restricted,new Capability());
public Channel(String name, ExecutorService exec, Mode mode, InputStream is, OutputStream os, OutputStream header, boolean restricted, ClassLoader base) throws IOException {
this(name,exec,mode,is,os,header,restricted,base,new Capability());
}
/*package*/ Channel(String name, ExecutorService exec, Mode mode, InputStream is, OutputStream os, OutputStream header, boolean restricted, Capability capability) throws IOException {
/*package*/ Channel(String name, ExecutorService exec, Mode mode, InputStream is, OutputStream os, OutputStream header, boolean restricted, ClassLoader base, Capability capability) throws IOException {
this.name = name;
this.executor = exec;
this.isRestricted = restricted;
if (base==null)
base = getClass().getClassLoader();
if(export(this,false)!=1)
throw new AssertionError(); // export number 1 is reserved for the channel itself
remoteChannel = RemoteInvocationHandler.wrap(this,1,IChannel.class,false,false);
......@@ -395,7 +408,7 @@ public class Channel implements VirtualChannel, IChannel {
this.oos = oos;
this.remoteCapability = cap;
this.pipeWriter = createPipeWriter();
this.ois = new ObjectInputStream(mode.wrap(is));
this.ois = new ObjectInputStreamEx(mode.wrap(is),base);
new ReaderThread(name).start();
return;
......
......@@ -70,7 +70,7 @@ interface ChannelRunner {
Thread t = new Thread("south bridge runner") {
public void run() {
try {
Channel s = new Channel("south", executor, Mode.BINARY, in2, out1, null, false, createCapability());
Channel s = new Channel("south", executor, Mode.BINARY, in2, out1, null, false, null, createCapability());
s.join();
System.out.println("south completed");
} catch (IOException e) {
......@@ -84,7 +84,7 @@ interface ChannelRunner {
};
t.start();
return new Channel("north", executor, Mode.BINARY, in1, out2, null, false, createCapability());
return new Channel("north", executor, Mode.BINARY, in1, out2, null, false, null, createCapability());
}
public void stop(Channel channel) throws Exception {
......
......@@ -152,7 +152,7 @@ THE SOFTWARE.
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>6.1.11</version>
<version>6.1.26</version>
</dependency>
<dependency>
<groupId>org.jvnet.hudson</groupId>
......@@ -176,9 +176,9 @@ THE SOFTWARE.
<version>1.0-beta-1</version>
</dependency-->
<dependency>
<groupId>org.jvnet.hudson</groupId>
<groupId>org.jenkins-ci</groupId>
<artifactId>htmlunit</artifactId>
<version>2.6-hudson-2</version>
<version>2.6-jenkins-3</version>
<exclusions>
<exclusion>
<!-- hides JDK DOM classes in Eclipse -->
......
......@@ -72,6 +72,8 @@ import hudson.model.TaskListener;
import hudson.model.UpdateSite;
import hudson.model.User;
import hudson.model.View;
import hudson.remoting.Channel;
import hudson.remoting.VirtualChannel;
import hudson.remoting.Which;
import hudson.security.ACL;
import hudson.security.AbstractPasswordBasedSecurityRealm;
......@@ -118,9 +120,11 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
......@@ -229,7 +233,12 @@ public abstract class HudsonTestCase extends TestCase implements RootAction {
/**
* Remember {@link WebClient}s that are created, to release them properly.
*/
private List<WeakReference<WebClient>> clients = new ArrayList<WeakReference<WebClient>>();
private List<WebClient> clients = new ArrayList<WebClient>();
/**
* Remember channels that are created, to release them at the end.
*/
private List<Channel> channels = new ArrayList<Channel>();
/**
* JavaScript "debugger" that provides you information about the JavaScript call stack
......@@ -336,13 +345,19 @@ public abstract class HudsonTestCase extends TestCase implements RootAction {
protected void tearDown() throws Exception {
try {
// cancel pending asynchronous operations, although this doesn't really seem to be working
for (WeakReference<WebClient> client : clients) {
WebClient c = client.get();
if(c==null) continue;
for (WebClient client : clients) {
// unload the page to cancel asynchronous operations
c.getPage("about:blank");
client.getPage("about:blank");
client.closeAllWindows();
}
clients.clear();
for (Channel c : channels)
c.close();
for (Channel c : channels)
c.join();
channels.clear();
} finally {
server.stop();
for (LenientRunnable r : tearDowns)
......@@ -432,6 +447,17 @@ public abstract class HudsonTestCase extends TestCase implements RootAction {
return realm;
}
@TestExtension
public static class ComputerListenerImpl extends ComputerListener {
@Override
public void onOnline(Computer c, TaskListener listener) throws IOException, InterruptedException {
VirtualChannel ch = c.getChannel();
if (ch instanceof Channel)
TestEnvironment.get().testCase.channels.add((Channel)ch);
}
}
// /**
// * Sets guest credentials to access java.net Subversion repo.
// */
......@@ -1414,7 +1440,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction {
// setJavaScriptEnabled(false);
setPageCreator(HudsonPageCreator.INSTANCE);
clients.add(new WeakReference<WebClient>(this));
clients.add(this);
// make ajax calls run as post-action for predictable behaviors that simplify debugging
setAjaxController(new AjaxController() {
public boolean processSynchron(HtmlPage page, WebRequestSettings settings, boolean async) {
......@@ -1456,6 +1482,10 @@ public abstract class HudsonTestCase extends TestCase implements RootAction {
public void contextReleased(Context cx) {
}
});
// avoid a hang by setting a time out. It should be long enough to prevent
// false-positive timeout on slow systems
setTimeout(60*1000);
}
/**
......
......@@ -54,10 +54,16 @@ public class BuildCommandTest extends HudsonTestCase {
}] as TestBuilder);
// this should be asynchronous
assertEquals(0,new CLI(getURL()).execute(["build", p.name]))
started.block();
assertTrue(p.getBuildByNumber(1).isBuilding())
completed.signal();
def cli = new CLI(getURL())
try {
assertEquals(0,cli.execute(["build", p.name]))
started.block()
assertTrue(p.getBuildByNumber(1).isBuilding())
completed.signal()
} finally {
cli.close();
}
}
/**
......@@ -67,16 +73,28 @@ public class BuildCommandTest extends HudsonTestCase {
def p = createFreeStyleProject();
p.buildersList.add(new Shell("sleep 3"));
new CLI(getURL()).execute(["build","-s",p.name])
assertFalse(p.getBuildByNumber(1).isBuilding())
def cli = new CLI(getURL())
try {
cli.execute(["build","-s",p.name])
assertFalse(p.getBuildByNumber(1).isBuilding())
} finally {
cli.close();
}
}
void testParameters() {
def p = createFreeStyleProject();
p.addProperty(new ParametersDefinitionProperty([new StringParameterDefinition("key",null)]));
new CLI(getURL()).execute(["build","-s","-p","key=foobar",p.name]);
def b = assertBuildStatusSuccess(p.getBuildByNumber(1));
assertEquals("foobar",b.getAction(ParametersAction.class).getParameter("key").value);
def cli = new CLI(getURL())
try {
cli.execute(["build","-s","-p","key=foobar",p.name])
def b = assertBuildStatusSuccess(p.getBuildByNumber(1))
assertEquals("foobar",b.getAction(ParametersAction.class).getParameter("key").value)
} finally {
cli.close();
};
}
}
\ No newline at end of file
......@@ -36,10 +36,14 @@ public class EnableJobCommandTest extends HudsonTestCase {
def cli = new CLI(getURL())
cli.execute(["disable-job",p.name])
assertTrue(p.disabled)
cli.execute(["enable-job",p.name])
assertFalse(p.disabled)
try {
cli.execute(["disable-job",p.name])
assertTrue(p.disabled)
cli.execute(["enable-job",p.name])
assertFalse(p.disabled)
} finally {
cli.close();
}
}
}
\ No newline at end of file
......@@ -56,12 +56,17 @@ public class ItemListenerTest extends HudsonTestCase {
public void testOnCreatedViaCLI() throws Exception {
ByteArrayOutputStream buf = new ByteArrayOutputStream();
PrintStream out = new PrintStream(buf);
new CLI(getURL()).execute(Arrays.asList("create-job","testJob"),
new ByteArrayInputStream(("<project><actions/><builders/><publishers/>"
+ "<buildWrappers/></project>").getBytes()),
out, out);
out.flush();
assertNotNull("job should be created: " + buf, hudson.getItem("testJob"));
assertEquals("onCreated event should be triggered: " + buf, "C", events.toString());
CLI cli = new CLI(getURL());
try {
cli.execute(Arrays.asList("create-job", "testJob"),
new ByteArrayInputStream(("<project><actions/><builders/><publishers/>"
+ "<buildWrappers/></project>").getBytes()),
out, out);
out.flush();
assertNotNull("job should be created: " + buf, hudson.getItem("testJob"));
assertEquals("onCreated event should be triggered: " + buf, "C", events.toString());
} finally {
cli.close();
}
}
}
......@@ -28,7 +28,12 @@ public class CliAuthenticationTest extends HudsonTestCase {
}
private int command(String... args) throws Exception {
return new CLI(getURL()).execute(args);
CLI cli = new CLI(getURL());
try {
return cli.execute(args);
} finally {
cli.close();
}
}
@TestExtension
......
/*
* The MIT License
*
* Copyright (c) 2011, CloudBees, Inc.
*
* 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
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package lib.hudson;
import hudson.model.InvisibleAction;
import hudson.model.RootAction;
import org.jvnet.hudson.test.HudsonTestCase;
import org.jvnet.hudson.test.TestExtension;
/**
* @author Kohsuke Kawaguchi
*/
public class ActionsTest extends HudsonTestCase {
public void testOverride() throws Exception {
assertNotNull(createWebClient().goTo("").getElementById("bravo"));
}
@TestExtension
public static class RootActionImpl extends InvisibleAction implements RootAction {
}
}
<j:jelly xmlns:j="jelly:core">
<div>
<b id='bravo'>Bravo</b>
</div>
</j:jelly>
\ No newline at end of file
......@@ -134,11 +134,15 @@ THE SOFTWARE.
</plugin>
<plugin>
<!-- this is really just a patched version of maven-jetty-plugin to workaround issue #932 -->
<groupId>org.jvnet.hudson.tools</groupId>
<artifactId>maven-hudson-dev-plugin</artifactId>
<version>6.1.7-hudson-1</version>
<groupId>org.jenkins-ci.tools</groupId>
<artifactId>maven-jenkins-dev-plugin</artifactId>
<version>6.1.26-jenkins-1</version>
<configuration>
<contextPath>${contextPath}</contextPath>
<!--
Reload webapp when you hit ENTER. (See JETTY-282 for more)
-->
<reload>manual</reload>
<connectors>
<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
<port>${port}</port>
......@@ -152,10 +156,6 @@ THE SOFTWARE.
<!-- use the test classpath for loading resources, since this takes priority -->
<testClassesDirectory>../core/src/main/resources</testClassesDirectory>
<useTestClasspath>true</useTestClasspath>
<!--
Reload webapp when you hit ENTER. (See JETTY-282 for more)
-->
<consoleForceReload>true</consoleForceReload>
<userRealms>
<userRealm implementation="org.mortbay.jetty.security.HashUserRealm">
<name>default</name>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册