提交 747238d8 编写于 作者: J Jesse Glick

Merge branch 'rc' into security-rc

...@@ -61,7 +61,56 @@ Upcoming changes</a> ...@@ -61,7 +61,56 @@ Upcoming changes</a>
<!-- these changes are controlled by the release process. DO NOT MODIFY --> <!-- these changes are controlled by the release process. DO NOT MODIFY -->
<div id="rc" style="display:none;"><!--=BEGIN=--> <div id="rc" style="display:none;"><!--=BEGIN=-->
<h3><a name=v1.578>What's new in 1.578</a> <!--=DATE=--></h3> <h3><a name=v1.581>What's new in 1.581</a> <!--=DATE=--></h3>
<ul class=image>
<li class=rfe>
Use slightly larger Jenkins head icon.
(<a href="https://github.com/jenkinsci/jenkins/pull/1360">pull 1360</a>)
<li class=rfe>
Allow setting a system property to disable X-Frame-Options header.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-21881">issue 21881</a>)
<li class=bug>
Explicitly set background color of various UI elements to white.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-24625">issue 24625</a>)
<li class=bug>
Wrong Hebrew localization resulted in broken console output since 1.539.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-24614">issue 24614</a>)
</ul>
</div><!--=END=-->
<h3><a name=v1.580>What's new in 1.580</a> (2014/09/14)</h3>
<ul class=image>
<li class=bug>
Health reports saved to disk before 1.576 showed no weather icon since that version.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-24407">issue 24407</a>)
<li class=bug>
Renaming jobs fails if parent dir of custom build records directory does not exist.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-19764">issue 19764</a>)
<li class=rfe>
Add editable descriptions for label atoms.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-6153">issue 6153</a>)
</ul>
<h3><a name=v1.579>What's new in 1.579</a> (2014/09/06)</h3>
<ul class=image>
<li class=bug>
<code>ConcurrentModificationException</code> in <code>RunListProgressiveRendering</code>.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-21437">issue 21437</a>)
<li class=bug>
<code>StackOverflowError</code> for some old <code>SCMListener</code>s.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-23522">issue 23522</a>)
<li class=bug>
Job status page shows "Build has been executing for null on master" for flyweight tasks.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-20307">issue 20307</a>)
<li class=bug>
File locking issue when running functional tests on Windows.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-21977">issue 21977</a>)
<li class=bug>
Tolerate ?auto_refresh in reverse proxy check on /manage page.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-24014">issue 24014</a>)
<li class=rfe>
Debian package now sets umask to 027 by default for better default privacy. See <tt>/etc/default/jenkins</tt> to change this.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-24514">issue 24514</a>)
</ul>
<h3><a name=v1.578>What's new in 1.578</a> (2014/08/31)</h3>
<ul class=image> <ul class=image>
<li class=rfe> <li class=rfe>
Added 'no-store' to the 'Cache-Control' header to avoid accidental information leak through local cache backup Added 'no-store' to the 'Cache-Control' header to avoid accidental information leak through local cache backup
...@@ -73,7 +122,6 @@ Upcoming changes</a> ...@@ -73,7 +122,6 @@ Upcoming changes</a>
Use absolute links for computer sidepanel items so they don't break as easily. Use absolute links for computer sidepanel items so they don't break as easily.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-23963">issue 23963</a>) (<a href="https://issues.jenkins-ci.org/browse/JENKINS-23963">issue 23963</a>)
</ul> </ul>
</div><!--=END=-->
<h3><a name=v1.577>What's new in 1.577</a> (2014/08/24)</h3> <h3><a name=v1.577>What's new in 1.577</a> (2014/08/24)</h3>
<ul class=image> <ul class=image>
<li class="major bug"> <li class="major bug">
...@@ -88,6 +136,11 @@ Upcoming changes</a> ...@@ -88,6 +136,11 @@ Upcoming changes</a>
<li class=bug> <li class=bug>
Fixed ClassCastException on org.dom4j.DocumentFactory Fixed ClassCastException on org.dom4j.DocumentFactory
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-13709">issue 13709</a>) (<a href="https://issues.jenkins-ci.org/browse/JENKINS-13709">issue 13709</a>)
<li class="rfe">
Jenkins now logs warnings when it fails to export objects to XML/JSON.
This can result in a lot of log output in case of heavy API use.
We recommend that API users use the <code>?tree</code> parameter instead of <code>?depth</code>.
(<a href="https://github.com/stapler/stapler/commit/ed2cb8b04c1514377f3a8bfbd567f050a67c6e1c">commit</a>)
<li class=rfe> <li class=rfe>
Allow BuildStep to work with non-AbstractProject Allow BuildStep to work with non-AbstractProject
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-23713">issue 23713</a>) (<a href="https://issues.jenkins-ci.org/browse/JENKINS-23713">issue 23713</a>)
...@@ -806,6 +859,9 @@ Upcoming changes</a> ...@@ -806,6 +859,9 @@ Upcoming changes</a>
<li class=rfe> <li class=rfe>
Add Batch Command tool installer for Windows nodes. Add Batch Command tool installer for Windows nodes.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-21202">issue 21202</a>) (<a href="https://issues.jenkins-ci.org/browse/JENKINS-21202">issue 21202</a>)
<li class=rfe>
Allow more specific loggers to reduce log level.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-21386">issue 21386</a>)
</ul> </ul>
<h3><a name=v1.548>What's new in 1.548</a> (2014/01/20)</h3> <h3><a name=v1.548>What's new in 1.548</a> (2014/01/20)</h3>
<ul class=image> <ul class=image>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<parent> <parent>
<artifactId>pom</artifactId> <artifactId>pom</artifactId>
<groupId>org.jenkins-ci.main</groupId> <groupId>org.jenkins-ci.main</groupId>
<version>1.578-SNAPSHOT</version> <version>1.581-SNAPSHOT</version>
</parent> </parent>
<artifactId>cli</artifactId> <artifactId>cli</artifactId>
......
...@@ -59,12 +59,14 @@ public class ConnectionTest extends Assert { ...@@ -59,12 +59,14 @@ public class ConnectionTest extends Assert {
t1.join(9999); t1.join(9999);
t2.join(9999); t2.join(9999);
if (e != null) {
throw e;
}
if (t1.isAlive() || t2.isAlive()) { if (t1.isAlive() || t2.isAlive()) {
t1.interrupt(); t1.interrupt();
t2.interrupt(); t2.interrupt();
throw new Error("thread is still alive"); throw new Error("thread is still alive");
} }
if (e!=null) throw e;
} }
} }
...@@ -29,7 +29,7 @@ THE SOFTWARE. ...@@ -29,7 +29,7 @@ THE SOFTWARE.
<parent> <parent>
<groupId>org.jenkins-ci.main</groupId> <groupId>org.jenkins-ci.main</groupId>
<artifactId>pom</artifactId> <artifactId>pom</artifactId>
<version>1.578-SNAPSHOT</version> <version>1.581-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
...@@ -484,7 +484,7 @@ THE SOFTWARE. ...@@ -484,7 +484,7 @@ THE SOFTWARE.
<dependency> <dependency>
<groupId>org.jvnet.winp</groupId> <groupId>org.jvnet.winp</groupId>
<artifactId>winp</artifactId> <artifactId>winp</artifactId>
<version>1.20</version> <version>1.21</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jenkins-ci</groupId> <groupId>org.jenkins-ci</groupId>
......
...@@ -111,6 +111,7 @@ import java.util.regex.Pattern; ...@@ -111,6 +111,7 @@ import java.util.regex.Pattern;
import static hudson.FilePath.TarCompression.*; import static hudson.FilePath.TarCompression.*;
import static hudson.Util.*; import static hudson.Util.*;
import javax.annotation.Nonnull;
/** /**
* {@link File} like object with remoting support. * {@link File} like object with remoting support.
...@@ -1161,7 +1162,7 @@ public final class FilePath implements Serializable { ...@@ -1161,7 +1162,7 @@ public final class FilePath implements Serializable {
* @param relOrAbsolute a relative or absolute path * @param relOrAbsolute a relative or absolute path
* @return a file on the same channel * @return a file on the same channel
*/ */
public FilePath child(String relOrAbsolute) { public @Nonnull FilePath child(String relOrAbsolute) {
return new FilePath(this,relOrAbsolute); return new FilePath(this,relOrAbsolute);
} }
......
...@@ -1009,7 +1009,7 @@ public abstract class Launcher { ...@@ -1009,7 +1009,7 @@ public abstract class Launcher {
* *
* @author rcampbell * @author rcampbell
* @author Oleg Nenashev, Synopsys Inc. * @author Oleg Nenashev, Synopsys Inc.
* @since TODO: define version * @since 1.568
*/ */
public static class DecoratedLauncher extends Launcher { public static class DecoratedLauncher extends Launcher {
......
...@@ -74,7 +74,7 @@ public class ReverseProxySetupMonitor extends AdministrativeMonitor { ...@@ -74,7 +74,7 @@ public class ReverseProxySetupMonitor extends AdministrativeMonitor {
assert j != null; assert j != null;
String inferred = j.getRootUrlFromRequest() + "manage"; String inferred = j.getRootUrlFromRequest() + "manage";
// TODO this could also verify that j.getRootUrl() has been properly configured, and send a different message if not // TODO this could also verify that j.getRootUrl() has been properly configured, and send a different message if not
if (rest.equals(inferred)) { if (rest.startsWith(inferred)) { // not using equals due to JENKINS-24014
throw HttpResponses.ok(); throw HttpResponses.ok();
} else { } else {
LOGGER.log(Level.WARNING, "{0} vs. {1}", new Object[] {inferred, rest}); LOGGER.log(Level.WARNING, "{0} vs. {1}", new Object[] {inferred, rest});
......
...@@ -292,7 +292,7 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs ...@@ -292,7 +292,7 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
* Normally, a workspace is assigned by {@link hudson.model.Run.RunExecution}, but this lets you set the workspace in case * Normally, a workspace is assigned by {@link hudson.model.Run.RunExecution}, but this lets you set the workspace in case
* {@link AbstractBuild} is created without a build. * {@link AbstractBuild} is created without a build.
*/ */
protected void setWorkspace(FilePath ws) { protected void setWorkspace(@Nonnull FilePath ws) {
this.workspace = ws.getRemote(); this.workspace = ws.getRemote();
} }
......
...@@ -1432,7 +1432,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A ...@@ -1432,7 +1432,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
} }
} }
private PollingResult pollWithWorkspace(TaskListener listener, SCM scm, R lb, FilePath ws, WorkspaceList l) throws InterruptedException, IOException { private PollingResult pollWithWorkspace(TaskListener listener, SCM scm, R lb, @Nonnull FilePath ws, WorkspaceList l) throws InterruptedException, IOException {
// if doing non-concurrent build, acquire a workspace in a way that causes builds to block for this workspace. // if doing non-concurrent build, acquire a workspace in a way that causes builds to block for this workspace.
// this prevents multiple workspaces of the same job --- the behavior of Hudson < 1.319. // this prevents multiple workspaces of the same job --- the behavior of Hudson < 1.319.
// //
......
...@@ -23,11 +23,13 @@ ...@@ -23,11 +23,13 @@
*/ */
package hudson.model; package hudson.model;
import hudson.slaves.SlaveComputer;
/** /**
* A listener for task related events from Executors * A listener for task related events from executors.
* * A {@link Computer#getRetentionStrategy} or {@link SlaveComputer#getLauncher} may implement this interface.
* @author Stephen Connolly * @author Stephen Connolly
* @since 17-Jun-2008 18:58:12 * @since 1.312
*/ */
public interface ExecutorListener { public interface ExecutorListener {
...@@ -47,7 +49,7 @@ public interface ExecutorListener { ...@@ -47,7 +49,7 @@ public interface ExecutorListener {
void taskCompleted(Executor executor, Queue.Task task, long durationMS); void taskCompleted(Executor executor, Queue.Task task, long durationMS);
/** /**
* Called whenever a task is completed without any problems by an executor. * Called whenever a task is completed with some problems by an executor.
* @param executor The executor. * @param executor The executor.
* @param task The task. * @param task The task.
* @param durationMS The number of milliseconds that the task took to complete. * @param durationMS The number of milliseconds that the task took to complete.
......
...@@ -34,7 +34,9 @@ import org.kohsuke.stapler.export.ExportedBean; ...@@ -34,7 +34,9 @@ import org.kohsuke.stapler.export.ExportedBean;
import java.io.*; import java.io.*;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Represents health of something (typically project). * Represents health of something (typically project).
...@@ -60,6 +62,15 @@ public class HealthReport implements Serializable, Comparable<HealthReport> { ...@@ -60,6 +62,15 @@ public class HealthReport implements Serializable, Comparable<HealthReport> {
private static final String HEALTH_0_TO_20_IMG = "health-00to19.png"; private static final String HEALTH_0_TO_20_IMG = "health-00to19.png";
private static final String HEALTH_UNKNOWN_IMG = "empty.png"; private static final String HEALTH_UNKNOWN_IMG = "empty.png";
private static final Map<String, String> iconIMGToClassMap = new HashMap<String, String>();
static {
iconIMGToClassMap.put(HEALTH_OVER_80_IMG, HEALTH_OVER_80);
iconIMGToClassMap.put(HEALTH_61_TO_80_IMG, HEALTH_61_TO_80);
iconIMGToClassMap.put(HEALTH_41_TO_60_IMG, HEALTH_41_TO_60);
iconIMGToClassMap.put(HEALTH_21_TO_40_IMG, HEALTH_21_TO_40);
iconIMGToClassMap.put(HEALTH_0_TO_20_IMG, HEALTH_0_TO_20);
}
/** /**
* The percentage health score (from 0 to 100 inclusive). * The percentage health score (from 0 to 100 inclusive).
*/ */
...@@ -351,6 +362,10 @@ public class HealthReport implements Serializable, Comparable<HealthReport> { ...@@ -351,6 +362,10 @@ public class HealthReport implements Serializable, Comparable<HealthReport> {
hr.localizibleDescription = new NonLocalizable(hr.description == null ? "" : hr.description); hr.localizibleDescription = new NonLocalizable(hr.description == null ? "" : hr.description);
OldDataMonitor.report(context, "1.256"); OldDataMonitor.report(context, "1.256");
} }
if (hr.iconClassName == null && hr.iconUrl != null && iconIMGToClassMap.containsKey(hr.iconUrl)) {
hr.iconClassName = iconIMGToClassMap.get(hr.iconUrl);
}
} }
} }
} }
...@@ -224,7 +224,7 @@ public interface Item extends PersistenceRoot, SearchableModelObject, AccessCont ...@@ -224,7 +224,7 @@ public interface Item extends PersistenceRoot, SearchableModelObject, AccessCont
Permission DELETE = new Permission(PERMISSIONS, "Delete", Messages._Item_DELETE_description(), Permission.DELETE, PermissionScope.ITEM); Permission DELETE = new Permission(PERMISSIONS, "Delete", Messages._Item_DELETE_description(), Permission.DELETE, PermissionScope.ITEM);
Permission CONFIGURE = new Permission(PERMISSIONS, "Configure", Messages._Item_CONFIGURE_description(), Permission.CONFIGURE, PermissionScope.ITEM); Permission CONFIGURE = new Permission(PERMISSIONS, "Configure", Messages._Item_CONFIGURE_description(), Permission.CONFIGURE, PermissionScope.ITEM);
Permission READ = new Permission(PERMISSIONS, "Read", Messages._Item_READ_description(), Permission.READ, PermissionScope.ITEM); Permission READ = new Permission(PERMISSIONS, "Read", Messages._Item_READ_description(), Permission.READ, PermissionScope.ITEM);
Permission DISCOVER = new Permission(PERMISSIONS, "Discover", Messages._AbstractProject_DiscoverPermission_Description(), Permission.READ, PermissionScope.ITEM); Permission DISCOVER = new Permission(PERMISSIONS, "Discover", Messages._AbstractProject_DiscoverPermission_Description(), READ, PermissionScope.ITEM);
Permission EXTENDED_READ = new Permission(PERMISSIONS,"ExtendedRead", Messages._AbstractProject_ExtendedReadPermission_Description(), CONFIGURE, Boolean.getBoolean("hudson.security.ExtendedReadPermission"), new PermissionScope[]{PermissionScope.ITEM}); Permission EXTENDED_READ = new Permission(PERMISSIONS,"ExtendedRead", Messages._AbstractProject_ExtendedReadPermission_Description(), CONFIGURE, Boolean.getBoolean("hudson.security.ExtendedReadPermission"), new PermissionScope[]{PermissionScope.ITEM});
// TODO the following really belong in Job, not Item, but too late to move since the owner.name is encoded in the ID: // TODO the following really belong in Job, not Item, but too late to move since the owner.name is encoded in the ID:
Permission BUILD = new Permission(PERMISSIONS, "Build", Messages._AbstractProject_BuildPermission_Description(), Permission.UPDATE, PermissionScope.ITEM); Permission BUILD = new Permission(PERMISSIONS, "Build", Messages._AbstractProject_BuildPermission_Description(), Permission.UPDATE, PermissionScope.ITEM);
......
...@@ -28,6 +28,7 @@ import java.io.IOException; ...@@ -28,6 +28,7 @@ import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.io.File; import java.io.File;
import javax.annotation.CheckForNull; import javax.annotation.CheckForNull;
import org.acegisecurity.AccessDeniedException;
/** /**
* Represents a grouping inherent to a kind of {@link Item}s. * Represents a grouping inherent to a kind of {@link Item}s.
...@@ -67,8 +68,10 @@ public interface ItemGroup<T extends Item> extends PersistenceRoot, ModelObject ...@@ -67,8 +68,10 @@ public interface ItemGroup<T extends Item> extends PersistenceRoot, ModelObject
/** /**
* Gets the {@link Item} inside this group that has a given name, or null if it does not exist. * Gets the {@link Item} inside this group that has a given name, or null if it does not exist.
* @throws AccessDeniedException if the current user has {@link Item#DISCOVER} but not {@link Item#READ} on this item
* @return an item whose {@link Item#getName} is {@code name} and whose {@link Item#getParent} is {@code this}, or null if there is no such item, or there is but the current user lacks both {@link Item#DISCOVER} and {@link Item#READ} on it
*/ */
@CheckForNull T getItem(String name); @CheckForNull T getItem(String name) throws AccessDeniedException;
/** /**
* Assigns the {@link Item#getRootDir() root directory} for children. * Assigns the {@link Item#getRootDir() root directory} for children.
......
...@@ -619,6 +619,9 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R ...@@ -619,6 +619,9 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
super.renameTo(newName); super.renameTo(newName);
File newBuildDir = getBuildDir(); File newBuildDir = getBuildDir();
if (oldBuildDir.isDirectory() && !newBuildDir.isDirectory()) { if (oldBuildDir.isDirectory() && !newBuildDir.isDirectory()) {
if (!newBuildDir.getParentFile().isDirectory()) {
newBuildDir.getParentFile().mkdirs();
}
if (!oldBuildDir.renameTo(newBuildDir)) { if (!oldBuildDir.renameTo(newBuildDir)) {
throw new IOException("failed to rename " + oldBuildDir + " to " + newBuildDir); throw new IOException("failed to rename " + oldBuildDir + " to " + newBuildDir);
} }
......
...@@ -142,6 +142,13 @@ public abstract class Label extends Actionable implements Comparable<Label>, Mod ...@@ -142,6 +142,13 @@ public abstract class Label extends Actionable implements Comparable<Label>, Mod
return getUrl(); return getUrl();
} }
/**
* Returns true iff this label is an atom.
*
* @since 1.580
*/
public boolean isAtom() { return false; }
/** /**
* Evaluates whether the label expression is true given the specified value assignment. * Evaluates whether the label expression is true given the specified value assignment.
* IOW, returns true if the assignment provided by the resolver matches this label expression. * IOW, returns true if the assignment provided by the resolver matches this label expression.
......
...@@ -1073,16 +1073,20 @@ public class Queue extends ResourceController implements Saveable { ...@@ -1073,16 +1073,20 @@ public class Queue extends ResourceController implements Saveable {
private void makeBuildable(BuildableItem p) { private void makeBuildable(BuildableItem p) {
if(Jenkins.FLYWEIGHT_SUPPORT && p.task instanceof FlyweightTask && !ifBlockedByHudsonShutdown(p.task)) { if(Jenkins.FLYWEIGHT_SUPPORT && p.task instanceof FlyweightTask && !ifBlockedByHudsonShutdown(p.task)) {
ConsistentHash<Node> hash = new ConsistentHash<Node>(new Hash<Node>() {
public String hash(Node node) {
return node.getNodeName();
}
});
Jenkins h = Jenkins.getInstance(); Jenkins h = Jenkins.getInstance();
Map<Node,Integer> hashSource = new HashMap<Node, Integer>(h.getNodes().size());
// Even if master is configured with zero executors, we may need to run a flyweight task like MatrixProject on it. // Even if master is configured with zero executors, we may need to run a flyweight task like MatrixProject on it.
hash.add(h, Math.max(h.getNumExecutors()*100, 1)); hashSource.put(h, Math.max(h.getNumExecutors() * 100, 1));
for (Node n : h.getNodes())
hash.add(n, n.getNumExecutors()*100); for (Node n : h.getNodes()) {
hashSource.put(n, n.getNumExecutors() * 100);
}
ConsistentHash<Node> hash = new ConsistentHash<Node>(NODE_HASH);
hash.addAll(hashSource);
Label lbl = p.getAssignedLabel(); Label lbl = p.getAssignedLabel();
for (Node n : hash.list(p.task.getFullDisplayName())) { for (Node n : hash.list(p.task.getFullDisplayName())) {
...@@ -1101,6 +1105,13 @@ public class Queue extends ResourceController implements Saveable { ...@@ -1101,6 +1105,13 @@ public class Queue extends ResourceController implements Saveable {
p.enter(this); p.enter(this);
} }
private static Hash<Node> NODE_HASH = new Hash<Node>() {
public String hash(Node node) {
return node.getNodeName();
}
};
private boolean makePending(BuildableItem p) { private boolean makePending(BuildableItem p) {
// LOGGER.info("Making "+p.task+" pending"); // REMOVE // LOGGER.info("Making "+p.task+" pending"); // REMOVE
p.isPending = true; p.isPending = true;
......
...@@ -507,6 +507,11 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run ...@@ -507,6 +507,11 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
if(e.getCurrentExecutable()==this) if(e.getCurrentExecutable()==this)
return e; return e;
} }
for (Executor e : c.getOneOffExecutors()) {
if(e.getCurrentExecutable()==this) {
return e;
}
}
} }
return null; return null;
} }
......
...@@ -33,15 +33,13 @@ import hudson.XmlFile; ...@@ -33,15 +33,13 @@ import hudson.XmlFile;
import hudson.model.Action; import hudson.model.Action;
import hudson.model.Descriptor.FormException; import hudson.model.Descriptor.FormException;
import hudson.model.Failure; import hudson.model.Failure;
import hudson.util.EditDistance; import hudson.util.*;
import jenkins.model.Jenkins; import jenkins.model.Jenkins;
import hudson.model.Label; import hudson.model.Label;
import hudson.model.Saveable; import hudson.model.Saveable;
import hudson.model.listeners.SaveableListener; import hudson.model.listeners.SaveableListener;
import hudson.util.DescribableList; import org.kohsuke.accmod.Restricted;
import hudson.util.QuotedStringTokenizer; import org.kohsuke.accmod.restrictions.DoNotUse;
import hudson.util.VariableResolver;
import hudson.util.XStream2;
import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.export.Exported; import org.kohsuke.stapler.export.Exported;
...@@ -73,6 +71,8 @@ public class LabelAtom extends Label implements Saveable { ...@@ -73,6 +71,8 @@ public class LabelAtom extends Label implements Saveable {
@CopyOnWrite @CopyOnWrite
protected transient volatile List<Action> transientActions = new Vector<Action>(); protected transient volatile List<Action> transientActions = new Vector<Action>();
private String description;
public LabelAtom(String name) { public LabelAtom(String name) {
super(name); super(name);
} }
...@@ -85,6 +85,9 @@ public class LabelAtom extends Label implements Saveable { ...@@ -85,6 +85,9 @@ public class LabelAtom extends Label implements Saveable {
return escape(name); return escape(name);
} }
@Override
public boolean isAtom() { return true; }
/** /**
* {@inheritDoc} * {@inheritDoc}
* *
...@@ -106,33 +109,24 @@ public class LabelAtom extends Label implements Saveable { ...@@ -106,33 +109,24 @@ public class LabelAtom extends Label implements Saveable {
protected void updateTransientActions() { protected void updateTransientActions() {
Vector<Action> ta = new Vector<Action>(); Vector<Action> ta = new Vector<Action>();
// add the config link
if (!getApplicablePropertyDescriptors().isEmpty()) {
// if there's no property descriptor, there's nothing interesting to configure.
ta.add(new Action() {
public String getIconFileName() {
if (Jenkins.getInstance().hasPermission(Jenkins.ADMINISTER))
return "setting.png";
else
return null;
}
public String getDisplayName() {
return "Configure";
}
public String getUrlName() {
return "configure";
}
});
}
for (LabelAtomProperty p : properties) for (LabelAtomProperty p : properties)
ta.addAll(p.getActions(this)); ta.addAll(p.getActions(this));
transientActions = ta; transientActions = ta;
} }
/**
* @since TODO
*/
public String getDescription() {
return description;
}
public void setDescription(String description) throws IOException {
this.description = description;
save();
}
/** /**
* Properties associated with this label. * Properties associated with this label.
*/ */
...@@ -210,11 +204,25 @@ public class LabelAtom extends Label implements Saveable { ...@@ -210,11 +204,25 @@ public class LabelAtom extends Label implements Saveable {
app.checkPermission(Jenkins.ADMINISTER); app.checkPermission(Jenkins.ADMINISTER);
properties.rebuild(req, req.getSubmittedForm(), getApplicablePropertyDescriptors()); properties.rebuild(req, req.getSubmittedForm(), getApplicablePropertyDescriptors());
this.description = req.getSubmittedForm().getString("description");
updateTransientActions(); updateTransientActions();
save(); save();
// take the user back to the label top page. FormApply.success(".").generateResponse(req, rsp, null);
rsp.sendRedirect2("."); }
/**
* Accepts the new description.
*/
@RequirePOST
@Restricted(DoNotUse.class)
public synchronized void doSubmitDescription( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException {
Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
setDescription(req.getParameter("description"));
rsp.sendRedirect("."); // go to the top page
} }
/** /**
......
...@@ -116,7 +116,9 @@ public abstract class SCMListener implements ExtensionPoint { ...@@ -116,7 +116,9 @@ public abstract class SCMListener implements ExtensionPoint {
@Deprecated @Deprecated
public void onChangeLogParsed(AbstractBuild<?,?> build, BuildListener listener, ChangeLogSet<?> changelog) throws Exception { public void onChangeLogParsed(AbstractBuild<?,?> build, BuildListener listener, ChangeLogSet<?> changelog) throws Exception {
onChangeLogParsed((Run) build, build.getProject().getScm(), listener, changelog); if (Util.isOverridden(SCMListener.class, getClass(), "onChangeLogParsed", Run.class, SCM.class, TaskListener.class, ChangeLogSet.class)) {
onChangeLogParsed((Run) build, build.getProject().getScm(), listener, changelog);
}
} }
/** /**
......
...@@ -68,6 +68,10 @@ public class ChannelPinger extends ComputerListener { ...@@ -68,6 +68,10 @@ public class ChannelPinger extends ComputerListener {
@Override @Override
public void preOnline(Computer c, Channel channel, FilePath root, TaskListener listener) { public void preOnline(Computer c, Channel channel, FilePath root, TaskListener listener) {
install(channel);
}
public void install(Channel channel) {
if (pingInterval < 1) { if (pingInterval < 1) {
LOGGER.fine("Slave ping is disabled"); LOGGER.fine("Slave ping is disabled");
return; return;
...@@ -75,9 +79,9 @@ public class ChannelPinger extends ComputerListener { ...@@ -75,9 +79,9 @@ public class ChannelPinger extends ComputerListener {
try { try {
channel.call(new SetUpRemotePing(pingInterval)); channel.call(new SetUpRemotePing(pingInterval));
LOGGER.fine("Set up a remote ping for " + c.getName()); LOGGER.fine("Set up a remote ping for " + channel.getName());
} catch (Exception e) { } catch (Exception e) {
LOGGER.severe("Failed to set up a ping for " + c.getName()); LOGGER.severe("Failed to set up a ping for " + channel.getName());
} }
// set up ping from both directions, so that in case of a router dropping a connection, // set up ping from both directions, so that in case of a router dropping a connection,
......
...@@ -32,6 +32,7 @@ import java.util.HashMap; ...@@ -32,6 +32,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.annotation.Nonnull;
/** /**
* Used by {@link Computer} to keep track of workspaces that are actively in use. * Used by {@link Computer} to keep track of workspaces that are actively in use.
...@@ -72,7 +73,7 @@ public final class WorkspaceList { ...@@ -72,7 +73,7 @@ public final class WorkspaceList {
*/ */
public final boolean quick; public final boolean quick;
public final FilePath path; public final @Nonnull FilePath path;
/** /**
* Multiple threads can acquire the same lock if they share the same context object. * Multiple threads can acquire the same lock if they share the same context object.
...@@ -81,11 +82,11 @@ public final class WorkspaceList { ...@@ -81,11 +82,11 @@ public final class WorkspaceList {
public int lockCount=1; public int lockCount=1;
private Entry(FilePath path, boolean quick) { private Entry(@Nonnull FilePath path, boolean quick) {
this(path,quick,new Object()); // unique context this(path,quick,new Object()); // unique context
} }
private Entry(FilePath path, boolean quick, Object context) { private Entry(@Nonnull FilePath path, boolean quick, Object context) {
this.path = path; this.path = path;
this.quick = quick; this.quick = quick;
this.context = context; this.context = context;
...@@ -104,9 +105,10 @@ public final class WorkspaceList { ...@@ -104,9 +105,10 @@ public final class WorkspaceList {
* Represents a leased workspace that needs to be returned later. * Represents a leased workspace that needs to be returned later.
*/ */
public static abstract class Lease { public static abstract class Lease {
public final FilePath path; public final @Nonnull FilePath path;
protected Lease(FilePath path) { protected Lease(@Nonnull FilePath path) {
path.getRemote(); // null check
this.path = path; this.path = path;
} }
...@@ -118,7 +120,7 @@ public final class WorkspaceList { ...@@ -118,7 +120,7 @@ public final class WorkspaceList {
/** /**
* Creates a dummy {@link Lease} object that does no-op in the release. * Creates a dummy {@link Lease} object that does no-op in the release.
*/ */
public static Lease createDummyLease(FilePath p) { public static Lease createDummyLease(@Nonnull FilePath p) {
return new Lease(p) { return new Lease(p) {
public void release() { public void release() {
// noop // noop
...@@ -130,7 +132,7 @@ public final class WorkspaceList { ...@@ -130,7 +132,7 @@ public final class WorkspaceList {
* Creates a {@link Lease} object that points to the specified path, but the lock * Creates a {@link Lease} object that points to the specified path, but the lock
* is controlled by the given parent lease object. * is controlled by the given parent lease object.
*/ */
public static Lease createLinkedDummyLease(FilePath p, final Lease parent) { public static Lease createLinkedDummyLease(@Nonnull FilePath p, final Lease parent) {
return new Lease(p) { return new Lease(p) {
public void release() { public void release() {
parent.release(); parent.release();
...@@ -151,7 +153,7 @@ public final class WorkspaceList { ...@@ -151,7 +153,7 @@ public final class WorkspaceList {
* This method doesn't block prolonged amount of time. Whenever a desired workspace * This method doesn't block prolonged amount of time. Whenever a desired workspace
* is in use, the unique variation is added. * is in use, the unique variation is added.
*/ */
public synchronized Lease allocate(FilePath base) throws InterruptedException { public synchronized Lease allocate(@Nonnull FilePath base) throws InterruptedException {
return allocate(base,new Object()); return allocate(base,new Object());
} }
...@@ -162,7 +164,7 @@ public final class WorkspaceList { ...@@ -162,7 +164,7 @@ public final class WorkspaceList {
* Threads that share the same context can re-acquire the same lock (which will just increment the lock count.) * Threads that share the same context can re-acquire the same lock (which will just increment the lock count.)
* This allows related executors to share the same workspace. * This allows related executors to share the same workspace.
*/ */
public synchronized Lease allocate(FilePath base, Object context) throws InterruptedException { public synchronized Lease allocate(@Nonnull FilePath base, Object context) throws InterruptedException {
for (int i=1; ; i++) { for (int i=1; ; i++) {
FilePath candidate = i==1 ? base : base.withSuffix(COMBINATOR+i); FilePath candidate = i==1 ? base : base.withSuffix(COMBINATOR+i);
Entry e = inUse.get(candidate); Entry e = inUse.get(candidate);
...@@ -175,7 +177,7 @@ public final class WorkspaceList { ...@@ -175,7 +177,7 @@ public final class WorkspaceList {
/** /**
* Just record that this workspace is being used, without paying any attention to the synchronization support. * Just record that this workspace is being used, without paying any attention to the synchronization support.
*/ */
public synchronized Lease record(FilePath p) { public synchronized Lease record(@Nonnull FilePath p) {
if (LOGGER.isLoggable(Level.FINE)) { if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "recorded " + p, new Throwable("from " + this)); LOGGER.log(Level.FINE, "recorded " + p, new Throwable("from " + this));
} }
...@@ -188,7 +190,7 @@ public final class WorkspaceList { ...@@ -188,7 +190,7 @@ public final class WorkspaceList {
/** /**
* Releases an allocated or acquired workspace. * Releases an allocated or acquired workspace.
*/ */
private synchronized void _release(FilePath p) { private synchronized void _release(@Nonnull FilePath p) {
Entry old = inUse.get(p); Entry old = inUse.get(p);
if (old==null) if (old==null)
throw new AssertionError("Releasing unallocated workspace "+p); throw new AssertionError("Releasing unallocated workspace "+p);
...@@ -207,7 +209,7 @@ public final class WorkspaceList { ...@@ -207,7 +209,7 @@ public final class WorkspaceList {
* @return * @return
* The same {@link FilePath} as given to this method. * The same {@link FilePath} as given to this method.
*/ */
public synchronized Lease acquire(FilePath p) throws InterruptedException { public synchronized Lease acquire(@Nonnull FilePath p) throws InterruptedException {
return acquire(p,false); return acquire(p,false);
} }
...@@ -218,7 +220,7 @@ public final class WorkspaceList { ...@@ -218,7 +220,7 @@ public final class WorkspaceList {
* If true, indicates that the acquired workspace will be returned quickly. * If true, indicates that the acquired workspace will be returned quickly.
* This makes other calls to {@link #allocate(FilePath)} to wait for the release of this workspace. * This makes other calls to {@link #allocate(FilePath)} to wait for the release of this workspace.
*/ */
public synchronized Lease acquire(FilePath p, boolean quick) throws InterruptedException { public synchronized Lease acquire(@Nonnull FilePath p, boolean quick) throws InterruptedException {
return acquire(p,quick,new Object()); return acquire(p,quick,new Object());
} }
...@@ -229,7 +231,7 @@ public final class WorkspaceList { ...@@ -229,7 +231,7 @@ public final class WorkspaceList {
* Threads that share the same context can re-acquire the same lock (which will just increment the lock count.) * Threads that share the same context can re-acquire the same lock (which will just increment the lock count.)
* This allows related executors to share the same workspace. * This allows related executors to share the same workspace.
*/ */
public synchronized Lease acquire(FilePath p, boolean quick, Object context) throws InterruptedException { public synchronized Lease acquire(@Nonnull FilePath p, boolean quick, Object context) throws InterruptedException {
Entry e; Entry e;
Thread t = Thread.currentThread(); Thread t = Thread.currentThread();
...@@ -257,7 +259,7 @@ public final class WorkspaceList { ...@@ -257,7 +259,7 @@ public final class WorkspaceList {
/** /**
* Wraps a path into a valid lease. * Wraps a path into a valid lease.
*/ */
private Lease lease(FilePath p) { private Lease lease(@Nonnull FilePath p) {
return new Lease(p) { return new Lease(p) {
public void release() { public void release() {
_release(path); _release(path);
......
...@@ -48,7 +48,7 @@ import hudson.util.Iterators.DuplicateFilterIterator; ...@@ -48,7 +48,7 @@ import hudson.util.Iterators.DuplicateFilterIterator;
* and then we use MD5 to create random enough distribution. * and then we use MD5 to create random enough distribution.
* *
* <p> * <p>
* This consistent hash implementaiton is consistent both to the addition/removal of Ts, as well * This consistent hash implementation is consistent both to the addition/removal of Ts, as well
* as increase/decrease of the replicas. * as increase/decrease of the replicas.
* *
* <p> * <p>
...@@ -186,7 +186,7 @@ public class ConsistentHash<T> { ...@@ -186,7 +186,7 @@ public class ConsistentHash<T> {
String hash(T t); String hash(T t);
} }
private static final Hash DEFAULT_HASH = new Hash() { static final Hash DEFAULT_HASH = new Hash() {
public String hash(Object o) { public String hash(Object o) {
return o.toString(); return o.toString();
} }
...@@ -201,13 +201,13 @@ public class ConsistentHash<T> { ...@@ -201,13 +201,13 @@ public class ConsistentHash<T> {
} }
public ConsistentHash(Hash<T> hash) { public ConsistentHash(Hash<T> hash) {
this(hash,100); this(hash, 100);
} }
public ConsistentHash(Hash<T> hash, int defaultReplication) { public ConsistentHash(Hash<T> hash, int defaultReplication) {
this.hash = hash; this.hash = hash;
this.defaultReplication = defaultReplication; this.defaultReplication = defaultReplication;
this.table = new Table(); // initial empty table refreshTable();
} }
public int countAllPoints() { public int countAllPoints() {
...@@ -229,7 +229,8 @@ public class ConsistentHash<T> { ...@@ -229,7 +229,8 @@ public class ConsistentHash<T> {
*/ */
public void addAll(T... nodes) { public void addAll(T... nodes) {
for (T node : nodes) for (T node : nodes)
add(node); addInternal(node,defaultReplication);
refreshTable();
} }
/** /**
...@@ -237,14 +238,24 @@ public class ConsistentHash<T> { ...@@ -237,14 +238,24 @@ public class ConsistentHash<T> {
*/ */
public void addAll(Collection<? extends T> nodes) { public void addAll(Collection<? extends T> nodes) {
for (T node : nodes) for (T node : nodes)
add(node); addInternal(node,defaultReplication);
refreshTable();
}
/**
* Calls {@link #add(Object,int)} with all the arguments.
*/
public void addAll(Map<? extends T,Integer> nodes) {
for (Map.Entry<? extends T,Integer> node : nodes.entrySet())
addInternal(node.getKey(),node.getValue());
refreshTable();
} }
/** /**
* Removes the node entirely. This is the same as {@code add(node,0)} * Removes the node entirely. This is the same as {@code add(node,0)}
*/ */
public void remove(T node) { public void remove(T node) {
add(node,0); add(node, 0);
} }
/** /**
...@@ -254,6 +265,11 @@ public class ConsistentHash<T> { ...@@ -254,6 +265,11 @@ public class ConsistentHash<T> {
* This is the only function that manipulates {@link #items}. * This is the only function that manipulates {@link #items}.
*/ */
public synchronized void add(T node, int replica) { public synchronized void add(T node, int replica) {
addInternal(node, replica);
refreshTable();
}
private void addInternal(T node, int replica) {
if(replica==0) { if(replica==0) {
items.remove(node); items.remove(node);
} else { } else {
...@@ -263,9 +279,13 @@ public class ConsistentHash<T> { ...@@ -263,9 +279,13 @@ public class ConsistentHash<T> {
points[i] = new Point(md5(seed+':'+i),node); points[i] = new Point(md5(seed+':'+i),node);
items.put(node,points); items.put(node,points);
} }
}
private void refreshTable() {
table = new Table(); table = new Table();
} }
/** /**
* Compresses a string into an integer with MD5. * Compresses a string into an integer with MD5.
*/ */
...@@ -314,8 +334,8 @@ public class ConsistentHash<T> { ...@@ -314,8 +334,8 @@ public class ConsistentHash<T> {
* Creates a permutation of all the nodes for the given data point. * Creates a permutation of all the nodes for the given data point.
* *
* <p> * <p>
* The returned pemutation is consistent, in the sense that small change * The returned permutation is consistent, in the sense that small change
* to the consitent hash (like addition/removal/change of replicas) only * to the consistent hash (like addition/removal/change of replicas) only
* creates a small change in the permutation. * creates a small change in the permutation.
* *
* <p> * <p>
......
...@@ -30,7 +30,7 @@ import org.apache.commons.io.IOUtils; ...@@ -30,7 +30,7 @@ import org.apache.commons.io.IOUtils;
* *
* @author Kohsuke Kawaguchi * @author Kohsuke Kawaguchi
*/ */
@Extension(optional=true) @Extension(optional=true) // TODO why would an extension using a built-in extension point need to be marked optional?
public class HsErrPidList extends AdministrativeMonitor { public class HsErrPidList extends AdministrativeMonitor {
/** /**
* hs_err_pid files that we think belong to us. * hs_err_pid files that we think belong to us.
...@@ -43,6 +43,9 @@ public class HsErrPidList extends AdministrativeMonitor { ...@@ -43,6 +43,9 @@ public class HsErrPidList extends AdministrativeMonitor {
private MappedByteBuffer map; private MappedByteBuffer map;
public HsErrPidList() { public HsErrPidList() {
if (Functions.getIsUnitTest()) {
return;
}
try { try {
FileChannel ch = new FileInputStream(getSecretKeyFile()).getChannel(); FileChannel ch = new FileInputStream(getSecretKeyFile()).getChannel();
map = ch.map(MapMode.READ_ONLY,0,1); map = ch.map(MapMode.READ_ONLY,0,1);
......
...@@ -2014,6 +2014,11 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve ...@@ -2014,6 +2014,11 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
return buildsDir; return buildsDir;
} }
@Restricted(NoExternalUse.class)
public void setRawBuildsDir(String buildsDir) {
this.buildsDir = buildsDir;
}
public FilePath getRootPath() { public FilePath getRootPath() {
return new FilePath(getRootDir()); return new FilePath(getRootDir());
} }
...@@ -2307,7 +2312,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve ...@@ -2307,7 +2312,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
* *
* Note that the look up is case-insensitive. * Note that the look up is case-insensitive.
*/ */
public TopLevelItem getItem(String name) { @Override public TopLevelItem getItem(String name) throws AccessDeniedException {
if (name==null) return null; if (name==null) return null;
TopLevelItem item = items.get(name); TopLevelItem item = items.get(name);
if (item==null) if (item==null)
...@@ -2411,8 +2416,9 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve ...@@ -2411,8 +2416,9 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
* @return * @return
* null if either such {@link Item} doesn't exist under the given full name, * null if either such {@link Item} doesn't exist under the given full name,
* or it exists but it's no an instance of the given type. * or it exists but it's no an instance of the given type.
* @throws AccessDeniedException as per {@link ItemGroup#getItem}
*/ */
public @CheckForNull <T extends Item> T getItemByFullName(String fullName, Class<T> type) { public @CheckForNull <T extends Item> T getItemByFullName(String fullName, Class<T> type) throws AccessDeniedException {
StringTokenizer tokens = new StringTokenizer(fullName,"/"); StringTokenizer tokens = new StringTokenizer(fullName,"/");
ItemGroup parent = this; ItemGroup parent = this;
......
package jenkins.security;
import hudson.Extension;
import hudson.model.PageDecorator;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
/**
* Adds the 'X-Frame-Options' header to all web pages.
*
* @since 1.581
*/
@Extension(ordinal = 1000)
public class FrameOptionsPageDecorator extends PageDecorator {
@Restricted(NoExternalUse.class)
public static boolean enabled = Boolean.valueOf(System.getProperty(FrameOptionsPageDecorator.class.getName() + ".enabled", "true"));
}
...@@ -63,7 +63,7 @@ public abstract class RunListProgressiveRendering extends ProgressiveRendering { ...@@ -63,7 +63,7 @@ public abstract class RunListProgressiveRendering extends ProgressiveRendering {
} }
JSONObject element = new JSONObject(); JSONObject element = new JSONObject();
calculate(build, element); calculate(build, element);
synchronized (results) { synchronized (this) {
results.add(element); results.add(element);
} }
decay *= (1 - 1 / MAX_LIKELY_RUNS); decay *= (1 - 1 / MAX_LIKELY_RUNS);
......
...@@ -27,8 +27,8 @@ THE SOFTWARE. ...@@ -27,8 +27,8 @@ THE SOFTWARE.
--> -->
<?jelly escape-by-default='true'?> <?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:f="/lib/form" xmlns:l="/lib/layout"> <j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define" xmlns:f="/lib/form" xmlns:l="/lib/layout">
<j:if test="${it.primaryView != null}"> <j:if test="${it.getPrimaryView() != null}">
<j:set var="it" value="${it.primaryView}"/> <j:set var="it" value="${it.getPrimaryView()}"/>
</j:if> </j:if>
<l:ajax> <l:ajax>
<form action="submitDescription" method="post"> <form action="submitDescription" method="post">
......
...@@ -32,6 +32,10 @@ THE SOFTWARE. ...@@ -32,6 +32,10 @@ THE SOFTWARE.
${it.name} ${it.name}
</h1> </h1>
<j:if test="${it.atom}">
<t:editableDescription permission="${app.ADMINISTER}"/>
</j:if>
<j:forEach var="a" items="${it.actions}"> <j:forEach var="a" items="${it.actions}">
<st:include page="summary.jelly" from="${a}" optional="true" it="${a}" /> <st:include page="summary.jelly" from="${a}" optional="true" it="${a}" />
</j:forEach> </j:forEach>
...@@ -40,7 +44,7 @@ THE SOFTWARE. ...@@ -40,7 +44,7 @@ THE SOFTWARE.
<h2>${%Nodes}</h2> <h2>${%Nodes}</h2>
<j:forEach var="n" items="${it.nodes}"> <j:forEach var="n" items="${it.nodes}">
<j:set var="c" value="${app.getComputer(n.nodeName)}"/> <j:set var="c" value="${app.getComputer(n.nodeName)}"/>
<j:set var="url" value="${rootURL}/computer/${n.nodeName}"/> <j:set var="url" value="${rootURL}/${c.url}"/>
<nobr> <nobr>
<a href="${url}"><l:icon class="${c.iconClassName} icon-sm"/></a> <a href="${url}"><l:icon class="${c.iconClassName} icon-sm"/></a>
<st:nbsp/> <st:nbsp/>
......
...@@ -33,6 +33,9 @@ THE SOFTWARE. ...@@ -33,6 +33,9 @@ THE SOFTWARE.
<j:set var="url" value="${h.getNearestAncestorUrl(request,it)}"/> <j:set var="url" value="${h.getNearestAncestorUrl(request,it)}"/>
<l:task contextMenu="false" href="${rootURL}/" icon="icon-up icon-md" title="${%Back to Dashboard}"/> <l:task contextMenu="false" href="${rootURL}/" icon="icon-up icon-md" title="${%Back to Dashboard}"/>
<l:task contextMenu="false" href="${url}" icon="icon-attribute icon-md" title="${%Overview}"/> <l:task contextMenu="false" href="${url}" icon="icon-attribute icon-md" title="${%Overview}"/>
<j:if test="${it.atom}">
<l:task href="${url}/configure" icon="icon-setting icon-md" title="${%Configure}" permission="${app.ADMINISTER}" />
</j:if>
<l:task href="${url}/load-statistics" icon="icon-monitor icon-md" title="${%Load Statistics}"/> <l:task href="${url}/load-statistics" icon="icon-monitor icon-md" title="${%Load Statistics}"/>
<st:include page="actions.jelly" /> <st:include page="actions.jelly" />
</l:tasks> </l:tasks>
......
...@@ -22,4 +22,4 @@ ...@@ -22,4 +22,4 @@
Console\ Output=\u05E4\u05DC\u05D8 \u05DE\u05E1\u05DA Console\ Output=\u05E4\u05DC\u05D8 \u05DE\u05E1\u05DA
View\ as\ plain\ text=\u05E6\u05E4\u05D9\u05D9\u05D4 \u05DB\u05D8\u05E7\u05E1\u05D8 View\ as\ plain\ text=\u05E6\u05E4\u05D9\u05D9\u05D4 \u05DB\u05D8\u05E7\u05E1\u05D8
skipSome=\u05DE\u05D3\u05DC\u05D2 {0,\u05DE\u05E1\u05E4\u05E8,\u05DE\u05E1\u05E4\u05E8 \u05E9\u05DC\u05DD} \u05E7"\u05D1.. <a href="{1}">\u05D3\u05D5"\u05D7 \u05DE\u05DC\u05D0</a> skipSome=\u05DE\u05D3\u05DC\u05D2 {0,number,integer} \u05E7"\u05D1.. <a href="{1}">\u05D3\u05D5"\u05D7 \u05DE\u05DC\u05D0</a>
...@@ -37,10 +37,15 @@ THE SOFTWARE. ...@@ -37,10 +37,15 @@ THE SOFTWARE.
<f:textbox value="${it.name}" readonly="true" /> <f:textbox value="${it.name}" readonly="true" />
</f:entry> </f:entry>
<f:entry title="${%Description}">
<f:textarea name="description" value="${it.description}" codemirror-mode="${app.markupFormatter.codeMirrorMode}" codemirror-config="${app.markupFormatter.codeMirrorConfig}" previewEndpoint="/markupFormatter/previewDescription"/>
</f:entry>
<f:descriptorList descriptors="${it.getApplicablePropertyDescriptors()}" instances="${it.properties}" /> <f:descriptorList descriptors="${it.getApplicablePropertyDescriptors()}" instances="${it.properties}" />
<f:block> <f:block>
<f:submit value="${%Save}"/> <f:submit value="${%Save}"/>
<f:apply />
</f:block> </f:block>
</f:form> </f:form>
<st:adjunct includes="lib.form.confirm" /> <st:adjunct includes="lib.form.confirm" />
......
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler">
<j:if test="${it.enabled}">
<st:header name="X-Frame-Options" value="sameorigin"/>
</j:if>
</j:jelly>
\ No newline at end of file
...@@ -56,7 +56,6 @@ THE SOFTWARE. ...@@ -56,7 +56,6 @@ THE SOFTWARE.
<st:setHeader name="Expires" value="0" /> <st:setHeader name="Expires" value="0" />
<st:setHeader name="Cache-Control" value="no-cache,no-store,must-revalidate" /> <st:setHeader name="Cache-Control" value="no-cache,no-store,must-revalidate" />
<st:setHeader name="X-Hudson-Theme" value="default" /> <st:setHeader name="X-Hudson-Theme" value="default" />
<st:setHeader name="X-Frame-Options" value="sameorigin" />
<st:contentType value="text/html;charset=UTF-8" /> <st:contentType value="text/html;charset=UTF-8" />
<j:new var="h" className="hudson.Functions" /><!-- instead of JSP functions --> <j:new var="h" className="hudson.Functions" /><!-- instead of JSP functions -->
......
/*
* The MIT License
*
* Copyright 2014 Jesse Glick.
*
* 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 hudson.model.listeners;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Run;
import hudson.model.TaskListener;
import hudson.scm.ChangeLogSet;
import hudson.scm.SCM;
import org.junit.Test;
import static org.junit.Assert.*;
import org.jvnet.hudson.test.Issue;
import org.mockito.Mockito;
@SuppressWarnings("deprecation")
public class SCMListenerTest {
@Issue("JENKINS-23522")
@SuppressWarnings({"rawtypes", "unchecked"})
@Test public void onChangeLogParsed() throws Exception {
SCM scm = Mockito.mock(SCM.class);
BuildListener bl = Mockito.mock(BuildListener.class);
ChangeLogSet cls = Mockito.mock(ChangeLogSet.class);
AbstractBuild ab = Mockito.mock(AbstractBuild.class);
AbstractProject ap = Mockito.mock(AbstractProject.class);
Mockito.when(ab.getProject()).thenReturn(ap);
Mockito.when(ap.getScm()).thenReturn(scm);
for (L l : new L[] {new L1(), new L2(), new L3()}) {
assertEquals(0, l.cnt);
l.onChangeLogParsed(ab, bl, cls);
assertEquals(1, l.cnt);
l.onChangeLogParsed(ab, scm, bl, cls);
assertEquals(2, l.cnt);
}
Run r = Mockito.mock(Run.class);
TaskListener tl = Mockito.mock(TaskListener.class);
L l = new L1();
l.onChangeLogParsed(r, scm, tl, cls);
assertEquals("cannot handle this", 0, l.cnt);
l = new L2();
l.onChangeLogParsed(r, scm, tl, cls);
assertEquals("does handle this", 1, l.cnt);
l = new L3();
l.onChangeLogParsed(r, scm, tl, cls);
assertEquals("cannot handle this", 0, l.cnt);
}
private static class L extends SCMListener {
int cnt;
}
private static class L1 extends L {
@Override public void onChangeLogParsed(AbstractBuild<?,?> build, BuildListener listener, ChangeLogSet<?> changelog) throws Exception {
cnt++;
}
}
private static class L2 extends L {
@Override public void onChangeLogParsed(Run<?,?> build, SCM scm, TaskListener listener, ChangeLogSet<?> changelog) throws Exception {
cnt++;
}
}
private static class L3 extends L {
@Override public void onChangeLogParsed(AbstractBuild<?,?> build, BuildListener listener, ChangeLogSet<?> changelog) throws Exception {
cnt++;
super.onChangeLogParsed(build, listener, changelog);
}
}
}
\ No newline at end of file
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
*/ */
package hudson.util; package hudson.util;
import com.google.common.collect.Iterables;
import hudson.util.CopyOnWriteMap.Hash;
import junit.framework.TestCase; import junit.framework.TestCase;
import java.util.Random; import java.util.Random;
...@@ -119,4 +121,23 @@ public class ConsistentHashTest extends TestCase { ...@@ -119,4 +121,23 @@ public class ConsistentHashTest extends TestCase {
assertNull(hash.lookup(0)); assertNull(hash.lookup(0));
assertNull(hash.lookup(999)); assertNull(hash.lookup(999));
} }
/**
* This test doesn't fail but it's written to measure the performance of the consistent hash function with large data set.
*/
public void testSpeed() {
Map<String,Integer> data = new Hash<String, Integer>();
for (int i = 0; i < 1000; i++)
data.put("node" + i,100);
data.put("tail",100);
long start = System.currentTimeMillis();
for (int j=0; j<10; j++) {
ConsistentHash<String> b = new ConsistentHash<String>();
b.addAll(data);
// System.out.println(Iterables.toString(b.list("x")));
}
System.out.println(System.currentTimeMillis()-start);
}
} }
jenkins (1.580) unstable; urgency=low
* See http://jenkins-ci.org/changelog for more details.
-- Kohsuke Kawaguchi <kk@kohsuke.org> Sun, 14 Sep 2014 16:50:17 -0700
jenkins (1.579) unstable; urgency=low
* See http://jenkins-ci.org/changelog for more details.
-- Kohsuke Kawaguchi <kk@kohsuke.org> Sat, 06 Sep 2014 08:13:20 -0700
jenkins (1.578) unstable; urgency=low
* See http://jenkins-ci.org/changelog for more details.
-- Kohsuke Kawaguchi <kk@kohsuke.org> Sun, 31 Aug 2014 20:10:25 -0700
jenkins (1.577) unstable; urgency=low jenkins (1.577) unstable; urgency=low
* See http://jenkins-ci.org/changelog for more details. * See http://jenkins-ci.org/changelog for more details.
......
...@@ -39,6 +39,11 @@ JENKINS_LOG=/var/log/jenkins/$NAME.log ...@@ -39,6 +39,11 @@ JENKINS_LOG=/var/log/jenkins/$NAME.log
# descriptors are forced to 1024 regardless of /etc/security/limits.conf # descriptors are forced to 1024 regardless of /etc/security/limits.conf
MAXOPENFILES=8192 MAXOPENFILES=8192
# set the umask to control permission bits of files that Jenkins creates.
# 027 makes files read-only for group and inaccessible for others. comment this out to inherit setting
# (as of Ubuntu 12.04, by default umask comes from pam_umask(8) and /etc/login.defs
UMASK=027
# port for HTTP connector (default 8080; disable with -1) # port for HTTP connector (default 8080; disable with -1)
HTTP_PORT=8080 HTTP_PORT=8080
......
...@@ -108,6 +108,12 @@ do_start() ...@@ -108,6 +108,12 @@ do_start()
ulimit -n $MAXOPENFILES ulimit -n $MAXOPENFILES
fi fi
# honor umask setting
if [ -n "$UMASK" ]; then
[ "$VERBOSE" != no ] && echo Setting umask to $UMASK
umask $UMASK
fi
# --user in daemon doesn't prepare environment variables like HOME, USER, LOGNAME or USERNAME, # --user in daemon doesn't prepare environment variables like HOME, USER, LOGNAME or USERNAME,
# so we let su do so for us now # so we let su do so for us now
$SU -l $JENKINS_USER --shell=/bin/bash -c "$DAEMON $DAEMON_ARGS -- $JAVA $JAVA_ARGS -jar $JENKINS_WAR $JENKINS_ARGS" || return 2 $SU -l $JENKINS_USER --shell=/bin/bash -c "$DAEMON $DAEMON_ARGS -- $JAVA $JAVA_ARGS -jar $JENKINS_WAR $JENKINS_ARGS" || return 2
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
<groupId>org.jenkins-ci.plugins</groupId> <groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId> <artifactId>plugin</artifactId>
<name>Jenkins plugin POM</name> <name>Jenkins plugin POM</name>
<version>1.578-SNAPSHOT</version> <version>1.581-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<!-- <!--
...@@ -40,19 +40,19 @@ ...@@ -40,19 +40,19 @@
<groupId>org.jenkins-ci.main</groupId> <groupId>org.jenkins-ci.main</groupId>
<artifactId>jenkins-war</artifactId> <artifactId>jenkins-war</artifactId>
<type>war</type> <type>war</type>
<version>1.578-SNAPSHOT</version> <version>1.581-SNAPSHOT</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jenkins-ci.main</groupId> <groupId>org.jenkins-ci.main</groupId>
<artifactId>jenkins-core</artifactId> <artifactId>jenkins-core</artifactId>
<version>1.578-SNAPSHOT</version> <version>1.581-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.jenkins-ci.main</groupId> <groupId>org.jenkins-ci.main</groupId>
<artifactId>jenkins-test-harness</artifactId> <artifactId>jenkins-test-harness</artifactId>
<version>1.578-SNAPSHOT</version> <version>1.581-SNAPSHOT</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- <!--
......
...@@ -33,7 +33,7 @@ THE SOFTWARE. ...@@ -33,7 +33,7 @@ THE SOFTWARE.
<groupId>org.jenkins-ci.main</groupId> <groupId>org.jenkins-ci.main</groupId>
<artifactId>pom</artifactId> <artifactId>pom</artifactId>
<version>1.578-SNAPSHOT</version> <version>1.581-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>Jenkins main module</name> <name>Jenkins main module</name>
......
...@@ -29,7 +29,7 @@ THE SOFTWARE. ...@@ -29,7 +29,7 @@ THE SOFTWARE.
<parent> <parent>
<artifactId>pom</artifactId> <artifactId>pom</artifactId>
<groupId>org.jenkins-ci.main</groupId> <groupId>org.jenkins-ci.main</groupId>
<version>1.578-SNAPSHOT</version> <version>1.581-SNAPSHOT</version>
</parent> </parent>
<groupId>org.jenkins-ci.main</groupId> <groupId>org.jenkins-ci.main</groupId>
<artifactId>jenkins-test-harness</artifactId> <artifactId>jenkins-test-harness</artifactId>
......
...@@ -2069,7 +2069,8 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { ...@@ -2069,7 +2069,8 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction {
} }
/** /**
* Adds a security crumb to the quest * Adds a security crumb to the request.
* Use {@link #createCrumbedUrl} instead if you intend to call {@link WebRequestSettings#setRequestBody}, typical of a POST request.
*/ */
public WebRequestSettings addCrumb(WebRequestSettings req) { public WebRequestSettings addCrumb(WebRequestSettings req) {
NameValuePair crumb[] = { new NameValuePair() }; NameValuePair crumb[] = { new NameValuePair() };
......
...@@ -277,4 +277,12 @@ public class JobTest { ...@@ -277,4 +277,12 @@ public class JobTest {
}).intValue()); }).intValue());
} }
@Bug(19764)
@Test public void testRenameWithCustomBuildsDirWithSubdir() throws Exception {
j.jenkins.setRawBuildsDir("${JENKINS_HOME}/builds/${ITEM_FULL_NAME}/builds");
final FreeStyleProject p = j.createFreeStyleProject();
p.scheduleBuild2(0).get();
p.renameTo("different-name");
}
} }
...@@ -419,7 +419,9 @@ public class ProjectTest { ...@@ -419,7 +419,9 @@ public class ProjectTest {
FreeStyleProject p = j.createFreeStyleProject("project"); FreeStyleProject p = j.createFreeStyleProject("project");
Slave slave = j.createOnlineSlave(); Slave slave = j.createOnlineSlave();
AbstractBuild build = p.createExecutable(); AbstractBuild build = p.createExecutable();
FilePath path = slave.toComputer().getWorkspaceList().allocate(slave.getWorkspaceFor(p), build).path; FilePath ws = slave.getWorkspaceFor(p);
assertNotNull(ws);
FilePath path = slave.toComputer().getWorkspaceList().allocate(ws, build).path;
build.setWorkspace(path); build.setWorkspace(path);
BuildListener listener = new StreamBuildListener(BuildListener.NULL.getLogger(), Charset.defaultCharset()); BuildListener listener = new StreamBuildListener(BuildListener.NULL.getLogger(), Charset.defaultCharset());
assertTrue("Project with null smc should perform checkout without problems.", p.checkout(build, new RemoteLauncher(listener, slave.getChannel(), true), listener, new File(build.getRootDir(),"changelog.xml"))); assertTrue("Project with null smc should perform checkout without problems.", p.checkout(build, new RemoteLauncher(listener, slave.getChannel(), true), listener, new File(build.getRootDir(),"changelog.xml")));
......
...@@ -45,6 +45,7 @@ import org.acegisecurity.Authentication; ...@@ -45,6 +45,7 @@ import org.acegisecurity.Authentication;
import org.acegisecurity.context.SecurityContext; import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder; import org.acegisecurity.context.SecurityContextHolder;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import static org.junit.Assume.*;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.jvnet.hudson.test.Bug; import org.jvnet.hudson.test.Bug;
...@@ -227,6 +228,7 @@ public class UserTest { ...@@ -227,6 +228,7 @@ public class UserTest {
@Issue("JENKINS-24317") @Issue("JENKINS-24317")
@LocalData @LocalData
@Test public void migration() throws Exception { @Test public void migration() throws Exception {
assumeFalse("was not a problem on a case-insensitive FS to begin with", new File(j.jenkins.getRootDir(), "users/bob").isDirectory());
User bob = User.get("bob"); User bob = User.get("bob");
assertEquals("Bob Smith", bob.getFullName()); assertEquals("Bob Smith", bob.getFullName());
assertEquals("Bob Smith", User.get("Bob").getFullName()); assertEquals("Bob Smith", User.get("Bob").getFullName());
......
...@@ -52,7 +52,6 @@ import org.junit.Test; ...@@ -52,7 +52,6 @@ import org.junit.Test;
import org.jvnet.hudson.test.Bug; import org.jvnet.hudson.test.Bug;
import org.jvnet.hudson.test.ExtractResourceSCM; import org.jvnet.hudson.test.ExtractResourceSCM;
import org.jvnet.hudson.test.HudsonTestCase; import org.jvnet.hudson.test.HudsonTestCase;
import org.jvnet.hudson.test.JenkinsRule.DummySecurityRealm;
import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.TestExtension;
import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponse;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
...@@ -298,8 +297,6 @@ public class JenkinsTest extends HudsonTestCase implements UnprotectedRootAction ...@@ -298,8 +297,6 @@ public class JenkinsTest extends HudsonTestCase implements UnprotectedRootAction
gmas.add(Jenkins.READ, "bob"); gmas.add(Jenkins.READ, "bob");
gmas.add(Jenkins.ADMINISTER, "charlie"); gmas.add(Jenkins.ADMINISTER, "charlie");
jenkins.setAuthorizationStrategy(gmas); jenkins.setAuthorizationStrategy(gmas);
// Otherwise get "RuntimeException: Trying to set the request parameters, but the request body has already been specified;the two are mutually exclusive!" from WebRequestSettings.setRequestParameters when POSTing content:
jenkins.setCrumbIssuer(null);
WebClient wc = createWebClient(); WebClient wc = createWebClient();
wc.login("alice"); wc.login("alice");
wc.assertFails("eval", HttpURLConnection.HTTP_BAD_METHOD); wc.assertFails("eval", HttpURLConnection.HTTP_BAD_METHOD);
...@@ -320,9 +317,9 @@ public class JenkinsTest extends HudsonTestCase implements UnprotectedRootAction ...@@ -320,9 +317,9 @@ public class JenkinsTest extends HudsonTestCase implements UnprotectedRootAction
} }
} }
private String eval(WebClient wc) throws Exception { private String eval(WebClient wc) throws Exception {
WebRequestSettings req = new WebRequestSettings(new URL(wc.getContextPath() + "eval"), HttpMethod.POST); WebRequestSettings req = new WebRequestSettings(wc.createCrumbedUrl("eval"), HttpMethod.POST);
req.setRequestBody("<j:jelly xmlns:j='jelly:core'>${1+2}</j:jelly>"); req.setRequestBody("<j:jelly xmlns:j='jelly:core'>${1+2}</j:jelly>");
return wc.getPage(/*wc.addCrumb(*/req/*)*/).getWebResponse().getContentAsString(); return wc.getPage(req).getWebResponse().getContentAsString();
} }
@TestExtension("testUnprotectedRootAction") @TestExtension("testUnprotectedRootAction")
......
package jenkins.security;
import com.gargoylesoftware.htmlunit.WebResponse;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import org.apache.commons.httpclient.NameValuePair;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.JenkinsRule;
import org.xml.sax.SAXException;
import java.io.IOException;
public class FrameOptionsPageDecoratorTest {
@Rule
public JenkinsRule j = new JenkinsRule();
@Test
public void defaultHeaderPresent() throws IOException, SAXException {
JenkinsRule.WebClient wc = j.createWebClient();
HtmlPage page = wc.goTo("");
Assert.assertEquals("Expected different X-Frame-Options value", getFrameOptionsFromResponse(page.getWebResponse()), "sameorigin");
}
@Test
public void testDisabledFrameOptions() throws IOException, SAXException {
FrameOptionsPageDecorator.enabled = false;
JenkinsRule.WebClient wc = j.createWebClient();
HtmlPage page = wc.goTo("");
Assert.assertNull("Expected X-Frame-Options unset", getFrameOptionsFromResponse(page.getWebResponse()));
}
private static String getFrameOptionsFromResponse(WebResponse response) {
for (NameValuePair pair : response.getResponseHeaders()) {
if (pair.getName().equals("X-Frame-Options")) {
return pair.getValue();
}
}
return null;
}
}
...@@ -28,7 +28,7 @@ THE SOFTWARE. ...@@ -28,7 +28,7 @@ THE SOFTWARE.
<parent> <parent>
<groupId>org.jenkins-ci.main</groupId> <groupId>org.jenkins-ci.main</groupId>
<artifactId>pom</artifactId> <artifactId>pom</artifactId>
<version>1.578-SNAPSHOT</version> <version>1.581-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
......
...@@ -50,13 +50,19 @@ body { ...@@ -50,13 +50,19 @@ body {
margin-left: 16px; margin-left: 16px;
} }
#jenkins-home-link {
position: absolute;
height: 40px;
}
#jenkins-head-icon { #jenkins-head-icon {
position: relative; position: absolute;
top: 2px; bottom: 0px;
} }
#jenkins-name-icon { #jenkins-name-icon {
position: relative; position: absolute;
top: 3px; bottom: 3px;
left: 32px;
} }
#header .searchbox, #header .login { #header .searchbox, #header .login {
...@@ -117,6 +123,7 @@ body, table, form, input, td, th, p, textarea, select ...@@ -117,6 +123,7 @@ body, table, form, input, td, th, p, textarea, select
font-family: Helvetica, Arial, sans-serif; font-family: Helvetica, Arial, sans-serif;
font-size: 13px; font-size: 13px;
color: #333; color: #333;
background-color: #fff;
} }
FORM { FORM {
......
...@@ -513,7 +513,7 @@ function makeButton(e,onclick) { ...@@ -513,7 +513,7 @@ function makeButton(e,onclick) {
btn.addListener("click",h); btn.addListener("click",h);
var be = btn.get("element"); var be = btn.get("element");
Element.addClassName(be,clsName); Element.addClassName(be,clsName);
if(n!=null) // copy the name if(n) // copy the name
be.setAttribute("name",n); be.setAttribute("name",n);
return btn; return btn;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册