提交 768abac9 编写于 作者: K Kohsuke Kawaguchi

merged 'ready-to-merge' from huybrechts

......@@ -212,7 +212,7 @@ public final class TcpSlaveAgentListener extends Thread {
return;
}
String nodeName = in.readUTF();
final String nodeName = in.readUTF();
SlaveComputer computer = (SlaveComputer) Hudson.getInstance().getComputer(nodeName);
if(computer==null) {
error(out, "No such slave: "+nodeName);
......@@ -241,7 +241,7 @@ public final class TcpSlaveAgentListener extends Thread {
e.printStackTrace();
}
if(cause!=null)
LOGGER.log(Level.WARNING, "Connection #"+id+" terminated",cause);
LOGGER.log(Level.WARNING, "Connection #"+id+" for + " + nodeName + " terminated",cause);
try {
ConnectionHandler.this.s.close();
} catch (IOException e) {
......@@ -254,7 +254,7 @@ public final class TcpSlaveAgentListener extends Thread {
logw.println("Failed to establish the connection with the slave");
throw e;
} catch (IOException e) {
logw.println("Failed to establish the connection with the slave");
logw.println("Failed to establish the connection with the slave " + nodeName);
e.printStackTrace(logw);
throw e;
}
......
package hudson.cli;
import hudson.Extension;
import hudson.model.AbstractProject;
import hudson.model.Run;
import hudson.remoting.Callable;
import java.io.IOException;
import java.io.Serializable;
import org.apache.commons.io.IOUtils;
import org.kohsuke.args4j.Argument;
@Extension
public class SetBuildDescriptionCommand extends CLICommand implements Serializable {
@Override
public String getShortDescription() {
return "Sets the description of a build";
}
@Argument(metaVar="JOB",usage="Name of the job to build",required=true,index=0)
public transient AbstractProject<?,?> job;
@Argument(metaVar="BUILD#",usage="Number of the build",required=true,index=1)
public int number;
@Argument(metaVar="DESCRIPTION",required=true,usage="Description to be set. '=' to read from stdin.", index=2)
public String description;
protected int run() throws Exception {
Run run = job.getBuildByNumber(number);
run.checkPermission(Run.UPDATE);
if ("=".equals(description)) {
description = channel.call(new Callable<String,IOException>() {
public String call() throws IOException {
return IOUtils.toString(System.in);
}
});
}
run.setDescription(description);
return 0;
}
}
......@@ -190,7 +190,8 @@ public abstract class Cause {
@Exported(visibility=3)
public String getUserName() {
return authenticationName;
User u = User.get(authenticationName, false);
return u != null ? u.getDisplayName() : authenticationName;
}
@Override
......
......@@ -166,25 +166,17 @@ public class ListView extends View implements Saveable {
jobFilters = new DescribableList<ViewJobFilter, Descriptor<ViewJobFilter>>(this,r);
}
/**
* Returns the transient {@link Action}s associated with the top page.
*
* @see Hudson#getActions()
*/
@Override
public List<Action> getActions() {
return Hudson.getInstance().getActions();
}
/**
* Used to determine if we want to display the Add button.
*/
public boolean hasJobFilterExtensions() {
return !ViewJobFilter.all().isEmpty();
}
public Iterable<ViewJobFilter> getJobFilters() {
return jobFilters;
}
public Iterable<ListViewColumn> getColumns() {
return columns;
}
......
......@@ -61,6 +61,8 @@ import hudson.util.ProcessTree;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
......@@ -94,6 +96,7 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.input.NullInputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.jelly.XMLOutput;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
......@@ -1072,8 +1075,19 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
* @since 1.349
*/
public void writeLogTo(long offset, XMLOutput out) throws IOException {
// TODO: resurrect compressed log file support
getLogText().writeHtmlTo(offset,out.asWriter());
try {
getLogText().writeHtmlTo(offset,out.asWriter());
} catch (IOException e) {
// try to fall back to the old getLogInputStream()
// mainly to support .gz compressed files
// In this case, console annotation handling will be turned off.
InputStream input = getLogInputStream();
try {
IOUtils.copy(input, out.asWriter());
} finally {
IOUtils.closeQuietly(input);
}
}
}
/**
......@@ -1909,4 +1923,4 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
out.flush();
}
}
}
\ No newline at end of file
}
package hudson.model;
import hudson.ExtensionList;
import java.util.ArrayList;
import java.util.List;
/**
* Extension point for adding transient {@link Action}s to {@link View}s.
*
*/
public abstract class TransientViewActionFactory {
/**
* returns a list of (transient) actions never null, may be empty
*
* @param v
* @return
*/
public abstract List<Action> createFor(View v);
/**
* Returns all the registered {@link TransientViewActionFactory}s.
*/
public static ExtensionList<TransientViewActionFactory> all() {
return Hudson.getInstance().getExtensionList(TransientViewActionFactory.class);
}
/**
* Creates {@link Action)s for a view, using all registered {@link TransientViewActionFactory}s.
*/
public static List<Action> createAllFor(View v) {
List<Action> result = new ArrayList<Action>();
for (TransientViewActionFactory f: all()) {
result.addAll(f.createFor(v));
}
return result;
}
}
......@@ -108,6 +108,8 @@ public abstract class View extends AbstractModelObject implements AccessControll
* If true, only show relevant queue items
*/
protected boolean filterQueue;
protected transient List<Action> transientActions;
protected View(String name) {
this.name = name;
......@@ -313,7 +315,22 @@ public abstract class View extends AbstractModelObject implements AccessControll
* @see Hudson#getActions()
*/
public List<Action> getActions() {
return Hudson.getInstance().getActions();
List<Action> result = new ArrayList<Action>();
result.addAll(Hudson.getInstance().getActions());
synchronized (this) {
if (transientActions == null) {
transientActions = TransientViewActionFactory.createAllFor(this);
}
result.addAll(transientActions);
}
return result;
}
public Object getDynamic(String token) {
for (Action a : getActions())
if(a.getUrlName().equals(token))
return a;
return null;
}
/**
......
......@@ -25,9 +25,20 @@ package hudson.tasks.junit;
import hudson.model.AbstractBuild;
import hudson.model.Hudson;
import hudson.tasks.test.TestResult;
import hudson.tasks.test.TestObject;
import hudson.util.*;
import hudson.tasks.test.TestResult;
import hudson.util.ChartUtil;
import hudson.util.ColorPalette;
import hudson.util.DataSetBuilder;
import hudson.util.Graph;
import hudson.util.ShiftedCategoryAxis;
import hudson.util.StackedAreaRenderer2;
import java.awt.Color;
import java.awt.Paint;
import java.util.ArrayList;
import java.util.List;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
......@@ -38,10 +49,8 @@ import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.StackedAreaRenderer;
import org.jfree.data.category.CategoryDataset;
import org.jfree.ui.RectangleInsets;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.StaplerRequest;
/**
* History of {@link hudson.tasks.test.TestObject} over time.
......@@ -66,16 +75,21 @@ public class History {
return false;
}
public List<TestResult> getList(int start, int end) {
List<TestResult> list = new ArrayList<TestResult>();
end = Math.min(end, testObject.getOwner().getParent().getBuilds().size());
for (AbstractBuild<?,?> b: testObject.getOwner().getParent().getBuilds().subList(start, end)) {
if (b.isBuilding()) continue;
TestResult o = testObject.getResultInBuild(b);
if (o != null) {
list.add(o);
}
}
return list;
}
public List<TestResult> getList() {
List<TestResult> list = new ArrayList<TestResult>();
for (AbstractBuild<?,?> b: testObject.getOwner().getParent().getBuilds()) {
if (b.isBuilding()) continue;
TestResult o = testObject.getResultInBuild(b);
if (o != null) {
list.add(o);
}
}
return list;
return getList(0, testObject.getOwner().getParent().getBuilds().size());
}
/**
......@@ -83,9 +97,20 @@ public class History {
*/
public Graph getDurationGraph() {
return new GraphImpl("seconds") {
protected DataSetBuilder<String, ChartLabel> createDataSet() {
DataSetBuilder<String, ChartLabel> data = new DataSetBuilder<String, ChartLabel>();
for (hudson.tasks.test.TestResult o: getList()) {
List<TestResult> list;
try {
list = getList(
Integer.parseInt(Stapler.getCurrentRequest().getParameter("start")),
Integer.parseInt(Stapler.getCurrentRequest().getParameter("end")));
} catch (NumberFormatException e) {
list = getList();
}
for (hudson.tasks.test.TestResult o: list) {
data.add(((double) o.getDuration()) / (1000), "", new ChartLabel(o) {
@Override
public Color getColor() {
......@@ -100,6 +125,7 @@ public class History {
}
return data;
}
};
}
......@@ -111,7 +137,16 @@ public class History {
protected DataSetBuilder<String, ChartLabel> createDataSet() {
DataSetBuilder<String, ChartLabel> data = new DataSetBuilder<String, ChartLabel>();
for (TestResult o: getList()) {
List<TestResult> list;
try {
list = getList(
Integer.parseInt(Stapler.getCurrentRequest().getParameter("start")),
Integer.parseInt(Stapler.getCurrentRequest().getParameter("end")));
} catch (NumberFormatException e) {
list = getList();
}
for (TestResult o: list) {
data.add(o.getPassCount(), "2Passed", new ChartLabel(o));
data.add(o.getFailCount(), "1Failed", new ChartLabel(o));
data.add(o.getSkipCount(), "0Skipped", new ChartLabel(o));
......@@ -125,7 +160,7 @@ public class History {
private final String yLabel;
protected GraphImpl(String yLabel) {
super(testObject.getOwner().getTimestamp(),600,300);
super(-1,600,300); // cannot use timestamp, since ranges may change
this.yLabel = yLabel;
}
......
......@@ -33,6 +33,8 @@ import hudson.tasks.junit.TestResultAction;
import org.kohsuke.stapler.*;
import org.kohsuke.stapler.export.ExportedBean;
import com.google.common.collect.MapMaker;
import javax.servlet.ServletException;
import java.io.IOException;
import java.util.*;
......@@ -339,7 +341,7 @@ public abstract class TestObject extends hudson.tasks.junit.TestObject {
UNIQUIFIED_NAMES.put(this, uniquified);
return uniquified;
}
private static final Map<TestObject, String> UNIQUIFIED_NAMES = new WeakHashMap<TestObject, String>();
private static final Map<TestObject, String> UNIQUIFIED_NAMES = new MapMaker().weakKeys().makeMap();
/**
* Replaces URL-unsafe characters.
......
......@@ -29,7 +29,8 @@ THE SOFTWARE.
<h1>${it.pronoun} ${it.displayName}</h1>
<t:editableDescription permission="${it.CONFIGURE}"/>
<j:if test="${it.disabled}">
<j:choose>
<j:when test="${it.disabled}">
<div class="warning">
<form method="post" action="enable">
${%This project is currently disabled}
......@@ -38,7 +39,17 @@ THE SOFTWARE.
</l:hasPermission>
</form>
</div>
</j:if>
</j:when>
<j:otherwise>
<div align="right">
<form method="post" action="disable">
<l:hasPermission permission="${it.CONFIGURE}">
<f:submit value="${%Disable Project}" />
</l:hasPermission>
</form>
</div>
</j:otherwise>
</j:choose>
<st:include page="jobpropertysummaries.jelly" />
<!-- inject main part here -->
......
......@@ -35,7 +35,7 @@ THE SOFTWARE.
<td class="pane-header" style="width:5em">${%Test Result}</td>
</tr>
<tbody>
<j:forEach var="b" items="${it.owner.parent.builds}">
<j:forEach var="b" items="${it.owner.parent.builds}" begin="${start}" end="${end}">
<j:set var="test" value="${it.getResultInBuild(b)}"/>
<j:if test="${test != null}">
<tr>
......
......@@ -34,7 +34,7 @@ THE SOFTWARE.
<td class="pane-header" style="width:5em">${%Total}</td>
</tr>
<tbody>
<j:forEach var="b" items="${it.owner.parent.builds}">
<j:forEach var="b" items="${it.owner.parent.builds}" begin="${start}" end="${end}">
<j:set var="p" value="${it.getResultInBuild(b)}"/>
<j:if test="${p != null}">
<tr>
......
......@@ -25,18 +25,20 @@ THE SOFTWARE.
<!-- Displays the chart that show how long builds are taking -->
<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" xmlns:i="jelly:fmt">
<l:layout title="${%title(it.testObject.displayName)}">
<j:set var="start" value="${request.getParameter('start')?:0}"/>
<j:set var="end" value="${request.getParameter('end')?:start+24}"/>
<j:set var="rangeParameters" value="start=${start}&amp;end=${end+1}"/>
<script type="text/javascript">
function setCount() {
document.getElementById("graph").src = "countGraph/png";
document.getElementById("graph").lazyMap = "countGraph/map";
document.getElementById("graph").src = "countGraph/png?${rangeParameters}";
document.getElementById("graph").lazyMap = "countGraph/map?${rangeParameters}";
document.getElementById("graph").alt = "[Count graph]";
document.getElementById("duration-link").style.display = "";
document.getElementById("count-link").style.display = "none";
}
function setDuration() {
document.getElementById("graph").src = "durationGraph/png"
document.getElementById("graph").lazyMap = "durationGraph/map"
document.getElementById("graph").src = "durationGraph/png?${rangeParameters}"
document.getElementById("graph").lazyMap = "durationGraph/map?${rangeParameters}"
document.getElementById("graph").alt = "[Duration graph]";
document.getElementById("duration-link").style.display = "none";
document.getElementById("count-link").style.display = "";
......@@ -49,7 +51,7 @@ THE SOFTWARE.
<j:choose>
<j:when test="${it.historyAvailable()}">
<div align="center">
<img id="graph" src="durationGraph/png" width="600" height="300" lazymap="durationGraph/map" alt="[Duration graph]"/>
<img id="graph" src="durationGraph/png?${rangeParameters}" width="600" height="300" lazymap="durationGraph/map?${rangeParameters}" alt="[Duration graph]"/>
</div>
<div align="center">
show
......@@ -62,6 +64,15 @@ THE SOFTWARE.
</j:otherwise>
</j:choose>
<st:include from="${it.testObject}" it="${it.testObject}" page="list.jelly" optional="true"/>
<div>
<j:if test="${start > 0}">
<a href="${app.rootUrl}${it.testObject.owner.url}testReport${it.testObject.url}/history${(start-25)>0?'?start='+(start-25):''}">${%Newer}</a>
</j:if>
 
<j:if test="${it.testObject.owner.project.builds.size() > end}">
<a href="${app.rootUrl}${it.testObject.owner.url}testReport${it.testObject.url}/history?start=${end+1}">${%Older}</a>
</j:if>
</div>
</l:main-panel>
</l:layout>
</j:jelly>
\ No newline at end of file
......@@ -34,7 +34,7 @@ THE SOFTWARE.
<td class="pane-header" style="width:5em">${%Total}</td>
</tr>
<tbody>
<j:forEach var="b" items="${it.owner.parent.builds}">
<j:forEach var="b" items="${it.owner.parent.builds}" begin="${start}" end="${end}">
<j:set var="p" value="${it.getResultInBuild(b)}"/>
<j:if test="${p != null}">
<tr>
......
......@@ -954,14 +954,14 @@ public class Channel implements VirtualChannel, IChannel {
ioe.initCause(e);
throw ioe;
} catch (ClassNotFoundException e) {
logger.log(Level.SEVERE, "Unable to read a command",e);
logger.log(Level.SEVERE, "Unable to read a command (channel " + name + ")",e);
}
if(logger.isLoggable(Level.FINE))
logger.fine("Received "+cmd);
try {
cmd.execute(Channel.this);
} catch (Throwable t) {
logger.log(Level.SEVERE, "Failed to execute command "+cmd,t);
logger.log(Level.SEVERE, "Failed to execute command "+cmd+ " (channel " + name + ")",t);
logger.log(Level.SEVERE, "This command is created here",cmd.createdAt);
}
}
......
......@@ -800,7 +800,7 @@ DIV.yahooTree td {
#search-box {
background: white url(../images/16x16/search.gif) no-repeat 2px center;
padding-left: 20px;
width: 10em;
width: 15em;
position: static;
}
......@@ -810,14 +810,14 @@ DIV.yahooTree td {
#search-box-completion {
text-align: left;
width:10em;
width:25em;
position: absolute;
z-index: 999;
}
#search-box-completion .yui-ac-content {
border: 1px solid black;
width:10em;
width:25em;
background-color: white;
overflow: hidden;
}
......@@ -838,7 +838,7 @@ DIV.yahooTree td {
#search-box-minWidth {
position:absolute;
visibility: hidden;
width:5em;
width:15em;
}
#search-box-sizer {
......@@ -846,6 +846,7 @@ DIV.yahooTree td {
visibility: hidden;
}
/* ========================= resizable text area ========================= */
TEXTAREA {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册