提交 ae3dac8a 编写于 作者: J Jesse Glick

Merge branch 'master' into JENKINS-14325

Conflicts:
	changelog.html
......@@ -58,12 +58,21 @@ Upcoming changes</a>
<li class=bug>
Enable/disable GUI for jobs either did not appear, or threw exceptions, for jobs inside folders
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-14325">issue 14325</a>)
<li class=bug>
<code>NullPointerException</code> from <code>UnlabeldLoadStatistics</code> <i>[sic]</i>
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-14330">issue 14330</a>)
<li class=bug>
Incorrect display of list items in project changes for SCMs such as Mercurial.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-14365">issue 14365</a>)
</ul>
</div><!--=TRUNK-END=-->
<!-- these changes are controlled by the release process. DO NOT MODIFY -->
<div id="rc" style="display:none;"><!--=BEGIN=-->
<h3><a name=v1.474>What's new in 1.474</a> <!--=DATE=--></h3>
<h3><a name=v1.475>What's new in 1.475</a> <!--=DATE=--></h3>
<!--=RC-CHANGES=-->
</div><!--=END=-->
<h3><a name=v1.474>What's new in 1.474</a> (2012/07/09)</h3>
<ul class=image>
<li class=bug>
Fix French translation
......@@ -75,7 +84,6 @@ Upcoming changes</a>
Added a new extension point to listen to polling activities.
(<a href="https://issues.jenkins-ci.org/browse/JENKINS-14178">issue 14178</a>)
</ul>
</div><!--=END=-->
<h3><a name=v1.473>What's new in 1.473</a> (2012/07/01)</h3>
<ul class=image>
<li class=bug>
......
......@@ -937,7 +937,7 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
* <p>
* This mechanism is used by {@link MatrixConfiguration} to pass
* the configuration values to the current build. It is up to
* {@link Builder}s to decide whether it wants to recognize the values
* {@link Builder}s to decide whether they want to recognize the values
* or how to use them.
*
* <p>
......
......@@ -88,6 +88,7 @@ import java.nio.charset.Charset;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.Inet4Address;
import javax.annotation.CheckForNull;
import static javax.servlet.http.HttpServletResponse.*;
......@@ -425,7 +426,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces
* null if the configuration has changed and the node is removed, yet the corresponding {@link Computer}
* is not yet gone.
*/
public Node getNode() {
public @CheckForNull Node getNode() {
if(nodeName==null)
return Jenkins.getInstance();
return Jenkins.getInstance().getNode(nodeName);
......
......@@ -33,13 +33,11 @@ import hudson.matrix.Axis;
import hudson.util.DescriptorList;
import hudson.util.XStream2;
import jenkins.model.Jenkins;
import org.apache.commons.lang.StringUtils;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.StringTokenizer;
import java.util.*;
/**
* Convenience methods related to {@link Item}.
......@@ -63,7 +61,7 @@ public class Items {
}
public static TopLevelItemDescriptor getDescriptor(String fqcn) {
return Descriptor.find(all(),fqcn);
return Descriptor.find(all(), fqcn);
}
/**
......@@ -104,6 +102,102 @@ public class Items {
return r;
}
/**
* Computes the canonical full name of a relative path in an {@link ItemGroup} context, handling relative
* positions ".." and "." as absolute path starting with "/". The resulting name is the item fullName from Jenkins
* root.
*/
public static String getCanonicalName(ItemGroup context, String path) {
String[] c = context.getFullName().split("/");
String[] p = path.split("/");
Stack name = new Stack();
for (int i=0; i<c.length;i++) {
if (i==0 && c[i].equals("")) continue;
name.push(c[i]);
}
for (int i=0; i<p.length;i++) {
if (i==0 && p[i].equals("")) {
// Absolute path starting with a "/"
name.clear();
continue;
}
if (p[i].equals("..")) {
name.pop();
continue;
}
if (p[i].equals(".")) {
continue;
}
name.push(p[i]);
}
return StringUtils.join(name, '/');
}
/**
* Compute the relative name of list of items after a rename occurred. Used to manage job references as names in
* plugins to support {@link hudson.model.listeners.ItemListener#onRenamed(hudson.model.Item, String, String)}.
* <p>
* In a hierarchical context, when a plugin has a reference to a job as <code>../foo/bar</code> this method will
* handle the relative path as "foo" is renamed to "zot" to compute <code>../zot/bar</code>
*
* @param oldFullName the old full name of the item
* @param newFullName the new full name of the item
* @param relativeNames coma separated list of Item relative names
* @param context the {link ItemGroup} relative names refer to
* @return relative name for the renamed item, based on the same ItemGroup context
*/
public static String computeRelativeNamesAfterRenaming(String oldFullName, String newFullName, String relativeNames, ItemGroup context) {
StringTokenizer tokens = new StringTokenizer(relativeNames,",");
List<String> newValue = new ArrayList<String>();
while(tokens.hasMoreTokens()) {
String relativeName = tokens.nextToken().trim();
String canonicalName = getCanonicalName(context, relativeName);
if (canonicalName.startsWith(oldFullName)) {
String newCanonicalName = newFullName + canonicalName.substring(oldFullName.length());
// relative name points to the renamed item, let's compute the new relative name
newValue.add( computeRelativeNameAfterRenaming(canonicalName, newCanonicalName, relativeName) );
} else {
newValue.add(relativeName);
}
}
return StringUtils.join(newValue, ",");
}
/**
* Compute the relative name of an Item after renaming
*/
private static String computeRelativeNameAfterRenaming(String oldFullName, String newFullName, String relativeName) {
String[] a = oldFullName.split("/");
String[] n = newFullName.split("/");
assert a.length == n.length;
String[] r = relativeName.split("/");
int j = a.length-1;
for(int i=r.length-1;i>=0;i--) {
String part = r[i];
if (part.equals("") && i==0) {
continue;
}
if (part.equals(".")) {
continue;
}
if (part.equals("..")) {
j--;
continue;
}
if (part.equals(a[j])) {
r[i] = n[j];
j--;
continue;
}
}
return StringUtils.join(r, '/');
}
/**
* Loads a {@link Item} from a config file.
*
......
......@@ -26,7 +26,6 @@ package hudson.model;
import hudson.model.MultiStageTimeSeries.TimeScale;
import hudson.model.MultiStageTimeSeries.TrendChart;
import jenkins.model.Jenkins;
import jenkins.model.UnlabeldLoadStatistics;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.export.Exported;
......
......@@ -590,7 +590,7 @@ public class Jenkins extends AbstractCIBase implements ModifiableItemGroup<TopLe
* @since 1.467
*/
@Exported
public transient final LoadStatistics unlabeledLoad = new UnlabeldLoadStatistics();
public transient final LoadStatistics unlabeledLoad = new UnlabeledLoadStatistics();
/**
* {@link NodeProvisioner} that reacts to {@link #unlabeledLoad}.
......
......@@ -39,18 +39,21 @@ import hudson.model.Queue.Task;
* @see OverallLoadStatistics
* @author Kohsuke Kawaguchi
*/
public class UnlabeldLoadStatistics extends LoadStatistics {
public class UnlabeledLoadStatistics extends LoadStatistics {
UnlabeldLoadStatistics() {
UnlabeledLoadStatistics() {
super(0, 0);
}
@Override
public int computeIdleExecutors() {
int r=0;
for (Computer c : Jenkins.getInstance().getComputers())
if(c.getNode().getMode()== Mode.NORMAL && (c.isOnline() || c.isConnecting()))
for (Computer c : Jenkins.getInstance().getComputers()) {
Node node = c.getNode();
if (node != null && node.getMode() == Mode.NORMAL && (c.isOnline() || c.isConnecting())) {
r += c.countIdle();
}
}
return r;
}
......@@ -58,8 +61,10 @@ public class UnlabeldLoadStatistics extends LoadStatistics {
public int computeTotalExecutors() {
int r=0;
for (Computer c : Jenkins.getInstance().getComputers()) {
if(c.getNode().getMode()==Mode.NORMAL && c.isOnline())
Node node = c.getNode();
if (node != null && node.getMode() == Mode.NORMAL && c.isOnline()) {
r += c.countExecutors();
}
}
return r;
}
......
......@@ -48,7 +48,7 @@ THE SOFTWARE.
<ol>
<j:forEach var="c" items="${b.changeSet.iterator()}" varStatus="loop">
<li value="${c.revision}">
<li value="${c.revision.class.name == 'java.lang.Integer' ? c.revision : null}">
<j:out value="${c.msgAnnotated}"/>
&#8212;
......
package hudson.model;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
/**
* @author: <a hef="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
*/
public class ItemsTest {
private static ItemGroup root;
private static ItemGroup foo;
private static ItemGroup foo_bar;
@BeforeClass
public static void itemGroups() {
root = mock(ItemGroup.class);
when(root.getFullName()).thenReturn("");
foo = mock(ItemGroup.class);
when(foo.getFullName()).thenReturn("foo");
foo_bar = mock(ItemGroup.class);
when(foo_bar.getFullName()).thenReturn("foo/bar");
}
@Test
public void getCanonicalName() {
assertEquals("foo", Items.getCanonicalName(root, "foo"));
assertEquals("foo", Items.getCanonicalName(root, "/foo"));
assertEquals("foo/bar", Items.getCanonicalName(root, "foo/bar"));
assertEquals("foo/bar", Items.getCanonicalName(foo, "bar"));
assertEquals("bar", Items.getCanonicalName(foo, "/bar"));
assertEquals("bar", Items.getCanonicalName(foo, "../bar"));
assertEquals("foo/bar", Items.getCanonicalName(foo, "./bar"));
assertEquals("foo/bar/baz/qux", Items.getCanonicalName(foo_bar, "baz/qux"));
assertEquals("foo/baz/qux", Items.getCanonicalName(foo_bar, "../baz/qux"));
}
@Test
public void computeRelativeNamesAfterRenaming() {
assertEquals("meu,bu,zo", Items.computeRelativeNamesAfterRenaming("ga", "meu", "ga,bu,zo", root ));
assertEquals("ga,bu,zo", Items.computeRelativeNamesAfterRenaming("ga", "meu", "ga,bu,zo", foo_bar ));
assertEquals("meu,bu,zo", Items.computeRelativeNamesAfterRenaming("foo/ga", "foo/meu", "ga,bu,zo", foo ));
assertEquals("/meu,/bu,/zo", Items.computeRelativeNamesAfterRenaming("ga", "meu", "/ga,/bu,/zo", root ));
assertEquals("/meu,/bu,/zo", Items.computeRelativeNamesAfterRenaming("ga", "meu", "/ga,/bu,/zo", foo_bar ));
assertEquals("../meu,../bu,../zo", Items.computeRelativeNamesAfterRenaming("ga", "meu", "../ga,../bu,../zo", foo ));
assertEquals("../qux/ga,bu,zo", Items.computeRelativeNamesAfterRenaming("foo/baz", "foo/qux", "../baz/ga,bu,zo", foo_bar ));
}
}
jenkins (1.474) unstable; urgency=low
* See http://jenkins-ci.org/changelog for more details.
-- Kohsuke Kawaguchi <kk@kohsuke.org> Mon, 09 Jul 2012 17:37:53 -0700
jenkins (1.473) unstable; urgency=low
* See http://jenkins-ci.org/changelog for more details.
......
......@@ -217,6 +217,7 @@ import static org.junit.matchers.JUnitMatchers.containsString;
*
* @see <a href="http://wiki.jenkins-ci.org/display/JENKINS/Unit+Test+JUnit4">Wiki article about unit testing in Jenkins</a>
* @author Stephen Connolly
* @since 1.436
*/
public class JenkinsRule implements TestRule, RootAction {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册