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

Merge branch 'rc' into security-rc

......@@ -61,7 +61,56 @@ Upcoming changes</a>
<!-- these changes are controlled by the release process. DO NOT MODIFY -->
<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>
<li class=rfe>
Added 'no-store' to the 'Cache-Control' header to avoid accidental information leak through local cache backup
......@@ -73,7 +122,6 @@ Upcoming changes</a>
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>)
</ul>
</div><!--=END=-->
<h3><a name=v1.577>What's new in 1.577</a> (2014/08/24)</h3>
<ul class=image>
<li class="major bug">
......@@ -88,6 +136,11 @@ Upcoming changes</a>
<li class=bug>
Fixed ClassCastException on org.dom4j.DocumentFactory
(<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>
Allow BuildStep to work with non-AbstractProject
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-23713">issue 23713</a>)
......@@ -806,6 +859,9 @@ Upcoming changes</a>
<li class=rfe>
Add Batch Command tool installer for Windows nodes.
(<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>
<h3><a name=v1.548>What's new in 1.548</a> (2014/01/20)</h3>
<ul class=image>
......
......@@ -5,7 +5,7 @@
<parent>
<artifactId>pom</artifactId>
<groupId>org.jenkins-ci.main</groupId>
<version>1.578-SNAPSHOT</version>
<version>1.581-SNAPSHOT</version>
</parent>
<artifactId>cli</artifactId>
......
......@@ -59,12 +59,14 @@ public class ConnectionTest extends Assert {
t1.join(9999);
t2.join(9999);
if (e != null) {
throw e;
}
if (t1.isAlive() || t2.isAlive()) {
t1.interrupt();
t2.interrupt();
throw new Error("thread is still alive");
}
if (e!=null) throw e;
}
}
......@@ -29,7 +29,7 @@ THE SOFTWARE.
<parent>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>pom</artifactId>
<version>1.578-SNAPSHOT</version>
<version>1.581-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
......@@ -484,7 +484,7 @@ THE SOFTWARE.
<dependency>
<groupId>org.jvnet.winp</groupId>
<artifactId>winp</artifactId>
<version>1.20</version>
<version>1.21</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci</groupId>
......
......@@ -111,6 +111,7 @@ import java.util.regex.Pattern;
import static hudson.FilePath.TarCompression.*;
import static hudson.Util.*;
import javax.annotation.Nonnull;
/**
* {@link File} like object with remoting support.
......@@ -1161,7 +1162,7 @@ public final class FilePath implements Serializable {
* @param relOrAbsolute a relative or absolute path
* @return a file on the same channel
*/
public FilePath child(String relOrAbsolute) {
public @Nonnull FilePath child(String relOrAbsolute) {
return new FilePath(this,relOrAbsolute);
}
......
......@@ -1009,7 +1009,7 @@ public abstract class Launcher {
*
* @author rcampbell
* @author Oleg Nenashev, Synopsys Inc.
* @since TODO: define version
* @since 1.568
*/
public static class DecoratedLauncher extends Launcher {
......
......@@ -74,7 +74,7 @@ public class ReverseProxySetupMonitor extends AdministrativeMonitor {
assert j != null;
String inferred = j.getRootUrlFromRequest() + "manage";
// 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();
} else {
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
* 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.
*/
protected void setWorkspace(FilePath ws) {
protected void setWorkspace(@Nonnull FilePath ws) {
this.workspace = ws.getRemote();
}
......
......@@ -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.
// this prevents multiple workspaces of the same job --- the behavior of Hudson < 1.319.
//
......
......@@ -23,11 +23,13 @@
*/
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
* @since 17-Jun-2008 18:58:12
* @since 1.312
*/
public interface ExecutorListener {
......@@ -47,7 +49,7 @@ public interface ExecutorListener {
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 task The task.
* @param durationMS The number of milliseconds that the task took to complete.
......
......@@ -34,7 +34,9 @@ import org.kohsuke.stapler.export.ExportedBean;
import java.io.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Represents health of something (typically project).
......@@ -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_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).
*/
......@@ -351,6 +362,10 @@ public class HealthReport implements Serializable, Comparable<HealthReport> {
hr.localizibleDescription = new NonLocalizable(hr.description == null ? "" : hr.description);
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
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 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});
// 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);
......
......@@ -28,6 +28,7 @@ import java.io.IOException;
import java.util.Collection;
import java.io.File;
import javax.annotation.CheckForNull;
import org.acegisecurity.AccessDeniedException;
/**
* Represents a grouping inherent to a kind of {@link Item}s.
......@@ -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.
* @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.
......
......@@ -619,6 +619,9 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
super.renameTo(newName);
File newBuildDir = getBuildDir();
if (oldBuildDir.isDirectory() && !newBuildDir.isDirectory()) {
if (!newBuildDir.getParentFile().isDirectory()) {
newBuildDir.getParentFile().mkdirs();
}
if (!oldBuildDir.renameTo(newBuildDir)) {
throw new IOException("failed to rename " + oldBuildDir + " to " + newBuildDir);
}
......
......@@ -142,6 +142,13 @@ public abstract class Label extends Actionable implements Comparable<Label>, Mod
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.
* 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 {
private void makeBuildable(BuildableItem p) {
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();
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.
hash.add(h, Math.max(h.getNumExecutors()*100, 1));
for (Node n : h.getNodes())
hash.add(n, n.getNumExecutors()*100);
hashSource.put(h, Math.max(h.getNumExecutors() * 100, 1));
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();
for (Node n : hash.list(p.task.getFullDisplayName())) {
......@@ -1101,6 +1105,13 @@ public class Queue extends ResourceController implements Saveable {
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) {
// LOGGER.info("Making "+p.task+" pending"); // REMOVE
p.isPending = true;
......
......@@ -507,6 +507,11 @@ public abstract class Run <JobT extends Job<JobT,RunT>,RunT extends Run<JobT,Run
if(e.getCurrentExecutable()==this)
return e;
}
for (Executor e : c.getOneOffExecutors()) {
if(e.getCurrentExecutable()==this) {
return e;
}
}
}
return null;
}
......
......@@ -33,15 +33,13 @@ import hudson.XmlFile;
import hudson.model.Action;
import hudson.model.Descriptor.FormException;
import hudson.model.Failure;
import hudson.util.EditDistance;
import hudson.util.*;
import jenkins.model.Jenkins;
import hudson.model.Label;
import hudson.model.Saveable;
import hudson.model.listeners.SaveableListener;
import hudson.util.DescribableList;
import hudson.util.QuotedStringTokenizer;
import hudson.util.VariableResolver;
import hudson.util.XStream2;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.DoNotUse;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.export.Exported;
......@@ -73,6 +71,8 @@ public class LabelAtom extends Label implements Saveable {
@CopyOnWrite
protected transient volatile List<Action> transientActions = new Vector<Action>();
private String description;
public LabelAtom(String name) {
super(name);
}
......@@ -85,6 +85,9 @@ public class LabelAtom extends Label implements Saveable {
return escape(name);
}
@Override
public boolean isAtom() { return true; }
/**
* {@inheritDoc}
*
......@@ -106,31 +109,22 @@ public class LabelAtom extends Label implements Saveable {
protected void updateTransientActions() {
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;
}
for (LabelAtomProperty p : properties)
ta.addAll(p.getActions(this));
public String getDisplayName() {
return "Configure";
transientActions = ta;
}
public String getUrlName() {
return "configure";
}
});
/**
* @since TODO
*/
public String getDescription() {
return description;
}
for (LabelAtomProperty p : properties)
ta.addAll(p.getActions(this));
transientActions = ta;
public void setDescription(String description) throws IOException {
this.description = description;
save();
}
/**
......@@ -210,11 +204,25 @@ public class LabelAtom extends Label implements Saveable {
app.checkPermission(Jenkins.ADMINISTER);
properties.rebuild(req, req.getSubmittedForm(), getApplicablePropertyDescriptors());
this.description = req.getSubmittedForm().getString("description");
updateTransientActions();
save();
// take the user back to the label top page.
rsp.sendRedirect2(".");
FormApply.success(".").generateResponse(req, rsp, null);
}
/**
* 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,8 +116,10 @@ public abstract class SCMListener implements ExtensionPoint {
@Deprecated
public void onChangeLogParsed(AbstractBuild<?,?> build, BuildListener listener, ChangeLogSet<?> changelog) throws Exception {
if (Util.isOverridden(SCMListener.class, getClass(), "onChangeLogParsed", Run.class, SCM.class, TaskListener.class, ChangeLogSet.class)) {
onChangeLogParsed((Run) build, build.getProject().getScm(), listener, changelog);
}
}
/**
* @since 1.568
......
......@@ -68,6 +68,10 @@ public class ChannelPinger extends ComputerListener {
@Override
public void preOnline(Computer c, Channel channel, FilePath root, TaskListener listener) {
install(channel);
}
public void install(Channel channel) {
if (pingInterval < 1) {
LOGGER.fine("Slave ping is disabled");
return;
......@@ -75,9 +79,9 @@ public class ChannelPinger extends ComputerListener {
try {
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) {
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,
......
......@@ -32,6 +32,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
/**
* Used by {@link Computer} to keep track of workspaces that are actively in use.
......@@ -72,7 +73,7 @@ public final class WorkspaceList {
*/
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.
......@@ -81,11 +82,11 @@ public final class WorkspaceList {
public int lockCount=1;
private Entry(FilePath path, boolean quick) {
private Entry(@Nonnull FilePath path, boolean quick) {
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.quick = quick;
this.context = context;
......@@ -104,9 +105,10 @@ public final class WorkspaceList {
* Represents a leased workspace that needs to be returned later.
*/
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;
}
......@@ -118,7 +120,7 @@ public final class WorkspaceList {
/**
* 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) {
public void release() {
// noop
......@@ -130,7 +132,7 @@ public final class WorkspaceList {
* Creates a {@link Lease} object that points to the specified path, but the lock
* 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) {
public void release() {
parent.release();
......@@ -151,7 +153,7 @@ public final class WorkspaceList {
* This method doesn't block prolonged amount of time. Whenever a desired workspace
* 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());
}
......@@ -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.)
* 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++) {
FilePath candidate = i==1 ? base : base.withSuffix(COMBINATOR+i);
Entry e = inUse.get(candidate);
......@@ -175,7 +177,7 @@ public final class WorkspaceList {
/**
* 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)) {
LOGGER.log(Level.FINE, "recorded " + p, new Throwable("from " + this));
}
......@@ -188,7 +190,7 @@ public final class WorkspaceList {
/**
* Releases an allocated or acquired workspace.
*/
private synchronized void _release(FilePath p) {
private synchronized void _release(@Nonnull FilePath p) {
Entry old = inUse.get(p);
if (old==null)
throw new AssertionError("Releasing unallocated workspace "+p);
......@@ -207,7 +209,7 @@ public final class WorkspaceList {
* @return
* 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);
}
......@@ -218,7 +220,7 @@ public final class WorkspaceList {
* 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.
*/
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());
}
......@@ -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.)
* 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;
Thread t = Thread.currentThread();
......@@ -257,7 +259,7 @@ public final class WorkspaceList {
/**
* Wraps a path into a valid lease.
*/
private Lease lease(FilePath p) {
private Lease lease(@Nonnull FilePath p) {
return new Lease(p) {
public void release() {
_release(path);
......
......@@ -48,7 +48,7 @@ import hudson.util.Iterators.DuplicateFilterIterator;
* and then we use MD5 to create random enough distribution.
*
* <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.
*
* <p>
......@@ -186,7 +186,7 @@ public class ConsistentHash<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) {
return o.toString();
}
......@@ -201,13 +201,13 @@ public class ConsistentHash<T> {
}
public ConsistentHash(Hash<T> hash) {
this(hash,100);
this(hash, 100);
}
public ConsistentHash(Hash<T> hash, int defaultReplication) {
this.hash = hash;
this.defaultReplication = defaultReplication;
this.table = new Table(); // initial empty table
refreshTable();
}
public int countAllPoints() {
......@@ -229,7 +229,8 @@ public class ConsistentHash<T> {
*/
public void addAll(T... nodes) {
for (T node : nodes)
add(node);
addInternal(node,defaultReplication);
refreshTable();
}
/**
......@@ -237,14 +238,24 @@ public class ConsistentHash<T> {
*/
public void addAll(Collection<? extends T> 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)}
*/
public void remove(T node) {
add(node,0);
add(node, 0);
}
/**
......@@ -254,6 +265,11 @@ public class ConsistentHash<T> {
* This is the only function that manipulates {@link #items}.
*/
public synchronized void add(T node, int replica) {
addInternal(node, replica);
refreshTable();
}
private void addInternal(T node, int replica) {
if(replica==0) {
items.remove(node);
} else {
......@@ -263,9 +279,13 @@ public class ConsistentHash<T> {
points[i] = new Point(md5(seed+':'+i),node);
items.put(node,points);
}
}
private void refreshTable() {
table = new Table();
}
/**
* Compresses a string into an integer with MD5.
*/
......@@ -314,8 +334,8 @@ public class ConsistentHash<T> {
* Creates a permutation of all the nodes for the given data point.
*
* <p>
* The returned pemutation is consistent, in the sense that small change
* to the consitent hash (like addition/removal/change of replicas) only
* The returned permutation is consistent, in the sense that small change
* to the consistent hash (like addition/removal/change of replicas) only
* creates a small change in the permutation.
*
* <p>
......
......@@ -30,7 +30,7 @@ import org.apache.commons.io.IOUtils;
*
* @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 {
/**
* hs_err_pid files that we think belong to us.
......@@ -43,6 +43,9 @@ public class HsErrPidList extends AdministrativeMonitor {
private MappedByteBuffer map;
public HsErrPidList() {
if (Functions.getIsUnitTest()) {
return;
}
try {
FileChannel ch = new FileInputStream(getSecretKeyFile()).getChannel();
map = ch.map(MapMode.READ_ONLY,0,1);
......
......@@ -2014,6 +2014,11 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
return buildsDir;
}
@Restricted(NoExternalUse.class)
public void setRawBuildsDir(String buildsDir) {
this.buildsDir = buildsDir;
}
public FilePath getRootPath() {
return new FilePath(getRootDir());
}
......@@ -2307,7 +2312,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
*
* 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;
TopLevelItem item = items.get(name);
if (item==null)
......@@ -2411,8 +2416,9 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve
* @return
* 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.
* @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,"/");
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 {
}
JSONObject element = new JSONObject();
calculate(build, element);
synchronized (results) {
synchronized (this) {
results.add(element);
}
decay *= (1 - 1 / MAX_LIKELY_RUNS);
......
......@@ -27,8 +27,8 @@ THE SOFTWARE.
-->
<?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:if test="${it.primaryView != null}">
<j:set var="it" value="${it.primaryView}"/>
<j:if test="${it.getPrimaryView() != null}">
<j:set var="it" value="${it.getPrimaryView()}"/>
</j:if>
<l:ajax>
<form action="submitDescription" method="post">
......
......@@ -32,6 +32,10 @@ THE SOFTWARE.
${it.name}
</h1>
<j:if test="${it.atom}">
<t:editableDescription permission="${app.ADMINISTER}"/>
</j:if>
<j:forEach var="a" items="${it.actions}">
<st:include page="summary.jelly" from="${a}" optional="true" it="${a}" />
</j:forEach>
......@@ -40,7 +44,7 @@ THE SOFTWARE.
<h2>${%Nodes}</h2>
<j:forEach var="n" items="${it.nodes}">
<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>
<a href="${url}"><l:icon class="${c.iconClassName} icon-sm"/></a>
<st:nbsp/>
......
......@@ -33,6 +33,9 @@ THE SOFTWARE.
<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="${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}"/>
<st:include page="actions.jelly" />
</l:tasks>
......
......@@ -22,4 +22,4 @@
Console\ Output=\u05E4\u05DC\u05D8 \u05DE\u05E1\u05DA
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.
<f:textbox value="${it.name}" readonly="true" />
</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:block>
<f:submit value="${%Save}"/>
<f:apply />
</f:block>
</f:form>
<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.
<st:setHeader name="Expires" value="0" />
<st:setHeader name="Cache-Control" value="no-cache,no-store,must-revalidate" />
<st:setHeader name="X-Hudson-Theme" value="default" />
<st:setHeader name="X-Frame-Options" value="sameorigin" />
<st:contentType value="text/html;charset=UTF-8" />
<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 @@
*/
package hudson.util;
import com.google.common.collect.Iterables;
import hudson.util.CopyOnWriteMap.Hash;
import junit.framework.TestCase;
import java.util.Random;
......@@ -119,4 +121,23 @@ public class ConsistentHashTest extends TestCase {
assertNull(hash.lookup(0));
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
* See http://jenkins-ci.org/changelog for more details.
......
......@@ -39,6 +39,11 @@ JENKINS_LOG=/var/log/jenkins/$NAME.log
# descriptors are forced to 1024 regardless of /etc/security/limits.conf
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)
HTTP_PORT=8080
......
......@@ -108,6 +108,12 @@ do_start()
ulimit -n $MAXOPENFILES
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,
# 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
......
......@@ -11,7 +11,7 @@
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<name>Jenkins plugin POM</name>
<version>1.578-SNAPSHOT</version>
<version>1.581-SNAPSHOT</version>
<packaging>pom</packaging>
<!--
......@@ -40,19 +40,19 @@
<groupId>org.jenkins-ci.main</groupId>
<artifactId>jenkins-war</artifactId>
<type>war</type>
<version>1.578-SNAPSHOT</version>
<version>1.581-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>jenkins-core</artifactId>
<version>1.578-SNAPSHOT</version>
<version>1.581-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>jenkins-test-harness</artifactId>
<version>1.578-SNAPSHOT</version>
<version>1.581-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<!--
......
......@@ -33,7 +33,7 @@ THE SOFTWARE.
<groupId>org.jenkins-ci.main</groupId>
<artifactId>pom</artifactId>
<version>1.578-SNAPSHOT</version>
<version>1.581-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Jenkins main module</name>
......
......@@ -29,7 +29,7 @@ THE SOFTWARE.
<parent>
<artifactId>pom</artifactId>
<groupId>org.jenkins-ci.main</groupId>
<version>1.578-SNAPSHOT</version>
<version>1.581-SNAPSHOT</version>
</parent>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>jenkins-test-harness</artifactId>
......
......@@ -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) {
NameValuePair crumb[] = { new NameValuePair() };
......
......@@ -277,4 +277,12 @@ public class JobTest {
}).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 {
FreeStyleProject p = j.createFreeStyleProject("project");
Slave slave = j.createOnlineSlave();
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);
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")));
......
......@@ -45,6 +45,7 @@ import org.acegisecurity.Authentication;
import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
import org.junit.Rule;
import org.junit.Test;
import org.jvnet.hudson.test.Bug;
......@@ -227,6 +228,7 @@ public class UserTest {
@Issue("JENKINS-24317")
@LocalData
@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");
assertEquals("Bob Smith", bob.getFullName());
assertEquals("Bob Smith", User.get("Bob").getFullName());
......
......@@ -52,7 +52,6 @@ import org.junit.Test;
import org.jvnet.hudson.test.Bug;
import org.jvnet.hudson.test.ExtractResourceSCM;
import org.jvnet.hudson.test.HudsonTestCase;
import org.jvnet.hudson.test.JenkinsRule.DummySecurityRealm;
import org.jvnet.hudson.test.TestExtension;
import org.kohsuke.stapler.HttpResponse;
import org.mockito.ArgumentCaptor;
......@@ -298,8 +297,6 @@ public class JenkinsTest extends HudsonTestCase implements UnprotectedRootAction
gmas.add(Jenkins.READ, "bob");
gmas.add(Jenkins.ADMINISTER, "charlie");
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();
wc.login("alice");
wc.assertFails("eval", HttpURLConnection.HTTP_BAD_METHOD);
......@@ -320,9 +317,9 @@ public class JenkinsTest extends HudsonTestCase implements UnprotectedRootAction
}
}
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>");
return wc.getPage(/*wc.addCrumb(*/req/*)*/).getWebResponse().getContentAsString();
return wc.getPage(req).getWebResponse().getContentAsString();
}
@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.
<parent>
<groupId>org.jenkins-ci.main</groupId>
<artifactId>pom</artifactId>
<version>1.578-SNAPSHOT</version>
<version>1.581-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
......
......@@ -50,13 +50,19 @@ body {
margin-left: 16px;
}
#jenkins-home-link {
position: absolute;
height: 40px;
}
#jenkins-head-icon {
position: relative;
top: 2px;
position: absolute;
bottom: 0px;
}
#jenkins-name-icon {
position: relative;
top: 3px;
position: absolute;
bottom: 3px;
left: 32px;
}
#header .searchbox, #header .login {
......@@ -117,6 +123,7 @@ body, table, form, input, td, th, p, textarea, select
font-family: Helvetica, Arial, sans-serif;
font-size: 13px;
color: #333;
background-color: #fff;
}
FORM {
......
......@@ -513,7 +513,7 @@ function makeButton(e,onclick) {
btn.addListener("click",h);
var be = btn.get("element");
Element.addClassName(be,clsName);
if(n!=null) // copy the name
if(n) // copy the name
be.setAttribute("name",n);
return btn;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册