From be67b45a31f2987dd20cdbdfd4b4997f5250d66f Mon Sep 17 00:00:00 2001 From: ikedam Date: Mon, 18 May 2015 07:56:30 +0900 Subject: [PATCH 001/256] [JENKINS-28440] Added tests to reproduce and explain JENKINS-28440. --- .../util/RobustReflectionConverterTest.java | 289 +++++++++++++++++- 1 file changed, 288 insertions(+), 1 deletion(-) diff --git a/test/src/test/java/hudson/util/RobustReflectionConverterTest.java b/test/src/test/java/hudson/util/RobustReflectionConverterTest.java index edcf7d003b..0763fb4b93 100644 --- a/test/src/test/java/hudson/util/RobustReflectionConverterTest.java +++ b/test/src/test/java/hudson/util/RobustReflectionConverterTest.java @@ -24,17 +24,41 @@ package hudson.util; +import hudson.cli.CLI; import hudson.diagnosis.OldDataMonitor; +import hudson.model.AbstractDescribableImpl; +import hudson.model.Items; +import hudson.model.JobProperty; +import hudson.model.JobPropertyDescriptor; +import hudson.model.Descriptor; import hudson.model.FreeStyleProject; +import hudson.model.Job; import hudson.model.Saveable; +import hudson.security.ACL; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.Arrays; import java.util.Collections; import java.util.Map; + +import jenkins.model.Jenkins; import static org.junit.Assert.*; +import net.sf.json.JSONObject; + import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.JenkinsRule.WebClient; +import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.recipes.LocalData; +import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.StaplerRequest; + +import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; +import com.gargoylesoftware.htmlunit.HttpMethod; +import com.gargoylesoftware.htmlunit.WebRequestSettings; public class RobustReflectionConverterTest { @@ -52,5 +76,268 @@ public class RobustReflectionConverterTest { String text = data.values().iterator().next().extra; assertTrue(text, text.contains("Could not call hudson.triggers.TimerTrigger.readResolve")); } - + + // Testing describable object to demonstrate what is expected with RobustReflectionConverter#addCriticalField + // This should be configured with a specific keyword, + // and should reject configurations with other keywords. + // GUI related implementations (@DataBoundConstructor and newInstance) aren't used actually + // (no jelly files are provides and they don't work actually), + // but written to clarify a use case. + public static class AcceptOnlySpecificKeyword extends AbstractDescribableImpl{ + public static final String ACCEPT_KEYWORD = "accept"; + private final String keyword; + + @DataBoundConstructor + public AcceptOnlySpecificKeyword(String keyword) { + this.keyword = keyword; + } + + public String getKeyword() { + return keyword; + } + + public boolean isAcceptable() { + return ACCEPT_KEYWORD.equals(keyword); + } + + public Object readResolve() throws Exception { + if (!ACL.SYSTEM.equals(Jenkins.getAuthentication())) { + // called via REST / CLI with authentication + if (!isAcceptable()) { + // Reject invalid configuration via REST / CLI. + throw new Exception(String.format("Bad keyword: %s", getKeyword())); + } + } + return this; + } + + @TestExtension + public static class DescriptorImpl extends Descriptor { + @Override + public String getDisplayName() { + return "AcceptOnlySpecificKeyword"; + } + + @Override + public AcceptOnlySpecificKeyword newInstance(StaplerRequest req, JSONObject formData) + throws FormException { + AcceptOnlySpecificKeyword instance = super.newInstance(req, formData); + if (!instance.isAcceptable()) { + throw new FormException(String.format("Bad keyword: %s", instance.getKeyword()), "keyword"); + } + return instance; + } + } + } + + public static class KeywordProperty extends JobProperty> { + private final AcceptOnlySpecificKeyword nonCriticalField; + private final AcceptOnlySpecificKeyword criticalField; + + public KeywordProperty(AcceptOnlySpecificKeyword nonCriticalField, AcceptOnlySpecificKeyword criticalField) { + this.nonCriticalField = nonCriticalField; + this.criticalField = criticalField; + } + + public AcceptOnlySpecificKeyword getNonCriticalField() { + return nonCriticalField; + } + + public AcceptOnlySpecificKeyword getCriticalField() { + return criticalField; + } + + @TestExtension + public static class DescriptorImpl extends JobPropertyDescriptor { + @Override + public String getDisplayName() { + return "KeywordProperty"; + } + + @Override + public JobProperty newInstance(StaplerRequest req, JSONObject formData) + throws FormException { + // unfortunately, default newInstance bypasses newInstances for members. + formData = formData.getJSONObject("keywordProperty"); + @SuppressWarnings("unchecked") + Descriptor d = Jenkins.getInstance().getDescriptor(AcceptOnlySpecificKeyword.class); + return new KeywordProperty( + d.newInstance(req, formData.getJSONObject("nonCriticalField")), + d.newInstance(req, formData.getJSONObject("criticalField")) + ); + } + } + } + + private static final String CONFIGURATION_TEMPLATE = + "" + + "" + + "" + + "" + + "" + + "%s" + + "" + + "" + + "%s" + + "" + + "" + + "" + + ""; + + @Test + public void testRestInterfaceFailure() throws Exception { + Items.XSTREAM2.addCriticalField(KeywordProperty.class, "criticalField"); + + // without addCriticalField. This is accepted. + { + FreeStyleProject p = r.createFreeStyleProject(); + p.addProperty(new KeywordProperty( + new AcceptOnlySpecificKeyword(AcceptOnlySpecificKeyword.ACCEPT_KEYWORD), + new AcceptOnlySpecificKeyword(AcceptOnlySpecificKeyword.ACCEPT_KEYWORD) + )); + p.save(); + + // Configure a bad keyword via REST. + r.jenkins.setSecurityRealm(r.createDummySecurityRealm()); + WebClient wc = r.createWebClient(); + wc.login("test", "test"); + WebRequestSettings req = new WebRequestSettings( + wc.createCrumbedUrl(String.format("%s/config.xml", p.getUrl())), + HttpMethod.POST + ); + req.setRequestBody(String.format(CONFIGURATION_TEMPLATE, "badvalue", AcceptOnlySpecificKeyword.ACCEPT_KEYWORD)); + wc.getPage(req); + + // AcceptOnlySpecificKeyword with bad value is not instantiated for rejected with readResolve, + assertNull(p.getProperty(KeywordProperty.class).getNonCriticalField()); + assertEquals(AcceptOnlySpecificKeyword.ACCEPT_KEYWORD, p.getProperty(KeywordProperty.class).getCriticalField().getKeyword()); + + // but save to the disk. + r.jenkins.reload(); + + p = r.jenkins.getItemByFullName(p.getFullName(), FreeStyleProject.class); + assertEquals("badvalue", p.getProperty(KeywordProperty.class).getNonCriticalField().getKeyword()); + assertEquals(AcceptOnlySpecificKeyword.ACCEPT_KEYWORD, p.getProperty(KeywordProperty.class).getCriticalField().getKeyword()); + } + + // with addCriticalField. This is not accepted. + { + FreeStyleProject p = r.createFreeStyleProject(); + p.addProperty(new KeywordProperty( + new AcceptOnlySpecificKeyword(AcceptOnlySpecificKeyword.ACCEPT_KEYWORD), + new AcceptOnlySpecificKeyword(AcceptOnlySpecificKeyword.ACCEPT_KEYWORD) + )); + p.save(); + + // Configure a bad keyword via REST. + r.jenkins.setSecurityRealm(r.createDummySecurityRealm()); + WebClient wc = r.createWebClient(); + wc.login("test", "test"); + WebRequestSettings req = new WebRequestSettings( + wc.createCrumbedUrl(String.format("%s/config.xml", p.getUrl())), + HttpMethod.POST + ); + req.setRequestBody(String.format(CONFIGURATION_TEMPLATE, AcceptOnlySpecificKeyword.ACCEPT_KEYWORD, "badvalue")); + + try { + wc.getPage(req); + // TODO: fail("Submitting unacceptable configuration via REST should fail."); + } catch (FailingHttpStatusCodeException e) { + // pass + } + + // Configuration should not be updated for a failure of the critical field, + // TODO: assertNotEquals("badvalue", p.getProperty(KeywordProperty.class).getCriticalField().getKeyword()); + + r.jenkins.reload(); + + // rejected configuration is not saved + p = r.jenkins.getItemByFullName(p.getFullName(), FreeStyleProject.class); + assertNotEquals("badvalue", p.getProperty(KeywordProperty.class).getCriticalField().getKeyword()); + } + } + + @Test + public void testCliFailure() throws Exception { + Items.XSTREAM2.addCriticalField(KeywordProperty.class, "criticalField"); + + // without addCriticalField. This is accepted. + { + FreeStyleProject p = r.createFreeStyleProject(); + p.addProperty(new KeywordProperty( + new AcceptOnlySpecificKeyword(AcceptOnlySpecificKeyword.ACCEPT_KEYWORD), + new AcceptOnlySpecificKeyword(AcceptOnlySpecificKeyword.ACCEPT_KEYWORD) + )); + p.save(); + + // Configure a bad keyword via CLI. + r.jenkins.setSecurityRealm(r.createDummySecurityRealm()); + CLI cli = new CLI(r.getURL()); + ByteArrayOutputStream stdout = new ByteArrayOutputStream(); + ByteArrayOutputStream stderr = new ByteArrayOutputStream(); + int ret = cli.execute( + Arrays.asList( + "update-job", + p.getFullName(), + "--username", + "test", + "--password", + "test" + ), + new ByteArrayInputStream(String.format(CONFIGURATION_TEMPLATE, "badvalue", AcceptOnlySpecificKeyword.ACCEPT_KEYWORD).getBytes()), + stdout, + stderr + ); + assertEquals(0, ret); + + // AcceptOnlySpecificKeyword with bad value is not instantiated for rejected with readResolve, + assertNull(p.getProperty(KeywordProperty.class).getNonCriticalField()); + assertEquals(AcceptOnlySpecificKeyword.ACCEPT_KEYWORD, p.getProperty(KeywordProperty.class).getCriticalField().getKeyword()); + + // but save to the disk. + r.jenkins.reload(); + + p = r.jenkins.getItemByFullName(p.getFullName(), FreeStyleProject.class); + assertEquals("badvalue", p.getProperty(KeywordProperty.class).getNonCriticalField().getKeyword()); + } + + // with addCriticalField. This is not accepted. + { + FreeStyleProject p = r.createFreeStyleProject(); + p.addProperty(new KeywordProperty( + new AcceptOnlySpecificKeyword(AcceptOnlySpecificKeyword.ACCEPT_KEYWORD), + new AcceptOnlySpecificKeyword(AcceptOnlySpecificKeyword.ACCEPT_KEYWORD) + )); + p.save(); + + // Configure a bad keyword via CLI. + r.jenkins.setSecurityRealm(r.createDummySecurityRealm()); + CLI cli = new CLI(r.getURL()); + ByteArrayOutputStream stdout = new ByteArrayOutputStream(); + ByteArrayOutputStream stderr = new ByteArrayOutputStream(); + int ret = cli.execute( + Arrays.asList( + "update-job", + p.getFullName(), + "--username", + "test", + "--password", + "test" + ), + new ByteArrayInputStream(String.format(CONFIGURATION_TEMPLATE, AcceptOnlySpecificKeyword.ACCEPT_KEYWORD, "badvalue").getBytes()), + stdout, + stderr + ); + // TODO: assertNotEquals(0, ret); + + // Configuration should not be updated for a failure of the critical field, + // TODO: assertNotEquals("badvalue", p.getProperty(KeywordProperty.class).getCriticalField().getKeyword()); + + r.jenkins.reload(); + + // rejected configuration is not saved + p = r.jenkins.getItemByFullName(p.getFullName(), FreeStyleProject.class); + assertNotEquals("badvalue", p.getProperty(KeywordProperty.class).getCriticalField().getKeyword()); + } + } } From 2082b08e2a0e54856370af9e3dda342475dff334 Mon Sep 17 00:00:00 2001 From: ikedam Date: Thu, 21 May 2015 06:45:40 +0900 Subject: [PATCH 002/256] [FIXED JENKINS-28440] Raises a critical exception for an error in a critical field. This allows plugins to reject unacceptable configurations via REST / CLI. --- .../java/hudson/util/CopyOnWriteList.java | 4 ++ .../util/RobustCollectionConverter.java | 4 ++ .../java/hudson/util/RobustMapConverter.java | 3 ++ .../util/RobustReflectionConverter.java | 5 ++- .../util/xstream/ImmutableListConverter.java | 4 ++ .../xstream/CriticalXStreamException.java | 39 +++++++++++++++++++ 6 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/jenkins/util/xstream/CriticalXStreamException.java diff --git a/core/src/main/java/hudson/util/CopyOnWriteList.java b/core/src/main/java/hudson/util/CopyOnWriteList.java index 179d2d0825..43e189ba19 100644 --- a/core/src/main/java/hudson/util/CopyOnWriteList.java +++ b/core/src/main/java/hudson/util/CopyOnWriteList.java @@ -39,6 +39,8 @@ import java.util.Iterator; import java.util.List; import java.util.Arrays; +import jenkins.util.xstream.CriticalXStreamException; + /** * {@link List}-like implementation that has copy-on-write semantics. @@ -194,6 +196,8 @@ public class CopyOnWriteList implements Iterable { try { Object item = readItem(reader, context, items); items.add(item); + } catch (CriticalXStreamException e) { + throw e; } catch (XStreamException e) { RobustReflectionConverter.addErrorInContext(context, e); } catch (LinkageError e) { diff --git a/core/src/main/java/hudson/util/RobustCollectionConverter.java b/core/src/main/java/hudson/util/RobustCollectionConverter.java index 78dc2b2f2f..d0903ff82b 100644 --- a/core/src/main/java/hudson/util/RobustCollectionConverter.java +++ b/core/src/main/java/hudson/util/RobustCollectionConverter.java @@ -36,6 +36,8 @@ import java.util.Collection; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; +import jenkins.util.xstream.CriticalXStreamException; + /** * {@link CollectionConverter} that ignores {@link XStreamException}. @@ -82,6 +84,8 @@ public class RobustCollectionConverter extends CollectionConverter { try { Object item = readItem(reader, context, collection); collection.add(item); + } catch (CriticalXStreamException e) { + throw e; } catch (XStreamException e) { RobustReflectionConverter.addErrorInContext(context, e); } catch (LinkageError e) { diff --git a/core/src/main/java/hudson/util/RobustMapConverter.java b/core/src/main/java/hudson/util/RobustMapConverter.java index 6a52bfb016..48bdf94c79 100644 --- a/core/src/main/java/hudson/util/RobustMapConverter.java +++ b/core/src/main/java/hudson/util/RobustMapConverter.java @@ -30,6 +30,7 @@ import com.thoughtworks.xstream.converters.collections.MapConverter; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.mapper.Mapper; import java.util.Map; +import jenkins.util.xstream.CriticalXStreamException; /** * Loads a {@link Map} while tolerating read errors on its keys and values. @@ -55,6 +56,8 @@ final class RobustMapConverter extends MapConverter { reader.moveDown(); try { return readItem(reader, context, map); + } catch (CriticalXStreamException x) { + throw x; } catch (XStreamException x) { RobustReflectionConverter.addErrorInContext(context, x); return ERROR; diff --git a/core/src/main/java/hudson/util/RobustReflectionConverter.java b/core/src/main/java/hudson/util/RobustReflectionConverter.java index 18909ba74f..7270ee4e10 100644 --- a/core/src/main/java/hudson/util/RobustReflectionConverter.java +++ b/core/src/main/java/hudson/util/RobustReflectionConverter.java @@ -54,6 +54,7 @@ import java.util.Set; import static java.util.logging.Level.FINE; import java.util.logging.Logger; import javax.annotation.Nonnull; +import jenkins.util.xstream.CriticalXStreamException; /** * Custom {@link ReflectionConverter} that handle errors more gracefully. @@ -307,9 +308,11 @@ public class RobustReflectionConverter implements Converter { implicitCollectionsForCurrentObject = writeValueToImplicitCollection(context, value, implicitCollectionsForCurrentObject, result, fieldName); } } + } catch (CriticalXStreamException e) { + throw e; } catch (XStreamException e) { if (critical) { - throw e; + throw new CriticalXStreamException(e); } addErrorInContext(context, e); } catch (LinkageError e) { diff --git a/core/src/main/java/hudson/util/xstream/ImmutableListConverter.java b/core/src/main/java/hudson/util/xstream/ImmutableListConverter.java index 18fd97ec98..3734c47245 100644 --- a/core/src/main/java/hudson/util/xstream/ImmutableListConverter.java +++ b/core/src/main/java/hudson/util/xstream/ImmutableListConverter.java @@ -39,6 +39,8 @@ import hudson.util.RobustReflectionConverter; import java.util.ArrayList; import java.util.List; +import jenkins.util.xstream.CriticalXStreamException; + /** * {@link ImmutableList} should convert like a list, instead of via serialization. * @@ -76,6 +78,8 @@ public class ImmutableListConverter extends CollectionConverter { try { Object item = readItem(reader, context, items); items.add(item); + } catch (CriticalXStreamException e) { + throw e; } catch (XStreamException e) { RobustReflectionConverter.addErrorInContext(context, e); } catch (LinkageError e) { diff --git a/core/src/main/java/jenkins/util/xstream/CriticalXStreamException.java b/core/src/main/java/jenkins/util/xstream/CriticalXStreamException.java new file mode 100644 index 0000000000..5636669568 --- /dev/null +++ b/core/src/main/java/jenkins/util/xstream/CriticalXStreamException.java @@ -0,0 +1,39 @@ +/* + * The MIT License + * + * Copyright (c) 2015 IKEDA Yasuyuki + * + * 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 jenkins.util.xstream; + +import com.thoughtworks.xstream.XStreamException; +import com.thoughtworks.xstream.converters.ConversionException; + +/** + * Wraps {@link XStreamException} to indicate it is critical for Jenkins. + */ +public class CriticalXStreamException extends ConversionException { + private static final long serialVersionUID = 1L; + + public CriticalXStreamException(XStreamException cause) { + super(cause); + } +} From 7958928aedab9695379f17e6462f8b8236910497 Mon Sep 17 00:00:00 2001 From: ikedam Date: Thu, 21 May 2015 06:52:13 +0900 Subject: [PATCH 003/256] [JENKINS-28440] Updates tests for JENKINS-28440 to verify behaviors of UI. --- .../java/hudson/util/RobustReflectionConverterTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/src/test/java/hudson/util/RobustReflectionConverterTest.java b/test/src/test/java/hudson/util/RobustReflectionConverterTest.java index 0763fb4b93..fa3d3ad1cf 100644 --- a/test/src/test/java/hudson/util/RobustReflectionConverterTest.java +++ b/test/src/test/java/hudson/util/RobustReflectionConverterTest.java @@ -241,13 +241,13 @@ public class RobustReflectionConverterTest { try { wc.getPage(req); - // TODO: fail("Submitting unacceptable configuration via REST should fail."); + fail("Submitting unacceptable configuration via REST should fail."); } catch (FailingHttpStatusCodeException e) { // pass } // Configuration should not be updated for a failure of the critical field, - // TODO: assertNotEquals("badvalue", p.getProperty(KeywordProperty.class).getCriticalField().getKeyword()); + assertNotEquals("badvalue", p.getProperty(KeywordProperty.class).getCriticalField().getKeyword()); r.jenkins.reload(); @@ -328,10 +328,10 @@ public class RobustReflectionConverterTest { stdout, stderr ); - // TODO: assertNotEquals(0, ret); + assertNotEquals(0, ret); // Configuration should not be updated for a failure of the critical field, - // TODO: assertNotEquals("badvalue", p.getProperty(KeywordProperty.class).getCriticalField().getKeyword()); + assertNotEquals("badvalue", p.getProperty(KeywordProperty.class).getCriticalField().getKeyword()); r.jenkins.reload(); From 1c74641e9144d082206eca1f6973c3b90227915d Mon Sep 17 00:00:00 2001 From: Manuel Blechschmidt Date: Thu, 21 May 2015 13:49:12 +0200 Subject: [PATCH 004/256] * Add a more stable workaround for adding PluginServletFilter when they are not available yet e.g. https://marvelution.atlassian.net/browse/JJI-188 --- core/src/main/java/hudson/util/PluginServletFilter.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/hudson/util/PluginServletFilter.java b/core/src/main/java/hudson/util/PluginServletFilter.java index dfc8bdf03e..8384d022cc 100644 --- a/core/src/main/java/hudson/util/PluginServletFilter.java +++ b/core/src/main/java/hudson/util/PluginServletFilter.java @@ -90,7 +90,8 @@ public class PluginServletFilter implements Filter, ExtensionPoint { public static void addFilter(Filter filter) throws ServletException { Jenkins j = Jenkins.getInstance(); - if (j==null) { + // https://marvelution.atlassian.net/browse/JJI-188 + if (j==null || getInstance(j.servletContext) == null) { // report who is doing legacy registration LOGGER.log(Level.WARNING, "Filter instance is registered too early: "+filter, new Exception()); LEGACY.add(filter); @@ -103,7 +104,7 @@ public class PluginServletFilter implements Filter, ExtensionPoint { public static void removeFilter(Filter filter) throws ServletException { Jenkins j = Jenkins.getInstance(); - if (j==null) { + if (j==null || getInstance(j.servletContext) == null) { LEGACY.remove(filter); } else { getInstance(j.servletContext).list.remove(filter); From e0fcf91910782cea30d5bacb1f15077088628ef3 Mon Sep 17 00:00:00 2001 From: recena Date: Sun, 24 May 2015 17:40:24 +0200 Subject: [PATCH 005/256] Related to https://issues.jenkins-ci.org/browse/JENKINS-28550 --- .../main/resources/lib/layout/layout.jelly | 49 ++++++------- war/src/main/webapp/css/style.css | 71 +++++++------------ .../main/webapp/scripts/hudson-behavior.js | 64 ----------------- 3 files changed, 50 insertions(+), 134 deletions(-) diff --git a/core/src/main/resources/lib/layout/layout.jelly b/core/src/main/resources/lib/layout/layout.jelly index f5f1769da2..4e2e59de81 100644 --- a/core/src/main/resources/lib/layout/layout.jelly +++ b/core/src/main/resources/lib/layout/layout.jelly @@ -227,12 +227,12 @@ ${h.initPageVariables(context)}
-
-
-
+
+
+
- +
@@ -244,35 +244,32 @@ ${h.initPageVariables(context)}
-
- -
-
+
-
-
-
-
- - +
+ + - - -
- - -
-
- - -
-
+ + +
+ + +
+
+ +
- -
+ +
${%Page generated}: REST API Jenkins ver. ${h.version} diff --git a/war/src/main/webapp/css/style.css b/war/src/main/webapp/css/style.css index a98d93b1c4..58b8b9d0b0 100644 --- a/war/src/main/webapp/css/style.css +++ b/war/src/main/webapp/css/style.css @@ -76,10 +76,23 @@ body { #side-panel { padding: 15px 15px 80px 15px; + float: left; + width: 320px; } #main-panel { padding: 15px 15px 80px 15px; + margin-left: 320px; +} + +@media (min-width: 1170px) { + #side-panel { + width: 360px; + } + + #main-panel { + margin-left: 360px; + } } /* task */ From 6d8db1c69ea53ffeb86ec1091993565eb21d2294 Mon Sep 17 00:00:00 2001 From: recena Date: Thu, 18 Jun 2015 11:39:24 +0200 Subject: [PATCH 013/256] Solving a problem in listing jobs --- war/src/main/webapp/css/style.css | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/war/src/main/webapp/css/style.css b/war/src/main/webapp/css/style.css index 58b8b9d0b0..5c241e3515 100644 --- a/war/src/main/webapp/css/style.css +++ b/war/src/main/webapp/css/style.css @@ -103,7 +103,7 @@ body { #tasks .task { margin-bottom: 4px; - font-size: 1.1em; + font-size: 14px; white-space: nowrap; } @@ -383,7 +383,7 @@ pre.console { /* tabBar */ .tabBar { - clear: both; + /*clear: both;*/ overflow: auto; position: relative; top: 1px; @@ -488,11 +488,6 @@ pre.console { .main-table { } -div.dashboard { - width: 100%; - clear:both; -} - /* pane */ .pane-frame { From 21d622132579babdd69c1bfa37ac6bbbed9c1f1f Mon Sep 17 00:00:00 2001 From: recena Date: Thu, 18 Jun 2015 11:49:37 +0200 Subject: [PATCH 014/256] Removing a commented CSS property --- war/src/main/webapp/css/style.css | 1 - 1 file changed, 1 deletion(-) diff --git a/war/src/main/webapp/css/style.css b/war/src/main/webapp/css/style.css index 5c241e3515..74f822ddca 100644 --- a/war/src/main/webapp/css/style.css +++ b/war/src/main/webapp/css/style.css @@ -383,7 +383,6 @@ pre.console { /* tabBar */ .tabBar { - /*clear: both;*/ overflow: auto; position: relative; top: 1px; From bce0bed49d7814de6d97f9adafe3e40caefac86a Mon Sep 17 00:00:00 2001 From: recena Date: Thu, 18 Jun 2015 12:58:44 +0200 Subject: [PATCH 015/256] Layout adapted to small devices --- war/src/main/webapp/css/style.css | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/war/src/main/webapp/css/style.css b/war/src/main/webapp/css/style.css index 74f822ddca..415e319a41 100644 --- a/war/src/main/webapp/css/style.css +++ b/war/src/main/webapp/css/style.css @@ -85,6 +85,19 @@ body { margin-left: 320px; } +@media (max-width: 750px) { + #side-panel { + width: 100%; + float: none; + padding-bottom: 20px; + } + + #main-panel { + margin-left: 0; + width: 100%; + } +} + @media (min-width: 1170px) { #side-panel { width: 360px; From 4b1f46be4806bdb20e40a864d47f3ffa1b32c0eb Mon Sep 17 00:00:00 2001 From: recena Date: Thu, 18 Jun 2015 22:11:31 +0200 Subject: [PATCH 016/256] Avoid other unwanted effect --- war/src/main/webapp/scripts/hudson-behavior.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/war/src/main/webapp/scripts/hudson-behavior.js b/war/src/main/webapp/scripts/hudson-behavior.js index 3584f799b9..20b399bcfc 100644 --- a/war/src/main/webapp/scripts/hudson-behavior.js +++ b/war/src/main/webapp/scripts/hudson-behavior.js @@ -1932,6 +1932,9 @@ function updateBuildHistory(ajaxUrl,nBuild) { window.setTimeout(updateBuilds, updateBuildsRefreshInterval); } } + + //updateBuilds(); + checkAllRowCellOverflows(); window.setTimeout(updateBuilds, updateBuildsRefreshInterval); onBuildHistoryChange(function() { From 05f49062de590baf37f97b206fb6aa99b3520651 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Mon, 22 Jun 2015 15:01:11 -0400 Subject: [PATCH 017/256] Added BlockedBecauseOfBuildInProgress. --- .../java/hudson/model/AbstractProject.java | 25 +++------ .../BlockedBecauseOfBuildInProgress.java | 51 +++++++++++++++++++ 2 files changed, 58 insertions(+), 18 deletions(-) create mode 100644 core/src/main/java/hudson/model/BlockedBecauseOfBuildInProgress.java diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java index 3f477f83e5..ae3074c111 100644 --- a/core/src/main/java/hudson/model/AbstractProject.java +++ b/core/src/main/java/hudson/model/AbstractProject.java @@ -1098,23 +1098,11 @@ public abstract class AbstractProject

,R extends A } /** - * Blocked because the previous build is already in progress. + * @deprecated use {@link BlockedBecauseOfBuildInProgress} instead. */ - public static class BecauseOfBuildInProgress extends CauseOfBlockage { - private final AbstractBuild build; - + public static class BecauseOfBuildInProgress extends BlockedBecauseOfBuildInProgress { public BecauseOfBuildInProgress(AbstractBuild build) { - this.build = build; - } - - @Override - public String getShortDescription() { - Executor e = build.getExecutor(); - String eta = ""; - if (e != null) - eta = Messages.AbstractProject_ETA(e.getEstimatedRemainingTime()); - int lbn = build.getNumber(); - return Messages.AbstractProject_BuildInProgress(lbn, eta); + super(build); } } @@ -1150,10 +1138,11 @@ public abstract class AbstractProject

,R extends A } } - public CauseOfBlockage getCauseOfBlockage() { + @Override public CauseOfBlockage getCauseOfBlockage() { // Block builds until they are done with post-production - if (isLogUpdated() && !isConcurrentBuild()) - return new BecauseOfBuildInProgress(getLastBuild()); + if (isLogUpdated() && !isConcurrentBuild()) { + return new BlockedBecauseOfBuildInProgress(getLastBuild()); + } if (blockBuildWhenDownstreamBuilding()) { AbstractProject bup = getBuildingDownstream(); if (bup!=null) diff --git a/core/src/main/java/hudson/model/BlockedBecauseOfBuildInProgress.java b/core/src/main/java/hudson/model/BlockedBecauseOfBuildInProgress.java new file mode 100644 index 0000000000..937059987d --- /dev/null +++ b/core/src/main/java/hudson/model/BlockedBecauseOfBuildInProgress.java @@ -0,0 +1,51 @@ +/* + * The MIT License + * + * Copyright 2015 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; + +import hudson.model.queue.CauseOfBlockage; + +/** + * Indicates that a new build is blocked because the previous build is already in progress. + * Useful for implementing {@link hudson.model.Queue.Task#getCauseOfBlockage} from a {@link Job} which supports {@link hudson.model.Queue.Task#isConcurrentBuild}. + * @since TODO + */ +public class BlockedBecauseOfBuildInProgress extends CauseOfBlockage { + + private final Run build; + + public BlockedBecauseOfBuildInProgress(Run build) { + this.build = build; + } + + @Override public String getShortDescription() { + Executor e = build.getExecutor(); + String eta = ""; + if (e != null) { + eta = Messages.AbstractProject_ETA(e.getEstimatedRemainingTime()); + } + int lbn = build.getNumber(); + return Messages.AbstractProject_BuildInProgress(lbn, eta); + } + +} From 60c64a2047ae81004d7633c8bb185db19e733ed1 Mon Sep 17 00:00:00 2001 From: ikedam Date: Sun, 28 Jun 2015 12:10:11 +0900 Subject: [PATCH 018/256] [FIXED JENKINS-29064] dropdownDescriptorSelector should accept descriptors without configurations. --- .../main/resources/lib/form/dropdownDescriptorSelector.jelly | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/form/dropdownDescriptorSelector.jelly b/core/src/main/resources/lib/form/dropdownDescriptorSelector.jelly index aad0a87e51..7b0ca4df26 100644 --- a/core/src/main/resources/lib/form/dropdownDescriptorSelector.jelly +++ b/core/src/main/resources/lib/form/dropdownDescriptorSelector.jelly @@ -57,7 +57,7 @@ THE SOFTWARE. lazy="descriptor"> - + From fbf484377c7389bb4ee0844c10b1c22301aa77ad Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Mon, 29 Jun 2015 06:45:54 -0700 Subject: [PATCH 019/256] [maven-release-plugin] prepare release jenkins-1.618 --- cli/pom.xml | 2 +- core/pom.xml | 2 +- plugins/pom.xml | 10 +++++----- pom.xml | 4 ++-- test/pom.xml | 2 +- war/pom.xml | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cli/pom.xml b/cli/pom.xml index fd98b53eae..dce7c3d6a3 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.618-SNAPSHOT + 1.618 cli diff --git a/core/pom.xml b/core/pom.xml index 3ed159dbc3..7eb20f0c73 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.618-SNAPSHOT + 1.618 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index 2db07d3139..a859d03f87 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.618-SNAPSHOT + 1.618 pom

+

What's new in 1.618 (2015/06/29)

  • Fix deadlock in hudson.model.Executor. @@ -87,7 +92,6 @@ Upcoming changes Always use earlier start time when merging two equivalent queue items. (issue 2180)
-

What's new in 1.617 (2015/06/07)

  • From 87d2ac642abc05faf7839b528b865b4bac295dfd Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Mon, 29 Jun 2015 13:50:22 -0400 Subject: [PATCH 022/256] Moved BlockedBecauseOfBuildInProgress to the jenkins.model package. --- core/src/main/java/hudson/model/AbstractProject.java | 1 + .../model/BlockedBecauseOfBuildInProgress.java | 10 +++++++--- .../main/resources/hudson/model/Messages.properties | 2 -- .../main/resources/hudson/model/Messages_da.properties | 2 -- .../main/resources/hudson/model/Messages_de.properties | 2 -- .../main/resources/hudson/model/Messages_es.properties | 2 -- .../main/resources/hudson/model/Messages_fr.properties | 2 -- .../main/resources/hudson/model/Messages_it.properties | 2 -- .../main/resources/hudson/model/Messages_ja.properties | 2 -- .../main/resources/hudson/model/Messages_nl.properties | 2 -- .../resources/hudson/model/Messages_pt_BR.properties | 2 -- .../main/resources/hudson/model/Messages_ru.properties | 2 -- .../main/resources/hudson/model/Messages_tr.properties | 2 -- .../resources/hudson/model/Messages_zh_CN.properties | 2 -- .../resources/hudson/model/Messages_zh_TW.properties | 2 -- .../main/resources/jenkins/model/Messages.properties | 2 ++ .../resources/jenkins/model/Messages_da.properties | 2 ++ .../resources/jenkins/model/Messages_de.properties | 2 ++ .../resources/jenkins/model/Messages_es.properties | 2 ++ .../resources/jenkins/model/Messages_fr.properties | 2 ++ .../resources/jenkins/model/Messages_it.properties | 2 ++ .../resources/jenkins/model/Messages_ja.properties | 2 ++ .../resources/jenkins/model/Messages_nl.properties | 2 ++ .../resources/jenkins/model/Messages_pt_BR.properties | 2 ++ .../resources/jenkins/model/Messages_ru.properties | 2 ++ .../resources/jenkins/model/Messages_tr.properties | 2 ++ .../resources/jenkins/model/Messages_zh_CN.properties | 2 ++ .../resources/jenkins/model/Messages_zh_TW.properties | 2 ++ 28 files changed, 34 insertions(+), 29 deletions(-) rename core/src/main/java/{hudson => jenkins}/model/BlockedBecauseOfBuildInProgress.java (86%) create mode 100644 core/src/main/resources/jenkins/model/Messages_it.properties create mode 100644 core/src/main/resources/jenkins/model/Messages_zh_CN.properties diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java index ae3074c111..4d603b2967 100644 --- a/core/src/main/java/hudson/model/AbstractProject.java +++ b/core/src/main/java/hudson/model/AbstractProject.java @@ -106,6 +106,7 @@ import java.util.logging.Logger; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import javax.servlet.ServletException; +import jenkins.model.BlockedBecauseOfBuildInProgress; import jenkins.model.Jenkins; import jenkins.model.JenkinsLocationConfiguration; import jenkins.model.ParameterizedJobMixIn; diff --git a/core/src/main/java/hudson/model/BlockedBecauseOfBuildInProgress.java b/core/src/main/java/jenkins/model/BlockedBecauseOfBuildInProgress.java similarity index 86% rename from core/src/main/java/hudson/model/BlockedBecauseOfBuildInProgress.java rename to core/src/main/java/jenkins/model/BlockedBecauseOfBuildInProgress.java index 937059987d..1e910b18f4 100644 --- a/core/src/main/java/hudson/model/BlockedBecauseOfBuildInProgress.java +++ b/core/src/main/java/jenkins/model/BlockedBecauseOfBuildInProgress.java @@ -21,8 +21,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package hudson.model; +package jenkins.model; + +import hudson.model.Executor; +import hudson.model.Job; +import hudson.model.Run; import hudson.model.queue.CauseOfBlockage; /** @@ -42,10 +46,10 @@ public class BlockedBecauseOfBuildInProgress extends CauseOfBlockage { Executor e = build.getExecutor(); String eta = ""; if (e != null) { - eta = Messages.AbstractProject_ETA(e.getEstimatedRemainingTime()); + eta = Messages.BlockedBecauseOfBuildInProgress_ETA(e.getEstimatedRemainingTime()); } int lbn = build.getNumber(); - return Messages.AbstractProject_BuildInProgress(lbn, eta); + return Messages.BlockedBecauseOfBuildInProgress_shortDescription(lbn, eta); } } diff --git a/core/src/main/resources/hudson/model/Messages.properties b/core/src/main/resources/hudson/model/Messages.properties index 3537e9978a..cd26f3bf50 100644 --- a/core/src/main/resources/hudson/model/Messages.properties +++ b/core/src/main/resources/hudson/model/Messages.properties @@ -36,13 +36,11 @@ AbstractProject.AwaitingBuildForWorkspace=Awaiting build to get a workspace. AbstractProject.AwaitingWorkspaceToComeOnline=We need to schedule a new build to get a workspace, but deferring {0}ms in the hope that one will become available soon AbstractProject.Pronoun=Project AbstractProject.Aborted=Aborted -AbstractProject.BuildInProgress=Build #{0} is already in progress{1} AbstractProject.BuildNow=Build Now AbstractProject.build_with_parameters=Build with Parameters AbstractProject.UpstreamBuildInProgress=Upstream project {0} is already building. AbstractProject.DownstreamBuildInProgress=Downstream project {0} is already building. AbstractProject.Disabled=Build disabled -AbstractProject.ETA=\ (ETA:{0}) AbstractProject.NoBuilds=No existing build. Scheduling a new one. AbstractProject.NoSCM=No SCM AbstractProject.NoWorkspace=No workspace is available, so can\u2019t check for updates. diff --git a/core/src/main/resources/hudson/model/Messages_da.properties b/core/src/main/resources/hudson/model/Messages_da.properties index 3300fc7388..47eaf5455b 100644 --- a/core/src/main/resources/hudson/model/Messages_da.properties +++ b/core/src/main/resources/hudson/model/Messages_da.properties @@ -161,7 +161,6 @@ Computer.BadChannel=Slave node offline eller ikke en fjernkanal (f.eks. en maste AbstractProject.Aborted=Afbrudt Queue.init=Genopretter byggek\u00f8en Hudson.NodeDescription=master Jenkins noden -AbstractProject.BuildInProgress=Byg #{0} er allerede i gang {1} Job.NoRecentBuildFailed=Ingen byg har fejlet for nyligt. Permalink.LastUnsuccessfulBuild=Seneste fejlede byg RunParameterDefinition.DisplayName=K\u00f8rselsparameter @@ -233,7 +232,6 @@ Note: direktoriet beh\u00f8ver ikke v\u00e6re synlig for master noden. Label.GroupOf=Gruppe af {0} Queue.InQuietPeriod=I en stilleperiode. udl\u00f8ber om {0} Queue.AllNodesOffline=Alle noder med etiket ''{0}'' er offline -AbstractProject.ETA=(ETA:{0}) Hudson.NoSuchDirectory=Intet direktorie ved navn: {0} LoadStatistics.Legends.BusyExecutors=Optagede afviklere HealthReport.EmptyString= diff --git a/core/src/main/resources/hudson/model/Messages_de.properties b/core/src/main/resources/hudson/model/Messages_de.properties index ffd402aa63..9b047f61ff 100644 --- a/core/src/main/resources/hudson/model/Messages_de.properties +++ b/core/src/main/resources/hudson/model/Messages_de.properties @@ -31,13 +31,11 @@ AbstractItem.Pronoun=Element AbstractProject.NewBuildForWorkspace=Plane einen neuen Build, um einen Arbeitsbereich anzulegen. AbstractProject.Pronoun=Projekt AbstractProject.Aborted=Abgebrochen -AbstractProject.BuildInProgress=Build #{0} ist bereits in Arbeit{1} AbstractProject.BuildNow=Jetzt bauen AbstractProject.build_with_parameters=Bauen mit Parametern AbstractProject.UpstreamBuildInProgress=Vorgelagertes Projekt {0} ist bereits in Arbeit. AbstractProject.DownstreamBuildInProgress=Nachgelagertes Projekt {0} ist bereits in Arbeit. AbstractProject.Disabled=Build deaktiviert -AbstractProject.ETA=\ (ETA:{0}) AbstractProject.NoSCM=Kein SCM AbstractProject.NoBuilds=Es existiert kein Build. Starte neuen Build. AbstractProject.NoWorkspace=Kein Arbeitsbereich verf\u00fcgbar, daher kann nicht auf Aktualisierungen \u00fcberpr\u00fcft werden. diff --git a/core/src/main/resources/hudson/model/Messages_es.properties b/core/src/main/resources/hudson/model/Messages_es.properties index 27eb91abc8..9224ee33bf 100644 --- a/core/src/main/resources/hudson/model/Messages_es.properties +++ b/core/src/main/resources/hudson/model/Messages_es.properties @@ -28,10 +28,8 @@ AbstractItem.NoSuchJobExists=La tarea ''{0}'' no existe. \u00bfQuiz\u00e1s quier AbstractProject.NewBuildForWorkspace=Lanzando una nueva ejecuci\u00f3n para crear el espacio de trabajo. AbstractProject.Pronoun=Proyecto AbstractProject.Aborted=Cancelado -AbstractProject.BuildInProgress=La ejecuci\u00f3n #{0} ya est\u00e1 en progreso {1} AbstractProject.UpstreamBuildInProgress=El proyecto padre {0} ya se est\u00e1 ejecutando. AbstractProject.Disabled=Ejecuci\u00f3n desactivada -AbstractProject.ETA= (ETA:{0}) AbstractProject.NoSCM=Sin SCM AbstractProject.NoWorkspace=No hay espacio de trabajo, por tanto no se puede comprobar las actualizaciones. AbstractProject.PollingABorted=Peticiones SCM abortadas diff --git a/core/src/main/resources/hudson/model/Messages_fr.properties b/core/src/main/resources/hudson/model/Messages_fr.properties index 82d0d98072..c2ccaf0d74 100644 --- a/core/src/main/resources/hudson/model/Messages_fr.properties +++ b/core/src/main/resources/hudson/model/Messages_fr.properties @@ -26,9 +26,7 @@ AbstractBuild.KeptBecause=conserv\u00e9 \u00e0 cause de {0} AbstractProject.NewBuildForWorkspace=Demande d''un nouveau build afin d''avoir un r\u00e9pertoire de travail AbstractProject.Pronoun=Projet AbstractProject.Aborted=Annul\u00e9 -AbstractProject.BuildInProgress=Le build #{0} est d\u00e9j\u00e0 en cours {1} AbstractProject.Disabled=Build d\u00e9sactiv\u00e9 -AbstractProject.ETA=\ (fin pr\u00e9vue \u00e0: {0}) AbstractProject.NoSCM=Pas d''outil de gestion de version AbstractProject.NoWorkspace=Pas r\u00e9pertoire de travail disponible, donc impossible de r\u00e9cup\u00e9rer les mises \u00e0 jour. AbstractProject.PollingABorted=Scrutation de l''outil de gestion de version annul\u00e9e diff --git a/core/src/main/resources/hudson/model/Messages_it.properties b/core/src/main/resources/hudson/model/Messages_it.properties index fd106bf53b..120b9a125a 100644 --- a/core/src/main/resources/hudson/model/Messages_it.properties +++ b/core/src/main/resources/hudson/model/Messages_it.properties @@ -33,12 +33,10 @@ AbstractProject.NewBuildForWorkspace=Scheduling a new build to get a workspace. AbstractProject.AwaitingBuildForWorkspace=Awaiting build to get a workspace. AbstractProject.Pronoun=Progetto AbstractProject.Aborted=Interrotta -AbstractProject.BuildInProgress=Build #{0} is already in progress{1} AbstractProject.BuildNow=Effettua build AbstractProject.UpstreamBuildInProgress=Upstream project {0} is already building. AbstractProject.DownstreamBuildInProgress=Downstream project {0} is already building. AbstractProject.Disabled=Build disabled -AbstractProject.ETA=\ (ETA:{0}) AbstractProject.NoBuilds=No existing build. Scheduling a new one. AbstractProject.NoSCM=No SCM AbstractProject.NoWorkspace=No workspace is available, so can''t check for updates. diff --git a/core/src/main/resources/hudson/model/Messages_ja.properties b/core/src/main/resources/hudson/model/Messages_ja.properties index 6d31b46cf5..900babdca7 100644 --- a/core/src/main/resources/hudson/model/Messages_ja.properties +++ b/core/src/main/resources/hudson/model/Messages_ja.properties @@ -34,13 +34,11 @@ AbstractProject.NewBuildForWorkspace=\u65b0\u898f\u306e\u30d3\u30eb\u30c9\u3092\ AbstractProject.AwaitingBuildForWorkspace=\u30ef\u30fc\u30af\u30b9\u30da\u30fc\u30b9\u304c\u7528\u610f\u3067\u304d\u308b\u307e\u3067\u30d3\u30eb\u30c9\u3092\u4fdd\u7559\u3057\u307e\u3059\u3002 AbstractProject.Pronoun=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 AbstractProject.Aborted=\u4e2d\u6b62 -AbstractProject.BuildInProgress=\u30d3\u30eb\u30c9 #{0} \u306f\u65e2\u306b\u5b9f\u884c\u4e2d\u3067\u3059\u3002{1} AbstractProject.BuildNow=\u30d3\u30eb\u30c9\u5b9f\u884c AbstractProject.build_with_parameters=\u30d1\u30e9\u30e1\u30fc\u30bf\u4ed8\u304d\u30d3\u30eb\u30c9 AbstractProject.UpstreamBuildInProgress=\u4e0a\u6d41\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 {0} \u306f\u3059\u3067\u306b\u30d3\u30eb\u30c9\u4e2d\u3067\u3059\u3002 AbstractProject.DownstreamBuildInProgress=\u4e0b\u6d41\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 {0} \u304c\u307e\u3060\u30d3\u30eb\u30c9\u4e2d\u3067\u3059\u3002 AbstractProject.Disabled=\u30d3\u30eb\u30c9\u306f\u7121\u52b9\u306b\u306a\u3063\u3066\u3044\u307e\u3059\u3002 -AbstractProject.ETA=\ (\u4e88\u5b9a\u6642\u9593:{0}) AbstractProject.NoBuilds=\u30d3\u30eb\u30c9\u306f\u3042\u308a\u307e\u305b\u3093\u3002\u65b0\u3057\u3044\u30d3\u30eb\u30c9\u3092\u30b9\u30b1\u30b8\u30e5\u30fc\u30eb\u3057\u307e\u3059\u3002 AbstractProject.NoSCM=SCM\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 AbstractProject.NoWorkspace=\u5229\u7528\u53ef\u80fd\u306a\u30ef\u30fc\u30af\u30b9\u30da\u30fc\u30b9\u304c\u306a\u3044\u306e\u3067\u3001\u66f4\u65b0\u3092\u30c1\u30a7\u30c3\u30af\u3067\u304d\u307e\u305b\u3093\u3002 diff --git a/core/src/main/resources/hudson/model/Messages_nl.properties b/core/src/main/resources/hudson/model/Messages_nl.properties index 88b53d8f21..4530183288 100644 --- a/core/src/main/resources/hudson/model/Messages_nl.properties +++ b/core/src/main/resources/hudson/model/Messages_nl.properties @@ -26,9 +26,7 @@ AbstractBuild.KeptBecause=Weerhouden omwille van {0} AbstractProject.NewBuildForWorkspace=Om een werkplaats te krijgen wordt een nieuwe bouwpoging gepland. AbstractProject.Pronoun=Project AbstractProject.Aborted=Afgebroken -AbstractProject.BuildInProgress=Bouwpoging #{0} is reeds actief {1} AbstractProject.Disabled=Bouwen gedeactiveerd -AbstractProject.ETA= (einde voorzien op:{0}) AbstractProject.NoSCM=Geen versiebeheersysteem beschikbaar AbstractProject.NoWorkspace=Er is geen werkplaats beschikbaar. Ophalen van wijzigingen is dus onmogelijk. AbstractProject.PollingABorted=Contact met versiebeheersysteem werd afgebroken. diff --git a/core/src/main/resources/hudson/model/Messages_pt_BR.properties b/core/src/main/resources/hudson/model/Messages_pt_BR.properties index 5162dbd6b9..81c1b21bbc 100644 --- a/core/src/main/resources/hudson/model/Messages_pt_BR.properties +++ b/core/src/main/resources/hudson/model/Messages_pt_BR.properties @@ -25,9 +25,7 @@ AbstractBuild.KeptBecause=mantido por causa de {0} AbstractProject.Pronoun=Projeto AbstractProject.Aborted=Abortado -AbstractProject.BuildInProgress=A builds #{0} j\u00e1 est\u00e1 em progresso{1} AbstractProject.Disabled=builds desabilitada -AbstractProject.ETA=\ (ETA:{0}) AbstractProject.NoSCM=Nenhum SCM AbstractProject.NoWorkspace=Nenhum workspace est\u00e1 dispon\u00edvel, assim n\u00e3o pode checar por atualiza\u00e7\u00f5es. AbstractProject.PollingABorted=Pesquisa SCM abortada diff --git a/core/src/main/resources/hudson/model/Messages_ru.properties b/core/src/main/resources/hudson/model/Messages_ru.properties index c0be7aa273..433c2a38b8 100644 --- a/core/src/main/resources/hudson/model/Messages_ru.properties +++ b/core/src/main/resources/hudson/model/Messages_ru.properties @@ -25,9 +25,7 @@ AbstractBuild.KeptBecause=\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043e AbstractProject.Pronoun=\u041f\u0440\u043e\u0435\u043a\u0442 AbstractProject.Aborted=\u041f\u0440\u0435\u0440\u0432\u0430\u043d\u043e -AbstractProject.BuildInProgress=\u0421\u0431\u043e\u0440\u043a\u0430 #{0} \u0443\u0436\u0435 \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 {1} AbstractProject.Disabled=\u0421\u0431\u043e\u0440\u043a\u0430 \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0430 -AbstractProject.ETA=\ (\u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c:{0}) AbstractProject.NoSCM=\u041d\u0435\u0442 \u0421\u0438\u0441\u0442\u0435\u043c\u044b \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u044f \u0432\u0435\u0440\u0441\u0438\u0439 AbstractProject.NoWorkspace=\u0421\u0431\u043e\u0440\u043e\u0447\u043d\u043e\u0439 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u0438 \u043d\u0435\u0442, \u043d\u0435 \u043c\u043e\u0433\u0443 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f. AbstractProject.PollingABorted=\u041e\u043f\u0440\u043e\u0441 SCM \u043f\u0440\u0435\u0440\u0432\u0430\u043d diff --git a/core/src/main/resources/hudson/model/Messages_tr.properties b/core/src/main/resources/hudson/model/Messages_tr.properties index 3ea32148ca..fc4fb70847 100644 --- a/core/src/main/resources/hudson/model/Messages_tr.properties +++ b/core/src/main/resources/hudson/model/Messages_tr.properties @@ -26,9 +26,7 @@ AbstractBuild.KeptBecause={0} y\u00fcz\u00fcnden tutulmu\u015f AbstractProject.NewBuildForWorkspace=\u00c7al\u0131\u015fma alan\u0131 olu\u015fturmak i\u00e7in bir yap\u0131land\u0131rma planlan\u0131yor AbstractProject.Pronoun=Proje AbstractProject.Aborted=Durduruldu -AbstractProject.BuildInProgress=Yap\u0131land\u0131rma #{0} zaten i\u015flemde {1} AbstractProject.Disabled=Yap\u0131land\u0131rma devre d\u0131\u015f\u0131 b\u0131rak\u0131ld\u0131 -AbstractProject.ETA=\ (ETA:{0}) AbstractProject.NoSCM=SCM yok AbstractProject.NoWorkspace=Herhangi bir \u00e7al\u0131\u015fma alan\u0131 bulunmad\u0131\u011f\u0131ndan g\u00fcncellemeler kontrol edilemiyor. AbstractProject.PollingABorted=SCM kontrol\u00fc durduruldu diff --git a/core/src/main/resources/hudson/model/Messages_zh_CN.properties b/core/src/main/resources/hudson/model/Messages_zh_CN.properties index d89016d3d2..299c1a485d 100644 --- a/core/src/main/resources/hudson/model/Messages_zh_CN.properties +++ b/core/src/main/resources/hudson/model/Messages_zh_CN.properties @@ -29,10 +29,8 @@ AbstractItem.NoSuchJobExists=No such job ''{0}'' exists. Perhaps you meant ''{1} AbstractProject.NewBuildForWorkspace=Scheduling a new build to get a workspace. AbstractProject.Pronoun=Project AbstractProject.Aborted=Aborted -AbstractProject.BuildInProgress=Build #{0} is already in progress{1} AbstractProject.UpstreamBuildInProgress=Upstream project {0} is already building. AbstractProject.Disabled=Build disabled -AbstractProject.ETA=\ (ETA:{0}) AbstractProject.NoBuilds=No existing build. Scheduling a new one. AbstractProject.NoSCM=No SCM AbstractProject.NoWorkspace=No workspace is available, so can''t check for updates. diff --git a/core/src/main/resources/hudson/model/Messages_zh_TW.properties b/core/src/main/resources/hudson/model/Messages_zh_TW.properties index 77437b859d..ef544a9939 100644 --- a/core/src/main/resources/hudson/model/Messages_zh_TW.properties +++ b/core/src/main/resources/hudson/model/Messages_zh_TW.properties @@ -34,12 +34,10 @@ AbstractProject.NewBuildForWorkspace=\u6311\u500b\u6642\u9593\u5efa\u7f6e\uff0c\ AbstractProject.AwaitingBuildForWorkspace=\u7b49\u5019\u5efa\u7f6e\u7522\u51fa\u5de5\u4f5c\u5340\u3002 AbstractProject.Pronoun=\u5c08\u6848 AbstractProject.Aborted=\u4e2d\u65b7 -AbstractProject.BuildInProgress=\u5efa\u7f6e #{0} \u57f7\u884c\u4e2d{1} AbstractProject.BuildNow=\u99ac\u4e0a\u5efa\u7f6e AbstractProject.UpstreamBuildInProgress=\u4e0a\u6e38\u5c08\u6848 {0} \u5efa\u7f6e\u4e2d\u3002 AbstractProject.DownstreamBuildInProgress=\u4e0b\u6e38\u5c08\u6848 {0} \u5efa\u7f6e\u4e2d\u3002 AbstractProject.Disabled=\u5efa\u7f6e\u505c\u7528 -AbstractProject.ETA=\ (\u9810\u4f30\u6642\u9593:{0}) AbstractProject.NoBuilds=\u6c92\u6709\u5efa\u7f6e\u8a18\u9304\u3002\u99ac\u4e0a\u5efa\u7f6e\u4e00\u6b21\u5427\u3002 AbstractProject.NoSCM=\u7121 SCM AbstractProject.NoWorkspace=\u6c92\u6709\u5de5\u4f5c\u5340\uff0c\u7121\u6cd5\u6aa2\u67e5\u66f4\u65b0\u3002 diff --git a/core/src/main/resources/jenkins/model/Messages.properties b/core/src/main/resources/jenkins/model/Messages.properties index 98c360e524..3b6e82bdb4 100644 --- a/core/src/main/resources/jenkins/model/Messages.properties +++ b/core/src/main/resources/jenkins/model/Messages.properties @@ -66,3 +66,5 @@ Mailer.Localhost.Error=Please set a valid host name, instead of localhost PatternProjectNamingStrategy.DisplayName=Pattern PatternProjectNamingStrategy.NamePatternRequired=Name Pattern is required PatternProjectNamingStrategy.NamePatternInvalidSyntax=regular expression's syntax is invalid. +BlockedBecauseOfBuildInProgress.shortDescription=Build #{0} is already in progress{1} +BlockedBecauseOfBuildInProgress.ETA=\ (ETA:{0}) diff --git a/core/src/main/resources/jenkins/model/Messages_da.properties b/core/src/main/resources/jenkins/model/Messages_da.properties index c355612da1..f0e9d75716 100644 --- a/core/src/main/resources/jenkins/model/Messages_da.properties +++ b/core/src/main/resources/jenkins/model/Messages_da.properties @@ -52,3 +52,5 @@ Nyttigt hvis du har modificeret konfigurationsfiler direkte, udenom Jenkins. Mailer.Address.Not.Configured=Adresse ikke konfigureret Mailer.Localhost.Error=Venligst inds\u00e6t et gyldigt v\u00e6rtsnavn, istedet for localhost +BlockedBecauseOfBuildInProgress.shortDescription=Byg #{0} er allerede i gang {1} +BlockedBecauseOfBuildInProgress.ETA=(ETA:{0}) diff --git a/core/src/main/resources/jenkins/model/Messages_de.properties b/core/src/main/resources/jenkins/model/Messages_de.properties index dc2b7ce547..d8cf45b10e 100644 --- a/core/src/main/resources/jenkins/model/Messages_de.properties +++ b/core/src/main/resources/jenkins/model/Messages_de.properties @@ -61,3 +61,5 @@ Mailer.Localhost.Error=Bitte verwenden Sie einen konkreten Hostnamen anstelle vo PatternProjectNamingStrategy.DisplayName=Muster PatternProjectNamingStrategy.NamePatternRequired=Der Regul\u00e4re Ausdruck darf nicht leer sein. PatternProjectNamingStrategy.NamePatternInvalidSyntax=Der Regul\u00e4re Ausdruck ist ung\u00fcltig. +BlockedBecauseOfBuildInProgress.shortDescription=Build #{0} ist bereits in Arbeit{1} +BlockedBecauseOfBuildInProgress.ETA=\ (ETA:{0}) diff --git a/core/src/main/resources/jenkins/model/Messages_es.properties b/core/src/main/resources/jenkins/model/Messages_es.properties index 4b4c61a764..089af06b0e 100644 --- a/core/src/main/resources/jenkins/model/Messages_es.properties +++ b/core/src/main/resources/jenkins/model/Messages_es.properties @@ -62,3 +62,5 @@ PatternProjectNamingStrategy.NamePatternInvalidSyntax=La sintaxis de la expresi Mailer.Address.Not.Configured=Dirección no configurada todavía Mailer.Localhost.Error=Escriba un nombre de servidor correcto en lugar de "localhost" +BlockedBecauseOfBuildInProgress.shortDescription=La ejecuci\u00f3n #{0} ya est\u00e1 en progreso {1} +BlockedBecauseOfBuildInProgress.ETA= (ETA:{0}) diff --git a/core/src/main/resources/jenkins/model/Messages_fr.properties b/core/src/main/resources/jenkins/model/Messages_fr.properties index ee643ff342..b7ad51f023 100644 --- a/core/src/main/resources/jenkins/model/Messages_fr.properties +++ b/core/src/main/resources/jenkins/model/Messages_fr.properties @@ -42,3 +42,5 @@ Hudson.ReadPermission.Description=\ — retirez ce droit \u00e0 l''utilisateur anonymous, puis \ ajoutez le pseudo-utilisateur "authenticated" et accordez-lui le droit en lecture. +BlockedBecauseOfBuildInProgress.shortDescription=Le build #{0} est d\u00e9j\u00e0 en cours {1} +BlockedBecauseOfBuildInProgress.ETA=\ (fin pr\u00e9vue \u00e0: {0}) diff --git a/core/src/main/resources/jenkins/model/Messages_it.properties b/core/src/main/resources/jenkins/model/Messages_it.properties new file mode 100644 index 0000000000..536604b3d1 --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_it.properties @@ -0,0 +1,2 @@ +BlockedBecauseOfBuildInProgress.shortDescription=Build #{0} is already in progress{1} +BlockedBecauseOfBuildInProgress.ETA=\ (ETA:{0}) diff --git a/core/src/main/resources/jenkins/model/Messages_ja.properties b/core/src/main/resources/jenkins/model/Messages_ja.properties index 115d02941b..00382af55d 100644 --- a/core/src/main/resources/jenkins/model/Messages_ja.properties +++ b/core/src/main/resources/jenkins/model/Messages_ja.properties @@ -62,3 +62,5 @@ PatternProjectNamingStrategy.NamePatternInvalidSyntax=\u6b63\u898f\u8868\u73fe\u Mailer.Address.Not.Configured=\u307e\u3060\u30a2\u30c9\u30ec\u30b9\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 Mailer.Localhost.Error=localhost\u306e\u4ee3\u308f\u308a\u306b\u59a5\u5f53\u306a\u30db\u30b9\u30c8\u540d\u3092\u8a2d\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +BlockedBecauseOfBuildInProgress.shortDescription=\u30d3\u30eb\u30c9 #{0} \u306f\u65e2\u306b\u5b9f\u884c\u4e2d\u3067\u3059\u3002{1} +BlockedBecauseOfBuildInProgress.ETA=\ (\u4e88\u5b9a\u6642\u9593:{0}) diff --git a/core/src/main/resources/jenkins/model/Messages_nl.properties b/core/src/main/resources/jenkins/model/Messages_nl.properties index 6e0492c762..f80916068b 100644 --- a/core/src/main/resources/jenkins/model/Messages_nl.properties +++ b/core/src/main/resources/jenkins/model/Messages_nl.properties @@ -30,3 +30,5 @@ Hudson.NoJavaInPath=java is niet beschikbaar op uw pad. Misschien moet je een Date: Mon, 29 Jun 2015 13:53:39 -0400 Subject: [PATCH 023/256] Matching test update. --- test/src/test/java/hudson/model/ProjectTest.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/src/test/java/hudson/model/ProjectTest.java b/test/src/test/java/hudson/model/ProjectTest.java index b7faf8bff9..209e162117 100644 --- a/test/src/test/java/hudson/model/ProjectTest.java +++ b/test/src/test/java/hudson/model/ProjectTest.java @@ -48,7 +48,6 @@ import hudson.model.AbstractProject.BecauseOfUpstreamBuildInProgress; import hudson.model.AbstractProject.BecauseOfDownstreamBuildInProgress; import jenkins.model.WorkspaceWriter; import jenkins.model.Jenkins; -import hudson.model.AbstractProject.BecauseOfBuildInProgress; import antlr.ANTLRException; import hudson.triggers.SCMTrigger; import hudson.model.Cause.LegacyCodeCause; @@ -87,10 +86,10 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; +import jenkins.model.BlockedBecauseOfBuildInProgress; import org.junit.Ignore; import org.jvnet.hudson.test.Issue; -import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.TestBuilder; /** @@ -359,7 +358,7 @@ public class ProjectTest { FreeStyleProject p = j.createFreeStyleProject("project"); p.getBuildersList().add(new Shell("sleep 10")); QueueTaskFuture b1 = waitForStart(p); - assertInstanceOf("Build can not start because previous build has not finished: " + p.getCauseOfBlockage(), p.getCauseOfBlockage(), BecauseOfBuildInProgress.class); + assertInstanceOf("Build can not start because previous build has not finished: " + p.getCauseOfBlockage(), p.getCauseOfBlockage(), BlockedBecauseOfBuildInProgress.class); p.getLastBuild().getExecutor().interrupt(); b1.get(); // wait for it to finish From 38818064a80d4e61ff286ccc2386bf971f54bddc Mon Sep 17 00:00:00 2001 From: recena Date: Tue, 30 Jun 2015 10:32:01 +0200 Subject: [PATCH 024/256] [JENKINS-28550] A commented line has been removed --- war/src/main/webapp/scripts/hudson-behavior.js | 1 - 1 file changed, 1 deletion(-) diff --git a/war/src/main/webapp/scripts/hudson-behavior.js b/war/src/main/webapp/scripts/hudson-behavior.js index 20b399bcfc..eeeb1172e1 100644 --- a/war/src/main/webapp/scripts/hudson-behavior.js +++ b/war/src/main/webapp/scripts/hudson-behavior.js @@ -1933,7 +1933,6 @@ function updateBuildHistory(ajaxUrl,nBuild) { } } - //updateBuilds(); checkAllRowCellOverflows(); window.setTimeout(updateBuilds, updateBuildsRefreshInterval); From a5f704c73ccd0aff2ef5272726b4e41982a7f410 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Wed, 1 Jul 2015 10:47:51 +0200 Subject: [PATCH 025/256] Fix typo --- changelog.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.html b/changelog.html index 351eaf22a6..82c1e87cfe 100644 --- a/changelog.html +++ b/changelog.html @@ -84,7 +84,7 @@ Upcoming changes (issue 28601)
  • Fix deadlock between hudson.model.Queue and hudson.model.Computer. - (issue 28840) + (issue 28840)
  • Fix jobs getting stuck in the Queue when there exists a cycle of upstream/downstream blocks between them. (issue 28926) From 112dd652d11993b68bb6b59001842e2ce3cf8f9f Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 1 Jul 2015 07:20:24 -0400 Subject: [PATCH 026/256] Adding @Deprecated at the suggestion of @daniel-beck. --- core/src/main/java/hudson/model/AbstractProject.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java index 4d603b2967..48886f6852 100644 --- a/core/src/main/java/hudson/model/AbstractProject.java +++ b/core/src/main/java/hudson/model/AbstractProject.java @@ -1101,6 +1101,7 @@ public abstract class AbstractProject

    ,R extends A /** * @deprecated use {@link BlockedBecauseOfBuildInProgress} instead. */ + @Deprecated public static class BecauseOfBuildInProgress extends BlockedBecauseOfBuildInProgress { public BecauseOfBuildInProgress(AbstractBuild build) { super(build); From c3eb4cfddb3e628c3410d4655643eb14a0718200 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 1 Jul 2015 13:55:06 -0400 Subject: [PATCH 027/256] Typo. This list is of JobProperty, not UserProperty. --- core/src/main/java/hudson/model/Job.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/Job.java b/core/src/main/java/hudson/model/Job.java index 286c7aba32..85d440f25a 100644 --- a/core/src/main/java/hudson/model/Job.java +++ b/core/src/main/java/hudson/model/Job.java @@ -160,7 +160,7 @@ public abstract class Job, RunT extends Run> properties = new CopyOnWriteList>(); From 63186180e0b17c486302cb4ac2c8add47096b637 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Thu, 2 Jul 2015 16:31:34 +0200 Subject: [PATCH 028/256] [FIX JENKINS-27694] Update dynamically loaded plugins' Downloadables --- .../java/hudson/model/DownloadService.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/core/src/main/java/hudson/model/DownloadService.java b/core/src/main/java/hudson/model/DownloadService.java index ff5e3811c9..905199581c 100644 --- a/core/src/main/java/hudson/model/DownloadService.java +++ b/core/src/main/java/hudson/model/DownloadService.java @@ -25,8 +25,11 @@ package hudson.model; import hudson.Extension; import hudson.ExtensionList; +import hudson.ExtensionListListener; import hudson.ExtensionPoint; import hudson.ProxyConfiguration; +import hudson.init.InitMilestone; +import hudson.init.Initializer; import hudson.util.FormValidation; import hudson.util.FormValidation.Kind; import hudson.util.QuotedStringTokenizer; @@ -37,6 +40,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLEncoder; +import java.util.logging.Level; import java.util.logging.Logger; import jenkins.model.DownloadSettings; import jenkins.model.Jenkins; @@ -194,6 +198,45 @@ public class DownloadService extends PageDecorator { } } + /** + * This installs itself as a listener to changes to the Downloadable extension list and will download the metadata + * for any newly added Downloadables. + */ + @Restricted(NoExternalUse.class) + public static class DownloadableListener extends ExtensionListListener { + + /** + * Install this listener to the Downloadable extension list after all extensions have been loaded; we only + * care about those that are added after initialization + */ + @Initializer(after = InitMilestone.EXTENSIONS_AUGMENTED) + public static void installListener() { + ExtensionList.lookup(Downloadable.class).addListener(new DownloadableListener()); + } + + /** + * Look for Downloadables that have no data, and update them. + */ + @Override + public void onChange() { + for (Downloadable d : Downloadable.all()) { + TextFile f = d.getDataFile(); + if (f == null || !f.exists()) { + LOGGER.log(Level.FINE, "Updating metadata for " + d.getId()); + try { + d.updateNow(); + } catch (IOException e) { + LOGGER.log(Level.WARNING, "Failed to update metadata for " + d.getId(), e); + } + } else { + LOGGER.log(Level.FINER, "Skipping update of metadata for " + d.getId()); + } + } + } + + private static final Logger LOGGER = Logger.getLogger(DownloadableListener.class.getName()); + } + /** * Represents a periodically updated JSON data file obtained from a remote URL. * From 2c6dd5e6276d04702ccf76a7d71c860ed7921ef9 Mon Sep 17 00:00:00 2001 From: David Alberto Date: Fri, 3 Jul 2015 09:33:40 -0400 Subject: [PATCH 029/256] LoadStatistics: fix spacing issue in message bundle pretty minor, but some words were joined together when rendering the message in the load statistics page. --- .../resources/hudson/model/LoadStatistics/main.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/resources/hudson/model/LoadStatistics/main.properties b/core/src/main/resources/hudson/model/LoadStatistics/main.properties index 8bd2d40967..9fc34ab657 100644 --- a/core/src/main/resources/hudson/model/LoadStatistics/main.properties +++ b/core/src/main/resources/hudson/model/LoadStatistics/main.properties @@ -57,8 +57,8 @@ blurb=\ adding more computers.\ \ \ -

    Note:The number of busy executors and the number of available executors need not \ - necessarily be equal to the number of online executors as executors can be suspended from\ +

    Note: The number of busy executors and the number of available executors need not \ + necessarily be equal to the number of online executors as executors can be suspended from \ accepting builds and thus be neither busy nor available.

    \

    The graph is an exponential moving average of periodically collected data values. \ 3 timespans are updated every 10 seconds, 1 minute and 1 hour respectively.

    From 86c26cd17e1ba1413f32e653568539ff3902808f Mon Sep 17 00:00:00 2001 From: Carlos Sanchez Date: Fri, 3 Jul 2015 16:38:13 +0200 Subject: [PATCH 030/256] Add @since annotation to ExtensionListListener --- core/src/main/java/hudson/ExtensionListListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/ExtensionListListener.java b/core/src/main/java/hudson/ExtensionListListener.java index 26950b985a..f5c8528add 100644 --- a/core/src/main/java/hudson/ExtensionListListener.java +++ b/core/src/main/java/hudson/ExtensionListListener.java @@ -27,7 +27,7 @@ package hudson; * {@link ExtensionList} listener. * * @author tom.fennelly@gmail.com - * @since TODO + * @since 1.614 */ public abstract class ExtensionListListener { From 3c785d5af0ad7362c5944aca95424a028219ce29 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Sun, 5 Jul 2015 16:42:08 +0200 Subject: [PATCH 031/256] Noting #1754 --- changelog.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.html b/changelog.html index 82c1e87cfe..b06d4da315 100644 --- a/changelog.html +++ b/changelog.html @@ -55,7 +55,9 @@ Upcoming changes

    What's new in 1.618 (2015/06/29)

    From 5410740d95ccd7074fb9f0fddbd91f1c9006042e Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Sun, 5 Jul 2015 16:52:59 +0200 Subject: [PATCH 032/256] Noting #1684 --- changelog.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/changelog.html b/changelog.html index b06d4da315..18fb3525f0 100644 --- a/changelog.html +++ b/changelog.html @@ -55,9 +55,12 @@ Upcoming changes

    What's new in 1.618 (2015/06/29)

    From 564a16df77b4ddcca1168af2925283cdef4353c9 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 5 Jul 2015 21:19:48 -0700 Subject: [PATCH 033/256] [maven-release-plugin] prepare release jenkins-1.619 --- cli/pom.xml | 2 +- core/pom.xml | 2 +- plugins/pom.xml | 10 +++++----- pom.xml | 4 ++-- test/pom.xml | 2 +- war/pom.xml | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cli/pom.xml b/cli/pom.xml index 2664af9263..28f8111061 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.619-SNAPSHOT + 1.619 cli diff --git a/core/pom.xml b/core/pom.xml index 252b0eeb5e..14de01f69f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.619-SNAPSHOT + 1.619 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index ac1f1cb2b8..ab828c2d24 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.619-SNAPSHOT + 1.619 pom +

    What's new in 1.619 (2015/07/05)

    • Update auto-installer metadata for newly installed plugins. @@ -62,7 +67,6 @@ Upcoming changes Allow plugins to veto process killing. (issue 9104)
    -

What's new in 1.618 (2015/06/29)

  • From df4bb2de2d22bfa8a0e1beed14615a40786e3942 Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Mon, 23 Mar 2015 22:23:49 +0300 Subject: [PATCH 036/256] Don't run disabled/copied projects --- core/src/main/java/hudson/triggers/Trigger.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/src/main/java/hudson/triggers/Trigger.java b/core/src/main/java/hudson/triggers/Trigger.java index 6f5c922d26..a4bdb4a236 100644 --- a/core/src/main/java/hudson/triggers/Trigger.java +++ b/core/src/main/java/hudson/triggers/Trigger.java @@ -241,6 +241,10 @@ public abstract class Trigger implements Describable> // FIXME allow to set a global crontab spec previousSynchronousPolling = scmd.getExecutor().submit(new DependencyRunner(new ProjectRunnable() { public void run(AbstractProject p) { + if (!p.isBuildable()) { + return; //skip disabled/copied project + } + for (Trigger t : (Collection) p.getTriggers().values()) { if (t instanceof SCMTrigger) { LOGGER.fine("synchronously triggering SCMTrigger for project " + t.job.getName()); @@ -256,6 +260,12 @@ public abstract class Trigger implements Describable> // Process all triggers, except SCMTriggers when synchronousPolling is set for (ParameterizedJobMixIn.ParameterizedJob p : inst.getAllItems(ParameterizedJobMixIn.ParameterizedJob.class)) { + if (p instanceof AbstractProject) { + if (!((AbstractProject) p).isBuildable()) { + continue; // skip disabled/copied project + } + } + for (Trigger t : p.getTriggers().values()) { if (! (t instanceof SCMTrigger && scmd.synchronousPolling)) { LOGGER.log(Level.FINE, "cron checking {0} with spec ‘{1}’", new Object[] {p, t.spec.trim()}); From 3c471f1fd26fd893726e3f7216de38a2fd3f7c5d Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Thu, 26 Mar 2015 19:07:07 +0300 Subject: [PATCH 037/256] Dont start onLoad and after submit for disabled --- .../java/hudson/model/AbstractProject.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java index 3f477f83e5..319f355fd5 100644 --- a/core/src/main/java/hudson/model/AbstractProject.java +++ b/core/src/main/java/hudson/model/AbstractProject.java @@ -324,11 +324,13 @@ public abstract class AbstractProject

    ,R extends A buildMixIn.onLoad(parent, name); builds = buildMixIn.getRunMap(); triggers().setOwner(this); - for (Trigger t : triggers()) { - try { - t.start(this, Items.currentlyUpdatingByXml()); - } catch (Throwable e) { - LOGGER.log(Level.WARNING, "could not start trigger while loading project '" + getFullName() + "'", e); + if (isBuildable()) { + for (Trigger t : triggers()) { + try { + t.start(this, Items.currentlyUpdatingByXml()); + } catch (Throwable e) { + LOGGER.log(Level.WARNING, "could not start trigger while loading project '" + getFullName() + "'", e); + } } } if(scm==null) @@ -1879,8 +1881,10 @@ public abstract class AbstractProject

    ,R extends A for (Trigger t : triggers()) t.stop(); triggers.replaceBy(buildDescribable(req, Trigger.for_(this))); - for (Trigger t : triggers()) - t.start(this,true); + if (isBuildable()) { + for (Trigger t : triggers()) + t.start(this, true); + } } /** From 1bea95f7a26e9d3ddcc3f5b6f1db014ba34ab976 Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Thu, 26 Mar 2015 21:31:57 +0300 Subject: [PATCH 038/256] Clarify doc because of unknown race conditions --- core/src/main/java/hudson/triggers/Trigger.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/java/hudson/triggers/Trigger.java b/core/src/main/java/hudson/triggers/Trigger.java index a4bdb4a236..a6b6443a0a 100644 --- a/core/src/main/java/hudson/triggers/Trigger.java +++ b/core/src/main/java/hudson/triggers/Trigger.java @@ -99,6 +99,8 @@ public abstract class Trigger implements Describable> * * This method is invoked when {@link #Trigger(String)} is used * to create an instance, and the crontab matches the current time. + *

    + * Maybe run even before {@link #start(hudson.model.Item, boolean)}, prepare for it. */ public void run() {} From d703b10fd6f9b6412d5e3450d5d637dae98d9550 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Wed, 8 Jul 2015 13:16:11 +0100 Subject: [PATCH 039/256] Added a simple isMultipart utility to MultipartFormDataParser --- .../hudson/security/csrf/CrumbFilter.java | 19 +------- .../hudson/util/MultipartFormDataParser.java | 19 ++++++++ .../util/MultipartFormDataParserTest.java | 43 +++++++++++++++++++ 3 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 core/src/test/java/hudson/util/MultipartFormDataParserTest.java diff --git a/core/src/main/java/hudson/security/csrf/CrumbFilter.java b/core/src/main/java/hudson/security/csrf/CrumbFilter.java index 788eaa50ca..fc6ec449f4 100644 --- a/core/src/main/java/hudson/security/csrf/CrumbFilter.java +++ b/core/src/main/java/hudson/security/csrf/CrumbFilter.java @@ -5,6 +5,7 @@ */ package hudson.security.csrf; +import hudson.util.MultipartFormDataParser; import jenkins.model.Jenkins; import java.io.IOException; @@ -97,23 +98,7 @@ public class CrumbFilter implements Filter { return false; } - String contentType = request.getContentType(); - if (contentType == null) { - return false; - } - - String[] parts = contentType.split(";"); - if (parts.length == 0) { - return false; - } - - for (int i = 0; i < parts.length; i++) { - if ("multipart/form-data".equals(parts[i])) { - return true; - } - } - - return false; + return MultipartFormDataParser.isMultipart(request.getContentType()); } /** diff --git a/core/src/main/java/hudson/util/MultipartFormDataParser.java b/core/src/main/java/hudson/util/MultipartFormDataParser.java index ee579b8390..2d2f6e3456 100644 --- a/core/src/main/java/hudson/util/MultipartFormDataParser.java +++ b/core/src/main/java/hudson/util/MultipartFormDataParser.java @@ -71,4 +71,23 @@ public class MultipartFormDataParser { for (FileItem item : byName.values()) item.delete(); } + + public static boolean isMultipart(String contentType) { + if (contentType == null) { + return false; + } + + String[] parts = contentType.split(";"); + if (parts.length == 0) { + return false; + } + + for (int i = 0; i < parts.length; i++) { + if ("multipart/form-data".equals(parts[i])) { + return true; + } + } + + return false; + } } diff --git a/core/src/test/java/hudson/util/MultipartFormDataParserTest.java b/core/src/test/java/hudson/util/MultipartFormDataParserTest.java new file mode 100644 index 0000000000..c90163b815 --- /dev/null +++ b/core/src/test/java/hudson/util/MultipartFormDataParserTest.java @@ -0,0 +1,43 @@ +/* + * The MIT License + * + * Copyright (c) 2015, CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package hudson.util; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author tom.fennelly@gmail.com + */ +public class MultipartFormDataParserTest { + + @Test + public void testIsMultipart() throws Exception { + Assert.assertEquals(false, MultipartFormDataParser.isMultipart(null)); + Assert.assertEquals(false, MultipartFormDataParser.isMultipart("blah")); + + Assert.assertEquals(true, MultipartFormDataParser.isMultipart("multipart/form-data")); + Assert.assertEquals(true, MultipartFormDataParser.isMultipart("multipart/form-data;")); + Assert.assertEquals(true, MultipartFormDataParser.isMultipart("multipart/form-data; boundary=----WebKitFormBoundary8OOwv1Xp4c5XkBmD")); + } +} From 76841f9d7e81bc4aa43caeca6916f52778bbd878 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Wed, 8 Jul 2015 14:03:28 +0100 Subject: [PATCH 040/256] Javadoc etc for @jtnord --- .../main/java/hudson/security/csrf/CrumbFilter.java | 2 +- .../java/hudson/util/MultipartFormDataParser.java | 11 ++++++++++- .../java/hudson/util/MultipartFormDataParserTest.java | 10 +++++----- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/hudson/security/csrf/CrumbFilter.java b/core/src/main/java/hudson/security/csrf/CrumbFilter.java index fc6ec449f4..615dd7f376 100644 --- a/core/src/main/java/hudson/security/csrf/CrumbFilter.java +++ b/core/src/main/java/hudson/security/csrf/CrumbFilter.java @@ -98,7 +98,7 @@ public class CrumbFilter implements Filter { return false; } - return MultipartFormDataParser.isMultipart(request.getContentType()); + return MultipartFormDataParser.isMultiPartForm(request.getContentType()); } /** diff --git a/core/src/main/java/hudson/util/MultipartFormDataParser.java b/core/src/main/java/hudson/util/MultipartFormDataParser.java index 2d2f6e3456..661cc303c5 100644 --- a/core/src/main/java/hudson/util/MultipartFormDataParser.java +++ b/core/src/main/java/hudson/util/MultipartFormDataParser.java @@ -28,6 +28,7 @@ import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadException; +import javax.annotation.CheckForNull; import javax.servlet.http.HttpServletRequest; import javax.servlet.ServletException; import java.util.List; @@ -72,7 +73,15 @@ public class MultipartFormDataParser { item.delete(); } - public static boolean isMultipart(String contentType) { + /** + * Checks a Content-Type string + * to assert if it is "multipart/form-data". + * + * @param contentType Content-Type string. + * @return {@code true} if the content type is "multipart/form-data", otherwise {@code false}. + * @since TODO + */ + public static boolean isMultiPartForm(@CheckForNull String contentType) { if (contentType == null) { return false; } diff --git a/core/src/test/java/hudson/util/MultipartFormDataParserTest.java b/core/src/test/java/hudson/util/MultipartFormDataParserTest.java index c90163b815..379181604b 100644 --- a/core/src/test/java/hudson/util/MultipartFormDataParserTest.java +++ b/core/src/test/java/hudson/util/MultipartFormDataParserTest.java @@ -33,11 +33,11 @@ public class MultipartFormDataParserTest { @Test public void testIsMultipart() throws Exception { - Assert.assertEquals(false, MultipartFormDataParser.isMultipart(null)); - Assert.assertEquals(false, MultipartFormDataParser.isMultipart("blah")); + Assert.assertEquals(false, MultipartFormDataParser.isMultiPartForm(null)); + Assert.assertEquals(false, MultipartFormDataParser.isMultiPartForm("blah")); - Assert.assertEquals(true, MultipartFormDataParser.isMultipart("multipart/form-data")); - Assert.assertEquals(true, MultipartFormDataParser.isMultipart("multipart/form-data;")); - Assert.assertEquals(true, MultipartFormDataParser.isMultipart("multipart/form-data; boundary=----WebKitFormBoundary8OOwv1Xp4c5XkBmD")); + Assert.assertEquals(true, MultipartFormDataParser.isMultiPartForm("multipart/form-data")); + Assert.assertEquals(true, MultipartFormDataParser.isMultiPartForm("multipart/form-data;")); + Assert.assertEquals(true, MultipartFormDataParser.isMultiPartForm("multipart/form-data; boundary=----WebKitFormBoundary8OOwv1Xp4c5XkBmD")); } } From 49e0d64f57ad0d43f31c887d32ddf4be224cf0cc Mon Sep 17 00:00:00 2001 From: tfennelly Date: Wed, 8 Jul 2015 14:58:49 +0100 Subject: [PATCH 041/256] More @jtnord w*f --- core/src/main/java/hudson/util/MultipartFormDataParser.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/hudson/util/MultipartFormDataParser.java b/core/src/main/java/hudson/util/MultipartFormDataParser.java index 661cc303c5..5c1184cd2e 100644 --- a/core/src/main/java/hudson/util/MultipartFormDataParser.java +++ b/core/src/main/java/hudson/util/MultipartFormDataParser.java @@ -74,10 +74,9 @@ public class MultipartFormDataParser { } /** - * Checks a Content-Type string - * to assert if it is "multipart/form-data". + * Checks a Content-Type string to assert if it is "multipart/form-data". * - * @param contentType Content-Type string. + * @param contentType Content-Type string. * @return {@code true} if the content type is "multipart/form-data", otherwise {@code false}. * @since TODO */ From b103e59238f9924f5261d0b9c7099329c8b84f94 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Wed, 8 Jul 2015 15:08:09 +0100 Subject: [PATCH 042/256] Making @jtnord happy ridiculous stuff --- .../java/hudson/util/MultipartFormDataParserTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/test/java/hudson/util/MultipartFormDataParserTest.java b/core/src/test/java/hudson/util/MultipartFormDataParserTest.java index 379181604b..3cf0de27f9 100644 --- a/core/src/test/java/hudson/util/MultipartFormDataParserTest.java +++ b/core/src/test/java/hudson/util/MultipartFormDataParserTest.java @@ -33,11 +33,11 @@ public class MultipartFormDataParserTest { @Test public void testIsMultipart() throws Exception { - Assert.assertEquals(false, MultipartFormDataParser.isMultiPartForm(null)); - Assert.assertEquals(false, MultipartFormDataParser.isMultiPartForm("blah")); + Assert.assertFalse("Wrongly identified \"multipart/form-data\"", MultipartFormDataParser.isMultiPartForm(null)); + Assert.assertFalse("Wrongly identified \"multipart/form-data\"", MultipartFormDataParser.isMultiPartForm("blah")); - Assert.assertEquals(true, MultipartFormDataParser.isMultiPartForm("multipart/form-data")); - Assert.assertEquals(true, MultipartFormDataParser.isMultiPartForm("multipart/form-data;")); - Assert.assertEquals(true, MultipartFormDataParser.isMultiPartForm("multipart/form-data; boundary=----WebKitFormBoundary8OOwv1Xp4c5XkBmD")); + Assert.assertTrue("Failed to identify \"multipart/form-data\"", MultipartFormDataParser.isMultiPartForm("multipart/form-data")); + Assert.assertTrue("Failed to identify \"multipart/form-data\"", MultipartFormDataParser.isMultiPartForm("multipart/form-data;")); + Assert.assertTrue("Failed to identify \"multipart/form-data\"", MultipartFormDataParser.isMultiPartForm("multipart/form-data; boundary=----WebKitFormBoundary8OOwv1Xp4c5XkBmD")); } } From f32e9673af478f8167d65c8efb734afc2cfd37ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Thu, 9 Jul 2015 16:14:50 +0200 Subject: [PATCH 043/256] Fix url presented by JenkinsRule#interactiveBreak --- test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index e1044c4188..7309c8acb5 100644 --- a/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -967,7 +967,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { * This is useful during debugging a test so that one can inspect the state of Hudson through the web browser. */ public void interactiveBreak() throws Exception { - System.out.println("Jenkins is running at http://localhost:"+localPort+"/"); + System.out.println("Jenkins is running at " + getURL()); new BufferedReader(new InputStreamReader(System.in)).readLine(); } From 48b909dbf03b4ab712d474596d3ea4a215209192 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Thu, 9 Jul 2015 16:24:17 +0200 Subject: [PATCH 044/256] [FIXED JENKINS-29300] Display system info even when slave is temporarily offline --- .../slaves/SlaveComputer/systemInfo.jelly | 4 +- .../java/hudson/cli/ComputerStateTest.java | 59 ++++++++++++++++++- 2 files changed, 59 insertions(+), 4 deletions(-) diff --git a/core/src/main/resources/hudson/slaves/SlaveComputer/systemInfo.jelly b/core/src/main/resources/hudson/slaves/SlaveComputer/systemInfo.jelly index f44b0a7269..f9b93b6e8c 100644 --- a/core/src/main/resources/hudson/slaves/SlaveComputer/systemInfo.jelly +++ b/core/src/main/resources/hudson/slaves/SlaveComputer/systemInfo.jelly @@ -44,7 +44,7 @@ THE SOFTWARE. - +

    ${it.oSDescription} slave, version ${it.slaveVersion}

    @@ -59,4 +59,4 @@ THE SOFTWARE. - \ No newline at end of file + diff --git a/test/src/test/java/hudson/cli/ComputerStateTest.java b/test/src/test/java/hudson/cli/ComputerStateTest.java index f726454b6c..6933b12544 100644 --- a/test/src/test/java/hudson/cli/ComputerStateTest.java +++ b/test/src/test/java/hudson/cli/ComputerStateTest.java @@ -25,19 +25,27 @@ package hudson.cli; import static org.junit.Assert.*; import static hudson.cli.CLICommandInvoker.Matcher.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.not; + import jenkins.model.Jenkins; import hudson.cli.CLICommandInvoker.Result; import hudson.model.Computer; import hudson.model.Slave; -import hudson.model.User; -import hudson.security.ACL; +import hudson.slaves.DumbSlave; import hudson.slaves.OfflineCause.UserCause; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.JenkinsRule.WebClient; + +import com.gargoylesoftware.htmlunit.ElementNotFoundException; +import com.gargoylesoftware.htmlunit.html.HtmlPage; /** * @author ogondza @@ -115,4 +123,51 @@ public class ComputerStateTest { assertThat(cause.toString(), endsWith("Custom cause message")); assertThat(cause.getUser(), equalTo(command.user())); } + + @Test + public void testUiForConnected() throws Exception { + DumbSlave slave = j.createOnlineSlave(); + Computer computer = slave.toComputer(); + + WebClient wc = j.createWebClient(); + assertConnected(wc, slave); + + computer.setTemporarilyOffline(true, null); + assertTrue(computer.isTemporarilyOffline()); + assertConnected(wc, slave); + + slave.toComputer().disconnect(null); + + HtmlPage page = wc.getPage(slave); + + assertLinkDoesNotExist(page, "Disconnect"); + + assertLinkDoesNotExist(page, "Script Console"); + HtmlPage script = wc.getPage(slave, "script"); + assertThat(script.getByXPath("//form[@action='script']"), empty()); + + assertLinkDoesNotExist(page, "System Information"); + HtmlPage info = wc.getPage(slave, "systemInfo"); + assertThat(info.asText(), not(containsString("Environment Variables"))); + } + + private void assertConnected(WebClient wc, DumbSlave slave) throws Exception { + HtmlPage main = wc.getPage(slave); + main.getAnchorByText("Disconnect"); + + main.getAnchorByText("Script Console"); + HtmlPage script = wc.getPage(slave, "script"); + assertThat(script.getByXPath("//form[@action='script']"), not(empty())); + + main.getAnchorByText("System Information"); + HtmlPage info = wc.getPage(slave, "systemInfo"); + assertThat(info.asText(), containsString("Environment Variables")); + } + + private void assertLinkDoesNotExist(HtmlPage page, String text) { + try { + page.getAnchorByText(text); + fail(text + " link should not exist"); + } catch (ElementNotFoundException _) { /*expected*/ } + } } From ae2163ac88e2b5953a6cb6dea1fbcebcb477b2db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Fri, 10 Jul 2015 16:13:40 +0200 Subject: [PATCH 045/256] Noting #1761 --- changelog.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.html b/changelog.html index 34170ba965..a16539522b 100644 --- a/changelog.html +++ b/changelog.html @@ -55,7 +55,9 @@ Upcoming changes

    What's new in 1.619 (2015/07/05)

    From fe9756673f8604d11cbe18e414c5578ea869df67 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 12 Jul 2015 18:30:37 -0700 Subject: [PATCH 046/256] [maven-release-plugin] prepare release jenkins-1.620 --- cli/pom.xml | 2 +- core/pom.xml | 2 +- plugins/pom.xml | 10 +++++----- pom.xml | 4 ++-- test/pom.xml | 2 +- war/pom.xml | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cli/pom.xml b/cli/pom.xml index 7e910ffbeb..476680d37b 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.620-SNAPSHOT + 1.620 cli diff --git a/core/pom.xml b/core/pom.xml index 910a474a59..c3fa3629e1 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.620-SNAPSHOT + 1.620 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index 8a9b7915f7..6f45e564d7 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.620-SNAPSHOT + 1.620 pom +

    What's new in 1.620 (2015/07/12)

    • Display system info even when slave is temporarily offline. (issue 29300)
    -

What's new in 1.619 (2015/07/05)

  • From fabec0eef00212109a1ad5c2bedcb8c55de4f38a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Mon, 13 Jul 2015 09:07:30 +0200 Subject: [PATCH 049/256] [FIXED JENKINS-29286] Use byte size to sort disk space monitor columns --- .../node_monitors/DiskSpaceMonitorDescriptor.java | 10 ++++++++++ .../hudson/node_monitors/DiskSpaceMonitor/column.jelly | 4 ++-- .../hudson/node_monitors/SwapSpaceMonitor/column.jelly | 2 +- .../node_monitors/TemporarySpaceMonitor/column.jelly | 4 ++-- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/hudson/node_monitors/DiskSpaceMonitorDescriptor.java b/core/src/main/java/hudson/node_monitors/DiskSpaceMonitorDescriptor.java index 4bd1c939c6..67d33c7227 100644 --- a/core/src/main/java/hudson/node_monitors/DiskSpaceMonitorDescriptor.java +++ b/core/src/main/java/hudson/node_monitors/DiskSpaceMonitorDescriptor.java @@ -37,6 +37,8 @@ import java.math.BigDecimal; import java.text.ParseException; import java.util.Locale; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.DoNotUse; import org.kohsuke.stapler.export.ExportedBean; import org.kohsuke.stapler.export.Exported; @@ -81,6 +83,14 @@ public abstract class DiskSpaceMonitorDescriptor extends AbstractAsyncNodeMonito return path; } + // Needed for jelly that does not seem to be able to access properties + // named 'size' as it confuses it with built-in size method and fails + // to parse the expression expecting '()'. + @Restricted(DoNotUse.class) + public long getFreeSize() { + return size; + } + /** * Gets GB left. */ diff --git a/core/src/main/resources/hudson/node_monitors/DiskSpaceMonitor/column.jelly b/core/src/main/resources/hudson/node_monitors/DiskSpaceMonitor/column.jelly index c71982967e..81a19eb0a9 100644 --- a/core/src/main/resources/hudson/node_monitors/DiskSpaceMonitor/column.jelly +++ b/core/src/main/resources/hudson/node_monitors/DiskSpaceMonitor/column.jelly @@ -29,7 +29,7 @@ THE SOFTWARE. N/A - + - \ No newline at end of file + diff --git a/core/src/main/resources/hudson/node_monitors/SwapSpaceMonitor/column.jelly b/core/src/main/resources/hudson/node_monitors/SwapSpaceMonitor/column.jelly index 5a817a5305..35fa757e79 100644 --- a/core/src/main/resources/hudson/node_monitors/SwapSpaceMonitor/column.jelly +++ b/core/src/main/resources/hudson/node_monitors/SwapSpaceMonitor/column.jelly @@ -32,4 +32,4 @@ THE SOFTWARE. - \ No newline at end of file + diff --git a/core/src/main/resources/hudson/node_monitors/TemporarySpaceMonitor/column.jelly b/core/src/main/resources/hudson/node_monitors/TemporarySpaceMonitor/column.jelly index ac42d83e35..5c1a410d1b 100644 --- a/core/src/main/resources/hudson/node_monitors/TemporarySpaceMonitor/column.jelly +++ b/core/src/main/resources/hudson/node_monitors/TemporarySpaceMonitor/column.jelly @@ -29,7 +29,7 @@ THE SOFTWARE. N/A - + - \ No newline at end of file + From 41ca5b8a36391a95701b794d41faaecb50abef40 Mon Sep 17 00:00:00 2001 From: Michael Prankl Date: Mon, 13 Jul 2015 10:30:34 +0200 Subject: [PATCH 050/256] Use log4j-bridge of slf4j, exclude log4j. --- core/pom.xml | 6 +++--- pom.xml | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index e5059b3e60..61f01681df 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -471,9 +471,9 @@ THE SOFTWARE. commons-logging commons-logging - - log4j - log4j + + org.slf4j + log4j-over-slf4j com.sun.xml.txw2 diff --git a/pom.xml b/pom.xml index 359bdadf9c..aa89332435 100644 --- a/pom.xml +++ b/pom.xml @@ -213,16 +213,16 @@ THE SOFTWARE. jcl-over-slf4j ${slf4jVersion} + + org.slf4j + log4j-over-slf4j + ${slf4jVersion} + commons-logging commons-logging 1.1.3 - - log4j - log4j - 1.2.17 - org.samba.jcifs jcifs From 1c1d5a95d9d5aa86b5ae890942553fbcb0f1a641 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Mon, 13 Jul 2015 10:34:47 +0200 Subject: [PATCH 051/256] [FIXED JENKINS-29376] Rename help texts as well Amends eec43983a3bdfce6de45ca0559d8a9f8a1250b71. --- .../{help-assignedLabelString.html => help-label.html} | 0 ...{help-assignedLabelString_zh_TW.html => help-label_zh_TW.html} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename core/src/main/resources/hudson/model/AbstractProject/{help-assignedLabelString.html => help-label.html} (100%) rename core/src/main/resources/hudson/model/AbstractProject/{help-assignedLabelString_zh_TW.html => help-label_zh_TW.html} (100%) diff --git a/core/src/main/resources/hudson/model/AbstractProject/help-assignedLabelString.html b/core/src/main/resources/hudson/model/AbstractProject/help-label.html similarity index 100% rename from core/src/main/resources/hudson/model/AbstractProject/help-assignedLabelString.html rename to core/src/main/resources/hudson/model/AbstractProject/help-label.html diff --git a/core/src/main/resources/hudson/model/AbstractProject/help-assignedLabelString_zh_TW.html b/core/src/main/resources/hudson/model/AbstractProject/help-label_zh_TW.html similarity index 100% rename from core/src/main/resources/hudson/model/AbstractProject/help-assignedLabelString_zh_TW.html rename to core/src/main/resources/hudson/model/AbstractProject/help-label_zh_TW.html From 316b32e07b34946f6759a45b88a0f22f269e824f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Tue, 14 Jul 2015 10:08:59 +0200 Subject: [PATCH 052/256] Noting #1763 and #1764 --- changelog.html | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/changelog.html b/changelog.html index 74d5d2495a..105caf499d 100644 --- a/changelog.html +++ b/changelog.html @@ -55,7 +55,12 @@ Upcoming changes

    What's new in 1.620 (2015/07/12)

    From aac20468ff5511ea6c58de07f3bcf3ae108b9cb0 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Tue, 14 Jul 2015 15:22:15 +0100 Subject: [PATCH 053/256] [FIXED JENKINS-28844] The curious case of the Channel memory cycles Pick up the remoting 2.52 release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 359bdadf9c..0394379690 100644 --- a/pom.xml +++ b/pom.xml @@ -177,7 +177,7 @@ THE SOFTWARE. org.jenkins-ci.main remoting - 2.51 + 2.52 From 3a527b24fc6ad527aa9dd297554150ba2ff8994d Mon Sep 17 00:00:00 2001 From: Michael Prankl Date: Tue, 14 Jul 2015 19:02:58 +0200 Subject: [PATCH 054/256] Added log4j to banned dependencies via maven-enforcer-plugin. --- pom.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/pom.xml b/pom.xml index aa89332435..511ed73147 100644 --- a/pom.xml +++ b/pom.xml @@ -663,6 +663,7 @@ THE SOFTWARE. org.sonatype.sisu:sisu-guice + log4j:log4j From 1edb51cb919a3270b26e8782a0426381385df9b9 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Thu, 16 Jul 2015 13:15:31 +0100 Subject: [PATCH 055/256] [JENKINS-28844] Noting merge of #1766 --- changelog.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.html b/changelog.html index 105caf499d..2d0f6de0f9 100644 --- a/changelog.html +++ b/changelog.html @@ -61,6 +61,9 @@ Upcoming changes
  • Label expression help is missing in recent Jenkins versions. (issue 29376) +
  • + Pre-emtively break memory cycles causing excessive live-set retention in remoting later by upgrading to remoting 2.52. + (issue 29376)
  • - Pre-emtively break memory cycles causing excessive live-set retention in remoting later by upgrading to remoting 2.52. - (issue 28844) +
  • + Don't run trigger for disabled/copied projects. + (PR 1617)

What's new in 1.620 (2015/07/12)

From 2a75ca1ffe0df0035024cb221381a66bb6dcf61c Mon Sep 17 00:00:00 2001 From: Peter Marcoen Date: Fri, 17 Jul 2015 14:01:57 +0200 Subject: [PATCH 057/256] [FIXED JENKINS-2327] Do not display 'No changes' if changelog calculation is still in progress --- .../hudson/model/AbstractBuild/changes.jelly | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/core/src/main/resources/hudson/model/AbstractBuild/changes.jelly b/core/src/main/resources/hudson/model/AbstractBuild/changes.jelly index 8b357557ff..f030f796e3 100644 --- a/core/src/main/resources/hudson/model/AbstractBuild/changes.jelly +++ b/core/src/main/resources/hudson/model/AbstractBuild/changes.jelly @@ -31,7 +31,17 @@ THE SOFTWARE. ${%Changes} - + + + + + + ${%Not yet determined} + + + ${%Failed to determine} (${%log}) + + From 669f94f4c31bb6676b79c5786d387391c2420e03 Mon Sep 17 00:00:00 2001 From: Eito Katagiri Date: Sat, 18 Jul 2015 01:59:13 +0900 Subject: [PATCH 058/256] Fix typo --- core/src/main/java/hudson/model/RunMap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/RunMap.java b/core/src/main/java/hudson/model/RunMap.java index 2eb65a2fb3..1f923e0910 100644 --- a/core/src/main/java/hudson/model/RunMap.java +++ b/core/src/main/java/hudson/model/RunMap.java @@ -186,7 +186,7 @@ public final class RunMap> extends AbstractLazyLoadRunMap // Defense against JENKINS-23152 and its ilk. File rootDir = r.getRootDir(); if (rootDir.isDirectory()) { - throw new IllegalStateException(rootDir + " already existed; will not overwite with " + r); + throw new IllegalStateException(rootDir + " already existed; will not overwrite with " + r); } if (!r.getClass().getName().equals("hudson.matrix.MatrixRun")) { // JENKINS-26739: grandfathered in proposeNewNumber(r.getNumber()); From 0cc691578cfa0abb3fbb0c3173ac5ddb15e455ed Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 19 Jul 2015 11:43:58 -0700 Subject: [PATCH 059/256] [maven-release-plugin] prepare release jenkins-1.621 --- cli/pom.xml | 2 +- core/pom.xml | 2 +- plugins/pom.xml | 10 +++++----- pom.xml | 4 ++-- test/pom.xml | 2 +- war/pom.xml | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cli/pom.xml b/cli/pom.xml index 200a5e0b44..c4b1a6026d 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.621-SNAPSHOT + 1.621 cli diff --git a/core/pom.xml b/core/pom.xml index e5059b3e60..4e06870330 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.621-SNAPSHOT + 1.621 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index 052b8ba72e..fda9fb0c43 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.621-SNAPSHOT + 1.621 pom +

What's new in 1.621 (2015/07/19)

  • Sort by 'Free Disk Space' is incorrect. @@ -68,7 +73,6 @@ Upcoming changes Don't run trigger for disabled/copied projects. (PR 1617)
-

What's new in 1.620 (2015/07/12)

  • From 05c6e66f0767347604b51cb02190882cca77ad6b Mon Sep 17 00:00:00 2001 From: Craig Rodrigues Date: Mon, 20 Jul 2015 13:07:51 -0400 Subject: [PATCH 062/256] akuma 1.10 adds support for FreeBSD --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index e5059b3e60..e564d3bef1 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -513,7 +513,7 @@ THE SOFTWARE. org.kohsuke akuma - 1.9 + 1.10 org.kohsuke From 252e1296099e838b8fba52221910442e0a757db4 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Wed, 22 Jul 2015 10:34:37 +0100 Subject: [PATCH 063/256] The call to PlannedNode.spent() *must* always occur - They have been removed from the pendingLaunches, so once we leave this method we have no reference to them - Arguably the call to spent should take place when removing from the pendingLaunches, but that would change the method contract --- core/src/main/java/hudson/slaves/NodeProvisioner.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/hudson/slaves/NodeProvisioner.java b/core/src/main/java/hudson/slaves/NodeProvisioner.java index bf326d7956..b24822e2f9 100644 --- a/core/src/main/java/hudson/slaves/NodeProvisioner.java +++ b/core/src/main/java/hudson/slaves/NodeProvisioner.java @@ -250,9 +250,9 @@ public class NodeProvisioner { for (CloudProvisioningListener cl : CloudProvisioningListener.all()) { cl.onFailure(f, e); } + } finally { + f.spent(); } - - f.spent(); } float plannedCapacity = plannedCapacitySnapshot; From 44d1d2b75fd4df1ab93ee33648ba645a0d4a3680 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 22 Jul 2015 09:39:10 -0400 Subject: [PATCH 064/256] Offering new convenience methods in ParameterizedJobMixIn. --- .../jenkins/model/ParameterizedJobMixIn.java | 54 ++++++++++++++++--- .../jenkins/triggers/ReverseBuildTrigger.java | 14 ++--- 2 files changed, 53 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java b/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java index 1fff85ec12..e998e3f6c5 100644 --- a/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java +++ b/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java @@ -94,17 +94,39 @@ public abstract class ParameterizedJobMixIn & Param } /** - * Convenience method to schedule a build with the ability to wait for its result. - * Often used during functional tests ({@code JenkinsRule.assertBuildStatusSuccess}). + * Provides a standard implementation of an optional method of the same name in a {@link Job} type to schedule a build with the ability to wait for its result. + * That job method is often used during functional tests ({@code JenkinsRule.assertBuildStatusSuccess}). * @param quietPeriod seconds to wait before starting (normally 0) * @param actions various actions to associate with the scheduling, such as {@link ParametersAction} or {@link CauseAction} * @return a handle by which you may wait for the build to complete (or just start); or null if the build was not actually scheduled for some reason */ public final @CheckForNull QueueTaskFuture scheduleBuild2(int quietPeriod, Action... actions) { - return scheduleBuild2(quietPeriod, Arrays.asList(actions)); + Queue.Item i = scheduleBuild2(quietPeriod, Arrays.asList(actions)); + return i != null ? (QueueTaskFuture) i.getFuture() : null; } - private @CheckForNull QueueTaskFuture scheduleBuild2(int quietPeriod, List actions) { + /** + * Convenience method to schedule a build. + * Useful for {@link Trigger} implementations, for example. + * If you need to wait for the build to start (or finish), use {@link Queue.Item#getFuture}. + * @param job a job which might be schedulable + * @param quietPeriod seconds to wait before starting; use {@code -1} to use the job’s default settings + * @param actions various actions to associate with the scheduling, such as {@link ParametersAction} or {@link CauseAction} + * @return a newly created, or reused, queue item if the job could be scheduled; null if it was refused for some reason (e.g., some {@link Queue.QueueDecisionHandler} rejected it), or if {@code job} is not a {@link ParameterizedJob} or it is not {@link Job#isBuildable}) + * @since TODO + */ + public static @CheckForNull Queue.Item scheduleBuild2(final Job job, int quietPeriod, Action... actions) { + if (!(job instanceof ParameterizedJob)) { + return null; + } + return new ParameterizedJobMixIn() { + @Override protected Job asJob() { + return job; + } + }.scheduleBuild2(quietPeriod == -1 ? ((ParameterizedJob) job).getQuietPeriod() : quietPeriod, Arrays.asList(actions)); + } + + @CheckForNull Queue.Item scheduleBuild2(int quietPeriod, List actions) { if (!asJob().isBuildable()) return null; @@ -112,8 +134,7 @@ public abstract class ParameterizedJobMixIn & Param if (isParameterized() && Util.filter(queueActions, ParametersAction.class).isEmpty()) { queueActions.add(new ParametersAction(getDefaultParametersValues())); } - Queue.Item i = Jenkins.getInstance().getQueue().schedule2(asJob(), quietPeriod, queueActions).getItem(); - return i != null ? (QueueTaskFuture) i.getFuture() : null; + return Jenkins.getInstance().getQueue().schedule2(asJob(), quietPeriod, queueActions).getItem(); } private List getDefaultParametersValues() { @@ -249,6 +270,26 @@ public abstract class ParameterizedJobMixIn & Param return isParameterized() ? hudson.model.Messages.AbstractProject_build_with_parameters() : hudson.model.Messages.AbstractProject_BuildNow(); } + /** + * Checks for the existence of a specific trigger on a job. + * @param a trigger type + * @param job a job + * @param clazz the type of the trigger + * @return a configured trigger of the requested type, or null if there is none such, or {@code job} is not a {@link ParameterizedJob} + * @since TODO + */ + public static @CheckForNull > T getTrigger(Job job, Class clazz) { + if (!(job instanceof ParameterizedJob)) { + return null; + } + for (Trigger t : ((ParameterizedJob) job).getTriggers().values()) { + if (clazz.isInstance(t)) { + return clazz.cast(t); + } + } + return null; + } + /** * Marker for job using this mixin. */ @@ -265,6 +306,7 @@ public abstract class ParameterizedJobMixIn & Param * Gets currently configured triggers. * You may use {@code } to configure them. * @return a map from trigger kind to instance + * @see #getTrigger */ Map> getTriggers(); diff --git a/core/src/main/java/jenkins/triggers/ReverseBuildTrigger.java b/core/src/main/java/jenkins/triggers/ReverseBuildTrigger.java index be6078eb51..8ff41f838a 100644 --- a/core/src/main/java/jenkins/triggers/ReverseBuildTrigger.java +++ b/core/src/main/java/jenkins/triggers/ReverseBuildTrigger.java @@ -32,6 +32,7 @@ import hudson.model.AbstractProject; import hudson.model.Action; import hudson.model.AutoCompletionCandidates; import hudson.model.Cause; +import hudson.model.CauseAction; import hudson.model.DependencyGraph; import hudson.model.Item; import hudson.model.ItemGroup; @@ -237,11 +238,7 @@ public final class ReverseBuildTrigger extends Trigger implements Dependenc continue; } String name = ModelHyperlinkNote.encodeTo(trigger.job) + " #" + trigger.job.getNextBuildNumber(); - if (new ParameterizedJobMixIn() { - @Override protected Job asJob() { - return trigger.job; - } - }.scheduleBuild(new Cause.UpstreamCause(r))) { + if (ParameterizedJobMixIn.scheduleBuild2(trigger.job, -1, new CauseAction(new Cause.UpstreamCause(r))) != null) { listener.getLogger().println(hudson.tasks.Messages.BuildTrigger_Triggering(name)); } else { listener.getLogger().println(hudson.tasks.Messages.BuildTrigger_InQueue(name)); @@ -257,10 +254,9 @@ public final class ReverseBuildTrigger extends Trigger implements Dependenc if (jenkins == null) { return; } - for (ParameterizedJobMixIn.ParameterizedJob p : jenkins.getAllItems(ParameterizedJobMixIn.ParameterizedJob.class)) { - Trigger _t = p.getTriggers().get(jenkins.getDescriptorByType(DescriptorImpl.class)); - if (_t instanceof ReverseBuildTrigger) { - ReverseBuildTrigger t = (ReverseBuildTrigger) _t; + for (Job p : jenkins.getAllItems(Job.class)) { + ReverseBuildTrigger t = ParameterizedJobMixIn.getTrigger(p, ReverseBuildTrigger.class); + if (t != null) { String revised = Items.computeRelativeNamesAfterRenaming(oldFullName, newFullName, t.upstreamProjects, p.getParent()); if (!revised.equals(t.upstreamProjects)) { t.upstreamProjects = revised; From 4ece8c06aa80e05edad876ad1b7d93e55995cbd5 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Wed, 22 Jul 2015 18:03:54 -0700 Subject: [PATCH 065/256] Added a test case to verify the behaviour of rowSet ... as a control case in the master branch to ensure the changes in the config-ui-changes do not break its behaviour. --- test/src/test/java/lib/form/RowSetTest.java | 53 +++++++++++++++ .../lib/form/RowSetTest/Subject/test1.jelly | 68 +++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 test/src/test/java/lib/form/RowSetTest.java create mode 100644 test/src/test/resources/lib/form/RowSetTest/Subject/test1.jelly diff --git a/test/src/test/java/lib/form/RowSetTest.java b/test/src/test/java/lib/form/RowSetTest.java new file mode 100644 index 0000000000..8a8fdb0aa9 --- /dev/null +++ b/test/src/test/java/lib/form/RowSetTest.java @@ -0,0 +1,53 @@ +package lib.form; + +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import hudson.model.RootAction; +import junit.framework.Assert; +import net.sf.json.JSONObject; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.TestExtension; +import org.kohsuke.stapler.StaplerRequest; + +/** + * @author Kohsuke Kawaguchi + */ +public class RowSetTest { + @Rule + public JenkinsRule j = new JenkinsRule(); + + @Test + public void json() throws Exception { + HtmlPage p = j.createWebClient().goTo("test/test1"); + j.submit(p.getFormByName("config")); + } + + @TestExtension + public static class Subject implements RootAction { + public void doSubmitTest1(StaplerRequest req) throws Exception { + JSONObject json = req.getSubmittedForm(); + json.remove("crumb"); + System.out.println(json); + + JSONObject expected = JSONObject.fromObject( + "{'a':'aaa','b':'bbb','c':{'c1':'ccc1','c2':'ccc2'},'d':{'d1':'d1','d2':'d2'}}"); + Assert.assertEquals(json,expected); + } + + @Override + public String getIconFileName() { + return null; + } + + @Override + public String getDisplayName() { + return null; + } + + @Override + public String getUrlName() { + return "test"; + } + } +} diff --git a/test/src/test/resources/lib/form/RowSetTest/Subject/test1.jelly b/test/src/test/resources/lib/form/RowSetTest/Subject/test1.jelly new file mode 100644 index 0000000000..f77f6249a5 --- /dev/null +++ b/test/src/test/resources/lib/form/RowSetTest/Subject/test1.jelly @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 4f0ca16b01abcd5ac84a9259736c2d96b1712354 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Thu, 23 Jul 2015 09:07:52 +0100 Subject: [PATCH 066/256] [FIXED JENKINS-29568] A better fix - 252e1296099e838b8fba52221910442e0a757db4 doesn't work for all cases as there are code paths where a pending launch can be removed from the pending list and not have spent() called. - There was no reason for iterating the list twice anyway, as all of this takes place with the locks held - My notifying each one as we process, if there is an Error, we will not leave any stranded. The next run through, if there is one, will cover those instances. --- .../java/hudson/slaves/NodeProvisioner.java | 68 ++++++++++--------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/core/src/main/java/hudson/slaves/NodeProvisioner.java b/core/src/main/java/hudson/slaves/NodeProvisioner.java index b24822e2f9..af8e7c513e 100644 --- a/core/src/main/java/hudson/slaves/NodeProvisioner.java +++ b/core/src/main/java/hudson/slaves/NodeProvisioner.java @@ -213,48 +213,50 @@ public class NodeProvisioner { // bring up. int plannedCapacitySnapshot = 0; - List completedLaunches = new ArrayList(); for (Iterator itr = pendingLaunches.iterator(); itr.hasNext(); ) { PlannedNode f = itr.next(); if (f.future.isDone()) { - completedLaunches.add(f); - itr.remove(); + try { + Node node = f.future.get(); + for (CloudProvisioningListener cl : CloudProvisioningListener.all()) { + cl.onComplete(f, node); + } + + jenkins.addNode(node); + LOGGER.log(Level.INFO, + "{0} provisioning successfully completed. " + + "We have now {1,number,integer} computer(s)", + new Object[]{f.displayName, jenkins.getComputers().length}); + } catch (InterruptedException e) { + throw new AssertionError(e); // since we confirmed that the future is already done + } catch (ExecutionException e) { + LOGGER.log(Level.WARNING, "Provisioned slave " + f.displayName + " failed to launch", + e.getCause()); + for (CloudProvisioningListener cl : CloudProvisioningListener.all()) { + cl.onFailure(f, e.getCause()); + } + } catch (IOException e) { + LOGGER.log(Level.WARNING, "Provisioned slave " + f.displayName + " failed to launch", + e); + for (CloudProvisioningListener cl : CloudProvisioningListener.all()) { + cl.onFailure(f, e); + } + } catch (Error e) { + // we are not supposed to try and recover from Errors + throw e; + } catch (Throwable e) { + LOGGER.log(Level.SEVERE, "Unexpected uncaught exception encountered while " + + "processing provisioned slave " + f.displayName, e); + } finally { + itr.remove(); + f.spent(); + } } else { plannedCapacitySnapshot += f.numExecutors; } } - for (PlannedNode f : completedLaunches) { - try { - Node node = f.future.get(); - for (CloudProvisioningListener cl : CloudProvisioningListener.all()) { - cl.onComplete(f, node); - } - - jenkins.addNode(node); - LOGGER.log(Level.INFO, - "{0} provisioning successfully completed. We have now {1,number,integer} computer" - + "(s)", - new Object[]{f.displayName, jenkins.getComputers().length}); - } catch (InterruptedException e) { - throw new AssertionError(e); // since we confirmed that the future is already done - } catch (ExecutionException e) { - LOGGER.log(Level.WARNING, "Provisioned slave " + f.displayName + " failed to launch", - e.getCause()); - for (CloudProvisioningListener cl : CloudProvisioningListener.all()) { - cl.onFailure(f, e.getCause()); - } - } catch (IOException e) { - LOGGER.log(Level.WARNING, "Provisioned slave " + f.displayName + " failed to launch", e); - for (CloudProvisioningListener cl : CloudProvisioningListener.all()) { - cl.onFailure(f, e); - } - } finally { - f.spent(); - } - } - float plannedCapacity = plannedCapacitySnapshot; plannedCapacitiesEMA.update(plannedCapacity); From 90f29f8cbc68312cbdbef8d4101fa5b5e971e021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Thu, 23 Jul 2015 16:35:45 +0200 Subject: [PATCH 067/256] Null safety for hudson.model.Result --- core/src/main/java/hudson/model/Result.java | 44 ++++++++++++--------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/hudson/model/Result.java b/core/src/main/java/hudson/model/Result.java index b17a98a4cf..02e71f3ff3 100644 --- a/core/src/main/java/hudson/model/Result.java +++ b/core/src/main/java/hudson/model/Result.java @@ -25,9 +25,11 @@ package hudson.model; import com.thoughtworks.xstream.converters.SingleValueConverter; import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; + import hudson.cli.declarative.OptionHandlerExtension; import hudson.init.Initializer; import hudson.util.EditDistance; + import org.apache.commons.beanutils.Converter; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; @@ -40,6 +42,9 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; + /** * The build outcome. * @@ -49,42 +54,42 @@ public final class Result implements Serializable, CustomExportedBean { /** * The build had no errors. */ - public static final Result SUCCESS = new Result("SUCCESS",BallColor.BLUE,0,true); + public static final @Nonnull Result SUCCESS = new Result("SUCCESS",BallColor.BLUE,0,true); /** * The build had some errors but they were not fatal. * For example, some tests failed. */ - public static final Result UNSTABLE = new Result("UNSTABLE",BallColor.YELLOW,1,true); + public static final @Nonnull Result UNSTABLE = new Result("UNSTABLE",BallColor.YELLOW,1,true); /** * The build had a fatal error. */ - public static final Result FAILURE = new Result("FAILURE",BallColor.RED,2,true); + public static final @Nonnull Result FAILURE = new Result("FAILURE",BallColor.RED,2,true); /** * The module was not built. *

    * This status code is used in a multi-stage build (like maven2) * where a problem in earlier stage prevented later stages from building. */ - public static final Result NOT_BUILT = new Result("NOT_BUILT",BallColor.NOTBUILT,3,false); + public static final @Nonnull Result NOT_BUILT = new Result("NOT_BUILT",BallColor.NOTBUILT,3,false); /** * The build was manually aborted. * * If you are catching {@link InterruptedException} and interpreting it as {@link #ABORTED}, * you should check {@link Executor#abortResult()} instead (starting 1.417.) */ - public static final Result ABORTED = new Result("ABORTED",BallColor.ABORTED,4,false); + public static final @Nonnull Result ABORTED = new Result("ABORTED",BallColor.ABORTED,4,false); - private final String name; + private final @Nonnull String name; /** * Bigger numbers are worse. */ - public final int ordinal; + public final @Nonnegative int ordinal; /** * Default ball color for this status. */ - public final BallColor color; + public final @Nonnull BallColor color; /** * Is this a complete build - i.e. did it run to the end (not aborted)? @@ -92,7 +97,7 @@ public final class Result implements Serializable, CustomExportedBean { */ public final boolean completeBuild; - private Result(String name, BallColor color, int ordinal, boolean complete) { + private Result(@Nonnull String name, @Nonnull BallColor color, @Nonnegative int ordinal, boolean complete) { this.name = name; this.color = color; this.ordinal = ordinal; @@ -102,26 +107,26 @@ public final class Result implements Serializable, CustomExportedBean { /** * Combines two {@link Result}s and returns the worse one. */ - public Result combine(Result that) { + public @Nonnull Result combine(@Nonnull Result that) { if(this.ordinal < that.ordinal) return that; else return this; } - public boolean isWorseThan(Result that) { + public boolean isWorseThan(@Nonnull Result that) { return this.ordinal > that.ordinal; } - public boolean isWorseOrEqualTo(Result that) { + public boolean isWorseOrEqualTo(@Nonnull Result that) { return this.ordinal >= that.ordinal; } - public boolean isBetterThan(Result that) { + public boolean isBetterThan(@Nonnull Result that) { return this.ordinal < that.ordinal; } - public boolean isBetterOrEqualTo(Result that) { + public boolean isBetterOrEqualTo(@Nonnull Result that) { return this.ordinal <= that.ordinal; } @@ -133,24 +138,23 @@ public final class Result implements Serializable, CustomExportedBean { return this.completeBuild; } - @Override - public String toString() { + public @Nonnull String toString() { return name; } - public String toExportedObject() { + public @Nonnull String toExportedObject() { return name; } - public static Result fromString(String s) { + public static @Nonnull Result fromString(@Nonnull String s) { for (Result r : all) if (s.equalsIgnoreCase(r.name)) return r; return FAILURE; } - private static List getNames() { + private static @Nonnull List getNames() { List l = new ArrayList(); for (Result r : all) l.add(r.name); @@ -170,10 +174,12 @@ public final class Result implements Serializable, CustomExportedBean { private static final Result[] all = new Result[] {SUCCESS,UNSTABLE,FAILURE,NOT_BUILT,ABORTED}; public static final SingleValueConverter conv = new AbstractSingleValueConverter () { + @Override public boolean canConvert(Class clazz) { return clazz==Result.class; } + @Override public Object fromString(String s) { return Result.fromString(s); } From e82f0094a01c45f63046cd340056963c2028aa46 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 26 Jul 2015 21:39:18 -0700 Subject: [PATCH 068/256] [maven-release-plugin] prepare release jenkins-1.622 --- cli/pom.xml | 2 +- core/pom.xml | 2 +- plugins/pom.xml | 10 +++++----- pom.xml | 4 ++-- test/pom.xml | 2 +- war/pom.xml | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cli/pom.xml b/cli/pom.xml index eb0b4e5112..edd880670e 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.622-SNAPSHOT + 1.622 cli diff --git a/core/pom.xml b/core/pom.xml index 8a213000f5..fc630d2e42 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.622-SNAPSHOT + 1.622 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index 8b8dca065b..94bff18620 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.622-SNAPSHOT + 1.622 pom +

    What's new in 1.622 (2015/07/27)

    +
      +
    • +

    What's new in 1.621 (2015/07/19)

    • From 1598a464ff7973cbe6d3d6aa2493085a4a0646ec Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Wed, 29 Jul 2015 15:35:09 +0200 Subject: [PATCH 071/256] Noting #1770 in 1.622, JENKINS-29568 --- changelog.html | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/changelog.html b/changelog.html index 6a1c2e3812..2fad9450e4 100644 --- a/changelog.html +++ b/changelog.html @@ -60,7 +60,12 @@ Upcoming changes

What's new in 1.622 (2015/07/27)

    -
  • +
  • + Jenkins now support self-restart and daemonization in FreeBSD + (PR 1770) +
  • + Node provisioner may fail to correctly indicate that provisioning was finished. + (JENKINS-29568)

What's new in 1.621 (2015/07/19)

    @@ -76,9 +81,6 @@ Upcoming changes
  • Don't run trigger for disabled/copied projects. (PR 1617) -
  • - Jenkins now support self-restart and daemonization in FreeBSD - (PR 1770)

What's new in 1.620 (2015/07/12)

    From db559bd6f5f611c588e127ff20852c81f45bc989 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 30 Jul 2015 16:28:12 -0400 Subject: [PATCH 072/256] =?UTF-8?q?Reduce=20logging=20level=20of=20?= =?UTF-8?q?=E2=80=9Cqueue=20length=20is=20less=20than=20the=20available=20?= =?UTF-8?q?capacity=E2=80=9D=20message.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/main/java/hudson/slaves/NodeProvisioner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/slaves/NodeProvisioner.java b/core/src/main/java/hudson/slaves/NodeProvisioner.java index b24822e2f9..bc34f9662a 100644 --- a/core/src/main/java/hudson/slaves/NodeProvisioner.java +++ b/core/src/main/java/hudson/slaves/NodeProvisioner.java @@ -264,7 +264,7 @@ public class NodeProvisioner { int queueLengthSnapshot = snapshot.getQueueLength(); if (queueLengthSnapshot <= availableSnapshot) { - LOGGER.log(Level.FINE, + LOGGER.log(Level.FINER, "Queue length {0} is less than the available capacity {1}. No provisioning strategy required", new Object[]{queueLengthSnapshot, availableSnapshot}); provisioningState = null; From 98c8caf51b5107ce59963a4f1df37f7eadfa000b Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Fri, 31 Jul 2015 07:03:24 -0400 Subject: [PATCH 073/256] Revert "Adding another cause" This reverts commit 68b383e0b2cdd2b1403a13a4284dc1a2d3e03e12. --- .../jenkins/model/CauseOfInterruption.java | 29 +------------------ .../ExceptionInterruption/summary.groovy | 5 ---- 2 files changed, 1 insertion(+), 33 deletions(-) delete mode 100644 core/src/main/resources/jenkins/model/CauseOfInterruption/ExceptionInterruption/summary.groovy diff --git a/core/src/main/java/jenkins/model/CauseOfInterruption.java b/core/src/main/java/jenkins/model/CauseOfInterruption.java index d733ffe33e..dbec0221ac 100644 --- a/core/src/main/java/jenkins/model/CauseOfInterruption.java +++ b/core/src/main/java/jenkins/model/CauseOfInterruption.java @@ -70,7 +70,7 @@ public abstract class CauseOfInterruption implements Serializable { } /** - * Indicates that the build was interrupted from UI by an user. + * Indicates that the build was interrupted from UI. */ public static final class UserInterruption extends CauseOfInterruption { private final String user; @@ -112,32 +112,5 @@ public abstract class CauseOfInterruption implements Serializable { private static final long serialVersionUID = 1L; } - /** - * Indicates that the build was interrupted as a result of another a problem. - * - *

    - * This is a less specific (thus less desirable) {@link CauseOfInterruption} - * in case there's no suitable {@link CauseOfInterruption}. Use sparingly. - */ - class ExceptionInterruption extends CauseOfInterruption { - private final Throwable cause; - - public ExceptionInterruption(Throwable cause) { - this.cause = cause; - } - - public Throwable getCause() { - return cause; - } - - @Override - public String getShortDescription() { - return "Exception: "+ cause.getMessage(); - } - - private static final long serialVersionUID = 1L; - } - - private static final long serialVersionUID = 1L; } diff --git a/core/src/main/resources/jenkins/model/CauseOfInterruption/ExceptionInterruption/summary.groovy b/core/src/main/resources/jenkins/model/CauseOfInterruption/ExceptionInterruption/summary.groovy deleted file mode 100644 index bcc6ce1492..0000000000 --- a/core/src/main/resources/jenkins/model/CauseOfInterruption/ExceptionInterruption/summary.groovy +++ /dev/null @@ -1,5 +0,0 @@ -package jenkins.model.CauseOfInterruption.ExceptionInterruption - -import hudson.util.FormValidation; - -raw(FormValidation.error(my.cause, my.cause.message).renderHtml()); From 3f7875c1509ee6d062891ac3904ce46ca6162fe5 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Fri, 31 Jul 2015 17:25:45 -0400 Subject: [PATCH 074/256] [FIXED JENKINS-26147] Move BUILD_NOW_TEXT to ParameterizedJobMixIn. --- .../java/hudson/model/AbstractProject.java | 4 +++- .../jenkins/model/ParameterizedJobMixIn.java | 12 ++++++++-- .../util/AlternativeUiTextProviderTest.java | 22 ++++++++++++------- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java index 319f355fd5..24a3529cd5 100644 --- a/core/src/main/java/hudson/model/AbstractProject.java +++ b/core/src/main/java/hudson/model/AbstractProject.java @@ -473,6 +473,7 @@ public abstract class AbstractProject

    ,R extends A * @since 1.401 */ public String getBuildNowText() { + // For compatibility, still use the deprecated replacer if specified. return AlternativeUiTextProvider.get(BUILD_NOW_TEXT, this, getParameterizedJobMixIn().getBuildNowText()); } @@ -2243,8 +2244,9 @@ public abstract class AbstractProject

    ,R extends A public static final Permission ABORT = CANCEL; /** - * Replaceable "Build Now" text. + * @deprecated Use {@link ParameterizedJobMixIn#BUILD_NOW_TEXT}. */ + @Deprecated public static final Message BUILD_NOW_TEXT = new Message(); /** diff --git a/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java b/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java index 020040f116..3bb7c665ce 100644 --- a/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java +++ b/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java @@ -41,6 +41,7 @@ import hudson.model.queue.QueueTaskFuture; import hudson.search.SearchIndexBuilder; import hudson.triggers.Trigger; import hudson.triggers.TriggerDescriptor; +import hudson.util.AlternativeUiTextProvider; import hudson.views.BuildButtonColumn; import java.io.IOException; import java.util.ArrayList; @@ -261,13 +262,20 @@ public abstract class ParameterizedJobMixIn & Param return new CauseAction(cause); } + /** + * Allows customization of the human-readable display name to be rendered in the Build Now link. + * @see #getBuildNowText + * @since TODO + */ + public static final AlternativeUiTextProvider.Message BUILD_NOW_TEXT = new AlternativeUiTextProvider.Message(); + /** * Suggested implementation of {@link ParameterizedJob#getBuildNowText}. + * Uses {@link #BUILD_NOW_TEXT}. */ public final String getBuildNowText() { - // TODO JENKINS-26147 use replacement for AbstractProject.BUILD_NOW_TEXT // TODO move these messages (& translations) to this package - return isParameterized() ? hudson.model.Messages.AbstractProject_build_with_parameters() : hudson.model.Messages.AbstractProject_BuildNow(); + return isParameterized() ? hudson.model.Messages.AbstractProject_build_with_parameters() : AlternativeUiTextProvider.get(BUILD_NOW_TEXT, asJob(), hudson.model.Messages.AbstractProject_BuildNow()); } /** diff --git a/test/src/test/java/hudson/util/AlternativeUiTextProviderTest.java b/test/src/test/java/hudson/util/AlternativeUiTextProviderTest.java index ecb0ba3ecb..8146f05744 100644 --- a/test/src/test/java/hudson/util/AlternativeUiTextProviderTest.java +++ b/test/src/test/java/hudson/util/AlternativeUiTextProviderTest.java @@ -23,18 +23,16 @@ */ package hudson.util; -import static org.junit.Assert.assertTrue; - import hudson.model.AbstractProject; import hudson.model.FreeStyleProject; +import jenkins.model.ParameterizedJobMixIn; +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertThat; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.TestExtension; -/** - * @author Kohsuke Kawaguchi - */ public class AlternativeUiTextProviderTest { @Rule @@ -42,9 +40,15 @@ public class AlternativeUiTextProviderTest { @TestExtension public static class Impl extends AlternativeUiTextProvider { + static boolean oldschool; + @SuppressWarnings("deprecation") @Override public String getText(Message text, T context) { - if (text==AbstractProject.BUILD_NOW_TEXT) - return "XYZ:"+AbstractProject.BUILD_NOW_TEXT.cast(context).getDisplayName(); + if (oldschool && text == ParameterizedJobMixIn.BUILD_NOW_TEXT) { + return "oldschool:" + ParameterizedJobMixIn.BUILD_NOW_TEXT.cast(context).getDisplayName(); + } + if (!oldschool && text == AbstractProject.BUILD_NOW_TEXT) { + return "newschool:" + AbstractProject.BUILD_NOW_TEXT.cast(context).getDisplayName(); + } return null; } } @@ -55,6 +59,8 @@ public class AlternativeUiTextProviderTest { @Test public void basics() throws Exception { FreeStyleProject p = j.createFreeStyleProject("aaa"); - assertTrue(j.createWebClient().getPage(p).asText().contains("XYZ:aaa")); + assertThat(j.createWebClient().getPage(p).asText(), containsString("newschool:aaa")); + Impl.oldschool = true; + assertThat(j.createWebClient().getPage(p).asText(), containsString("oldschool:aaa")); } } From 6bf099d322ae5e9adb777f2b12653a60fb38ae9a Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Fri, 31 Jul 2015 17:37:43 -0400 Subject: [PATCH 075/256] Moving some messages to the natural package. --- core/src/main/java/jenkins/model/ParameterizedJobMixIn.java | 3 +-- core/src/main/resources/hudson/model/Messages.properties | 2 -- core/src/main/resources/hudson/model/Messages_ca.properties | 1 - core/src/main/resources/hudson/model/Messages_da.properties | 1 - core/src/main/resources/hudson/model/Messages_de.properties | 2 -- core/src/main/resources/hudson/model/Messages_es.properties | 1 - core/src/main/resources/hudson/model/Messages_fi.properties | 1 - core/src/main/resources/hudson/model/Messages_fr.properties | 1 - core/src/main/resources/hudson/model/Messages_hu.properties | 1 - core/src/main/resources/hudson/model/Messages_it.properties | 1 - core/src/main/resources/hudson/model/Messages_ja.properties | 2 -- core/src/main/resources/hudson/model/Messages_nl.properties | 1 - core/src/main/resources/hudson/model/Messages_pt_BR.properties | 2 -- core/src/main/resources/hudson/model/Messages_ru.properties | 1 - core/src/main/resources/hudson/model/Messages_sl.properties | 1 - core/src/main/resources/hudson/model/Messages_sv_SE.properties | 1 - core/src/main/resources/hudson/model/Messages_tr.properties | 1 - core/src/main/resources/hudson/model/Messages_zh_CN.properties | 1 - core/src/main/resources/hudson/model/Messages_zh_TW.properties | 1 - core/src/main/resources/jenkins/model/Messages.properties | 2 ++ core/src/main/resources/jenkins/model/Messages_ca.properties | 1 + core/src/main/resources/jenkins/model/Messages_da.properties | 1 + core/src/main/resources/jenkins/model/Messages_de.properties | 2 ++ core/src/main/resources/jenkins/model/Messages_es.properties | 1 + core/src/main/resources/jenkins/model/Messages_fi.properties | 1 + core/src/main/resources/jenkins/model/Messages_fr.properties | 1 + core/src/main/resources/jenkins/model/Messages_hu.properties | 1 + core/src/main/resources/jenkins/model/Messages_it.properties | 1 + core/src/main/resources/jenkins/model/Messages_ja.properties | 2 ++ core/src/main/resources/jenkins/model/Messages_nl.properties | 1 + .../src/main/resources/jenkins/model/Messages_pt_BR.properties | 2 ++ core/src/main/resources/jenkins/model/Messages_ru.properties | 1 + core/src/main/resources/jenkins/model/Messages_sl.properties | 1 + .../src/main/resources/jenkins/model/Messages_sv_SE.properties | 1 + core/src/main/resources/jenkins/model/Messages_tr.properties | 1 + .../src/main/resources/jenkins/model/Messages_zh_CN.properties | 1 + .../src/main/resources/jenkins/model/Messages_zh_TW.properties | 1 + 37 files changed, 23 insertions(+), 24 deletions(-) create mode 100644 core/src/main/resources/jenkins/model/Messages_ca.properties create mode 100644 core/src/main/resources/jenkins/model/Messages_fi.properties create mode 100644 core/src/main/resources/jenkins/model/Messages_hu.properties create mode 100644 core/src/main/resources/jenkins/model/Messages_it.properties create mode 100644 core/src/main/resources/jenkins/model/Messages_sl.properties create mode 100644 core/src/main/resources/jenkins/model/Messages_sv_SE.properties create mode 100644 core/src/main/resources/jenkins/model/Messages_zh_CN.properties diff --git a/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java b/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java index 3bb7c665ce..07d1e61e6b 100644 --- a/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java +++ b/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java @@ -274,8 +274,7 @@ public abstract class ParameterizedJobMixIn & Param * Uses {@link #BUILD_NOW_TEXT}. */ public final String getBuildNowText() { - // TODO move these messages (& translations) to this package - return isParameterized() ? hudson.model.Messages.AbstractProject_build_with_parameters() : AlternativeUiTextProvider.get(BUILD_NOW_TEXT, asJob(), hudson.model.Messages.AbstractProject_BuildNow()); + return isParameterized() ? Messages.ParameterizedJobMixIn_build_with_parameters() : AlternativeUiTextProvider.get(BUILD_NOW_TEXT, asJob(), Messages.ParameterizedJobMixIn_build_now()); } /** diff --git a/core/src/main/resources/hudson/model/Messages.properties b/core/src/main/resources/hudson/model/Messages.properties index 3537e9978a..19818bcfdc 100644 --- a/core/src/main/resources/hudson/model/Messages.properties +++ b/core/src/main/resources/hudson/model/Messages.properties @@ -37,8 +37,6 @@ AbstractProject.AwaitingWorkspaceToComeOnline=We need to schedule a new build to AbstractProject.Pronoun=Project AbstractProject.Aborted=Aborted AbstractProject.BuildInProgress=Build #{0} is already in progress{1} -AbstractProject.BuildNow=Build Now -AbstractProject.build_with_parameters=Build with Parameters AbstractProject.UpstreamBuildInProgress=Upstream project {0} is already building. AbstractProject.DownstreamBuildInProgress=Downstream project {0} is already building. AbstractProject.Disabled=Build disabled diff --git a/core/src/main/resources/hudson/model/Messages_ca.properties b/core/src/main/resources/hudson/model/Messages_ca.properties index 0f88dbec7e..2237bbee1d 100644 --- a/core/src/main/resources/hudson/model/Messages_ca.properties +++ b/core/src/main/resources/hudson/model/Messages_ca.properties @@ -1,2 +1 @@ -AbstractProject.BuildNow=Construir Ara ManageJenkinsAction.DisplayName=Configuraci\u00F3 de Jenkins diff --git a/core/src/main/resources/hudson/model/Messages_da.properties b/core/src/main/resources/hudson/model/Messages_da.properties index 3300fc7388..7f7707d648 100644 --- a/core/src/main/resources/hudson/model/Messages_da.properties +++ b/core/src/main/resources/hudson/model/Messages_da.properties @@ -238,5 +238,4 @@ Hudson.NoSuchDirectory=Intet direktorie ved navn: {0} LoadStatistics.Legends.BusyExecutors=Optagede afviklere HealthReport.EmptyString= MultiStageTimeSeries.EMPTY_STRING= -AbstractProject.BuildNow=Byg nu ManageJenkinsAction.DisplayName=Bestyr Jenkins diff --git a/core/src/main/resources/hudson/model/Messages_de.properties b/core/src/main/resources/hudson/model/Messages_de.properties index ffd402aa63..39a6cdae6e 100644 --- a/core/src/main/resources/hudson/model/Messages_de.properties +++ b/core/src/main/resources/hudson/model/Messages_de.properties @@ -32,8 +32,6 @@ AbstractProject.NewBuildForWorkspace=Plane einen neuen Build, um einen Arbeitsbe AbstractProject.Pronoun=Projekt AbstractProject.Aborted=Abgebrochen AbstractProject.BuildInProgress=Build #{0} ist bereits in Arbeit{1} -AbstractProject.BuildNow=Jetzt bauen -AbstractProject.build_with_parameters=Bauen mit Parametern AbstractProject.UpstreamBuildInProgress=Vorgelagertes Projekt {0} ist bereits in Arbeit. AbstractProject.DownstreamBuildInProgress=Nachgelagertes Projekt {0} ist bereits in Arbeit. AbstractProject.Disabled=Build deaktiviert diff --git a/core/src/main/resources/hudson/model/Messages_es.properties b/core/src/main/resources/hudson/model/Messages_es.properties index 27eb91abc8..3c7930125f 100644 --- a/core/src/main/resources/hudson/model/Messages_es.properties +++ b/core/src/main/resources/hudson/model/Messages_es.properties @@ -279,7 +279,6 @@ AbstractProject.AwaitingBuildForWorkspace=El trabajo est\u00e1 esperando para te Run.ArtifactsPermission.Description=\ Este permiso sirve para poder utilizar los artefactos producidos en los proyectos. AbstractProject.AssignedLabelString.InvalidBooleanExpression=Expresi\u00f3n booleana incorrecta: {0} -AbstractProject.BuildNow=Construir ahora ManageJenkinsAction.DisplayName=Administrar Jenkins Computer.NoSuchSlaveExists=El nodo {0} no existe. ¿Quizás se esté refiriendo a {1}? ResultTrend.StillFailing=Todavía falla diff --git a/core/src/main/resources/hudson/model/Messages_fi.properties b/core/src/main/resources/hudson/model/Messages_fi.properties index a5937f2baf..b8537b4403 100644 --- a/core/src/main/resources/hudson/model/Messages_fi.properties +++ b/core/src/main/resources/hudson/model/Messages_fi.properties @@ -1,2 +1 @@ -AbstractProject.BuildNow=K\u00E4\u00E4nn\u00E4 nyt ManageJenkinsAction.DisplayName=Hallitse Jenkinsia diff --git a/core/src/main/resources/hudson/model/Messages_fr.properties b/core/src/main/resources/hudson/model/Messages_fr.properties index 82d0d98072..2a47d2237e 100644 --- a/core/src/main/resources/hudson/model/Messages_fr.properties +++ b/core/src/main/resources/hudson/model/Messages_fr.properties @@ -193,5 +193,4 @@ Cause.RemoteCause.ShortDescription=D\u00e9marr\u00e9 \u00e0 distance par {0} MyViewsProperty.DisplayName=Mes vues MyViewsProperty.GlobalAction.DisplayName=Mes vues -AbstractProject.BuildNow=Lancer un build ManageJenkinsAction.DisplayName=Administrer Jenkins diff --git a/core/src/main/resources/hudson/model/Messages_hu.properties b/core/src/main/resources/hudson/model/Messages_hu.properties index cbad071927..ed0c34be08 100644 --- a/core/src/main/resources/hudson/model/Messages_hu.properties +++ b/core/src/main/resources/hudson/model/Messages_hu.properties @@ -1,2 +1 @@ -AbstractProject.BuildNow=\u00C9p\u00EDt\u00E9s Most ManageJenkinsAction.DisplayName=Jenkins Kezel\u00E9se diff --git a/core/src/main/resources/hudson/model/Messages_it.properties b/core/src/main/resources/hudson/model/Messages_it.properties index fd106bf53b..82d784c450 100644 --- a/core/src/main/resources/hudson/model/Messages_it.properties +++ b/core/src/main/resources/hudson/model/Messages_it.properties @@ -34,7 +34,6 @@ AbstractProject.AwaitingBuildForWorkspace=Awaiting build to get a workspace. AbstractProject.Pronoun=Progetto AbstractProject.Aborted=Interrotta AbstractProject.BuildInProgress=Build #{0} is already in progress{1} -AbstractProject.BuildNow=Effettua build AbstractProject.UpstreamBuildInProgress=Upstream project {0} is already building. AbstractProject.DownstreamBuildInProgress=Downstream project {0} is already building. AbstractProject.Disabled=Build disabled diff --git a/core/src/main/resources/hudson/model/Messages_ja.properties b/core/src/main/resources/hudson/model/Messages_ja.properties index 6d31b46cf5..346395b1c8 100644 --- a/core/src/main/resources/hudson/model/Messages_ja.properties +++ b/core/src/main/resources/hudson/model/Messages_ja.properties @@ -35,8 +35,6 @@ AbstractProject.AwaitingBuildForWorkspace=\u30ef\u30fc\u30af\u30b9\u30da\u30fc\u AbstractProject.Pronoun=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 AbstractProject.Aborted=\u4e2d\u6b62 AbstractProject.BuildInProgress=\u30d3\u30eb\u30c9 #{0} \u306f\u65e2\u306b\u5b9f\u884c\u4e2d\u3067\u3059\u3002{1} -AbstractProject.BuildNow=\u30d3\u30eb\u30c9\u5b9f\u884c -AbstractProject.build_with_parameters=\u30d1\u30e9\u30e1\u30fc\u30bf\u4ed8\u304d\u30d3\u30eb\u30c9 AbstractProject.UpstreamBuildInProgress=\u4e0a\u6d41\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 {0} \u306f\u3059\u3067\u306b\u30d3\u30eb\u30c9\u4e2d\u3067\u3059\u3002 AbstractProject.DownstreamBuildInProgress=\u4e0b\u6d41\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 {0} \u304c\u307e\u3060\u30d3\u30eb\u30c9\u4e2d\u3067\u3059\u3002 AbstractProject.Disabled=\u30d3\u30eb\u30c9\u306f\u7121\u52b9\u306b\u306a\u3063\u3066\u3044\u307e\u3059\u3002 diff --git a/core/src/main/resources/hudson/model/Messages_nl.properties b/core/src/main/resources/hudson/model/Messages_nl.properties index 88b53d8f21..4b45bad4ee 100644 --- a/core/src/main/resources/hudson/model/Messages_nl.properties +++ b/core/src/main/resources/hudson/model/Messages_nl.properties @@ -102,5 +102,4 @@ Permalink.LastBuild=Laatste bouwpoging Permalink.LastStableBuild=Laatste stabiele bouwpoging Permalink.LastSuccessfulBuild=Laatste succesvolle bouwpoging Permalink.LastFailedBuild=Laatst gefaalde bouwpoging -AbstractProject.BuildNow=Start nu een bouwpoging ManageJenkinsAction.DisplayName=Beheer Jenkins diff --git a/core/src/main/resources/hudson/model/Messages_pt_BR.properties b/core/src/main/resources/hudson/model/Messages_pt_BR.properties index 5162dbd6b9..d5cd0f2338 100644 --- a/core/src/main/resources/hudson/model/Messages_pt_BR.properties +++ b/core/src/main/resources/hudson/model/Messages_pt_BR.properties @@ -382,7 +382,6 @@ Label.GroupOf=Grupo de {0} Queue.AllNodesOffline=Todos os rotulos ''{0}'' est\u00e3o offline. # Busy executors LoadStatistics.Legends.BusyExecutors=Executores ocupados. -AbstractProject.BuildNow=Construir agora ManageJenkinsAction.DisplayName=Gerenciar Jenkins # Workspace of {0} AbstractProject.WorkspaceTitle=Workspace de {0} @@ -507,7 +506,6 @@ AbstractProject.LabelLink=Slaves em label: {2} # Artifacts of {0} {1} Run.ArtifactsBrowserTitle=Artefatos de {0} {1} # Build with Parameters -AbstractProject.build_with_parameters=Construir com par\u00e2metros # Still unstable ResultTrend.StillUnstable=Ainda inst\u00e1vel # Running as {0} diff --git a/core/src/main/resources/hudson/model/Messages_ru.properties b/core/src/main/resources/hudson/model/Messages_ru.properties index c0be7aa273..8214675442 100644 --- a/core/src/main/resources/hudson/model/Messages_ru.properties +++ b/core/src/main/resources/hudson/model/Messages_ru.properties @@ -102,5 +102,4 @@ Permalink.LastBuild=\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u044 Permalink.LastStableBuild=\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0441\u0442\u0430\u0431\u0438\u043b\u044c\u043d\u0430\u044f \u0441\u0431\u043e\u0440\u043a\u0430 Permalink.LastSuccessfulBuild=\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u0443\u0441\u043f\u0435\u0448\u043d\u0430\u044f \u0441\u0431\u043e\u0440\u043a\u0430 Permalink.LastFailedBuild=\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f \u043f\u0440\u043e\u0432\u0430\u043b\u0438\u0432\u0448\u0430\u044f\u0441\u044f \u0441\u0431\u043e\u0440\u043a\u0430 -AbstractProject.BuildNow=\u0421\u043E\u0431\u0440\u0430\u0442\u044C \u0441\u0435\u0439\u0447\u0430\u0441 ManageJenkinsAction.DisplayName=\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Jenkins diff --git a/core/src/main/resources/hudson/model/Messages_sl.properties b/core/src/main/resources/hudson/model/Messages_sl.properties index a9fc958501..e69de29bb2 100644 --- a/core/src/main/resources/hudson/model/Messages_sl.properties +++ b/core/src/main/resources/hudson/model/Messages_sl.properties @@ -1 +0,0 @@ -AbstractProject.BuildNow=Prevedi takoj diff --git a/core/src/main/resources/hudson/model/Messages_sv_SE.properties b/core/src/main/resources/hudson/model/Messages_sv_SE.properties index 7c0ec4d60a..763f29cdd2 100644 --- a/core/src/main/resources/hudson/model/Messages_sv_SE.properties +++ b/core/src/main/resources/hudson/model/Messages_sv_SE.properties @@ -1,5 +1,4 @@ AbstractProject.Pronoun=Projekt -AbstractProject.BuildNow=Starta bygge nu Job.Pronoun=Projekt diff --git a/core/src/main/resources/hudson/model/Messages_tr.properties b/core/src/main/resources/hudson/model/Messages_tr.properties index 3ea32148ca..929f984c4b 100644 --- a/core/src/main/resources/hudson/model/Messages_tr.properties +++ b/core/src/main/resources/hudson/model/Messages_tr.properties @@ -103,5 +103,4 @@ Permalink.LastBuild=Son yap\u0131land\u0131rma Permalink.LastStableBuild=Son stabil yap\u0131land\u0131rma Permalink.LastSuccessfulBuild=Son ba\u015far\u0131l\u0131 yap\u0131land\u0131rma Permalink.LastFailedBuild=Son ba\u015far\u0131s\u0131z yap\u0131land\u0131rma -AbstractProject.BuildNow=\u015eimdi Yap\u0131land\u0131r ManageJenkinsAction.DisplayName=Jenkins''\u0131 Y\u00f6net diff --git a/core/src/main/resources/hudson/model/Messages_zh_CN.properties b/core/src/main/resources/hudson/model/Messages_zh_CN.properties index d89016d3d2..d3ec7be43e 100644 --- a/core/src/main/resources/hudson/model/Messages_zh_CN.properties +++ b/core/src/main/resources/hudson/model/Messages_zh_CN.properties @@ -270,5 +270,4 @@ CLI.keep-build.shortDescription=Mark the build to keep the build forever. CLI.quiet-down.shortDescription=Quiet down Jenkins, in preparation for a restart. Don''t start any builds. CLI.cancel-quiet-down.shortDescription=Cancel the effect of the "quiet-down" command. CLI.reload-configuration.shortDescription=Discard all the loaded data in memory and reload everything from file system. Useful when you modified config files directly on disk. -AbstractProject.BuildNow=\u7acb\u5373\u6784\u5efa ManageJenkinsAction.DisplayName=\u7cfb\u7edf\u7ba1\u7406 diff --git a/core/src/main/resources/hudson/model/Messages_zh_TW.properties b/core/src/main/resources/hudson/model/Messages_zh_TW.properties index 77437b859d..c055f0514b 100644 --- a/core/src/main/resources/hudson/model/Messages_zh_TW.properties +++ b/core/src/main/resources/hudson/model/Messages_zh_TW.properties @@ -35,7 +35,6 @@ AbstractProject.AwaitingBuildForWorkspace=\u7b49\u5019\u5efa\u7f6e\u7522\u51fa\u AbstractProject.Pronoun=\u5c08\u6848 AbstractProject.Aborted=\u4e2d\u65b7 AbstractProject.BuildInProgress=\u5efa\u7f6e #{0} \u57f7\u884c\u4e2d{1} -AbstractProject.BuildNow=\u99ac\u4e0a\u5efa\u7f6e AbstractProject.UpstreamBuildInProgress=\u4e0a\u6e38\u5c08\u6848 {0} \u5efa\u7f6e\u4e2d\u3002 AbstractProject.DownstreamBuildInProgress=\u4e0b\u6e38\u5c08\u6848 {0} \u5efa\u7f6e\u4e2d\u3002 AbstractProject.Disabled=\u5efa\u7f6e\u505c\u7528 diff --git a/core/src/main/resources/jenkins/model/Messages.properties b/core/src/main/resources/jenkins/model/Messages.properties index 98c360e524..9eaeb6838d 100644 --- a/core/src/main/resources/jenkins/model/Messages.properties +++ b/core/src/main/resources/jenkins/model/Messages.properties @@ -66,3 +66,5 @@ Mailer.Localhost.Error=Please set a valid host name, instead of localhost PatternProjectNamingStrategy.DisplayName=Pattern PatternProjectNamingStrategy.NamePatternRequired=Name Pattern is required PatternProjectNamingStrategy.NamePatternInvalidSyntax=regular expression's syntax is invalid. +ParameterizedJobMixIn.build_with_parameters=Build with Parameters +ParameterizedJobMixIn.build_now=Build Now diff --git a/core/src/main/resources/jenkins/model/Messages_ca.properties b/core/src/main/resources/jenkins/model/Messages_ca.properties new file mode 100644 index 0000000000..a5ded4670c --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_ca.properties @@ -0,0 +1 @@ +ParameterizedJobMixIn.build_now=Construir Ara diff --git a/core/src/main/resources/jenkins/model/Messages_da.properties b/core/src/main/resources/jenkins/model/Messages_da.properties index c355612da1..7e20fed778 100644 --- a/core/src/main/resources/jenkins/model/Messages_da.properties +++ b/core/src/main/resources/jenkins/model/Messages_da.properties @@ -52,3 +52,4 @@ Nyttigt hvis du har modificeret konfigurationsfiler direkte, udenom Jenkins. Mailer.Address.Not.Configured=Adresse ikke konfigureret Mailer.Localhost.Error=Venligst inds\u00e6t et gyldigt v\u00e6rtsnavn, istedet for localhost +ParameterizedJobMixIn.build_now=Byg nu diff --git a/core/src/main/resources/jenkins/model/Messages_de.properties b/core/src/main/resources/jenkins/model/Messages_de.properties index dc2b7ce547..bdf20ef081 100644 --- a/core/src/main/resources/jenkins/model/Messages_de.properties +++ b/core/src/main/resources/jenkins/model/Messages_de.properties @@ -61,3 +61,5 @@ Mailer.Localhost.Error=Bitte verwenden Sie einen konkreten Hostnamen anstelle vo PatternProjectNamingStrategy.DisplayName=Muster PatternProjectNamingStrategy.NamePatternRequired=Der Regul\u00e4re Ausdruck darf nicht leer sein. PatternProjectNamingStrategy.NamePatternInvalidSyntax=Der Regul\u00e4re Ausdruck ist ung\u00fcltig. +ParameterizedJobMixIn.build_with_parameters=Bauen mit Parametern +ParameterizedJobMixIn.build_now=Jetzt bauen diff --git a/core/src/main/resources/jenkins/model/Messages_es.properties b/core/src/main/resources/jenkins/model/Messages_es.properties index 4b4c61a764..4e41e75259 100644 --- a/core/src/main/resources/jenkins/model/Messages_es.properties +++ b/core/src/main/resources/jenkins/model/Messages_es.properties @@ -62,3 +62,4 @@ PatternProjectNamingStrategy.NamePatternInvalidSyntax=La sintaxis de la expresi Mailer.Address.Not.Configured=Dirección no configurada todavía Mailer.Localhost.Error=Escriba un nombre de servidor correcto en lugar de "localhost" +ParameterizedJobMixIn.build_now=Construir ahora diff --git a/core/src/main/resources/jenkins/model/Messages_fi.properties b/core/src/main/resources/jenkins/model/Messages_fi.properties new file mode 100644 index 0000000000..ad6283cffe --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_fi.properties @@ -0,0 +1 @@ +ParameterizedJobMixIn.build_now=K\u00E4\u00E4nn\u00E4 nyt diff --git a/core/src/main/resources/jenkins/model/Messages_fr.properties b/core/src/main/resources/jenkins/model/Messages_fr.properties index ee643ff342..49ac02a98b 100644 --- a/core/src/main/resources/jenkins/model/Messages_fr.properties +++ b/core/src/main/resources/jenkins/model/Messages_fr.properties @@ -42,3 +42,4 @@ Hudson.ReadPermission.Description=\ — retirez ce droit \u00e0 l''utilisateur anonymous, puis \ ajoutez le pseudo-utilisateur "authenticated" et accordez-lui le droit en lecture. +ParameterizedJobMixIn.build_now=Lancer un build diff --git a/core/src/main/resources/jenkins/model/Messages_hu.properties b/core/src/main/resources/jenkins/model/Messages_hu.properties new file mode 100644 index 0000000000..d75db0b3e3 --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_hu.properties @@ -0,0 +1 @@ +ParameterizedJobMixIn.build_now=\u00C9p\u00EDt\u00E9s Most diff --git a/core/src/main/resources/jenkins/model/Messages_it.properties b/core/src/main/resources/jenkins/model/Messages_it.properties new file mode 100644 index 0000000000..95fad9d487 --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_it.properties @@ -0,0 +1 @@ +ParameterizedJobMixIn.build_now=Effettua build diff --git a/core/src/main/resources/jenkins/model/Messages_ja.properties b/core/src/main/resources/jenkins/model/Messages_ja.properties index 115d02941b..f1fb238d21 100644 --- a/core/src/main/resources/jenkins/model/Messages_ja.properties +++ b/core/src/main/resources/jenkins/model/Messages_ja.properties @@ -62,3 +62,5 @@ PatternProjectNamingStrategy.NamePatternInvalidSyntax=\u6b63\u898f\u8868\u73fe\u Mailer.Address.Not.Configured=\u307e\u3060\u30a2\u30c9\u30ec\u30b9\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 Mailer.Localhost.Error=localhost\u306e\u4ee3\u308f\u308a\u306b\u59a5\u5f53\u306a\u30db\u30b9\u30c8\u540d\u3092\u8a2d\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +ParameterizedJobMixIn.build_with_parameters=\u30d1\u30e9\u30e1\u30fc\u30bf\u4ed8\u304d\u30d3\u30eb\u30c9 +ParameterizedJobMixIn.build_now=\u30d3\u30eb\u30c9\u5b9f\u884c diff --git a/core/src/main/resources/jenkins/model/Messages_nl.properties b/core/src/main/resources/jenkins/model/Messages_nl.properties index 6e0492c762..08c27845b2 100644 --- a/core/src/main/resources/jenkins/model/Messages_nl.properties +++ b/core/src/main/resources/jenkins/model/Messages_nl.properties @@ -30,3 +30,4 @@ Hudson.NoJavaInPath=java is niet beschikbaar op uw pad. Misschien moet je een Date: Sun, 2 Aug 2015 21:26:36 -0700 Subject: [PATCH 076/256] [maven-release-plugin] prepare release jenkins-1.623 --- cli/pom.xml | 2 +- core/pom.xml | 2 +- plugins/pom.xml | 10 +++++----- pom.xml | 4 ++-- test/pom.xml | 2 +- war/pom.xml | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cli/pom.xml b/cli/pom.xml index ee3d8c04a8..10dc053126 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.623-SNAPSHOT + 1.623 cli diff --git a/core/pom.xml b/core/pom.xml index a69bd3192c..224ecca6b6 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.623-SNAPSHOT + 1.623 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index e6758f8fb6..d9a8046d59 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.623-SNAPSHOT + 1.623 pom +

    What's new in 1.623 (2015/08/02)

    +
      +
    • +

    What's new in 1.622 (2015/07/27)

    • From 4589ce5d669ac18b4415f22daf4305d5f9f0d50e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Tue, 4 Aug 2015 09:33:10 +0200 Subject: [PATCH 079/256] Avoid "EmptyStackException: null" in Items#getCanonicalName --- core/src/main/java/hudson/model/Items.java | 7 +++++- .../src/test/java/hudson/model/ItemsTest.java | 22 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/Items.java b/core/src/main/java/hudson/model/Items.java index 26efd209b5..8700c0554f 100644 --- a/core/src/main/java/hudson/model/Items.java +++ b/core/src/main/java/hudson/model/Items.java @@ -204,7 +204,7 @@ public class Items { String[] c = context.getFullName().split("/"); String[] p = path.split("/"); - Stack name = new Stack(); + Stack name = new Stack(); for (int i=0; i Date: Tue, 4 Aug 2015 10:12:03 +0200 Subject: [PATCH 080/256] Make it easier to determine Computer is Unix or Windows --- core/src/main/java/hudson/model/Computer.java | 13 ++++++++++++- core/src/main/java/hudson/slaves/SlaveComputer.java | 7 +------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index d0c049c2e5..9430c32792 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -28,6 +28,7 @@ import edu.umd.cs.findbugs.annotations.OverrideMustInvoke; import edu.umd.cs.findbugs.annotations.When; import hudson.EnvVars; import hudson.Extension; +import hudson.Functions; import hudson.Launcher.ProcStarter; import hudson.Util; import hudson.cli.declarative.CLIMethod; @@ -522,7 +523,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces @CLIMethod(name="online-node") public void cliOnline() throws ExecutionException, InterruptedException { checkPermission(CONNECT); - setTemporarilyOffline(false,null); + setTemporarilyOffline(false, null); } /** @@ -545,6 +546,16 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces return nodeName != null ? nodeName : ""; } + /** + * True if this computer is a Unix machine (as opposed to Windows machine). + * + * @return + * null if the computer is disconnected and therefore we don't know whether it is Unix or not. + */ + public Boolean isUnix() { + return !Functions.isWindows(); + } + /** * Returns the {@link Node} that this computer represents. * diff --git a/core/src/main/java/hudson/slaves/SlaveComputer.java b/core/src/main/java/hudson/slaves/SlaveComputer.java index c62401dc76..85f2c6def3 100644 --- a/core/src/main/java/hudson/slaves/SlaveComputer.java +++ b/core/src/main/java/hudson/slaves/SlaveComputer.java @@ -172,12 +172,7 @@ public class SlaveComputer extends Computer { this.acceptingTasks = acceptingTasks; } - /** - * True if this computer is a Unix machine (as opposed to Windows machine). - * - * @return - * null if the computer is disconnected and therefore we don't know whether it is Unix or not. - */ + @Override public Boolean isUnix() { return isUnix; } From d331c12bbc2cf863efd39e0b135c584da364937a Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Tue, 4 Aug 2015 16:26:23 +0200 Subject: [PATCH 081/256] =?UTF-8?q?prefer=20Computer#isUnix=20to=20be=20ab?= =?UTF-8?q?stract=20few=20chances=20there=E2=80=99s=20another=20implementa?= =?UTF-8?q?tion=20but=20if=20one=20exists=20Function.isWindows=20would=20p?= =?UTF-8?q?robably=20be=20wrong=20implementation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/src/main/java/hudson/model/Computer.java | 5 ++--- core/src/main/java/jenkins/model/Jenkins.java | 5 +++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index 9430c32792..4b2d035049 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -549,12 +549,11 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces /** * True if this computer is a Unix machine (as opposed to Windows machine). * + * @since 1.624 * @return * null if the computer is disconnected and therefore we don't know whether it is Unix or not. */ - public Boolean isUnix() { - return !Functions.isWindows(); - } + public abstract @CheckForNull Boolean isUnix(); /** * Returns the {@link Node} that this computer represents. diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index c8dedf7577..188a668b50 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -3998,6 +3998,11 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve return true; } + @Override + public Boolean isUnix() { + return !Functions.isWindows(); + } + /** * Report an error. */ From 7dfa765d8b7562ea25b8eab6c26d8c7a5ca6ef1b Mon Sep 17 00:00:00 2001 From: Vincent Latombe Date: Wed, 5 Aug 2015 11:59:32 +0200 Subject: [PATCH 082/256] [FIXED JENKINS-29798] Failed to listen to incoming slave connection Factor tcpSlaveAgentListener logic to a single method able to shutdown existing listener if required, then launch a new one if it needs to. Also, the administrative monitor gets cleared if we had previously a taken port and changed to a valid port. --- changelog.html | 2 + core/src/main/java/jenkins/model/Jenkins.java | 46 +++++++++++-------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/changelog.html b/changelog.html index d7cf18d4bc..88090ebc78 100644 --- a/changelog.html +++ b/changelog.html @@ -55,6 +55,8 @@ Upcoming changes diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 188a668b50..5bf95e3abf 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -821,16 +821,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve if(KILL_AFTER_LOAD) System.exit(0); - if(slaveAgentPort!=-1) { - try { - tcpSlaveAgentListener = new TcpSlaveAgentListener(slaveAgentPort); - } catch (BindException e) { - new AdministrativeError(getClass().getName()+".tcpBind", - "Failed to listen to incoming slave connection", - "Failed to listen to incoming slave connection. Change the port number to solve the problem.",e); - } - } else - tcpSlaveAgentListener = null; + launchTcpSlaveAgentListener(); if (UDPBroadcastThread.PORT != -1) { try { @@ -946,17 +937,34 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve */ public void setSlaveAgentPort(int port) throws IOException { this.slaveAgentPort = port; + launchTcpSlaveAgentListener(); + } - // relaunch the agent - if(tcpSlaveAgentListener==null) { - if(slaveAgentPort!=-1) + private void launchTcpSlaveAgentListener() throws IOException { + // shutdown previous agent if the port has changed + if(tcpSlaveAgentListener != null && tcpSlaveAgentListener.configuredPort!=slaveAgentPort) { + tcpSlaveAgentListener.shutdown(); + tcpSlaveAgentListener = null; + } + if(slaveAgentPort!=-1 && tcpSlaveAgentListener == null) { + String administrativeMonitorId = getClass().getName()+".tcpBind"; + try { tcpSlaveAgentListener = new TcpSlaveAgentListener(slaveAgentPort); - } else { - if(tcpSlaveAgentListener.configuredPort!=slaveAgentPort) { - tcpSlaveAgentListener.shutdown(); - tcpSlaveAgentListener = null; - if(slaveAgentPort!=-1) - tcpSlaveAgentListener = new TcpSlaveAgentListener(slaveAgentPort); + // remove previous monitor in case of previous error + AdministrativeMonitor previousMonitor = null; + for(AdministrativeMonitor am : AdministrativeMonitor.all()) { + if (administrativeMonitorId.equals(am.id)) { + previousMonitor = am; + break; + } + } + if (previousMonitor != null) { + AdministrativeMonitor.all().remove(previousMonitor); + } + } catch (BindException e) { + new AdministrativeError(administrativeMonitorId, + "Failed to listen to incoming slave connection", + "Failed to listen to incoming slave connection. Change the port number to solve the problem.",e); } } } From 4d3285398b9dbbf4ab6dd0b7704f0e9dd02346de Mon Sep 17 00:00:00 2001 From: Vincent Latombe Date: Wed, 5 Aug 2015 12:38:13 +0200 Subject: [PATCH 083/256] Remove administrativeMonitor in loop to catch hypothetical dups --- core/src/main/java/jenkins/model/Jenkins.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 5bf95e3abf..18df39cf57 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -951,16 +951,12 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve try { tcpSlaveAgentListener = new TcpSlaveAgentListener(slaveAgentPort); // remove previous monitor in case of previous error - AdministrativeMonitor previousMonitor = null; - for(AdministrativeMonitor am : AdministrativeMonitor.all()) { + for(Iterator it = AdministrativeMonitor.all().iterator(); it.hasNext();) { + AdministrativeMonitor am = it.next(); if (administrativeMonitorId.equals(am.id)) { - previousMonitor = am; - break; + it.remove(); } } - if (previousMonitor != null) { - AdministrativeMonitor.all().remove(previousMonitor); - } } catch (BindException e) { new AdministrativeError(administrativeMonitorId, "Failed to listen to incoming slave connection", From 0ba505b60ca86d6b103b070a690a98ae6fef8c5d Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Thu, 6 Aug 2015 10:39:54 +0100 Subject: [PATCH 084/256] [JENKINS-28690] Aha! So I believe this will fully resolve any of these kinds of deadlocks - Without this, then it becomes a question of find catch and release for each potential code path that might end up restoring the interrupt flag on the current thread. - Since standard Lock support is kind enough to restore the interrupt flag on the current thread when blocked waiting for the lock, that would be a hiding to nothing - I welcome others to review my logic detailed in the code comment - I am leaving the code comment as this is IMHO too important to assume that somebody will check the git commit history --- core/src/main/java/hudson/model/Executor.java | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/Executor.java b/core/src/main/java/hudson/model/Executor.java index f4c85460ac..5f021cfe80 100644 --- a/core/src/main/java/hudson/model/Executor.java +++ b/core/src/main/java/hudson/model/Executor.java @@ -142,7 +142,34 @@ public class Executor extends Thread implements ModelObject { @Override public void interrupt() { - interrupt(Result.ABORTED); + if (Thread.currentThread() == this) { + // If you catch an InterruptedException the "correct" options are limited to one of two choices: + // 1. Propagate the exception; + // 2. Restore the Thread.currentThread().interrupted() flag + // The JVM locking support assumes such behaviour. + // Evil Jenkins overrides the interrupt() method so that when a different thread interrupts this thread + // we abort the build. + // but that causes JENKINS-28690 style deadlocks when the correctly written code does + // + // try { + // ... some long running thing ... + // } catch (InterruptedException e) { + // ... some tidy up + // // restore interrupted flag + // Thread.currentThread().interrupted(); + // } + // + // What about why we do not set the Result.ABORTED on this branch? + // That is a good question to ask, the answer is that the only time a thread should be restoring + // its own interrupted flag is when that thread has already been interrupted by another thread + // as such we should assume that the result has already been applied. If that assumption were + // incorrect, then the Run.execute's catch (InterruptedException) block will either set the result + // or have been escaped - in which case the result of the run has been sealed anyway so it does not + // matter. + super.interrupt(); + } else { + interrupt(Result.ABORTED); + } } void interruptForShutdown() { From a798aa427ff34e1e0e835515cc07ec41dc2d1b56 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Thu, 6 Aug 2015 11:42:07 +0200 Subject: [PATCH 085/256] 1.623 has no notable changes --- changelog.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/changelog.html b/changelog.html index d7cf18d4bc..7ea47af53f 100644 --- a/changelog.html +++ b/changelog.html @@ -59,9 +59,7 @@ Upcoming changes

What's new in 1.623 (2015/08/02)

-
    -
  • -
+

No major user-visible changes in this release.

What's new in 1.622 (2015/07/27)

  • From 030793f01da3607ad59d6d644192e0a226c7efa2 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Thu, 6 Aug 2015 11:03:40 +0100 Subject: [PATCH 086/256] [FIXES #1777] Make accessing pendingLaunches lock free - My objection to #1777 is that it is introducing more locking. The ultimate aim is to make node provisioning and queue maintenance completely lock free. Thus adding more locks than is strictly required is a bad plan. - We cannot completely remove provisioningLock at this time as it is used to ensure that only one provisioning activity can take place for a given label at a time. - This change ensures that the provisioningLock is only used by the NodeProvisioner for its internal thread guarantees and is thus no-longer used accidentally by any external threads --- .../java/hudson/slaves/NodeProvisioner.java | 70 ++++++++++++------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/core/src/main/java/hudson/slaves/NodeProvisioner.java b/core/src/main/java/hudson/slaves/NodeProvisioner.java index b1bb60ce5a..216c8b3ef1 100644 --- a/core/src/main/java/hudson/slaves/NodeProvisioner.java +++ b/core/src/main/java/hudson/slaves/NodeProvisioner.java @@ -42,6 +42,7 @@ import java.util.Collection; import java.util.ArrayList; import java.util.Iterator; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Logger; @@ -122,8 +123,8 @@ public class NodeProvisioner { */ private final Label label; - @GuardedBy("provisioningLock") - private final List pendingLaunches = new ArrayList(); + private final AtomicReference> pendingLaunches + = new AtomicReference>(new ArrayList()); private final Lock provisioningLock = new ReentrantLock(); @@ -155,12 +156,7 @@ public class NodeProvisioner { * @since 1.401 */ public List getPendingLaunches() { - provisioningLock.lock(); - try { - return new ArrayList(pendingLaunches); - } finally { - provisioningLock.unlock(); - } + return new ArrayList(pendingLaunches.get()); } /** @@ -214,7 +210,8 @@ public class NodeProvisioner { int plannedCapacitySnapshot = 0; - for (Iterator itr = pendingLaunches.iterator(); itr.hasNext(); ) { + List snapPendingLaunches = new ArrayList(pendingLaunches.get()); + for (Iterator itr = snapPendingLaunches.iterator(); itr.hasNext(); ) { PlannedNode f = itr.next(); if (f.future.isDone()) { try { @@ -249,7 +246,29 @@ public class NodeProvisioner { LOGGER.log(Level.SEVERE, "Unexpected uncaught exception encountered while " + "processing provisioned slave " + f.displayName, e); } finally { - itr.remove(); + while (true) { + List orig = pendingLaunches.get(); + List repl = new ArrayList(orig); + // the contract for List.remove(o) is that the first element i where + // (o==null ? get(i)==null : o.equals(get(i))) + // is true will be removed from the list + // since PlannedNode.equals(o) is not final and we cannot assume + // that subclasses do not override with an equals which does not + // assure object identity comparison, we need to manually + // do the removal based on instance identity not equality + boolean changed = false; + for (Iterator iterator = repl.iterator(); iterator.hasNext(); ) { + PlannedNode p = iterator.next(); + if (p == f) { + iterator.remove(); + changed = true; + break; + } + } + if (!changed || pendingLaunches.compareAndSet(orig, repl)) { + break; + } + } f.spent(); } } else { @@ -355,7 +374,6 @@ public class NodeProvisioner { * The current statistics snapshot for this {@link #label}. */ private final LoadStatistics.LoadStatisticsSnapshot snapshot; - private final List pendingLaunches; /** * The additional planned capacity for this {@link #label} and provisioned by previous strategies during the * current updating of the {@link NodeProvisioner}. @@ -372,7 +390,6 @@ public class NodeProvisioner { this.snapshot = snapshot; this.label = label; this.plannedCapacitySnapshot = plannedCapacitySnapshot; - pendingLaunches = NodeProvisioner.this.pendingLaunches; } /** @@ -428,13 +445,8 @@ public class NodeProvisioner { * The additional planned capacity for this {@link #getLabel()} and provisioned by previous strategies during * the current updating of the {@link NodeProvisioner}. */ - public int getAdditionalPlannedCapacity() { - provisioningLock.lock(); - try { - return additionalPlannedCapacity; - } finally { - provisioningLock.unlock(); - } + public synchronized int getAdditionalPlannedCapacity() { + return additionalPlannedCapacity; } /** @@ -544,7 +556,7 @@ public class NodeProvisioner { additionalPlannedCapacity += node.getNumExecutors(); } } catch (InterruptedException e) { - // ignore, this will be caught by others later + // should never happen as we were told the future was done } catch (ExecutionException e) { // ignore, this will be caught by others later } @@ -552,14 +564,18 @@ public class NodeProvisioner { additionalPlannedCapacity += f.numExecutors; } } - provisioningLock.lock(); - try { - pendingLaunches.addAll(plannedNodes); - if (additionalPlannedCapacity > 0) { - this.additionalPlannedCapacity += additionalPlannedCapacity; + while (!plannedNodes.isEmpty()) { + List orig = pendingLaunches.get(); + List repl = new ArrayList(orig); + repl.addAll(plannedNodes); + if (pendingLaunches.compareAndSet(orig, repl)) { + if (additionalPlannedCapacity > 0) { + synchronized (this) { + this.additionalPlannedCapacity += additionalPlannedCapacity; + } + } + break; } - } finally { - provisioningLock.unlock(); } } From 9bcd351eec9663a583d57f20395653b64a6e1efd Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 6 Aug 2015 14:59:48 -0400 Subject: [PATCH 087/256] arbitrary change --- core/src/main/java/hudson/model/AbstractProject.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java index acfe0574e6..70e115b190 100644 --- a/core/src/main/java/hudson/model/AbstractProject.java +++ b/core/src/main/java/hudson/model/AbstractProject.java @@ -1143,7 +1143,8 @@ public abstract class AbstractProject

    ,R extends A } } - @Override public CauseOfBlockage getCauseOfBlockage() { + @Override + public CauseOfBlockage getCauseOfBlockage() { // Block builds until they are done with post-production if (isLogUpdated() && !isConcurrentBuild()) { return new BlockedBecauseOfBuildInProgress(getLastBuild()); From 03bba487296dd7d0f44a0c235724c3b7fb41cd69 Mon Sep 17 00:00:00 2001 From: Vincent Latombe Date: Fri, 7 Aug 2015 11:57:33 +0200 Subject: [PATCH 088/256] [JENKINS-29798] Add a lock to serialize updates of tcpSlaveAgentListener --- core/src/main/java/jenkins/model/Jenkins.java | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 18df39cf57..2774e8bcf3 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -552,6 +552,8 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve public transient volatile TcpSlaveAgentListener tcpSlaveAgentListener; + private transient final Object tcpSlaveAgentListenerLock = new Object(); + private transient UDPBroadcastThread udpBroadcastThread; private transient DNSMultiCast dnsMultiCast; @@ -941,26 +943,28 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } private void launchTcpSlaveAgentListener() throws IOException { - // shutdown previous agent if the port has changed - if(tcpSlaveAgentListener != null && tcpSlaveAgentListener.configuredPort!=slaveAgentPort) { - tcpSlaveAgentListener.shutdown(); - tcpSlaveAgentListener = null; - } - if(slaveAgentPort!=-1 && tcpSlaveAgentListener == null) { - String administrativeMonitorId = getClass().getName()+".tcpBind"; - try { - tcpSlaveAgentListener = new TcpSlaveAgentListener(slaveAgentPort); - // remove previous monitor in case of previous error - for(Iterator it = AdministrativeMonitor.all().iterator(); it.hasNext();) { - AdministrativeMonitor am = it.next(); - if (administrativeMonitorId.equals(am.id)) { - it.remove(); + synchronized(tcpSlaveAgentListenerLock) { + // shutdown previous agent if the port has changed + if (tcpSlaveAgentListener != null && tcpSlaveAgentListener.configuredPort != slaveAgentPort) { + tcpSlaveAgentListener.shutdown(); + tcpSlaveAgentListener = null; + } + if (slaveAgentPort != -1 && tcpSlaveAgentListener == null) { + String administrativeMonitorId = getClass().getName() + ".tcpBind"; + try { + tcpSlaveAgentListener = new TcpSlaveAgentListener(slaveAgentPort); + // remove previous monitor in case of previous error + for (Iterator it = AdministrativeMonitor.all().iterator(); it.hasNext(); ) { + AdministrativeMonitor am = it.next(); + if (administrativeMonitorId.equals(am.id)) { + it.remove(); + } } + } catch (BindException e) { + new AdministrativeError(administrativeMonitorId, + "Failed to listen to incoming slave connection", + "Failed to listen to incoming slave connection. Change the port number to solve the problem.", e); } - } catch (BindException e) { - new AdministrativeError(administrativeMonitorId, - "Failed to listen to incoming slave connection", - "Failed to listen to incoming slave connection. Change the port number to solve the problem.",e); } } } From fe7514a5990aeb12bf3baa6c541cbf3a34327aec Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 9 Aug 2015 10:27:52 -0700 Subject: [PATCH 089/256] [maven-release-plugin] prepare release jenkins-1.624 --- cli/pom.xml | 2 +- core/pom.xml | 2 +- plugins/pom.xml | 10 +++++----- pom.xml | 4 ++-- test/pom.xml | 2 +- war/pom.xml | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cli/pom.xml b/cli/pom.xml index e6d03d979b..e3df361f7d 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.624-SNAPSHOT + 1.624 cli diff --git a/core/pom.xml b/core/pom.xml index 9a5a4d0d22..2ff85156f4 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.624-SNAPSHOT + 1.624 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index 064d2a113a..a5279ecbcb 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.624-SNAPSHOT + 1.624 pom +

    What's new in 1.624 (2015/08/09)

    +
      +
    • +

    What's new in 1.623 (2015/08/02)

    No major user-visible changes in this release.

    What's new in 1.622 (2015/07/27)

    From fb820155203807810b3aa7970678d055a4105a6b Mon Sep 17 00:00:00 2001 From: Benjamin Herbert Date: Mon, 10 Aug 2015 16:39:28 +0200 Subject: [PATCH 092/256] Update link to Groovy Codehaus terminated all services - now Groovy's new home is groovy-lang.org. --- core/src/main/resources/lib/hudson/scriptConsole.properties | 2 +- .../src/main/resources/lib/hudson/scriptConsole_da.properties | 2 +- .../src/main/resources/lib/hudson/scriptConsole_de.properties | 2 +- .../src/main/resources/lib/hudson/scriptConsole_es.properties | 2 +- .../src/main/resources/lib/hudson/scriptConsole_fr.properties | 2 +- .../src/main/resources/lib/hudson/scriptConsole_ja.properties | 2 +- .../src/main/resources/lib/hudson/scriptConsole_ko.properties | 2 +- .../main/resources/lib/hudson/scriptConsole_nb_NO.properties | 2 +- .../src/main/resources/lib/hudson/scriptConsole_nl.properties | 2 +- .../src/main/resources/lib/hudson/scriptConsole_pl.properties | 2 +- .../main/resources/lib/hudson/scriptConsole_pt_BR.properties | 4 ++-- .../src/main/resources/lib/hudson/scriptConsole_ru.properties | 2 +- .../main/resources/lib/hudson/scriptConsole_sv_SE.properties | 2 +- .../main/resources/lib/hudson/scriptConsole_zh_TW.properties | 2 +- 14 files changed, 15 insertions(+), 15 deletions(-) diff --git a/core/src/main/resources/lib/hudson/scriptConsole.properties b/core/src/main/resources/lib/hudson/scriptConsole.properties index 518475dc89..69c972a938 100644 --- a/core/src/main/resources/lib/hudson/scriptConsole.properties +++ b/core/src/main/resources/lib/hudson/scriptConsole.properties @@ -21,7 +21,7 @@ # THE SOFTWARE. description=\ - Type in an arbitrary Groovy script and \ + Type in an arbitrary Groovy script and \ execute it on the server. Useful for trouble-shooting and diagnostics. \ Use the \u2018println\u2019 command to see the output (if you use System.out, \ it will go to the server\u2019s stdout, which is harder to see.) Example: diff --git a/core/src/main/resources/lib/hudson/scriptConsole_da.properties b/core/src/main/resources/lib/hudson/scriptConsole_da.properties index 4593448d00..cf1afc4cbb 100644 --- a/core/src/main/resources/lib/hudson/scriptConsole_da.properties +++ b/core/src/main/resources/lib/hudson/scriptConsole_da.properties @@ -23,7 +23,7 @@ Result=Resultat Run=K\u00f8r Script\ Console=Skriptkonsol -description=Indtast et Groovyskript og \ +description=Indtast et Groovyskript og \ k\u00f8r det p\u00e5 serveren. Nyttigt til fejlfinding og diagnostik. \ Benyt ''println'' kommandoen for at se output (hvis du bruger System.out, \ vil output g\u00e5 til serverens stdout, hvilket kan v\u00e6re sv\u00e6rere at finde.) Eksempel: diff --git a/core/src/main/resources/lib/hudson/scriptConsole_de.properties b/core/src/main/resources/lib/hudson/scriptConsole_de.properties index 488a8941a9..df68cd002f 100644 --- a/core/src/main/resources/lib/hudson/scriptConsole_de.properties +++ b/core/src/main/resources/lib/hudson/scriptConsole_de.properties @@ -23,7 +23,7 @@ Script\ Console=Skript-Konsole Result=Ergebnis Run=Ausführen -description=Geben Sie ein beliebiges Groovy-Skript \ +description=Geben Sie ein beliebiges Groovy-Skript \ ein und führen Sie dieses auf dem Server aus. Dies ist nützlich bei der Fehlersuche und zur Diagnostik. \ Verwenden Sie das ''println''-Kommando, um Ausgaben sichtbar zu machen (wenn Sie System.out \ verwenden, gehen die Ausgaben auf die Standardausgabe (STDOUT) des Servers, die schwieriger \ diff --git a/core/src/main/resources/lib/hudson/scriptConsole_es.properties b/core/src/main/resources/lib/hudson/scriptConsole_es.properties index 9531839f14..d7df2acb0d 100644 --- a/core/src/main/resources/lib/hudson/scriptConsole_es.properties +++ b/core/src/main/resources/lib/hudson/scriptConsole_es.properties @@ -21,7 +21,7 @@ # THE SOFTWARE. description=\ - Escribe un ''script'' Groovy script y \ + Escribe un ''script'' Groovy script y \ ejecutaló en el servidor. Es útil para depurar e investigar problemas. \ Usa ''println'' para ver la salida (si usas System.out, se escribirá \ en la salida ''stdout'' del servidor, lo que es más difícil de visualizar). Ejemplo: diff --git a/core/src/main/resources/lib/hudson/scriptConsole_fr.properties b/core/src/main/resources/lib/hudson/scriptConsole_fr.properties index ea256983eb..6f17fa4ae4 100644 --- a/core/src/main/resources/lib/hudson/scriptConsole_fr.properties +++ b/core/src/main/resources/lib/hudson/scriptConsole_fr.properties @@ -23,6 +23,6 @@ Script\ Console=Console de script Result=Résultat Run=Exécuter -description=Vous pouvez saisir ici un script Groovy quelconque pour l\u2019ex\u00E9cuter sur le serveur.
    Utile pour diagnostiquer et r\u00E9soudre des probl\u00E8mes.
    Utilisez la commande "println" pour voir la sortie (si vous utilisez System.out, cela ira vers la sortie standard du serveur, qui est plus complexe \u00E0 retrouver.)
    Par exemple : +description=Vous pouvez saisir ici un script Groovy quelconque pour l\u2019ex\u00E9cuter sur le serveur.
    Utile pour diagnostiquer et r\u00E9soudre des probl\u00E8mes.
    Utilisez la commande "println" pour voir la sortie (si vous utilisez System.out, cela ira vers la sortie standard du serveur, qui est plus complexe \u00E0 retrouver.)
    Par exemple : description2=Toutes les classes de tous les plugins sont visibles. jenkins.*, jenkins.model.*, hudson.*, et hudson.model.* sont pr\u00E9-import\u00E9es. diff --git a/core/src/main/resources/lib/hudson/scriptConsole_ja.properties b/core/src/main/resources/lib/hudson/scriptConsole_ja.properties index da54325180..1360878239 100644 --- a/core/src/main/resources/lib/hudson/scriptConsole_ja.properties +++ b/core/src/main/resources/lib/hudson/scriptConsole_ja.properties @@ -24,7 +24,7 @@ Script\ Console=\u30b9\u30af\u30ea\u30d7\u30c8\u30b3\u30f3\u30bd\u30fc\u30eb Run=\u5b9f\u884c Result=\u7d50\u679c description= \ - \u4efb\u610f\u306eGroovy\u30b9\u30af\u30ea\u30d7\u30c8\u3092\u5165\u529b\u3057\u3066\u3001 \ + \u4efb\u610f\u306eGroovy\u30b9\u30af\u30ea\u30d7\u30c8\u3092\u5165\u529b\u3057\u3066\u3001 \ \u30b5\u30fc\u30d0\u30fc\u4e0a\u3067\u5b9f\u884c\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u30c8\u30e9\u30d6\u30eb\u30b7\u30e5\u30fc\u30c6\u30a3\u30f3\u30b0\u3084\u8a3a\u65ad\u306b\u4fbf\u5229\u3067\u3059\u3002 \ \u51fa\u529b\u3092\u898b\u308b\u306b\u306f''println''\u30b3\u30de\u30f3\u30c9\u3092\u4f7f\u7528\u3057\u307e\u3059 \ (System.out\u3092\u4f7f\u7528\u3059\u308b\u3068\u30b5\u30fc\u30d0\u30fc\u306e\u6a19\u6e96\u51fa\u529b\u306b\u51fa\u529b\u3055\u308c\u307e\u3059\u304c\u3001\u898b\u306b\u304f\u3044\u3067\u3059\uff09\u3002\u4f8b: diff --git a/core/src/main/resources/lib/hudson/scriptConsole_ko.properties b/core/src/main/resources/lib/hudson/scriptConsole_ko.properties index 6e8c7a8bf9..523c9f7126 100644 --- a/core/src/main/resources/lib/hudson/scriptConsole_ko.properties +++ b/core/src/main/resources/lib/hudson/scriptConsole_ko.properties @@ -23,7 +23,7 @@ Result=\uACB0\uACFC Run=\uC2E4\uD589 Script\ Console=\uC2A4\uD06C\uB9BD\uD2B8 \uCF58\uC194 -description=\uC784\uC758\uC758 Groovy\uC2A4\uD06C\uB9BD\uD2B8\uB97C \uC785\uB825\uD558\uC5EC \uC11C\uBC84\uC5D0\uC11C \uC2E4\uD589\uD569\uB2C8\uB2E4.
    \uBB38\uC81C\uD574\uACB0\uACFC \uC9C4\uB2E8\uC2DC\uC5D0 \uC720\uC6A9\uD569\uB2C8\uB2E4. \uCD9C\uB825\uBB3C\uC744 \uBCF4\uB824\uBA74 ''println'' \uBA85\uB839\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.
    (System.out\uB97C \uC0AC\uC6A9\uD558\uBA74 \uC11C\uBC84\uC758 \uD45C\uC900\uCD9C\uB825\uC73C\uB85C \uBCF4\uB0B4\uC9C0\uACE0, \uAC00\uB3C5\uC131\uC774 \uB5A8\uC5B4\uC9D1\uB2C8\uB2E4.)

    +description=\uC784\uC758\uC758 Groovy\uC2A4\uD06C\uB9BD\uD2B8\uB97C \uC785\uB825\uD558\uC5EC \uC11C\uBC84\uC5D0\uC11C \uC2E4\uD589\uD569\uB2C8\uB2E4.
    \uBB38\uC81C\uD574\uACB0\uACFC \uC9C4\uB2E8\uC2DC\uC5D0 \uC720\uC6A9\uD569\uB2C8\uB2E4. \uCD9C\uB825\uBB3C\uC744 \uBCF4\uB824\uBA74 ''println'' \uBA85\uB839\uC744 \uC0AC\uC6A9\uD558\uC138\uC694.
    (System.out\uB97C \uC0AC\uC6A9\uD558\uBA74 \uC11C\uBC84\uC758 \uD45C\uC900\uCD9C\uB825\uC73C\uB85C \uBCF4\uB0B4\uC9C0\uACE0, \uAC00\uB3C5\uC131\uC774 \uB5A8\uC5B4\uC9D1\uB2C8\uB2E4.)

    \uC608\uC81C:
    \uC608\uC81C:
    diff --git a/core/src/main/resources/lib/hudson/scriptConsole_nb_NO.properties b/core/src/main/resources/lib/hudson/scriptConsole_nb_NO.properties index 524bfd281b..ef03bcb2ec 100644 --- a/core/src/main/resources/lib/hudson/scriptConsole_nb_NO.properties +++ b/core/src/main/resources/lib/hudson/scriptConsole_nb_NO.properties @@ -22,7 +22,7 @@ Run=Kj\u00F8r Script\ Console=Skript-konsoll -description=Skriv inn et vilk\u00E5rlig Groovy script og kj\u00F8r det p\u00E5 serveren. Nyttig i forbindelse med feils\u00F8king og diagnostisering. Bruke "println"-kommandoen for \u00E5 se utdataene. (Hvis du bruker System.out havner det i serverens STDOUT, som er vanskeligere \u00E5 se. +description=Skriv inn et vilk\u00E5rlig Groovy script og kj\u00F8r det p\u00E5 serveren. Nyttig i forbindelse med feils\u00F8king og diagnostisering. Bruke "println"-kommandoen for \u00E5 se utdataene. (Hvis du bruker System.out havner det i serverens STDOUT, som er vanskeligere \u00E5 se. Eksempel: println(hudson.model.Hudson.instance.pluginManager.plugins) diff --git a/core/src/main/resources/lib/hudson/scriptConsole_nl.properties b/core/src/main/resources/lib/hudson/scriptConsole_nl.properties index 68b9130c6f..263f9a0fa1 100644 --- a/core/src/main/resources/lib/hudson/scriptConsole_nl.properties +++ b/core/src/main/resources/lib/hudson/scriptConsole_nl.properties @@ -23,4 +23,4 @@ Script\ Console=Scriptconsole Run=Voer uit Result=Resultaat -description=Geef een willekeurig Groovy script in en voer het uit op de server. Dit is nuttig voor troubleshooting en het stellen van diagnoses. Gebruik het "println"-commando om uitvoer te zien (wanneer je System.out gebruikt, gaat de uitvoer naar de stdout van de server, en deze is moeilijker te bekijken.) Bijvoorbeeld: +description=Geef een willekeurig Groovy script in en voer het uit op de server. Dit is nuttig voor troubleshooting en het stellen van diagnoses. Gebruik het "println"-commando om uitvoer te zien (wanneer je System.out gebruikt, gaat de uitvoer naar de stdout van de server, en deze is moeilijker te bekijken.) Bijvoorbeeld: diff --git a/core/src/main/resources/lib/hudson/scriptConsole_pl.properties b/core/src/main/resources/lib/hudson/scriptConsole_pl.properties index bb22871fb6..666edf81bf 100644 --- a/core/src/main/resources/lib/hudson/scriptConsole_pl.properties +++ b/core/src/main/resources/lib/hudson/scriptConsole_pl.properties @@ -3,6 +3,6 @@ Result=Rezultat Run=Wykonaj Script\ Console=Konsola Skrypt\u00F3w -description=Wpisz skrypt Groovy script i wykonaj go na serwerze. U\u017Cyteczne w przypadku problem\u00F3w i diagnostyki. U\u017Cyj komendy ''''println'''' aby zobaczy\u0107 wynik (je\u015Bli u\u017Cyjesz System.out, wynik b\u0119dzie trudniejszy do znalezienia). Przyk\u0142ad: +description=Wpisz skrypt Groovy script i wykonaj go na serwerze. U\u017Cyteczne w przypadku problem\u00F3w i diagnostyki. U\u017Cyj komendy ''''println'''' aby zobaczy\u0107 wynik (je\u015Bli u\u017Cyjesz System.out, wynik b\u0119dzie trudniejszy do znalezienia). Przyk\u0142ad: description2=Wszystkie klasy ze wszystkich dodatk\u00F3w s\u0105 widoczne. jenkins.*, jenkins.model.*, hudson.*, i hudson.model.* s\u0105 wst\u0119pnie zaimportowane. diff --git a/core/src/main/resources/lib/hudson/scriptConsole_pt_BR.properties b/core/src/main/resources/lib/hudson/scriptConsole_pt_BR.properties index 04f4d0a53f..9013530e50 100644 --- a/core/src/main/resources/lib/hudson/scriptConsole_pt_BR.properties +++ b/core/src/main/resources/lib/hudson/scriptConsole_pt_BR.properties @@ -23,11 +23,11 @@ Script\ Console=Console de script Run=Executar Result=Resultado -# Type in an arbitrary Groovy script and \ +# Type in an arbitrary Groovy script and \ # execute it on the server. Useful for trouble-shooting and diagnostics. \ # Use the ''println'' command to see the output (if you use System.out, \ # it will go to the server''s stdout, which is harder to see.) Example: -description=Digite um comando Groovy script qualquer e \ +description=Digite um comando Groovy script qualquer e \ execute-o no servidor. \u00DAtil para resolu\u00E7\u00E3o de problemas e diagn\u00F3sticos. \ Use o comando "println" para ver a sa\u00EDda (se voc\u00EA usa System.out, \ ele ir\u00E1 para o log do servidor, que \u00E9 mais dif\u00EDcil de ver). Exemplo: diff --git a/core/src/main/resources/lib/hudson/scriptConsole_ru.properties b/core/src/main/resources/lib/hudson/scriptConsole_ru.properties index 7149e33861..b0b68ceaf5 100644 --- a/core/src/main/resources/lib/hudson/scriptConsole_ru.properties +++ b/core/src/main/resources/lib/hudson/scriptConsole_ru.properties @@ -23,5 +23,5 @@ Script\ Console=\u041a\u043e\u043d\u0441\u043e\u043b\u044c Result=\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 Run=\u0417\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c -description=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 Groovy \u0441\u043A\u0440\u0438\u043F\u0442 \u0438 \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \u0435\u0433\u043E \u043D\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. \u041F\u043E\u043B\u0435\u0437\u043D\u043E \u043F\u0440\u0438 \u0443\u0441\u0442\u0440\u0430\u043D\u0435\u043D\u0438\u0438 \u043D\u0435\u043F\u043E\u043B\u0430\u0434\u043E\u043A \u0438 \u0434\u0438\u0430\u0433\u043D\u043E\u0441\u0442\u0438\u043A\u0438. \u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 \u043A\u043E\u043C\u0430\u043D\u0434\u0443 "println" \u0434\u043B\u044F \u043F\u0435\u0447\u0430\u0442\u0438 \u0432 \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u044B\u0439 \u0432\u044B\u0432\u043E\u0434 (\u0435\u0441\u043B\u0438 \u0432\u044B \u0432\u043E\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0435\u0441\u044C System.out, \u0442\u043E \u0432\u044B\u0432\u043E\u0434 \u043F\u043E\u0439\u0434\u0451\u0442 \u0432 stdout \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0441\u043B\u043E\u0436\u043D\u0435\u0435 \u0443\u0432\u0438\u0434\u0435\u0442\u044C). \u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: +description=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 Groovy \u0441\u043A\u0440\u0438\u043F\u0442 \u0438 \u0432\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \u0435\u0433\u043E \u043D\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435. \u041F\u043E\u043B\u0435\u0437\u043D\u043E \u043F\u0440\u0438 \u0443\u0441\u0442\u0440\u0430\u043D\u0435\u043D\u0438\u0438 \u043D\u0435\u043F\u043E\u043B\u0430\u0434\u043E\u043A \u0438 \u0434\u0438\u0430\u0433\u043D\u043E\u0441\u0442\u0438\u043A\u0438. \u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439\u0442\u0435 \u043A\u043E\u043C\u0430\u043D\u0434\u0443 "println" \u0434\u043B\u044F \u043F\u0435\u0447\u0430\u0442\u0438 \u0432 \u0441\u0442\u0430\u043D\u0434\u0430\u0440\u0442\u043D\u044B\u0439 \u0432\u044B\u0432\u043E\u0434 (\u0435\u0441\u043B\u0438 \u0432\u044B \u0432\u043E\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442\u0435\u0441\u044C System.out, \u0442\u043E \u0432\u044B\u0432\u043E\u0434 \u043F\u043E\u0439\u0434\u0451\u0442 \u0432 stdout \u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u043A\u043E\u0442\u043E\u0440\u044B\u0439 \u0441\u043B\u043E\u0436\u043D\u0435\u0435 \u0443\u0432\u0438\u0434\u0435\u0442\u044C). \u041D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: description2=\u0412\u0441\u0435 \u043A\u043B\u0430\u0441\u0441\u044B \u0438\u0437 \u0432\u0441\u0435\u0445 \u043F\u043B\u0430\u0433\u0438\u043D\u043E\u0432 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B. jenkins.*, jenkins.model.*, hudson.* \u0438 hudson.model.* \u0443\u0436\u0435 \u0438\u043C\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u044B \u043F\u043E \u0443\u043C\u043E\u043B\u0447\u0430\u043D\u0438\u044E. diff --git a/core/src/main/resources/lib/hudson/scriptConsole_sv_SE.properties b/core/src/main/resources/lib/hudson/scriptConsole_sv_SE.properties index 1710048f28..eb6893c691 100644 --- a/core/src/main/resources/lib/hudson/scriptConsole_sv_SE.properties +++ b/core/src/main/resources/lib/hudson/scriptConsole_sv_SE.properties @@ -23,5 +23,5 @@ Result=Resultat Run=K\u00F6r Script\ Console=Skriptkonsoll -description=Skriv in ett godtyckligt Groovy skript och k\u00F6r den p\u00E5 noden. Detta \u00E4r anv\u00E4ndbart vid fels\u00F6kning och diagnostik. Anv\u00E4nd''''println''''kommandot f\u00F6r att se resultatet (om du anv\u00E4nder System.out kommer det att g\u00E5 till serverns standard ut, som \u00E4r sv\u00E5rare att se.) Exempel: +description=Skriv in ett godtyckligt Groovy skript och k\u00F6r den p\u00E5 noden. Detta \u00E4r anv\u00E4ndbart vid fels\u00F6kning och diagnostik. Anv\u00E4nd''''println''''kommandot f\u00F6r att se resultatet (om du anv\u00E4nder System.out kommer det att g\u00E5 till serverns standard ut, som \u00E4r sv\u00E5rare att se.) Exempel: description2=Alla klasser fr\u00E5n pluginet \u00E4r synliga. jenkins.*, jenkins.model.*, hudson.*, and hudson.model.* are pre-imported. diff --git a/core/src/main/resources/lib/hudson/scriptConsole_zh_TW.properties b/core/src/main/resources/lib/hudson/scriptConsole_zh_TW.properties index 0a474875c7..6e968873db 100644 --- a/core/src/main/resources/lib/hudson/scriptConsole_zh_TW.properties +++ b/core/src/main/resources/lib/hudson/scriptConsole_zh_TW.properties @@ -23,7 +23,7 @@ Script\ Console=Script \u4e3b\u63a7\u53f0 description=\ - \u8f38\u5165\u4efb\u610f\u7684 Groovy Script\uff0c\u5728\u4f3a\u670d\u5668\u4e0a\u57f7\u884c\u3002\ + \u8f38\u5165\u4efb\u610f\u7684 Groovy Script\uff0c\u5728\u4f3a\u670d\u5668\u4e0a\u57f7\u884c\u3002\ \u7591\u96e3\u6392\u89e3\u6216\u8a3a\u65b7\u6642\u5f88\u6709\u7528\u3002\u4f7f\u7528 "println" \u6307\u4ee4\u53ef\u4ee5\u770b\u5230\u8f38\u51fa\u7d50\u679c \ (\u5982\u679c\u60a8\u4f7f\u7528 System.out\uff0c\u5c07\u8f38\u51fa\u5230\u4f3a\u670d\u5668\u4e0a\u7684 stdout\uff0c\u6703\u6bd4\u8f03\u96e3\u770b\u5230)\u3002\u7bc4\u4f8b: description2=\u6240\u6709\u5916\u639B\u7A0B\u5F0F\u7684 class \u90FD\u53EF\u4EE5\u4F7F\u7528\u3002\u5DF2\u9810\u5148 import \u4E86 jenkins.*, jenkins.model.*, hudson.* \u53CA hudson.model.* \u7B49 package\u3002 From 4b9318f5046834e9615807b7db5757a63c015af5 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Mon, 10 Aug 2015 20:49:49 +0200 Subject: [PATCH 093/256] Noting #1779 --- changelog.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/changelog.html b/changelog.html index 7cc706e100..0927d1cfb7 100644 --- a/changelog.html +++ b/changelog.html @@ -60,7 +60,9 @@ Upcoming changes

What's new in 1.624 (2015/08/09)

    -
  • +
  • + Allow more job types to use a custom "Build Now" text. + (issue 26147)

What's new in 1.623 (2015/08/02)

No major user-visible changes in this release.

@@ -71,7 +73,7 @@ Upcoming changes (PR 1770)
  • Node provisioner may fail to correctly indicate that provisioning was finished. - (JENKINS-29568) + (issue 29568)

    What's new in 1.621 (2015/07/19)

      From d58903558e9047cb6dde4a64f15e587de6972278 Mon Sep 17 00:00:00 2001 From: Veres Lajos Date: Sat, 8 Aug 2015 11:12:31 +0100 Subject: [PATCH 094/256] typofix - https://github.com/vlajos/misspell_fixer --- core/src/main/java/hudson/FilePath.java | 2 +- core/src/main/java/hudson/FileSystemProvisioner.java | 2 +- .../java/hudson/FileSystemProvisionerDescriptor.java | 2 +- core/src/main/java/hudson/Functions.java | 2 +- core/src/main/java/hudson/PluginWrapper.java | 2 +- core/src/main/java/hudson/cli/CloneableCLICommand.java | 2 +- .../java/hudson/model/ChoiceParameterDefinition.java | 10 +++++++--- core/src/main/java/hudson/model/Computer.java | 4 ++-- core/src/main/java/hudson/model/UsageStatistics.java | 4 ++-- core/src/main/java/hudson/os/SU.java | 4 ++-- core/src/main/java/hudson/scheduler/CronTab.java | 2 +- core/src/main/java/hudson/security/ACL.java | 2 +- core/src/main/java/hudson/security/SecurityRealm.java | 2 +- core/src/main/java/hudson/tasks/Maven.java | 2 +- core/src/main/java/hudson/util/ChartUtil.java | 4 ++-- .../src/main/java/hudson/util/DoubleLaunchChecker.java | 2 +- .../main/java/hudson/util/QuotedStringTokenizer.java | 6 +++--- core/src/main/java/hudson/util/jna/DotNet.java | 2 +- .../jenkins/model/JenkinsLocationConfiguration.java | 4 ++-- .../java/jenkins/slaves/restarter/SlaveRestarter.java | 2 +- .../jenkins/security/s2m/filepath-filter.conf | 2 +- core/src/site/markdown/index.md | 2 +- .../test/java/hudson/model/ParametersActionTest.java | 2 +- .../test/java/hudson/util/ArgumentListBuilderTest.java | 4 ++-- .../java/org/jvnet/hudson/test/ExtractResourceSCM.java | 2 +- .../hudson/cli/SetBuildDisplayNameCommandTest.java | 2 +- test/src/test/java/hudson/model/JobQueueTest.java | 4 ++-- .../test/java/hudson/model/MyViewsPropertyTest.java | 2 +- test/src/test/java/hudson/model/SimpleJobTest.java | 2 +- test/src/test/java/hudson/model/UserTest.java | 2 +- test/src/test/java/hudson/model/ViewTest.java | 2 +- .../java/hudson/model/queue/WideExecutionTest.java | 2 +- test/src/test/java/lib/form/RepeatableTest.java | 2 +- translation-tool.pl | 2 +- .../webapp/help/project-config/custom-workspace.html | 2 +- 35 files changed, 50 insertions(+), 46 deletions(-) diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index d2778ba37e..ca137d2e11 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -175,7 +175,7 @@ import org.jenkinsci.remoting.RoleSensitive; * * *

      - * When {@link FileCallable} is transfered to a remote node, it will be done so + * When {@link FileCallable} is transferred to a remote node, it will be done so * by using the same Java serialization scheme that the remoting module uses. * See {@link Channel} for more about this. * diff --git a/core/src/main/java/hudson/FileSystemProvisioner.java b/core/src/main/java/hudson/FileSystemProvisioner.java index 15932a1dca..bbb98f5e9d 100644 --- a/core/src/main/java/hudson/FileSystemProvisioner.java +++ b/core/src/main/java/hudson/FileSystemProvisioner.java @@ -238,7 +238,7 @@ public abstract class FileSystemProvisioner implements ExtensionPoint, Describab @Extension public static final class DescriptorImpl extends FileSystemProvisionerDescriptor { public boolean discard(FilePath ws, TaskListener listener) throws IOException, InterruptedException { - // the default provisioner doens't do anything special, + // the default provisioner does not do anything special, // so allow other types to manage it return false; } diff --git a/core/src/main/java/hudson/FileSystemProvisionerDescriptor.java b/core/src/main/java/hudson/FileSystemProvisionerDescriptor.java index 2cb0506fa9..4827366d36 100644 --- a/core/src/main/java/hudson/FileSystemProvisionerDescriptor.java +++ b/core/src/main/java/hudson/FileSystemProvisionerDescriptor.java @@ -39,7 +39,7 @@ public abstract class FileSystemProvisionerDescriptor extends Descriptor * Because users may modify the file system behind Hudson, and slaves may come and go when - * configuration changes hapen, in general case Hudson is unable to keep track of which jobs + * configuration changes happen, in general case Hudson is unable to keep track of which jobs * have workspaces in which slaves. * *

      diff --git a/core/src/main/java/hudson/Functions.java b/core/src/main/java/hudson/Functions.java index bcdc69f7f3..4ecd7721d8 100644 --- a/core/src/main/java/hudson/Functions.java +++ b/core/src/main/java/hudson/Functions.java @@ -1385,7 +1385,7 @@ public class Functions { /** * If the value exists, return that value. Otherwise return the default value. *

      - * Starting 1.294, JEXL supports the elvis operator "x?:y" that supercedes this. + * Starting 1.294, JEXL supports the elvis operator "x?:y" that supersedes this. * * @since 1.150 */ diff --git a/core/src/main/java/hudson/PluginWrapper.java b/core/src/main/java/hudson/PluginWrapper.java index aa683e630f..50fad48550 100644 --- a/core/src/main/java/hudson/PluginWrapper.java +++ b/core/src/main/java/hudson/PluginWrapper.java @@ -63,7 +63,7 @@ import javax.annotation.CheckForNull; * for Jenkins to control {@link Plugin}. * *

      - * A plug-in is packaged into a jar file whose extension is ".jpi" (or ".hpi" for backward compatability), + * A plug-in is packaged into a jar file whose extension is ".jpi" (or ".hpi" for backward compatibility), * A plugin needs to have a special manifest entry to identify what it is. * *

      diff --git a/core/src/main/java/hudson/cli/CloneableCLICommand.java b/core/src/main/java/hudson/cli/CloneableCLICommand.java index 7fb3b96dd3..f6a4c60b02 100644 --- a/core/src/main/java/hudson/cli/CloneableCLICommand.java +++ b/core/src/main/java/hudson/cli/CloneableCLICommand.java @@ -26,7 +26,7 @@ package hudson.cli; /** * {@link Cloneable} {@link CLICommand}. * - * Uses {@link #clone()} instead of "new" to create a copy for exection. + * Uses {@link #clone()} instead of "new" to create a copy for execution. * * @author Kohsuke Kawaguchi */ diff --git a/core/src/main/java/hudson/model/ChoiceParameterDefinition.java b/core/src/main/java/hudson/model/ChoiceParameterDefinition.java index c13137d62a..0bd4b60ab3 100644 --- a/core/src/main/java/hudson/model/ChoiceParameterDefinition.java +++ b/core/src/main/java/hudson/model/ChoiceParameterDefinition.java @@ -17,20 +17,24 @@ import java.util.Arrays; * @author huybrechts */ public class ChoiceParameterDefinition extends SimpleParameterDefinition { - public static final String CHOICES_DELIMETER = "\\r?\\n"; + public static final String CHOICES_DELIMITER = "\\r?\\n"; + + @Deprecated + public static final String CHOICES_DELIMETER = CHOICES_DELIMITER; + private final List choices; private final String defaultValue; public static boolean areValidChoices(String choices) { String strippedChoices = choices.trim(); - return !StringUtils.isEmpty(strippedChoices) && strippedChoices.split(CHOICES_DELIMETER).length > 0; + return !StringUtils.isEmpty(strippedChoices) && strippedChoices.split(CHOICES_DELIMITER).length > 0; } @DataBoundConstructor public ChoiceParameterDefinition(String name, String choices, String description) { super(name, description); - this.choices = Arrays.asList(choices.split(CHOICES_DELIMETER)); + this.choices = Arrays.asList(choices.split(CHOICES_DELIMITER)); defaultValue = null; } diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index 4b2d035049..5bc8bb7cdd 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -1566,8 +1566,8 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces if (m.matches()) { File newLocation = new File(dir, "logs/slaves/" + m.group(1) + "/slave.log" + Util.fixNull(m.group(2))); newLocation.getParentFile().mkdirs(); - boolean relocationSuccessfull=f.renameTo(newLocation); - if (relocationSuccessfull) { // The operation will fail if mkdir fails + boolean relocationSuccessful=f.renameTo(newLocation); + if (relocationSuccessful) { // The operation will fail if mkdir fails LOGGER.log(Level.INFO, "Relocated log file {0} to {1}",new Object[] {f.getPath(),newLocation.getPath()}); } else { LOGGER.log(Level.WARNING, "Cannot relocate log file {0} to {1}",new Object[] {f.getPath(),newLocation.getPath()}); diff --git a/core/src/main/java/hudson/model/UsageStatistics.java b/core/src/main/java/hudson/model/UsageStatistics.java index 805403216b..4d2cde5411 100644 --- a/core/src/main/java/hudson/model/UsageStatistics.java +++ b/core/src/main/java/hudson/model/UsageStatistics.java @@ -197,10 +197,10 @@ public class UsageStatistics extends PageDecorator { } /** - * Assymetric cipher is slow and in case of Sun RSA implementation it can only encyrypt the first block. + * Asymmetric cipher is slow and in case of Sun RSA implementation it can only encyrypt the first block. * * So first create a symmetric key, then place this key in the beginning of the stream by encrypting it - * with the assymetric cipher. The rest of the stream will be encrypted by a symmetric cipher. + * with the asymmetric cipher. The rest of the stream will be encrypted by a symmetric cipher. */ public static final class CombinedCipherOutputStream extends FilterOutputStream { public CombinedCipherOutputStream(OutputStream out, Cipher asym, String algorithm) throws IOException, GeneralSecurityException { diff --git a/core/src/main/java/hudson/os/SU.java b/core/src/main/java/hudson/os/SU.java index 6a2b8abfa2..5998d366c0 100644 --- a/core/src/main/java/hudson/os/SU.java +++ b/core/src/main/java/hudson/os/SU.java @@ -62,7 +62,7 @@ public abstract class SU { } /** - * Returns a {@link VirtualChannel} that's connected to the priviledge-escalated environment. + * Returns a {@link VirtualChannel} that's connected to the privilege-escalated environment. * * @param listener * What this method is doing (such as what process it's invoking) will be sent here. @@ -122,7 +122,7 @@ public abstract class SU { } /** - * Starts a new priviledge-escalated environment, execute a closure, and shut it down. + * Starts a new privilege-escalated environment, execute a closure, and shut it down. */ public static V execute(TaskListener listener, String rootUsername, String rootPassword, final Callable closure) throws T, IOException, InterruptedException { VirtualChannel ch = start(listener, rootUsername, rootPassword); diff --git a/core/src/main/java/hudson/scheduler/CronTab.java b/core/src/main/java/hudson/scheduler/CronTab.java index dd8e0efa9d..d289dc32ef 100644 --- a/core/src/main/java/hudson/scheduler/CronTab.java +++ b/core/src/main/java/hudson/scheduler/CronTab.java @@ -92,7 +92,7 @@ public final class CronTab { /** * @param timezone - * Used to schedule cron in a differnt timezone. Null to use the default system + * Used to schedule cron in a different timezone. Null to use the default system * timezone * @since 1.615 */ diff --git a/core/src/main/java/hudson/security/ACL.java b/core/src/main/java/hudson/security/ACL.java index b0ed675d8b..e4736cbe9e 100644 --- a/core/src/main/java/hudson/security/ACL.java +++ b/core/src/main/java/hudson/security/ACL.java @@ -127,7 +127,7 @@ public abstract class ACL { * *

      * This doesn't need to be included in {@link Authentication#getAuthorities()}, - * but {@link ACL} is responsible for checking it nontheless, as if it was the + * but {@link ACL} is responsible for checking it nonetheless, as if it was the * last entry in the granted authority. */ public static final Sid EVERYONE = new Sid() { diff --git a/core/src/main/java/hudson/security/SecurityRealm.java b/core/src/main/java/hudson/security/SecurityRealm.java index 3c598632ab..0621d4a440 100644 --- a/core/src/main/java/hudson/security/SecurityRealm.java +++ b/core/src/main/java/hudson/security/SecurityRealm.java @@ -357,7 +357,7 @@ public abstract class SecurityRealm extends AbstractDescribableImpl - * This set up error occasionally happens especialy when the user is trying to reassign the context path of the app, + * This set up error occasionally happens especially when the user is trying to reassign the context path of the app, * and it results in a hard-to-diagnose error, so we actively check this. * *

      diff --git a/core/src/main/java/hudson/util/QuotedStringTokenizer.java b/core/src/main/java/hudson/util/QuotedStringTokenizer.java index 248f1ac954..e33b15ccab 100644 --- a/core/src/main/java/hudson/util/QuotedStringTokenizer.java +++ b/core/src/main/java/hudson/util/QuotedStringTokenizer.java @@ -44,7 +44,7 @@ import java.util.ArrayList; /** StringTokenizer with Quoting support. * * This class is a copy of the java.util.StringTokenizer API and - * the behaviour is the same, except that single and doulbe quoted + * the behaviour is the same, except that single and double quoted * string values are recognized. * Delimiters within quotes are not considered delimiters. * Quotes can be escaped with '\'. @@ -328,7 +328,7 @@ public class QuotedStringTokenizer /* ------------------------------------------------------------ */ /** Quote a string. * The string is quoted only if quoting is required due to - * embeded delimiters, quote characters or the + * embedded delimiters, quote characters or the * empty string. * @param s The string to quote. * @return quoted string @@ -358,7 +358,7 @@ public class QuotedStringTokenizer /* ------------------------------------------------------------ */ /** Quote a string. * The string is quoted only if quoting is required due to - * embeded delimiters, quote characters or the + * embedded delimiters, quote characters or the * empty string. * @param s The string to quote. * @return quoted string diff --git a/core/src/main/java/hudson/util/jna/DotNet.java b/core/src/main/java/hudson/util/jna/DotNet.java index 4011767b19..4d820149ca 100644 --- a/core/src/main/java/hudson/util/jna/DotNet.java +++ b/core/src/main/java/hudson/util/jna/DotNet.java @@ -46,7 +46,7 @@ public class DotNet { try { // see http://support.microsoft.com/?scid=kb;en-us;315291 for the basic algorithm // observation in my registry shows that the actual key name can be things like "v2.0 SP1" - // or "v2.0.50727", so the regexp is written to accomodate this. + // or "v2.0.50727", so the regexp is written to accommodate this. RegistryKey key = RegistryKey.LOCAL_MACHINE.openReadonly("SOFTWARE\\Microsoft\\.NETFramework"); try { for( String keyName : key.getSubKeys() ) { diff --git a/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java b/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java index d9ed205ef0..f626750deb 100644 --- a/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java +++ b/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java @@ -77,7 +77,7 @@ public class JenkinsLocationConfiguration extends GlobalConfiguration { /** * Gets the service administrator e-mail address. - * @return Admin adress or "address not configured" stub + * @return Admin address or "address not configured" stub */ public @Nonnull String getAdminAddress() { String v = adminAddress; @@ -92,7 +92,7 @@ public class JenkinsLocationConfiguration extends GlobalConfiguration { public void setAdminAddress(@CheckForNull String adminAddress) { String address = Util.nullify(adminAddress); if(address != null && address.startsWith("\"") && address.endsWith("\"")) { - // some users apparently quote the whole thing. Don't konw why + // some users apparently quote the whole thing. Don't know why // anyone does this, but it's a machine's job to forgive human mistake address = address.substring(1,address.length()-1); } diff --git a/core/src/main/java/jenkins/slaves/restarter/SlaveRestarter.java b/core/src/main/java/jenkins/slaves/restarter/SlaveRestarter.java index e0c7c2f912..506c1a6806 100644 --- a/core/src/main/java/jenkins/slaves/restarter/SlaveRestarter.java +++ b/core/src/main/java/jenkins/slaves/restarter/SlaveRestarter.java @@ -11,7 +11,7 @@ import java.util.logging.Logger; * Extension point to control how to restart JNLP slave when it loses the connection with the master. * *

      - * Objects are instantiated on the master, then transfered to a slave via serialization. + * Objects are instantiated on the master, then transferred to a slave via serialization. * * @author Kohsuke Kawaguchi */ diff --git a/core/src/main/resources/jenkins/security/s2m/filepath-filter.conf b/core/src/main/resources/jenkins/security/s2m/filepath-filter.conf index faa7cffa16..c1883cc562 100644 --- a/core/src/main/resources/jenkins/security/s2m/filepath-filter.conf +++ b/core/src/main/resources/jenkins/security/s2m/filepath-filter.conf @@ -36,5 +36,5 @@ allow create,mkdirs,read,stat,write /.+ # cobertura also writes out annotated sources to a dir under the job: allow create,mkdirs,read,stat,write /jobs/.+/cobertura.* -# all the other accesses that aren't specified here will be left upto other rules in this directory. +# all the other accesses that aren't specified here will be left up to other rules in this directory. # if no rules in those other files matches, then the access will be rejected. diff --git a/core/src/site/markdown/index.md b/core/src/site/markdown/index.md index 40ee40c80b..a915159a00 100644 --- a/core/src/site/markdown/index.md +++ b/core/src/site/markdown/index.md @@ -1 +1 @@ -Collection of Maven auto-generated reports. The primary interest is probably [Jelly tag libary reference](jelly-taglib-ref.html). +Collection of Maven auto-generated reports. The primary interest is probably [Jelly tag library reference](jelly-taglib-ref.html). diff --git a/core/src/test/java/hudson/model/ParametersActionTest.java b/core/src/test/java/hudson/model/ParametersActionTest.java index 8b96940a7b..d9b6e63e69 100644 --- a/core/src/test/java/hudson/model/ParametersActionTest.java +++ b/core/src/test/java/hudson/model/ParametersActionTest.java @@ -89,7 +89,7 @@ public class ParametersActionTest { @Test @Issue("JENKINS-15094") - public void checkNullParamaterValues() { + public void checkNullParameterValues() { SubTask subtask = mock(SubTask.class); Build build = mock(Build.class); diff --git a/core/src/test/java/hudson/util/ArgumentListBuilderTest.java b/core/src/test/java/hudson/util/ArgumentListBuilderTest.java index 8bef4df9fd..7afe8c670e 100644 --- a/core/src/test/java/hudson/util/ArgumentListBuilderTest.java +++ b/core/src/test/java/hudson/util/ArgumentListBuilderTest.java @@ -41,7 +41,7 @@ public class ArgumentListBuilderTest { builder.add("arg"); builder.add("other", "arguments"); - assertFalse("There shouldnt be any masked arguments", builder.hasMaskedArguments()); + assertFalse("There should not be any masked arguments", builder.hasMaskedArguments()); boolean[] array = builder.toMaskArray(); assertNotNull("The mask array should not be null", array); assertThat("The mask array was incorrect", array, is(new boolean[] { false, false, false })); @@ -166,7 +166,7 @@ public class ArgumentListBuilderTest { ArgumentListBuilder builder = new ArgumentListBuilder(); builder.addKeyValuePairs(null, KEY_VALUES); - assertFalse("There shouldnt be any masked arguments", builder.hasMaskedArguments()); + assertFalse("There should not be any masked arguments", builder.hasMaskedArguments()); boolean[] array = builder.toMaskArray(); assertNotNull("The mask array should not be null", array); assertThat("The mask array was incorrect", array, is(new boolean[] { false, false, false })); diff --git a/test/src/main/java/org/jvnet/hudson/test/ExtractResourceSCM.java b/test/src/main/java/org/jvnet/hudson/test/ExtractResourceSCM.java index 743eecde22..495e88ee61 100644 --- a/test/src/main/java/org/jvnet/hudson/test/ExtractResourceSCM.java +++ b/test/src/main/java/org/jvnet/hudson/test/ExtractResourceSCM.java @@ -57,7 +57,7 @@ public class ExtractResourceSCM extends NullSCM { /** * with this constructor your zip can contains a folder - * more usefull to create a project test zip foo.zip foo + * more useful to create a project test zip foo.zip foo * @param zip * @param parentFolder */ diff --git a/test/src/test/java/hudson/cli/SetBuildDisplayNameCommandTest.java b/test/src/test/java/hudson/cli/SetBuildDisplayNameCommandTest.java index 7b4b8f942a..f706fa2b70 100644 --- a/test/src/test/java/hudson/cli/SetBuildDisplayNameCommandTest.java +++ b/test/src/test/java/hudson/cli/SetBuildDisplayNameCommandTest.java @@ -62,7 +62,7 @@ public class SetBuildDisplayNameCommandTest { assertThat(result, failedWith(-1)); } - @Test public void setDescriptionSuccesfully() throws Exception { + @Test public void setDescriptionSuccessfully() throws Exception { FreeStyleProject job = j.createFreeStyleProject("project"); FreeStyleBuild build = job.scheduleBuild2(0).get(); diff --git a/test/src/test/java/hudson/model/JobQueueTest.java b/test/src/test/java/hudson/model/JobQueueTest.java index 4c92d2032d..41af7e4d1e 100644 --- a/test/src/test/java/hudson/model/JobQueueTest.java +++ b/test/src/test/java/hudson/model/JobQueueTest.java @@ -89,7 +89,7 @@ public class JobQueueTest { assertTrue(j.jenkins.getQueue().getItem(project) instanceof BlockedItem); //check is it is blocked } else { - fail("The maximum attemps for checking if the job is in POST_PRODUCTION State have reached"); + fail("The maximum attempts for checking if the job is in POST_PRODUCTION State have reached"); } count=0; while(!JobQueueTest.fireFinalizeFlag && count<100) { @@ -104,7 +104,7 @@ public class JobQueueTest { assertFalse(j.jenkins.getQueue().getItem(project) instanceof BlockedItem); } else { - fail("The maximum attemps for checking if the job is in COMPLETED State have reached"); + fail("The maximum attempts for checking if the job is in COMPLETED State have reached"); } Thread.sleep(1000); //Sleep till job completes. } diff --git a/test/src/test/java/hudson/model/MyViewsPropertyTest.java b/test/src/test/java/hudson/model/MyViewsPropertyTest.java index 4c94f1bd50..666a383d20 100644 --- a/test/src/test/java/hudson/model/MyViewsPropertyTest.java +++ b/test/src/test/java/hudson/model/MyViewsPropertyTest.java @@ -186,7 +186,7 @@ public class MyViewsPropertyTest { user.addProperty(property); View view = new ListView("foo", property); property.addView(view); - assertTrue("Property should contians view " + view.name, property.getViews().contains(view)); + assertTrue("Property should contains view " + view.name, property.getViews().contains(view)); User.reload(); user = User.get("User"); property = user.getProperty(property.getClass()); diff --git a/test/src/test/java/hudson/model/SimpleJobTest.java b/test/src/test/java/hudson/model/SimpleJobTest.java index ad26b57e68..3f3f6f4010 100644 --- a/test/src/test/java/hudson/model/SimpleJobTest.java +++ b/test/src/test/java/hudson/model/SimpleJobTest.java @@ -102,7 +102,7 @@ public class SimpleJobTest { TestBuild lastBuild = new TestBuild(project, Result.FAILURE, 50, previousBuild); runs.put(1, lastBuild); - // failed builds must not be used, if there are succesfulBuilds available. + // failed builds must not be used, if there are successfulBuilds available. assertEquals(1, project.getEstimatedDuration()); } diff --git a/test/src/test/java/hudson/model/UserTest.java b/test/src/test/java/hudson/model/UserTest.java index 800d1862a9..c6a41de76d 100644 --- a/test/src/test/java/hudson/model/UserTest.java +++ b/test/src/test/java/hudson/model/UserTest.java @@ -302,7 +302,7 @@ public class UserTest { assertNotNull("User should not be null.", user); user.clear(); user = User.get("John Smith", false, Collections.emptyMap()); - assertNull("User shoudl be null", user); + assertNull("User should be null", user); } @Test diff --git a/test/src/test/java/hudson/model/ViewTest.java b/test/src/test/java/hudson/model/ViewTest.java index 1b37513e6c..68c370c295 100644 --- a/test/src/test/java/hudson/model/ViewTest.java +++ b/test/src/test/java/hudson/model/ViewTest.java @@ -362,7 +362,7 @@ public class ViewTest { ListView view2 = listView("foo"); try{ view2.rename("renamed"); - fail("Attemt to rename job with a name used by another view with the same owner should throw exception"); + fail("Attempt to rename job with a name used by another view with the same owner should throw exception"); } catch(Exception Exception){ } diff --git a/test/src/test/java/hudson/model/queue/WideExecutionTest.java b/test/src/test/java/hudson/model/queue/WideExecutionTest.java index f5ac35c03e..304b6ac38d 100644 --- a/test/src/test/java/hudson/model/queue/WideExecutionTest.java +++ b/test/src/test/java/hudson/model/queue/WideExecutionTest.java @@ -50,7 +50,7 @@ public class WideExecutionTest { public JenkinsRule j = new JenkinsRule(); @TestExtension - public static class Contributer extends SubTaskContributor { + public static class Contributor extends SubTaskContributor { public Collection forProject(final AbstractProject p) { return Collections.singleton(new AbstractSubTask() { private final AbstractSubTask outer = this; diff --git a/test/src/test/java/lib/form/RepeatableTest.java b/test/src/test/java/lib/form/RepeatableTest.java index 48ee7bf5e3..9807f14f5a 100644 --- a/test/src/test/java/lib/form/RepeatableTest.java +++ b/test/src/test/java/lib/form/RepeatableTest.java @@ -340,7 +340,7 @@ public class RepeatableTest extends HudsonTestCase { } } - /** Tests nested repeatable and use of @DataBoundContructor to process formData */ + /** Tests nested repeatable and use of @DataBoundConstructor to process formData */ public void testNested() throws Exception { HtmlPage p = createWebClient().goTo("self/testNested"); HtmlForm f = p.getFormByName("config"); diff --git a/translation-tool.pl b/translation-tool.pl index 95ca0c59de..977ba736b1 100755 --- a/translation-tool.pl +++ b/translation-tool.pl @@ -1,7 +1,7 @@ #!/usr/bin/perl -w # The MIT License # -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributers +# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributors # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/war/src/main/webapp/help/project-config/custom-workspace.html b/war/src/main/webapp/help/project-config/custom-workspace.html index b9b7f312f0..581f5b1ba2 100644 --- a/war/src/main/webapp/help/project-config/custom-workspace.html +++ b/war/src/main/webapp/help/project-config/custom-workspace.html @@ -18,7 +18,7 @@ If you are in a distributed build environment, unless you tie a job to a specific node, Jenkins may still move around jobs to different slaves. Sometimes this is desirable, sometimes this is not. Also, you can map multiple projects to have the same workspace, but if you do so, make sure concurrent executions - of those jobs won't have nasty interferance with each other. + of those jobs won't have nasty interference with each other.

      If this path is relative, it's resolved against the "remote FS root" directory of the slave, or $JENKINS_HOME From 697fe70f59040e147d16840c0b31dba9f150b4b4 Mon Sep 17 00:00:00 2001 From: George Gastaldi Date: Thu, 13 Aug 2015 11:43:41 -0300 Subject: [PATCH 095/256] Fixed typos in pt_BR and pt_PT translations --- .../hudson/model/AbstractBuild/index_pt_BR.properties | 6 +++--- .../hudson/model/AbstractBuild/index_pt_PT.properties | 6 +++--- .../hudson/model/AbstractBuild/sidepanel_pt_PT.properties | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/src/main/resources/hudson/model/AbstractBuild/index_pt_BR.properties b/core/src/main/resources/hudson/model/AbstractBuild/index_pt_BR.properties index e601d09c88..7e954f6854 100644 --- a/core/src/main/resources/hudson/model/AbstractBuild/index_pt_BR.properties +++ b/core/src/main/resources/hudson/model/AbstractBuild/index_pt_BR.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Reginaldo L. Russinholi, Cleiber Silva, Fernando Boaglio +# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Reginaldo L. Russinholi, Cleiber Silva, Fernando Boaglio, George Gastaldi # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -21,9 +21,9 @@ # THE SOFTWARE. startedAgo=Iniciado {0} atr\u00e1s -Build\ Artifacts=Artefatos da builds +Build\ Artifacts=Artefatos da build Changes\ in\ dependency=Mudan\u00E7as na depend\u00EAncia -beingExecuted=Tempo de execu\u00E7\u00E3o da builds {0} +beingExecuted=Tempo de execu\u00E7\u00E3o da build {0} detail=detalhe Not\ yet\ determined=Ainda n\u00e3o determinado Failed\ to\ determine=Falhou ao determinar diff --git a/core/src/main/resources/hudson/model/AbstractBuild/index_pt_PT.properties b/core/src/main/resources/hudson/model/AbstractBuild/index_pt_PT.properties index cb85ec5b93..8a54bd9d03 100644 --- a/core/src/main/resources/hudson/model/AbstractBuild/index_pt_PT.properties +++ b/core/src/main/resources/hudson/model/AbstractBuild/index_pt_PT.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2010, Sun Microsystems, Inc. +# Copyright (c) 2004-2010, Sun Microsystems, Inc., George Gastaldi # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -20,8 +20,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build=Contru\u00E7\u00E3o -Build\ Artifacts=Contru\u00E7\u00E3o de artefactos +Build=Constru\u00E7\u00E3o +Build\ Artifacts=Constru\u00E7\u00E3o de artefactos Took=Demorou beingExecuted=Compila\u00E7\u00E3o a ser executada h\u00E1 {0} on=em diff --git a/core/src/main/resources/hudson/model/AbstractBuild/sidepanel_pt_PT.properties b/core/src/main/resources/hudson/model/AbstractBuild/sidepanel_pt_PT.properties index 70b25b6c11..8695d88bf5 100644 --- a/core/src/main/resources/hudson/model/AbstractBuild/sidepanel_pt_PT.properties +++ b/core/src/main/resources/hudson/model/AbstractBuild/sidepanel_pt_PT.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Next\ Build=Pr\u00F3xima builds -Previous\ Build=Prever/ver contru\u00E7\u00E3o +Next\ Build=Pr\u00F3xima build +Previous\ Build=Prever/ver constru\u00E7\u00E3o From 8a077a801960aa74da455441cfb12d300c6d6e3a Mon Sep 17 00:00:00 2001 From: James Nord Date: Thu, 13 Aug 2015 19:10:51 +0100 Subject: [PATCH 096/256] [JENKINS-29936] when removing an item use ACL.SYTEM. The OldDataMonitor should be using ACL.system not the ACL of the calling thread - this also avoids the deadlock when an authorization strategy is being saved (locking the auth strategy) which will call into the ODM at the same point the ODM is being called an a Run has been saved (which will cause a lookup of the job which will do a permissions check). --- .../java/hudson/diagnosis/OldDataMonitor.java | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/hudson/diagnosis/OldDataMonitor.java b/core/src/main/java/hudson/diagnosis/OldDataMonitor.java index 29a2187b93..5707b6d81b 100644 --- a/core/src/main/java/hudson/diagnosis/OldDataMonitor.java +++ b/core/src/main/java/hudson/diagnosis/OldDataMonitor.java @@ -25,6 +25,7 @@ package hudson.diagnosis; import com.google.common.base.Predicate; import com.thoughtworks.xstream.converters.UnmarshallingContext; + import hudson.Extension; import hudson.XmlFile; import hudson.model.AdministrativeMonitor; @@ -36,8 +37,10 @@ import hudson.model.Saveable; import hudson.model.listeners.ItemListener; import hudson.model.listeners.RunListener; import hudson.model.listeners.SaveableListener; +import hudson.security.ACL; import hudson.util.RobustReflectionConverter; import hudson.util.VersionNumber; + import java.io.IOException; import java.util.ArrayList; import java.util.Collection; @@ -48,8 +51,13 @@ import java.util.Map; import java.util.TreeSet; import java.util.logging.Level; import java.util.logging.Logger; + import javax.annotation.CheckForNull; + import jenkins.model.Jenkins; + +import org.acegisecurity.context.SecurityContext; +import org.acegisecurity.context.SecurityContextHolder; import org.kohsuke.stapler.HttpRedirect; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponses; @@ -102,12 +110,21 @@ public class OldDataMonitor extends AdministrativeMonitor { } private static void remove(Saveable obj, boolean isDelete) { - OldDataMonitor odm = get(Jenkins.getInstance()); - synchronized (odm) { - odm.data.remove(referTo(obj)); - if (isDelete && obj instanceof Job) - for (Run r : ((Job)obj).getBuilds()) - odm.data.remove(referTo(r)); + Jenkins j = Jenkins.getInstance(); + if (j != null) { + OldDataMonitor odm = get(j); + SecurityContext oldContext = ACL.impersonate(ACL.SYSTEM); + try { + synchronized (odm) { + odm.data.remove(referTo(obj)); + if (isDelete && obj instanceof Job) + for (Run r : ((Job)obj).getBuilds()) + odm.data.remove(referTo(r)); + } + } + finally { + SecurityContextHolder.setContext(oldContext); + } } } From 94efc7ba6a96eb54a4ff18e0073a3d213e2e82ae Mon Sep 17 00:00:00 2001 From: Peter Darton Date: Wed, 12 Aug 2015 16:36:56 +0100 Subject: [PATCH 097/256] Improved unit test for Util.deleteFile(File) Added unit test for Util.deleteRecursive(File) --- core/src/test/java/hudson/UtilTest.java | 135 ++++++++++++++++++++++-- 1 file changed, 125 insertions(+), 10 deletions(-) diff --git a/core/src/test/java/hudson/UtilTest.java b/core/src/test/java/hudson/UtilTest.java index 5be69d004b..6757940a68 100644 --- a/core/src/test/java/hudson/UtilTest.java +++ b/core/src/test/java/hudson/UtilTest.java @@ -24,17 +24,26 @@ */ package hudson; +import java.util.List; import java.util.Map; import java.util.HashMap; import java.util.Locale; import java.util.Properties; +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicReference; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.not; import static org.junit.Assert.*; +import org.apache.commons.io.FileUtils; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.junit.Assume; @@ -42,12 +51,13 @@ import org.junit.Test; import org.jvnet.hudson.test.Issue; import hudson.util.StreamTaskListener; -import java.io.FileOutputStream; -import java.io.OutputStream; + import org.junit.Rule; import org.junit.internal.AssumptionViolatedException; import org.junit.rules.TemporaryFolder; +import com.google.common.collect.Lists; + /** * @author Kohsuke Kawaguchi */ @@ -248,7 +258,17 @@ public class UtilTest { } } - @Test public void deleteFile() throws Exception { + @Test + public void testDeleteFile() throws Exception { + File f = tmp.newFile(); + // Test: File is deleted + mkfiles(f); + Util.deleteFile(f); + assertFalse("f exists after calling Util.deleteFile", f.exists()); + } + + @Test + public void testDeleteFile_onWindows() throws Exception { Assume.assumeTrue(Functions.isWindows()); Class c; try { @@ -256,23 +276,118 @@ public class UtilTest { } catch (ClassNotFoundException x) { throw new AssumptionViolatedException("prior to JDK 7", x); } - File d = tmp.getRoot(); try { - File f = new File(d, "f"); - OutputStream os = new FileOutputStream(f); + File f = tmp.newFile(); + // Test: If we cannot delete a file, we throw explaining why + mkfiles(f); + lockFileForDeletion(f); try { Util.deleteFile(f); fail("should not have been deletable"); } catch (IOException x) { - assertEquals(c, x.getClass()); - } finally { - os.close(); + assertThat(calcExceptionHierarchy(x), hasItem(c)); + assertThat(x.getMessage(), containsString(f.getPath())); } } finally { - Util.deleteRecursive(d); + unlockFilesForDeletion(); } } + @Test + public void testDeleteRecursive() throws Exception { + final File dir = tmp.newFolder(); + final File d1 = new File(dir, "d1"); + final File d2 = new File(dir, "d2"); + final File f1 = new File(dir, "f1"); + final File d1f1 = new File(d1, "d1f1"); + final File d2f2 = new File(d2, "d1f2"); + // Test: Files and directories are deleted + mkdirs(dir, d1, d2); + mkfiles(f1, d1f1, d2f2); + Util.deleteRecursive(dir); + assertFalse("dir exists", dir.exists()); + } + + @Test + public void testDeleteRecursive_onWindows() throws Exception { + Assume.assumeTrue(Functions.isWindows()); + final File dir = tmp.newFolder(); + final File d1 = new File(dir, "d1"); + final File d2 = new File(dir, "d2"); + final File f1 = new File(dir, "f1"); + final File d1f1 = new File(d1, "d1f1"); + final File d2f2 = new File(d2, "d1f2"); + try { + // Test: If we cannot delete a file, we throw + mkdirs(dir, d1, d2); + mkfiles(f1, d1f1, d2f2); + lockFileForDeletion(d1f1); + try { + Util.deleteRecursive(dir); + fail("Expected IOException"); + } catch (IOException x) { + assertTrue("dir exists", dir.exists()); + assertTrue("d1 exists", d1.exists()); + assertTrue("d1f1 exists", d1f1.exists()); + assertThat(x.getMessage(), containsString(dir.getPath())); + } + } finally { + unlockFilesForDeletion(); + } + } + + /** Creates multiple directories. */ + private static void mkdirs(File... dirs) { + for( File d : dirs ) { + d.mkdir(); + assertTrue(d.getPath(), d.isDirectory()); + } + } + + /** Creates multiple files, each containing their filename as text content. */ + private static void mkfiles(File... files) throws IOException { + for( File f : files ) + FileUtils.write(f, f.getName()); + } + + /** Means of unlocking all the files we have locked, indexed by {@link File}. */ + private final Map> unlockFileCallables = new HashMap>(); + + /** Prevents a file from being deleted, so we can stress the deletion code's retries. */ + private void lockFileForDeletion(File f) throws IOException, InterruptedException { + assert !unlockFileCallables.containsKey(f) : f + " is already locked." ; + // Limitation: Only works on Windows. On unix we can delete anything we can create. + // On unix, can't use "chmod a-w" on the dir as the code-under-test undoes that. + // On unix, can't use "chattr +i" because that needs root. + // On unix, can't use "chattr +u" because ext fs ignores it. + // On Windows, we can't delete files that are open for reading, so we use that. + assert Functions.isWindows(); + final InputStream s = new FileInputStream(f); + unlockFileCallables.put(f, new Callable() { + public Void call() throws IOException { s.close(); return null; }; + }); + } + + /** Undoes a call to {@link #lockFileForDeletion(File)}. */ + private void unlockFileForDeletion(File f) throws Exception { + unlockFileCallables.remove(f).call(); + } + + /** Undoes all calls to {@link #lockFileForDeletion(File)}. */ + private void unlockFilesForDeletion() throws Exception { + while( !unlockFileCallables.isEmpty() ) { + unlockFileForDeletion(unlockFileCallables.keySet().iterator().next()); + } + } + + /** Returns all classes in the exception hierarchy. */ + private static Iterable> calcExceptionHierarchy(Throwable t) { + final List> result = Lists.newArrayList(); + for( ; t!=null ; t = t.getCause()) + result.add(t.getClass()); + return result; + } + @Test public void testHtmlEscape() { assertEquals("
      ", Util.escape("\n")); From e0849bdaf84457246708c10e6cd8a5a10fa35725 Mon Sep 17 00:00:00 2001 From: James Nord Date: Mon, 17 Aug 2015 10:32:14 +0100 Subject: [PATCH 098/256] Noting JENKINS-29936 --- changelog.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.html b/changelog.html index 0927d1cfb7..376030a34c 100644 --- a/changelog.html +++ b/changelog.html @@ -55,7 +55,9 @@ Upcoming changes

      What's new in 1.624 (2015/08/09)

      From 94d80ea4f227fe5e121ea0d3806e59c9f779a2d5 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Mon, 17 Aug 2015 13:19:19 +0200 Subject: [PATCH 099/256] Noting #1715, #1767 --- changelog.html | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/changelog.html b/changelog.html index 376030a34c..03030378d7 100644 --- a/changelog.html +++ b/changelog.html @@ -58,6 +58,12 @@ Upcoming changes
    • Fixed a deadlock between the old data monitor and authorization strategies. (JENKINS-29936) +
    • + Allow rejecting configurations with errors in critical fields via REST / CLI. + (JENKINS-28440) +
    • + Do not display No changes if changelog is still being computed. + (JENKINS-2327)
  • What's new in 1.624 (2015/08/09)

    From dc27285173132c4dda0801b9246ae78b87b4fe3e Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Tue, 18 Aug 2015 01:51:28 +0300 Subject: [PATCH 100/256] Update javadoc-plugin version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7a376f67b0..a5445df74a 100644 --- a/pom.xml +++ b/pom.xml @@ -348,7 +348,7 @@ THE SOFTWARE. org.apache.maven.plugins maven-javadoc-plugin - 2.8 + 2.10.3 org.apache.maven.plugins From 60ebcfb3f12fa58a7ea52eec6a3572d7e38d85c6 Mon Sep 17 00:00:00 2001 From: John Pederzolli Date: Mon, 17 Aug 2015 15:53:11 -0700 Subject: [PATCH 101/256] Update RunIdMigrator to properly handle matrix and maven jobs Properly revert job history for matrix and maven jobs (depending on setup). Examples paths include: jobs/someproject/Environment=prod/builds jobs/someproject/test$test/builds --- .../java/jenkins/model/RunIdMigrator.java | 5 +++++ .../java/jenkins/model/RunIdMigratorTest.java | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/core/src/main/java/jenkins/model/RunIdMigrator.java b/core/src/main/java/jenkins/model/RunIdMigrator.java index 4666a5fb86..0316cf4c4c 100644 --- a/core/src/main/java/jenkins/model/RunIdMigrator.java +++ b/core/src/main/java/jenkins/model/RunIdMigrator.java @@ -350,6 +350,11 @@ public final class RunIdMigrator { return; } for (File job : jobDirs) { + + if (job.getName().equals("builds")) { + unmigrateBuildsDir(job); + } + File[] kids = job.listFiles(); if (kids == null) { continue; diff --git a/core/src/test/java/jenkins/model/RunIdMigratorTest.java b/core/src/test/java/jenkins/model/RunIdMigratorTest.java index fb9805db77..4b890ac50a 100644 --- a/core/src/test/java/jenkins/model/RunIdMigratorTest.java +++ b/core/src/test/java/jenkins/model/RunIdMigratorTest.java @@ -128,6 +128,26 @@ public class RunIdMigratorTest { assertEquals("{1=→2014-01-02_03-04-05, 2014-01-02_03-04-05={build.xml='\n\n ok\n 1\n ok\n'}}", summarize()); } + @Test public void reverseMatrixAfterNewBuilds() throws Exception { + File root = dir; + dir = new File(dir, "jobs/someproject/Environment=prod/builds"); + write("1/build.xml", "\n\n ok\n 1388649845000\n ok\n"); + write("legacyIds", ""); + assertEquals("{1={build.xml='\n\n ok\n 1388649845000\n ok\n'}, legacyIds=''}", summarize()); + RunIdMigrator.main(root.getAbsolutePath()); + assertEquals("{1=→2014-01-02_03-04-05, 2014-01-02_03-04-05={build.xml='\n\n ok\n 1\n ok\n'}}", summarize()); + } + + @Test public void reverseMavenAfterNewBuilds() throws Exception { + File root = dir; + dir = new File(dir, "jobs/someproject/test$test/builds"); + write("1/build.xml", "\n\n ok\n 1388649845000\n ok\n"); + write("legacyIds", ""); + assertEquals("{1={build.xml='\n\n ok\n 1388649845000\n ok\n'}, legacyIds=''}", summarize()); + RunIdMigrator.main(root.getAbsolutePath()); + assertEquals("{1=→2014-01-02_03-04-05, 2014-01-02_03-04-05={build.xml='\n\n ok\n 1\n ok\n'}}", summarize()); + } + // TODO test sane recovery from various error conditions private void write(String file, String text) throws Exception { From 8d8703a781f83be19086592e0c8fa4b4c14da13c Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Mon, 17 Aug 2015 21:19:42 -0700 Subject: [PATCH 102/256] [maven-release-plugin] prepare release jenkins-1.625 --- cli/pom.xml | 2 +- core/pom.xml | 2 +- plugins/pom.xml | 10 +++++----- pom.xml | 4 ++-- test/pom.xml | 2 +- war/pom.xml | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cli/pom.xml b/cli/pom.xml index b9c8be7bfc..c9e09db28e 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.625-SNAPSHOT + 1.625 cli diff --git a/core/pom.xml b/core/pom.xml index b6efee0ad7..e560e4cceb 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.625-SNAPSHOT + 1.625 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index 2967d15060..e210b609a6 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.625-SNAPSHOT + 1.625 pom +

    What's new in 1.625 (2015/08/17)

    +
      +
    • +

    What's new in 1.624 (2015/08/09)

    • From 087103015473119b18fdf8eda5de441fcd286612 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Tue, 18 Aug 2015 14:38:32 +0200 Subject: [PATCH 105/256] [JENKINS-30007] let Installable implement NodeSpecific --- core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java b/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java index 938325f668..e1a8e98e35 100644 --- a/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java +++ b/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java @@ -4,6 +4,7 @@ import hudson.FilePath; import hudson.model.DownloadService.Downloadable; import hudson.model.Node; import hudson.model.TaskListener; +import hudson.slaves.NodeSpecific; import net.sf.json.JSONObject; import java.io.IOException; @@ -64,6 +65,9 @@ public abstract class DownloadFromUrlInstaller extends ToolInstaller { return expected; } + if (inst instanceof NodeSpecific) + inst = (Installable) ((NodeSpecific) inst).forNode(node, log); + if(isUpToDate(expected,inst)) return expected; From c775e25f40087a4bcb608f8e1fdc24e4bb382e37 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Tue, 18 Aug 2015 14:53:52 +0200 Subject: [PATCH 106/256] [JENKINS-30007] let Installable implement NodeSpecific --- .../src/main/java/hudson/tools/DownloadFromUrlInstaller.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java b/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java index e1a8e98e35..6765aed8f5 100644 --- a/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java +++ b/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java @@ -65,8 +65,9 @@ public abstract class DownloadFromUrlInstaller extends ToolInstaller { return expected; } - if (inst instanceof NodeSpecific) - inst = (Installable) ((NodeSpecific) inst).forNode(node, log); + if (inst instanceof NodeSpecific) { + inst = (Installable) ((NodeSpecific) inst).forNode(node, log); + } if(isUpToDate(expected,inst)) return expected; From 1c0e94bfe95de6fb9087318bc208c2091f9b2d08 Mon Sep 17 00:00:00 2001 From: John Pederzolli Date: Tue, 18 Aug 2015 08:27:58 -0700 Subject: [PATCH 107/256] minor cleanup to trigger pull request --- core/src/main/java/jenkins/model/RunIdMigrator.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/java/jenkins/model/RunIdMigrator.java b/core/src/main/java/jenkins/model/RunIdMigrator.java index 0316cf4c4c..0315eb5fb1 100644 --- a/core/src/main/java/jenkins/model/RunIdMigrator.java +++ b/core/src/main/java/jenkins/model/RunIdMigrator.java @@ -354,7 +354,6 @@ public final class RunIdMigrator { if (job.getName().equals("builds")) { unmigrateBuildsDir(job); } - File[] kids = job.listFiles(); if (kids == null) { continue; From 7795039e33961ce250db9729a9e1c2b7a8313c92 Mon Sep 17 00:00:00 2001 From: John Pederzolli Date: Tue, 18 Aug 2015 08:41:15 -0700 Subject: [PATCH 108/256] additional comments --- core/src/main/java/jenkins/model/RunIdMigrator.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/jenkins/model/RunIdMigrator.java b/core/src/main/java/jenkins/model/RunIdMigrator.java index 0315eb5fb1..88dc17b900 100644 --- a/core/src/main/java/jenkins/model/RunIdMigrator.java +++ b/core/src/main/java/jenkins/model/RunIdMigrator.java @@ -352,8 +352,10 @@ public final class RunIdMigrator { for (File job : jobDirs) { if (job.getName().equals("builds")) { + // Might be maven modules, matrix builds, etc. which are direct children of job unmigrateBuildsDir(job); } + File[] kids = job.listFiles(); if (kids == null) { continue; @@ -365,7 +367,8 @@ public final class RunIdMigrator { if (kid.getName().equals("builds")) { unmigrateBuildsDir(kid); } else { - // Might be jobs, modules, promotions, etc.; we assume an ItemGroup.getRootDirFor implementation returns grandchildren. + // Might be jobs, modules, promotions, etc.; we assume an ItemGroup.getRootDirFor implementation + // returns grandchildren, unmigrateJobsDir(job) call above handles children. unmigrateJobsDir(kid); } } From 115ccba4aa1124927f57b850308ab5a76157ab75 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 19 Aug 2015 08:51:26 +0200 Subject: [PATCH 109/256] convenient decorator class to make Installable NodeSpecific --- .../java/hudson/tools/DownloadFromUrlInstaller.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java b/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java index 6765aed8f5..a5f902d24a 100644 --- a/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java +++ b/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java @@ -180,4 +180,16 @@ public abstract class DownloadFromUrlInstaller extends ToolInstaller { */ public String url; } + + /** + * Convenient abstract class to implement a NodeSpecificInstallable based on an existing Installable + */ + public abstract class NodeSpecificInstallable extends Installable implements NodeSpecific { + + public NodeSpecificInstallable(Installable inst) { + this.id = inst.id; + this.name = inst.name; + this.url = inst.url; + } + } } From 906aaf7ca355a5c7ddf6cabefbe513afed06022e Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 19 Aug 2015 09:20:52 +0200 Subject: [PATCH 110/256] @since --- core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java b/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java index a5f902d24a..f009b729b7 100644 --- a/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java +++ b/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java @@ -183,6 +183,7 @@ public abstract class DownloadFromUrlInstaller extends ToolInstaller { /** * Convenient abstract class to implement a NodeSpecificInstallable based on an existing Installable + * @since TODO */ public abstract class NodeSpecificInstallable extends Installable implements NodeSpecific { From 190e9e849cd36052f8a651a603a4482d56fd6251 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Wed, 19 Aug 2015 17:46:54 +0200 Subject: [PATCH 111/256] Move entries from trunk to 1.625 --- changelog.html | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/changelog.html b/changelog.html index a7f94f9ab1..47ed9cfce5 100644 --- a/changelog.html +++ b/changelog.html @@ -54,6 +54,13 @@ Upcoming changes +

      What's new in 1.625 (2015/08/17)

      • Fixed a deadlock between the old data monitor and authorization strategies. @@ -64,14 +71,6 @@ Upcoming changes
      • Do not display No changes if changelog is still being computed. (JENKINS-2327) -
      • - Fix error message "Failed to listen to incoming slave connection" after fixing port through init.groovy.d (JENKINS-29798) -
      • -
      -
    -

    What's new in 1.625 (2015/08/17)

    -
      -

    What's new in 1.624 (2015/08/09)

      From 2cf8446ba9273815aba064a51e6d4ec8aade7266 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Wed, 19 Aug 2015 17:48:40 +0200 Subject: [PATCH 112/256] Disambiguate message for 1.623 --- changelog.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.html b/changelog.html index 47ed9cfce5..20c3ef0acc 100644 --- a/changelog.html +++ b/changelog.html @@ -79,7 +79,7 @@ Upcoming changes (issue 26147)

    What's new in 1.623 (2015/08/02)

    -

    No major user-visible changes in this release.

    +

    No notable changes in this release.

    What's new in 1.622 (2015/07/27)

    • From 832236fc0c7875c84cd841a8c80b448cd36c0c3e Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Wed, 19 Aug 2015 17:51:47 +0200 Subject: [PATCH 113/256] Consistently use 'issue' instead of 'JENKINS' --- changelog.html | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/changelog.html b/changelog.html index 20c3ef0acc..5929d856b4 100644 --- a/changelog.html +++ b/changelog.html @@ -56,7 +56,8 @@ Upcoming changes @@ -64,13 +65,13 @@ Upcoming changes

      What's new in 1.624 (2015/08/09)

        From 06f690dbb9f491d592d42f5b911ae9d49f6e1290 Mon Sep 17 00:00:00 2001 From: James Nord Date: Thu, 20 Aug 2015 15:27:53 +0100 Subject: [PATCH 114/256] [JENKINS-30057] NodeProperties should be owned by the corresponding Saveable. Node objects are owned by the Nodes class not by Jenkins so NodeProperties and anything modifiying them needs to be updated. Also modifying Nodes requires a lock on the Queue so use this lock not Jenkins to prevent the deadlock observed in JENKINS-30057 --- core/src/main/java/hudson/model/Computer.java | 30 +++++++++++-------- core/src/main/java/hudson/model/Slave.java | 2 +- core/src/main/java/jenkins/model/Jenkins.java | 10 +++++++ 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index 5bc8bb7cdd..ebd95e8ae1 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -40,6 +40,7 @@ import hudson.model.Queue.FlyweightTask; import hudson.model.labels.LabelAtom; import hudson.model.queue.WorkUnit; import hudson.node_monitors.NodeMonitor; +import hudson.remoting.Callable; import hudson.remoting.Channel; import hudson.remoting.VirtualChannel; import hudson.security.ACL; @@ -67,6 +68,7 @@ import jenkins.model.Jenkins; import jenkins.model.queue.AsynchronousExecution; import jenkins.util.ContextResettingExecutorService; import jenkins.security.MasterToSlaveCallable; + import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.DoNotUse; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -87,6 +89,7 @@ import org.kohsuke.stapler.interceptor.RequirePOST; import javax.annotation.concurrent.GuardedBy; import javax.servlet.ServletException; + import java.io.File; import java.io.FilenameFilter; import java.io.IOException; @@ -108,6 +111,7 @@ import java.net.NetworkInterface; import java.net.Inet4Address; import java.util.regex.Matcher; import java.util.regex.Pattern; + import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -1426,21 +1430,23 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces /** * Replaces the current {@link Node} by another one. */ - private void replaceBy(Node newNode) throws ServletException, IOException { + private void replaceBy(final Node newNode) throws ServletException, IOException { final Jenkins app = Jenkins.getInstance(); - // replace the old Node object by the new one - synchronized (app) { - List nodes = new ArrayList(app.getNodes()); - Node node = getNode(); - int i = (node != null) ? nodes.indexOf(node) : -1; - if(i<0) { - throw new IOException("This slave appears to be removed while you were editing the configuration"); + // use the queue lock until Nodes has a way of directly modifying a single node. + Queue.withLock(new Callable() { + public Void call() throws IOException { + List nodes = new ArrayList(app.getNodes()); + Node node = getNode(); + int i = (node != null) ? nodes.indexOf(node) : -1; + if(i<0) { + throw new IOException("This slave appears to be removed while you were editing the configuration"); + } + nodes.set(i, newNode); + app.setNodes(nodes); + return null; } - - nodes.set(i, newNode); - app.setNodes(nodes); - } + }); } /** diff --git a/core/src/main/java/hudson/model/Slave.java b/core/src/main/java/hudson/model/Slave.java index 30bc6bf217..de5cd5cccb 100644 --- a/core/src/main/java/hudson/model/Slave.java +++ b/core/src/main/java/hudson/model/Slave.java @@ -127,7 +127,7 @@ public abstract class Slave extends Node implements Serializable { */ private String label=""; - private /*almost final*/ DescribableList,NodePropertyDescriptor> nodeProperties = new DescribableList,NodePropertyDescriptor>(Jenkins.getInstance()); + private /*almost final*/ DescribableList,NodePropertyDescriptor> nodeProperties = new DescribableList,NodePropertyDescriptor>(Jenkins.getInstance().getNodesObject()); /** * Lazily computed set of labels from {@link #label}. diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 2774e8bcf3..582d86a8d5 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -1710,6 +1710,16 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve return nodes.getNodes(); } + /** + * Get the {@code Nodes}object that handles maintaining {@code Node}s. + * @return The Nodes object. + */ + @Restricted(NoExternalUse.class) + public Nodes getNodesObject() { + // TODO replace this with something better when we properly expose Nodes. + return nodes; + } + /** * Adds one more {@link Node} to Jenkins. */ From d72d7b83ba33f99799adbd9139ade9b64661c617 Mon Sep 17 00:00:00 2001 From: James Nord Date: Thu, 20 Aug 2015 19:41:14 +0100 Subject: [PATCH 115/256] compiler tweaks and address review comments --- core/src/main/java/hudson/model/Computer.java | 6 ++---- core/src/main/java/hudson/model/Slave.java | 5 +++-- core/src/main/java/jenkins/model/Jenkins.java | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index ebd95e8ae1..003162eafe 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -28,7 +28,6 @@ import edu.umd.cs.findbugs.annotations.OverrideMustInvoke; import edu.umd.cs.findbugs.annotations.When; import hudson.EnvVars; import hudson.Extension; -import hudson.Functions; import hudson.Launcher.ProcStarter; import hudson.Util; import hudson.cli.declarative.CLIMethod; @@ -40,7 +39,6 @@ import hudson.model.Queue.FlyweightTask; import hudson.model.labels.LabelAtom; import hudson.model.queue.WorkUnit; import hudson.node_monitors.NodeMonitor; -import hudson.remoting.Callable; import hudson.remoting.Channel; import hudson.remoting.VirtualChannel; import hudson.security.ACL; @@ -65,9 +63,9 @@ import hudson.util.RunList; import hudson.util.Futures; import hudson.util.NamingThreadFactory; import jenkins.model.Jenkins; -import jenkins.model.queue.AsynchronousExecution; import jenkins.util.ContextResettingExecutorService; import jenkins.security.MasterToSlaveCallable; +import jenkins.security.NotReallyRoleSensitiveCallable; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.DoNotUse; @@ -1434,7 +1432,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces final Jenkins app = Jenkins.getInstance(); // use the queue lock until Nodes has a way of directly modifying a single node. - Queue.withLock(new Callable() { + Queue.withLock(new NotReallyRoleSensitiveCallable() { public Void call() throws IOException { List nodes = new ArrayList(app.getNodes()); Node node = getNode(); diff --git a/core/src/main/java/hudson/model/Slave.java b/core/src/main/java/hudson/model/Slave.java index de5cd5cccb..0b21fa89ae 100644 --- a/core/src/main/java/hudson/model/Slave.java +++ b/core/src/main/java/hudson/model/Slave.java @@ -127,7 +127,8 @@ public abstract class Slave extends Node implements Serializable { */ private String label=""; - private /*almost final*/ DescribableList,NodePropertyDescriptor> nodeProperties = new DescribableList,NodePropertyDescriptor>(Jenkins.getInstance().getNodesObject()); + private /*almost final*/ DescribableList,NodePropertyDescriptor> nodeProperties = + new DescribableList,NodePropertyDescriptor>(Jenkins.getInstance().getNodesObject()); /** * Lazily computed set of labels from {@link #label}. @@ -408,7 +409,7 @@ public abstract class Slave extends Node implements Serializable { : new CommandLauncher(agentCommand); } if(nodeProperties==null) - nodeProperties = new DescribableList,NodePropertyDescriptor>(Jenkins.getInstance()); + nodeProperties = new DescribableList,NodePropertyDescriptor>(Jenkins.getInstance().getNodesObject()); return this; } diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 582d86a8d5..ade0908991 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -1711,7 +1711,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } /** - * Get the {@code Nodes}object that handles maintaining {@code Node}s. + * Get the {@link Nodes} object that handles maintaining individual {@link Node}s. * @return The Nodes object. */ @Restricted(NoExternalUse.class) From a2ba196e63cfdc41c9d4d31422f6946a57403a04 Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Fri, 21 Aug 2015 21:08:47 +0300 Subject: [PATCH 116/256] test-annotations -> 1.2 Allows @Issue(String[]) --- pom.xml | 3 ++- test/pom.xml | 4 ++-- test/src/test/java/hudson/PluginTest.java | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index a406b4e8c4..1bccfbc9f8 100644 --- a/pom.xml +++ b/pom.xml @@ -101,6 +101,7 @@ THE SOFTWARE. 1.4.1 ${skipTests} 3.0.1 + 1.2 7 @@ -243,7 +244,7 @@ THE SOFTWARE. org.jenkins-ci test-annotations - 1.1 + ${test-annotations.version} test diff --git a/test/pom.xml b/test/pom.xml index 134c5ce8e1..d4269b6a88 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -108,9 +108,9 @@ THE SOFTWARE. org.jenkins-ci test-annotations - 1.1 - compile + ${test-annotations.version} + compile org.jvnet.mock-javamail diff --git a/test/src/test/java/hudson/PluginTest.java b/test/src/test/java/hudson/PluginTest.java index 05e7156dfc..19cd52bac7 100644 --- a/test/src/test/java/hudson/PluginTest.java +++ b/test/src/test/java/hudson/PluginTest.java @@ -34,7 +34,7 @@ public class PluginTest { @Rule public JenkinsRule r = new JenkinsRule(); - @Issue("SECURITY-131") // TODO test-annotations 1.2+: @Issue({"SECURITY-131", "SECURITY-155"}) + @Issue({"SECURITY-131", "SECURITY-155"}) @Test public void doDynamic() throws Exception { r.createWebClient().goTo("plugin/credentials/images/24x24/credentials.png", "image/png"); /* Collapsed somewhere before it winds up in restOfPath: From 79c0bbf76680c8491e601be76d062299b7170971 Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Wed, 5 Aug 2015 02:37:33 +0300 Subject: [PATCH 117/256] Protect from race condition in Triggers [FIXED JENKINS-29790] [FIXED JENKINS-29945] --- .../main/java/hudson/triggers/SCMTrigger.java | 22 +++++++++- .../java/hudson/triggers/TimerTrigger.java | 5 +++ .../main/java/hudson/triggers/Trigger.java | 4 +- .../java/hudson/triggers/SCMTriggerTest.java | 42 +++++++++++++++++++ .../hudson/triggers/TimerTriggerTest.java | 39 +++++++++++++++++ 5 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 core/src/test/java/hudson/triggers/SCMTriggerTest.java create mode 100644 core/src/test/java/hudson/triggers/TimerTriggerTest.java diff --git a/core/src/main/java/hudson/triggers/SCMTrigger.java b/core/src/main/java/hudson/triggers/SCMTrigger.java index c1b2dde483..a7048fbffd 100644 --- a/core/src/main/java/hudson/triggers/SCMTrigger.java +++ b/core/src/main/java/hudson/triggers/SCMTrigger.java @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Brian Westrich, Jean-Baptiste Quenot, id:cactusman + * 2015 Kanstantsin Shautsou * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,6 +25,7 @@ package hudson.triggers; import antlr.ANTLRException; +import com.google.common.base.Preconditions; import hudson.Extension; import hudson.Util; import hudson.console.AnnotatedLargeText; @@ -117,6 +119,10 @@ public class SCMTrigger extends Trigger { @Override public void run() { + if (job == null) { + return; + } + run(null); } @@ -128,6 +134,10 @@ public class SCMTrigger extends Trigger { * @since 1.375 */ public void run(Action[] additionalActions) { + if (job == null) { + return; + } + DescriptorImpl d = getDescriptor(); LOGGER.fine("Scheduling a polling for "+job); @@ -152,6 +162,10 @@ public class SCMTrigger extends Trigger { @Override public Collection getProjectActions() { + if (job == null) { + return Collections.emptyList(); + } + return Collections.singleton(new SCMAction()); } @@ -457,10 +471,12 @@ public class SCMTrigger extends Trigger { private Action[] additionalActions; public Runner() { - additionalActions = new Action[0]; + this(null); } public Runner(Action[] actions) { + Preconditions.checkNotNull(job, "Runner can't be instantiated when job is null"); + if (actions == null) { additionalActions = new Action[0]; } else { @@ -532,6 +548,10 @@ public class SCMTrigger extends Trigger { } public void run() { + if (job == null) { + return; + } + String threadName = Thread.currentThread().getName(); Thread.currentThread().setName("SCM polling for "+job); try { diff --git a/core/src/main/java/hudson/triggers/TimerTrigger.java b/core/src/main/java/hudson/triggers/TimerTrigger.java index 0466c8a4c3..3c835d70f9 100644 --- a/core/src/main/java/hudson/triggers/TimerTrigger.java +++ b/core/src/main/java/hudson/triggers/TimerTrigger.java @@ -2,6 +2,7 @@ * The MIT License * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Jean-Baptiste Quenot, Martin Eigenbrodt + * 2015 Kanstantsin Shautsou * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -52,6 +53,10 @@ public class TimerTrigger extends Trigger { @Override public void run() { + if (job == null) { + return; + } + job.scheduleBuild(0, new TimerTriggerCause()); } diff --git a/core/src/main/java/hudson/triggers/Trigger.java b/core/src/main/java/hudson/triggers/Trigger.java index a6b6443a0a..9d4e735e6d 100644 --- a/core/src/main/java/hudson/triggers/Trigger.java +++ b/core/src/main/java/hudson/triggers/Trigger.java @@ -2,7 +2,8 @@ * The MIT License * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Brian Westrich, Jean-Baptiste Quenot, Stephen Connolly, Tom Huybrechts - * + * 2015 Kanstantsin Shautsou + * * 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 @@ -149,6 +150,7 @@ public abstract class Trigger implements Describable> protected final String spec; protected transient CronTabList tabs; + @CheckForNull protected transient J job; /** diff --git a/core/src/test/java/hudson/triggers/SCMTriggerTest.java b/core/src/test/java/hudson/triggers/SCMTriggerTest.java new file mode 100644 index 0000000000..42e1a121bb --- /dev/null +++ b/core/src/test/java/hudson/triggers/SCMTriggerTest.java @@ -0,0 +1,42 @@ +/* + * The MIT License + * + * Copyright (c) 2015 Kanstantsin Shautsou + * + * 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.triggers; + +import org.junit.Test; +import org.jvnet.hudson.test.Issue; + +/** + * @author Kanstantsin Shautsou + */ +public class SCMTriggerTest { + @Issue({"JENKINS-29790", "JENKINS-29945"}) + @Test + public void testNoNPE() throws Exception { + final SCMTrigger scmTrigger = new SCMTrigger(""); + + scmTrigger.run(); + scmTrigger.run(null); + scmTrigger.getProjectActions(); + } +} diff --git a/core/src/test/java/hudson/triggers/TimerTriggerTest.java b/core/src/test/java/hudson/triggers/TimerTriggerTest.java new file mode 100644 index 0000000000..ef6edf4400 --- /dev/null +++ b/core/src/test/java/hudson/triggers/TimerTriggerTest.java @@ -0,0 +1,39 @@ +/* + * The MIT License + * + * Copyright (c) 2015 Kanstantsin Shautsou + * + * 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.triggers; + +import antlr.ANTLRException; +import org.junit.Test; +import org.jvnet.hudson.test.Issue; + +/** + * @author Kanstantsin Shautsou + */ +public class TimerTriggerTest { + @Issue("JENKINS-29790") + @Test + public void testNoNPE() throws ANTLRException { + new TimerTrigger("").run(); + } +} From 4ffb025f70227594257749939f46c4cdb5baf46a Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Thu, 20 Aug 2015 23:32:21 +0300 Subject: [PATCH 118/256] FB annotations and diamond in ReverseBuildTrigger.class --- .../java/jenkins/triggers/ReverseBuildTrigger.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/jenkins/triggers/ReverseBuildTrigger.java b/core/src/main/java/jenkins/triggers/ReverseBuildTrigger.java index 8ff41f838a..df08b6d8cc 100644 --- a/core/src/main/java/jenkins/triggers/ReverseBuildTrigger.java +++ b/core/src/main/java/jenkins/triggers/ReverseBuildTrigger.java @@ -72,6 +72,8 @@ import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; +import javax.annotation.Nonnull; + /** * Like {@link BuildTrigger} but defined on the downstream project. * Operates via {@link BuildTrigger#execute} and {@link DependencyGraph}, @@ -84,12 +86,13 @@ import org.kohsuke.stapler.QueryParameter; public final class ReverseBuildTrigger extends Trigger implements DependencyDeclarer { private static final Logger LOGGER = Logger.getLogger(ReverseBuildTrigger.class.getName()); - private static final Map> upstream2Trigger = new WeakHashMap>(); + private static final Map> upstream2Trigger = new WeakHashMap<>(); private String upstreamProjects; private final Result threshold; - @DataBoundConstructor public ReverseBuildTrigger(String upstreamProjects, Result threshold) { + @DataBoundConstructor + public ReverseBuildTrigger(String upstreamProjects, Result threshold) { this.upstreamProjects = upstreamProjects; this.threshold = threshold; } @@ -155,7 +158,7 @@ public final class ReverseBuildTrigger extends Trigger implements Dependenc synchronized (upstream2Trigger) { Collection triggers = upstream2Trigger.get(upstream); if (triggers == null) { - triggers = new LinkedList(); + triggers = new LinkedList<>(); upstream2Trigger.put(upstream, triggers); } triggers.remove(this); @@ -222,14 +225,14 @@ public final class ReverseBuildTrigger extends Trigger implements Dependenc } @Extension public static final class RunListenerImpl extends RunListener { - @Override public void onCompleted(Run r, TaskListener listener) { + @Override public void onCompleted(@Nonnull Run r, @Nonnull TaskListener listener) { Collection triggers; synchronized (upstream2Trigger) { Collection _triggers = upstream2Trigger.get(r.getParent()); if (_triggers == null || _triggers.isEmpty()) { return; } - triggers = new ArrayList(_triggers); + triggers = new ArrayList<>(_triggers); } for (final ReverseBuildTrigger trigger : triggers) { if (trigger.shouldTrigger(r, listener)) { From 194c1dc6069e06a0b8f17812aa497f8d81fc8c5b Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Thu, 20 Aug 2015 23:31:09 +0300 Subject: [PATCH 119/256] FB annotations for Trigger.class --- core/src/main/java/hudson/triggers/Trigger.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/hudson/triggers/Trigger.java b/core/src/main/java/hudson/triggers/Trigger.java index 9d4e735e6d..dade0854c3 100644 --- a/core/src/main/java/hudson/triggers/Trigger.java +++ b/core/src/main/java/hudson/triggers/Trigger.java @@ -58,6 +58,8 @@ import java.util.logging.Logger; import antlr.ANTLRException; import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; + import edu.umd.cs.findbugs.annotations.SuppressWarnings; import hudson.model.Items; import jenkins.model.ParameterizedJobMixIn; @@ -158,7 +160,7 @@ public abstract class Trigger implements Describable> * periodically. This is useful when your trigger does * some polling work. */ - protected Trigger(String cronTabSpec) throws ANTLRException { + protected Trigger(@Nonnull String cronTabSpec) throws ANTLRException { this.spec = cronTabSpec; this.tabs = CronTabList.create(cronTabSpec); } @@ -318,7 +320,7 @@ public abstract class Trigger implements Describable> * Returns a subset of {@link TriggerDescriptor}s that applys to the given item. */ public static List for_(Item i) { - List r = new ArrayList(); + List r = new ArrayList<>(); for (TriggerDescriptor t : all()) { if(!t.isApplicable(i)) continue; From e70f134d7d72a1d4c3b293ae3497bcf7a6bcfc40 Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Thu, 20 Aug 2015 23:30:10 +0300 Subject: [PATCH 120/256] FB annotations in TimerTrigger.class --- core/src/main/java/hudson/triggers/TimerTrigger.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/triggers/TimerTrigger.java b/core/src/main/java/hudson/triggers/TimerTrigger.java index 3c835d70f9..1925f00b90 100644 --- a/core/src/main/java/hudson/triggers/TimerTrigger.java +++ b/core/src/main/java/hudson/triggers/TimerTrigger.java @@ -39,6 +39,8 @@ import org.kohsuke.stapler.AncestorInPath; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; +import javax.annotation.Nonnull; + /** * {@link Trigger} that runs a job periodically. * @@ -47,7 +49,7 @@ import org.kohsuke.stapler.QueryParameter; public class TimerTrigger extends Trigger { @DataBoundConstructor - public TimerTrigger(String spec) throws ANTLRException { + public TimerTrigger(@Nonnull String spec) throws ANTLRException { super(spec); } From fa8973062f4a02edba99667589f88b5604a9a270 Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Thu, 20 Aug 2015 23:28:50 +0300 Subject: [PATCH 121/256] FB annotations and Diamons in CronTabList.class --- core/src/main/java/hudson/scheduler/CronTabList.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/hudson/scheduler/CronTabList.java b/core/src/main/java/hudson/scheduler/CronTabList.java index 34a3c6df1e..3243dda38e 100644 --- a/core/src/main/java/hudson/scheduler/CronTabList.java +++ b/core/src/main/java/hudson/scheduler/CronTabList.java @@ -29,6 +29,8 @@ import java.util.TimeZone; import java.util.Collection; import java.util.Vector; import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; + import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -44,7 +46,7 @@ public final class CronTabList { private final Vector tabs; public CronTabList(Collection tabs) { - this.tabs = new Vector(tabs); + this.tabs = new Vector<>(tabs); } /** @@ -90,12 +92,12 @@ public final class CronTabList { return null; } - public static CronTabList create(String format) throws ANTLRException { + public static CronTabList create(@Nonnull String format) throws ANTLRException { return create(format,null); } - public static CronTabList create(String format, Hash hash) throws ANTLRException { - Vector r = new Vector(); + public static CronTabList create(@Nonnull String format, Hash hash) throws ANTLRException { + Vector r = new Vector<>(); int lineNumber = 0; String timezone = null; From 65cca9822c2aa501c741dcdff3076d3e630875a4 Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Fri, 21 Aug 2015 21:44:36 +0300 Subject: [PATCH 122/256] FB annotation in SequentialExecutionQueue --- core/src/main/java/hudson/util/SequentialExecutionQueue.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/util/SequentialExecutionQueue.java b/core/src/main/java/hudson/util/SequentialExecutionQueue.java index 31f10e049d..a1cfa3ccba 100644 --- a/core/src/main/java/hudson/util/SequentialExecutionQueue.java +++ b/core/src/main/java/hudson/util/SequentialExecutionQueue.java @@ -1,5 +1,6 @@ package hudson.util; +import javax.annotation.Nonnull; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -58,7 +59,7 @@ public class SequentialExecutionQueue implements Executor { } - public synchronized void execute(Runnable item) { + public synchronized void execute(@Nonnull Runnable item) { QueueEntry e = entries.get(item); if(e==null) { e = new QueueEntry(item); From c26fd238e020bbd40bd8d90bb6d458d7a12520b1 Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Fri, 21 Aug 2015 21:45:30 +0300 Subject: [PATCH 123/256] Multi-catch in SCMTrigger.class --- core/src/main/java/hudson/triggers/SCMTrigger.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/core/src/main/java/hudson/triggers/SCMTrigger.java b/core/src/main/java/hudson/triggers/SCMTrigger.java index a7048fbffd..6f772064a5 100644 --- a/core/src/main/java/hudson/triggers/SCMTrigger.java +++ b/core/src/main/java/hudson/triggers/SCMTrigger.java @@ -530,11 +530,7 @@ public class SCMTrigger extends Trigger { else logger.println("No changes"); return result; - } catch (Error e) { - e.printStackTrace(listener.error("Failed to record SCM polling for "+job)); - LOGGER.log(Level.SEVERE,"Failed to record SCM polling for "+job,e); - throw e; - } catch (RuntimeException e) { + } catch (Error | RuntimeException e) { e.printStackTrace(listener.error("Failed to record SCM polling for "+job)); LOGGER.log(Level.SEVERE,"Failed to record SCM polling for "+job,e); throw e; From c973f8ea7d26a338f8c5ee4eb5fbe5be3c9ef2a1 Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Thu, 20 Aug 2015 19:51:00 +0300 Subject: [PATCH 124/256] maven-hpi-plugin -> 1.114 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a406b4e8c4..144f5ce730 100644 --- a/pom.xml +++ b/pom.xml @@ -501,7 +501,7 @@ THE SOFTWARE. org.jenkins-ci.tools maven-hpi-plugin - 1.110 + 1.114 org.apache.maven.plugins From ee7565ee65b4588d11f0cdf26ee8bcb107d05674 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Fri, 21 Aug 2015 23:13:44 +0200 Subject: [PATCH 125/256] @since --- core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java b/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java index f009b729b7..6433718c75 100644 --- a/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java +++ b/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java @@ -183,7 +183,7 @@ public abstract class DownloadFromUrlInstaller extends ToolInstaller { /** * Convenient abstract class to implement a NodeSpecificInstallable based on an existing Installable - * @since TODO + * @since 1.626 */ public abstract class NodeSpecificInstallable extends Installable implements NodeSpecific { From b4d57aebd182c9204bb042b7adeefa90f5d483e2 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Fri, 21 Aug 2015 17:18:00 -0400 Subject: [PATCH 126/256] [JENKINS-29989] Noting merge of #1802. --- changelog.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.html b/changelog.html index 5929d856b4..0bd0a3e4b6 100644 --- a/changelog.html +++ b/changelog.html @@ -55,6 +55,9 @@ Upcoming changes

        What's new in 1.625 (2015/08/17)

        • From b204bd0719c75201a454a2b6c6883d8acc7d0712 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Mon, 24 Aug 2015 10:51:15 -0400 Subject: [PATCH 131/256] [JENKINS-28840] Cancel the test timer only after we call Jenkins.cleanUp, in case that hung. Merges #1809. --- .../org/jvnet/hudson/test/JenkinsRule.java | 10 +- .../hudson/main/JenkinsRuleTimeoutTest.java | 125 ++++++++++++++++++ 2 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 test/src/test/java/org/jvnet/hudson/main/JenkinsRuleTimeoutTest.java diff --git a/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 7309c8acb5..f63842f398 100644 --- a/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -426,11 +426,6 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { tl.onTearDown(); } - if (timeoutTimer!=null) { - timeoutTimer.cancel(); - timeoutTimer = null; - } - // cancel pending asynchronous operations, although this doesn't really seem to be working for (WebClient client : clients) { // unload the page to cancel asynchronous operations @@ -467,6 +462,11 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { x.printStackTrace(); } + if (timeoutTimer != null) { + timeoutTimer.cancel(); + timeoutTimer = null; + } + // Hudson creates ClassLoaders for plugins that hold on to file descriptors of its jar files, // but because there's no explicit dispose method on ClassLoader, they won't get GC-ed until // at some later point, leading to possible file descriptor overflow. So encourage GC now. diff --git a/test/src/test/java/org/jvnet/hudson/main/JenkinsRuleTimeoutTest.java b/test/src/test/java/org/jvnet/hudson/main/JenkinsRuleTimeoutTest.java new file mode 100644 index 0000000000..913b924cb8 --- /dev/null +++ b/test/src/test/java/org/jvnet/hudson/main/JenkinsRuleTimeoutTest.java @@ -0,0 +1,125 @@ +/* + * The MIT License + * + * Copyright 2015 CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.jvnet.hudson.main; + +import hudson.model.listeners.ItemListener; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.Rule; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.TestExtension; + +public class JenkinsRuleTimeoutTest { + + @Rule + public JenkinsRule r = new JenkinsRule(); + { + r.timeout = 10; // let us not wait three minutes! + } + + @Test + public void hangInterruptiblyInTest() throws Exception { + try { + hangInterruptibly(); + } catch (InterruptedException x) { + System.err.println("Interrupted, good."); + } + } + + @Ignore("TODO ought to use the idiom from org.junit.internal.runners.statements.FailOnTimeout: " + + "run test in its own thread so we can fail even if it does not respond to interruptions") + @Test + public void hangUninterruptiblyInTest() throws Exception { + hangUninterruptibly(); + } + + @Test + public void hangInterruptiblyInShutdown() throws Exception { + System.err.println("Test itself passed…"); + } + @TestExtension("hangInterruptiblyInShutdown") + public static class HangsInterruptibly extends ItemListener { + @Override + public void onBeforeShutdown() { + try { + hangInterruptibly(); + } catch (InterruptedException x) { + System.err.println("Interrupted, good."); + } + } + + } + + @Ignore("TODO ditto") + @Test + public void hangUninterruptiblyInShutdown() throws Exception { + System.err.println("Test itself passed…"); + } + @TestExtension("hangUninterruptiblyInShutdown") + public static class HangsUninterruptibly extends ItemListener { + @Override + public void onBeforeShutdown() { + hangUninterruptibly(); + } + + } + + private static void hangInterruptibly() throws InterruptedException { + Thread.sleep(Long.MAX_VALUE); + } + + @SuppressWarnings("SleepWhileHoldingLock") + private static void hangUninterruptibly() { + // Adapted from http://stackoverflow.com/a/22489064/12916 + final Object a = new Object(); + final Object b = new Object(); + new Thread("other") { + @Override + public void run() { + synchronized (a) { + try { + Thread.sleep(3000); + } catch (InterruptedException exc) { + System.err.println("interrupted t1"); + } + synchronized (b) { + assert false : "should not get here"; + } + } + } + }.start(); + synchronized (b) { + try { + Thread.sleep(3000); + } catch (InterruptedException exc) { + System.err.println("interrupted t2"); + } + synchronized (a) { + assert false : "should not get here"; + } + } + } + +} From 38b469f62f1c799d9237c249c6353a9b58a93d7f Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 14:02:11 +0100 Subject: [PATCH 132/256] JenkinsRule compiling against HtmlUnit 2.17 --- test/pom.xml | 4 +- .../htmlunit/html/DomNodeUtil.java} | 34 ++--- .../htmlunit/html/HtmlFormUtil.java | 137 ++++++++++++++++++ .../org/jvnet/hudson/test/JenkinsRule.java | 49 +++---- 4 files changed, 173 insertions(+), 51 deletions(-) rename test/src/main/java/{org/jvnet/hudson/test/junit/FailedTest.java => com/gargoylesoftware/htmlunit/html/DomNodeUtil.java} (59%) create mode 100644 test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java diff --git a/test/pom.xml b/test/pom.xml index a5014fac9c..59a6eb871c 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -127,9 +127,9 @@ THE SOFTWARE. 1.3 - org.jenkins-ci + net.sourceforge.htmlunit htmlunit - 2.6-jenkins-6 + 2.17 diff --git a/test/src/main/java/org/jvnet/hudson/test/junit/FailedTest.java b/test/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java similarity index 59% rename from test/src/main/java/org/jvnet/hudson/test/junit/FailedTest.java rename to test/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java index 364364ef8d..54af4584b7 100644 --- a/test/src/main/java/org/jvnet/hudson/test/junit/FailedTest.java +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java @@ -1,7 +1,7 @@ /* * The MIT License * - * Copyright (c) 2004-2009, Sun Microsystems, Inc. + * Copyright (c) 2015, CloudBees, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,34 +21,26 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.jvnet.hudson.test.junit; +package com.gargoylesoftware.htmlunit.html; -import junit.framework.TestCase; +import com.gargoylesoftware.htmlunit.html.xpath.XPathUtils; + +import java.util.List; /** - * {@link TestCase} implementation that has already failed. - * Used to represent a problem happened during a test suite construction. - * - * @author Kohsuke Kawaguchi + * @author tom.fennelly@gmail.com */ -public class FailedTest extends TestCase { - /** - * The failure. If null, the test will succeed, despite the class name. - */ - private final Throwable problem; +public class DomNodeUtil { - public FailedTest(String name, Throwable problem) { - super(name); - this.problem = problem; + public static List getByXPath(final DomNode domNode, final String xpathExpr) { + return (List) XPathUtils.getByXPath(domNode, xpathExpr, null); } - public FailedTest(Class name, Throwable problem) { - this(name.getName(),problem); + public static List selectNodes(final DomNode domNode, final String xpathExpr) { + return getByXPath(domNode, xpathExpr); } - @Override - protected void runTest() throws Throwable { - if (problem!=null) - throw problem; + public static X selectSingleNode(final DomNode domNode, final String xpathExpr) { + return domNode.getFirstByXPath(xpathExpr); } } diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java new file mode 100644 index 0000000000..566336ee6a --- /dev/null +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java @@ -0,0 +1,137 @@ +/* + * The MIT License + * + * Copyright (c) 2015, CloudBees, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.gargoylesoftware.htmlunit.html; + +import com.gargoylesoftware.htmlunit.ElementNotFoundException; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.ScriptResult; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.WebRequest; +import com.gargoylesoftware.htmlunit.WebWindow; +import com.gargoylesoftware.htmlunit.javascript.host.Event; +import com.gargoylesoftware.htmlunit.protocol.javascript.JavaScriptURLConnection; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.reflect.FieldUtils; +import org.junit.Assert; + +import java.io.IOException; +import java.util.List; + +/** + * @author tom.fennelly@gmail.com + */ +public class HtmlFormUtil { + + /** + * Plain {@link com.gargoylesoftware.htmlunit.html.HtmlForm#submit()} doesn't work correctly due to the use of YUI in Hudson. + */ + public static Page submit(final HtmlForm htmlForm) throws IOException { + final HtmlSubmitInput submitElement = getSubmitButton(htmlForm); + return submit(htmlForm, submitElement); + } + + /** + * Plain {@link com.gargoylesoftware.htmlunit.html.HtmlForm#submit()} doesn't work correctly due to the use of YUI in Hudson. + */ + public static Page submit(HtmlForm htmlForm, HtmlSubmitInput submitElement) throws IOException { + final HtmlPage htmlPage = (HtmlPage) htmlForm.getPage(); + final WebClient webClient = htmlPage.getWebClient(); + if (webClient.getOptions().isJavaScriptEnabled()) { + if (submitElement != null) { + // To make YUI event handling work, this combo seems to be necessary + // the click will trigger _onClick in buton-*.js, but it doesn't submit the form + // (a comment alluding to this behavior can be seen in submitForm method) + // so to complete it, submit the form later. + // + // Just doing form.submit() doesn't work either, because it doesn't do + // the preparation work needed to pass along the name of the button that + // triggered a submission (more concretely, m_oSubmitTrigger is not set.) + submitElement.click(); + + try { + FieldUtils.writeField(htmlForm, "isPreventDefault_", false, true); + final ScriptResult scriptResult = htmlForm.fireEvent(Event.TYPE_SUBMIT); + if ((Boolean)FieldUtils.readField(htmlForm, "isPreventDefault_", true)) { + // null means 'nothing executed' + if (scriptResult == null) { + return htmlPage; + } + return scriptResult.getNewPage(); + } + } catch (IllegalAccessException e) { + Assert.fail("Unexpected error accessing property HtmlForm.isPreventDefault_: "); + } + } + + final String action = htmlForm.getActionAttribute().trim(); + if (StringUtils.startsWithIgnoreCase(action, JavaScriptURLConnection.JAVASCRIPT_PREFIX)) { + return htmlPage.executeJavaScriptIfPossible(action, "Form action", htmlForm.getStartLineNumber()).getNewPage(); + } + } + else { + if (StringUtils.startsWithIgnoreCase(htmlForm.getActionAttribute(), JavaScriptURLConnection.JAVASCRIPT_PREFIX)) { + // The action is JavaScript but JavaScript isn't enabled. + // Return the current page. + return htmlPage; + } + } + + final WebRequest request = htmlForm.getWebRequest(submitElement); + final String target = htmlPage.getResolvedTarget(htmlForm.getTargetAttribute()); + + final WebWindow webWindow = htmlPage.getEnclosingWindow(); + webClient.download(webWindow, target, request, false, "JS form.submit()"); + return htmlPage; + } + + /** + * Returns all the <input type="submit"> elements in this form. + */ + public static List getSubmitButtons(final HtmlForm htmlForm) throws ElementNotFoundException { + final List list = htmlForm.getElementsByAttribute("input", "type", "submit"); + + // collect inputs from lost children + for (final HtmlElement elt : htmlForm.getLostChildren()) { + if (elt instanceof HtmlSubmitInput) { + list.add((HtmlSubmitInput) elt); + } + } + return list; + } + + /** + * Gets the first <input type="submit"> element in this form. + */ + public static HtmlSubmitInput getSubmitButton(final HtmlForm htmlForm) throws ElementNotFoundException { + return getSubmitButtons(htmlForm).get(0); + } + + public static HtmlButton getButtonByCaption(final HtmlForm htmlForm, final String caption) throws ElementNotFoundException { + for (HtmlElement b : htmlForm.getHtmlElementsByTagName("button")) { + if(b.getTextContent().trim().equals(caption)) + return (HtmlButton)b; + } + throw new ElementNotFoundException("button", "caption", caption); + } +} diff --git a/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index f63842f398..5e38f9066c 100644 --- a/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -30,7 +30,7 @@ import com.gargoylesoftware.htmlunit.DefaultCssErrorHandler; import com.gargoylesoftware.htmlunit.ElementNotFoundException; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebRequest; import com.gargoylesoftware.htmlunit.WebResponse; import com.gargoylesoftware.htmlunit.html.DomNode; import com.gargoylesoftware.htmlunit.html.HtmlButton; @@ -39,8 +39,10 @@ import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlImage; import com.gargoylesoftware.htmlunit.html.HtmlInput; import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; import com.gargoylesoftware.htmlunit.javascript.HtmlUnitContextFactory; import com.gargoylesoftware.htmlunit.javascript.host.xml.XMLHttpRequest; +import com.gargoylesoftware.htmlunit.util.NameValuePair; import com.gargoylesoftware.htmlunit.xml.XmlPage; import hudson.ClassicPluginStrategy; import hudson.CloseProofOutputStream; @@ -173,7 +175,6 @@ import org.acegisecurity.GrantedAuthorityImpl; import org.acegisecurity.userdetails.UserDetails; import org.acegisecurity.userdetails.UsernameNotFoundException; import org.apache.commons.beanutils.PropertyUtils; -import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.io.FileUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.resolver.AbstractArtifactResolutionException; @@ -190,6 +191,8 @@ import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import org.jvnet.hudson.test.recipes.Recipe; import org.jvnet.hudson.test.rhino.JavaScriptDebugger; import org.kohsuke.stapler.ClassDescriptor; @@ -1179,8 +1182,9 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { * Asserts that the XPath matches. */ public void assertXPath(HtmlPage page, String xpath) { + HtmlElement documentElement = page.getDocumentElement(); assertNotNull("There should be an object that matches XPath:" + xpath, - page.getDocumentElement().selectSingleNode(xpath)); + DomNodeUtil.selectSingleNode(documentElement, xpath)); } /** Asserts that the XPath matches the contents of a DomNode page. This @@ -1236,7 +1240,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { * (By default, HtmlUnit doesn't load images.) */ public void assertAllImageLoadSuccessfully(HtmlPage p) { - for (HtmlImage img : p.selectNodes("//IMG")) { + for (HtmlImage img : DomNodeUtil.selectNodes(p, "//IMG")) { try { img.getHeight(); } catch (IOException e) { @@ -1299,7 +1303,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { * Plain {@link com.gargoylesoftware.htmlunit.html.HtmlForm#submit()} doesn't work correctly due to the use of YUI in Hudson. */ public HtmlPage submit(HtmlForm form) throws Exception { - return (HtmlPage) form.submit((HtmlButton) last(form.getHtmlElementsByTagName("button"))); + return (HtmlPage) HtmlFormUtil.submit(form); } /** @@ -1312,23 +1316,14 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { for( HtmlElement e : form.getHtmlElementsByTagName("button")) { HtmlElement p = (HtmlElement)e.getParentNode().getParentNode(); if(p.getAttribute("name").equals(name)) { - // To make YUI event handling work, this combo seems to be necessary - // the click will trigger _onClick in buton-*.js, but it doesn't submit the form - // (a comment alluding to this behavior can be seen in submitForm method) - // so to complete it, submit the form later. - // - // Just doing form.submit() doesn't work either, because it doesn't do - // the preparation work needed to pass along the name of the button that - // triggered a submission (more concretely, m_oSubmitTrigger is not set.) - ((HtmlButton)e).click(); - return (HtmlPage)form.submit((HtmlButton)e); + return (HtmlPage)HtmlFormUtil.submit(form, (HtmlSubmitInput) e); } } throw new AssertionError("No such submit button with the name "+name); } public HtmlInput findPreviousInputElement(HtmlElement current, String name) { - return (HtmlInput)current.selectSingleNode("(preceding::input[@name='_."+name+"'])[last()]"); + return DomNodeUtil.selectSingleNode(current, "(preceding::input[@name='_."+name+"'])[last()]"); } public HtmlButton getButtonByCaption(HtmlForm f, String s) { @@ -1839,7 +1834,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { public WebClient() { // default is IE6, but this causes 'n.doScroll('left')' to fail in event-debug.js:1907 as HtmlUnit doesn't implement such a method, // so trying something else, until we discover another problem. - super(BrowserVersion.FIREFOX_2); + super(BrowserVersion.FIREFOX_38); // setJavaScriptEnabled(false); setPageCreator(HudsonPageCreator.INSTANCE); @@ -1847,7 +1842,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { // make ajax calls run as post-action for predictable behaviors that simplify debugging setAjaxController(new AjaxController() { private static final long serialVersionUID = -5844060943564822678L; - public boolean processSynchron(HtmlPage page, WebRequestSettings settings, boolean async) { + public boolean processSynchron(HtmlPage page, WebRequest settings, boolean async) { return false; } }); @@ -1892,7 +1887,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { // avoid a hang by setting a time out. It should be long enough to prevent // false-positive timeout on slow systems - setTimeout(60*1000); + //setTimeout(60*1000); } /** @@ -1918,7 +1913,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { // remember me not available is OK so long as the caller didn't ask for it assert !rememberMe; } - form.submit(null); + HtmlFormUtil.submit(form, null); return this; } @@ -1984,7 +1979,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { HtmlPage top = goTo(""); HtmlForm search = top.getFormByName("search"); search.getInputByName("q").setValueAttribute(q); - return (HtmlPage)search.submit(null); + return (HtmlPage)HtmlFormUtil.submit(search, null); } /** @@ -2126,14 +2121,12 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { /** * Adds a security crumb to the request. - * Use {@link #createCrumbedUrl} instead if you intend to call {@link WebRequestSettings#setRequestBody}, typical of a POST request. + * Use {@link #createCrumbedUrl} instead if you intend to call {@link WebRequest#setRequestBody}, typical of a POST request. */ - public WebRequestSettings addCrumb(WebRequestSettings req) { - NameValuePair crumb[] = { new NameValuePair() }; - - crumb[0].setName(jenkins.getCrumbIssuer().getDescriptor().getCrumbRequestField()); - crumb[0].setValue(jenkins.getCrumbIssuer().getCrumb( null )); - + public WebRequest addCrumb(WebRequest req) { + NameValuePair crumb = new NameValuePair( + jenkins.getCrumbIssuer().getDescriptor().getCrumbRequestField(), + jenkins.getCrumbIssuer().getCrumb( null )); req.setRequestParameters(Arrays.asList( crumb )); return req; } From b5093630b308d78ec6a1031fce249a92028f37f2 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 14:10:09 +0100 Subject: [PATCH 133/256] HudsonTestCase compiling against HtmlUnit 2.17 --- .../org/jvnet/hudson/test/HudsonTestCase.java | 44 ++++++++----------- .../hudson/model/AbstractProjectTest.groovy | 16 ++----- 2 files changed, 21 insertions(+), 39 deletions(-) diff --git a/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java b/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java index 066ce52cea..efb54899b3 100644 --- a/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java +++ b/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java @@ -25,7 +25,11 @@ package org.jvnet.hudson.test; import com.gargoylesoftware.htmlunit.AlertHandler; +import com.gargoylesoftware.htmlunit.WebRequest; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import com.gargoylesoftware.htmlunit.html.HtmlImage; +import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput; import com.google.inject.Injector; import hudson.ClassicPluginStrategy; @@ -175,7 +179,6 @@ import com.gargoylesoftware.htmlunit.BrowserVersion; import com.gargoylesoftware.htmlunit.DefaultCssErrorHandler; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebRequestSettings; import com.gargoylesoftware.htmlunit.html.DomNode; import com.gargoylesoftware.htmlunit.html.HtmlButton; import com.gargoylesoftware.htmlunit.html.HtmlElement; @@ -1042,7 +1045,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { */ public void assertXPath(HtmlPage page, String xpath) { assertNotNull("There should be an object that matches XPath:" + xpath, - page.getDocumentElement().selectSingleNode(xpath)); + DomNodeUtil.selectSingleNode(page.getDocumentElement(), xpath)); } /** Asserts that the XPath matches the contents of a DomNode page. This @@ -1098,7 +1101,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { * (By default, HtmlUnit doesn't load images.) */ public void assertAllImageLoadSuccessfully(HtmlPage p) { - for (HtmlImage img : p.selectNodes("//IMG")) { + for (HtmlImage img : DomNodeUtil.selectNodes(p, "//IMG")) { try { img.getHeight(); } catch (IOException e) { @@ -1160,7 +1163,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { * Plain {@link HtmlForm#submit()} doesn't work correctly due to the use of YUI in Hudson. */ public HtmlPage submit(HtmlForm form) throws Exception { - return (HtmlPage)form.submit((HtmlButton)last(form.getHtmlElementsByTagName("button"))); + return (HtmlPage) HtmlFormUtil.submit(form); } /** @@ -1173,23 +1176,14 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { for( HtmlElement e : form.getHtmlElementsByTagName("button")) { HtmlElement p = (HtmlElement)e.getParentNode().getParentNode(); if(p.getAttribute("name").equals(name)) { - // To make YUI event handling work, this combo seems to be necessary - // the click will trigger _onClick in buton-*.js, but it doesn't submit the form - // (a comment alluding to this behavior can be seen in submitForm method) - // so to complete it, submit the form later. - // - // Just doing form.submit() doesn't work either, because it doesn't do - // the preparation work needed to pass along the name of the button that - // triggered a submission (more concretely, m_oSubmitTrigger is not set.) - ((HtmlButton)e).click(); - return (HtmlPage)form.submit((HtmlButton)e); + return (HtmlPage)HtmlFormUtil.submit(form, (HtmlSubmitInput) e); } } throw new AssertionError("No such submit button with the name "+name); } protected HtmlInput findPreviousInputElement(HtmlElement current, String name) { - return (HtmlInput)current.selectSingleNode("(preceding::input[@name='_."+name+"'])[last()]"); + return DomNodeUtil.selectSingleNode(current, "(preceding::input[@name='_."+name+"'])[last()]"); } protected HtmlButton getButtonByCaption(HtmlForm f, String s) { @@ -1634,14 +1628,14 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { public WebClient() { // default is IE6, but this causes 'n.doScroll('left')' to fail in event-debug.js:1907 as HtmlUnit doesn't implement such a method, // so trying something else, until we discover another problem. - super(BrowserVersion.FIREFOX_2); + super(BrowserVersion.FIREFOX_38); setPageCreator(HudsonPageCreator.INSTANCE); clients.add(this); // make ajax calls run as post-action for predictable behaviors that simplify debugging setAjaxController(new AjaxController() { private static final long serialVersionUID = -5844060943564822678L; - public boolean processSynchron(HtmlPage page, WebRequestSettings settings, boolean async) { + public boolean processSynchron(HtmlPage page, WebRequest settings, boolean async) { return false; } }); @@ -1689,7 +1683,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { // avoid a hang by setting a time out. It should be long enough to prevent // false-positive timeout on slow systems - setTimeout(60*1000); + //setTimeout(60*1000); } /** @@ -1701,7 +1695,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { HtmlForm form = page.getFormByName("login"); form.getInputByName("j_username").setValueAttribute(username); form.getInputByName("j_password").setValueAttribute(password); - form.submit(null); + HtmlFormUtil.submit(form, null); return this; } @@ -1767,7 +1761,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { HtmlPage top = goTo(""); HtmlForm search = top.getFormByName("search"); search.getInputByName("q").setValueAttribute(q); - return (HtmlPage)search.submit(null); + return (HtmlPage)HtmlFormUtil.submit(search, null); } /** @@ -1895,12 +1889,10 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { /** * Adds a security crumb to the quest */ - public WebRequestSettings addCrumb(WebRequestSettings req) { - NameValuePair crumb[] = { new NameValuePair() }; - - crumb[0].setName(jenkins.getCrumbIssuer().getDescriptor().getCrumbRequestField()); - crumb[0].setValue(jenkins.getCrumbIssuer().getCrumb( null )); - + public WebRequest addCrumb(WebRequest req) { + com.gargoylesoftware.htmlunit.util.NameValuePair crumb = new com.gargoylesoftware.htmlunit.util.NameValuePair( + jenkins.getCrumbIssuer().getDescriptor().getCrumbRequestField(), + jenkins.getCrumbIssuer().getCrumb( null )); req.setRequestParameters(Arrays.asList( crumb )); return req; } diff --git a/test/src/test/groovy/hudson/model/AbstractProjectTest.groovy b/test/src/test/groovy/hudson/model/AbstractProjectTest.groovy index f40a32ed3a..d63ab86090 100644 --- a/test/src/test/groovy/hudson/model/AbstractProjectTest.groovy +++ b/test/src/test/groovy/hudson/model/AbstractProjectTest.groovy @@ -25,18 +25,13 @@ package hudson.model; import com.gargoylesoftware.htmlunit.ElementNotFoundException import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; -import com.gargoylesoftware.htmlunit.HttpMethod; -import com.gargoylesoftware.htmlunit.WebRequestSettings -import com.gargoylesoftware.htmlunit.html.HtmlPage; -import hudson.security.* +import com.gargoylesoftware.htmlunit.HttpMethod +import com.gargoylesoftware.htmlunit.WebRequest; import hudson.tasks.BuildStepMonitor; -import hudson.tasks.BuildTrigger -import hudson.tasks.Publisher import hudson.tasks.Recorder; import com.gargoylesoftware.htmlunit.html.HtmlPage import hudson.maven.MavenModuleSet; import hudson.security.*; -import hudson.tasks.BuildTrigger; import hudson.tasks.Shell; import hudson.scm.NullSCM; import hudson.scm.SCM @@ -53,17 +48,12 @@ import hudson.triggers.TriggerDescriptor; import hudson.util.StreamTaskListener; import hudson.util.OneShotEvent import jenkins.model.Jenkins; -import org.acegisecurity.context.SecurityContext; -import org.acegisecurity.context.SecurityContextHolder import org.jvnet.hudson.test.HudsonTestCase import org.jvnet.hudson.test.Issue; -import org.jvnet.hudson.test.MemoryAssert -import org.jvnet.hudson.test.SequenceLock; import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.recipes.PresetData; import org.jvnet.hudson.test.recipes.PresetData.DataSet import org.apache.commons.io.FileUtils; -import java.lang.ref.WeakReference import org.jvnet.hudson.test.MockFolder @@ -393,7 +383,7 @@ public class AbstractProjectTest extends HudsonTestCase { private String deleteRedirectTarget(String job) { def wc = createWebClient(); String base = wc.getContextPath(); - String loc = wc.getPage(wc.addCrumb(new WebRequestSettings(new URL(base + job + "/doDelete"), HttpMethod.POST))).getWebResponse().getUrl().toString(); + String loc = wc.getPage(wc.addCrumb(new WebRequest(new URL(base + job + "/doDelete"), HttpMethod.POST))).getWebResponse().getUrl().toString(); assert loc.startsWith(base): loc; return loc.substring(base.length()); } From 4e75d375193f8fbfe55a5c41cd63d52921a376b9 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 14:11:23 +0100 Subject: [PATCH 134/256] DirectlyModifiableViewTest compiling against HtmlUnit 2.17 --- .../test/java/hudson/model/DirectlyModifiableViewTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/src/test/java/hudson/model/DirectlyModifiableViewTest.java b/test/src/test/java/hudson/model/DirectlyModifiableViewTest.java index f6f62d935f..977f7b7e9b 100644 --- a/test/src/test/java/hudson/model/DirectlyModifiableViewTest.java +++ b/test/src/test/java/hudson/model/DirectlyModifiableViewTest.java @@ -30,6 +30,7 @@ import java.net.URL; import javax.annotation.Nonnull; +import com.gargoylesoftware.htmlunit.WebRequest; import org.hamcrest.Matchers; import org.junit.Rule; import org.junit.Test; @@ -39,7 +40,6 @@ import org.jvnet.hudson.test.MockFolder; import com.gargoylesoftware.htmlunit.HttpMethod; import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebRequestSettings; import com.gargoylesoftware.htmlunit.WebResponse; public class DirectlyModifiableViewTest { @@ -186,8 +186,8 @@ public class DirectlyModifiableViewTest { private Page doPost(View view, String path) throws Exception { WebClient wc = j.createWebClient(); - wc.setThrowExceptionOnFailingStatusCode(false); - WebRequestSettings req = new WebRequestSettings( + // wc.setThrowExceptionOnFailingStatusCode(false); + WebRequest req = new WebRequest( new URL(j.jenkins.getRootUrl() + view.getUrl() + path), HttpMethod.POST ); From a0040dbc27a97b26033570c6897c56bf84fdf8ee Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 14:17:45 +0100 Subject: [PATCH 135/256] Reinstate FailedTest Not sure how I managed to delete that duh --- .../jvnet/hudson/test/junit/FailedTest.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 test/src/main/java/org/jvnet/hudson/test/junit/FailedTest.java diff --git a/test/src/main/java/org/jvnet/hudson/test/junit/FailedTest.java b/test/src/main/java/org/jvnet/hudson/test/junit/FailedTest.java new file mode 100644 index 0000000000..670a9d4e1e --- /dev/null +++ b/test/src/main/java/org/jvnet/hudson/test/junit/FailedTest.java @@ -0,0 +1,54 @@ +/* + * The MIT License + * + * Copyright (c) 2004-2009, Sun Microsystems, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package org.jvnet.hudson.test.junit; + +import junit.framework.TestCase; + +/** + * {@link TestCase} implementation that has already failed. + * Used to represent a problem happened during a test suite construction. + * + * @author Kohsuke Kawaguchi + */ +public class FailedTest extends TestCase { + /** + * The failure. If null, the test will succeed, despite the class name. + */ + private final Throwable problem; + + public FailedTest(String name, Throwable problem) { + super(name); + this.problem = problem; + } + + public FailedTest(Class name, Throwable problem) { + this(name.getName(),problem); + } + + @Override + protected void runTest() throws Throwable { + if (problem!=null) + throw problem; + } +} \ No newline at end of file From 919cbfbed6273c5aaed8fad2eda8c91938da1c5b Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 14:22:48 +0100 Subject: [PATCH 136/256] Remove xml-apis transitive exclusion from htmlunit dependency --- test/pom.xml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/pom.xml b/test/pom.xml index 59a6eb871c..0af213f6b9 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -130,13 +130,6 @@ THE SOFTWARE. net.sourceforge.htmlunit htmlunit 2.17 - - - - xml-apis - xml-apis - - xalan From d1ca4225260d810b12c4eb4b3ea5f08f18bf351b Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 16:49:42 +0100 Subject: [PATCH 137/256] Simplify HtmlFormUtil.submit --- .../htmlunit/html/HtmlFormUtil.java | 67 +++---------------- 1 file changed, 11 insertions(+), 56 deletions(-) diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java index 566336ee6a..1ba14e7f30 100644 --- a/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java @@ -25,15 +25,6 @@ package com.gargoylesoftware.htmlunit.html; import com.gargoylesoftware.htmlunit.ElementNotFoundException; import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.ScriptResult; -import com.gargoylesoftware.htmlunit.WebClient; -import com.gargoylesoftware.htmlunit.WebRequest; -import com.gargoylesoftware.htmlunit.WebWindow; -import com.gargoylesoftware.htmlunit.javascript.host.Event; -import com.gargoylesoftware.htmlunit.protocol.javascript.JavaScriptURLConnection; -import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.reflect.FieldUtils; -import org.junit.Assert; import java.io.IOException; import java.util.List; @@ -55,54 +46,18 @@ public class HtmlFormUtil { * Plain {@link com.gargoylesoftware.htmlunit.html.HtmlForm#submit()} doesn't work correctly due to the use of YUI in Hudson. */ public static Page submit(HtmlForm htmlForm, HtmlSubmitInput submitElement) throws IOException { - final HtmlPage htmlPage = (HtmlPage) htmlForm.getPage(); - final WebClient webClient = htmlPage.getWebClient(); - if (webClient.getOptions().isJavaScriptEnabled()) { - if (submitElement != null) { - // To make YUI event handling work, this combo seems to be necessary - // the click will trigger _onClick in buton-*.js, but it doesn't submit the form - // (a comment alluding to this behavior can be seen in submitForm method) - // so to complete it, submit the form later. - // - // Just doing form.submit() doesn't work either, because it doesn't do - // the preparation work needed to pass along the name of the button that - // triggered a submission (more concretely, m_oSubmitTrigger is not set.) - submitElement.click(); - - try { - FieldUtils.writeField(htmlForm, "isPreventDefault_", false, true); - final ScriptResult scriptResult = htmlForm.fireEvent(Event.TYPE_SUBMIT); - if ((Boolean)FieldUtils.readField(htmlForm, "isPreventDefault_", true)) { - // null means 'nothing executed' - if (scriptResult == null) { - return htmlPage; - } - return scriptResult.getNewPage(); - } - } catch (IllegalAccessException e) { - Assert.fail("Unexpected error accessing property HtmlForm.isPreventDefault_: "); - } - } - - final String action = htmlForm.getActionAttribute().trim(); - if (StringUtils.startsWithIgnoreCase(action, JavaScriptURLConnection.JAVASCRIPT_PREFIX)) { - return htmlPage.executeJavaScriptIfPossible(action, "Form action", htmlForm.getStartLineNumber()).getNewPage(); - } + if (submitElement != null) { + // To make YUI event handling work, this combo seems to be necessary + // the click will trigger _onClick in buton-*.js, but it doesn't submit the form + // (a comment alluding to this behavior can be seen in submitForm method) + // so to complete it, submit the form later. + // + // Just doing form.submit() doesn't work either, because it doesn't do + // the preparation work needed to pass along the name of the button that + // triggered a submission (more concretely, m_oSubmitTrigger is not set.) + submitElement.click(); } - else { - if (StringUtils.startsWithIgnoreCase(htmlForm.getActionAttribute(), JavaScriptURLConnection.JAVASCRIPT_PREFIX)) { - // The action is JavaScript but JavaScript isn't enabled. - // Return the current page. - return htmlPage; - } - } - - final WebRequest request = htmlForm.getWebRequest(submitElement); - final String target = htmlPage.getResolvedTarget(htmlForm.getTargetAttribute()); - - final WebWindow webWindow = htmlPage.getEnclosingWindow(); - webClient.download(webWindow, target, request, false, "JS form.submit()"); - return htmlPage; + return htmlForm.submit(submitElement); } /** From 6d763f256fb6c57aafa7a4bf1e13308f2442371a Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 16:51:10 +0100 Subject: [PATCH 138/256] ConsoleAnnotatorTest compiling against HtmlUnit 2.17 --- .../test/java/hudson/console/ConsoleAnnotatorTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/src/test/java/hudson/console/ConsoleAnnotatorTest.java b/test/src/test/java/hudson/console/ConsoleAnnotatorTest.java index 7ab76e9170..59dcd9bc3e 100644 --- a/test/src/test/java/hudson/console/ConsoleAnnotatorTest.java +++ b/test/src/test/java/hudson/console/ConsoleAnnotatorTest.java @@ -2,7 +2,8 @@ package hudson.console; import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.TextPage; -import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebRequest; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import hudson.FilePath; import hudson.Launcher; @@ -62,7 +63,7 @@ public class ConsoleAnnotatorTest { // make sure we see the annotation HtmlPage rsp = r.createWebClient().getPage(b, "console"); - assertEquals(1,rsp.selectNodes("//B[@class='demo']").size()); + assertEquals(1, DomNodeUtil.selectNodes(rsp, "//B[@class='demo']").size()); // make sure raw console output doesn't include the garbage TextPage raw = (TextPage)r.createWebClient().goTo(b.getUrl()+"consoleText","text/plain"); @@ -112,7 +113,7 @@ public class ConsoleAnnotatorTest { // make sure we see the annotation HtmlPage rsp = r.createWebClient().getPage(b, "console"); - assertEquals(1,rsp.selectNodes("//A[@href='http://infradna.com/']").size()); + assertEquals(1, DomNodeUtil.selectNodes(rsp, "//A[@href='http://infradna.com/']").size()); // make sure raw console output doesn't include the garbage TextPage raw = (TextPage)r.createWebClient().goTo(b.getUrl()+"consoleText","text/plain"); @@ -138,7 +139,7 @@ public class ConsoleAnnotatorTest { } String next() throws IOException { - WebRequestSettings req = new WebRequestSettings(new URL(r.getURL() + run.getUrl() + "/logText/progressiveHtml"+(start!=null?"?start="+start:""))); + WebRequest req = new WebRequest(new URL(r.getURL() + run.getUrl() + "/logText/progressiveHtml"+(start!=null?"?start="+start:""))); Map headers = new HashMap(); if (consoleAnnotator!=null) headers.put("X-ConsoleAnnotator",consoleAnnotator); From d3078ca4faa7d8f848721ca55e0db89cb3e6c033 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 16:51:59 +0100 Subject: [PATCH 139/256] ReverseProxySetupMonitorTest compiling against HtmlUnit 2.17 --- .../java/hudson/diagnosis/ReverseProxySetupMonitorTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/test/java/hudson/diagnosis/ReverseProxySetupMonitorTest.java b/test/src/test/java/hudson/diagnosis/ReverseProxySetupMonitorTest.java index 2e2d8dd6f1..6029837a5d 100644 --- a/test/src/test/java/hudson/diagnosis/ReverseProxySetupMonitorTest.java +++ b/test/src/test/java/hudson/diagnosis/ReverseProxySetupMonitorTest.java @@ -24,7 +24,7 @@ package hudson.diagnosis; -import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebRequest; import java.net.URL; import org.junit.Test; import org.junit.Rule; @@ -35,7 +35,7 @@ public class ReverseProxySetupMonitorTest { @Rule public JenkinsRule r = new JenkinsRule(); @Test public void normal() throws Exception { - WebRequestSettings wrs = new WebRequestSettings(new URL(r.getURL(), r.jenkins.getAdministrativeMonitor(ReverseProxySetupMonitor.class.getName()).getUrl() + "/test")); + WebRequest wrs = new WebRequest(new URL(r.getURL(), r.jenkins.getAdministrativeMonitor(ReverseProxySetupMonitor.class.getName()).getUrl() + "/test")); wrs.setAdditionalHeader("Referer", r.getURL() + "manage"); r.createWebClient().getPage(wrs); } From c7738f6351fb598a9e733eaa1f1c4a1b96d61d0a Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 16:52:38 +0100 Subject: [PATCH 140/256] ExpandableTextboxTest compiling against HtmlUnit 2.17 --- test/src/test/java/lib/form/ExpandableTextboxTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/test/java/lib/form/ExpandableTextboxTest.java b/test/src/test/java/lib/form/ExpandableTextboxTest.java index b930652d15..46cdf00e17 100644 --- a/test/src/test/java/lib/form/ExpandableTextboxTest.java +++ b/test/src/test/java/lib/form/ExpandableTextboxTest.java @@ -25,7 +25,7 @@ package lib.form; import static com.gargoylesoftware.htmlunit.HttpMethod.POST; import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebRequest; import com.gargoylesoftware.htmlunit.html.HtmlPage; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.HudsonTestCase; @@ -53,7 +53,7 @@ public class ExpandableTextboxTest extends HudsonTestCase { protected HtmlPage evaluateAsHtml(String jellyScript) throws Exception { HudsonTestCase.WebClient wc = new WebClient(); - WebRequestSettings req = new WebRequestSettings(wc.createCrumbedUrl("eval"), POST); + WebRequest req = new WebRequest(wc.createCrumbedUrl("eval"), POST); req.setRequestBody(""+jellyScript+""); Page page = wc.getPage(req); return (HtmlPage) page; From 3de7117413e026b87edef42ff65674cbc27ec53e Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 17:31:41 +0100 Subject: [PATCH 141/256] RepeatableTest compiling against HtmlUnit 2.17 --- .../test/java/lib/form/RepeatableTest.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/test/src/test/java/lib/form/RepeatableTest.java b/test/src/test/java/lib/form/RepeatableTest.java index 9807f14f5a..395e4b886f 100644 --- a/test/src/test/java/lib/form/RepeatableTest.java +++ b/test/src/test/java/lib/form/RepeatableTest.java @@ -24,6 +24,7 @@ package lib.form; import com.gargoylesoftware.htmlunit.ElementNotFoundException; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlSelect; @@ -33,7 +34,6 @@ import java.util.ArrayList; import java.util.List; import com.gargoylesoftware.htmlunit.javascript.background.JavaScriptJob; -import com.gargoylesoftware.htmlunit.javascript.background.JavaScriptJobManagerImpl; import hudson.DescriptorExtensionList; import hudson.Extension; import hudson.ExtensionPoint; @@ -68,11 +68,11 @@ public class RepeatableTest extends HudsonTestCase { private void doTestSimple() throws Exception { HtmlPage p = createWebClient().goTo("self/testSimple"); HtmlForm f = p.getFormByName("config"); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); f.getInputByValue("").setValueAttribute("value one"); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); f.getInputByValue("").setValueAttribute("value two"); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); f.getInputByValue("").setValueAttribute("value three"); f.getInputsByName("bool").get(2).click(); submit(f); @@ -201,10 +201,10 @@ public class RepeatableTest extends HudsonTestCase { public void testRadio() throws Exception { HtmlPage p = createWebClient().goTo("self/testRadio"); HtmlForm f = p.getFormByName("config"); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); f.getInputByValue("").setValueAttribute("txt one"); f.getElementsByAttribute("INPUT", "type", "radio").get(1).click(); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); f.getInputByValue("").setValueAttribute("txt two"); f.getElementsByAttribute("INPUT", "type", "radio").get(3).click(); submit(f); @@ -224,7 +224,7 @@ public class RepeatableTest extends HudsonTestCase { list.add(new FooRadio("three", "one")); HtmlPage p = createWebClient().goTo("self/testRadio"); HtmlForm f = p.getFormByName("config"); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); f.getInputByValue("").setValueAttribute("txt 4"); f.getElementsByAttribute("INPUT", "type", "radio").get(7).click(); submit(f); @@ -238,12 +238,12 @@ public class RepeatableTest extends HudsonTestCase { public void testRadioBlock() throws Exception { HtmlPage p = createWebClient().goTo("self/testRadioBlock"); HtmlForm f = p.getFormByName("config"); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); f.getInputByValue("").setValueAttribute("txt one"); f.getInputByValue("").setValueAttribute("avalue do not send"); f.getElementsByAttribute("INPUT", "type", "radio").get(1).click(); f.getInputByValue("").setValueAttribute("bvalue"); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); f.getInputByValue("").setValueAttribute("txt two"); f.getElementsByAttribute("INPUT", "type", "radio").get(2).click(); f.getInputByValue("").setValueAttribute("avalue two"); @@ -303,11 +303,11 @@ public class RepeatableTest extends HudsonTestCase { public void testDropdownList() throws Exception { HtmlPage p = createWebClient().goTo("self/testDropdownList"); HtmlForm f = p.getFormByName("config"); - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); waitForJavaScript(p); f.getInputByValue("").setValueAttribute("17"); // seeds f.getInputByValue("").setValueAttribute("pie"); // word - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); waitForJavaScript(p); // select banana in 2nd select element: ((HtmlSelect)f.getElementsByTagName("select").get(1)).getOption(1).click(); @@ -367,7 +367,7 @@ public class RepeatableTest extends HudsonTestCase { } private void clickButton(HtmlPage p, HtmlForm f, String caption) throws IOException { - f.getButtonByCaption(caption).click(); + HtmlFormUtil.getButtonByCaption(f, caption).click(); waitForJavaScript(p); } @@ -377,10 +377,10 @@ public class RepeatableTest extends HudsonTestCase { try { clickButton(p, f, "Add"); f.getElementsByAttribute("input", "type", "radio").get(1).click(); // outer=two - f.getButtonByCaption("Add Moo").click(); + HtmlFormUtil.getButtonByCaption(f, "Add Moo").click(); waitForJavaScript(p); f.getElementsByAttribute("input", "type", "radio").get(2).click(); // inner=inone - f.getButtonByCaption("Add").click(); + HtmlFormUtil.getButtonByCaption(f, "Add").click(); waitForJavaScript(p); f.getElementsByAttribute("input", "type", "radio").get(4).click(); // outer=one Thread.sleep(500); From 19818ec745b626e4b34cfffa5121ba3bcd2be45f Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 17:32:25 +0100 Subject: [PATCH 142/256] BasicHeaderProcessorTest compiling against HtmlUnit 2.17 --- .../test/java/jenkins/security/BasicHeaderProcessorTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/test/java/jenkins/security/BasicHeaderProcessorTest.java b/test/src/test/java/jenkins/security/BasicHeaderProcessorTest.java index b83327a118..1ef280e738 100644 --- a/test/src/test/java/jenkins/security/BasicHeaderProcessorTest.java +++ b/test/src/test/java/jenkins/security/BasicHeaderProcessorTest.java @@ -5,7 +5,7 @@ import static org.junit.Assert.fail; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebRequest; import hudson.model.UnprotectedRootAction; import hudson.model.User; import hudson.util.HttpResponses; @@ -81,7 +81,7 @@ public class BasicHeaderProcessorTest { } private void makeRequestWithAuthAndVerify(String userAndPass, String username) throws IOException, SAXException { - WebRequestSettings req = new WebRequestSettings(new URL(j.getURL(),"test")); + WebRequest req = new WebRequest(new URL(j.getURL(),"test")); if (userAndPass!=null) req.setAdditionalHeader("Authorization","Basic "+Scrambler.scramble(userAndPass)); Page p = wc.getPage(req); From 5d983399313833ac239f4847b8285e2f6da6f3ce Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 17:38:27 +0100 Subject: [PATCH 143/256] JenkinsTest compiling against HtmlUnit 2.17 --- test/src/test/java/jenkins/model/JenkinsTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/src/test/java/jenkins/model/JenkinsTest.java b/test/src/test/java/jenkins/model/JenkinsTest.java index 4b4bc7422d..724dc2632b 100644 --- a/test/src/test/java/jenkins/model/JenkinsTest.java +++ b/test/src/test/java/jenkins/model/JenkinsTest.java @@ -35,7 +35,7 @@ import static org.junit.Assert.fail; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.HttpMethod; import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebRequest; import com.gargoylesoftware.htmlunit.WebResponse; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; @@ -287,11 +287,11 @@ public class JenkinsTest { wc.goTo("script"); wc.assertFails("script?script=System.setProperty('hack','me')", HttpURLConnection.HTTP_BAD_METHOD); assertNull(System.getProperty("hack")); - WebRequestSettings req = new WebRequestSettings(new URL(wc.getContextPath() + "script?script=System.setProperty('hack','me')"), HttpMethod.POST); + WebRequest req = new WebRequest(new URL(wc.getContextPath() + "script?script=System.setProperty('hack','me')"), HttpMethod.POST); wc.getPage(wc.addCrumb(req)); assertEquals("me", System.getProperty("hack")); wc.assertFails("scriptText?script=System.setProperty('hack','me')", HttpURLConnection.HTTP_BAD_METHOD); - req = new WebRequestSettings(new URL(wc.getContextPath() + "scriptText?script=System.setProperty('huck','you')"), HttpMethod.POST); + req = new WebRequest(new URL(wc.getContextPath() + "scriptText?script=System.setProperty('huck','you')"), HttpMethod.POST); wc.getPage(wc.addCrumb(req)); assertEquals("you", System.getProperty("huck")); wc.login("bob"); @@ -333,7 +333,7 @@ public class JenkinsTest { } } private String eval(WebClient wc) throws Exception { - WebRequestSettings req = new WebRequestSettings(wc.createCrumbedUrl("eval"), HttpMethod.POST); + WebRequest req = new WebRequest(wc.createCrumbedUrl("eval"), HttpMethod.POST); req.setRequestBody("${1+2}"); return wc.getPage(req).getWebResponse().getContentAsString(); } @@ -393,7 +393,7 @@ public class JenkinsTest { assertTrue(!Jenkins.getInstance().getACL().hasPermission(Jenkins.ANONYMOUS,Jenkins.READ)); WebClient wc = j.createWebClient(); - wc.setThrowExceptionOnFailingStatusCode(false); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); HtmlPage p = wc.goTo("error/reportError"); assertEquals(p.asText(), 400, p.getWebResponse().getStatusCode()); // not 403 forbidden @@ -440,9 +440,9 @@ public class JenkinsTest { URL url = new URL(j.getURL(), "computer/" + slave.getNodeName() + "/scriptText?script=println(42)"); WebClient wc = j.createWebClient(); - wc.setThrowExceptionOnFailingStatusCode(false); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); - WebRequestSettings req = new WebRequestSettings(url, HttpMethod.POST); + WebRequest req = new WebRequest(url, HttpMethod.POST); Page page = wc.getPage(wc.addCrumb(req)); WebResponse rsp = page.getWebResponse(); From b19ccc28b8832b04f30d6d478f7446bcfc4220c9 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 17:42:19 +0100 Subject: [PATCH 144/256] HudsonTest compiling against HtmlUnit 2.17 --- test/src/test/java/hudson/model/HudsonTest.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/src/test/java/hudson/model/HudsonTest.java b/test/src/test/java/hudson/model/HudsonTest.java index 4a296f895f..5f5c006b59 100644 --- a/test/src/test/java/hudson/model/HudsonTest.java +++ b/test/src/test/java/hudson/model/HudsonTest.java @@ -28,9 +28,10 @@ import static org.junit.Assert.*; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.HttpMethod; import com.gargoylesoftware.htmlunit.Page; -import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebRequest; +import com.gargoylesoftware.htmlunit.html.DomElement; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import com.gargoylesoftware.htmlunit.html.HtmlAnchor; -import com.gargoylesoftware.htmlunit.html.HtmlElement; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; import hudson.model.Node.Mode; @@ -128,7 +129,7 @@ public class HudsonTest { FreeStyleProject p = j.createFreeStyleProject(); Page jobPage = j.search(p.getName()); - URL url = jobPage.getWebResponse().getUrl(); + URL url = jobPage.getUrl(); System.out.println(url); assertTrue(url.getPath().endsWith("/job/"+p.getName()+"/")); } @@ -139,8 +140,8 @@ public class HudsonTest { @Test public void breadcrumb() throws Exception { HtmlPage root = j.createWebClient().goTo(""); - HtmlElement navbar = root.getElementById("breadcrumbs"); - assertEquals(1,navbar.selectNodes("LI/A").size()); + DomElement navbar = root.getElementById("breadcrumbs"); + assertEquals(1, DomNodeUtil.selectNodes(navbar, "LI/A").size()); } /** @@ -165,7 +166,7 @@ public class HudsonTest { assertFalse(a.getHrefAttribute(),a.getHrefAttribute().endsWith("delete")); // try to delete it by hitting the final URL directly - WebRequestSettings req = new WebRequestSettings(new URL(wc.getContextPath()+"computer/(master)/doDelete"), HttpMethod.POST); + WebRequest req = new WebRequest(new URL(wc.getContextPath()+"computer/(master)/doDelete"), HttpMethod.POST); try { wc.getPage(wc.addCrumb(req)); fail("Error code expected"); From d380c884498cdc5ce5fea49765e6cf39a13c94f9 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 17:45:50 +0100 Subject: [PATCH 145/256] ViewTest compiling against HtmlUnit 2.17 --- test/src/test/java/hudson/model/ViewTest.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/test/src/test/java/hudson/model/ViewTest.java b/test/src/test/java/hudson/model/ViewTest.java index 68c370c295..ee696105b7 100644 --- a/test/src/test/java/hudson/model/ViewTest.java +++ b/test/src/test/java/hudson/model/ViewTest.java @@ -23,11 +23,12 @@ */ package hudson.model; +import com.gargoylesoftware.htmlunit.WebRequest; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import jenkins.model.Jenkins; import org.jvnet.hudson.test.Issue; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.HttpMethod; -import com.gargoylesoftware.htmlunit.WebRequestSettings; import com.gargoylesoftware.htmlunit.html.HtmlAnchor; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlLabel; @@ -48,9 +49,7 @@ import hudson.slaves.DumbSlave; import hudson.util.HudsonIsLoading; import java.io.File; import java.io.IOException; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import static org.junit.Assert.*; import org.junit.Ignore; import org.junit.Rule; @@ -100,7 +99,7 @@ public class ViewTest { WebClient wc = j.createWebClient(); HtmlPage userPage = wc.goTo("user/me"); - HtmlAnchor privateViewsLink = userPage.getFirstAnchorByText("My Views"); + HtmlAnchor privateViewsLink = userPage.getAnchorByText("My Views"); assertNotNull("My Views link not available", privateViewsLink); HtmlPage privateViewsPage = (HtmlPage) privateViewsLink.click(); @@ -157,7 +156,7 @@ public class ViewTest { @Test public void allImagesCanBeLoaded() throws Exception { User.get("user", true); WebClient webClient = j.createWebClient(); - webClient.setJavaScriptEnabled(false); + webClient.getOptions().setJavaScriptEnabled(false); j.assertAllImageLoadSuccessfully(webClient.goTo("asynchPeople")); } @@ -196,7 +195,7 @@ public class ViewTest { String xml = wc.goToXml("view/v/config.xml").getContent(); assertTrue(xml, xml.contains("one")); xml = xml.replace("one", "two"); - WebRequestSettings req = new WebRequestSettings(wc.createCrumbedUrl("view/v/config.xml"), HttpMethod.POST); + WebRequest req = new WebRequest(wc.createCrumbedUrl("view/v/config.xml"), HttpMethod.POST); req.setRequestBody(xml); wc.getPage(req); assertEquals("two", view.getDescription()); @@ -401,7 +400,7 @@ public class ViewTest { View view = listView("foo"); Thread.sleep(100000); HtmlForm f = j.createWebClient().getPage(view, "configure").getFormByName("viewConfig"); - ((HtmlLabel)f.selectSingleNode(".//LABEL[text()='Test property']")).click(); + ((HtmlLabel) DomNodeUtil.selectSingleNode(f, ".//LABEL[text()='Test property']")).click(); j.submit(f); assertNotNull("View should contains ViewPropertyImpl property.", view.getProperties().get(PropertyImpl.class)); } From c3b4f24057b88aa0bc23780e2744bb38431f31b8 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 17:46:46 +0100 Subject: [PATCH 146/256] JDKInstallerTest compiling against HtmlUnit 2.17 --- test/src/test/java/hudson/tools/JDKInstallerTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/src/test/java/hudson/tools/JDKInstallerTest.java b/test/src/test/java/hudson/tools/JDKInstallerTest.java index f4b79f6ca5..8f7bf1cf65 100644 --- a/test/src/test/java/hudson/tools/JDKInstallerTest.java +++ b/test/src/test/java/hudson/tools/JDKInstallerTest.java @@ -4,6 +4,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import hudson.tools.JDKInstaller.DescriptorImpl; import org.junit.Before; @@ -74,7 +75,7 @@ public class JDKInstallerTest { HtmlForm form = p.getFormByName("postCredential"); form.getInputByName("username").setValueAttribute("foo"); form.getInputByName("password").setValueAttribute("bar"); - form.submit(null); + HtmlFormUtil.submit(form, null); DescriptorImpl d = j.jenkins.getDescriptorByType(DescriptorImpl.class); assertEquals("foo",d.getUsername()); From f6d882f9982f795a3a0da284abf32d828bc3ab7f Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 17:47:57 +0100 Subject: [PATCH 147/256] FrameOptionsPageDecoratorTest compiling against HtmlUnit 2.17 --- .../java/jenkins/security/FrameOptionsPageDecoratorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/test/java/jenkins/security/FrameOptionsPageDecoratorTest.java b/test/src/test/java/jenkins/security/FrameOptionsPageDecoratorTest.java index f4507f81c8..0cb73f1d5a 100644 --- a/test/src/test/java/jenkins/security/FrameOptionsPageDecoratorTest.java +++ b/test/src/test/java/jenkins/security/FrameOptionsPageDecoratorTest.java @@ -5,7 +5,7 @@ import static org.junit.Assert.assertNull; import com.gargoylesoftware.htmlunit.WebResponse; import com.gargoylesoftware.htmlunit.html.HtmlPage; -import org.apache.commons.httpclient.NameValuePair; +import com.gargoylesoftware.htmlunit.util.NameValuePair; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; From 6127455912ef4b9104fc35839d34c5144f11faef Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 17:52:52 +0100 Subject: [PATCH 148/256] DirectlyModifiableViewTest compiling against HtmlUnit 2.17 --- test/src/test/java/hudson/model/DirectlyModifiableViewTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/test/java/hudson/model/DirectlyModifiableViewTest.java b/test/src/test/java/hudson/model/DirectlyModifiableViewTest.java index 977f7b7e9b..459862efa6 100644 --- a/test/src/test/java/hudson/model/DirectlyModifiableViewTest.java +++ b/test/src/test/java/hudson/model/DirectlyModifiableViewTest.java @@ -186,7 +186,7 @@ public class DirectlyModifiableViewTest { private Page doPost(View view, String path) throws Exception { WebClient wc = j.createWebClient(); - // wc.setThrowExceptionOnFailingStatusCode(false); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); WebRequest req = new WebRequest( new URL(j.jenkins.getRootUrl() + view.getUrl() + path), HttpMethod.POST From eb66d6b3107b1454da15ba67f4b5da9316e0a878 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 17:54:20 +0100 Subject: [PATCH 149/256] RekeySecretAdminMonitorTest compiling against HtmlUnit 2.17 --- .../jenkins/security/RekeySecretAdminMonitorTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java b/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java index 0797dc396f..92dfc68e24 100644 --- a/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java +++ b/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java @@ -1,6 +1,7 @@ package jenkins.security; import com.gargoylesoftware.htmlunit.ElementNotFoundException; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import com.gargoylesoftware.htmlunit.html.HtmlButton; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; @@ -100,8 +101,8 @@ public class RekeySecretAdminMonitorTest extends HudsonTestCase { // should be no warning/error now HtmlPage manage = wc.goTo("manage"); - assertEquals(0,manage.selectNodes("//*[class='error']").size()); - assertEquals(0,manage.selectNodes("//*[class='warning']").size()); + assertEquals(0,DomNodeUtil.selectNodes(manage, "//*[class='error']").size()); + assertEquals(0,DomNodeUtil.selectNodes(manage, "//*[class='warning']").size()); // and the data should be rewritten verifyRewrite(jenkins.getRootDir()); @@ -140,8 +141,8 @@ public class RekeySecretAdminMonitorTest extends HudsonTestCase { // should be no warning/error now HtmlPage manage = wc.goTo("/manage"); - assertEquals(0,manage.selectNodes("//*[class='error']").size()); - assertEquals(0,manage.selectNodes("//*[class='warning']").size()); + assertEquals(0,DomNodeUtil.selectNodes(manage, "//*[class='error']").size()); + assertEquals(0,DomNodeUtil.selectNodes(manage, "//*[class='warning']").size()); } private String encryptOld(String str) throws Exception { From 1894e1dfe61b9842a7b36b397764c72096c7bed3 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 17:55:58 +0100 Subject: [PATCH 150/256] HelpLinkTest compiling against HtmlUnit 2.17 --- test/src/test/java/hudson/model/HelpLinkTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/src/test/java/hudson/model/HelpLinkTest.java b/test/src/test/java/hudson/model/HelpLinkTest.java index 907f127cc9..f18a22124e 100644 --- a/test/src/test/java/hudson/model/HelpLinkTest.java +++ b/test/src/test/java/hudson/model/HelpLinkTest.java @@ -3,6 +3,7 @@ package hudson.model; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import hudson.tasks.BuildStepMonitor; import org.junit.Rule; import org.junit.Test; @@ -52,7 +53,7 @@ public class HelpLinkTest { } private void clickAllHelpLinks(HtmlPage p) throws Exception { - List helpLinks = p.selectNodes("//a[@class='help-button']"); + List helpLinks = DomNodeUtil.selectNodes(p, "//a[@class='help-button']"); assertTrue(helpLinks.size()>0); System.out.println("Clicking "+helpLinks.size()+" help links"); From 83d529cb93c21a06a36ba64531cdf7787dd2fb73 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 17:57:01 +0100 Subject: [PATCH 151/256] TooManyJobsButNoViewTest compiling against HtmlUnit 2.17 --- .../test/java/hudson/diagnosis/TooManyJobsButNoViewTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/test/java/hudson/diagnosis/TooManyJobsButNoViewTest.java b/test/src/test/java/hudson/diagnosis/TooManyJobsButNoViewTest.java index d8b1583271..2f6dab5072 100644 --- a/test/src/test/java/hudson/diagnosis/TooManyJobsButNoViewTest.java +++ b/test/src/test/java/hudson/diagnosis/TooManyJobsButNoViewTest.java @@ -55,7 +55,7 @@ public class TooManyJobsButNoViewTest { assertNotNull(f); // this should take us to the new view page - URL url = r.submit(f,"yes").getWebResponse().getUrl(); + URL url = r.submit(f,"yes").getUrl(); assertTrue(url.toExternalForm(),url.toExternalForm().endsWith("/newView")); // since we didn't create a view, if we go back, we should see the warning again From 84788b757e27e52467e96bb20e75d2050f72262c Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 17:57:35 +0100 Subject: [PATCH 152/256] UseRecipesWithJenkinsRuleTest compiling against HtmlUnit 2.17 --- .../org/jvnet/hudson/main/UseRecipesWithJenkinsRuleTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/test/java/org/jvnet/hudson/main/UseRecipesWithJenkinsRuleTest.java b/test/src/test/java/org/jvnet/hudson/main/UseRecipesWithJenkinsRuleTest.java index 18f1672c24..c4ded0e43e 100644 --- a/test/src/test/java/org/jvnet/hudson/main/UseRecipesWithJenkinsRuleTest.java +++ b/test/src/test/java/org/jvnet/hudson/main/UseRecipesWithJenkinsRuleTest.java @@ -62,7 +62,7 @@ public class UseRecipesWithJenkinsRuleTest { private void verifyNotError(WebClient wc) throws IOException, SAXException { HtmlPage p = wc.goTo("loginError"); - URL url = p.getWebResponse().getUrl(); + URL url = p.getUrl(); System.out.println(url); assertFalse(url.toExternalForm().contains("login")); } From 69b6b725c2bf31692cb73e682142a6f3085d26f9 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 18:00:39 +0100 Subject: [PATCH 153/256] LoginTest compiling against HtmlUnit 2.17 --- test/src/test/java/hudson/security/LoginTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/src/test/java/hudson/security/LoginTest.java b/test/src/test/java/hudson/security/LoginTest.java index 37551a39a3..86c1a0662c 100644 --- a/test/src/test/java/hudson/security/LoginTest.java +++ b/test/src/test/java/hudson/security/LoginTest.java @@ -6,6 +6,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput; @@ -40,7 +41,7 @@ public class LoginTest { private void verifyNotError(WebClient wc) throws IOException, SAXException { HtmlPage p = wc.goTo("loginError"); - URL url = p.getWebResponse().getUrl(); + URL url = p.getUrl(); System.out.println(url); assertFalse(url.toExternalForm().contains("login")); } @@ -84,7 +85,7 @@ public class LoginTest { public void loginRememberMe() throws Exception { WebClient wc = j.createWebClient(); - prepareLoginFormWithRememberMeChecked(wc).submit(null); + HtmlFormUtil.submit(prepareLoginFormWithRememberMeChecked(wc), null); assertNotNull(getRememberMeCookie(wc)); } @@ -100,7 +101,7 @@ public class LoginTest { HtmlForm form = prepareLoginFormWithRememberMeChecked(wc); j.jenkins.setDisableRememberMe(true); - form.submit(null); + HtmlFormUtil.submit(form, null); assertNull(getRememberMeCookie(wc)); } From be110a65bd4451fec49985c58c151bb76a03c762 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 18:01:29 +0100 Subject: [PATCH 154/256] QueueTest compiling against HtmlUnit 2.17 --- test/src/test/java/hudson/model/QueueTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/src/test/java/hudson/model/QueueTest.java b/test/src/test/java/hudson/model/QueueTest.java index 283b771a2c..6e566f7129 100644 --- a/test/src/test/java/hudson/model/QueueTest.java +++ b/test/src/test/java/hudson/model/QueueTest.java @@ -25,6 +25,7 @@ package hudson.model; import com.gargoylesoftware.htmlunit.html.HtmlFileInput; import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.xml.XmlPage; import hudson.Launcher; @@ -284,7 +285,7 @@ public class QueueTest { HtmlForm f = p.getFormByName("main"); HtmlFileInput input = (HtmlFileInput) f.getInputByName("test"); input.setData(testData); - f.submit(); + HtmlFormUtil.submit(f); } finally { server.stop(); } From fc80e221a66b3f9dc4925a272ce0af9757c16b8e Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 18:02:14 +0100 Subject: [PATCH 155/256] ListScmBrowsersTest compiling against HtmlUnit 2.17 --- test/src/test/java/lib/hudson/ListScmBrowsersTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/src/test/java/lib/hudson/ListScmBrowsersTest.java b/test/src/test/java/lib/hudson/ListScmBrowsersTest.java index 5c24db227e..f920bde13c 100644 --- a/test/src/test/java/lib/hudson/ListScmBrowsersTest.java +++ b/test/src/test/java/lib/hudson/ListScmBrowsersTest.java @@ -2,6 +2,7 @@ package lib.hudson; import static org.junit.Assert.assertTrue; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import com.gargoylesoftware.htmlunit.html.HtmlOption; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.html.HtmlSelect; @@ -41,7 +42,7 @@ public class ListScmBrowsersTest { private void check(Item p) throws IOException, SAXException { HtmlPage page = j.createWebClient().getPage(p, "configure"); - List selects = page.selectNodes("//select"); + List selects = DomNodeUtil.selectNodes(page, "//select"); assertTrue(selects.size()>0); for (HtmlSelect select : selects) { Set title = new HashSet(); From ed2f9cab15d67dd7aec9b3693b0d87a14e34ae47 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 18:09:49 +0100 Subject: [PATCH 156/256] ParametersTest compiling against HtmlUnit 2.17 --- .../htmlunit/html/HtmlFormUtil.java | 4 +- .../java/hudson/model/ParametersTest.java | 50 ++++++++++--------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java index 1ba14e7f30..e08177881c 100644 --- a/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java @@ -82,10 +82,10 @@ public class HtmlFormUtil { return getSubmitButtons(htmlForm).get(0); } - public static HtmlButton getButtonByCaption(final HtmlForm htmlForm, final String caption) throws ElementNotFoundException { + public static HtmlSubmitInput getButtonByCaption(final HtmlForm htmlForm, final String caption) throws ElementNotFoundException { for (HtmlElement b : htmlForm.getHtmlElementsByTagName("button")) { if(b.getTextContent().trim().equals(caption)) - return (HtmlButton)b; + return (HtmlSubmitInput) b; } throw new ElementNotFoundException("button", "caption", caption); } diff --git a/test/src/test/java/hudson/model/ParametersTest.java b/test/src/test/java/hudson/model/ParametersTest.java index 2d87d5ef9e..9f525a420c 100644 --- a/test/src/test/java/hudson/model/ParametersTest.java +++ b/test/src/test/java/hudson/model/ParametersTest.java @@ -2,6 +2,8 @@ package hudson.model; import static org.junit.Assert.*; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import org.junit.Rule; import org.junit.Test; @@ -42,38 +44,38 @@ public class ParametersTest { project.getBuildersList().add(builder); WebClient wc = j.createWebClient(); - wc.setThrowExceptionOnFailingStatusCode(false); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); HtmlPage page = wc.goTo("job/" + project.getName() + "/build?delay=0sec"); HtmlForm form = page.getFormByName("parameters"); - HtmlElement element = (HtmlElement) form.selectSingleNode("//tr[td/div/input/@value='string']"); + HtmlElement element = (HtmlElement) DomNodeUtil.selectSingleNode(form, "//tr[td/div/input/@value='string']"); assertNotNull(element); - assertEquals("string description", ((HtmlElement) element.getNextSibling().getNextSibling().selectSingleNode("td[@class='setting-description']")).getTextContent()); + assertEquals("string description", ((HtmlElement) DomNodeUtil.selectSingleNode(element.getNextSibling().getNextSibling(), "td[@class='setting-description']")).getTextContent()); - HtmlTextInput stringParameterInput = (HtmlTextInput) element.selectSingleNode(".//input[@name='value']"); + HtmlTextInput stringParameterInput = (HtmlTextInput) DomNodeUtil.selectSingleNode(element, ".//input[@name='value']"); assertEquals("defaultValue", stringParameterInput.getAttribute("value")); - assertEquals("string", ((HtmlElement) element.selectSingleNode("td[@class='setting-name']")).getTextContent()); + assertEquals("string", ((HtmlElement) DomNodeUtil.selectSingleNode(element, "td[@class='setting-name']")).getTextContent()); stringParameterInput.setAttribute("value", "newValue"); - element = (HtmlElement) form.selectSingleNode("//tr[td/div/input/@value='boolean']"); + element = (HtmlElement) DomNodeUtil.selectSingleNode(form, "//tr[td/div/input/@value='boolean']"); assertNotNull(element); - assertEquals("boolean description", ((HtmlElement) element.getNextSibling().getNextSibling().selectSingleNode("td[@class='setting-description']")).getTextContent()); - Object o = element.selectSingleNode(".//input[@name='value']"); + assertEquals("boolean description", ((HtmlElement) DomNodeUtil.selectSingleNode(element.getNextSibling().getNextSibling(), "td[@class='setting-description']")).getTextContent()); + Object o = DomNodeUtil.selectSingleNode(element, ".//input[@name='value']"); System.out.println(o); HtmlCheckBoxInput booleanParameterInput = (HtmlCheckBoxInput) o; assertEquals(true, booleanParameterInput.isChecked()); - assertEquals("boolean", ((HtmlElement) element.selectSingleNode("td[@class='setting-name']")).getTextContent()); + assertEquals("boolean", ((HtmlElement) DomNodeUtil.selectSingleNode(element, "td[@class='setting-name']")).getTextContent()); - element = (HtmlElement) form.selectSingleNode(".//tr[td/div/input/@value='choice']"); + element = (HtmlElement) DomNodeUtil.selectSingleNode(form, ".//tr[td/div/input/@value='choice']"); assertNotNull(element); - assertEquals("choice description", ((HtmlElement) element.getNextSibling().getNextSibling().selectSingleNode("td[@class='setting-description']")).getTextContent()); - assertEquals("choice", ((HtmlElement) element.selectSingleNode("td[@class='setting-name']")).getTextContent()); + assertEquals("choice description", ((HtmlElement) DomNodeUtil.selectSingleNode(element.getNextSibling().getNextSibling(), "td[@class='setting-description']")).getTextContent()); + assertEquals("choice", ((HtmlElement) DomNodeUtil.selectSingleNode(element, "td[@class='setting-name']")).getTextContent()); - element = (HtmlElement) form.selectSingleNode(".//tr[td/div/input/@value='run']"); + element = (HtmlElement) DomNodeUtil.selectSingleNode(form, ".//tr[td/div/input/@value='run']"); assertNotNull(element); - assertEquals("run description", ((HtmlElement) element.getNextSibling().getNextSibling().selectSingleNode("td[@class='setting-description']")).getTextContent()); - assertEquals("run", ((HtmlElement) element.selectSingleNode("td[@class='setting-name']")).getTextContent()); + assertEquals("run description", ((HtmlElement) DomNodeUtil.selectSingleNode(element.getNextSibling().getNextSibling(), "td[@class='setting-description']")).getTextContent()); + assertEquals("run", ((HtmlElement) DomNodeUtil.selectSingleNode(element, "td[@class='setting-name']")).getTextContent()); j.submit(form); Queue.Item q = j.jenkins.getQueue().getItem(project); @@ -96,15 +98,15 @@ public class ParametersTest { project.getBuildersList().add(builder); WebClient wc = j.createWebClient(); - wc.setThrowExceptionOnFailingStatusCode(false); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); HtmlPage page = wc.goTo("job/" + project.getName() + "/build?delay=0sec"); HtmlForm form = page.getFormByName("parameters"); - HtmlElement element = (HtmlElement) form.selectSingleNode(".//tr[td/div/input/@value='choice']"); + HtmlElement element = (HtmlElement) DomNodeUtil.selectSingleNode(form, ".//tr[td/div/input/@value='choice']"); assertNotNull(element); - assertEquals("choice description", ((HtmlElement) element.getNextSibling().getNextSibling().selectSingleNode("td[@class='setting-description']")).getTextContent()); - assertEquals("choice", ((HtmlElement) element.selectSingleNode("td[@class='setting-name']")).getTextContent()); - HtmlOption opt = (HtmlOption)element.selectSingleNode("td/div/select/option[@value='Choice <2>']"); + assertEquals("choice description", ((HtmlElement) DomNodeUtil.selectSingleNode(element.getNextSibling().getNextSibling(), "td[@class='setting-description']")).getTextContent()); + assertEquals("choice", ((HtmlElement) DomNodeUtil.selectSingleNode(element, "td[@class='setting-name']")).getTextContent()); + HtmlOption opt = (HtmlOption)DomNodeUtil.selectSingleNode(element, "td/div/select/option[@value='Choice <2>']"); assertNotNull(opt); assertEquals("Choice <2>", opt.asText()); opt.setSelected(true); @@ -183,7 +185,7 @@ public class ParametersTest { project.addProperty(pdp); WebClient wc = j.createWebClient(); - wc.setThrowExceptionOnFailingStatusCode(false); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); HtmlPage page = wc.goTo("job/" + project.getName() + "/build?delay=0sec"); HtmlForm form = page.getFormByName("parameters"); @@ -206,12 +208,12 @@ public class ParametersTest { p.addProperty(pdb); WebClient wc = j.createWebClient(); - wc.setThrowExceptionOnFailingStatusCode(false); // Ignore 405 + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); // Ignore 405 HtmlPage page = wc.getPage(p, "build"); // java.lang.IllegalArgumentException: No such parameter definition: . - wc.setThrowExceptionOnFailingStatusCode(true); + wc.getOptions().setThrowExceptionOnFailingStatusCode(true); final HtmlForm form = page.getFormByName("parameters"); - form.submit(form.getButtonByCaption("Build")); + HtmlFormUtil.submit(form, HtmlFormUtil.getButtonByCaption(form, "Build")); } } From fa8865b9f256e9745e14380faa9b8e50bc3c9b8f Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 19:01:51 +0100 Subject: [PATCH 157/256] ApiTokenPropertyTest compiling against HtmlUnit 2.17 (PITA) --- .../security/ApiTokenPropertyTest.java | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java b/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java index a28c0582a0..54d75bf66c 100644 --- a/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java +++ b/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java @@ -5,19 +5,13 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import com.gargoylesoftware.htmlunit.HttpWebConnection; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; import hudson.Util; import hudson.model.User; import jenkins.model.Jenkins; -import org.apache.commons.httpclient.Credentials; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.UsernamePasswordCredentials; -import org.apache.commons.httpclient.auth.AuthScheme; -import org.apache.commons.httpclient.auth.AuthScope; -import org.apache.commons.httpclient.auth.CredentialsNotAvailableException; -import org.apache.commons.httpclient.auth.CredentialsProvider; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; @@ -53,20 +47,22 @@ public class ApiTokenPropertyTest { assertSame(t, u.getProperty(ApiTokenProperty.class)); WebClient wc = j.createWebClient(); - wc.setCredentialsProvider(new CredentialsProvider() { - public Credentials getCredentials(AuthScheme scheme, String host, int port, boolean proxy) throws CredentialsNotAvailableException { - return new UsernamePasswordCredentials("foo", token); - } - }); - wc.setWebConnection(new HttpWebConnection(wc) { - @Override - protected HttpClient getHttpClient() { - HttpClient c = super.getHttpClient(); - c.getParams().setAuthenticationPreemptive(true); - c.getState().setCredentials(new AuthScope("localhost", AuthScope.ANY_PORT, AuthScope.ANY_REALM), new UsernamePasswordCredentials("foo", token)); - return c; - } - }); + wc.getCredentialsProvider().setCredentials( + new AuthScope("localhost", AuthScope.ANY_PORT), + new UsernamePasswordCredentials("foo", token) + ); +// TODO: Find a way to do this. +// May need to upgrade to httpclient 4.3+ by adding a org.apache.httpcomponents:httpclient exclusion on the maven-plugin +// See http://stackoverflow.com/questions/2014700/preemptive-basic-authentication-with-apache-httpclient-4 etc +// wc.setWebConnection(new HttpWebConnection(wc) { +// @Override +// protected HttpClient getHttpClient() { +// HttpClient c = super.getHttpClient(); +// c.getParams().setAuthenticationPreemptive(true); +// c.getState().setCredentials(new AuthScope("localhost", AuthScope.ANY_PORT, AuthScope.ANY_REALM), new UsernamePasswordCredentials("foo", token)); +// return c; +// } +// }); // test the authentication assertEquals(u,wc.executeOnServer(new Callable() { From 1cdfdf5809e1426817863cf0402a0dcb4bb56060 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 19:28:18 +0100 Subject: [PATCH 158/256] ViewPropertyTest compiling against HtmlUnit 2.17 --- test/src/test/java/hudson/model/ViewPropertyTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/src/test/java/hudson/model/ViewPropertyTest.java b/test/src/test/java/hudson/model/ViewPropertyTest.java index 5aa6ca9919..7524865984 100644 --- a/test/src/test/java/hudson/model/ViewPropertyTest.java +++ b/test/src/test/java/hudson/model/ViewPropertyTest.java @@ -23,6 +23,7 @@ */ package hudson.model; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlLabel; import hudson.model.Descriptor.FormException; @@ -42,7 +43,7 @@ public class ViewPropertyTest extends HudsonTestCase { // make sure it renders as optionalBlock HtmlForm f = createWebClient().getPage(foo, "configure").getFormByName("viewConfig"); - ((HtmlLabel)f.selectSingleNode(".//LABEL[text()='Debug Property']")).click(); + ((HtmlLabel) DomNodeUtil.selectSingleNode(f, ".//LABEL[text()='Debug Property']")).click(); submit(f); ViewPropertyImpl vp = foo.getProperties().get(ViewPropertyImpl.class); assertEquals("Duke",vp.name); From 9e6dab9e26db52ff343997fe188a25da1a034d78 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 19:29:02 +0100 Subject: [PATCH 159/256] JnlpAccessWithSecuredHudsonTest compiling against HtmlUnit 2.17 --- .../test/java/hudson/bugs/JnlpAccessWithSecuredHudsonTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/test/java/hudson/bugs/JnlpAccessWithSecuredHudsonTest.java b/test/src/test/java/hudson/bugs/JnlpAccessWithSecuredHudsonTest.java index 52dc53e89b..778294e034 100644 --- a/test/src/test/java/hudson/bugs/JnlpAccessWithSecuredHudsonTest.java +++ b/test/src/test/java/hudson/bugs/JnlpAccessWithSecuredHudsonTest.java @@ -74,7 +74,7 @@ public class JnlpAccessWithSecuredHudsonTest extends HudsonTestCase { // parse the JNLP page into DOM to list up the jars. XmlPage jnlp = (XmlPage) wc.goTo("computer/test/slave-agent.jnlp","application/x-java-jnlp-file"); - URL baseUrl = jnlp.getWebResponse().getUrl(); + URL baseUrl = jnlp.getUrl(); Document dom = new DOMReader().read(jnlp.getXmlDocument()); for( Element jar : (List)dom.selectNodes("//jar") ) { URL url = new URL(baseUrl,jar.attributeValue("href")); From 4a3ec64b648dc7662485c65566abb6353cef0aa9 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 19:30:32 +0100 Subject: [PATCH 160/256] RowVisibilityGroupTest compiling against HtmlUnit 2.17 --- .../test/java/lib/form/RowVisibilityGroupTest.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/src/test/java/lib/form/RowVisibilityGroupTest.java b/test/src/test/java/lib/form/RowVisibilityGroupTest.java index 2163ac0a69..1c00a255db 100644 --- a/test/src/test/java/lib/form/RowVisibilityGroupTest.java +++ b/test/src/test/java/lib/form/RowVisibilityGroupTest.java @@ -1,5 +1,6 @@ package lib.form; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import com.gargoylesoftware.htmlunit.html.HtmlElement; import com.gargoylesoftware.htmlunit.html.HtmlInput; import com.gargoylesoftware.htmlunit.html.HtmlOption; @@ -42,9 +43,9 @@ public class RowVisibilityGroupTest extends HudsonTestCase implements Describabl public void test1() throws Exception { HtmlPage p = createWebClient().goTo("self/test1"); - HtmlElement outer = (HtmlElement)p.selectSingleNode("//INPUT[@name='outer']"); - HtmlElement inner = (HtmlElement)p.selectSingleNode("//INPUT[@name='inner']"); - HtmlInput field = (HtmlInput)p.selectSingleNode("//INPUT[@type='text'][@name='_.field']"); + HtmlElement outer = (HtmlElement)DomNodeUtil.selectSingleNode(p, "//INPUT[@name='outer']"); + HtmlElement inner = (HtmlElement)DomNodeUtil.selectSingleNode(p, "//INPUT[@name='inner']"); + HtmlInput field = (HtmlInput)DomNodeUtil.selectSingleNode(p, "//INPUT[@type='text'][@name='_.field']"); // outer gets unfolded, but inner should be still folded outer.click(); @@ -67,7 +68,7 @@ public class RowVisibilityGroupTest extends HudsonTestCase implements Describabl public void test2() throws Exception { HtmlPage p = createWebClient().goTo("self/test2"); - HtmlSelect s = (HtmlSelect)p.selectSingleNode("//SELECT"); + HtmlSelect s = (HtmlSelect)DomNodeUtil.selectSingleNode(p, "//SELECT"); List opts = s.getOptions(); // those first selections will load additional HTMLs @@ -78,13 +79,13 @@ public class RowVisibilityGroupTest extends HudsonTestCase implements Describabl s.setSelectedAttribute(opts.get(0),true); // make sure that the inner control is still hidden - List textboxes = p.selectNodes("//INPUT[@name='_.textbox2']"); + List textboxes = DomNodeUtil.selectNodes(p, "//INPUT[@name='_.textbox2']"); assertEquals(2,textboxes.size()); for (HtmlInput e : textboxes) assertTrue(!e.isDisplayed()); // reveal the text box - List checkboxes = p.selectNodes("//INPUT[@name='inner']"); + List checkboxes = DomNodeUtil.selectNodes(p, "//INPUT[@name='inner']"); assertEquals(2,checkboxes.size()); checkboxes.get(0).click(); assertTrue(textboxes.get(0).isDisplayed()); From 63d42661daca29c0fb663c9d453df379be6f1674 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 19:31:32 +0100 Subject: [PATCH 161/256] LoginRedirectTest compiling against HtmlUnit 2.17 --- test/src/test/java/hudson/bugs/LoginRedirectTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/src/test/java/hudson/bugs/LoginRedirectTest.java b/test/src/test/java/hudson/bugs/LoginRedirectTest.java index d26ab3c11a..033966cf18 100644 --- a/test/src/test/java/hudson/bugs/LoginRedirectTest.java +++ b/test/src/test/java/hudson/bugs/LoginRedirectTest.java @@ -24,6 +24,7 @@ package hudson.bugs; import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import java.net.HttpURLConnection; import org.jvnet.hudson.test.Issue; @@ -47,7 +48,7 @@ public class LoginRedirectTest extends HudsonTestCase { public void testRedirect() throws Exception { WebClient wc = new WebClient(); // Hudson first causes 403 FORBIDDEN error, then redirect the browser to the page - wc.setThrowExceptionOnFailingStatusCode(false); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); HtmlPage p = wc.goTo("/"); System.out.println(p.getDocumentURI()); @@ -55,7 +56,7 @@ public class LoginRedirectTest extends HudsonTestCase { HtmlForm form = p.getFormByName("login"); form.getInputByName("j_username").setValueAttribute("alice"); form.getInputByName("j_password").setValueAttribute("alice"); - p = (HtmlPage) form.submit(null); + p = (HtmlPage) HtmlFormUtil.submit(form, null); System.out.println(p); } From 6cad8d254cab52b69aae635938d816e9741f7a98 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 19:32:14 +0100 Subject: [PATCH 162/256] AdvancedButtonTest compiling against HtmlUnit 2.17 --- test/src/test/java/lib/form/AdvancedButtonTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/src/test/java/lib/form/AdvancedButtonTest.java b/test/src/test/java/lib/form/AdvancedButtonTest.java index afba6e2cb6..e96c2c61b6 100644 --- a/test/src/test/java/lib/form/AdvancedButtonTest.java +++ b/test/src/test/java/lib/form/AdvancedButtonTest.java @@ -1,6 +1,7 @@ package lib.form; import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import hudson.util.FormValidation; import net.sf.json.JSONObject; @@ -17,7 +18,7 @@ public class AdvancedButtonTest extends HudsonTestCase { public void testNestedOptionalBlock() throws Exception { HtmlPage p = createWebClient().goTo("self/testNestedOptionalBlock"); HtmlForm f = p.getFormByName("config"); - f.getButtonByCaption("Advanced...").click(); + HtmlFormUtil.getButtonByCaption(f, "Advanced...").click(); f.getInputByName("c").click(); submit(f); } From 9b5a4ea4c637b99353e5d8ea8293740eea4360d2 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 19:33:22 +0100 Subject: [PATCH 163/256] LayoutTest compiling against HtmlUnit 2.17 --- test/src/test/java/lib/layout/LayoutTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/test/java/lib/layout/LayoutTest.java b/test/src/test/java/lib/layout/LayoutTest.java index 8590ff4aed..1889d71d51 100644 --- a/test/src/test/java/lib/layout/LayoutTest.java +++ b/test/src/test/java/lib/layout/LayoutTest.java @@ -24,7 +24,7 @@ package lib.layout; -import com.gargoylesoftware.htmlunit.html.HtmlElement; +import com.gargoylesoftware.htmlunit.html.DomElement; import com.gargoylesoftware.htmlunit.html.HtmlLink; import org.junit.Rule; import org.junit.Test; @@ -41,7 +41,7 @@ public class LayoutTest { @Test public void rejectedLinks() throws Exception { JenkinsRule.WebClient wc = r.createWebClient(); String prefix = r.contextPath + '/'; - for (HtmlElement e : wc.goTo("login").getElementsByTagName("link")) { + for (DomElement e : wc.goTo("login").getElementsByTagName("link")) { String href = ((HtmlLink) e).getHrefAttribute(); if (!href.startsWith(prefix)) { System.err.println("ignoring " + href); From d2606593579e9849235a0b91864a4512be2bd0cc Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 19:34:14 +0100 Subject: [PATCH 164/256] ValidateButtonTest compiling against HtmlUnit 2.17 --- test/src/test/java/lib/form/ValidateButtonTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/src/test/java/lib/form/ValidateButtonTest.java b/test/src/test/java/lib/form/ValidateButtonTest.java index 6cd1e5fc92..1039686af4 100644 --- a/test/src/test/java/lib/form/ValidateButtonTest.java +++ b/test/src/test/java/lib/form/ValidateButtonTest.java @@ -23,6 +23,7 @@ */ package lib.form; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import org.jvnet.hudson.test.HudsonTestCase; import org.kohsuke.stapler.QueryParameter; import hudson.model.Describable; @@ -41,7 +42,7 @@ public class ValidateButtonTest extends HudsonTestCase implements Describable Date: Thu, 23 Jul 2015 19:34:46 +0100 Subject: [PATCH 165/256] ManagementLinkTest compiling against HtmlUnit 2.17 --- test/src/test/java/hudson/model/ManagementLinkTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/src/test/java/hudson/model/ManagementLinkTest.java b/test/src/test/java/hudson/model/ManagementLinkTest.java index 52622e28ef..4b19f2c8bb 100644 --- a/test/src/test/java/hudson/model/ManagementLinkTest.java +++ b/test/src/test/java/hudson/model/ManagementLinkTest.java @@ -25,6 +25,7 @@ package hudson.model; import static org.junit.Assert.assertTrue; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import com.gargoylesoftware.htmlunit.html.HtmlAnchor; import com.gargoylesoftware.htmlunit.html.HtmlPage; import org.junit.Rule; @@ -47,7 +48,7 @@ public class ManagementLinkTest { @Test public void links() throws Exception { HtmlPage page = j.createWebClient().goTo("manage"); - List anchors = page.selectNodes("id('management-links')//*[@class='link']/a[not(@onclick)]"); + List anchors = DomNodeUtil.selectNodes(page, "id('management-links')//*[@class='link']/a[not(@onclick)]"); assertTrue(anchors.size()>=8); for(HtmlAnchor e : (List) anchors) { e.click(); From 8dea7d9b01c72f7ead9fb457a80c996c7ce5c705 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 19:35:14 +0100 Subject: [PATCH 166/256] Security177Test compiling against HtmlUnit 2.17 --- test/src/test/java/jenkins/security/Security177Test.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/test/java/jenkins/security/Security177Test.java b/test/src/test/java/jenkins/security/Security177Test.java index c212cba2d2..d52b308822 100644 --- a/test/src/test/java/jenkins/security/Security177Test.java +++ b/test/src/test/java/jenkins/security/Security177Test.java @@ -20,7 +20,7 @@ public class Security177Test { @Test public void nosniff() throws Exception { WebClient wc = jenkins.createWebClient(); - wc.setThrowExceptionOnFailingStatusCode(false); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); URL u = jenkins.getURL(); verifyNoSniff(wc.getPage(new URL(u, "adjuncts/507db12b/nosuch/adjunct.js"))); From 61173941bd384c9ea9465ce3b774447d0c605864 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 19:36:46 +0100 Subject: [PATCH 167/256] IconTest compiling against HtmlUnit 2.17 --- test/src/test/java/lib/layout/IconTest.java | 24 ++++++++++----------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/test/src/test/java/lib/layout/IconTest.java b/test/src/test/java/lib/layout/IconTest.java index dbcfc7e19b..1e9814c8df 100644 --- a/test/src/test/java/lib/layout/IconTest.java +++ b/test/src/test/java/lib/layout/IconTest.java @@ -23,9 +23,7 @@ */ package lib.layout; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - +import com.gargoylesoftware.htmlunit.html.DomElement; import com.gargoylesoftware.htmlunit.html.HtmlElement; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.google.common.collect.Lists; @@ -53,8 +51,8 @@ public class IconTest extends HudsonTestCase { public void testIcons() throws Exception { HtmlPage p = createWebClient().goTo("self/01_testIcons"); - HtmlElement iconsBlock = p.getElementById("iconsBlock"); - List icons = Lists.newArrayList(iconsBlock.getChildElements()); + DomElement iconsBlock = p.getElementById("iconsBlock"); + List icons = Lists.newArrayList(iconsBlock.getChildElements()); assertIconToImageOkay(icons.get(0), "/images/16x16/aborted.png", "icon-aborted icon-sm"); assertIconToImageOkay(icons.get(1), "/images/24x24/aborted.png", "icon-aborted icon-md"); @@ -72,12 +70,12 @@ public class IconTest extends HudsonTestCase { public void testBallColorTd() throws Exception { HtmlPage p = createWebClient().goTo("self/02_testBallColorTd"); - HtmlElement ballColorAborted = p.getElementById("ballColorAborted"); - List ballIcons = Lists.newArrayList(ballColorAborted.getChildElements()); + DomElement ballColorAborted = p.getElementById("ballColorAborted"); + List ballIcons = Lists.newArrayList(ballColorAborted.getChildElements()); assertIconToImageOkay(ballIcons.get(0), "/images/32x32/aborted.png", "icon-aborted icon-lg"); - HtmlElement statusIcons = p.getElementById("statusIcons"); - List statusIconsList = Lists.newArrayList(statusIcons.getChildElements()); + DomElement statusIcons = p.getElementById("statusIcons"); + List statusIconsList = Lists.newArrayList(statusIcons.getChildElements()); assertIconToImageOkay(statusIconsList.get(0), "/images/32x32/folder.png", "icon-folder icon-lg"); assertIconToImageOkay(statusIconsList.get(1), "/plugin/12345/icons/s2.png"); @@ -86,8 +84,8 @@ public class IconTest extends HudsonTestCase { public void testTasks() throws Exception { HtmlPage p = createWebClient().goTo("self/03_testTask"); - HtmlElement tasksDiv = p.getElementById("tasks"); - List taskDivs = Lists.newArrayList(tasksDiv.getChildElements()); + DomElement tasksDiv = p.getElementById("tasks"); + List taskDivs = Lists.newArrayList(tasksDiv.getChildElements()); assertIconToImageOkay(taskDivs.get(0).getElementsByTagName("img").get(0), "/images/24x24/up.png", "icon-up icon-md"); assertIconToImageOkay(taskDivs.get(1).getElementsByTagName("img").get(0), "/images/24x24/folder.png", "icon-folder icon-md"); @@ -120,11 +118,11 @@ public class IconTest extends HudsonTestCase { }; } - private void assertIconToImageOkay(HtmlElement icon, String imgPath) { + private void assertIconToImageOkay(DomElement icon, String imgPath) { assertIconToImageOkay(icon, imgPath, null); } - private void assertIconToImageOkay(HtmlElement icon, String imgPath, String classSpec) { + private void assertIconToImageOkay(DomElement icon, String imgPath, String classSpec) { assertEquals("img", icon.getTagName()); assertTrue(icon.getAttribute("src").endsWith(imgPath)); if (classSpec != null) { From dc1e42088691d06c61023fea8210490d82d491a7 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 19:37:25 +0100 Subject: [PATCH 168/256] NodePropertyTest compiling against HtmlUnit 2.17 --- test/src/test/java/hudson/slaves/NodePropertyTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/src/test/java/hudson/slaves/NodePropertyTest.java b/test/src/test/java/hudson/slaves/NodePropertyTest.java index 6bcdb8070e..27e88fc58a 100644 --- a/test/src/test/java/hudson/slaves/NodePropertyTest.java +++ b/test/src/test/java/hudson/slaves/NodePropertyTest.java @@ -6,6 +6,7 @@ import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlLabel; import hudson.model.Descriptor.FormException; @@ -63,7 +64,7 @@ public class NodePropertyTest { public void basicConfigRoundtrip() throws Exception { DumbSlave s = j.createSlave(); HtmlForm f = j.createWebClient().goTo("computer/" + s.getNodeName() + "/configure").getFormByName("config"); - ((HtmlLabel)f.selectSingleNode(".//LABEL[text()='Some Property']")).click(); + ((HtmlLabel)DomNodeUtil.selectSingleNode(f, ".//LABEL[text()='Some Property']")).click(); j.submit(f); PropertyImpl p = j.jenkins.getNode(s.getNodeName()).getNodeProperties().get(PropertyImpl.class); assertEquals("Duke",p.name); From fc557968d2e4c3d04643f2b7bf34f6a3bcbcfbaa Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 19:38:07 +0100 Subject: [PATCH 169/256] AsynchPeopleTest compiling against HtmlUnit 2.17 --- test/src/test/java/hudson/model/AsynchPeopleTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/test/java/hudson/model/AsynchPeopleTest.java b/test/src/test/java/hudson/model/AsynchPeopleTest.java index 00fae6b364..c13017848e 100644 --- a/test/src/test/java/hudson/model/AsynchPeopleTest.java +++ b/test/src/test/java/hudson/model/AsynchPeopleTest.java @@ -25,7 +25,7 @@ package hudson.model; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; -import com.gargoylesoftware.htmlunit.html.HtmlElement; +import com.gargoylesoftware.htmlunit.html.DomElement; import com.gargoylesoftware.htmlunit.html.HtmlPage; import static org.junit.Assert.*; import org.junit.Rule; @@ -53,7 +53,7 @@ public class AsynchPeopleTest { } assertEquals(0, wc.waitForBackgroundJavaScript(120000)); boolean found = false; - for (HtmlElement table : page.getElementsByTagName("table")) { + for (DomElement table : page.getElementsByTagName("table")) { if (table.getAttribute("class").contains("progress-bar")) { found = true; assertEquals("display: none;", table.getAttribute("style")); From 17ea748fa9ed9ed35eebee8c0bc835c25cd4914b Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 19:39:28 +0100 Subject: [PATCH 170/256] JobTest compiling against HtmlUnit 2.17 --- test/src/test/java/hudson/model/JobTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/src/test/java/hudson/model/JobTest.java b/test/src/test/java/hudson/model/JobTest.java index b8176491f4..b49b13e45d 100644 --- a/test/src/test/java/hudson/model/JobTest.java +++ b/test/src/test/java/hudson/model/JobTest.java @@ -25,6 +25,7 @@ package hudson.model; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.WebAssert; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.TextPage; @@ -211,7 +212,7 @@ public class JobTest { // But it posts invalid data so we expect 500 if we have permission, 403 if not HtmlPage page = wc.goTo("userContent/post.html"); try { - page.getForms().get(0).submit(); + HtmlFormUtil.submit(page.getForms().get(0)); fail("Expected exception: " + msg); } catch (FailingHttpStatusCodeException expected) { assertEquals(msg, status, expected.getStatusCode()); From 12ff659deb326b0a8b978104ff5211b8b59817b9 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 19:41:58 +0100 Subject: [PATCH 171/256] RenderOnDemandTest compiling against HtmlUnit 2.17 --- test/src/test/java/lib/layout/RenderOnDemandTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/src/test/java/lib/layout/RenderOnDemandTest.java b/test/src/test/java/lib/layout/RenderOnDemandTest.java index 7e450063e4..ad9dbf000e 100644 --- a/test/src/test/java/lib/layout/RenderOnDemandTest.java +++ b/test/src/test/java/lib/layout/RenderOnDemandTest.java @@ -24,6 +24,7 @@ package lib.layout; import com.gargoylesoftware.htmlunit.ScriptResult; +import com.gargoylesoftware.htmlunit.html.HtmlElement; import com.gargoylesoftware.htmlunit.html.HtmlPage; import org.jvnet.hudson.test.HudsonTestCase; @@ -75,7 +76,7 @@ public class RenderOnDemandTest extends HudsonTestCase { HtmlPage p = createWebClient().goTo("self/testScript"); assertNull(p.getElementById("loaded")); - p.getElementById("button").click(); + ((HtmlElement)p.getElementById("button")).click(); // all AJAX calls complete before the above method returns assertNotNull(p.getElementById("loaded")); From 20bbaea191cf8306210d9e80a82f15306b7ee45f Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 19:49:13 +0100 Subject: [PATCH 172/256] SearchTest compiling against HtmlUnit 2.17 --- test/src/test/java/hudson/search/SearchTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/test/java/hudson/search/SearchTest.java b/test/src/test/java/hudson/search/SearchTest.java index 090fab430b..c8949a6317 100644 --- a/test/src/test/java/hudson/search/SearchTest.java +++ b/test/src/test/java/hudson/search/SearchTest.java @@ -118,7 +118,7 @@ public class SearchTest { assertNotNull(result); j.assertGoodStatus(result); - URL resultUrl = result.getWebResponse().getUrl(); + URL resultUrl = result.getUrl(); assertTrue(resultUrl.toString().equals(j.getInstance().getRootUrl() + myFreeStyleProject.getUrl())); } @@ -134,7 +134,7 @@ public class SearchTest { assertNotNull(result); j.assertGoodStatus(result); - URL resultUrl = result.getWebResponse().getUrl(); + URL resultUrl = result.getUrl(); assertTrue(resultUrl.toString().equals(j.getInstance().getRootUrl() + myFreeStyleProject.getUrl())); } From f189af856bddaa6db678e5ac4350bd285d2edfd6 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 19:49:29 +0100 Subject: [PATCH 173/256] SignupPage compiling against HtmlUnit 2.17 --- test/src/test/java/hudson/security/pages/SignupPage.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/test/java/hudson/security/pages/SignupPage.java b/test/src/test/java/hudson/security/pages/SignupPage.java index 5007bce1b5..2b05f95a16 100644 --- a/test/src/test/java/hudson/security/pages/SignupPage.java +++ b/test/src/test/java/hudson/security/pages/SignupPage.java @@ -60,6 +60,6 @@ public class SignupPage { } public void assertErrorContains(String msg) { - assertThat(signupForm.getElementById("main-panel").getTextContent(),containsString(msg)); + assertThat(signupForm.getPage().getElementById("main-panel").getTextContent(),containsString(msg)); } } From 5a08cf48b411f90565235921af6ae5f42aaba3c6 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Thu, 23 Jul 2015 20:20:09 +0100 Subject: [PATCH 174/256] Dependency exclusions for http commons + some test fixes --- test/pom.xml | 10 +++++++ .../htmlunit/html/HtmlFormUtil.java | 27 +++++++++++-------- .../org/jvnet/hudson/test/HudsonTestCase.java | 4 +-- .../org/jvnet/hudson/test/JenkinsRule.java | 4 +-- .../java/hudson/bugs/LoginRedirectTest.java | 2 +- 5 files changed, 31 insertions(+), 16 deletions(-) diff --git a/test/pom.xml b/test/pom.xml index 0af213f6b9..34495fd778 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -64,6 +64,16 @@ THE SOFTWARE. ${project.groupId} maven-plugin ${maven-plugin.version} + + + org.apache.httpcomponents + httpclient + + + org.apache.httpcomponents + httpcore + + org.jenkins-ci.plugins diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java index e08177881c..9ad296633e 100644 --- a/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java @@ -38,14 +38,14 @@ public class HtmlFormUtil { * Plain {@link com.gargoylesoftware.htmlunit.html.HtmlForm#submit()} doesn't work correctly due to the use of YUI in Hudson. */ public static Page submit(final HtmlForm htmlForm) throws IOException { - final HtmlSubmitInput submitElement = getSubmitButton(htmlForm); + final HtmlButton submitElement = getSubmitButton(htmlForm); return submit(htmlForm, submitElement); } /** * Plain {@link com.gargoylesoftware.htmlunit.html.HtmlForm#submit()} doesn't work correctly due to the use of YUI in Hudson. */ - public static Page submit(HtmlForm htmlForm, HtmlSubmitInput submitElement) throws IOException { + public static Page submit(HtmlForm htmlForm, HtmlButton submitElement) throws IOException { if (submitElement != null) { // To make YUI event handling work, this combo seems to be necessary // the click will trigger _onClick in buton-*.js, but it doesn't submit the form @@ -63,13 +63,13 @@ public class HtmlFormUtil { /** * Returns all the <input type="submit"> elements in this form. */ - public static List getSubmitButtons(final HtmlForm htmlForm) throws ElementNotFoundException { - final List list = htmlForm.getElementsByAttribute("input", "type", "submit"); + public static List getSubmitButtons(final HtmlForm htmlForm) throws ElementNotFoundException { + final List list = htmlForm.getElementsByAttribute("input", "type", "submit"); // collect inputs from lost children for (final HtmlElement elt : htmlForm.getLostChildren()) { - if (elt instanceof HtmlSubmitInput) { - list.add((HtmlSubmitInput) elt); + if (elt instanceof HtmlButton) { + list.add((HtmlButton) elt); } } return list; @@ -78,14 +78,19 @@ public class HtmlFormUtil { /** * Gets the first <input type="submit"> element in this form. */ - public static HtmlSubmitInput getSubmitButton(final HtmlForm htmlForm) throws ElementNotFoundException { - return getSubmitButtons(htmlForm).get(0); + public static HtmlButton getSubmitButton(final HtmlForm htmlForm) throws ElementNotFoundException { + List submitButtons = getSubmitButtons(htmlForm); + if (!submitButtons.isEmpty()) { + return submitButtons.get(0); + } + return null; } - public static HtmlSubmitInput getButtonByCaption(final HtmlForm htmlForm, final String caption) throws ElementNotFoundException { + public static HtmlButton getButtonByCaption(final HtmlForm htmlForm, final String caption) throws ElementNotFoundException { for (HtmlElement b : htmlForm.getHtmlElementsByTagName("button")) { - if(b.getTextContent().trim().equals(caption)) - return (HtmlSubmitInput) b; + if(b instanceof HtmlButton && b.getTextContent().trim().equals(caption)) { + return (HtmlButton) b; + } } throw new ElementNotFoundException("button", "caption", caption); } diff --git a/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java b/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java index efb54899b3..8717c27704 100644 --- a/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java +++ b/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java @@ -1175,8 +1175,8 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { public HtmlPage submit(HtmlForm form, String name) throws Exception { for( HtmlElement e : form.getHtmlElementsByTagName("button")) { HtmlElement p = (HtmlElement)e.getParentNode().getParentNode(); - if(p.getAttribute("name").equals(name)) { - return (HtmlPage)HtmlFormUtil.submit(form, (HtmlSubmitInput) e); + if(e instanceof HtmlButton && p.getAttribute("name").equals(name)) { + return (HtmlPage)HtmlFormUtil.submit(form, (HtmlButton) e); } } throw new AssertionError("No such submit button with the name "+name); diff --git a/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 5e38f9066c..20f4b87e40 100644 --- a/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -1315,8 +1315,8 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { public HtmlPage submit(HtmlForm form, String name) throws Exception { for( HtmlElement e : form.getHtmlElementsByTagName("button")) { HtmlElement p = (HtmlElement)e.getParentNode().getParentNode(); - if(p.getAttribute("name").equals(name)) { - return (HtmlPage)HtmlFormUtil.submit(form, (HtmlSubmitInput) e); + if(e instanceof HtmlButton && p.getAttribute("name").equals(name)) { + return (HtmlPage)HtmlFormUtil.submit(form, (HtmlButton) e); } } throw new AssertionError("No such submit button with the name "+name); diff --git a/test/src/test/java/hudson/bugs/LoginRedirectTest.java b/test/src/test/java/hudson/bugs/LoginRedirectTest.java index 033966cf18..c34a45c338 100644 --- a/test/src/test/java/hudson/bugs/LoginRedirectTest.java +++ b/test/src/test/java/hudson/bugs/LoginRedirectTest.java @@ -51,7 +51,7 @@ public class LoginRedirectTest extends HudsonTestCase { wc.getOptions().setThrowExceptionOnFailingStatusCode(false); HtmlPage p = wc.goTo("/"); - System.out.println(p.getDocumentURI()); + //System.out.println(p.getDocumentURI()); assertEquals(200, p.getWebResponse().getStatusCode()); HtmlForm form = p.getFormByName("login"); form.getInputByName("j_username").setValueAttribute("alice"); From 684a25daaff21b7899fa152c9e3a2a0e5af2966e Mon Sep 17 00:00:00 2001 From: tfennelly Date: Fri, 24 Jul 2015 08:51:57 +0100 Subject: [PATCH 175/256] Added temp copy of JavaScriptEngine for patching TODO: remove once upstream has the fixes made here --- .../htmlunit/javascript/JavaScriptEngine.java | 1015 +++++++++++++++++ 1 file changed, 1015 insertions(+) create mode 100644 test/src/main/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngine.java diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngine.java b/test/src/main/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngine.java new file mode 100644 index 0000000000..e78f1bbf57 --- /dev/null +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngine.java @@ -0,0 +1,1015 @@ +/* + * Copyright (c) 2002-2015 Gargoyle Software Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gargoylesoftware.htmlunit.javascript; + +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_ALLOW_CONST_ASSIGNMENT; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_CONSTRUCTOR; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_DATE_USE_UTC; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_DEFINE_GETTER; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_DONT_ENUM_FUNCTIONS; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_ECMA5_FUNCTIONS; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_FUNCTION_BIND; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_FUNCTION_TOSOURCE; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_IMAGE_PROTOTYPE_SAME_AS_HTML_IMAGE; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_INTL; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_Iterator; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_OBJECT_WITH_PROTOTYPE_PROPERTY_IN_WINDOW_SCOPE; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_OPTION_PROTOTYPE_SAME_AS_HTML_OPTION; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_WINDOW_ACTIVEXOBJECT_HIDDEN; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.JS_XML; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.STRING_CONTAINS; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.STRING_TRIM; +import static com.gargoylesoftware.htmlunit.BrowserVersionFeatures.STRING_TRIM_LEFT_RIGHT; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Stack; + +import net.sourceforge.htmlunit.corejs.javascript.Context; +import net.sourceforge.htmlunit.corejs.javascript.ContextAction; +import net.sourceforge.htmlunit.corejs.javascript.Function; +import net.sourceforge.htmlunit.corejs.javascript.FunctionObject; +import net.sourceforge.htmlunit.corejs.javascript.Script; +import net.sourceforge.htmlunit.corejs.javascript.ScriptRuntime; +import net.sourceforge.htmlunit.corejs.javascript.Scriptable; +import net.sourceforge.htmlunit.corejs.javascript.ScriptableObject; +import net.sourceforge.htmlunit.corejs.javascript.UniqueTag; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.gargoylesoftware.htmlunit.BrowserVersion; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.ScriptException; +import com.gargoylesoftware.htmlunit.WebAssert; +import com.gargoylesoftware.htmlunit.WebClient; +import com.gargoylesoftware.htmlunit.WebWindow; +import com.gargoylesoftware.htmlunit.html.DomNode; +import com.gargoylesoftware.htmlunit.html.HtmlDivision; +import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.javascript.background.BackgroundJavaScriptFactory; +import com.gargoylesoftware.htmlunit.javascript.background.JavaScriptExecutor; +import com.gargoylesoftware.htmlunit.javascript.configuration.ClassConfiguration; +import com.gargoylesoftware.htmlunit.javascript.configuration.JavaScriptConfiguration; +import com.gargoylesoftware.htmlunit.javascript.host.ActiveXObject; +import com.gargoylesoftware.htmlunit.javascript.host.DateCustom; +import com.gargoylesoftware.htmlunit.javascript.host.Element; +import com.gargoylesoftware.htmlunit.javascript.host.StringCustom; +import com.gargoylesoftware.htmlunit.javascript.host.Window; +import com.gargoylesoftware.htmlunit.javascript.host.html.HTMLDocument; +import com.gargoylesoftware.htmlunit.javascript.host.intl.Intl; + +/** + * A wrapper for the Rhino JavaScript engine + * that provides browser specific features.
          + * Like all classes in this package, this class is not intended for direct use + * and may change without notice. + * + * @version $Revision: 10607 $ + * @author Mike Bowler + * @author Chen Jun + * @author David K. Taylor + * @author Chris Erskine + * @author Ben Curren + * @author David D. Kilzer + * @author Marc Guillemot + * @author Daniel Gredler + * @author Ahmed Ashour + * @author Amit Manjhi + * @author Ronald Brill + * @author Frank Danek + * @see + * Rhino and Java Browser + */ +public class JavaScriptEngine { + + private static final Log LOG = LogFactory.getLog(JavaScriptEngine.class); + + private final WebClient webClient_; + private final HtmlUnitContextFactory contextFactory_; + private final JavaScriptConfiguration jsConfig_; + + private transient ThreadLocal javaScriptRunning_; + private transient ThreadLocal> postponedActions_; + private transient boolean holdPostponedActions_; + + /** The JavaScriptExecutor corresponding to all windows of this Web client */ + private transient JavaScriptExecutor javaScriptExecutor_; + + /** + * Key used to place the scope in which the execution of some JavaScript code + * started as thread local attribute in current context.
          + * This is needed to resolve some relative locations relatively to the page + * in which the script is executed and not to the page which location is changed. + */ + public static final String KEY_STARTING_SCOPE = "startingScope"; + + /** + * Key used to place the {@link HtmlPage} for which the JavaScript code is executed + * as thread local attribute in current context. + */ + public static final String KEY_STARTING_PAGE = "startingPage"; + + /** + * Creates an instance for the specified {@link WebClient}. + * + * @param webClient the client that will own this engine + */ + public JavaScriptEngine(final WebClient webClient) { + webClient_ = webClient; + contextFactory_ = new HtmlUnitContextFactory(webClient); + initTransientFields(); + jsConfig_ = JavaScriptConfiguration.getInstance(webClient.getBrowserVersion()); + } + + /** + * Returns the web client that this engine is associated with. + * @return the web client + */ + public final WebClient getWebClient() { + return webClient_; + } + + /** + * Returns this JavaScript engine's Rhino {@link net.sourceforge.htmlunit.corejs.javascript.ContextFactory}. + * @return this JavaScript engine's Rhino {@link net.sourceforge.htmlunit.corejs.javascript.ContextFactory} + */ + public HtmlUnitContextFactory getContextFactory() { + return contextFactory_; + } + + /** + * Performs initialization for the given webWindow. + * @param webWindow the web window to initialize for + */ + public void initialize(final WebWindow webWindow) { + WebAssert.notNull("webWindow", webWindow); + + final ContextAction action = new ContextAction() { + public Object run(final Context cx) { + try { + init(webWindow, cx); + } + catch (final Exception e) { + LOG.error("Exception while initializing JavaScript for the page", e); + throw new ScriptException(null, e); // BUG: null is not useful. + } + + return null; + } + }; + + getContextFactory().call(action); + } + + /** + * Returns the JavaScriptExecutor. + * @return the JavaScriptExecutor. + */ + public JavaScriptExecutor getJavaScriptExecutor() { + return javaScriptExecutor_; + } + + /** + * Initializes all the JS stuff for the window. + * @param webWindow the web window + * @param context the current context + * @throws Exception if something goes wrong + */ + private void init(final WebWindow webWindow, final Context context) throws Exception { + final WebClient webClient = webWindow.getWebClient(); + final BrowserVersion browserVersion = webClient.getBrowserVersion(); + final Map, Scriptable> prototypes = new HashMap<>(); + final Map prototypesPerJSName = new HashMap<>(); + + final Window window = new Window(); + ((SimpleScriptable) window).setClassName("Window"); + context.initStandardObjects(window); + + if (browserVersion.hasFeature(JS_CONSTRUCTOR)) { + final ClassConfiguration windowConfig = jsConfig_.getClassConfiguration("Window"); + if (windowConfig.getJsConstructor() != null) { + final FunctionObject functionObject = new RecursiveFunctionObject("Window", + windowConfig.getJsConstructor(), window); + ScriptableObject.defineProperty(window, "constructor", functionObject, + ScriptableObject.DONTENUM | ScriptableObject.PERMANENT | ScriptableObject.READONLY); + } + else { + defineConstructor(browserVersion, window, window, new Window()); + } + } + else { + deleteProperties(window, "constructor"); + } + + // remove some objects, that Rhino defines in top scope but that we don't want + deleteProperties(window, "java", "javax", "org", "com", "edu", "net", + "JavaAdapter", "JavaImporter", "Continuation", "Packages", "getClass"); + if (!browserVersion.hasFeature(JS_XML)) { + deleteProperties(window, "XML", "XMLList", "Namespace", "QName"); + } + + if (!browserVersion.hasFeature(JS_Iterator)) { + deleteProperties(window, "Iterator", "StopIteration"); + } + + if (browserVersion.hasFeature(JS_INTL)) { + final Intl intl = new Intl(); + intl.setParentScope(window); + window.defineProperty(intl.getClassName(), intl, ScriptableObject.DONTENUM); + intl.defineProperties(browserVersion); + } + + // put custom object to be called as very last prototype to call the fallback getter (if any) + final Scriptable fallbackCaller = new FallbackCaller(); + ScriptableObject.getObjectPrototype(window).setPrototype(fallbackCaller); + + final boolean putPrototypeInWindowScope = + browserVersion.hasFeature(JS_OBJECT_WITH_PROTOTYPE_PROPERTY_IN_WINDOW_SCOPE); + for (final ClassConfiguration config : jsConfig_.getAll()) { + final boolean isWindow = Window.class.getName().equals(config.getHostClass().getName()); + if (isWindow) { + configureConstantsPropertiesAndFunctions(config, window, browserVersion); + + final ScriptableObject prototype = configureClass(config, window, browserVersion); + prototypesPerJSName.put(config.getClassName(), prototype); + } + else { + final ScriptableObject prototype = configureClass(config, window, browserVersion); + if (config.isJsObject()) { + // Place object with prototype property in Window scope + if (putPrototypeInWindowScope) { + final SimpleScriptable obj = config.getHostClass().newInstance(); + prototype.defineProperty("__proto__", prototype, ScriptableObject.DONTENUM); + obj.defineProperty("prototype", prototype, ScriptableObject.DONTENUM); // but not setPrototype! + obj.setParentScope(window); + obj.setClassName(config.getClassName()); + ScriptableObject.defineProperty(window, obj.getClassName(), obj, ScriptableObject.DONTENUM); + // this obj won't have prototype, constants need to be configured on it again + configureConstants(config, obj); + + if (obj.getClass() == Element.class) { + final Page page = webWindow.getEnclosedPage(); + if (page != null && page.isHtmlPage()) { + final DomNode domNode = new HtmlDivision("", (HtmlPage) page, null); + obj.setDomNode(domNode); + } + } + } + } + prototypes.put(config.getHostClass(), prototype); + prototypesPerJSName.put(config.getClassName(), prototype); + } + } + + for (final ClassConfiguration config : jsConfig_.getAll()) { + final Member jsConstructor = config.getJsConstructor(); + final String jsClassName = config.getClassName(); + Scriptable prototype = prototypesPerJSName.get(jsClassName); + final String hostClassSimpleName = config.getHostClass().getSimpleName(); + if ("Image".equals(hostClassSimpleName) + && browserVersion.hasFeature(JS_IMAGE_PROTOTYPE_SAME_AS_HTML_IMAGE)) { + prototype = prototypesPerJSName.get("HTMLImageElement"); + } + if ("Option".equals(hostClassSimpleName) + && browserVersion.hasFeature(JS_OPTION_PROTOTYPE_SAME_AS_HTML_OPTION)) { + prototype = prototypesPerJSName.get("HTMLOptionElement"); + } + if (prototype != null && config.isJsObject()) { + if (jsConstructor != null) { + final FunctionObject functionObject; + if ("Window".equals(jsClassName)) { + functionObject = (FunctionObject) ScriptableObject.getProperty(window, "constructor"); + } + else { + functionObject = new RecursiveFunctionObject(jsClassName, jsConstructor, window); + } + + if ("Image".equals(hostClassSimpleName) || "Option".equals(hostClassSimpleName)) { + final Object prototypeProperty = ScriptableObject.getProperty(window, prototype.getClassName()); + + functionObject.addAsConstructor(window, prototype); + + ScriptableObject.defineProperty(window, hostClassSimpleName, functionObject, + ScriptableObject.DONTENUM); + + // the prototype class name is set as a side effect of functionObject.addAsConstructor + // so we restore its value + if (!hostClassSimpleName.equals(prototype.getClassName())) { + if (prototypeProperty == UniqueTag.NOT_FOUND) { + ScriptableObject.deleteProperty(window, prototype.getClassName()); + } + else { + ScriptableObject.defineProperty(window, prototype.getClassName(), + prototypeProperty, ScriptableObject.DONTENUM); + } + } + } + else { + functionObject.addAsConstructor(window, prototype); + } + + configureConstants(config, functionObject); + + for (final Entry staticfunctionInfo : config.getStaticFunctionEntries()) { + final String functionName = staticfunctionInfo.getKey(); + final Method method = staticfunctionInfo.getValue(); + final FunctionObject staticFunctionObject = new FunctionObject(functionName, method, + functionObject); + functionObject.defineProperty(functionName, staticFunctionObject, ScriptableObject.EMPTY); + } + } + else { + if (browserVersion.hasFeature(JS_CONSTRUCTOR)) { + final ScriptableObject constructor; + if ("Window".equals(jsClassName)) { + constructor = (ScriptableObject) ScriptableObject.getProperty(window, "constructor"); + } + else { + constructor = config.getHostClass().newInstance(); + ((SimpleScriptable) constructor).setClassName(config.getClassName()); + } + defineConstructor(browserVersion, window, prototype, constructor); + configureConstants(config, constructor); + } + else { + if (!"Window".equals(jsClassName)) { + final ScriptableObject constructor = config.getHostClass().newInstance(); + constructor.setParentScope(window); + window.defineProperty(constructor.getClassName(), constructor, ScriptableObject.DONTENUM); + } + + deleteProperties(prototype, "constructor"); + } + } + } + } + window.setPrototype(prototypesPerJSName.get(Window.class.getSimpleName())); + + // once all prototypes have been build, it's possible to configure the chains + final Scriptable objectPrototype = ScriptableObject.getObjectPrototype(window); + for (final Map.Entry entry : prototypesPerJSName.entrySet()) { + final String name = entry.getKey(); + final ClassConfiguration config = jsConfig_.getClassConfiguration(name); + Scriptable prototype = entry.getValue(); + if (prototype.getPrototype() != null) { + prototype = prototype.getPrototype(); // "double prototype" hack for FF + } + if (!StringUtils.isEmpty(config.getExtendedClassName())) { + final Scriptable parentPrototype = prototypesPerJSName.get(config.getExtendedClassName()); + prototype.setPrototype(parentPrototype); + } + else { + prototype.setPrototype(objectPrototype); + } + } + + // IE11 ActiveXObject simulation + // see http://msdn.microsoft.com/en-us/library/ie/dn423948%28v=vs.85%29.aspx + // DEV Note: this is at the moment the only usage of HiddenFunctionObject + // if we need more in the future, we have to enhance our JSX annotations + if (browserVersion.hasFeature(JS_WINDOW_ACTIVEXOBJECT_HIDDEN)) { + final Scriptable prototype = prototypesPerJSName.get("ActiveXObject"); + if (null != prototype) { + final Method jsConstructor = ActiveXObject.class.getDeclaredMethod("jsConstructor", + Context.class, Object[].class, Function.class, boolean.class); + final FunctionObject functionObject = new HiddenFunctionObject("ActiveXObject", jsConstructor, window); + functionObject.addAsConstructor(window, prototype); + } + } + + // Rhino defines too much methods for us, particularly since implementation of ECMAScript5 + removePrototypeProperties(window, "String", "equals", "equalsIgnoreCase"); + if (!browserVersion.hasFeature(STRING_TRIM)) { + removePrototypeProperties(window, "String", "trim"); + } + if (!browserVersion.hasFeature(STRING_TRIM_LEFT_RIGHT)) { + removePrototypeProperties(window, "String", "trimLeft"); + removePrototypeProperties(window, "String", "trimRight"); + } + if (browserVersion.hasFeature(STRING_CONTAINS)) { + final ScriptableObject stringPrototype = + (ScriptableObject) ScriptableObject.getClassPrototype(window, "String"); + stringPrototype.defineFunctionProperties(new String[] {"contains"}, + StringCustom.class, ScriptableObject.EMPTY); + } + + if (!browserVersion.hasFeature(JS_FUNCTION_BIND)) { + removePrototypeProperties(window, "Function", "bind"); + } + if (!browserVersion.hasFeature(JS_ECMA5_FUNCTIONS)) { + removePrototypeProperties(window, "Date", "toISOString", "toJSON"); + } + + if (!browserVersion.hasFeature(JS_DEFINE_GETTER)) { + removePrototypeProperties(window, "Object", "__defineGetter__", "__defineSetter__", "__lookupGetter__", + "__lookupSetter__"); + } + + // only FF has toSource + if (!browserVersion.hasFeature(JS_FUNCTION_TOSOURCE)) { + deleteProperties(window, "uneval"); + removePrototypeProperties(window, "Object", "toSource"); + removePrototypeProperties(window, "Array", "toSource"); + removePrototypeProperties(window, "Date", "toSource"); + removePrototypeProperties(window, "Function", "toSource"); + removePrototypeProperties(window, "Number", "toSource"); + removePrototypeProperties(window, "String", "toSource"); + } + deleteProperties(window, "isXMLName"); + + NativeFunctionToStringFunction.installFix(window, webClient.getBrowserVersion()); + + if (browserVersion.hasFeature(JS_ALLOW_CONST_ASSIGNMENT)) { + makeConstWritable(window, "undefined", "NaN", "Infinity"); + } + + final ScriptableObject datePrototype = (ScriptableObject) ScriptableObject.getClassPrototype(window, "Date"); + datePrototype.defineFunctionProperties(new String[] {"toLocaleDateString", "toLocaleTimeString"}, + DateCustom.class, ScriptableObject.DONTENUM); + + if (browserVersion.hasFeature(JS_DATE_USE_UTC)) { + datePrototype.defineFunctionProperties(new String[] {"toUTCString"}, + DateCustom.class, ScriptableObject.DONTENUM); + } + + window.setPrototypes(prototypes, prototypesPerJSName); + window.initialize(webWindow); + } + + private void defineConstructor(final BrowserVersion browserVersion, final Window window, + final Scriptable prototype, final ScriptableObject constructor) { + constructor.setParentScope(window); + final Object constructorValue = browserVersion.hasFeature(JS_CONSTRUCTOR) ? constructor : null; + ScriptableObject.defineProperty(prototype, "constructor", constructorValue, + ScriptableObject.DONTENUM | ScriptableObject.PERMANENT | ScriptableObject.READONLY); + ScriptableObject.defineProperty(constructor, "prototype", prototype, + ScriptableObject.DONTENUM | ScriptableObject.PERMANENT | ScriptableObject.READONLY); + window.defineProperty(constructor.getClassName(), constructor, ScriptableObject.DONTENUM); + } + + private void makeConstWritable(final ScriptableObject scope, final String... constNames) { + for (final String name : constNames) { + final Object value = ScriptableObject.getProperty(scope, name); + ScriptableObject.defineProperty(scope, name, value, + ScriptableObject.DONTENUM | ScriptableObject.PERMANENT); + } + } + + /** + * Deletes the properties with the provided names. + * @param scope the scope from which properties have to be removed + * @param propertiesToDelete the list of property names + */ + private void deleteProperties(final Scriptable scope, final String... propertiesToDelete) { + for (final String property : propertiesToDelete) { + scope.delete(property); + } + } + + /** + * Define properties in Standards Mode. + * + * @param page the page + */ + public void definePropertiesInStandardsMode(final HtmlPage page) { + final Window window = ((HTMLDocument) page.getScriptObject()).getWindow(); + final BrowserVersion browserVersion = window.getBrowserVersion(); + for (final ClassConfiguration config : jsConfig_.getAll()) { + final String jsClassName = config.getClassName(); + if (config.isDefinedInStandardsMode()) { + final Scriptable prototype = window.getPrototype(jsClassName); + if ("Window".equals(jsClassName)) { + defineConstructor(browserVersion, window, window, new Window()); + } + else if (!config.isJsObject()) { + try { + final ScriptableObject constructor = config.getHostClass().newInstance(); + defineConstructor(browserVersion, window, prototype, constructor); + } + catch (final Exception e) { + throw new RuntimeException(e); + } + } + } + } + } + + /** + * Removes prototype properties. + * @param scope the scope + * @param className the class for which properties should be removed + * @param properties the properties to remove + */ + private void removePrototypeProperties(final Scriptable scope, final String className, + final String... properties) { + final ScriptableObject prototype = (ScriptableObject) ScriptableObject.getClassPrototype(scope, className); + for (final String property : properties) { + prototype.delete(property); + } + } + + /** + * Configures the specified class for access via JavaScript. + * @param config the configuration settings for the class to be configured + * @param window the scope within which to configure the class + * @param browserVersion the browser version + * @throws InstantiationException if the new class cannot be instantiated + * @throws IllegalAccessException if we don't have access to create the new instance + * @return the created prototype + */ + public static SimpleScriptable configureClass(final ClassConfiguration config, final Scriptable window, + final BrowserVersion browserVersion) + throws InstantiationException, IllegalAccessException { + + final SimpleScriptable prototype = config.getHostClass().newInstance(); + prototype.setParentScope(window); + prototype.setClassName(config.getClassName()); + + configureConstantsPropertiesAndFunctions(config, prototype, browserVersion); + + return prototype; + } + + /** + * Configures constants, properties and functions on the object. + * @param config the configuration for the object + * @param scriptable the object to configure + */ + private static void configureConstantsPropertiesAndFunctions(final ClassConfiguration config, + final ScriptableObject scriptable, final BrowserVersion browserVersion) { + + // the constants + configureConstants(config, scriptable); + + // the properties + for (final Entry propertyEntry : config.getPropertyEntries()) { + final String propertyName = propertyEntry.getKey(); + final Method readMethod = propertyEntry.getValue().getReadMethod(); + final Method writeMethod = propertyEntry.getValue().getWriteMethod(); + int flag = ScriptableObject.EMPTY; + + // https://code.google.com/p/chromium/issues/detail?id=492999 + if (browserVersion.isChrome() && "cssFloat".equals(propertyName)) { + flag = ScriptableObject.DONTENUM; + } + scriptable.defineProperty(propertyName, null, readMethod, writeMethod, flag); + } + + int attributes; + if (browserVersion.hasFeature(JS_DONT_ENUM_FUNCTIONS)) { + attributes = ScriptableObject.DONTENUM; + } + else { + attributes = ScriptableObject.EMPTY; + } + // the functions + for (final Entry functionInfo : config.getFunctionEntries()) { + final String functionName = functionInfo.getKey(); + final Method method = functionInfo.getValue(); + final FunctionObject functionObject = new FunctionObject(functionName, method, scriptable); + scriptable.defineProperty(functionName, functionObject, attributes); + } + } + + private static void configureConstants(final ClassConfiguration config, + final ScriptableObject scriptable) { + final Class linkedClass = config.getHostClass(); + for (final String constant : config.getConstants()) { + try { + final Object value = linkedClass.getField(constant).get(null); + scriptable.defineProperty(constant, value, ScriptableObject.READONLY | ScriptableObject.PERMANENT); + } + catch (final Exception e) { + throw Context.reportRuntimeError("Cannot get field '" + constant + "' for type: " + + config.getHostClass().getName()); + } + } + } + + /** + * Register WebWindow with the JavaScriptExecutor. + * @param webWindow the WebWindow to be registered. + */ + public synchronized void registerWindowAndMaybeStartEventLoop(final WebWindow webWindow) { + if (javaScriptExecutor_ == null) { + javaScriptExecutor_ = BackgroundJavaScriptFactory.theFactory().createJavaScriptExecutor(webClient_); + } + javaScriptExecutor_.addWindow(webWindow); + } + + /** + * Executes the jobs in the eventLoop till timeoutMillis expires or the eventLoop becomes empty. + * No use in non-GAE mode (see {@link com.gargoylesoftware.htmlunit.gae.GAEUtils#isGaeMode}. + * @param timeoutMillis the timeout in milliseconds + * @return the number of jobs executed + */ + public int pumpEventLoop(final long timeoutMillis) { + if (javaScriptExecutor_ == null) { + return 0; + } + return javaScriptExecutor_.pumpEventLoop(timeoutMillis); + } + + /** + * Shutdown the JavaScriptEngine. + */ + public void shutdown() { + if (javaScriptExecutor_ != null) { + javaScriptExecutor_.shutdown(); + javaScriptExecutor_ = null; + } + if (postponedActions_ != null) { + postponedActions_.remove(); + } + if (javaScriptRunning_ != null) { + javaScriptRunning_.remove(); + } + holdPostponedActions_ = false; + } + + /** + * Compiles the specified JavaScript code in the context of a given HTML page. + * + * @param htmlPage the page that the code will execute within + * @param sourceCode the JavaScript code to execute + * @param sourceName the name that will be displayed on error conditions + * @param startLine the line at which the script source starts + * @return the result of executing the specified code + */ + public Script compile(final HtmlPage htmlPage, final String sourceCode, + final String sourceName, final int startLine) { + + WebAssert.notNull("sourceCode", sourceCode); + + if (LOG.isTraceEnabled()) { + final String newline = System.getProperty("line.separator"); + LOG.trace("Javascript compile " + sourceName + newline + sourceCode + newline); + } + + final Scriptable scope = getScope(htmlPage, null); + final String source = sourceCode; + final ContextAction action = new HtmlUnitContextAction(scope, htmlPage) { + @Override + public Object doRun(final Context cx) { + return cx.compileString(source, sourceName, startLine, null); + } + + @Override + protected String getSourceCode(final Context cx) { + return source; + } + }; + + return (Script) getContextFactory().call(action); + } + + /** + * Executes the specified JavaScript code in the context of a given HTML page. + * + * @param htmlPage the page that the code will execute within + * @param sourceCode the JavaScript code to execute + * @param sourceName the name that will be displayed on error conditions + * @param startLine the line at which the script source starts + * @return the result of executing the specified code + */ + public Object execute(final HtmlPage htmlPage, + final String sourceCode, + final String sourceName, + final int startLine) { + + final Script script = compile(htmlPage, sourceCode, sourceName, startLine); + if (script == null) { // happens with syntax error + throwExceptionOnScriptError = false + return null; + } + return execute(htmlPage, script); + } + + /** + * Executes the specified JavaScript code in the context of a given HTML page. + * + * @param htmlPage the page that the code will execute within + * @param script the script to execute + * @return the result of executing the specified code + */ + public Object execute(final HtmlPage htmlPage, final Script script) { + final Scriptable scope = getScope(htmlPage, null); + + final ContextAction action = new HtmlUnitContextAction(scope, htmlPage) { + @Override + public Object doRun(final Context cx) { + return script.exec(cx, scope); + } + + @Override + protected String getSourceCode(final Context cx) { + return null; + } + }; + + return getContextFactory().call(action); + } + + /** + * Calls a JavaScript function and return the result. + * @param htmlPage the page + * @param javaScriptFunction the function to call + * @param thisObject the this object for class method calls + * @param args the list of arguments to pass to the function + * @param htmlElement the HTML element that will act as the context + * @return the result of the function call + */ + public Object callFunction( + final HtmlPage htmlPage, + final Function javaScriptFunction, + final Scriptable thisObject, + final Object[] args, + final DomNode htmlElement) { + + final Scriptable scope = getScope(htmlPage, htmlElement); + + return callFunction(htmlPage, javaScriptFunction, scope, thisObject, args); + } + + /** + * Calls the given function taking care of synchronization issues. + * @param htmlPage the HTML page that caused this script to executed + * @param function the JavaScript function to execute + * @param scope the execution scope + * @param thisObject the 'this' object + * @param args the function's arguments + * @return the function result + */ + public Object callFunction(final HtmlPage htmlPage, final Function function, + final Scriptable scope, final Scriptable thisObject, final Object[] args) { + + final ContextAction action = new HtmlUnitContextAction(scope, htmlPage) { + @Override + public Object doRun(final Context cx) { + if (ScriptRuntime.hasTopCall(cx)) { + return function.call(cx, scope, thisObject, args); + } + return ScriptRuntime.doTopCall(function, cx, scope, thisObject, args); + } + @Override + protected String getSourceCode(final Context cx) { + return cx.decompileFunction(function, 2); + } + }; + return getContextFactory().call(action); + } + + private Scriptable getScope(final HtmlPage htmlPage, final DomNode htmlElement) { + if (htmlElement != null) { + return htmlElement.getScriptObject(); + } + return (Window) htmlPage.getEnclosingWindow().getScriptObject(); + } + + /** + * Indicates if JavaScript is running in current thread.
          + * This allows code to know if there own evaluation is has been triggered by some JS code. + * @return true if JavaScript is running + */ + public boolean isScriptRunning() { + return Boolean.TRUE.equals(javaScriptRunning_.get()); + } + + /** + * Facility for ContextAction usage. + * ContextAction should be preferred because according to Rhino doc it + * "guarantees proper association of Context instances with the current thread and is faster". + */ + private abstract class HtmlUnitContextAction implements ContextAction { + private final Scriptable scope_; + private final HtmlPage htmlPage_; + public HtmlUnitContextAction(final Scriptable scope, final HtmlPage htmlPage) { + scope_ = scope; + htmlPage_ = htmlPage; + } + + public final Object run(final Context cx) { + final Boolean javaScriptAlreadyRunning = javaScriptRunning_.get(); + javaScriptRunning_.set(Boolean.TRUE); + + try { + // KEY_STARTING_SCOPE maintains a stack of scopes + @SuppressWarnings("unchecked") + Stack stack = (Stack) cx.getThreadLocal(JavaScriptEngine.KEY_STARTING_SCOPE); + if (null == stack) { + stack = new Stack(); + cx.putThreadLocal(KEY_STARTING_SCOPE, stack); + } + + final Object response; + stack.push(scope_); + try { + cx.putThreadLocal(KEY_STARTING_PAGE, htmlPage_); + synchronized (htmlPage_) { // 2 scripts can't be executed in parallel for one page + if (htmlPage_ != htmlPage_.getEnclosingWindow().getEnclosedPage()) { + return null; // page has been unloaded + } + response = doRun(cx); + } + } + finally { + stack.pop(); + } + + // doProcessPostponedActions is synchronized + // moved out of the sync block to avoid deadlocks + if (!holdPostponedActions_) { + doProcessPostponedActions(); + } + return response; + } + catch (final Exception e) { + handleJavaScriptException(new ScriptException(htmlPage_, e, getSourceCode(cx)), true); + return null; + } + catch (final TimeoutError e) { + final JavaScriptErrorListener javaScriptErrorListener = getWebClient().getJavaScriptErrorListener(); + if (javaScriptErrorListener != null) { + javaScriptErrorListener.timeoutError(htmlPage_, e.getAllowedTime(), e.getExecutionTime()); + } + if (getWebClient().getOptions().isThrowExceptionOnScriptError()) { + throw new RuntimeException(e); + } + LOG.info("Caught script timeout error", e); + return null; + } + finally { + javaScriptRunning_.set(javaScriptAlreadyRunning); + } + } + + protected abstract Object doRun(final Context cx); + + protected abstract String getSourceCode(final Context cx); + } + + private void doProcessPostponedActions() { + holdPostponedActions_ = false; + + try { + getWebClient().loadDownloadedResponses(); + } + catch (final RuntimeException e) { + throw e; + } + catch (final Exception e) { + throw new RuntimeException(e); + } + + final List actions = postponedActions_.get(); + if (actions != null) { + postponedActions_.set(null); + try { + for (final PostponedAction action : actions) { + if (LOG.isDebugEnabled()) { + LOG.debug("Processing PostponedAction " + action); + } + + // verify that the page that registered this PostponedAction is still alive + if (action.isStillAlive()) { + action.execute(); + } + } + } + catch (final Exception e) { + Context.throwAsScriptRuntimeEx(e); + } + } + } + + /** + * Adds an action that should be executed first when the script currently being executed has finished. + * @param action the action + */ + public void addPostponedAction(final PostponedAction action) { + List actions = postponedActions_.get(); + if (actions == null) { + actions = new ArrayList<>(); + postponedActions_.set(actions); + } + actions.add(action); + } + + /** + * Handles an exception that occurred during execution of JavaScript code. + * @param scriptException the exception + * @param triggerOnError if true, this triggers the onerror handler + */ + protected void handleJavaScriptException(final ScriptException scriptException, final boolean triggerOnError) { + // Trigger window.onerror, if it has been set. + final HtmlPage page = scriptException.getPage(); + if (triggerOnError && page != null) { + final WebWindow window = page.getEnclosingWindow(); + if (window != null) { + final Window w = (Window) window.getScriptObject(); + if (w != null) { + try { + w.triggerOnError(scriptException); + } + catch (final Exception e) { + handleJavaScriptException(new ScriptException(page, e, null), false); + } + } + } + } + final JavaScriptErrorListener javaScriptErrorListener = getWebClient().getJavaScriptErrorListener(); + if (javaScriptErrorListener != null) { + javaScriptErrorListener.scriptException(page, scriptException); + } + // Throw a Java exception if the user wants us to. + if (getWebClient().getOptions().isThrowExceptionOnScriptError()) { + throw scriptException; + } + // Log the error; ScriptException instances provide good debug info. + LOG.info("Caught script exception", scriptException); + } + + /** + * INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.
          + * Indicates that no postponed action should be executed. + */ + public void holdPosponedActions() { + holdPostponedActions_ = true; + } + + /** + * INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.
          + * Process postponed actions, if any. + */ + public void processPostponedActions() { + doProcessPostponedActions(); + } + + /** + * Re-initializes transient fields when an object of this type is deserialized. + */ + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + initTransientFields(); + } + + private void initTransientFields() { + javaScriptRunning_ = new ThreadLocal(); + postponedActions_ = new ThreadLocal>(); + holdPostponedActions_ = false; + } + + private static class FallbackCaller extends ScriptableObject { + private static final long serialVersionUID = 5142592186670858001L; + + @Override + public Object get(final String name, final Scriptable start) { + if (start instanceof ScriptableWithFallbackGetter) { + return ((ScriptableWithFallbackGetter) start).getWithFallback(name); + } + return NOT_FOUND; + } + + @Override + public String getClassName() { + return "htmlUnitHelper-fallbackCaller"; + } + } + + /** + * Gets the class of the JavaScript object for the node class. + * @param c the node class {@link DomNode} or some subclass. + * @return null if none found + */ + public Class getJavaScriptClass(final Class c) { + return jsConfig_.getDomJavaScriptMapping().get(c); + } + + /** + * Gets the associated configuration. + * @return the configuration + */ + public JavaScriptConfiguration getJavaScriptConfiguration() { + return jsConfig_; + } +} From ce06a0a771a2605859cae1fa19892c37051adc6f Mon Sep 17 00:00:00 2001 From: tfennelly Date: Fri, 24 Jul 2015 09:33:12 +0100 Subject: [PATCH 176/256] Perform AJAX requests as a postponed action, so that the XHR See https://github.com/jenkinsci/htmlunit/commit/72262c3edb2431c2ef9ec3d17977a683e1ccec82 --- .../htmlunit/javascript/JavaScriptEngine.java | 40 ++++++++++++------- 1 file changed, 25 insertions(+), 15 deletions(-) diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngine.java b/test/src/main/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngine.java index e78f1bbf57..65eb987b74 100644 --- a/test/src/main/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngine.java +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngine.java @@ -727,7 +727,11 @@ public class JavaScriptEngine { } }; - return getContextFactory().call(action); + try { + return getContextFactory().call(action); + } finally { + doProcessPostponedActions(); + } } /** @@ -881,23 +885,29 @@ public class JavaScriptEngine { throw new RuntimeException(e); } - final List actions = postponedActions_.get(); - if (actions != null) { - postponedActions_.set(null); - try { - for (final PostponedAction action : actions) { - if (LOG.isDebugEnabled()) { - LOG.debug("Processing PostponedAction " + action); - } + while (true) { // postponed action can result in more postponed actions + final List actions = postponedActions_.get(); + if (actions == null) { + break; + } - // verify that the page that registered this PostponedAction is still alive - if (action.isStillAlive()) { - action.execute(); + if (actions != null) { + postponedActions_.set(null); + try { + for (final PostponedAction action : actions) { + if (LOG.isDebugEnabled()) { + LOG.debug("Processing PostponedAction " + action); + } + + // verify that the page that registered this PostponedAction is still alive + if (action.isStillAlive()) { + action.execute(); + } } } - } - catch (final Exception e) { - Context.throwAsScriptRuntimeEx(e); + catch (final Exception e) { + Context.throwAsScriptRuntimeEx(e); + } } } } From 5e493f889649d84b124e26055f962a11131a3654 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Fri, 24 Jul 2015 12:05:10 +0100 Subject: [PATCH 177/256] Perform AJAX requests as a postponed action, so that the XHR (part 2) See https://github.com/jenkinsci/htmlunit/commit/72262c3edb2431c2ef9ec3d17977a683e1ccec82 --- .../htmlunit/javascript/JavaScriptEngine.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngine.java b/test/src/main/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngine.java index 65eb987b74..a01f0b66d7 100644 --- a/test/src/main/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngine.java +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/javascript/JavaScriptEngine.java @@ -179,7 +179,7 @@ public class JavaScriptEngine { } }; - getContextFactory().call(action); + callAction(action); } /** @@ -681,7 +681,7 @@ public class JavaScriptEngine { } }; - return (Script) getContextFactory().call(action); + return (Script) callAction(action); } /** @@ -727,6 +727,10 @@ public class JavaScriptEngine { } }; + return callAction(action); + } + + private Object callAction(ContextAction action) { try { return getContextFactory().call(action); } finally { @@ -780,7 +784,7 @@ public class JavaScriptEngine { return cx.decompileFunction(function, 2); } }; - return getContextFactory().call(action); + return callAction(action); } private Scriptable getScope(final HtmlPage htmlPage, final DomNode htmlElement) { From b5b76bab93a08e1d14c0c6319b41f90980e0b0f7 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Fri, 24 Jul 2015 12:06:45 +0100 Subject: [PATCH 178/256] Fixed getSubmitButton to accommodate or

    What's new in 1.626 (2015/08/23)

    From 8e97fd1c5cd6e809fb1a4b9521af83862220686f Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Tue, 25 Aug 2015 01:17:07 +0300 Subject: [PATCH 226/256] commons-compress -> 1.10 --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index a230835039..41c9fec669 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -279,7 +279,7 @@ THE SOFTWARE. org.apache.commons commons-compress - 1.9 + 1.10 javax.mail From 7adbeef5a70a37768f6d2f8caf3f9e29c8e57436 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Tue, 25 Aug 2015 15:36:47 +0100 Subject: [PATCH 227/256] Fixing NITs from @KostyaSha --- .../main/java/org/jvnet/hudson/test/HudsonTestCase.java | 6 +++--- test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java | 4 ++-- test/src/test/java/hudson/bugs/LoginRedirectTest.java | 1 - .../jenkins/security/RekeySecretAdminMonitorTest.java | 8 ++++---- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java b/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java index 6543b55e57..e17372122c 100644 --- a/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java +++ b/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java @@ -1176,7 +1176,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { public HtmlPage submit(HtmlForm form, String name) throws Exception { for( HtmlElement e : form.getHtmlElementsByTagName("button")) { HtmlElement p = (HtmlElement)e.getParentNode().getParentNode(); - if(e instanceof HtmlButton && p.getAttribute("name").equals(name)) { + if (e instanceof HtmlButton && p.getAttribute("name").equals(name)) { return (HtmlPage)HtmlFormUtil.submit(form, (HtmlButton) e); } } @@ -1624,7 +1624,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { * for accessing Hudson. */ public class WebClient extends com.gargoylesoftware.htmlunit.WebClient { - private static final long serialVersionUID = 5808915989048338267L; + private static final long serialVersionUID = 8720028298174337333L; public WebClient() { // default is IE6, but this causes 'n.doScroll('left')' to fail in event-debug.js:1907 as HtmlUnit doesn't implement such a method, @@ -1635,7 +1635,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { clients.add(this); // make ajax calls run as post-action for predictable behaviors that simplify debugging setAjaxController(new AjaxController() { - private static final long serialVersionUID = -5844060943564822678L; + private static final long serialVersionUID = 6730107519583349963L; public boolean processSynchron(HtmlPage page, WebRequest settings, boolean async) { return false; } diff --git a/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index 60bcdffa08..20bb06a033 100644 --- a/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -1856,7 +1856,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { * for accessing Hudson. */ public class WebClient extends com.gargoylesoftware.htmlunit.WebClient { - private static final long serialVersionUID = 5808915989048338267L; + private static final long serialVersionUID = -7944895389154288881L; private List webResponseListeners = new ArrayList<>(); @@ -1870,7 +1870,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { clients.add(this); // make ajax calls run as post-action for predictable behaviors that simplify debugging setAjaxController(new AjaxController() { - private static final long serialVersionUID = -5844060943564822678L; + private static final long serialVersionUID = -76034615893907856L; public boolean processSynchron(HtmlPage page, WebRequest settings, boolean async) { return false; } diff --git a/test/src/test/java/hudson/bugs/LoginRedirectTest.java b/test/src/test/java/hudson/bugs/LoginRedirectTest.java index c34a45c338..af63ad9380 100644 --- a/test/src/test/java/hudson/bugs/LoginRedirectTest.java +++ b/test/src/test/java/hudson/bugs/LoginRedirectTest.java @@ -51,7 +51,6 @@ public class LoginRedirectTest extends HudsonTestCase { wc.getOptions().setThrowExceptionOnFailingStatusCode(false); HtmlPage p = wc.goTo("/"); - //System.out.println(p.getDocumentURI()); assertEquals(200, p.getWebResponse().getStatusCode()); HtmlForm form = p.getFormByName("login"); form.getInputByName("j_username").setValueAttribute("alice"); diff --git a/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java b/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java index 92dfc68e24..ea7a08ba45 100644 --- a/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java +++ b/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java @@ -101,8 +101,8 @@ public class RekeySecretAdminMonitorTest extends HudsonTestCase { // should be no warning/error now HtmlPage manage = wc.goTo("manage"); - assertEquals(0,DomNodeUtil.selectNodes(manage, "//*[class='error']").size()); - assertEquals(0,DomNodeUtil.selectNodes(manage, "//*[class='warning']").size()); + assertEquals(0, DomNodeUtil.selectNodes(manage, "//*[class='error']").size()); + assertEquals(0, DomNodeUtil.selectNodes(manage, "//*[class='warning']").size()); // and the data should be rewritten verifyRewrite(jenkins.getRootDir()); @@ -141,8 +141,8 @@ public class RekeySecretAdminMonitorTest extends HudsonTestCase { // should be no warning/error now HtmlPage manage = wc.goTo("/manage"); - assertEquals(0,DomNodeUtil.selectNodes(manage, "//*[class='error']").size()); - assertEquals(0,DomNodeUtil.selectNodes(manage, "//*[class='warning']").size()); + assertEquals(0, DomNodeUtil.selectNodes(manage, "//*[class='error']").size()); + assertEquals(0, DomNodeUtil.selectNodes(manage, "//*[class='warning']").size()); } private String encryptOld(String str) throws Exception { From 67208cf5bf9a4ce1778c469cbfcbde39e8da18d7 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Tue, 25 Aug 2015 16:30:43 +0100 Subject: [PATCH 228/256] Fixing comments from @amuniz --- .../htmlunit/WebClientUtil.java | 49 +++++++++++++++++++ .../htmlunit/html/DomNodeUtil.java | 29 +++++++++-- .../htmlunit/html/HtmlElementUtil.java | 31 +++++++++--- .../htmlunit/html/HtmlFormUtil.java | 33 ++++++++++--- 4 files changed, 124 insertions(+), 18 deletions(-) diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/WebClientUtil.java b/test/src/main/java/com/gargoylesoftware/htmlunit/WebClientUtil.java index bf8503bf1b..d330c77a4a 100644 --- a/test/src/main/java/com/gargoylesoftware/htmlunit/WebClientUtil.java +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/WebClientUtil.java @@ -30,25 +30,48 @@ import java.net.MalformedURLException; import java.net.URL; /** + * {@link WebClient} helper methods. * @author tom.fennelly@gmail.com */ public class WebClientUtil { + /** + * Wait for all async JavaScript tasks associated with the supplied {@link WebClient} instance + * to complete. + *

    + * Waits for 10 seconds before timing out. + * @param webClient The {@link WebClient} instance. + */ public static void waitForJSExec(WebClient webClient) { waitForJSExec(webClient, 10000); } + /** + * Wait for all async JavaScript tasks associated with the supplied {@link WebClient} instance + * to complete. + * @param webClient The {@link WebClient} instance. + * @param timeout The timeout in milliseconds. + */ public static void waitForJSExec(WebClient webClient, long timeout) { webClient.getJavaScriptEngine().processPostponedActions(); webClient.waitForBackgroundJavaScript(timeout); } + /** + * Create and add an {@link ExceptionListener} to the {@link WebClient} instance. + * @param webClient The {@link WebClient} instance. + * @return The {@link ExceptionListener}. + */ public static ExceptionListener addExceptionListener(WebClient webClient) { ExceptionListener exceptionListener = new ExceptionListener(webClient); webClient.setJavaScriptErrorListener(exceptionListener); return exceptionListener; } + /** + * JavaScript Exception listener. + * @see #addExceptionListener(WebClient) + */ public static class ExceptionListener implements JavaScriptErrorListener { private final WebClient webClient; @@ -58,31 +81,57 @@ public class WebClientUtil { this.webClient = webClient; } + /** + * Get the last {@link ScriptException}. + * @return The last {@link ScriptException}, or {@code null} if none happened. + */ public ScriptException getScriptException() { return scriptException; } + /** + * Get the last {@link ScriptException}. + *

    + * Performs a call to {@link #assertHasException()}. + * @return The last {@link ScriptException}. + */ public ScriptException getExpectedScriptException() { assertHasException(); return scriptException; } + /** + * {@inheritDoc} + */ @Override public void scriptException(InteractivePage htmlPage, ScriptException scriptException) { this.scriptException = scriptException; } + /** + * Assert that a {@link ScriptException} occurred within the JavaScript executing + * on the associated {@link WebClient}. + */ public void assertHasException() { WebClientUtil.waitForJSExec(webClient); Assert.assertNotNull("A JavaScript Exception was expected.", scriptException); } + /** + * {@inheritDoc} + */ @Override public void timeoutError(InteractivePage htmlPage, long allowedTime, long executionTime) { } + /** + * {@inheritDoc} + */ @Override public void malformedScriptURL(InteractivePage htmlPage, String url, MalformedURLException malformedURLException) { } + /** + * {@inheritDoc} + */ @Override public void loadScriptError(InteractivePage htmlPage, URL scriptUrl, Exception exception) { } diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java b/test/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java index 4da720e59d..a70716b852 100644 --- a/test/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java @@ -29,19 +29,38 @@ import com.gargoylesoftware.htmlunit.html.xpath.XPathUtils; import java.util.List; /** + * {@link DomNode} helper methods. + * * @author tom.fennelly@gmail.com */ public class DomNodeUtil { - public static List getByXPath(final DomNode domNode, final String xpathExpr) { + /** + * Evaluates an XPath expression from the specified node, returning the resultant nodes. + *

    + * Calls {@link WebClientUtil#waitForJSExec(com.gargoylesoftware.htmlunit.WebClient)} before + * executing the query. + * + * @param domNode the node to start searching from + * @param xpathExpr the XPath expression + * @return the list of objects found. + */ + public static List selectNodes(final DomNode domNode, final String xpathExpr) { WebClientUtil.waitForJSExec(domNode.getPage().getWebClient()); return (List) XPathUtils.getByXPath(domNode, xpathExpr, null); } - public static List selectNodes(final DomNode domNode, final String xpathExpr) { - return getByXPath(domNode, xpathExpr); - } - + /** + * Evaluates the specified XPath expression from this node, returning the first matching element, + * or null if no node matches the specified XPath expression. + *

    + * Calls {@link WebClientUtil#waitForJSExec(com.gargoylesoftware.htmlunit.WebClient)} before + * executing the query. + * + * @param domNode the node to start searching from + * @param xpathExpr the XPath expression + * @return the first element matching the specified XPath expression + */ public static X selectSingleNode(final DomNode domNode, final String xpathExpr) { WebClientUtil.waitForJSExec(domNode.getPage().getWebClient()); return domNode.getFirstByXPath(xpathExpr); diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlElementUtil.java b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlElementUtil.java index 10fb84d792..c8d599b11f 100644 --- a/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlElementUtil.java +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlElementUtil.java @@ -23,22 +23,39 @@ */ package com.gargoylesoftware.htmlunit.html; +import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.WebClientUtil; import java.io.IOException; /** + * {@link HtmlElement} helper methods. * @author tom.fennelly@gmail.com */ public class HtmlElementUtil { - public static void click(HtmlElement element) throws IOException { - element.click(); - - // The JS script execution tasks are added to a queue and executed - // async. Wait for all to finish executing. - WebClient webClient = element.getPage().getWebClient(); - WebClientUtil.waitForJSExec(webClient); + /** + * Click on the supplied element. + *

    + * Waits for all executing JavaScript tasks to complete before returning. + * + * @param element The element to click. + * @return The page resulting from the click + * @throws IOException if an IO error occurs + */ + public static Page click(HtmlElement element) throws IOException { + if (element == null) { + return null; + } + + try { + return element.click(); + } finally { + // The JS script execution tasks are added to a queue and executed + // async. Wait for all to finish executing. + WebClient webClient = element.getPage().getWebClient(); + WebClientUtil.waitForJSExec(webClient); + } } } diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java index f2963b0c77..2ebebc0b86 100644 --- a/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java @@ -27,21 +27,37 @@ import com.gargoylesoftware.htmlunit.ElementNotFoundException; import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.WebClientUtil; -import com.gargoylesoftware.htmlunit.util.WebClientUtils; import java.io.IOException; import java.util.List; /** + * {@link HtmlForm} helper functions. + * * @author tom.fennelly@gmail.com */ public class HtmlFormUtil { + /** + * Submit the supplied {@link HtmlForm}. + *

    + * Locates the submit element/button on the form. + * @param htmlForm The {@link HtmlForm}. + * @return The submit result page. + * @throws IOException Error performing submit. + */ public static Page submit(final HtmlForm htmlForm) throws IOException { HtmlElement submitElement = getSubmitButton(htmlForm); return submit(htmlForm, submitElement); } + /** + * Submit the supplied {@link HtmlForm} via the supplied submit element. + * @param htmlForm The {@link HtmlForm}. + * @param submitElement The element through which the submit should be performed. + * @return The submit result page. + * @throws IOException Error performing submit. + */ public static Page submit(HtmlForm htmlForm, HtmlElement submitElement) throws IOException { final HtmlPage htmlPage = (HtmlPage) htmlForm.getPage(); final WebClient webClient = htmlPage.getWebClient(); @@ -64,12 +80,10 @@ public class HtmlFormUtil { Page resultPage = webClient.getCurrentWindow().getEnclosedPage(); if (resultPage == htmlPage) { - // We're still on the same page (form submit didn't bring us anywhere). - // Hackery. Seems like YUI is messing us about. - return submitElement.click(); + return HtmlElementUtil.click(submitElement); + } else { + return resultPage; } - - return resultPage; } } finally { // Make sure all background JS has executed. @@ -107,6 +121,13 @@ public class HtmlFormUtil { return null; } + /** + * Get the form button having the specified text/caption. + * @param htmlForm The form containing the button. + * @param caption The button text/caption being searched for. + * @return The button if found. + * @throws ElementNotFoundException Failed to find the button on the form. + */ public static HtmlButton getButtonByCaption(final HtmlForm htmlForm, final String caption) throws ElementNotFoundException { for (HtmlElement b : htmlForm.getHtmlElementsByTagName("button")) { if(b instanceof HtmlButton && b.getTextContent().trim().equals(caption)) { From d85b0362cbcbaa1731daa3f9db36d13c3c284881 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Wed, 26 Aug 2015 15:41:57 +0100 Subject: [PATCH 229/256] Some docs --- .../com/gargoylesoftware/htmlunit/README.md | 39 +++++++++++++++++++ .../htmlunit/html/HtmlFormUtil.java | 3 ++ 2 files changed, 42 insertions(+) create mode 100644 test/src/main/java/com/gargoylesoftware/htmlunit/README.md diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/README.md b/test/src/main/java/com/gargoylesoftware/htmlunit/README.md new file mode 100644 index 0000000000..4d65cfdcc2 --- /dev/null +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/README.md @@ -0,0 +1,39 @@ +# Overview +Jenkins used to maintain a forked version of HtmlUnit and use it via `JenkinsRule` (and `HudsonTestCase`). Moving +away from the forked version has allowed Jenkins GUI to start using more modern JavaScript libraries than were +possible through the forked version. + +Moving away from the forked version also means that some tests in plugins may no longer compile due to the +fact that they were using some methods that were added to the fork, but not available in the mainstream HtmlUnit. +To help with that, the test harness now provides static utilities for all of this functionality. + +# WebClientUtil +The `WebClientUtil` class provides static utilities for interacting asynchronously with HtmlUnit's `WebClient`, +supporting `waitForJSExec` calls to allow your test code wait for background (asynchronous) JavaScript code to complete +before the test continues. Calling these methods are not required in many cases as they are called for you from +other static utilities (e.g. `HtmlFormUtil.submit`), but sometimes it is required to call them directly. + +Because HtmlUnit executes JavaScript asynchronously, it's usually not possible to block and catch exceptions. For +that reason, `WebClientUtil` provides the `addExceptionListener` utility as a way of registering an exception listener. +This typically needs to be used in conjunction with the `waitForJSExec` method e.g. + +``` +WebClient webClient = jenkinsRule.createWebClient(); +WebClientUtil.ExceptionListener exceptionListener = WebClientUtil.addExceptionListener(webClient); + +// Interact with Jenkins UI as normal in a test... + +// Make sure all background JavaScript has completed so as expected exceptions have been thrown. +WebClientUtil.waitForJSExec(webClient); + +// Now we can check for exceptions etc... +exceptionListener.assertHasException(); +ScriptException e = exceptionListener.getScriptException(); +Assert.assertTrue(e.getMessage().contains("simulated error")); +``` + +# HtmlElementUtil, HtmlFormUtil and DomNodeUtil +These classes provide static utility methods to replace functionality that was added to the forked HtmlUnit e.g. +for triggering `

    ` submit, triggering a click event on an element etc. + +Use your IDE to access these utility classes and the static methods available. \ No newline at end of file diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java index 2ebebc0b86..af95c37cdf 100644 --- a/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java @@ -33,6 +33,9 @@ import java.util.List; /** * {@link HtmlForm} helper functions. + *

    + * In many cases, the methods defined here replace methods of the same name that were + * added to the {@link HtmlForm} class on the old forked version of HtmlUnit. * * @author tom.fennelly@gmail.com */ From 1625c8466f05c1f14db8e74deaf186d5686ed774 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Wed, 26 Aug 2015 15:44:37 +0100 Subject: [PATCH 230/256] Some docs --- test/src/main/java/com/gargoylesoftware/htmlunit/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/README.md b/test/src/main/java/com/gargoylesoftware/htmlunit/README.md index 4d65cfdcc2..5aadb8e293 100644 --- a/test/src/main/java/com/gargoylesoftware/htmlunit/README.md +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/README.md @@ -17,7 +17,7 @@ Because HtmlUnit executes JavaScript asynchronously, it's usually not possible t that reason, `WebClientUtil` provides the `addExceptionListener` utility as a way of registering an exception listener. This typically needs to be used in conjunction with the `waitForJSExec` method e.g. -``` +```java WebClient webClient = jenkinsRule.createWebClient(); WebClientUtil.ExceptionListener exceptionListener = WebClientUtil.addExceptionListener(webClient); From d6f9c5cdde8b80a40d3ce65f716099621c0ae9ce Mon Sep 17 00:00:00 2001 From: ikedam Date: Sun, 30 Aug 2015 12:04:44 +0900 Subject: [PATCH 231/256] [JENKINS-28440] Added @since for CriticalXStreamException. --- .../java/jenkins/util/xstream/CriticalXStreamException.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/java/jenkins/util/xstream/CriticalXStreamException.java b/core/src/main/java/jenkins/util/xstream/CriticalXStreamException.java index 5636669568..4c098ff1e4 100644 --- a/core/src/main/java/jenkins/util/xstream/CriticalXStreamException.java +++ b/core/src/main/java/jenkins/util/xstream/CriticalXStreamException.java @@ -29,6 +29,8 @@ import com.thoughtworks.xstream.converters.ConversionException; /** * Wraps {@link XStreamException} to indicate it is critical for Jenkins. + * + * @since 1.625 */ public class CriticalXStreamException extends ConversionException { private static final long serialVersionUID = 1L; From 0d54d89a367e5b3de3bde6fcc590ba6bedbfa82e Mon Sep 17 00:00:00 2001 From: ikedam Date: Sun, 30 Aug 2015 12:05:54 +0900 Subject: [PATCH 232/256] [JENKINS-28440] Uses CLICommandInvoker in tests. --- .../util/RobustReflectionConverterTest.java | 62 ++++++++----------- 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/test/src/test/java/hudson/util/RobustReflectionConverterTest.java b/test/src/test/java/hudson/util/RobustReflectionConverterTest.java index fa3d3ad1cf..21cdf66443 100644 --- a/test/src/test/java/hudson/util/RobustReflectionConverterTest.java +++ b/test/src/test/java/hudson/util/RobustReflectionConverterTest.java @@ -24,7 +24,7 @@ package hudson.util; -import hudson.cli.CLI; +import hudson.cli.CLICommandInvoker; import hudson.diagnosis.OldDataMonitor; import hudson.model.AbstractDescribableImpl; import hudson.model.Items; @@ -37,8 +37,6 @@ import hudson.model.Saveable; import hudson.security.ACL; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.util.Arrays; import java.util.Collections; import java.util.Map; @@ -272,23 +270,19 @@ public class RobustReflectionConverterTest { // Configure a bad keyword via CLI. r.jenkins.setSecurityRealm(r.createDummySecurityRealm()); - CLI cli = new CLI(r.getURL()); - ByteArrayOutputStream stdout = new ByteArrayOutputStream(); - ByteArrayOutputStream stderr = new ByteArrayOutputStream(); - int ret = cli.execute( - Arrays.asList( - "update-job", - p.getFullName(), - "--username", - "test", - "--password", - "test" - ), - new ByteArrayInputStream(String.format(CONFIGURATION_TEMPLATE, "badvalue", AcceptOnlySpecificKeyword.ACCEPT_KEYWORD).getBytes()), - stdout, - stderr - ); - assertEquals(0, ret); + + CLICommandInvoker.Result ret = new CLICommandInvoker(r, "update-job") + .withStdin(new ByteArrayInputStream(String.format(CONFIGURATION_TEMPLATE, "badvalue", AcceptOnlySpecificKeyword.ACCEPT_KEYWORD).getBytes())) + .withArgs( + p.getFullName(), + "--username", + "test", + "--password", + "test" + ) + .invoke(); + + assertEquals(0, ret.returnCode()); // AcceptOnlySpecificKeyword with bad value is not instantiated for rejected with readResolve, assertNull(p.getProperty(KeywordProperty.class).getNonCriticalField()); @@ -312,23 +306,17 @@ public class RobustReflectionConverterTest { // Configure a bad keyword via CLI. r.jenkins.setSecurityRealm(r.createDummySecurityRealm()); - CLI cli = new CLI(r.getURL()); - ByteArrayOutputStream stdout = new ByteArrayOutputStream(); - ByteArrayOutputStream stderr = new ByteArrayOutputStream(); - int ret = cli.execute( - Arrays.asList( - "update-job", - p.getFullName(), - "--username", - "test", - "--password", - "test" - ), - new ByteArrayInputStream(String.format(CONFIGURATION_TEMPLATE, AcceptOnlySpecificKeyword.ACCEPT_KEYWORD, "badvalue").getBytes()), - stdout, - stderr - ); - assertNotEquals(0, ret); + CLICommandInvoker.Result ret = new CLICommandInvoker(r, "update-job") + .withStdin(new ByteArrayInputStream(String.format(CONFIGURATION_TEMPLATE, AcceptOnlySpecificKeyword.ACCEPT_KEYWORD, "badvalue").getBytes())) + .withArgs( + p.getFullName(), + "--username", + "test", + "--password", + "test" + ) + .invoke(); + assertNotEquals(0, ret.returnCode()); // Configuration should not be updated for a failure of the critical field, assertNotEquals("badvalue", p.getProperty(KeywordProperty.class).getCriticalField().getKeyword()); From 51d13389c0f4949d506997726c8e690f118ddef0 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 30 Aug 2015 14:58:07 -0700 Subject: [PATCH 233/256] [maven-release-plugin] prepare release jenkins-1.627 --- cli/pom.xml | 2 +- core/pom.xml | 2 +- plugins/pom.xml | 10 +++++----- pom.xml | 4 ++-- test/pom.xml | 2 +- war/pom.xml | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cli/pom.xml b/cli/pom.xml index 7cdee3d47f..33301f257a 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.627-SNAPSHOT + 1.627 cli diff --git a/core/pom.xml b/core/pom.xml index 41c9fec669..98b4638316 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.627-SNAPSHOT + 1.627 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index 159036134d..3ead091a12 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.627-SNAPSHOT + 1.627 pom

    +

    What's new in 1.627 (2015/08/30)

    • Race condition in triggers could cause various NullPointerExceptions. @@ -65,7 +70,6 @@ Upcoming changes Allow plugins to augment or replace the plugin manager UI. (PR 1788)
    -

    What's new in 1.626 (2015/08/23)

    • From b61a4095904f3d1b148a3546c573f04c53c1019e Mon Sep 17 00:00:00 2001 From: Mirko Friedenhagen Date: Tue, 1 Sep 2015 22:47:13 +0200 Subject: [PATCH 236/256] Use slf4j adapters for logging. - By introducing adapters for log4j and commons-logging and - including the original log4j and commons-logging dependencies as provided all logging should be redirected to slf4j and finally java.util.logging. --- core/pom.xml | 8 ++------ plugins/pom.xml | 28 ++++++++++++++++++++++++++++ pom.xml | 14 ++++++++++---- 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 064fc8038d..f349a9cb30 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -401,10 +401,6 @@ THE SOFTWARE. org.springframework spring-support - - log4j - log4j - @@ -473,8 +469,8 @@ THE SOFTWARE. 1.1.0 - commons-logging - commons-logging + org.slf4j + jcl-over-slf4j org.slf4j diff --git a/plugins/pom.xml b/plugins/pom.xml index dd9422fd11..10de0d719b 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -34,6 +34,8 @@ UTF-8 2 + + 1.7.7 @@ -80,6 +82,32 @@ provided true + + + org.slf4j + slf4j-api + ${slf4jVersion} + provided + + + org.slf4j + log4j-over-slf4j + ${slf4jVersion} + provided + + + org.slf4j + jcl-over-slf4j + ${slf4jVersion} + provided + + + + org.slf4j + slf4j-jdk14 + ${slf4jVersion} + test + diff --git a/pom.xml b/pom.xml index 3963bf7fd1..b527872f5c 100644 --- a/pom.xml +++ b/pom.xml @@ -214,15 +214,22 @@ THE SOFTWARE. jcl-over-slf4j ${slf4jVersion} + + commons-logging + commons-logging + 1.1.3 + provided + org.slf4j log4j-over-slf4j ${slf4jVersion} - commons-logging - commons-logging - 1.1.3 + log4j + log4j + 1.2.17 + provided org.samba.jcifs @@ -664,7 +671,6 @@ THE SOFTWARE. org.sonatype.sisu:sisu-guice - log4j:log4j From a639beed2b0a1e07a09ac70400d8238a4675b400 Mon Sep 17 00:00:00 2001 From: Mirko Friedenhagen Date: Tue, 1 Sep 2015 22:59:34 +0200 Subject: [PATCH 237/256] Include slf4j-jdk14 during tests. --- core/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/pom.xml b/core/pom.xml index f349a9cb30..f9939ec761 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -476,6 +476,11 @@ THE SOFTWARE. org.slf4j log4j-over-slf4j + + org.slf4j + slf4j-jdk14 + test + com.sun.xml.txw2 txw2 From ed94d62c342ba9c09e1853f4a0bccf3fee6d9543 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Tue, 1 Sep 2015 15:29:36 -0700 Subject: [PATCH 238/256] Document allBuilds for Job remote access API --- core/src/main/resources/hudson/model/Job/_api.jelly | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/src/main/resources/hudson/model/Job/_api.jelly b/core/src/main/resources/hudson/model/Job/_api.jelly index 684e8cc9fe..f2ee7bcf00 100644 --- a/core/src/main/resources/hudson/model/Job/_api.jelly +++ b/core/src/main/resources/hudson/model/Job/_api.jelly @@ -27,6 +27,14 @@ THE SOFTWARE. +

      Retrieving all builds

      +

      + To prevent Jenkins from having to load all builds from disk when someone accesses the job API, the builds + tree only contains the 50 newest builds. If you really need to get all builds, access the allBuilds tree, + e.g. by fetching …/api/xml?tree=allBuilds[…]. Note that this may result in significant performance degradation + if you have a lot of builds in this job. +

      +

      Fetch/Update job description

      this URL From 9080c699e30c0184eff2889d9789cecaf9059eb5 Mon Sep 17 00:00:00 2001 From: Mirko Friedenhagen Date: Wed, 2 Sep 2015 06:52:18 +0200 Subject: [PATCH 239/256] Reintroduce enforcer rules as suggested by @jtnord. --- pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pom.xml b/pom.xml index b527872f5c..bd32871579 100644 --- a/pom.xml +++ b/pom.xml @@ -671,6 +671,8 @@ THE SOFTWARE. org.sonatype.sisu:sisu-guice + log4j:log4j + commons-logging:commons-logging From a6485510be07ef06639d7b193a9a0d119effc3be Mon Sep 17 00:00:00 2001 From: Mirko Friedenhagen Date: Wed, 2 Sep 2015 08:41:53 +0200 Subject: [PATCH 240/256] Only exclude commons-logging and log4j in dangerous scopes compile and runtime. --- pom.xml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index bd32871579..9490a34030 100644 --- a/pom.xml +++ b/pom.xml @@ -671,8 +671,10 @@ THE SOFTWARE. org.sonatype.sisu:sisu-guice - log4j:log4j - commons-logging:commons-logging + log4j:log4j:*:jar:compile + log4j:log4j:*:jar:runtime + commons-logging:commons-logging:*:jar:compile + commons-logging:commons-logging:*:jar:runtime From ff36f58886ea4784125eb33e0e3c5c929706af61 Mon Sep 17 00:00:00 2001 From: Mirko Friedenhagen Date: Wed, 2 Sep 2015 08:46:43 +0200 Subject: [PATCH 241/256] Exclude commons-logging and log4j in dangerous scopes compile and runtime in plugins as well. --- plugins/pom.xml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/plugins/pom.xml b/plugins/pom.xml index 10de0d719b..31c4304fcf 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -117,6 +117,31 @@ --> ${project.artifactId} + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-banned-dependencies + + enforce + + + + + + org.sonatype.sisu:sisu-guice + log4j:log4j:*:jar:compile + log4j:log4j:*:jar:runtime + commons-logging:commons-logging:*:jar:compile + commons-logging:commons-logging:*:jar:runtime + + + + + + + org.jenkins-ci.tools maven-hpi-plugin From 1003796ff22ee7af122abe9d080d3f4b1ebbee43 Mon Sep 17 00:00:00 2001 From: Mirko Friedenhagen Date: Thu, 3 Sep 2015 09:41:39 +0200 Subject: [PATCH 242/256] Manage commons-logging and log4j as provided, include slf4j adapters for tests. By means of this *all* logging should go to JUL. By defining slf4j-api as compile scope we mark it as the one to be used, while by declaring it optional we make sure it is not packaged in the resulting HPI. --- plugins/pom.xml | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/plugins/pom.xml b/plugins/pom.xml index 31c4304fcf..89c92c7de2 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -37,7 +37,23 @@ 1.7.7 - + + + + + commons-logging + commons-logging + 1.1.3 + provided + + + log4j + log4j + 1.2.17 + provided + + + org.jenkins-ci.main @@ -82,26 +98,27 @@ provided true - org.slf4j slf4j-api ${slf4jVersion} - provided + compile + + true + org.slf4j log4j-over-slf4j ${slf4jVersion} - provided + test org.slf4j jcl-over-slf4j ${slf4jVersion} - provided + test - org.slf4j slf4j-jdk14 From 93dfe3377ec8d430818f5b9073f16c677343adb4 Mon Sep 17 00:00:00 2001 From: James Nord Date: Fri, 4 Sep 2015 15:01:46 +0100 Subject: [PATCH 243/256] noting merge of PR#1816 - use slf4j interceptors --- changelog.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.html b/changelog.html index 1a3f839eac..5f80578727 100644 --- a/changelog.html +++ b/changelog.html @@ -55,7 +55,9 @@ Upcoming changes

      What's new in 1.627 (2015/08/30)

      From 4c8fe88343828f7b4ddcede4e4b730bd3da97d7d Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 6 Sep 2015 23:38:15 -0700 Subject: [PATCH 244/256] [maven-release-plugin] prepare release jenkins-1.628 --- cli/pom.xml | 2 +- core/pom.xml | 2 +- plugins/pom.xml | 10 +++++----- pom.xml | 4 ++-- test/pom.xml | 2 +- war/pom.xml | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cli/pom.xml b/cli/pom.xml index 17ca72fe80..d88f20dc33 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.628-SNAPSHOT + 1.628 cli diff --git a/core/pom.xml b/core/pom.xml index f9939ec761..1c39bae977 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.628-SNAPSHOT + 1.628 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index 89c92c7de2..d027d5924e 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.628-SNAPSHOT + 1.628 pom +

      What's new in 1.628 (2015/09/06)

      • Replaced all non java.util.logging logging libraries with slf4j interceptors. (PR 1816)
      -

      What's new in 1.627 (2015/08/30)

      • From 9b94b4676288c70684cf166166a0a1b922e8fdb9 Mon Sep 17 00:00:00 2001 From: Spike Washburn Date: Wed, 9 Sep 2015 14:27:55 -0400 Subject: [PATCH 247/256] [JENKINS-30374] Update obsolete help message Remove obsolete reference to "location you configured above" since the location is now determined automatically rather than explicitly configured. --- .../resources/hudson/tools/InstallSourceProperty/help.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/resources/hudson/tools/InstallSourceProperty/help.html b/core/src/main/resources/hudson/tools/InstallSourceProperty/help.html index dcf41ecf37..25ecfe6d61 100644 --- a/core/src/main/resources/hudson/tools/InstallSourceProperty/help.html +++ b/core/src/main/resources/hudson/tools/InstallSourceProperty/help.html @@ -1,6 +1,5 @@
        - Choose this option to let Jenkins install this tool for you on demand, - to the location you configured above. + Choose this option to let Jenkins install this tool for you on demand.

        If you check this option, you'll then be asked to configure a series From 2c5deeb6c061a91aeac232e978756de3b1d0be98 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Thu, 10 Sep 2015 14:25:04 +0100 Subject: [PATCH 248/256] [JENKINS-30139] Switch from a big fat lock to a concurrent collection --- .../java/hudson/diagnosis/OldDataMonitor.java | 98 ++++++++++--------- 1 file changed, 51 insertions(+), 47 deletions(-) diff --git a/core/src/main/java/hudson/diagnosis/OldDataMonitor.java b/core/src/main/java/hudson/diagnosis/OldDataMonitor.java index 5707b6d81b..c58eaa2811 100644 --- a/core/src/main/java/hudson/diagnosis/OldDataMonitor.java +++ b/core/src/main/java/hudson/diagnosis/OldDataMonitor.java @@ -25,7 +25,6 @@ package hudson.diagnosis; import com.google.common.base.Predicate; import com.thoughtworks.xstream.converters.UnmarshallingContext; - import hudson.Extension; import hudson.XmlFile; import hudson.model.AdministrativeMonitor; @@ -40,7 +39,6 @@ import hudson.model.listeners.SaveableListener; import hudson.security.ACL; import hudson.util.RobustReflectionConverter; import hudson.util.VersionNumber; - import java.io.IOException; import java.util.ArrayList; import java.util.Collection; @@ -49,13 +47,12 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; import java.util.logging.Logger; - import javax.annotation.CheckForNull; - import jenkins.model.Jenkins; - import org.acegisecurity.context.SecurityContext; import org.acegisecurity.context.SecurityContextHolder; import org.kohsuke.stapler.HttpRedirect; @@ -75,7 +72,7 @@ import org.kohsuke.stapler.interceptor.RequirePOST; public class OldDataMonitor extends AdministrativeMonitor { private static final Logger LOGGER = Logger.getLogger(OldDataMonitor.class.getName()); - private HashMap data = new HashMap(); + private ConcurrentMap data = new ConcurrentHashMap(); static OldDataMonitor get(Jenkins j) { return (OldDataMonitor) j.getAdministrativeMonitor("OldData"); @@ -95,12 +92,8 @@ public class OldDataMonitor extends AdministrativeMonitor { } public Map getData() { - Map _data; - synchronized (this) { - _data = new HashMap(this.data); - } Map r = new HashMap(); - for (Map.Entry entry : _data.entrySet()) { + for (Map.Entry entry : this.data.entrySet()) { Saveable s = entry.getKey().get(); if (s != null) { r.put(s, entry.getValue()); @@ -115,14 +108,13 @@ public class OldDataMonitor extends AdministrativeMonitor { OldDataMonitor odm = get(j); SecurityContext oldContext = ACL.impersonate(ACL.SYSTEM); try { - synchronized (odm) { - odm.data.remove(referTo(obj)); - if (isDelete && obj instanceof Job) - for (Run r : ((Job)obj).getBuilds()) - odm.data.remove(referTo(r)); + odm.data.remove(referTo(obj)); + if (isDelete && obj instanceof Job) { + for (Run r : ((Job) obj).getBuilds()) { + odm.data.remove(referTo(r)); + } } - } - finally { + } finally { SecurityContextHolder.setContext(oldContext); } } @@ -163,15 +155,19 @@ public class OldDataMonitor extends AdministrativeMonitor { */ public static void report(Saveable obj, String version) { OldDataMonitor odm = get(Jenkins.getInstance()); - synchronized (odm) { - try { - SaveableReference ref = referTo(obj); + try { + SaveableReference ref = referTo(obj); + while (true) { VersionRange vr = odm.data.get(ref); - if (vr != null) vr.add(version); - else odm.data.put(ref, new VersionRange(version, null)); - } catch (IllegalArgumentException ex) { - LOGGER.log(Level.WARNING, "Bad parameter given to OldDataMonitor", ex); + if (vr != null) { + vr.add(version); + break; + } else if (odm.data.putIfAbsent(ref, new VersionRange(version, null)) == null) { + break; + } } + } catch (IllegalArgumentException ex) { + LOGGER.log(Level.WARNING, "Bad parameter given to OldDataMonitor", ex); } } @@ -218,11 +214,15 @@ public class OldDataMonitor extends AdministrativeMonitor { return; } OldDataMonitor odm = get(j); - synchronized (odm) { - SaveableReference ref = referTo(obj); + SaveableReference ref = referTo(obj); + while (true) { VersionRange vr = odm.data.get(ref); - if (vr != null) vr.extra = buf.toString(); - else odm.data.put(ref, new VersionRange(null, buf.toString())); + if (vr != null) { + vr.extra = buf.toString(); + break; + } else if (odm.data.put(ref, new VersionRange(null, buf.toString())) == null) { + break; + } } } @@ -238,7 +238,7 @@ public class OldDataMonitor extends AdministrativeMonitor { this.extra = extra; } - public void add(String version) { + public synchronized void add(String version) { VersionNumber ver = new VersionNumber(version); if (min==null) { min = max = ver; } else { @@ -248,7 +248,7 @@ public class OldDataMonitor extends AdministrativeMonitor { } @Override - public String toString() { + public synchronized String toString() { return min==null ? "" : min.toString() + (single ? "" : " - " + max.toString()); } @@ -257,20 +257,31 @@ public class OldDataMonitor extends AdministrativeMonitor { * @param threshold Number of releases * @return True if the major version# differs or the minor# differs by >= threshold */ - public boolean isOld(int threshold) { + public synchronized boolean isOld(int threshold) { return currentVersion != null && min != null && (currentVersion.digit(0) > min.digit(0) || (currentVersion.digit(0) == min.digit(0) && currentVersion.digit(1) - min.digit(1) >= threshold)); } + + synchronized VersionNumber getMax() { + return max; + } + + synchronized VersionNumber getMin() { + return min; + } } /** * Sorted list of unique max-versions in the data set. For select list in jelly. */ - public synchronized Iterator getVersionList() { + public Iterator getVersionList() { TreeSet set = new TreeSet(); - for (VersionRange vr : data.values()) - if (vr.max!=null) set.add(vr.max); + for (VersionRange vr : data.values()) { + if (vr.getMax() != null) { + set.add(vr.getMax()); + } + } return set.iterator(); } @@ -296,10 +307,10 @@ public class OldDataMonitor extends AdministrativeMonitor { final String thruVerParam = req.getParameter("thruVer"); final VersionNumber thruVer = thruVerParam.equals("all") ? null : new VersionNumber(thruVerParam); - saveAndRemoveEntries( new Predicate>() { + saveAndRemoveEntries(new Predicate>() { @Override public boolean apply(Map.Entry entry) { - VersionNumber version = entry.getValue().max; + VersionNumber version = entry.getValue().getMax(); return version != null && (thruVer == null || !version.isNewerThan(thruVer)); } }); @@ -316,7 +327,7 @@ public class OldDataMonitor extends AdministrativeMonitor { saveAndRemoveEntries( new Predicate>() { @Override public boolean apply(Map.Entry entry) { - return entry.getValue().max == null; + return entry.getValue().getMax() == null; } }); @@ -335,13 +346,8 @@ public class OldDataMonitor extends AdministrativeMonitor { * does occur: just means the user will be prompted to discard less than they should have been (and * would see the warning again after next restart). */ - Map localCopy = null; - synchronized (this) { - localCopy = new HashMap(data); - } - List removed = new ArrayList(); - for (Map.Entry entry : localCopy.entrySet()) { + for (Map.Entry entry : data.entrySet()) { if (matchingPredicate.apply(entry)) { Saveable s = entry.getKey().get(); if (s != null) { @@ -355,9 +361,7 @@ public class OldDataMonitor extends AdministrativeMonitor { } } - synchronized (this) { - data.keySet().removeAll(removed); - } + data.keySet().removeAll(removed); } public HttpResponse doIndex(StaplerResponse rsp) throws IOException { From 9a57858a925aea1a01da9061d60e91e37d319873 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Thu, 10 Sep 2015 14:49:57 +0100 Subject: [PATCH 249/256] [JENKINS-30139] Add @Restricted to prevent external use of internal data --- .../java/hudson/diagnosis/OldDataMonitor.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/hudson/diagnosis/OldDataMonitor.java b/core/src/main/java/hudson/diagnosis/OldDataMonitor.java index c58eaa2811..e1ea6eeec1 100644 --- a/core/src/main/java/hudson/diagnosis/OldDataMonitor.java +++ b/core/src/main/java/hudson/diagnosis/OldDataMonitor.java @@ -55,6 +55,8 @@ import javax.annotation.CheckForNull; import jenkins.model.Jenkins; import org.acegisecurity.context.SecurityContext; import org.acegisecurity.context.SecurityContextHolder; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.HttpRedirect; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponses; @@ -229,8 +231,13 @@ public class OldDataMonitor extends AdministrativeMonitor { public static class VersionRange { private static VersionNumber currentVersion = Jenkins.getVersion(); - VersionNumber min, max; + @Restricted(NoExternalUse.class) + VersionNumber min; + @Restricted(NoExternalUse.class) + VersionNumber max; + @Restricted(NoExternalUse.class) boolean single = true; + @Restricted(NoExternalUse.class) public String extra; public VersionRange(String version, String extra) { @@ -263,10 +270,12 @@ public class OldDataMonitor extends AdministrativeMonitor { && currentVersion.digit(1) - min.digit(1) >= threshold)); } + @Restricted(NoExternalUse.class) synchronized VersionNumber getMax() { return max; } + @Restricted(NoExternalUse.class) synchronized VersionNumber getMin() { return min; } @@ -275,11 +284,13 @@ public class OldDataMonitor extends AdministrativeMonitor { /** * Sorted list of unique max-versions in the data set. For select list in jelly. */ + @Restricted(NoExternalUse.class) public Iterator getVersionList() { TreeSet set = new TreeSet(); for (VersionRange vr : data.values()) { - if (vr.getMax() != null) { - set.add(vr.getMax()); + VersionNumber max = vr.getMax(); + if (max != null) { + set.add(max); } } return set.iterator(); From 67cce20291be4d4002d7e293f1e0de6ee60058f3 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Thu, 10 Sep 2015 15:54:10 +0100 Subject: [PATCH 250/256] [JENKINS-30139] Forgot to change this one --- core/src/main/java/hudson/diagnosis/OldDataMonitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/diagnosis/OldDataMonitor.java b/core/src/main/java/hudson/diagnosis/OldDataMonitor.java index e1ea6eeec1..0786a85544 100644 --- a/core/src/main/java/hudson/diagnosis/OldDataMonitor.java +++ b/core/src/main/java/hudson/diagnosis/OldDataMonitor.java @@ -222,7 +222,7 @@ public class OldDataMonitor extends AdministrativeMonitor { if (vr != null) { vr.extra = buf.toString(); break; - } else if (odm.data.put(ref, new VersionRange(null, buf.toString())) == null) { + } else if (odm.data.putIfAbsent(ref, new VersionRange(null, buf.toString())) == null) { break; } } From e9471744338546539ed163d106763be021f278f8 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Fri, 11 Sep 2015 09:25:56 +0100 Subject: [PATCH 251/256] [JENKINS-30139] Oleg wants to keep the data accessible so we have to go for immutable --- .../java/hudson/diagnosis/OldDataMonitor.java | 79 +++++++++---------- 1 file changed, 38 insertions(+), 41 deletions(-) diff --git a/core/src/main/java/hudson/diagnosis/OldDataMonitor.java b/core/src/main/java/hudson/diagnosis/OldDataMonitor.java index 0786a85544..b955cd2178 100644 --- a/core/src/main/java/hudson/diagnosis/OldDataMonitor.java +++ b/core/src/main/java/hudson/diagnosis/OldDataMonitor.java @@ -161,10 +161,9 @@ public class OldDataMonitor extends AdministrativeMonitor { SaveableReference ref = referTo(obj); while (true) { VersionRange vr = odm.data.get(ref); - if (vr != null) { - vr.add(version); + if (vr != null && odm.data.replace(ref, vr, new VersionRange(vr, version, null))) { break; - } else if (odm.data.putIfAbsent(ref, new VersionRange(version, null)) == null) { + } else if (odm.data.putIfAbsent(ref, new VersionRange(null, version, null)) == null) { break; } } @@ -219,10 +218,9 @@ public class OldDataMonitor extends AdministrativeMonitor { SaveableReference ref = referTo(obj); while (true) { VersionRange vr = odm.data.get(ref); - if (vr != null) { - vr.extra = buf.toString(); + if (vr != null && odm.data.replace(ref, vr, new VersionRange(vr, null, buf.toString()))) { break; - } else if (odm.data.putIfAbsent(ref, new VersionRange(null, buf.toString())) == null) { + } else if (odm.data.putIfAbsent(ref, new VersionRange(null, null, buf.toString())) == null) { break; } } @@ -231,31 +229,40 @@ public class OldDataMonitor extends AdministrativeMonitor { public static class VersionRange { private static VersionNumber currentVersion = Jenkins.getVersion(); - @Restricted(NoExternalUse.class) - VersionNumber min; - @Restricted(NoExternalUse.class) - VersionNumber max; - @Restricted(NoExternalUse.class) - boolean single = true; - @Restricted(NoExternalUse.class) - public String extra; + final VersionNumber min; + final VersionNumber max; + final boolean single; + final public String extra; - public VersionRange(String version, String extra) { - min = max = version != null ? new VersionNumber(version) : null; - this.extra = extra; - } - - public synchronized void add(String version) { - VersionNumber ver = new VersionNumber(version); - if (min==null) { min = max = ver; } - else { - if (ver.isOlderThan(min)) { min = ver; single = false; } - if (ver.isNewerThan(max)) { max = ver; single = false; } + public VersionRange(VersionRange previous, String version, String extra) { + if (previous == null) { + min = max = version != null ? new VersionNumber(version) : null; + this.single = true; + this.extra = extra; + } else if (version == null) { + min = previous.min; + max = previous.max; + single = previous.single; + this.extra = extra; + } else { + VersionNumber ver = new VersionNumber(version); + if (previous.min == null || ver.isOlderThan(previous.min)) { + this.min = ver; + } else { + this.min = previous.min; + } + if (previous.max == null || ver.isNewerThan(previous.max)) { + this.max = ver; + } else { + this.max = previous.max; + } + this.single = this.max.isNewerThan(this.min); + this.extra = extra; } } @Override - public synchronized String toString() { + public String toString() { return min==null ? "" : min.toString() + (single ? "" : " - " + max.toString()); } @@ -264,21 +271,12 @@ public class OldDataMonitor extends AdministrativeMonitor { * @param threshold Number of releases * @return True if the major version# differs or the minor# differs by >= threshold */ - public synchronized boolean isOld(int threshold) { + public boolean isOld(int threshold) { return currentVersion != null && min != null && (currentVersion.digit(0) > min.digit(0) || (currentVersion.digit(0) == min.digit(0) && currentVersion.digit(1) - min.digit(1) >= threshold)); } - @Restricted(NoExternalUse.class) - synchronized VersionNumber getMax() { - return max; - } - - @Restricted(NoExternalUse.class) - synchronized VersionNumber getMin() { - return min; - } } /** @@ -288,9 +286,8 @@ public class OldDataMonitor extends AdministrativeMonitor { public Iterator getVersionList() { TreeSet set = new TreeSet(); for (VersionRange vr : data.values()) { - VersionNumber max = vr.getMax(); - if (max != null) { - set.add(max); + if (vr.max != null) { + set.add(vr.max); } } return set.iterator(); @@ -321,7 +318,7 @@ public class OldDataMonitor extends AdministrativeMonitor { saveAndRemoveEntries(new Predicate>() { @Override public boolean apply(Map.Entry entry) { - VersionNumber version = entry.getValue().getMax(); + VersionNumber version = entry.getValue().max; return version != null && (thruVer == null || !version.isNewerThan(thruVer)); } }); @@ -338,7 +335,7 @@ public class OldDataMonitor extends AdministrativeMonitor { saveAndRemoveEntries( new Predicate>() { @Override public boolean apply(Map.Entry entry) { - return entry.getValue().getMax() == null; + return entry.getValue().max == null; } }); From b757e28ba9b125ffff8c1fd31f56c4566cba02ec Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Tue, 15 Sep 2015 00:08:56 -0700 Subject: [PATCH 252/256] [maven-release-plugin] prepare release jenkins-1.629 --- cli/pom.xml | 2 +- core/pom.xml | 2 +- plugins/pom.xml | 10 +++++----- pom.xml | 4 ++-- test/pom.xml | 2 +- war/pom.xml | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cli/pom.xml b/cli/pom.xml index cd2deac47d..f3294603fb 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.629-SNAPSHOT + 1.629 cli diff --git a/core/pom.xml b/core/pom.xml index 3d1227aae4..47e0805799 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.629-SNAPSHOT + 1.629 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index be24864f23..24583aa30a 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.629-SNAPSHOT + 1.629 pom +

        What's new in 1.629 (2015/09/15)

        +
          +
        • +

        What's new in 1.628 (2015/09/06)

        • From 72dc7c9bd72b5c9d54945a3aa7048eccc4cdbbc5 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Tue, 15 Sep 2015 23:19:09 +0200 Subject: [PATCH 255/256] Noting #1825 --- changelog.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.html b/changelog.html index 858b728ea3..1a85df42ee 100644 --- a/changelog.html +++ b/changelog.html @@ -60,7 +60,9 @@ Upcoming changes

        What's new in 1.629 (2015/09/15)

          -
        • +
        • + Old data monitor made Jenkins single-threaded for all saves. + (issue 30139)

        What's new in 1.628 (2015/09/06)

          From 4ea5246b868078a3fc39b17e0eef535b5a2f2d53 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Tue, 15 Sep 2015 23:24:38 +0200 Subject: [PATCH 256/256] Noting #1817 --- changelog.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.html b/changelog.html index 1a85df42ee..4a165300ef 100644 --- a/changelog.html +++ b/changelog.html @@ -69,6 +69,9 @@ Upcoming changes
        • Replaced all non java.util.logging logging libraries with slf4j interceptors. (PR 1816) +
        • + Document allBuilds subtree in remote API for jobs. + (PR 1817)

        What's new in 1.627 (2015/08/30)