From 86319de87b8469c06cf56ed933cfe85bade4eee4 Mon Sep 17 00:00:00 2001 From: ikedam Date: Sun, 13 Apr 2014 08:48:09 +0900 Subject: [PATCH 0001/2573] [FIXED JENKINS-19565] Pass ${it} and ${instance} to contents of dropdownDescriptorSelector. And developers now can specify attr.capture to pass any variables. --- .../resources/lib/form/dropdownDescriptorSelector.jelly | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/form/dropdownDescriptorSelector.jelly b/core/src/main/resources/lib/form/dropdownDescriptorSelector.jelly index aad0a87e51..122e7f6a8b 100644 --- a/core/src/main/resources/lib/form/dropdownDescriptorSelector.jelly +++ b/core/src/main/resources/lib/form/dropdownDescriptorSelector.jelly @@ -42,6 +42,11 @@ THE SOFTWARE. If specified, this will be chosen as the default value in case the current selection is null. The default can be an specific instance or a descriptor e.g. ${descriptor.defaultSettingsProvider} or ${descriptor.defaultSettingsProvider.descriptor}. In the later case, the from input fields will be empty. + + Config fragments from descriptors are rendered lazily by default, which means + variables seen in the caller aren't visible to them. This attribute allows you + to nominate additional variables and their values to be captured for descriptors. + @@ -51,10 +56,11 @@ THE SOFTWARE. + + lazy="descriptor,it,${capture}"> From 358b9cee87c154e7ed9b689acfc35bf58b481614 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 27 Jun 2014 15:25:40 -0700 Subject: [PATCH 0002/2573] Adding a module to allow organizations to track usage of Jenkins within their domain. There is a privacy concern in having this information reported, but OTOH in a corporate network this seems like a reasonable compromise, and people really often do not have any clues where they are running. --- war/pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/war/pom.xml b/war/pom.xml index d4d10cd1b0..6179ef6247 100644 --- a/war/pom.xml +++ b/war/pom.xml @@ -106,6 +106,11 @@ THE SOFTWARE. 2.3 test + + org.jenkins-ci.modules + domain-discovery + 1.0 + org.jenkins-ci.modules instance-identity From b105627b7357149f98f87ec2bf494e25bd2ed88b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Sat, 4 Oct 2014 19:02:41 +0200 Subject: [PATCH 0003/2573] Towards 1.580.1 --- cli/pom.xml | 2 +- core/pom.xml | 2 +- pom.xml | 2 +- test/pom.xml | 2 +- war/pom.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cli/pom.xml b/cli/pom.xml index aefb8624d1..1246ee67ac 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ pom org.jenkins-ci.main - 1.580 + 1.580.1-SNAPSHOT cli diff --git a/core/pom.xml b/core/pom.xml index d4237c9570..a8c3aff01f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.580 + 1.580.1-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index c750099276..ec02c9834a 100644 --- a/pom.xml +++ b/pom.xml @@ -33,7 +33,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.580 + 1.580.1-SNAPSHOT pom Jenkins main module diff --git a/test/pom.xml b/test/pom.xml index ad8ad4021e..6b17874b33 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. pom org.jenkins-ci.main - 1.580 + 1.580.1-SNAPSHOT org.jenkins-ci.main jenkins-test-harness diff --git a/war/pom.xml b/war/pom.xml index 7908cc6d8d..9d24986be1 100644 --- a/war/pom.xml +++ b/war/pom.xml @@ -28,7 +28,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.580 + 1.580.1-SNAPSHOT ../pom.xml From 8ae29e50c7356a8e2ec9be1126bad957dab0117a Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Wed, 17 Sep 2014 15:35:22 -0700 Subject: [PATCH 0004/2573] [JENKINS-24458 JENKINS-11543] integrated the newer version of stapler with reduced log level (cherry picked from commit c57f9ed577b9635f01aa5affabf1f770b689a115) Conflicts: changelog.html --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index a8c3aff01f..0b4e47b806 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -42,7 +42,7 @@ THE SOFTWARE. true - 1.228 + 1.229 2.5.6.SEC03 1.8.9 From 9c82fc42eb08b89047c544aaa586291ad1485472 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 5 Sep 2014 15:54:04 -0700 Subject: [PATCH 0005/2573] [JENKINS-23471 JENKINS-24050] Integrated the fix in remoting to Jenkins 1.580. (cherry picked from commit 8fc609fe0952b285d5b26a59fd5ff4c29704d33d) --- changelog.html | 7 ++++++- pom.xml | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/changelog.html b/changelog.html index 9a573c333c..e77e92e036 100644 --- a/changelog.html +++ b/changelog.html @@ -55,7 +55,12 @@ Upcoming changes diff --git a/pom.xml b/pom.xml index ec02c9834a..96343e1015 100644 --- a/pom.xml +++ b/pom.xml @@ -173,7 +173,7 @@ THE SOFTWARE. org.jenkins-ci.main remoting - 2.44 + 2.45 From 4d455fbb0d2f33bd87a8c38580f7ff2ffb78b0ac Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Sun, 14 Sep 2014 13:03:08 +0200 Subject: [PATCH 0006/2573] [FIXED JENKINS-24614] Broken format string in Hebrew console output (cherry picked from commit 07fd5fa45d4b818fc11de97ce99ab6b3423aca85) --- core/src/main/resources/hudson/model/Run/console_he.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/hudson/model/Run/console_he.properties b/core/src/main/resources/hudson/model/Run/console_he.properties index 36cd1812f3..03765f592e 100644 --- a/core/src/main/resources/hudson/model/Run/console_he.properties +++ b/core/src/main/resources/hudson/model/Run/console_he.properties @@ -22,4 +22,4 @@ Console\ Output=\u05E4\u05DC\u05D8 \u05DE\u05E1\u05DA View\ as\ plain\ text=\u05E6\u05E4\u05D9\u05D9\u05D4 \u05DB\u05D8\u05E7\u05E1\u05D8 -skipSome=\u05DE\u05D3\u05DC\u05D2 {0,\u05DE\u05E1\u05E4\u05E8,\u05DE\u05E1\u05E4\u05E8 \u05E9\u05DC\u05DD} \u05E7"\u05D1.. \u05D3\u05D5"\u05D7 \u05DE\u05DC\u05D0 +skipSome=\u05DE\u05D3\u05DC\u05D2 {0,number,integer} \u05E7"\u05D1.. \u05D3\u05D5"\u05D7 \u05DE\u05DC\u05D0 From efae48a451b1dbb15a13abff26b0bec269a63909 Mon Sep 17 00:00:00 2001 From: David Ruhmann Date: Fri, 15 Aug 2014 12:21:15 -0500 Subject: [PATCH 0007/2573] [FIXED JENKINS-7478] Create Line Ending Conversion utility to convert scripts to proper OS line ending type. Tests included. (cherry picked from commit 67ac47af0709dde6297dffeb210b03d8b65f6033) --- .../src/main/java/hudson/tasks/BatchFile.java | 10 ++- core/src/main/java/hudson/tasks/Shell.java | 34 +++------- .../tools/AbstractCommandInstaller.java | 15 +---- .../hudson/tools/BatchCommandInstaller.java | 8 ++- .../java/hudson/tools/CommandInstaller.java | 8 ++- .../hudson/util/LineEndingConversion.java | 66 +++++++++++++++++++ .../test/java/hudson/tasks/BatchFileTest.java | 30 +++++++++ .../src/test/java/hudson/tasks/ShellTest.java | 43 +++++++++--- .../tools/BatchCommandInstallerTest.java | 22 +++++++ .../hudson/tools/CommandInstallerTest.java | 22 +++++++ .../hudson/util/LineEndingConversionTest.java | 28 ++++++++ 11 files changed, 233 insertions(+), 53 deletions(-) create mode 100644 core/src/main/java/hudson/util/LineEndingConversion.java create mode 100644 test/src/test/java/hudson/tasks/BatchFileTest.java create mode 100644 test/src/test/java/hudson/tools/BatchCommandInstallerTest.java create mode 100644 test/src/test/java/hudson/tools/CommandInstallerTest.java create mode 100644 test/src/test/java/hudson/util/LineEndingConversionTest.java diff --git a/core/src/main/java/hudson/tasks/BatchFile.java b/core/src/main/java/hudson/tasks/BatchFile.java index 0943e9147f..b2506474be 100644 --- a/core/src/main/java/hudson/tasks/BatchFile.java +++ b/core/src/main/java/hudson/tasks/BatchFile.java @@ -26,9 +26,11 @@ package hudson.tasks; import hudson.FilePath; import hudson.Extension; import hudson.model.AbstractProject; +import hudson.util.LineEndingConversion; import net.sf.json.JSONObject; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.StaplerRequest; +import java.io.ObjectStreamException; /** * Executes commands by using Windows batch file. @@ -38,7 +40,7 @@ import org.kohsuke.stapler.StaplerRequest; public class BatchFile extends CommandInterpreter { @DataBoundConstructor public BatchFile(String command) { - super(command); + super(LineEndingConversion.convertEOL(command, LineEndingConversion.EOLType.Windows)); } public String[] buildCommandLine(FilePath script) { @@ -46,13 +48,17 @@ public class BatchFile extends CommandInterpreter { } protected String getContents() { - return command+"\r\nexit %ERRORLEVEL%"; + return LineEndingConversion.convertEOL(command+"\r\nexit %ERRORLEVEL%",LineEndingConversion.EOLType.Windows); } protected String getFileExtension() { return ".bat"; } + private Object readResolve() throws ObjectStreamException { + return new BatchFile(command); + } + @Extension public static final class DescriptorImpl extends BuildStepDescriptor { @Override diff --git a/core/src/main/java/hudson/tasks/Shell.java b/core/src/main/java/hudson/tasks/Shell.java index 5a3a2053db..17ce0b8819 100644 --- a/core/src/main/java/hudson/tasks/Shell.java +++ b/core/src/main/java/hudson/tasks/Shell.java @@ -32,6 +32,8 @@ import hudson.remoting.Callable; import hudson.remoting.VirtualChannel; import hudson.util.FormValidation; import java.io.IOException; +import java.io.ObjectStreamException; +import hudson.util.LineEndingConversion; import net.sf.json.JSONObject; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.StaplerRequest; @@ -50,29 +52,7 @@ import java.util.logging.Logger; public class Shell extends CommandInterpreter { @DataBoundConstructor public Shell(String command) { - super(fixCrLf(command)); - } - - /** - * Fix CR/LF and always make it Unix style. - */ - private static String fixCrLf(String s) { - // eliminate CR - int idx; - while((idx=s.indexOf("\r\n"))!=-1) - s = s.substring(0,idx)+s.substring(idx+1); - - //// add CR back if this is for Windows - //if(isWindows()) { - // idx=0; - // while(true) { - // idx = s.indexOf('\n',idx); - // if(idx==-1) break; - // s = s.substring(0,idx)+'\r'+s.substring(idx); - // idx+=2; - // } - //} - return s; + super(LineEndingConversion.convertEOL(command, LineEndingConversion.EOLType.Unix)); } /** @@ -80,7 +60,7 @@ public class Shell extends CommandInterpreter { * makes the shell think the file is a binary file and not a script. Adding * a leading line feed works around this problem. */ - private static String addCrForNonASCII(String s) { + private static String addLineFeedForNonASCII(String s) { if(!s.startsWith("#!")) { if (s.indexOf('\n')!=0) { return "\n" + s; @@ -105,7 +85,7 @@ public class Shell extends CommandInterpreter { } protected String getContents() { - return addCrForNonASCII(fixCrLf(command)); + return addLineFeedForNonASCII(LineEndingConversion.convertEOL(command,LineEndingConversion.EOLType.Unix)); } protected String getFileExtension() { @@ -117,6 +97,10 @@ public class Shell extends CommandInterpreter { return (DescriptorImpl)super.getDescriptor(); } + private Object readResolve() throws ObjectStreamException { + return new Shell(command); + } + @Extension public static class DescriptorImpl extends BuildStepDescriptor { /** diff --git a/core/src/main/java/hudson/tools/AbstractCommandInstaller.java b/core/src/main/java/hudson/tools/AbstractCommandInstaller.java index 07d91c6c0c..18431fcda1 100644 --- a/core/src/main/java/hudson/tools/AbstractCommandInstaller.java +++ b/core/src/main/java/hudson/tools/AbstractCommandInstaller.java @@ -48,7 +48,7 @@ public abstract class AbstractCommandInstaller extends ToolInstaller { public AbstractCommandInstaller(String label, String command, String toolHome) { super(label); - this.command = fixCrLf(command); + this.command = command; this.toolHome = toolHome; } @@ -84,19 +84,6 @@ public abstract class AbstractCommandInstaller extends ToolInstaller { return dir.child(getToolHome()); } - /** - * Fix CR/LF and always make it Unix style. - */ - //TODO: replace by a Windows style - private static String fixCrLf(String s) { - // eliminate CR - int idx; - while ((idx = s.indexOf("\r\n")) != -1) { - s = s.substring(0, idx) + s.substring(idx + 1); - } - return s; - } - public static abstract class Descriptor extends ToolInstallerDescriptor { diff --git a/core/src/main/java/hudson/tools/BatchCommandInstaller.java b/core/src/main/java/hudson/tools/BatchCommandInstaller.java index 415dbb700f..2085fe7fa0 100644 --- a/core/src/main/java/hudson/tools/BatchCommandInstaller.java +++ b/core/src/main/java/hudson/tools/BatchCommandInstaller.java @@ -26,7 +26,9 @@ package hudson.tools; import hudson.Extension; import hudson.FilePath; +import hudson.util.LineEndingConversion; import org.kohsuke.stapler.DataBoundConstructor; +import java.io.ObjectStreamException; /** * Installs tool via script execution of Batch script. @@ -37,7 +39,7 @@ public class BatchCommandInstaller extends AbstractCommandInstaller { @DataBoundConstructor public BatchCommandInstaller(String label, String command, String toolHome) { - super(label, command, toolHome); + super(label, LineEndingConversion.convertEOL(command, LineEndingConversion.EOLType.Windows), toolHome); } @Override @@ -50,6 +52,10 @@ public class BatchCommandInstaller extends AbstractCommandInstaller { String[] cmd = {"cmd", "/c", "call", script.getRemote()}; return cmd; } + + private Object readResolve() throws ObjectStreamException { + return new BatchCommandInstaller(getLabel(), getCommand(), getToolHome()); + } @Extension public static class DescriptorImpl extends Descriptor { diff --git a/core/src/main/java/hudson/tools/CommandInstaller.java b/core/src/main/java/hudson/tools/CommandInstaller.java index b02137f0f5..6f2506dd04 100644 --- a/core/src/main/java/hudson/tools/CommandInstaller.java +++ b/core/src/main/java/hudson/tools/CommandInstaller.java @@ -26,7 +26,9 @@ package hudson.tools; import hudson.Extension; import hudson.FilePath; +import hudson.util.LineEndingConversion; import org.kohsuke.stapler.DataBoundConstructor; +import java.io.ObjectStreamException; /** * Installs a tool by running an arbitrary shell command. @@ -36,7 +38,7 @@ public class CommandInstaller extends AbstractCommandInstaller { @DataBoundConstructor public CommandInstaller(String label, String command, String toolHome) { - super(label, command, toolHome); + super(label, LineEndingConversion.convertEOL(command, LineEndingConversion.EOLType.Unix), toolHome); } @Override @@ -50,6 +52,10 @@ public class CommandInstaller extends AbstractCommandInstaller { return cmd; } + private Object readResolve() throws ObjectStreamException { + return new CommandInstaller(getLabel(), getCommand(), getToolHome()); + } + @Extension public static class DescriptorImpl extends Descriptor { diff --git a/core/src/main/java/hudson/util/LineEndingConversion.java b/core/src/main/java/hudson/util/LineEndingConversion.java new file mode 100644 index 0000000000..744ff4a4ea --- /dev/null +++ b/core/src/main/java/hudson/util/LineEndingConversion.java @@ -0,0 +1,66 @@ +package hudson.util; + +/** + * Converts line endings of a string. + * + * @since TODO + * @author David Ruhmann + */ +public class LineEndingConversion { + + /** + * Supported line ending types for conversion + */ + public enum EOLType { + CR, + CRLF, + LF, + LFCR, + Mac, + Unix, + Windows + } + + /** + * Convert line endings of a string to the given type. Default to Unix type. + * + * @param input + * The string containing line endings to be converted. + * @param type + * Type of line endings to convert the string into. + * @return + * String updated with the new line endings or null if given null. + */ + public static String convertEOL(String input, EOLType type) { + if (null == input || 0 == input.length()) { + return input; + } + // Convert line endings to Unix LF, + // which also sets up the string for other conversions + input = input.replace("\r\n","\n"); + input = input.replace("\r","\n"); + switch (type) { + case CR: + case Mac: + // Convert line endings to CR + input = input.replace("\n", "\r"); + break; + case CRLF: + case Windows: + // Convert line endings to Windows CR/LF + input = input.replace("\n", "\r\n"); + break; + default: + case LF: + case Unix: + // Conversion already completed + return input; + case LFCR: + // Convert line endings to LF/CR + input = input.replace("\n", "\n\r"); + break; + } + return input; + } +} + diff --git a/test/src/test/java/hudson/tasks/BatchFileTest.java b/test/src/test/java/hudson/tasks/BatchFileTest.java new file mode 100644 index 0000000000..8cc16fd10a --- /dev/null +++ b/test/src/test/java/hudson/tasks/BatchFileTest.java @@ -0,0 +1,30 @@ +package hudson.tasks; + +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.JenkinsRule; + +/** + * Tests for the BatchFile tasks class. + * + * @author David Ruhmann + */ +public class BatchFileTest { + + @Rule + public JenkinsRule rule = new JenkinsRule(); + + @Issue("JENKINS-7478") + @Test + public void validateBatchFileCommandEOL() throws Exception { + BatchFile obj = new BatchFile("echo A\necho B\recho C"); + rule.assertStringContains(obj.getCommand(), "echo A\r\necho B\r\necho C"); + } + + @Test + public void validateBatchFileContents() throws Exception { + BatchFile obj = new BatchFile("echo A\necho B\recho C"); + rule.assertStringContains(obj.getContents(), "echo A\r\necho B\r\necho C\r\nexit %ERRORLEVEL%"); + } +} diff --git a/test/src/test/java/hudson/tasks/ShellTest.java b/test/src/test/java/hudson/tasks/ShellTest.java index e1e0d7d867..8aadb4f4ba 100644 --- a/test/src/test/java/hudson/tasks/ShellTest.java +++ b/test/src/test/java/hudson/tasks/ShellTest.java @@ -7,7 +7,6 @@ import hudson.model.FreeStyleBuild; import hudson.model.FreeStyleProject; import org.apache.commons.io.FileUtils; import org.jvnet.hudson.test.FakeLauncher; -import org.jvnet.hudson.test.HudsonTestCase; import org.jvnet.hudson.test.PretendSlave; import java.io.File; @@ -15,23 +14,47 @@ import java.io.IOException; import java.io.PrintStream; import java.util.List; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + /** + * Tests for the Shell tasks class + * * @author Kohsuke Kawaguchi */ -public class ShellTest extends HudsonTestCase { +public class ShellTest { + + @Rule + public JenkinsRule rule = new JenkinsRule(); + + @Test + public void validateShellCommandEOL() throws Exception { + Shell obj = new Shell("echo A\r\necho B\recho C"); + rule.assertStringContains(obj.getCommand(), "echo A\necho B\necho C"); + } + + @Test + public void validateShellContents() throws Exception { + Shell obj = new Shell("echo A\r\necho B\recho C"); + rule.assertStringContains(obj.getContents(), "\necho A\necho B\necho C"); + } + + @Test public void testBasic() throws Exception { // If we're on Windows, don't bother doing this. if (Functions.isWindows()) return; // TODO: define a FakeLauncher implementation with easymock so that this kind of assertions can be simplified. - PretendSlave s = createPretendSlave(new FakeLauncher() { + PretendSlave s = rule.createPretendSlave(new FakeLauncher() { public Proc onLaunch(ProcStarter p) throws IOException { // test the command line argument. List cmds = p.cmds(); - assertEquals("/bin/sh",cmds.get(0)); - assertEquals("-xe",cmds.get(1)); - assertTrue(new File(cmds.get(2)).exists()); + rule.assertStringContains("/bin/sh",cmds.get(0)); + rule.assertStringContains("-xe",cmds.get(1)); + Assert.assertTrue(new File(cmds.get(2)).exists()); // fake the execution PrintStream ps = new PrintStream(p.stdout()); @@ -41,13 +64,13 @@ public class ShellTest extends HudsonTestCase { return new FinishedProc(0); } }); - FreeStyleProject p = createFreeStyleProject(); + FreeStyleProject p = rule.createFreeStyleProject(); p.getBuildersList().add(new Shell("echo abc")); p.setAssignedNode(s); - FreeStyleBuild b = assertBuildStatusSuccess(p.scheduleBuild2(0).get()); + FreeStyleBuild b = rule.assertBuildStatusSuccess(p.scheduleBuild2(0).get()); - assertEquals(1,s.numLaunch); - assertTrue(FileUtils.readFileToString(b.getLogFile()).contains("Hudson was here")); + Assert.assertEquals(1,s.numLaunch); + Assert.assertTrue(FileUtils.readFileToString(b.getLogFile()).contains("Hudson was here")); } } diff --git a/test/src/test/java/hudson/tools/BatchCommandInstallerTest.java b/test/src/test/java/hudson/tools/BatchCommandInstallerTest.java new file mode 100644 index 0000000000..e14a90b405 --- /dev/null +++ b/test/src/test/java/hudson/tools/BatchCommandInstallerTest.java @@ -0,0 +1,22 @@ +package hudson.tools; + +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + +/** + * Tests for the BatchCommandInstaller tools class. + * + * @author David Ruhmann + */ +public class BatchCommandInstallerTest { + + @Rule + public JenkinsRule rule = new JenkinsRule(); + + @Test + public void validateBatchCommandInstallerCommandEOL() throws Exception { + BatchCommandInstaller obj = new BatchCommandInstaller("", "echo A\necho B\recho C", ""); + rule.assertStringContains(obj.getCommand(), "echo A\r\necho B\r\necho C"); + } +} diff --git a/test/src/test/java/hudson/tools/CommandInstallerTest.java b/test/src/test/java/hudson/tools/CommandInstallerTest.java new file mode 100644 index 0000000000..7a58c1ec8c --- /dev/null +++ b/test/src/test/java/hudson/tools/CommandInstallerTest.java @@ -0,0 +1,22 @@ +package hudson.tools; + +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + +/** + * Tests for the CommandInstaller tools class. + * + * @author David Ruhmann + */ +public class CommandInstallerTest { + + @Rule + public JenkinsRule rule = new JenkinsRule(); + + @Test + public void validateCommandInstallerCommandEOL() throws Exception { + CommandInstaller obj = new CommandInstaller("", "echo A\r\necho B\recho C", ""); + rule.assertStringContains(obj.getCommand(), "echo A\necho B\necho C"); + } +} diff --git a/test/src/test/java/hudson/util/LineEndingConversionTest.java b/test/src/test/java/hudson/util/LineEndingConversionTest.java new file mode 100644 index 0000000000..66773fbbb9 --- /dev/null +++ b/test/src/test/java/hudson/util/LineEndingConversionTest.java @@ -0,0 +1,28 @@ +package hudson.util; + +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.JenkinsRule; + +/** + * Tests for the LineEndingConversion util class. + * + * @author David Ruhmann + */ +public class LineEndingConversionTest { + + @Rule + public JenkinsRule rule = new JenkinsRule(); + + @Issue("JENKINS-7478") + @Test + public void validateWindowsEOL() throws Exception { + rule.assertStringContains(LineEndingConversion.convertEOL("echo A\necho B\recho C", LineEndingConversion.EOLType.Windows), "echo A\r\necho B\r\necho C"); + } + + @Test + public void validateUnixEOL() throws Exception { + rule.assertStringContains(LineEndingConversion.convertEOL("echo A\r\necho B\recho C", LineEndingConversion.EOLType.Unix), "echo A\necho B\necho C"); + } +} From 20473dab36e88fca4f7826a61346a4e3a043f1ac Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 17 Sep 2014 10:01:13 -0400 Subject: [PATCH 0008/2573] @DataBoundConstructor makes no sense on an abstract class. (cherry picked from commit 71600d8b37581ea367937e0cda6dbc31b13c6904) --- core/src/main/java/hudson/model/Slave.java | 2 -- .../java/hudson/node_monitors/AbstractDiskSpaceMonitor.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/core/src/main/java/hudson/model/Slave.java b/core/src/main/java/hudson/model/Slave.java index d29ed99a13..625cea4b05 100644 --- a/core/src/main/java/hudson/model/Slave.java +++ b/core/src/main/java/hudson/model/Slave.java @@ -62,7 +62,6 @@ import jenkins.model.Jenkins; import jenkins.slaves.WorkspaceLocator; import org.apache.commons.io.IOUtils; -import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; @@ -134,7 +133,6 @@ public abstract class Slave extends Node implements Serializable { */ private String userId; - @DataBoundConstructor public Slave(String name, String nodeDescription, String remoteFS, String numExecutors, Mode mode, String labelString, ComputerLauncher launcher, RetentionStrategy retentionStrategy, List> nodeProperties) throws FormException, IOException { this(name,nodeDescription,remoteFS,Util.tryParseNumber(numExecutors, 1).intValue(),mode,labelString,launcher,retentionStrategy, nodeProperties); diff --git a/core/src/main/java/hudson/node_monitors/AbstractDiskSpaceMonitor.java b/core/src/main/java/hudson/node_monitors/AbstractDiskSpaceMonitor.java index be90b91d0e..384133b937 100644 --- a/core/src/main/java/hudson/node_monitors/AbstractDiskSpaceMonitor.java +++ b/core/src/main/java/hudson/node_monitors/AbstractDiskSpaceMonitor.java @@ -5,7 +5,6 @@ import hudson.node_monitors.DiskSpaceMonitorDescriptor.DiskSpace; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; -import org.kohsuke.stapler.DataBoundConstructor; import java.text.ParseException; import java.util.logging.Logger; @@ -21,7 +20,6 @@ public abstract class AbstractDiskSpaceMonitor extends NodeMonitor { */ public final String freeSpaceThreshold; - @DataBoundConstructor public AbstractDiskSpaceMonitor(String threshold) throws ParseException { this.freeSpaceThreshold = threshold; DiskSpace.parse(threshold); // make sure it parses From 21fb398bfa7068f6f72154763bdbb09baddf313d Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Mon, 22 Sep 2014 18:09:26 -0700 Subject: [PATCH 0009/2573] [JENKINS-24453][ZD-20503] Incorporated a newer version of winp. This version checks the critical flag of the process, as killing such a process results in BSoD. (cherry picked from commit 040b7d4047b324f17c0971f2511f954eb173fa23) Conflicts: changelog.html --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index 0b4e47b806..214de797f6 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -484,7 +484,7 @@ THE SOFTWARE. org.jvnet.winp winp - 1.21 + 1.22 org.jenkins-ci From 66dce647d1d7df919f9707b4ce631cd49dc242f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Mon, 13 Oct 2014 22:02:57 +0200 Subject: [PATCH 0010/2573] [JENKINS-11543] Unit test (cherry picked from commit 75f5d2180f7340ce2efd4f41c8670afb049eb530) --- .../java/hudson/model/ParametersTest.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/test/src/test/java/hudson/model/ParametersTest.java b/test/src/test/java/hudson/model/ParametersTest.java index 0cc4044942..3b5610cdcb 100644 --- a/test/src/test/java/hudson/model/ParametersTest.java +++ b/test/src/test/java/hudson/model/ParametersTest.java @@ -1,13 +1,20 @@ package hudson.model; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; + +import org.junit.Test; +import org.jvnet.hudson.test.Bug; import org.jvnet.hudson.test.HudsonTestCase; import org.jvnet.hudson.test.CaptureEnvironmentBuilder; + import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlElement; import com.gargoylesoftware.htmlunit.html.HtmlTextInput; import com.gargoylesoftware.htmlunit.html.HtmlCheckBoxInput; import com.gargoylesoftware.htmlunit.html.HtmlOption; + import java.util.Set; /** @@ -157,4 +164,23 @@ public class ParametersTest extends HudsonTestCase { assertTrue(sensitiveVars.contains("password")); assertFalse(sensitiveVars.contains("string2")); } + + @Bug(11543) + public void testUnicodeParametersArePresetedCorrectly() throws Exception { + final FreeStyleProject p = createFreeStyleProject(); + ParametersDefinitionProperty pdb = new ParametersDefinitionProperty( + new StringParameterDefinition("sname:a¶‱ﻷ", "svalue:a¶‱ﻷ", "sdesc:a¶‱ﻷ"), + new FileParameterDefinition("fname:a¶‱ﻷ", "fdesc:a¶‱ﻷ") + ); + p.addProperty(pdb); + + WebClient wc = createWebClient(); + wc.setThrowExceptionOnFailingStatusCode(false); // Ignore 405 + HtmlPage page = wc.getPage(p, "build"); + + // java.lang.IllegalArgumentException: No such parameter definition: . + wc.setThrowExceptionOnFailingStatusCode(true); + final HtmlForm form = page.getFormByName("parameters"); + form.submit(form.getButtonByCaption("Build")); + } } From 96b973c4082569d4ed386aca5edf21205bfb7314 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Wed, 8 Oct 2014 13:46:33 -0700 Subject: [PATCH 0011/2573] Integrated the new version. This version includes a change from christ66 in https://github.com/stapler/stapler/pull/40 (cherry picked from commit 65c2d378814ebd3fe8c43f428a1408dd6354c9bb) Conflicts: core/pom.xml --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index 214de797f6..fe7fcf64ee 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -42,7 +42,7 @@ THE SOFTWARE. true - 1.229 + 1.231 2.5.6.SEC03 1.8.9 From 69c1492fa09c89456d69a804d2560c443405b662 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 16 Oct 2014 19:41:26 -0400 Subject: [PATCH 0012/2573] maven-plugin SECURITY-144 is now 2.7.1-SNAPSHOT. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7649134c7b..30f92d3fc6 100644 --- a/pom.xml +++ b/pom.xml @@ -95,7 +95,7 @@ THE SOFTWARE. jenkins-jira 1.7.7 - 2.6.1-SNAPSHOT + 2.7.1-SNAPSHOT ${skipTests} 6 From 69a4969a988f993eebbfecb65c3e1dfb13fcfdb1 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Fri, 17 Oct 2014 07:40:47 -0400 Subject: [PATCH 0013/2573] b105627 failed to move completely away from 1.580. --- plugins/pom.xml | 9 ++++----- pom.xml | 1 - 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/plugins/pom.xml b/plugins/pom.xml index 14e8099395..fba5031f78 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.580 + 1.580.1-SNAPSHOT pom org.jenkins-ci winstone - 2.3 + 2.8 test From e0952e94ea7ae5cdc072a579ad13216df2cfb56c Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Wed, 29 Oct 2014 17:43:29 -0700 Subject: [PATCH 0015/2573] Switch to a released version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b4dc341c62..eaf120d3df 100644 --- a/pom.xml +++ b/pom.xml @@ -172,7 +172,7 @@ THE SOFTWARE. org.jenkins-ci.main remoting - 2.47-SNAPSHOT + 2.47 From 388fa0b44a56cdc1d56596ab5b6415da8e1de04f Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Wed, 29 Oct 2014 21:06:06 -0700 Subject: [PATCH 0016/2573] [maven-release-plugin] prepare release jenkins-1.580.1 --- cli/pom.xml | 2 +- core/pom.xml | 2 +- plugins/pom.xml | 9 +++++---- pom.xml | 3 ++- test/pom.xml | 2 +- war/pom.xml | 2 +- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/cli/pom.xml b/cli/pom.xml index 1246ee67ac..1926e5a75e 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ pom org.jenkins-ci.main - 1.580.1-SNAPSHOT + 1.580.1 cli diff --git a/core/pom.xml b/core/pom.xml index a676e18c9e..8043fe488c 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.580.1-SNAPSHOT + 1.580.1 ../pom.xml diff --git a/plugins/pom.xml b/plugins/pom.xml index fba5031f78..ab79ca6f2e 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.580.1-SNAPSHOT + 1.580.1 pom + + + + + Generates an anchor element with the ability to send POST requests and/or + asynchronous requests. It depends the combination of post and async attributes. + + @since TODO + + Additional CSS classes. + + + Link destination URL. + + + If this must send a POST request. + + + If this must send an asynchronous request. + + + + + + + diff --git a/core/src/main/resources/lib/form/link/link.js b/core/src/main/resources/lib/form/link/link.js new file mode 100644 index 0000000000..bb6e332115 --- /dev/null +++ b/core/src/main/resources/lib/form/link/link.js @@ -0,0 +1,27 @@ +Behaviour.specify('A.post', 'link.post', 0, function(element) { + element.onclick = function(evt) { + var form = document.createElement('form'); + form.setAttribute('method', 'POST'); + form.setAttribute('action', element.getAttribute('href')); + crumb.appendToForm(form); + document.body.appendChild(form); + form.submit(); + return false; + } +}); + +Behaviour.specify('A.post-async', 'link.post-async', 0, function(element) { + element.onclick = function(evt) { + new Ajax.Request(element.getAttribute('href')); + return false; + } +}); + +Behaviour.specify('A.async', 'link.async', 0, function(element) { + element.onclick = function(evt) { + new Ajax.Request(element.getAttribute('href'), { + method : 'get' + }); + return false; + } +}); diff --git a/core/src/main/resources/lib/hudson/queue.jelly b/core/src/main/resources/lib/hudson/queue.jelly index 1b9996a9e5..2a48bf96a8 100644 --- a/core/src/main/resources/lib/hudson/queue.jelly +++ b/core/src/main/resources/lib/hudson/queue.jelly @@ -51,7 +51,7 @@ THE SOFTWARE. ${%Jenkins is going to shut down. No further builds will be performed.} - (${%cancel}) + (${%cancel}) From fff888cc822f235dde8ebdd01152c626e85a12b2 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sun, 28 Sep 2014 18:11:57 +0400 Subject: [PATCH 0025/2573] [FIXED JENKINS-19017] - FileParameter - Handle non-null file parameters as different values The change prevents the issue when Jenkins merges builds with different files coming from one source (It may happen!). Signed-off-by: Oleg Nenashev (cherry picked from commit 7c4f6b7ef433f4a3d85707096f9e5f8b366f232a) --- .../java/hudson/model/FileParameterValue.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/hudson/model/FileParameterValue.java b/core/src/main/java/hudson/model/FileParameterValue.java index c9303fabe5..6669895bc4 100644 --- a/core/src/main/java/hudson/model/FileParameterValue.java +++ b/core/src/main/java/hudson/model/FileParameterValue.java @@ -162,7 +162,8 @@ public class FileParameterValue extends ParameterValue { } /** - * In practice this will always be false, since location should be unique. + * Compares file parameters (existing files will be considered as different). + * Function has been modified in order to avoid JENKINS-19017 issue (wrong merge of builds in the queue). */ @Override public boolean equals(Object obj) { @@ -173,12 +174,13 @@ public class FileParameterValue extends ParameterValue { if (getClass() != obj.getClass()) return false; FileParameterValue other = (FileParameterValue) obj; - if (location == null) { - if (other.location != null) - return false; - } else if (!location.equals(other.location)) - return false; - return true; + + if (location == null && other.location == null) + return true; // Consider null parameters as equal + + //TODO: check fingerprints or checksums to improve the behavior + // Return false even if files are equal + return false; } @Override From be835bfcfb172ecde489ad3598750b7fdc88a965 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 18 Oct 2014 22:03:28 +0400 Subject: [PATCH 0026/2573] [JENKINS-19017] - Unit tests Signed-off-by: Oleg Nenashev (cherry picked from commit cc06ae78e3955746176f64ff3f36d7f0e3cc80ab) --- .../hudson/model/FileParameterValueTest.java | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 core/src/test/java/hudson/model/FileParameterValueTest.java diff --git a/core/src/test/java/hudson/model/FileParameterValueTest.java b/core/src/test/java/hudson/model/FileParameterValueTest.java new file mode 100644 index 0000000000..cd03b68409 --- /dev/null +++ b/core/src/test/java/hudson/model/FileParameterValueTest.java @@ -0,0 +1,64 @@ +/* + * The MIT License + * + * Copyright 2014 Oleg Nenashev . + * + * 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 java.io.File; +import org.junit.Assert; +import org.junit.Test; +import org.jvnet.hudson.test.Issue; + +/** + * Test for {@link FileParameterValue}. + * @author Oleg Nenashev + */ +public class FileParameterValueTest { + + @Issue("JENKINS-19017") + @Test public void compareParamsWithSameName() { + final String paramName = "MY_FILE_PARAM"; // Same paramName (location) reproduces the bug + final FileParameterValue param1 = new FileParameterValue(paramName, new File("ws_param1.txt"), "param1.txt"); + final FileParameterValue param2 = new FileParameterValue(paramName, new File("ws_param2.txt"), "param2.txt"); + + Assert.assertNotEquals("Files with same locations shoud be considered as different", param1, param2); + Assert.assertNotEquals("Files with same locations shoud be considered as different", param2, param1); + } + + @Test public void compareNullParams() { + final String paramName = "MY_FILE_PARAM"; + FileParameterValue nonNullParam = new FileParameterValue(paramName, new File("ws_param1.txt"), "param1.txt"); + FileParameterValue nullParam1 = new FileParameterValue(null, new File("null_param1.txt"), "null_param1.txt"); + FileParameterValue nullParam2 = new FileParameterValue(null, new File("null_param2.txt"), "null_param2.txt"); + + // Combine nulls + Assert.assertEquals(nullParam1, nullParam1); + Assert.assertEquals(nullParam1, nullParam2); + Assert.assertEquals(nullParam2, nullParam1); + Assert.assertEquals(nullParam2, nullParam2); + + // Compare with non-null + Assert.assertNotEquals(nullParam1, nonNullParam); + Assert.assertNotEquals(nonNullParam, nullParam1); + } +} From 8fbd44db2b2ebf81947a6c3c5861bc30b48cc775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Sat, 8 Nov 2014 11:12:30 +0100 Subject: [PATCH 0027/2573] Revert "[FIXED JENKINS-20108]" This reverts commit 68eb26633b1c042d90a426efac7b6e60dd4b2ede. --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index 59610a927c..22f4764fa0 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -117,7 +117,7 @@ THE SOFTWARE. org.jenkins-ci trilead-ssh2 - build217-jenkins-7 + build217-jenkins-5 org.kohsuke.stapler From 0efd811adb89769c8a6180e33e3d06d755bca4b5 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 24 Sep 2014 11:06:00 -0400 Subject: [PATCH 0028/2573] [FIXED JENKINS-22769] ItemListener callbacks should run as SYSTEM since they sometimes do ACL-checked calls. (cherry picked from commit c04cdcd9f717ddcd3e8c9dbe86cb353c14ae511e) Conflicts: changelog.html --- .../hudson/model/listeners/ItemListener.java | 56 ++++++++++++++----- .../test/java/hudson/model/ListViewTest.java | 42 ++++++++++++++ 2 files changed, 83 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/hudson/model/listeners/ItemListener.java b/core/src/main/java/hudson/model/listeners/ItemListener.java index b1787f4b47..91a55c23eb 100644 --- a/core/src/main/java/hudson/model/listeners/ItemListener.java +++ b/core/src/main/java/hudson/model/listeners/ItemListener.java @@ -26,10 +26,10 @@ package hudson.model.listeners; import hudson.ExtensionPoint; import hudson.ExtensionList; import hudson.Extension; -import jenkins.model.Jenkins; import hudson.model.Item; import hudson.model.ItemGroup; import hudson.model.Items; +import hudson.security.ACL; /** * Receives notifications about CRUD operations of {@link Item}. @@ -151,26 +151,45 @@ public class ItemListener implements ExtensionPoint { return ExtensionList.lookup(ItemListener.class); } - public static void fireOnCopied(Item src, Item result) { - for (ItemListener l : all()) - l.onCopied(src,result); + public static void fireOnCopied(final Item src, final Item result) { + ACL.impersonate(ACL.SYSTEM, new Runnable() { + @Override public void run() { + for (ItemListener l : all()) { + l.onCopied(src, result); + } + } + }); } - public static void fireOnCreated(Item item) { - for (ItemListener l : all()) - l.onCreated(item); + public static void fireOnCreated(final Item item) { + ACL.impersonate(ACL.SYSTEM, new Runnable() { + @Override public void run() { + for (ItemListener l : all()) { + l.onCreated(item); + } + } + }); } - public static void fireOnUpdated(Item item) { - for (ItemListener l : all()) - l.onUpdated(item); + public static void fireOnUpdated(final Item item) { + ACL.impersonate(ACL.SYSTEM, new Runnable() { + @Override public void run() { + for (ItemListener l : all()) { + l.onUpdated(item); + } + } + }); } /** @since 1.548 */ - public static void fireOnDeleted(Item item) { - for (ItemListener l : all()) { - l.onDeleted(item); - } + public static void fireOnDeleted(final Item item) { + ACL.impersonate(ACL.SYSTEM, new Runnable() { + @Override public void run() { + for (ItemListener l : all()) { + l.onDeleted(item); + } + } + }); } /** @@ -179,7 +198,14 @@ public class ItemListener implements ExtensionPoint { * @param oldFullName the previous {@link Item#getFullName} * @since 1.548 */ - public static void fireLocationChange(Item rootItem, String oldFullName) { + public static void fireLocationChange(final Item rootItem, final String oldFullName) { + ACL.impersonate(ACL.SYSTEM, new Runnable() { + @Override public void run() { + doFireLocationChange(rootItem, oldFullName); + } + }); + } + private static void doFireLocationChange(Item rootItem, String oldFullName) { String prefix = rootItem.getParent().getFullName(); if (!prefix.isEmpty()) { prefix += '/'; diff --git a/test/src/test/java/hudson/model/ListViewTest.java b/test/src/test/java/hudson/model/ListViewTest.java index 6bcb51715d..a4d9a06049 100644 --- a/test/src/test/java/hudson/model/ListViewTest.java +++ b/test/src/test/java/hudson/model/ListViewTest.java @@ -31,17 +31,23 @@ import hudson.Functions; import hudson.matrix.AxisList; import hudson.matrix.MatrixProject; import hudson.matrix.TextAxis; +import hudson.security.ACL; +import hudson.security.AuthorizationStrategy; +import hudson.security.Permission; import java.io.IOException; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import org.acegisecurity.Authentication; import static org.junit.Assert.*; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Bug; +import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule.WebClient; import org.jvnet.hudson.test.MockFolder; @@ -205,4 +211,40 @@ public class ListViewTest { assertFalse(view.contains(job)); assertFalse(view.jobNamesContains(job)); } + + @Issue("JENKINS-22769") + @Test public void renameJobInViewYouCannotSee() throws Exception { + j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); + j.jenkins.setAuthorizationStrategy(new AllButViewsAuthorizationStrategy()); + final FreeStyleProject p = j.createFreeStyleProject("p1"); + ListView v = new ListView("v", j.jenkins); + v.add(p); + j.jenkins.addView(v); + ACL.impersonate(User.get("alice").impersonate(), new Runnable() { + @Override public void run() { + try { + p.renameTo("p2"); + } catch (IOException x) { + throw new RuntimeException(x); + } + } + }); + assertEquals(Collections.singletonList(p), v.getItems()); + } + private static class AllButViewsAuthorizationStrategy extends AuthorizationStrategy { + @Override public ACL getRootACL() { + return UNSECURED.getRootACL(); + } + @Override public Collection getGroups() { + return Collections.emptyList(); + } + @Override public ACL getACL(View item) { + return new ACL() { + @Override public boolean hasPermission(Authentication a, Permission permission) { + return a.equals(SYSTEM); + } + }; + } + } + } From b70313476a86813417b9197555780622cf5170b8 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Mon, 6 Oct 2014 10:18:16 -0400 Subject: [PATCH 0029/2573] =?UTF-8?q?[JENKINS-21224]=20Defend=20against=20?= =?UTF-8?q?exceptions=20in=20listeners,=20for=20now=20just=20for=20ItemLis?= =?UTF-8?q?tener.=20java.lang.RuntimeException:=20Unable=20to=20copy=20/?= =?UTF-8?q?=E2=80=A6/jobs/=E2=80=A6/config.xml=20=09at=20hudson.plugins.jo?= =?UTF-8?q?bConfigHistory.FileHistoryDao.createNewHistoryEntryAndCopyConfi?= =?UTF-8?q?g(FileHistoryDao.java:252)=20=09at=20hudson.plugins.jobConfigHi?= =?UTF-8?q?story.FileHistoryDao.createNewItem(FileHistoryDao.java:238)=20?= =?UTF-8?q?=09at=20hudson.plugins.jobConfigHistory.JobConfigHistoryJobList?= =?UTF-8?q?ener.onCreated(JobConfigHistoryJobListener.java:31)=20=09at=20h?= =?UTF-8?q?udson.model.listeners.ItemListener.fireOnCreated(ItemListener.j?= =?UTF-8?q?ava:161)=20=09at=20jenkins.model.Jenkins.putItem(Jenkins.java:2?= =?UTF-8?q?483)=20=09at=20=E2=80=A6=20Caused=20by:=20java.io.FileNotFoundE?= =?UTF-8?q?xception:=20/=E2=80=A6/jobs/=E2=80=A6/config.xml=20(No=20such?= =?UTF-8?q?=20file=20or=20directory)=20=09at=20java.io.FileInputStream.ope?= =?UTF-8?q?n(Native=20Method)=20=09at=20java.io.FileInputStream.(Fil?= =?UTF-8?q?eInputStream.java:120)=20=09at=20hudson.plugins.jobConfigHistor?= =?UTF-8?q?y.FileHistoryDao.copyConfigFile(FileHistoryDao.java:178)=20=09a?= =?UTF-8?q?t=20hudson.plugins.jobConfigHistory.FileHistoryDao.createNewHis?= =?UTF-8?q?toryEntryAndCopyConfig(FileHistoryDao.java:250)=20=09...=20108?= =?UTF-8?q?=20more=20(cherry=20picked=20from=20commit=206825121f06d6427304?= =?UTF-8?q?fd5149531216ecae6fdf93)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hudson/model/listeners/ItemListener.java | 107 +++++++++++------- 1 file changed, 69 insertions(+), 38 deletions(-) diff --git a/core/src/main/java/hudson/model/listeners/ItemListener.java b/core/src/main/java/hudson/model/listeners/ItemListener.java index 91a55c23eb..3babd001a9 100644 --- a/core/src/main/java/hudson/model/listeners/ItemListener.java +++ b/core/src/main/java/hudson/model/listeners/ItemListener.java @@ -23,6 +23,7 @@ */ package hudson.model.listeners; +import com.google.common.base.Function; import hudson.ExtensionPoint; import hudson.ExtensionList; import hudson.Extension; @@ -30,6 +31,8 @@ import hudson.model.Item; import hudson.model.ItemGroup; import hudson.model.Items; import hudson.security.ACL; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Receives notifications about CRUD operations of {@link Item}. @@ -38,6 +41,9 @@ import hudson.security.ACL; * @author Kohsuke Kawaguchi */ public class ItemListener implements ExtensionPoint { + + private static final Logger LOGGER = Logger.getLogger(ItemListener.class.getName()); + /** * Called after a new job is created and added to {@link jenkins.model.Jenkins}, * before the initial configuration page is provided. @@ -151,45 +157,61 @@ public class ItemListener implements ExtensionPoint { return ExtensionList.lookup(ItemListener.class); } - public static void fireOnCopied(final Item src, final Item result) { - ACL.impersonate(ACL.SYSTEM, new Runnable() { + // TODO JENKINS-21224 generalize this to a method perhaps in ExtensionList and use consistently from all listeners + private static void forAll(final /* java.util.function.Consumer */Function consumer, boolean asSystem) { + Runnable r = new Runnable() { @Override public void run() { for (ItemListener l : all()) { - l.onCopied(src, result); + try { + consumer.apply(l); + } catch (RuntimeException x) { + LOGGER.log(Level.WARNING, "failed to send event to listener of " + l.getClass(), x); + } } } - }); + }; + if (asSystem) { + ACL.impersonate(ACL.SYSTEM, r); + } else { + r.run(); + } + } + + public static void fireOnCopied(final Item src, final Item result) { + forAll(new Function() { + @Override public Void apply(ItemListener l) { + l.onCopied(src, result); + return null; + } + }, true); } public static void fireOnCreated(final Item item) { - ACL.impersonate(ACL.SYSTEM, new Runnable() { - @Override public void run() { - for (ItemListener l : all()) { - l.onCreated(item); - } + forAll(new Function() { + @Override public Void apply(ItemListener l) { + l.onCreated(item); + return null; } - }); + }, true); } public static void fireOnUpdated(final Item item) { - ACL.impersonate(ACL.SYSTEM, new Runnable() { - @Override public void run() { - for (ItemListener l : all()) { - l.onUpdated(item); - } + forAll(new Function() { + @Override public Void apply(ItemListener l) { + l.onUpdated(item); + return null; } - }); + }, true); } /** @since 1.548 */ public static void fireOnDeleted(final Item item) { - ACL.impersonate(ACL.SYSTEM, new Runnable() { - @Override public void run() { - for (ItemListener l : all()) { - l.onDeleted(item); - } + forAll(new Function() { + @Override public Void apply(ItemListener l) { + l.onDeleted(item); + return null; } - }); + }, true); } /** @@ -205,34 +227,43 @@ public class ItemListener implements ExtensionPoint { } }); } - private static void doFireLocationChange(Item rootItem, String oldFullName) { + private static void doFireLocationChange(final Item rootItem, final String oldFullName) { String prefix = rootItem.getParent().getFullName(); if (!prefix.isEmpty()) { prefix += '/'; } - String newFullName = rootItem.getFullName(); + final String newFullName = rootItem.getFullName(); assert newFullName.startsWith(prefix); int prefixS = prefix.length(); if (oldFullName.startsWith(prefix) && oldFullName.indexOf('/', prefixS) == -1) { - String oldName = oldFullName.substring(prefixS); - String newName = rootItem.getName(); + final String oldName = oldFullName.substring(prefixS); + final String newName = rootItem.getName(); assert newName.equals(newFullName.substring(prefixS)); - for (ItemListener l : all()) { - l.onRenamed(rootItem, oldName, newName); + forAll(new Function() { + @Override public Void apply(ItemListener l) { + l.onRenamed(rootItem, oldName, newName); + return null; + } + }, false); + } + forAll(new Function() { + @Override public Void apply(ItemListener l) { + l.onLocationChanged(rootItem, oldFullName, newFullName); + return null; } - } - for (ItemListener l : all()) { - l.onLocationChanged(rootItem, oldFullName, newFullName); - } + }, false); if (rootItem instanceof ItemGroup) { - for (Item child : Items.getAllItems((ItemGroup) rootItem, Item.class)) { - String childNew = child.getFullName(); + for (final Item child : Items.getAllItems((ItemGroup) rootItem, Item.class)) { + final String childNew = child.getFullName(); assert childNew.startsWith(newFullName); assert childNew.charAt(newFullName.length()) == '/'; - String childOld = oldFullName + childNew.substring(newFullName.length()); - for (ItemListener l : all()) { - l.onLocationChanged(child, childOld, childNew); - } + final String childOld = oldFullName + childNew.substring(newFullName.length()); + forAll(new Function() { + @Override public Void apply(ItemListener l) { + l.onLocationChanged(child, childOld, childNew); + return null; + } + }, false); } } } From 8478e24609d407268bd579609bf0ce3ad395a046 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Tue, 4 Nov 2014 15:36:01 -0500 Subject: [PATCH 0030/2573] [FIXED JENKINS-25400] Rework fix of JENKINS-22769 (c04cdcd) to put the burden on each listener to impersonate ACL.SYSTEM if it needs to. (cherry picked from commit a6a3d5e1660735edc18d331500f7ce9850fbc724) Conflicts: changelog.html --- .../main/java/hudson/model/Fingerprint.java | 10 +++- core/src/main/java/hudson/model/ListView.java | 19 ++++++- .../hudson/model/listeners/ItemListener.java | 50 ++++++++----------- .../main/java/hudson/tasks/BuildTrigger.java | 9 +++- 4 files changed, 54 insertions(+), 34 deletions(-) diff --git a/core/src/main/java/hudson/model/Fingerprint.java b/core/src/main/java/hudson/model/Fingerprint.java index 1dd598c36e..22fac5bb8d 100644 --- a/core/src/main/java/hudson/model/Fingerprint.java +++ b/core/src/main/java/hudson/model/Fingerprint.java @@ -39,6 +39,7 @@ import hudson.BulkChange; import hudson.Extension; import hudson.model.listeners.ItemListener; import hudson.model.listeners.SaveableListener; +import hudson.security.ACL; import hudson.util.AtomicFileWriter; import hudson.util.HexBinaryConverter; import hudson.util.Iterators; @@ -729,7 +730,14 @@ public class Fingerprint implements ModelObject, Saveable { @Extension public static final class ProjectRenameListener extends ItemListener { @Override - public void onLocationChanged(Item item, String oldName, String newName) { + public void onLocationChanged(final Item item, final String oldName, final String newName) { + ACL.impersonate(ACL.SYSTEM, new Runnable() { + @Override public void run() { + locationChanged(item, oldName, newName); + } + }); + } + private void locationChanged(Item item, String oldName, String newName) { if (item instanceof AbstractProject) { AbstractProject p = Jenkins.getInstance().getItemByFullName(newName, AbstractProject.class); if (p != null) { diff --git a/core/src/main/java/hudson/model/ListView.java b/core/src/main/java/hudson/model/ListView.java index 652f69868d..73b63b4915 100644 --- a/core/src/main/java/hudson/model/ListView.java +++ b/core/src/main/java/hudson/model/ListView.java @@ -29,6 +29,7 @@ import hudson.Util; import hudson.diagnosis.OldDataMonitor; import hudson.model.Descriptor.FormException; import hudson.model.listeners.ItemListener; +import hudson.security.ACL; import hudson.util.CaseInsensitiveComparator; import hudson.util.DescribableList; import hudson.util.FormValidation; @@ -431,7 +432,14 @@ public class ListView extends View implements DirectlyModifiableView { @Restricted(NoExternalUse.class) @Extension public static final class Listener extends ItemListener { - @Override public void onLocationChanged(Item item, String oldFullName, String newFullName) { + @Override public void onLocationChanged(final Item item, final String oldFullName, final String newFullName) { + ACL.impersonate(ACL.SYSTEM, new Runnable() { + @Override public void run() { + locationChanged(item, oldFullName, newFullName); + } + }); + } + private void locationChanged(Item item, String oldFullName, String newFullName) { final Jenkins jenkins = Jenkins.getInstance(); for (View view: jenkins.getViews()) { if (view instanceof ListView) { @@ -469,7 +477,14 @@ public class ListView extends View implements DirectlyModifiableView { } } - @Override public void onDeleted(Item item) { + @Override public void onDeleted(final Item item) { + ACL.impersonate(ACL.SYSTEM, new Runnable() { + @Override public void run() { + deleted(item); + } + }); + } + private void deleted(Item item) { final Jenkins jenkins = Jenkins.getInstance(); for (View view: jenkins.getViews()) { if (view instanceof ListView) { diff --git a/core/src/main/java/hudson/model/listeners/ItemListener.java b/core/src/main/java/hudson/model/listeners/ItemListener.java index 3babd001a9..4f3d235f51 100644 --- a/core/src/main/java/hudson/model/listeners/ItemListener.java +++ b/core/src/main/java/hudson/model/listeners/ItemListener.java @@ -31,8 +31,10 @@ import hudson.model.Item; import hudson.model.ItemGroup; import hudson.model.Items; import hudson.security.ACL; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import jenkins.security.NotReallyRoleSensitiveCallable; /** * Receives notifications about CRUD operations of {@link Item}. @@ -158,22 +160,13 @@ public class ItemListener implements ExtensionPoint { } // TODO JENKINS-21224 generalize this to a method perhaps in ExtensionList and use consistently from all listeners - private static void forAll(final /* java.util.function.Consumer */Function consumer, boolean asSystem) { - Runnable r = new Runnable() { - @Override public void run() { - for (ItemListener l : all()) { - try { - consumer.apply(l); - } catch (RuntimeException x) { - LOGGER.log(Level.WARNING, "failed to send event to listener of " + l.getClass(), x); - } - } + private static void forAll(final /* java.util.function.Consumer */Function consumer) { + for (ItemListener l : all()) { + try { + consumer.apply(l); + } catch (RuntimeException x) { + LOGGER.log(Level.WARNING, "failed to send event to listener of " + l.getClass(), x); } - }; - if (asSystem) { - ACL.impersonate(ACL.SYSTEM, r); - } else { - r.run(); } } @@ -183,7 +176,7 @@ public class ItemListener implements ExtensionPoint { l.onCopied(src, result); return null; } - }, true); + }); } public static void fireOnCreated(final Item item) { @@ -192,7 +185,7 @@ public class ItemListener implements ExtensionPoint { l.onCreated(item); return null; } - }, true); + }); } public static void fireOnUpdated(final Item item) { @@ -201,7 +194,7 @@ public class ItemListener implements ExtensionPoint { l.onUpdated(item); return null; } - }, true); + }); } /** @since 1.548 */ @@ -211,7 +204,7 @@ public class ItemListener implements ExtensionPoint { l.onDeleted(item); return null; } - }, true); + }); } /** @@ -221,13 +214,6 @@ public class ItemListener implements ExtensionPoint { * @since 1.548 */ public static void fireLocationChange(final Item rootItem, final String oldFullName) { - ACL.impersonate(ACL.SYSTEM, new Runnable() { - @Override public void run() { - doFireLocationChange(rootItem, oldFullName); - } - }); - } - private static void doFireLocationChange(final Item rootItem, final String oldFullName) { String prefix = rootItem.getParent().getFullName(); if (!prefix.isEmpty()) { prefix += '/'; @@ -244,16 +230,20 @@ public class ItemListener implements ExtensionPoint { l.onRenamed(rootItem, oldName, newName); return null; } - }, false); + }); } forAll(new Function() { @Override public Void apply(ItemListener l) { l.onLocationChanged(rootItem, oldFullName, newFullName); return null; } - }, false); + }); if (rootItem instanceof ItemGroup) { - for (final Item child : Items.getAllItems((ItemGroup) rootItem, Item.class)) { + for (final Item child : ACL.impersonate(ACL.SYSTEM, new NotReallyRoleSensitiveCallable,RuntimeException>() { + @Override public List call() { + return Items.getAllItems((ItemGroup) rootItem, Item.class); + } + })) { final String childNew = child.getFullName(); assert childNew.startsWith(newFullName); assert childNew.charAt(newFullName.length()) == '/'; @@ -263,7 +253,7 @@ public class ItemListener implements ExtensionPoint { l.onLocationChanged(child, childOld, childNew); return null; } - }, false); + }); } } } diff --git a/core/src/main/java/hudson/tasks/BuildTrigger.java b/core/src/main/java/hudson/tasks/BuildTrigger.java index 40533373fd..ee121ca195 100644 --- a/core/src/main/java/hudson/tasks/BuildTrigger.java +++ b/core/src/main/java/hudson/tasks/BuildTrigger.java @@ -406,7 +406,14 @@ public class BuildTrigger extends Recorder implements DependencyDeclarer { @Extension public static class ItemListenerImpl extends ItemListener { @Override - public void onLocationChanged(Item item, String oldFullName, String newFullName) { + public void onLocationChanged(final Item item, final String oldFullName, final String newFullName) { + ACL.impersonate(ACL.SYSTEM, new Runnable() { + @Override public void run() { + locationChanged(item, oldFullName, newFullName); + } + }); + } + private void locationChanged(Item item, String oldFullName, String newFullName) { // update BuildTrigger of other projects that point to this object. // can't we generalize this? for( Project p : Jenkins.getInstance().getAllItems(Project.class) ) { From 03600e925c3d674b204981a140031a4ae3571609 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Mon, 15 Dec 2014 11:15:16 -0800 Subject: [PATCH 0031/2573] [maven-release-plugin] prepare release jenkins-1.580.2 --- 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 43e07fb442..8c397c0667 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ pom org.jenkins-ci.main - 1.580.2-SNAPSHOT + 1.580.2 cli diff --git a/core/pom.xml b/core/pom.xml index 22f4764fa0..adbec441ff 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.580.2-SNAPSHOT + 1.580.2 ../pom.xml diff --git a/plugins/pom.xml b/plugins/pom.xml index 5aacf0d292..c088374650 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.580.2-SNAPSHOT + 1.580.2 pom - + + ${buildHealth.score} @@ -74,7 +75,7 @@ THE SOFTWARE. - + From cca17cc4f6106304c954a0bf3942ad0d7be4c7e6 Mon Sep 17 00:00:00 2001 From: N Nachiappan Date: Fri, 24 Oct 2014 14:06:42 -0700 Subject: [PATCH 0035/2573] [FIXED JENKINS-25473] move config file check as part of loading job to do it in multithread fashion than in a single thread (cherry picked from commit dc547cf2974365a6b355de9981b7183f3d4fc17f) --- core/src/main/java/jenkins/model/Jenkins.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index ffd693e6fd..ec73d6a6e5 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -2603,11 +2603,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve throw new IOException(projectsDir+" is not a directory"); throw new IOException("Unable to create "+projectsDir+"\nPermission issue? Please create this directory manually."); } - File[] subdirs = projectsDir.listFiles(new FileFilter() { - public boolean accept(File child) { - return child.isDirectory() && Items.getConfigFile(child).exists(); - } - }); + File[] subdirs = projectsDir.listFiles(); final Set loadedNames = Collections.synchronizedSet(new HashSet()); @@ -2653,6 +2649,10 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve for (final File subdir : subdirs) { g.requires(loadHudson).attains(JOB_LOADED).notFatal().add("Loading job "+subdir.getName(),new Executable() { public void run(Reactor session) throws Exception { + if(!Items.getConfigFile(subdir).exists()) { + //Does not have job config file, so it is not a jenkins job hence skip it + return; + } TopLevelItem item = (TopLevelItem) Items.load(Jenkins.this, subdir); items.put(item.getName(), item); loadedNames.add(item.getName()); From 7169a3916528ac95eada2cf13e3fbd7e50ae6387 Mon Sep 17 00:00:00 2001 From: Christof Schoell Date: Tue, 14 Oct 2014 18:00:10 +0200 Subject: [PATCH 0036/2573] [JENKINS-25144] return authentication object instead of null if authentication is not required - otherwise valid login fails with basic authentication (cherry picked from commit 0176b6d902faeec7bff63eb34ce16e2f70062035) --- .../security/BasicHeaderRealPasswordAuthenticator.java | 2 +- .../java/jenkins/security/BasicHeaderProcessorTest.java | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/jenkins/security/BasicHeaderRealPasswordAuthenticator.java b/core/src/main/java/jenkins/security/BasicHeaderRealPasswordAuthenticator.java index 4d3e5554e0..1e640014ef 100644 --- a/core/src/main/java/jenkins/security/BasicHeaderRealPasswordAuthenticator.java +++ b/core/src/main/java/jenkins/security/BasicHeaderRealPasswordAuthenticator.java @@ -50,7 +50,7 @@ public class BasicHeaderRealPasswordAuthenticator extends BasicHeaderAuthenticat return null; if (!authenticationIsRequired(username)) - return null; + return SecurityContextHolder.getContext().getAuthentication(); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); diff --git a/test/src/test/java/jenkins/security/BasicHeaderProcessorTest.java b/test/src/test/java/jenkins/security/BasicHeaderProcessorTest.java index 803767f9a4..c11726fd93 100644 --- a/test/src/test/java/jenkins/security/BasicHeaderProcessorTest.java +++ b/test/src/test/java/jenkins/security/BasicHeaderProcessorTest.java @@ -56,10 +56,15 @@ public class BasicHeaderProcessorTest extends Assert { // call with incorrect password makeRequestAndFail("foo:bar"); - // if the session cookie is valid, then basic header won't be needed + wc.login("bar"); + + // if the session cookie is valid, then basic header won't be needed makeRequestWithAuthAndVerify(null, "bar"); + // if the session cookie is valid, and basic header is set anyway login should not fail either + makeRequestWithAuthAndVerify("bar:bar", "bar"); + // but if the password is incorrect, it should fail, instead of silently logging in as the user indicated by session makeRequestAndFail("foo:bar"); } From be34b675f0f9cb59a67c09dbe42364d34c3eaff1 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Fri, 7 Nov 2014 09:40:07 -0800 Subject: [PATCH 0037/2573] [FIXED JENKINS-25144] Revisiting the attempted fix in the previous commit. IIUC, the issue here is that the request in question contains both a valid session cookie AND basic authentication header, and that path results in a failure because BasicHeaderProcessor expects one of BasicHeaderAuthenticators to validate the basic authentication header (without knowing that there's already a valid Authentication object that came from the HTTP session, yet no BasicHeaderAuthenticator actually processes this because BasicHeaderRealPasswordAuthenticator backs away from doing that. I think the corect fix is for BasicHeaderRealPasswordAuthenticator to get rid of authenticationIsRequired check. This check instead belongs to BasicHeaderProcessor, where it should be used to check if any BasicHeaderAuthenticator should be consulted or not. The problem with having this logic in BasicHeaderRealPasswordAuthenticator is that this is just an implementation of an extension point, and thus it needs to be removable. As it stands right now in this fix, if this impl is removed, JENKINS-25144 will be back again. (cherry picked from commit 9e81b8e4feebceef94d117b757952c965bf91c61) --- .../security/BasicHeaderProcessor.java | 47 ++++++++++++++++++- .../BasicHeaderRealPasswordAuthenticator.java | 36 -------------- 2 files changed, 46 insertions(+), 37 deletions(-) diff --git a/core/src/main/java/jenkins/security/BasicHeaderProcessor.java b/core/src/main/java/jenkins/security/BasicHeaderProcessor.java index 60d217a67e..6bec1a2e4a 100644 --- a/core/src/main/java/jenkins/security/BasicHeaderProcessor.java +++ b/core/src/main/java/jenkins/security/BasicHeaderProcessor.java @@ -1,12 +1,14 @@ package jenkins.security; import hudson.security.ACL; +import hudson.security.SecurityRealm; import hudson.util.Scrambler; import org.acegisecurity.Authentication; -import org.acegisecurity.AuthenticationManager; import org.acegisecurity.BadCredentialsException; import org.acegisecurity.context.SecurityContext; import org.acegisecurity.context.SecurityContextHolder; +import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; +import org.acegisecurity.providers.anonymous.AnonymousAuthenticationToken; import org.acegisecurity.ui.AuthenticationEntryPoint; import org.acegisecurity.ui.rememberme.NullRememberMeServices; import org.acegisecurity.ui.rememberme.RememberMeServices; @@ -67,6 +69,11 @@ public class BasicHeaderProcessor implements Filter { String username = uidpassword.substring(0, idx); String password = uidpassword.substring(idx+1); + if (!authenticationIsRequired(username)) { + chain.doFilter(request, response); + return; + } + for (BasicHeaderAuthenticator a : all()) { LOGGER.log(FINER, "Attempting to authenticate with {0}", a); Authentication auth = a.authenticate(req, rsp, username, password); @@ -87,6 +94,44 @@ public class BasicHeaderProcessor implements Filter { } } + /** + * If the request is already authenticated to the same user that the Authorization header claims, + * for example through the HTTP session, then there's no need to re-authenticate the Authorization header, + * so we skip that. This avoids stressing {@link SecurityRealm}. + * + * This method returns false if we can take this short-cut. + */ + // taken from BasicProcessingFilter.java + protected boolean authenticationIsRequired(String username) { + // Only reauthenticate if username doesn't match SecurityContextHolder and user isn't authenticated + // (see SEC-53) + Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication(); + + if(existingAuth == null || !existingAuth.isAuthenticated()) { + return true; + } + + // Limit username comparison to providers which use usernames (ie UsernamePasswordAuthenticationToken) + // (see SEC-348) + + if (existingAuth instanceof UsernamePasswordAuthenticationToken && !existingAuth.getName().equals(username)) { + return true; + } + + // Handle unusual condition where an AnonymousAuthenticationToken is already present + // This shouldn't happen very often, as BasicProcessingFitler is meant to be earlier in the filter + // chain than AnonymousProcessingFilter. Nevertheless, presence of both an AnonymousAuthenticationToken + // together with a BASIC authentication request header should indicate reauthentication using the + // BASIC protocol is desirable. This behaviour is also consistent with that provided by form and digest, + // both of which force re-authentication if the respective header is detected (and in doing so replace + // any existing AnonymousAuthenticationToken). See SEC-610. + if (existingAuth instanceof AnonymousAuthenticationToken) { + return true; + } + + return false; + } + protected void success(HttpServletRequest req, HttpServletResponse rsp, FilterChain chain, Authentication auth) throws IOException, ServletException { rememberMeServices.loginSuccess(req, rsp, auth); diff --git a/core/src/main/java/jenkins/security/BasicHeaderRealPasswordAuthenticator.java b/core/src/main/java/jenkins/security/BasicHeaderRealPasswordAuthenticator.java index 1e640014ef..3b41c006dd 100644 --- a/core/src/main/java/jenkins/security/BasicHeaderRealPasswordAuthenticator.java +++ b/core/src/main/java/jenkins/security/BasicHeaderRealPasswordAuthenticator.java @@ -19,9 +19,7 @@ import jenkins.ExtensionFilter; import jenkins.model.Jenkins; import org.acegisecurity.Authentication; import org.acegisecurity.AuthenticationException; -import org.acegisecurity.context.SecurityContextHolder; import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; -import org.acegisecurity.providers.anonymous.AnonymousAuthenticationToken; import org.acegisecurity.ui.AuthenticationDetailsSource; import org.acegisecurity.ui.AuthenticationDetailsSourceImpl; @@ -49,9 +47,6 @@ public class BasicHeaderRealPasswordAuthenticator extends BasicHeaderAuthenticat if (DISABLE) return null; - if (!authenticationIsRequired(username)) - return SecurityContextHolder.getContext().getAuthentication(); - UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); authRequest.setDetails(authenticationDetailsSource.buildDetails(req)); @@ -68,37 +63,6 @@ public class BasicHeaderRealPasswordAuthenticator extends BasicHeaderAuthenticat } } - // taken from BasicProcessingFilter.java - protected boolean authenticationIsRequired(String username) { - // Only reauthenticate if username doesn't match SecurityContextHolder and user isn't authenticated - // (see SEC-53) - Authentication existingAuth = SecurityContextHolder.getContext().getAuthentication(); - - if(existingAuth == null || !existingAuth.isAuthenticated()) { - return true; - } - - // Limit username comparison to providers which use usernames (ie UsernamePasswordAuthenticationToken) - // (see SEC-348) - - if (existingAuth instanceof UsernamePasswordAuthenticationToken && !existingAuth.getName().equals(username)) { - return true; - } - - // Handle unusual condition where an AnonymousAuthenticationToken is already present - // This shouldn't happen very often, as BasicProcessingFitler is meant to be earlier in the filter - // chain than AnonymousProcessingFilter. Nevertheless, presence of both an AnonymousAuthenticationToken - // together with a BASIC authentication request header should indicate reauthentication using the - // BASIC protocol is desirable. This behaviour is also consistent with that provided by form and digest, - // both of which force re-authentication if the respective header is detected (and in doing so replace - // any existing AnonymousAuthenticationToken). See SEC-610. - if (existingAuth instanceof AnonymousAuthenticationToken) { - return true; - } - - return false; - } - private static final Logger LOGGER = Logger.getLogger(BasicHeaderRealPasswordAuthenticator.class.getName()); /** From bd0453fe98e33cd99df9920c822210e49ad5cb6e Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Mon, 17 Nov 2014 17:48:48 -0500 Subject: [PATCH 0038/2573] [FIXED JENKINS-25655] Incorrect caching from entrySet sometimes caused incorrect results. Caused a failure in hudson.plugins.promoted_builds.conditions.ManualConditionTest.testManualPromotionProcessViaWebClient when run against 1.580.1. (cherry picked from commit b76e7bf9988ebf5b3b7e2c5e588d5ce6dbde957e) --- .../java/jenkins/model/lazy/AbstractLazyLoadRunMap.java | 4 ++++ .../java/jenkins/model/lazy/LazyLoadRunMapEntrySet.java | 4 ++++ .../jenkins/model/lazy/AbstractLazyLoadRunMapTest.java | 7 +++++++ 3 files changed, 15 insertions(+) diff --git a/core/src/main/java/jenkins/model/lazy/AbstractLazyLoadRunMap.java b/core/src/main/java/jenkins/model/lazy/AbstractLazyLoadRunMap.java index 33ba98c598..f299d598d0 100644 --- a/core/src/main/java/jenkins/model/lazy/AbstractLazyLoadRunMap.java +++ b/core/src/main/java/jenkins/model/lazy/AbstractLazyLoadRunMap.java @@ -585,6 +585,8 @@ public abstract class AbstractLazyLoadRunMap extends AbstractMap i numberOnDisk = a; } + entrySet.clearCache(); + return unwrap(old); } @@ -742,6 +744,8 @@ public abstract class AbstractLazyLoadRunMap extends AbstractMap i BuildReference old = copy.byId.remove(getIdOf(run)); this.index = copy; + entrySet.clearCache(); + return unwrap(old)!=null; } diff --git a/core/src/main/java/jenkins/model/lazy/LazyLoadRunMapEntrySet.java b/core/src/main/java/jenkins/model/lazy/LazyLoadRunMapEntrySet.java index b3910b51ae..48aada93e0 100644 --- a/core/src/main/java/jenkins/model/lazy/LazyLoadRunMapEntrySet.java +++ b/core/src/main/java/jenkins/model/lazy/LazyLoadRunMapEntrySet.java @@ -32,6 +32,10 @@ class LazyLoadRunMapEntrySet extends AbstractSet> { return all; } + synchronized void clearCache() { + all = null; + } + @Override public int size() { return all().size(); diff --git a/core/src/test/java/jenkins/model/lazy/AbstractLazyLoadRunMapTest.java b/core/src/test/java/jenkins/model/lazy/AbstractLazyLoadRunMapTest.java index 55bd0bdfde..6cb55b6e7d 100644 --- a/core/src/test/java/jenkins/model/lazy/AbstractLazyLoadRunMapTest.java +++ b/core/src/test/java/jenkins/model/lazy/AbstractLazyLoadRunMapTest.java @@ -414,6 +414,13 @@ public class AbstractLazyLoadRunMapTest extends Assert { assertEquals(0, b.entrySet().size()); } + @Issue("JENKINS-25655") + @Test public void entrySetChanges() { + assertEquals(3, a.entrySet().size()); + a.put(new Build(7, "D")); + assertEquals(4, a.entrySet().size()); + } + @Issue("JENKINS-18065") @Test public void entrySetContains() { From 23e0d6ad1964e0efdd1e0f1c90360321acc8a073 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Mon, 24 Nov 2014 10:37:58 -0500 Subject: [PATCH 0039/2573] [FIXED JENKINS-25759] Avoid consuming too much memory while running validateAntFileMask. Not fully solved, since the scannedDirs field can still grow to be large, but at least clearing files/dirsNotIncluded. Also imposing a 5s timeout on the scan regardless of file count, and defining a user-customizable bound. (cherry picked from commit 534328b264f9338e48418d2bcc0d28daaf48b3a0) Conflicts: changelog.html --- core/src/main/java/hudson/FilePath.java | 18 +++++++++++++++--- .../java/hudson/tasks/ArtifactArchiver.java | 2 +- .../java/hudson/util/FormFieldValidator.java | 2 +- core/src/test/java/hudson/FilePathTest.java | 5 ++++- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index 1fcb6a5763..b39d036231 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -2236,11 +2236,18 @@ public final class FilePath implements Serializable { * null if no error was found. Otherwise returns a human readable error message. * @since 1.90 * @see #validateFileMask(FilePath, String) + * @deprecated use {@link #validateAntFileMask(String, int)} instead */ public String validateAntFileMask(final String fileMasks) throws IOException, InterruptedException { return validateAntFileMask(fileMasks, Integer.MAX_VALUE); } + /** + * Default bound for {@link #validateAntFileMask(String, int)}. + * @since 1.592 + */ + public static int VALIDATE_ANT_FILE_MASK_BOUND = Integer.getInteger(FilePath.class.getName() + ".VALIDATE_ANT_FILE_MASK_BOUND", 10000); + /** * Like {@link #validateAntFileMask(String)} but performing only a bounded number of operations. *

Whereas the unbounded overload is appropriate for calling from cancelable, long-running tasks such as build steps, @@ -2250,7 +2257,7 @@ public final class FilePath implements Serializable { * A message is returned in case the file pattern can definitely be determined to not match anything in the directory within the alloted time. * If the time runs out without finding a match but without ruling out the possibility that there might be one, {@link InterruptedException} is thrown, * in which case the calling code should give the user the benefit of the doubt and use {@link hudson.util.FormValidation.Kind#OK} (with or without a message). - * @param bound a maximum number of negative operations (deliberately left vague) to perform before giving up on a precise answer; 10_000 is a reasonable pick + * @param bound a maximum number of negative operations (deliberately left vague) to perform before giving up on a precise answer; try {@link #VALIDATE_ANT_FILE_MASK_BOUND} * @throws InterruptedException not only in case of a channel failure, but also if too many operations were performed without finding any matches * @since 1.484 */ @@ -2358,10 +2365,15 @@ public final class FilePath implements Serializable { class Cancel extends RuntimeException {} DirectoryScanner ds = bound == Integer.MAX_VALUE ? new DirectoryScanner() : new DirectoryScanner() { int ticks; + long start = System.currentTimeMillis(); @Override public synchronized boolean isCaseSensitive() { - if (!filesIncluded.isEmpty() || !dirsIncluded.isEmpty() || ticks++ > bound) { + if (!filesIncluded.isEmpty() || !dirsIncluded.isEmpty() || ticks++ > bound || System.currentTimeMillis() - start > 5000) { throw new Cancel(); } + filesNotIncluded.clear(); + dirsNotIncluded.clear(); + // notFollowedSymlinks might be large, but probably unusual + // scannedDirs will typically be largish, but seems to be needed return super.isCaseSensitive(); } }; @@ -2424,7 +2436,7 @@ public final class FilePath implements Serializable { if(!exists()) // no workspace. can't check return FormValidation.ok(); - String msg = validateAntFileMask(value, 10000); + String msg = validateAntFileMask(value, VALIDATE_ANT_FILE_MASK_BOUND); if(errorIfNotExist) return FormValidation.error(msg); else return FormValidation.warning(msg); } catch (InterruptedException e) { diff --git a/core/src/main/java/hudson/tasks/ArtifactArchiver.java b/core/src/main/java/hudson/tasks/ArtifactArchiver.java index 43839ce936..383481f93d 100644 --- a/core/src/main/java/hudson/tasks/ArtifactArchiver.java +++ b/core/src/main/java/hudson/tasks/ArtifactArchiver.java @@ -227,7 +227,7 @@ public class ArtifactArchiver extends Recorder implements SimpleBuildStep { listenerWarnOrError(listener, Messages.ArtifactArchiver_NoMatchFound(artifacts)); String msg = null; try { - msg = ws.validateAntFileMask(artifacts); + msg = ws.validateAntFileMask(artifacts, FilePath.VALIDATE_ANT_FILE_MASK_BOUND); } catch (Exception e) { listenerWarnOrError(listener, e.getMessage()); } diff --git a/core/src/main/java/hudson/util/FormFieldValidator.java b/core/src/main/java/hudson/util/FormFieldValidator.java index 9558090186..d344dd43d5 100644 --- a/core/src/main/java/hudson/util/FormFieldValidator.java +++ b/core/src/main/java/hudson/util/FormFieldValidator.java @@ -378,7 +378,7 @@ public abstract class FormFieldValidator { return; } - String msg = ws.validateAntFileMask(value, 10000); + String msg = ws.validateAntFileMask(value, FilePath.VALIDATE_ANT_FILE_MASK_BOUND); if(errorIfNotExist) error(msg); else warning(msg); } catch (InterruptedException e) { diff --git a/core/src/test/java/hudson/FilePathTest.java b/core/src/test/java/hudson/FilePathTest.java index 529fcd937e..3fe2788f20 100644 --- a/core/src/test/java/hudson/FilePathTest.java +++ b/core/src/test/java/hudson/FilePathTest.java @@ -56,6 +56,7 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; +import org.jvnet.hudson.test.Issue; import static org.mockito.Mockito.*; @@ -496,11 +497,13 @@ public class FilePathTest extends ChannelTestCase { } } + @SuppressWarnings("deprecation") private static void assertValidateAntFileMask(String expected, FilePath d, String fileMasks) throws Exception { assertEquals(expected, d.validateAntFileMask(fileMasks)); } - @Bug(7214) + @Issue("JENKINS-7214") + @SuppressWarnings("deprecation") public void testValidateAntFileMaskBounded() throws Exception { File tmp = Util.createTempDir(); try { From 5e02457709e72c1577cf9a6a52a6bd9450acd590 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Fri, 5 Dec 2014 11:32:51 -0500 Subject: [PATCH 0040/2573] Misleading error message. (cherry picked from commit e4c5c7104206536c80379ce18ec640f56b7dba74) --- .../main/java/jenkins/security/DefaultConfidentialStore.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/jenkins/security/DefaultConfidentialStore.java b/core/src/main/java/jenkins/security/DefaultConfidentialStore.java index 88eb84fc1c..989769b32a 100644 --- a/core/src/main/java/jenkins/security/DefaultConfidentialStore.java +++ b/core/src/main/java/jenkins/security/DefaultConfidentialStore.java @@ -106,7 +106,7 @@ public class DefaultConfidentialStore extends ConfidentialStore { byte[] bytes = IOUtils.toByteArray(cis); return verifyMagic(bytes); } catch (GeneralSecurityException e) { - throw new IOException("Failed to persist the key: "+key.getId(),e); + throw new IOException("Failed to load the key: "+key.getId(),e); } finally { IOUtils.closeQuietly(cis); IOUtils.closeQuietly(fis); From 5ded56a8288dfcfb9e389ea85edc13cf49981a2a Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Fri, 5 Dec 2014 12:07:50 -0500 Subject: [PATCH 0041/2573] [FIXED JENKINS-25937] Treat BadPaddingException as an unloadable key and continue. (cherry picked from commit 6318b8d800abdf8b280f4e1b8ce8bf22e49242ad) Conflicts: changelog.html --- .../java/jenkins/security/DefaultConfidentialStore.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/src/main/java/jenkins/security/DefaultConfidentialStore.java b/core/src/main/java/jenkins/security/DefaultConfidentialStore.java index 989769b32a..7821f492fd 100644 --- a/core/src/main/java/jenkins/security/DefaultConfidentialStore.java +++ b/core/src/main/java/jenkins/security/DefaultConfidentialStore.java @@ -16,6 +16,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.SecureRandom; +import javax.crypto.BadPaddingException; import org.apache.commons.io.IOUtils; /** @@ -107,6 +108,12 @@ public class DefaultConfidentialStore extends ConfidentialStore { return verifyMagic(bytes); } catch (GeneralSecurityException e) { throw new IOException("Failed to load the key: "+key.getId(),e); + } catch (IOException x) { + if (x.getCause() instanceof BadPaddingException) { + return null; // broken somehow + } else { + throw x; + } } finally { IOUtils.closeQuietly(cis); IOUtils.closeQuietly(fis); From ca561319fda4aeaa461ca9fe251d9bad74e71cfa Mon Sep 17 00:00:00 2001 From: ikedam Date: Sat, 3 Jan 2015 13:03:45 +0900 Subject: [PATCH 0042/2573] [FIXED JENKINS-26270] Added "lastCompletedBuild" to permalinks. --- .../java/hudson/model/PermalinkProjectAction.java | 14 ++++++++++++++ .../resources/hudson/model/Messages.properties | 1 + .../resources/hudson/model/Messages_ja.properties | 1 + 3 files changed, 16 insertions(+) diff --git a/core/src/main/java/hudson/model/PermalinkProjectAction.java b/core/src/main/java/hudson/model/PermalinkProjectAction.java index 60e38d3cd2..38e561a982 100644 --- a/core/src/main/java/hudson/model/PermalinkProjectAction.java +++ b/core/src/main/java/hudson/model/PermalinkProjectAction.java @@ -178,6 +178,19 @@ public interface PermalinkProjectAction extends Action { return !run.isBuilding() && run.getResult()!=Result.SUCCESS; } }; + public static final Permalink LAST_COMPLETED_BUILD = new Permalink() { + public String getDisplayName() { + return Messages.Permalink_LastCompletedBuild(); + } + + public String getId() { + return "lastCompletedBuild"; + } + + public Run resolve(Job job) { + return job.getLastCompletedBuild(); + } + }; static { BUILTIN.add(LAST_BUILD); @@ -186,6 +199,7 @@ public interface PermalinkProjectAction extends Action { BUILTIN.add(LAST_FAILED_BUILD); BUILTIN.add(LAST_UNSTABLE_BUILD); BUILTIN.add(LAST_UNSUCCESSFUL_BUILD); + BUILTIN.add(LAST_COMPLETED_BUILD); } } } diff --git a/core/src/main/resources/hudson/model/Messages.properties b/core/src/main/resources/hudson/model/Messages.properties index 1f68d066dc..f544acdaeb 100644 --- a/core/src/main/resources/hudson/model/Messages.properties +++ b/core/src/main/resources/hudson/model/Messages.properties @@ -299,6 +299,7 @@ Permalink.LastUnstableBuild=Last unstable build Permalink.LastUnsuccessfulBuild=Last unsuccessful build Permalink.LastSuccessfulBuild=Last successful build Permalink.LastFailedBuild=Last failed build +Permalink.LastCompletedBuild=Last completed build ParameterAction.DisplayName=Parameters ParametersDefinitionProperty.DisplayName=Parameters diff --git a/core/src/main/resources/hudson/model/Messages_ja.properties b/core/src/main/resources/hudson/model/Messages_ja.properties index f47d7cb685..6f150801a2 100644 --- a/core/src/main/resources/hudson/model/Messages_ja.properties +++ b/core/src/main/resources/hudson/model/Messages_ja.properties @@ -272,6 +272,7 @@ Permalink.LastUnstableBuild=\u6700\u65b0\u306e\u4e0d\u5b89\u5b9a\u30d3\u30eb\u30 Permalink.LastUnsuccessfulBuild=\u6700\u65b0\u306e\u4e0d\u6210\u529f\u30d3\u30eb\u30c9 Permalink.LastSuccessfulBuild=\u6700\u65b0\u306e\u6210\u529f\u30d3\u30eb\u30c9 Permalink.LastFailedBuild=\u6700\u65b0\u306e\u5931\u6557\u30d3\u30eb\u30c9 +Permalink.LastCompletedBuild=\u6700\u65b0\u306e\u5b8c\u4e86\u30d3\u30eb\u30c9 ParameterAction.DisplayName=\u30d1\u30e9\u30e1\u30fc\u30bf From ea6baf9a103b841ec99dd1c2a9aac85fe6d8d29f Mon Sep 17 00:00:00 2001 From: Richard Mortimer Date: Fri, 15 Aug 2014 20:28:44 +0100 Subject: [PATCH 0043/2573] [FIXES JENKINS-24272] jnlp slaves fail to reconnect when master is restarted During master restart only attempt to reconnect the slave after the master has finished restarting. (cherry picked from commit 48e19c58f9e2caa998d0942417d58679f5ce47f0) --- .../jenkins/slaves/restarter/JnlpSlaveRestarterInstaller.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/jenkins/slaves/restarter/JnlpSlaveRestarterInstaller.java b/core/src/main/java/jenkins/slaves/restarter/JnlpSlaveRestarterInstaller.java index aee8ffcd45..61e21c4b18 100644 --- a/core/src/main/java/jenkins/slaves/restarter/JnlpSlaveRestarterInstaller.java +++ b/core/src/main/java/jenkins/slaves/restarter/JnlpSlaveRestarterInstaller.java @@ -69,7 +69,7 @@ public class JnlpSlaveRestarterInstaller extends ComputerListener implements Ser e.addListener(new EngineListenerAdapter() { @Override - public void onDisconnect() { + public void onReconnect() { try { for (SlaveRestarter r : restarters) { try { From 23152a6da4212b65398650faed91146364343b2f Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Tue, 9 Dec 2014 15:07:15 -0500 Subject: [PATCH 0044/2573] For RunMapTest to be Groovy was pointless and aggravating. (cherry picked from commit 30f00b111ad7e6ef689ae018969b2b9dc5ce1571) --- .../groovy/hudson/model/RunMapTest.groovy | 74 ------------------- .../test/java/hudson/model/RunMapTest.java | 74 +++++++++++++++++++ 2 files changed, 74 insertions(+), 74 deletions(-) delete mode 100644 test/src/test/groovy/hudson/model/RunMapTest.groovy create mode 100644 test/src/test/java/hudson/model/RunMapTest.java diff --git a/test/src/test/groovy/hudson/model/RunMapTest.groovy b/test/src/test/groovy/hudson/model/RunMapTest.groovy deleted file mode 100644 index 63529cf668..0000000000 --- a/test/src/test/groovy/hudson/model/RunMapTest.groovy +++ /dev/null @@ -1,74 +0,0 @@ -package hudson.model - -import org.jvnet.hudson.test.Bug -import org.jvnet.hudson.test.HudsonTestCase -import org.jvnet.hudson.test.SleepBuilder -import org.jvnet.hudson.test.TestEnvironment - -import javax.xml.transform.stream.StreamSource - -/** - * - * - * @author Kohsuke Kawaguchi - */ -class RunMapTest extends HudsonTestCase { - /** - * Makes sure that reloading the project while a build is in progress won't clobber that in-progress build. - */ - @Bug(12318) - public void testReloadWhileBuildIsInProgress() { - def p = createFreeStyleProject() - - // want some completed build records - def b1 = assertBuildStatusSuccess(p.scheduleBuild2(0)) - - // now create a build that hangs until we signal the OneShotEvent - p.buildersList.add(new SleepBuilder(9999999)); - def b2 = p.scheduleBuild2(0).waitForStart() - assertEquals 2,b2.number - - // now reload - p.updateByXml(new StreamSource(p.configFile.file)) - - // we should still see the same object for #2 because that's in progress - assertSame p.getBuildByNumber(b2.number),b2 - // build #1 should be reloaded - assertNotSame b1,p.getBuildByNumber(1) - - // and reference gets fixed up - b1 = p.getBuildByNumber(1) - assertSame b1.nextBuild,b2 - assertSame b2.previousBuild,b1 - } - - /** - * Testing if the lazy loading can gracefully tolerate a RuntimeException during unmarshalling. - */ - @Bug(15533) - public void testRuntimeExceptionInUnmarshalling() { - def p = createFreeStyleProject() - def b = assertBuildStatusSuccess(p.scheduleBuild2(0)) - b.addAction(new BombAction()); - b.save() - - p._getRuns().purgeCache() - b = p.getBuildByNumber(b.number) - // Original test assumed that b == null, but after JENKINS-21024 this is no longer true, - // so this may not really be testing anything interesting: - assert b != null - assert b.getAction(BombAction.class) == null - assert bombed - } - - public static class BombAction extends InvisibleAction { - public Object readResolve() { - TestEnvironment.get().testCase.bombed = true - throw new NullPointerException(); - } - } - - boolean bombed; - - -} diff --git a/test/src/test/java/hudson/model/RunMapTest.java b/test/src/test/java/hudson/model/RunMapTest.java new file mode 100644 index 0000000000..c1ad3833ec --- /dev/null +++ b/test/src/test/java/hudson/model/RunMapTest.java @@ -0,0 +1,74 @@ +package hudson.model; + +import org.jvnet.hudson.test.Bug; +import org.jvnet.hudson.test.HudsonTestCase; +import org.jvnet.hudson.test.SleepBuilder; +import org.jvnet.hudson.test.TestEnvironment; + +import javax.xml.transform.stream.StreamSource; + +/** + * + * + * @author Kohsuke Kawaguchi + */ +public class RunMapTest extends HudsonTestCase { + /** + * Makes sure that reloading the project while a build is in progress won't clobber that in-progress build. + */ + @Bug(12318) + public void testReloadWhileBuildIsInProgress() throws Exception { + FreeStyleProject p = createFreeStyleProject(); + + // want some completed build records + FreeStyleBuild b1 = assertBuildStatusSuccess(p.scheduleBuild2(0)); + + // now create a build that hangs until we signal the OneShotEvent + p.getBuildersList().add(new SleepBuilder(9999999)); + FreeStyleBuild b2 = p.scheduleBuild2(0).waitForStart(); + assertEquals(2, b2.number); + + // now reload + p.updateByXml(new StreamSource(p.getConfigFile().getFile())); + + // we should still see the same object for #2 because that's in progress + assertSame(p.getBuildByNumber(b2.number), b2); + // build #1 should be reloaded + assertNotSame(b1, p.getBuildByNumber(1)); + + // and reference gets fixed up + b1 = p.getBuildByNumber(1); + assertSame(b1.getNextBuild(), b2); + assertSame(b2.getPreviousBuild(), b1); + } + + /** + * Testing if the lazy loading can gracefully tolerate a RuntimeException during unmarshalling. + */ + @Bug(15533) + public void testRuntimeExceptionInUnmarshalling() throws Exception { + FreeStyleProject p = createFreeStyleProject(); + FreeStyleBuild b = assertBuildStatusSuccess(p.scheduleBuild2(0)); + b.addAction(new BombAction()); + b.save(); + + p._getRuns().purgeCache(); + b = p.getBuildByNumber(b.number); + // Original test assumed that b == null, but after JENKINS-21024 this is no longer true, + // so this may not really be testing anything interesting: + assertNotNull(b); + assertNull(b.getAction(BombAction.class)); + assertTrue(bombed); + } + + public static class BombAction extends InvisibleAction { + public Object readResolve() { + ((RunMapTest) TestEnvironment.get().testCase).bombed = true; + throw new NullPointerException(); + } + } + + private boolean bombed; + + +} From 21a619f2e0ad1658435c9edf5e461d9309ff26af Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Tue, 9 Dec 2014 15:12:19 -0500 Subject: [PATCH 0045/2573] JUnit 4. (cherry picked from commit 96ecabedb0a6bc77f7f838bdaa5482f4f2c10190) --- .../test/java/hudson/model/RunMapTest.java | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/test/src/test/java/hudson/model/RunMapTest.java b/test/src/test/java/hudson/model/RunMapTest.java index c1ad3833ec..a6b45fe602 100644 --- a/test/src/test/java/hudson/model/RunMapTest.java +++ b/test/src/test/java/hudson/model/RunMapTest.java @@ -1,27 +1,30 @@ package hudson.model; -import org.jvnet.hudson.test.Bug; -import org.jvnet.hudson.test.HudsonTestCase; -import org.jvnet.hudson.test.SleepBuilder; -import org.jvnet.hudson.test.TestEnvironment; - +import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; +import static org.junit.Assert.*; +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.SleepBuilder; /** - * - * * @author Kohsuke Kawaguchi */ -public class RunMapTest extends HudsonTestCase { +public class RunMapTest { + + @Rule public JenkinsRule r = new JenkinsRule(); + /** * Makes sure that reloading the project while a build is in progress won't clobber that in-progress build. */ - @Bug(12318) - public void testReloadWhileBuildIsInProgress() throws Exception { - FreeStyleProject p = createFreeStyleProject(); + @Issue("JENKNS-12318") + @Test public void reloadWhileBuildIsInProgress() throws Exception { + FreeStyleProject p = r.createFreeStyleProject(); // want some completed build records - FreeStyleBuild b1 = assertBuildStatusSuccess(p.scheduleBuild2(0)); + FreeStyleBuild b1 = r.assertBuildStatusSuccess(p.scheduleBuild2(0)); // now create a build that hangs until we signal the OneShotEvent p.getBuildersList().add(new SleepBuilder(9999999)); @@ -29,7 +32,7 @@ public class RunMapTest extends HudsonTestCase { assertEquals(2, b2.number); // now reload - p.updateByXml(new StreamSource(p.getConfigFile().getFile())); + p.updateByXml((Source) new StreamSource(p.getConfigFile().getFile())); // we should still see the same object for #2 because that's in progress assertSame(p.getBuildByNumber(b2.number), b2); @@ -45,10 +48,10 @@ public class RunMapTest extends HudsonTestCase { /** * Testing if the lazy loading can gracefully tolerate a RuntimeException during unmarshalling. */ - @Bug(15533) - public void testRuntimeExceptionInUnmarshalling() throws Exception { - FreeStyleProject p = createFreeStyleProject(); - FreeStyleBuild b = assertBuildStatusSuccess(p.scheduleBuild2(0)); + @Issue("JENKINS-15533") + @Test public void runtimeExceptionInUnmarshalling() throws Exception { + FreeStyleProject p = r.createFreeStyleProject(); + FreeStyleBuild b = r.assertBuildStatusSuccess(p.scheduleBuild2(0)); b.addAction(new BombAction()); b.save(); @@ -63,12 +66,11 @@ public class RunMapTest extends HudsonTestCase { public static class BombAction extends InvisibleAction { public Object readResolve() { - ((RunMapTest) TestEnvironment.get().testCase).bombed = true; + bombed = true; throw new NullPointerException(); } } - private boolean bombed; - + private static boolean bombed; } From 14d676bb15dbf8ddc3208bd8a80033e831756d49 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Tue, 9 Dec 2014 15:24:06 -0500 Subject: [PATCH 0046/2573] [FIXED JENKINS-25788] RunMap.remove was always returning false, even when the Run was in fact removed. (cherry picked from commit ce94579c50621990517c86120236ee9a1d0490da) Conflicts: changelog.html --- .../model/lazy/AbstractLazyLoadRunMap.java | 2 +- .../test/java/hudson/model/RunMapTest.java | 20 ++++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/jenkins/model/lazy/AbstractLazyLoadRunMap.java b/core/src/main/java/jenkins/model/lazy/AbstractLazyLoadRunMap.java index f299d598d0..3085d8fb82 100644 --- a/core/src/main/java/jenkins/model/lazy/AbstractLazyLoadRunMap.java +++ b/core/src/main/java/jenkins/model/lazy/AbstractLazyLoadRunMap.java @@ -746,7 +746,7 @@ public abstract class AbstractLazyLoadRunMap extends AbstractMap i entrySet.clearCache(); - return unwrap(old)!=null; + return old != null; } /** diff --git a/test/src/test/java/hudson/model/RunMapTest.java b/test/src/test/java/hudson/model/RunMapTest.java index a6b45fe602..13d49dcd60 100644 --- a/test/src/test/java/hudson/model/RunMapTest.java +++ b/test/src/test/java/hudson/model/RunMapTest.java @@ -9,9 +9,6 @@ import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.SleepBuilder; -/** - * @author Kohsuke Kawaguchi - */ public class RunMapTest { @Rule public JenkinsRule r = new JenkinsRule(); @@ -73,4 +70,21 @@ public class RunMapTest { private static boolean bombed; + @Issue("JENKINS-25788") + @Test public void remove() throws Exception { + FreeStyleProject p = r.createFreeStyleProject(); + FreeStyleBuild b1 = r.buildAndAssertSuccess(p); + FreeStyleBuild b2 = r.buildAndAssertSuccess(p); + RunMap runs = p._getRuns(); + assertEquals(2, runs.size()); + assertTrue(runs.remove(b1)); + assertEquals(1, runs.size()); + assertFalse(runs.remove(b1)); + assertEquals(1, runs.size()); + assertTrue(runs.remove(b2)); + assertEquals(0, runs.size()); + assertFalse(runs.remove(b2)); + assertEquals(0, runs.size()); + } + } From 2172503f3ce2acf1dd9fb95891e41441bff5197f Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Sun, 21 Dec 2014 03:29:39 +0100 Subject: [PATCH 0047/2573] [FIXED JENKINS-25989] Allow breaking label and node lists (cherry picked from commit 2820e59202975ce8ad302e4a0b0e17c07e4c40cf) --- core/src/main/resources/hudson/model/Computer/index.jelly | 1 + core/src/main/resources/hudson/model/Label/index.jelly | 1 + 2 files changed, 2 insertions(+) diff --git a/core/src/main/resources/hudson/model/Computer/index.jelly b/core/src/main/resources/hudson/model/Computer/index.jelly index 9adde755c6..ecd9dbf11e 100644 --- a/core/src/main/resources/hudson/model/Computer/index.jelly +++ b/core/src/main/resources/hudson/model/Computer/index.jelly @@ -94,6 +94,7 @@ THE SOFTWARE. ${entry.item.name} + diff --git a/core/src/main/resources/hudson/model/Label/index.jelly b/core/src/main/resources/hudson/model/Label/index.jelly index 22cd6d0ac3..931d7932df 100644 --- a/core/src/main/resources/hudson/model/Label/index.jelly +++ b/core/src/main/resources/hudson/model/Label/index.jelly @@ -50,6 +50,7 @@ THE SOFTWARE. ${c.displayName} + From 3603b69938e72bd7a03dd431cd1ac7066a5646ef Mon Sep 17 00:00:00 2001 From: tfennelly Date: Mon, 24 Nov 2014 22:58:25 +0000 Subject: [PATCH 0048/2573] Single/Multiline Build History (cherry picked from commit cb9036c45527223525cc1b48020a8ed777020c1a) --- .../widgets/BuildHistoryWidget/entries.jelly | 54 ++- .../hudson/widgets/HistoryWidget/entry.jelly | 69 +-- .../hudson/widgets/HistoryWidget/index.jelly | 1 + war/src/main/webapp/css/style.css | 132 +++++- .../main/webapp/scripts/hudson-behavior.js | 436 +++++++++++++++++- 5 files changed, 620 insertions(+), 72 deletions(-) diff --git a/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly b/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly index 80eaf3cbfd..f84e541e08 100644 --- a/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly +++ b/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly @@ -33,30 +33,38 @@ THE SOFTWARE. - - - - - - #${queuedItems.size()==1 ? it.owner.nextBuildNumber - : it.owner.nextBuildNumber+queuedItems.size()-i-1} - - -

- - - + + +
+
+ +
+ +
+ #${queuedItems.size()==1 ? it.owner.nextBuildNumber + : it.owner.nextBuildNumber+queuedItems.size()-i-1} +
- - - - (${%pending}—) - - - (${%pending}) - - - ${item.params} +
+ + + + (${%pending}—) + + + (${%pending}) + + + ${item.params} +
+
+
+ + + +
+
+
diff --git a/core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly b/core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly index 8ef23a9da0..2283a6603a 100644 --- a/core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly +++ b/core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly @@ -29,41 +29,48 @@ THE SOFTWARE. - - - - ${build.displayName} - - - - - - - - - + + + +
+ + + + + + + +
+
+
+ + + + + + + +
+ +
+ + + + +
+
+
-
+
- - - - - - - - - - - - - - - - - +
diff --git a/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly b/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly index e545de38d0..f43ba94068 100644 --- a/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly +++ b/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly @@ -88,6 +88,7 @@ THE SOFTWARE. newhist.headers = hist.headers replace(hist, newhist); + fireBuildHistoryChanged(); } }); } diff --git a/war/src/main/webapp/css/style.css b/war/src/main/webapp/css/style.css index 9947dabaca..a01d3c945a 100644 --- a/war/src/main/webapp/css/style.css +++ b/war/src/main/webapp/css/style.css @@ -431,10 +431,6 @@ pre.console { width: 480px; } -.build-row { - padding: 3px 4px 3px 4px; -} - .build-keep { font-weight: bold; } @@ -924,18 +920,140 @@ table.parameters > tbody:hover { } #buildHistory .desc { + position: relative; padding: 0; margin-top: 5px; white-space: normal; - max-width: 200px; + opacity: 0.6; + font-style: italic; +} + +#buildHistory .build-row-cell { + position: relative; } #buildHistory .build-rss-links { float: right; } -#buildHistory .build-name { - max-width: 120px; +.build-row { + padding: 3px 4px 3px 4px; +} + +.build-row:hover { + background: #e8e8e8 !important; +} + +.build-row-cell { + font-size: 12px; +} + +.build-row-cell .pane.build-name { + width: 20%; + font-weight: bold; +} +.build-row-cell .pane.build-details { + width: 50%; +} +.build-row-cell .pane.build-controls { + width: 30%; + text-align: right; +} +.build-row-cell .pane.build-details.block { + width: 100%; +} + +.pane.build-name a, +.pane.build-name a:visited { + color: black; + text-decoration: underline; +} + +.pane.build-details a, +.pane.build-details a:visited { + color: black; + opacity: 0.6; + text-decoration: none; +} +.pane.build-details a:hover { + opacity: 1.0; + text-decoration: underline; +} + +.build-row.multi-line .build-row-cell .pane.build-name.block { + width: 100%; +} +.build-row-cell .pane.build-controls.block { + width: 100%; +} + +.build-row-cell .pane.build-name .build-icon, +.build-row-cell .pane.build-name .display-name { + display: inline-block; +} +.build-row-cell .pane.build-name .build-icon { + position: absolute; +} + +.build-row-cell .build-stop { + display: inline-block; + width: 30%; +} +.build-row-cell .build-badge { + display: inline-block; + padding: 2px; + width: 70%; + text-align: right; +} +.build-row .build-name-controls .pane.build-name, +.build-row .build-details-controls .pane.build-details { + width: 70%; +} + +.build-row .build-row-cell .pane { + padding: 0px 2px; /* Sync changes with func expandControlsTo50Percent in hudson-behavior.js */ + display: inline-block; + overflow: hidden; +} + +.build-row.multi-line .build-row-cell .block { + display: block; + overflow: auto; +} + +.build-row.multi-line .build-row-cell .indent-multiline { + margin-top: 5px; +} + +.build-row.multi-line .build-row-cell .left-bar { + position: absolute; + top: 19px; + bottom: 3px; + left: 14px; + border-left: 1px solid #cdcdcd; +} + +.build-row-cell .pane.build-name .display-name, +.build-row-cell .indent-multiline { + padding-left: 20px !important; /* Sync changes with func expandControlsTo50Percent in hudson-behavior.js */ +} + +.build-row .build-row-cell { + visibility: hidden; +} +.build-row.overflow-checked .build-row-cell { + visibility: visible; +} + +/* ================ Element overflow calculation helper styles ================ */ + +.force-wrap, .force-wrap a { + white-space: normal !important; + overflow: visible !important; +} +.force-nowrap, .force-nowrap a { + white-space: nowrap !important; + overflow: hidden !important; } /* ========================= editable combobox style ========================= */ diff --git a/war/src/main/webapp/scripts/hudson-behavior.js b/war/src/main/webapp/scripts/hudson-behavior.js index 35d61270bf..f7983edbd1 100644 --- a/war/src/main/webapp/scripts/hudson-behavior.js +++ b/war/src/main/webapp/scripts/hudson-behavior.js @@ -1557,19 +1557,322 @@ Form.findMatchingInput = function(base, name) { return null; // not found } +function onBuildHistoryChange(handler) { + Event.observe(window, 'jenkins:buildHistoryChanged', handler); +} +function fireBuildHistoryChanged() { + Event.fire(window, 'jenkins:buildHistoryChanged'); +} + function updateBuildHistory(ajaxUrl,nBuild) { if(isRunAsTest) return; - $('buildHistory').headers = ["n",nBuild]; + var bh = $('buildHistory'); - function updateBuilds() { - if(isPageVisible()){ - var bh = $('buildHistory'); - if (bh.headers == null) { - // Yahoo.log("Missing headers in buildHistory element"); + bh.headers = ["n",nBuild]; + + function getDataTable(buildHistoryDiv) { + return $(buildHistoryDiv).getElementsBySelector('table.pane')[0]; + } + + var leftRightPadding = 4; + function checkRowCellOverflows(row) { + if (!row) { + return; + } + + if (Element.hasClassName(row, "overflow-checked")) { + // already done. + return; + } + + function markSingleline() { + Element.addClassName(row, "single-line"); + Element.removeClassName(row, "multi-line"); + } + function markMultiline() { + Element.removeClassName(row, "single-line"); + Element.addClassName(row, "multi-line"); + } + function indentMultiline(element) { + Element.addClassName(element, "indent-multiline"); + } + + function blockWrap(el1, el2) { + var div = document.createElement('div'); + + Element.addClassName(div, "block"); + Element.addClassName(div, "wrap"); + Element.addClassName(el1, "wrapped"); + Element.addClassName(el2, "wrapped"); + + el1.parentNode.insertBefore(div, el1); + el1.parentNode.removeChild(el1); + el2.parentNode.removeChild(el2); + div.appendChild(el1); + div.appendChild(el2); + + return div; + } + function blockUnwrap(element) { + var wrapped = $(element).getElementsBySelector('.wrapped'); + for (var i = 0; i < wrapped.length; i++) { + var wrappedEl = wrapped[i]; + wrappedEl.parentNode.removeChild(wrappedEl); + element.parentNode.insertBefore(wrappedEl, element); + Element.removeClassName(wrappedEl, "wrapped"); + } + element.parentNode.removeChild(element); + } + + var buildName = $(row).getElementsBySelector('.build-name')[0]; + var buildDetails = $(row).getElementsBySelector('.build-details')[0]; + + if (!buildName || !buildDetails) { + return; + } + + var displayName = $(buildName).getElementsBySelector('.display-name')[0]; + var buildControls = $(row).getElementsBySelector('.build-controls')[0]; + var desc; + + var descElements = $(row).getElementsBySelector('.desc'); + if (descElements.length > 0) { + desc = descElements[0]; + } + + function resetCellOverflows() { + markSingleline(); + + // undo block wraps + var blockWraps = $(row).getElementsBySelector('.block.wrap'); + for (var i = 0; i < blockWraps.length; i++) { + blockUnwrap(blockWraps[i]); } - function getDataTable(buildHistoryDiv) { - return $(buildHistoryDiv).getElementsBySelector('table.pane')[0]; + removeZeroWidthSpaces(displayName); + removeZeroWidthSpaces(desc); + Element.removeClassName(buildName, "block"); + buildName.removeAttribute('style'); + Element.removeClassName(buildDetails, "block"); + buildDetails.removeAttribute('style'); + if (buildControls) { + Element.removeClassName(buildControls, "block"); + buildDetails.removeAttribute('style'); + } + } + + // Undo everything from the previous poll. + resetCellOverflows(); + + // Insert zero-width spaces so as to allow text to wrap, allowing us to get the true clientWidth. + insertZeroWidthSpaces(displayName, 2); + if (desc) { + insertZeroWidthSpaces(desc, 30); + markMultiline(); + } + + var rowWidth = bh.clientWidth; + var usableRowWidth = rowWidth - (leftRightPadding * 2); + var nameOverflowParams = getElementOverflowParams(buildName); + var detailsOverflowParams = getElementOverflowParams(buildDetails); + + var controlsOverflowParams; + if (buildControls) { + controlsOverflowParams = getElementOverflowParams(buildControls); + } + + if (nameOverflowParams.isOverflowed) { + // If the name is overflowed, lets remove the zero-width spaces we added above and + // re-add zero-width spaces with a bigger max word sizes. + removeZeroWidthSpaces(displayName); + insertZeroWidthSpaces(displayName, 20); + } + + function fitToControlsHeight(element) { + if (buildControls) { + if (element.clientHeight < buildControls.clientHeight) { + $(element).setStyle({height: buildControls.clientHeight.toString() + 'px'}); + } + } + } + + function setBuildControlWidths() { + if (buildControls) { + var buildBadge = $(buildControls).getElementsBySelector('.build-badge')[0]; + + if (buildBadge) { + var buildControlsWidth = buildControls.clientWidth; + var buildBadgeWidth; + + var buildStop = $(buildControls).getElementsBySelector('.build-stop')[0]; + if (buildStop) { + $(buildStop).setStyle({width: '24px'}); + // Minus 24 for the buildStop width, + // minus 4 for left+right padding in the controls container + buildBadgeWidth = (buildControlsWidth - 24 - leftRightPadding); + if (Element.hasClassName(buildControls, "indent-multiline")) { + buildBadgeWidth = buildBadgeWidth - 20; + } + $(buildBadge).setStyle({width: (buildBadgeWidth) + 'px'}); + } else { + $(buildBadge).setStyle({width: '100%'}); + } + } + controlsOverflowParams = getElementOverflowParams(buildControls); + } + } + setBuildControlWidths(); + + var controlsRepositioned = false; + + if (nameOverflowParams.isOverflowed || detailsOverflowParams.isOverflowed) { + // At least one of the cells (name or details) needs to move to a row of its own. + + markMultiline(); + + if (buildControls) { + + // We have build controls. Lets see can we find a combination that allows the build controls + // to sit beside either the build name or the build details. + + var badgesOverflowing = false; + var nameLessThanHalf = true; + var detailsLessThanHalf = true; + var buildBadge = $(buildControls).getElementsBySelector('.build-badge')[0]; + if (buildBadge) { + var badgeOverflowParams = getElementOverflowParams(buildBadge); + + if (badgeOverflowParams.isOverflowed) { + // The badges are also overflowing. In this case, we will only attempt to + // put the controls on the same line as the name or details (see below) + // if the name or details is using less than half the width of the build history + // widget. + badgesOverflowing = true; + nameLessThanHalf = (nameOverflowParams.scrollWidth < usableRowWidth/2); + detailsLessThanHalf = (detailsOverflowParams.scrollWidth < usableRowWidth/2); + } + } + function expandLeftWithRight(leftCellOverFlowParams, rightCellOverflowParams) { + // Float them left and right... + $(leftCellOverFlowParams.element).setStyle({float: 'left'}); + $(rightCellOverflowParams.element).setStyle({float: 'right'}); + + if (!leftCellOverFlowParams.isOverflowed && !rightCellOverflowParams.isOverflowed) { + // If neither left nor right are overflowed, just leave as is and let them float left and right. + return; + } + if (leftCellOverFlowParams.isOverflowed && !rightCellOverflowParams.isOverflowed) { + $(leftCellOverFlowParams.element).setStyle({width: leftCellOverFlowParams.scrollWidth + 'px'}); + return; + } + if (!leftCellOverFlowParams.isOverflowed && rightCellOverflowParams.isOverflowed) { + $(rightCellOverflowParams.element).setStyle({width: rightCellOverflowParams.scrollWidth + 'px'}); + return; + } + } + + if ((!badgesOverflowing || nameLessThanHalf) && + (nameOverflowParams.scrollWidth + controlsOverflowParams.scrollWidth <= usableRowWidth)) { + // Build name and controls can go on one row (first row). Need to move build details down + // to a row of its own (second row) by making it a block element, forcing it to wrap. If there + // are controls, we move them up to position them after the build name by inserting before the + // build details. + Element.addClassName(buildDetails, "block"); + buildControls.parentNode.removeChild(buildControls); + buildDetails.parentNode.insertBefore(buildControls, buildDetails); + var wrap = blockWrap(buildName, buildControls); + Element.addClassName(wrap, "build-name-controls"); + indentMultiline(buildDetails); + nameOverflowParams = getElementOverflowParams(buildName); // recalculate + expandLeftWithRight(nameOverflowParams, controlsOverflowParams); + setBuildControlWidths(); + fitToControlsHeight(buildName); + } else if ((!badgesOverflowing || detailsLessThanHalf) && + (detailsOverflowParams.scrollWidth + controlsOverflowParams.scrollWidth <= usableRowWidth)) { + // Build details and controls can go on one row. Need to make the + // build name (first field) a block element, forcing the details and controls to wrap + // onto the next row (creating a second row). + Element.addClassName(buildName, "block"); + var wrap = blockWrap(buildDetails, buildControls); + indentMultiline(wrap); + Element.addClassName(wrap, "build-details-controls"); + $(displayName).setStyle({width: '100%'}); + detailsOverflowParams = getElementOverflowParams(buildDetails); // recalculate + expandLeftWithRight(detailsOverflowParams, controlsOverflowParams); + setBuildControlWidths(); + fitToControlsHeight(buildDetails); + } else { + // No suitable combo fits on a row. All need to go on rows of their own. + Element.addClassName(buildName, "block"); + Element.addClassName(buildDetails, "block"); + Element.addClassName(buildControls, "block"); + indentMultiline(buildDetails); + indentMultiline(buildControls); + nameOverflowParams = getElementOverflowParams(buildName); // recalculate + detailsOverflowParams = getElementOverflowParams(buildDetails); // recalculate + setBuildControlWidths(); + } + controlsRepositioned = true; + } else { + Element.addClassName(buildName, "block"); + Element.addClassName(buildDetails, "block"); + indentMultiline(buildDetails); + } + } + + if (buildControls && !controlsRepositioned) { + var buildBadge = $(buildControls).getElementsBySelector('.build-badge')[0]; + if (buildBadge) { + var badgeOverflowParams = getElementOverflowParams(buildBadge); + + if (badgeOverflowParams.isOverflowed) { + markMultiline(); + indentMultiline(buildControls); + Element.addClassName(buildControls, "block"); + controlsRepositioned = true; + setBuildControlWidths(); + } + } + } + + if (!nameOverflowParams.isOverflowed && !detailsOverflowParams.isOverflowed && !controlsRepositioned) { + fitToControlsHeight(buildName); + fitToControlsHeight(buildDetails); + } + + Element.addClassName(row, "overflow-checked"); + } + + function checkAllRowCellOverflows() { + if(isRunAsTest) { + return; + } + + var bh = $('buildHistory'); + var dataTable = getDataTable(bh); + var rows = dataTable.rows; + + // Insert zero-width spaces in text that may cause overflow distortions. + var displayNames = $(bh).getElementsBySelector('.display-name'); + for (var i = 0; i < displayNames.length; i++) { + insertZeroWidthSpaces(displayNames[i], 2); + } + var descriptions = $(bh).getElementsBySelector('.desc'); + for (var i = 0; i < descriptions.length; i++) { + insertZeroWidthSpaces(descriptions[i], 30); + } + + for (var i = 0; i < rows.length; i++) { + var row = rows[i]; + checkRowCellOverflows(row); + } + } + + var updateBuildsRefreshInterval = 5000; + function updateBuilds() { + if(isPageVisible()){ + if (bh.headers == null) { + // Yahoo.log("Missing headers in buildHistory element"); } new Ajax.Request(ajaxUrl, { @@ -1603,17 +1906,128 @@ function updateBuildHistory(ajaxUrl,nBuild) { // next update bh.headers = ["n",rsp.getResponseHeader("n")]; - window.setTimeout(updateBuilds, 5000); + window.setTimeout(updateBuilds, updateBuildsRefreshInterval); + + checkAllRowCellOverflows(); } }); } else { // Reschedule again - window.setTimeout(updateBuilds, 5000); + window.setTimeout(updateBuilds, updateBuildsRefreshInterval); } } - window.setTimeout(updateBuilds, 5000); + window.setTimeout(updateBuilds, updateBuildsRefreshInterval); + + onPanelResize(function() { + checkAllRowCellOverflows(); + }); + onBuildHistoryChange(function() { + checkAllRowCellOverflows(); + }); } +function getElementOverflowParams(element) { + // First we force it to wrap so we can get those dimension. + // Then we force it to "nowrap", so we can get those dimension. + // We can then compare the two sets, which will indicate if + // wrapping is potentially happening, or not. + + // Force it to wrap. + Element.addClassName(element, "force-wrap"); + var wrappedClientWidth = element.clientWidth; + var wrappedClientHeight = element.clientHeight; + Element.removeClassName(element, "force-wrap"); + + // Force it to nowrap. Return the comparisons. + Element.addClassName(element, "force-nowrap"); + var nowrapClientHeight = element.clientHeight; + try { + var overflowParams = { + element: element, + clientWidth: wrappedClientWidth, + scrollWidth: element.scrollWidth, + isOverflowed: wrappedClientHeight > nowrapClientHeight + }; + return overflowParams; + } finally { + Element.removeClassName(element, "force-nowrap"); + } +} + +var zeroWidthSpace = String.fromCharCode(8203); +function insertZeroWidthSpaces(element, maxWordSize) { + if (Element.hasClassName(element, 'zws-inserted')) { + // already done. + return; + } + + var words = element.textContent.split(/\s+/); + var newTextContent = ''; + + var splitRegex = new RegExp('.{1,' + maxWordSize + '}', 'g'); + for (var i = 0; i < words.length; i++) { + var word = words[i]; + var wordTokens = word.match(splitRegex); + if (wordTokens) { + for (var ii = 0; ii < wordTokens.length; ii++) { + if (newTextContent.length === 0) { + newTextContent += wordTokens[ii]; + } else { + newTextContent += zeroWidthSpace + wordTokens[ii]; + } + } + } else { + newTextContent += word; + } + newTextContent += ' '; + } + + element.textContent = newTextContent; + Element.addClassName(element, 'zws-inserted'); +} +function removeZeroWidthSpaces(element) { + if (element) { + element.textContent = element.textContent.replace(zeroWidthSpace, ''); + Element.removeClassName(element, 'zws-inserted'); + } +} + +function onPanelResize(handler) { + Event.observe(window, 'jenkins:panelResized', handler); +} +function firePanelResized() { + Event.fire(window, 'jenkins:panelResized'); +} + +Element.observe(document, 'dom:loaded', function(){ + if(isRunAsTest) { + return; + } + + var fixedSidePanelWidth = 360; + var pageBody = $('page-body'); + var sidePanel = $(pageBody).getElementsBySelector('#side-panel')[0]; + var mainPanel = $(pageBody).getElementsBySelector('#main-panel')[0]; + + function doPanelResize() { + var pageBodyWidth = Element.getWidth(pageBody); + if (pageBodyWidth > 768) { + $(sidePanel).setAttribute('style', 'width: ' + fixedSidePanelWidth + 'px;'); + $(mainPanel).setAttribute('style', 'width: ' + (pageBodyWidth - fixedSidePanelWidth - 5) + 'px;'); + } else { + $(sidePanel).removeAttribute('style'); + $(mainPanel).removeAttribute('style'); + } + + firePanelResized(); + } + doPanelResize(); + + Event.observe(window, 'resize', function() { + doPanelResize(); + }); +}); + // get the cascaded computed style value. 'a' is the style name like 'backgroundColor' function getStyle(e,a){ if(document.defaultView && document.defaultView.getComputedStyle) From ff021d3c374a067d622fdb078a4e391149df7d41 Mon Sep 17 00:00:00 2001 From: "Hughes, Wilfred (London)" Date: Wed, 14 Jan 2015 16:27:35 +0000 Subject: [PATCH 0049/2573] [JENKINS-755] Describe the built-in JDK as '(System)'. As suggested in https://issues.jenkins-ci.org/browse/JENKINS-755?focusedCommentId=206175&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-206175 this avoids confusion where users incorrectly think they're getting a JDK they've listed in the configuration page. --- core/src/main/java/hudson/model/JDK.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/hudson/model/JDK.java b/core/src/main/java/hudson/model/JDK.java index fe2152b8a6..addb666a63 100644 --- a/core/src/main/java/hudson/model/JDK.java +++ b/core/src/main/java/hudson/model/JDK.java @@ -54,10 +54,10 @@ import org.kohsuke.stapler.DataBoundConstructor; public final class JDK extends ToolInstallation implements NodeSpecific, EnvironmentSpecific { /** - * Name of the “default JDK”, meaning no specific JDK selected. + * Name of the “System JDK”, which is just the JDK on Jenkins' $PATH. * @since 1.577 */ - public static final String DEFAULT_NAME = "(Default)"; + public static final String DEFAULT_NAME = "(System)"; /** * @deprecated since 2009-02-25 From ef2582db489c0901d52364522dea1498514c7149 Mon Sep 17 00:00:00 2001 From: chris-daw Date: Thu, 15 Jan 2015 12:51:04 +0000 Subject: [PATCH 0050/2573] Update login.jelly Added autocorrect off and autocapitalize off to username input. This switches off functionality on mobile devices which attempts to auto correct text entered into the username field, and removes automatic capitalisation of first word entered. --- core/src/main/resources/jenkins/model/Jenkins/login.jelly | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/jenkins/model/Jenkins/login.jelly b/core/src/main/resources/jenkins/model/Jenkins/login.jelly index a5f68b1178..f7e02a5f50 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/login.jelly +++ b/core/src/main/resources/jenkins/model/Jenkins/login.jelly @@ -35,7 +35,7 @@ THE SOFTWARE. - + From a82b5e195b5ffa501eeb236d15dbb506421435aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Wed, 21 Jan 2015 00:05:54 +0100 Subject: [PATCH 0051/2573] Revert "Single/Multiline Build History" This reverts commit 3603b69938e72bd7a03dd431cd1ac7066a5646ef. --- .../widgets/BuildHistoryWidget/entries.jelly | 54 +-- .../hudson/widgets/HistoryWidget/entry.jelly | 69 ++- .../hudson/widgets/HistoryWidget/index.jelly | 1 - war/src/main/webapp/css/style.css | 132 +----- .../main/webapp/scripts/hudson-behavior.js | 432 +----------------- 5 files changed, 70 insertions(+), 618 deletions(-) diff --git a/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly b/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly index f84e541e08..80eaf3cbfd 100644 --- a/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly +++ b/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly @@ -33,38 +33,30 @@ THE SOFTWARE. - - + + diff --git a/core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly b/core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly index 2283a6603a..8ef23a9da0 100644 --- a/core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly +++ b/core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly @@ -29,48 +29,41 @@ THE SOFTWARE. - - + + + + diff --git a/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly b/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly index f43ba94068..e545de38d0 100644 --- a/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly +++ b/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly @@ -88,7 +88,6 @@ THE SOFTWARE. newhist.headers = hist.headers replace(hist, newhist); - fireBuildHistoryChanged(); } }); } diff --git a/war/src/main/webapp/css/style.css b/war/src/main/webapp/css/style.css index a01d3c945a..9947dabaca 100644 --- a/war/src/main/webapp/css/style.css +++ b/war/src/main/webapp/css/style.css @@ -431,6 +431,10 @@ pre.console { width: 480px; } +.build-row { + padding: 3px 4px 3px 4px; +} + .build-keep { font-weight: bold; } @@ -920,140 +924,18 @@ table.parameters > tbody:hover { } #buildHistory .desc { - position: relative; padding: 0; margin-top: 5px; white-space: normal; - opacity: 0.6; - font-style: italic; -} - -#buildHistory .build-row-cell { - position: relative; + max-width: 200px; } #buildHistory .build-rss-links { float: right; } -.build-row { - padding: 3px 4px 3px 4px; -} - -.build-row:hover { - background: #e8e8e8 !important; -} - -.build-row-cell { - font-size: 12px; -} - -.build-row-cell .pane.build-name { - width: 20%; - font-weight: bold; -} -.build-row-cell .pane.build-details { - width: 50%; -} -.build-row-cell .pane.build-controls { - width: 30%; - text-align: right; -} -.build-row-cell .pane.build-details.block { - width: 100%; -} - -.pane.build-name a, -.pane.build-name a:visited { - color: black; - text-decoration: underline; -} - -.pane.build-details a, -.pane.build-details a:visited { - color: black; - opacity: 0.6; - text-decoration: none; -} -.pane.build-details a:hover { - opacity: 1.0; - text-decoration: underline; -} - -.build-row.multi-line .build-row-cell .pane.build-name.block { - width: 100%; -} -.build-row-cell .pane.build-controls.block { - width: 100%; -} - -.build-row-cell .pane.build-name .build-icon, -.build-row-cell .pane.build-name .display-name { - display: inline-block; -} -.build-row-cell .pane.build-name .build-icon { - position: absolute; -} - -.build-row-cell .build-stop { - display: inline-block; - width: 30%; -} -.build-row-cell .build-badge { - display: inline-block; - padding: 2px; - width: 70%; - text-align: right; -} -.build-row .build-name-controls .pane.build-name, -.build-row .build-details-controls .pane.build-details { - width: 70%; -} - -.build-row .build-row-cell .pane { - padding: 0px 2px; /* Sync changes with func expandControlsTo50Percent in hudson-behavior.js */ - display: inline-block; - overflow: hidden; -} - -.build-row.multi-line .build-row-cell .block { - display: block; - overflow: auto; -} - -.build-row.multi-line .build-row-cell .indent-multiline { - margin-top: 5px; -} - -.build-row.multi-line .build-row-cell .left-bar { - position: absolute; - top: 19px; - bottom: 3px; - left: 14px; - border-left: 1px solid #cdcdcd; -} - -.build-row-cell .pane.build-name .display-name, -.build-row-cell .indent-multiline { - padding-left: 20px !important; /* Sync changes with func expandControlsTo50Percent in hudson-behavior.js */ -} - -.build-row .build-row-cell { - visibility: hidden; -} -.build-row.overflow-checked .build-row-cell { - visibility: visible; -} - -/* ================ Element overflow calculation helper styles ================ */ - -.force-wrap, .force-wrap a { - white-space: normal !important; - overflow: visible !important; -} -.force-nowrap, .force-nowrap a { - white-space: nowrap !important; - overflow: hidden !important; +#buildHistory .build-name { + max-width: 120px; } /* ========================= editable combobox style ========================= */ diff --git a/war/src/main/webapp/scripts/hudson-behavior.js b/war/src/main/webapp/scripts/hudson-behavior.js index f7983edbd1..35d61270bf 100644 --- a/war/src/main/webapp/scripts/hudson-behavior.js +++ b/war/src/main/webapp/scripts/hudson-behavior.js @@ -1557,324 +1557,21 @@ Form.findMatchingInput = function(base, name) { return null; // not found } -function onBuildHistoryChange(handler) { - Event.observe(window, 'jenkins:buildHistoryChanged', handler); -} -function fireBuildHistoryChanged() { - Event.fire(window, 'jenkins:buildHistoryChanged'); -} - function updateBuildHistory(ajaxUrl,nBuild) { if(isRunAsTest) return; - var bh = $('buildHistory'); + $('buildHistory').headers = ["n",nBuild]; - bh.headers = ["n",nBuild]; - - function getDataTable(buildHistoryDiv) { - return $(buildHistoryDiv).getElementsBySelector('table.pane')[0]; - } - - var leftRightPadding = 4; - function checkRowCellOverflows(row) { - if (!row) { - return; - } - - if (Element.hasClassName(row, "overflow-checked")) { - // already done. - return; - } - - function markSingleline() { - Element.addClassName(row, "single-line"); - Element.removeClassName(row, "multi-line"); - } - function markMultiline() { - Element.removeClassName(row, "single-line"); - Element.addClassName(row, "multi-line"); - } - function indentMultiline(element) { - Element.addClassName(element, "indent-multiline"); - } - - function blockWrap(el1, el2) { - var div = document.createElement('div'); - - Element.addClassName(div, "block"); - Element.addClassName(div, "wrap"); - Element.addClassName(el1, "wrapped"); - Element.addClassName(el2, "wrapped"); - - el1.parentNode.insertBefore(div, el1); - el1.parentNode.removeChild(el1); - el2.parentNode.removeChild(el2); - div.appendChild(el1); - div.appendChild(el2); - - return div; - } - function blockUnwrap(element) { - var wrapped = $(element).getElementsBySelector('.wrapped'); - for (var i = 0; i < wrapped.length; i++) { - var wrappedEl = wrapped[i]; - wrappedEl.parentNode.removeChild(wrappedEl); - element.parentNode.insertBefore(wrappedEl, element); - Element.removeClassName(wrappedEl, "wrapped"); - } - element.parentNode.removeChild(element); - } - - var buildName = $(row).getElementsBySelector('.build-name')[0]; - var buildDetails = $(row).getElementsBySelector('.build-details')[0]; - - if (!buildName || !buildDetails) { - return; - } - - var displayName = $(buildName).getElementsBySelector('.display-name')[0]; - var buildControls = $(row).getElementsBySelector('.build-controls')[0]; - var desc; - - var descElements = $(row).getElementsBySelector('.desc'); - if (descElements.length > 0) { - desc = descElements[0]; - } - - function resetCellOverflows() { - markSingleline(); - - // undo block wraps - var blockWraps = $(row).getElementsBySelector('.block.wrap'); - for (var i = 0; i < blockWraps.length; i++) { - blockUnwrap(blockWraps[i]); - } - - removeZeroWidthSpaces(displayName); - removeZeroWidthSpaces(desc); - Element.removeClassName(buildName, "block"); - buildName.removeAttribute('style'); - Element.removeClassName(buildDetails, "block"); - buildDetails.removeAttribute('style'); - if (buildControls) { - Element.removeClassName(buildControls, "block"); - buildDetails.removeAttribute('style'); - } - } - - // Undo everything from the previous poll. - resetCellOverflows(); - - // Insert zero-width spaces so as to allow text to wrap, allowing us to get the true clientWidth. - insertZeroWidthSpaces(displayName, 2); - if (desc) { - insertZeroWidthSpaces(desc, 30); - markMultiline(); - } - - var rowWidth = bh.clientWidth; - var usableRowWidth = rowWidth - (leftRightPadding * 2); - var nameOverflowParams = getElementOverflowParams(buildName); - var detailsOverflowParams = getElementOverflowParams(buildDetails); - - var controlsOverflowParams; - if (buildControls) { - controlsOverflowParams = getElementOverflowParams(buildControls); - } - - if (nameOverflowParams.isOverflowed) { - // If the name is overflowed, lets remove the zero-width spaces we added above and - // re-add zero-width spaces with a bigger max word sizes. - removeZeroWidthSpaces(displayName); - insertZeroWidthSpaces(displayName, 20); - } - - function fitToControlsHeight(element) { - if (buildControls) { - if (element.clientHeight < buildControls.clientHeight) { - $(element).setStyle({height: buildControls.clientHeight.toString() + 'px'}); - } - } - } - - function setBuildControlWidths() { - if (buildControls) { - var buildBadge = $(buildControls).getElementsBySelector('.build-badge')[0]; - - if (buildBadge) { - var buildControlsWidth = buildControls.clientWidth; - var buildBadgeWidth; - - var buildStop = $(buildControls).getElementsBySelector('.build-stop')[0]; - if (buildStop) { - $(buildStop).setStyle({width: '24px'}); - // Minus 24 for the buildStop width, - // minus 4 for left+right padding in the controls container - buildBadgeWidth = (buildControlsWidth - 24 - leftRightPadding); - if (Element.hasClassName(buildControls, "indent-multiline")) { - buildBadgeWidth = buildBadgeWidth - 20; - } - $(buildBadge).setStyle({width: (buildBadgeWidth) + 'px'}); - } else { - $(buildBadge).setStyle({width: '100%'}); - } - } - controlsOverflowParams = getElementOverflowParams(buildControls); - } - } - setBuildControlWidths(); - - var controlsRepositioned = false; - - if (nameOverflowParams.isOverflowed || detailsOverflowParams.isOverflowed) { - // At least one of the cells (name or details) needs to move to a row of its own. - - markMultiline(); - - if (buildControls) { - - // We have build controls. Lets see can we find a combination that allows the build controls - // to sit beside either the build name or the build details. - - var badgesOverflowing = false; - var nameLessThanHalf = true; - var detailsLessThanHalf = true; - var buildBadge = $(buildControls).getElementsBySelector('.build-badge')[0]; - if (buildBadge) { - var badgeOverflowParams = getElementOverflowParams(buildBadge); - - if (badgeOverflowParams.isOverflowed) { - // The badges are also overflowing. In this case, we will only attempt to - // put the controls on the same line as the name or details (see below) - // if the name or details is using less than half the width of the build history - // widget. - badgesOverflowing = true; - nameLessThanHalf = (nameOverflowParams.scrollWidth < usableRowWidth/2); - detailsLessThanHalf = (detailsOverflowParams.scrollWidth < usableRowWidth/2); - } - } - function expandLeftWithRight(leftCellOverFlowParams, rightCellOverflowParams) { - // Float them left and right... - $(leftCellOverFlowParams.element).setStyle({float: 'left'}); - $(rightCellOverflowParams.element).setStyle({float: 'right'}); - - if (!leftCellOverFlowParams.isOverflowed && !rightCellOverflowParams.isOverflowed) { - // If neither left nor right are overflowed, just leave as is and let them float left and right. - return; - } - if (leftCellOverFlowParams.isOverflowed && !rightCellOverflowParams.isOverflowed) { - $(leftCellOverFlowParams.element).setStyle({width: leftCellOverFlowParams.scrollWidth + 'px'}); - return; - } - if (!leftCellOverFlowParams.isOverflowed && rightCellOverflowParams.isOverflowed) { - $(rightCellOverflowParams.element).setStyle({width: rightCellOverflowParams.scrollWidth + 'px'}); - return; - } - } - - if ((!badgesOverflowing || nameLessThanHalf) && - (nameOverflowParams.scrollWidth + controlsOverflowParams.scrollWidth <= usableRowWidth)) { - // Build name and controls can go on one row (first row). Need to move build details down - // to a row of its own (second row) by making it a block element, forcing it to wrap. If there - // are controls, we move them up to position them after the build name by inserting before the - // build details. - Element.addClassName(buildDetails, "block"); - buildControls.parentNode.removeChild(buildControls); - buildDetails.parentNode.insertBefore(buildControls, buildDetails); - var wrap = blockWrap(buildName, buildControls); - Element.addClassName(wrap, "build-name-controls"); - indentMultiline(buildDetails); - nameOverflowParams = getElementOverflowParams(buildName); // recalculate - expandLeftWithRight(nameOverflowParams, controlsOverflowParams); - setBuildControlWidths(); - fitToControlsHeight(buildName); - } else if ((!badgesOverflowing || detailsLessThanHalf) && - (detailsOverflowParams.scrollWidth + controlsOverflowParams.scrollWidth <= usableRowWidth)) { - // Build details and controls can go on one row. Need to make the - // build name (first field) a block element, forcing the details and controls to wrap - // onto the next row (creating a second row). - Element.addClassName(buildName, "block"); - var wrap = blockWrap(buildDetails, buildControls); - indentMultiline(wrap); - Element.addClassName(wrap, "build-details-controls"); - $(displayName).setStyle({width: '100%'}); - detailsOverflowParams = getElementOverflowParams(buildDetails); // recalculate - expandLeftWithRight(detailsOverflowParams, controlsOverflowParams); - setBuildControlWidths(); - fitToControlsHeight(buildDetails); - } else { - // No suitable combo fits on a row. All need to go on rows of their own. - Element.addClassName(buildName, "block"); - Element.addClassName(buildDetails, "block"); - Element.addClassName(buildControls, "block"); - indentMultiline(buildDetails); - indentMultiline(buildControls); - nameOverflowParams = getElementOverflowParams(buildName); // recalculate - detailsOverflowParams = getElementOverflowParams(buildDetails); // recalculate - setBuildControlWidths(); - } - controlsRepositioned = true; - } else { - Element.addClassName(buildName, "block"); - Element.addClassName(buildDetails, "block"); - indentMultiline(buildDetails); - } - } - - if (buildControls && !controlsRepositioned) { - var buildBadge = $(buildControls).getElementsBySelector('.build-badge')[0]; - if (buildBadge) { - var badgeOverflowParams = getElementOverflowParams(buildBadge); - - if (badgeOverflowParams.isOverflowed) { - markMultiline(); - indentMultiline(buildControls); - Element.addClassName(buildControls, "block"); - controlsRepositioned = true; - setBuildControlWidths(); - } - } - } - - if (!nameOverflowParams.isOverflowed && !detailsOverflowParams.isOverflowed && !controlsRepositioned) { - fitToControlsHeight(buildName); - fitToControlsHeight(buildDetails); - } - - Element.addClassName(row, "overflow-checked"); - } - - function checkAllRowCellOverflows() { - if(isRunAsTest) { - return; - } - - var bh = $('buildHistory'); - var dataTable = getDataTable(bh); - var rows = dataTable.rows; - - // Insert zero-width spaces in text that may cause overflow distortions. - var displayNames = $(bh).getElementsBySelector('.display-name'); - for (var i = 0; i < displayNames.length; i++) { - insertZeroWidthSpaces(displayNames[i], 2); - } - var descriptions = $(bh).getElementsBySelector('.desc'); - for (var i = 0; i < descriptions.length; i++) { - insertZeroWidthSpaces(descriptions[i], 30); - } - - for (var i = 0; i < rows.length; i++) { - var row = rows[i]; - checkRowCellOverflows(row); - } - } - - var updateBuildsRefreshInterval = 5000; function updateBuilds() { if(isPageVisible()){ + var bh = $('buildHistory'); if (bh.headers == null) { // Yahoo.log("Missing headers in buildHistory element"); } + function getDataTable(buildHistoryDiv) { + return $(buildHistoryDiv).getElementsBySelector('table.pane')[0]; + } + new Ajax.Request(ajaxUrl, { requestHeaders: bh.headers, onSuccess: function(rsp) { @@ -1906,128 +1603,17 @@ function updateBuildHistory(ajaxUrl,nBuild) { // next update bh.headers = ["n",rsp.getResponseHeader("n")]; - window.setTimeout(updateBuilds, updateBuildsRefreshInterval); - - checkAllRowCellOverflows(); + window.setTimeout(updateBuilds, 5000); } }); } else { // Reschedule again - window.setTimeout(updateBuilds, updateBuildsRefreshInterval); + window.setTimeout(updateBuilds, 5000); } } - window.setTimeout(updateBuilds, updateBuildsRefreshInterval); - - onPanelResize(function() { - checkAllRowCellOverflows(); - }); - onBuildHistoryChange(function() { - checkAllRowCellOverflows(); - }); + window.setTimeout(updateBuilds, 5000); } -function getElementOverflowParams(element) { - // First we force it to wrap so we can get those dimension. - // Then we force it to "nowrap", so we can get those dimension. - // We can then compare the two sets, which will indicate if - // wrapping is potentially happening, or not. - - // Force it to wrap. - Element.addClassName(element, "force-wrap"); - var wrappedClientWidth = element.clientWidth; - var wrappedClientHeight = element.clientHeight; - Element.removeClassName(element, "force-wrap"); - - // Force it to nowrap. Return the comparisons. - Element.addClassName(element, "force-nowrap"); - var nowrapClientHeight = element.clientHeight; - try { - var overflowParams = { - element: element, - clientWidth: wrappedClientWidth, - scrollWidth: element.scrollWidth, - isOverflowed: wrappedClientHeight > nowrapClientHeight - }; - return overflowParams; - } finally { - Element.removeClassName(element, "force-nowrap"); - } -} - -var zeroWidthSpace = String.fromCharCode(8203); -function insertZeroWidthSpaces(element, maxWordSize) { - if (Element.hasClassName(element, 'zws-inserted')) { - // already done. - return; - } - - var words = element.textContent.split(/\s+/); - var newTextContent = ''; - - var splitRegex = new RegExp('.{1,' + maxWordSize + '}', 'g'); - for (var i = 0; i < words.length; i++) { - var word = words[i]; - var wordTokens = word.match(splitRegex); - if (wordTokens) { - for (var ii = 0; ii < wordTokens.length; ii++) { - if (newTextContent.length === 0) { - newTextContent += wordTokens[ii]; - } else { - newTextContent += zeroWidthSpace + wordTokens[ii]; - } - } - } else { - newTextContent += word; - } - newTextContent += ' '; - } - - element.textContent = newTextContent; - Element.addClassName(element, 'zws-inserted'); -} -function removeZeroWidthSpaces(element) { - if (element) { - element.textContent = element.textContent.replace(zeroWidthSpace, ''); - Element.removeClassName(element, 'zws-inserted'); - } -} - -function onPanelResize(handler) { - Event.observe(window, 'jenkins:panelResized', handler); -} -function firePanelResized() { - Event.fire(window, 'jenkins:panelResized'); -} - -Element.observe(document, 'dom:loaded', function(){ - if(isRunAsTest) { - return; - } - - var fixedSidePanelWidth = 360; - var pageBody = $('page-body'); - var sidePanel = $(pageBody).getElementsBySelector('#side-panel')[0]; - var mainPanel = $(pageBody).getElementsBySelector('#main-panel')[0]; - - function doPanelResize() { - var pageBodyWidth = Element.getWidth(pageBody); - if (pageBodyWidth > 768) { - $(sidePanel).setAttribute('style', 'width: ' + fixedSidePanelWidth + 'px;'); - $(mainPanel).setAttribute('style', 'width: ' + (pageBodyWidth - fixedSidePanelWidth - 5) + 'px;'); - } else { - $(sidePanel).removeAttribute('style'); - $(mainPanel).removeAttribute('style'); - } - - firePanelResized(); - } - doPanelResize(); - - Event.observe(window, 'resize', function() { - doPanelResize(); - }); -}); - // get the cascaded computed style value. 'a' is the style name like 'backgroundColor' function getStyle(e,a){ if(document.defaultView && document.defaultView.getComputedStyle) From 19511a117eb3694b838f42b380aef55c88f83d0b Mon Sep 17 00:00:00 2001 From: "Hughes, Wilfred (London)" Date: Thu, 15 Jan 2015 10:14:21 +0000 Subject: [PATCH 0052/2573] Add utility method to compare with the default JDK. --- .../java/hudson/model/AbstractProject.java | 2 +- core/src/main/java/hudson/model/JDK.java | 11 ++++ core/src/main/java/jenkins/model/Jenkins.java | 2 +- .../test/java/jenkins/model/JDKNameTest.java | 59 +++++++++++++++++++ 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 core/src/test/java/jenkins/model/JDKNameTest.java diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java index 4a8e3dd901..045e95e06e 100644 --- a/core/src/main/java/hudson/model/AbstractProject.java +++ b/core/src/main/java/hudson/model/AbstractProject.java @@ -351,7 +351,7 @@ public abstract class AbstractProject

,R extends A jdkTool = jdkTool.forNode(node, listener); } jdkTool.buildEnvVars(env); - } else if (jdk != null && !jdk.equals(JDK.DEFAULT_NAME)) { + } else if (!JDK.isDefaultName(jdk)) { listener.getLogger().println("No JDK named ‘" + jdk + "’ found"); } diff --git a/core/src/main/java/hudson/model/JDK.java b/core/src/main/java/hudson/model/JDK.java index addb666a63..90baa0ba73 100644 --- a/core/src/main/java/hudson/model/JDK.java +++ b/core/src/main/java/hudson/model/JDK.java @@ -45,6 +45,8 @@ import java.util.Collections; import jenkins.model.Jenkins; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; /** * Information about JDK installation. @@ -59,6 +61,15 @@ public final class JDK extends ToolInstallation implements NodeSpecific, En */ public static final String DEFAULT_NAME = "(System)"; + @Restricted(NoExternalUse.class) + public static boolean isDefaultName(String name) { + if ("(Default)".equals(name)) { + // DEFAULT_NAME took this value prior to 1.598. + return true; + } + return DEFAULT_NAME.equals(name); + } + /** * @deprecated since 2009-02-25 */ diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 34cbe9b758..f5b2e23872 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -3627,7 +3627,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * If the user chose the default JDK, make sure we got 'java' in PATH. */ public FormValidation doDefaultJDKCheck(StaplerRequest request, @QueryParameter String value) { - if(!value.equals(JDK.DEFAULT_NAME)) + if(!JDK.isDefaultName(value)) // assume the user configured named ones properly in system config --- // or else system config should have reported form field validation errors. return FormValidation.ok(); diff --git a/core/src/test/java/jenkins/model/JDKNameTest.java b/core/src/test/java/jenkins/model/JDKNameTest.java new file mode 100644 index 0000000000..f3e8502f51 --- /dev/null +++ b/core/src/test/java/jenkins/model/JDKNameTest.java @@ -0,0 +1,59 @@ +/* + * The MIT License + * + * Copyright (c) 2014 + * + * 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.model; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import hudson.model.JDK; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.jvnet.hudson.test.Issue; +import org.powermock.modules.junit4.PowerMockRunner; + +@RunWith(PowerMockRunner.class) +public class JDKNameTest { + @Test + public void nullIsNotDefaultName() { + assertThat(JDK.isDefaultName(null), is(false)); + } + + @Test + public void recognizeOldDefaultName() { + // DEFAULT_NAME took this value prior to 1.598. + assertThat(JDK.isDefaultName("(Default)"), is(true)); + } + + @Test + public void recognizeDefaultName() { + assertThat(JDK.isDefaultName(JDK.DEFAULT_NAME), is(true)); + } + + @Test + public void othernameNotDefault() { + assertThat(JDK.isDefaultName("I'm a customized name"), is(false)); + } + +} From 49ffccaf030ec85a83f22a86e76a4e94ec314fa2 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Tue, 27 Jan 2015 17:38:15 -0800 Subject: [PATCH 0053/2573] [maven-release-plugin] prepare release jenkins-1.580.3 --- 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 d9a61ed571..5afd781d3d 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ pom org.jenkins-ci.main - 1.580.3-SNAPSHOT + 1.580.3 cli diff --git a/core/pom.xml b/core/pom.xml index ce4a07d044..26ed10edcf 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.580.3-SNAPSHOT + 1.580.3 ../pom.xml diff --git a/plugins/pom.xml b/plugins/pom.xml index 463ad48e7e..48ec9035c4 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -11,7 +11,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.580.3-SNAPSHOT + 1.580.3 pom -

-
-
-
- - +
+ + - - -
- - -
-
- - -
-
+ + +
+ + +
+
+ +
- -
+ +
${%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 0232/2573] 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 0233/2573] 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 0234/2573] 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 76f4c3519b62ff25c6169e2dd95742f90b3cbbaf Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Thu, 18 Jun 2015 17:06:18 +0200 Subject: [PATCH 0235/2573] Noting #1665 --- changelog.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.html b/changelog.html index 247914a445..a30285049d 100644 --- a/changelog.html +++ b/changelog.html @@ -83,6 +83,9 @@ Upcoming changes
  • Fix jobs getting stuck in the Queue when there exists a cycle of upstream/downstream blocks between them. (issue 28926) +
  • + Always use earlier start time when merging two equivalent queue items. + (issue 2180)
  • What's new in 1.617 (2015/06/07)

    From 17fb4a4ffb41b44ff54a0233afeb64ee3a34469f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Thu, 18 Jun 2015 22:01:26 +0200 Subject: [PATCH 0236/2573] [JENKINS-27436] Fix button link appearance --- war/src/main/webapp/css/style.css | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/war/src/main/webapp/css/style.css b/war/src/main/webapp/css/style.css index d635a76cfd..31480a0fdc 100644 --- a/war/src/main/webapp/css/style.css +++ b/war/src/main/webapp/css/style.css @@ -1579,6 +1579,7 @@ table#legend-table td { border-style: none; border-color: transparent; background: none; + text-decoration: none; } #jenkins .yui-button .first-child { @@ -1685,4 +1686,4 @@ table#legend-table td { background-color: #e5958c; color: #f8f8f8; border: 1px solid #e39280; -} \ No newline at end of file +} From 4b1f46be4806bdb20e40a864d47f3ffa1b32c0eb Mon Sep 17 00:00:00 2001 From: recena Date: Thu, 18 Jun 2015 22:11:31 +0200 Subject: [PATCH 0237/2573] 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 6ac59d6154da6a408e0bdc4a7d6e0aaf41235fe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Antoniuk?= Date: Thu, 18 Jun 2015 21:22:59 -0400 Subject: [PATCH 0238/2573] Update Messages.properties --- core/src/main/resources/hudson/markup/Messages.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/hudson/markup/Messages.properties b/core/src/main/resources/hudson/markup/Messages.properties index eb67aa4c42..9b79e845e2 100644 --- a/core/src/main/resources/hudson/markup/Messages.properties +++ b/core/src/main/resources/hudson/markup/Messages.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -EscapedMarkupFormatter.DisplayName=plain text +EscapedMarkupFormatter.DisplayName=Plain text From 9eb5793c8d7567c03cfa3aa9b5eac59da8c77f9f Mon Sep 17 00:00:00 2001 From: Stephen Souness Date: Fri, 19 Jun 2015 08:22:51 +0100 Subject: [PATCH 0239/2573] Added warning flag to shebang line, corrected string formatting, minor spelling and grammar fixes to comments. --- translation-tool.pl | 71 ++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/translation-tool.pl b/translation-tool.pl index 2b4a6bbfde..95ca0c59de 100755 --- a/translation-tool.pl +++ b/translation-tool.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/perl -w # The MIT License # # Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributers @@ -24,28 +24,28 @@ # Author: Manuel Carrasco # Date: 20 Mar 2010 -# Perl script to generate missing translation keys and missing properties files, -# to remove unused keys, and to convert utf8 properties files to iso or ascii. +# Perl script to generate missing translation keys and missing properties files, +# to remove unused keys, and to convert utf8 properties files to iso or ascii. # -# 1.- It recursively looks for files in a folder, and analizes them to extract the -# keys being used in the application. +# 1.- It recursively looks for files in a folder, and analizes them to extract the +# keys being used in the application. # 2.- If --add=true, it generates the appropriate file for the desired language and adds # these keys to it, adding the english text as a reference. # If the properties file already exists the script update it with the new keys. # 3.- When --remove=true and there are unused keys in our file, the script removes them. # 4.- If an editor is passed as argument, the script edits each modified file after adding new keys. -# 5.- Finally, when --toiso=true or --toascii=true, the script is able to convert utf-8 -# properties files to iso or unicode hex representation is ascii. -# +# 5.- Finally, when --toiso=true or --toascii=true, the script is able to convert utf-8 +# properties files to iso or unicode hex representation is ascii. +# -# Note, while the migration to Jenkins this file will report the keys which should point +# Note, while the migration to Jenkins this file will report the keys which should point # to Jenkins instead of the old name. use strict; use File::Find; my ($lang, $editor, $dir, $toiso, $toascii, $add, $remove, $reuse) = (undef, undef, "./", undef, undef, undef, undef, undef); -my ($tfiles, $tkeys, $tmissing, $tunused, $tempty, $tsame, $tnojenkins) = (0, 0, 0, 0, 0, 0); +my ($tfiles, $tkeys, $tmissing, $tunused, $tempty, $tsame, $tnojenkins) = (0, 0, 0, 0, 0, 0, 0); ## read arguments foreach (@ARGV) { if (/^--lang=(.*)$/) { @@ -62,7 +62,7 @@ foreach (@ARGV) { $remove = 1; } elsif (/^--reuse=(.*)$/) { $reuse = $1; - } else { + } else { $dir=$_; } } @@ -75,7 +75,7 @@ if (!$lang || $lang eq "en") { } print STDERR "\rWait ..."; -## look for Message.properties and *.jelly files in the provided folder +## look for Message.properties and *.jelly files in the provided folder my @files = findTranslatableFiles($dir); ## load a cache with keys already translated to utilize in the case the same key is used @@ -106,10 +106,9 @@ if ($tkeys != 0) { $psame = $tsame/$tkeys*100; $pnojenkins = $tnojenkins/$tkeys*100; } -printf ("\nTOTAL: Files: %d Keys: %d Done: %d(%.2f\%)\n Missing: %d(%.2f\%) Orphan: %d(%.2f\%) Empty: %d(%.2f\%) Same: %d(%.2f\%) NoJenkins: %d(%.2f\%)\n\n", - $tfiles, $tkeys, $tdone, $pdone, - $tmissing, $pmissing, $tunused, $punused, - $tempty, $pempty, $tsame, $psame, $tnojenkins, $pnojenkins); + +my @formatParameters = ($tfiles, $tkeys, $tdone, $pdone, $tmissing, $pmissing, $tunused, $punused, $tempty, $pempty, $tsame, $psame, $tnojenkins, $pnojenkins); +printf "\nTOTAL: Files: %d Keys: %d Done: %d(%.2f%%)\n Missing: %d(%.2f%%) Orphan: %d(%.2f%%) Empty: %d(%.2f%%) Same: %d(%.2f%%) NoJenkins: %d(%.2f%%)\n\n", (@formatParameters); ## end exit(); @@ -117,7 +116,7 @@ exit(); ### This is the main method with is run for each file sub processFile { - # ofile -> output file in the current language, + # ofile -> output file in the current language, # efile -> english file my $file = shift; my ($ofile, $efile) = ($file, $file); @@ -154,7 +153,7 @@ sub processFile { } } - # calculate old keys in the file which are currently unused + # calculate old keys in the file which are currently unused my $unused = ""; foreach (keys %okeys) { if (!defined $keys{$_}) { @@ -163,7 +162,7 @@ sub processFile { } } - # calculate keys which has the same value in english + # calculate keys which have the same value in English my $same = ""; foreach (keys %okeys) { if ($okeys{$_} && $ekeys{$_} && $okeys{$_} eq $ekeys{$_}) { @@ -179,9 +178,9 @@ sub processFile { $tnojenkins ++; } } - - # Show Alerts + + # Show Alerts print "\nFile: $ofile\n$missing$unused$same$nj" if ($missing ne "" || $unused ne '' || $same ne '' || $nj ne ''); # write new keys in our file adding the English translation as a reference @@ -198,14 +197,14 @@ sub processFile { } close(F); } - - # open the editor if the user has especified it and there are changes to manage + + # open the editor if the user has specified it and there are changes to manage system("$editor $ofile") if ($editor && $add && ($missing ne "" || $same ne "" || $nj ne '')); # write new keys in our file adding the English translation as a reference removeUnusedKeys($ofile, %keys) if ($remove && $unused ne ""); - - # convert the language file to ISO or ACII which are + + # convert the language file to ISO or ASCII which are # the charsets which Jenkins supports right now convert($ofile, $toiso, $toascii) if ( -f $ofile ); } @@ -248,7 +247,7 @@ sub loadJellyFile { my $line = $_; while ($line =~ /^.*?\$\{\%([^\(\}]+)(.*)$/ || $line=~ /^.*?\$\{.*?['"]\%([^\(\}\"\']+)(.*)$/ ) { $line = $2; - my $word = $1; + my $word = $1; $word =~ s/\(.+$//g; $word =~ s/'+/''/g; $word =~ s/ /\\ /g; @@ -307,9 +306,9 @@ sub removeUnusedKeys { } close(FI); close(FO); - unlink($back); + unlink($back); } -} +} # convert a UTF-8 file to either ISO-8859 or ASCII sub convert { @@ -322,9 +321,9 @@ sub convert { if ($toiso) { s/([\xC2\xC3])([\x80-\xBF])/chr(ord($1)<<6&0xC0|ord($2)&0x3F)/eg; } else { - s/([\xC0-\xDF])([\x80-\xBF])/sprintf('\\u%04x', + s/([\xC0-\xDF])([\x80-\xBF])/sprintf('\\u%04x', unpack("c",$1)<<6&0x07C0|unpack("c",$2)&0x003F)/ge; - s/([\xE0-\xEF])([\x80-\xBF])([\x80-\xBF])/sprintf('\\u%04x', + s/([\xE0-\xEF])([\x80-\xBF])([\x80-\xBF])/sprintf('\\u%04x', unpack("c",$1)<<12&0xF000|unpack("c",$2)<<6&0x0FC0|unpack("c",$3)&0x003F)/ge; s/([\xF0-\xF7])([\x80-\xBF])([\x80-\xBF])([\x80-\xBF])/sprintf('\\u%04x', unpack("c",$1)<<18&0x1C0000|unpack("c",$2)<<12&0x3F000| @@ -384,11 +383,11 @@ sub trim($) return $string; } -### Usage +### Usage sub usage { print " Translation Tool for Jenkins - + Usage: $0 --lang=xx [options] [dir] dir: -> source folder for searching files (default current) @@ -403,14 +402,14 @@ Usage: $0 --lang=xx [options] [dir] order to utilize them when the same key appears Examples: - - Look for Spanish files with incomplete keys in the 'main' folder, + - Look for Spanish files with incomplete keys in the 'main' folder, edit them with gedit, and finally convert them to ISO-8859 $0 --lang=es --editor=gedit --toiso main - Convert all Japanese files in the current folder encoded with UTF-8 to ASCII $0 --lang=ja --toascii . - - Remove all orphand keys from German files which are in the current file - $0 --lang=de --remove . - + - Remove all orphaned keys from German files which are in the current file + $0 --lang=de --remove . + "; exit(); } From 05f49062de590baf37f97b206fb6aa99b3520651 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Mon, 22 Jun 2015 15:01:11 -0400 Subject: [PATCH 0240/2573] 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 09d9367f56827aec87b3260f97d98887b16fac0b Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Tue, 23 Jun 2015 07:12:10 -0400 Subject: [PATCH 0241/2573] AbstractScmTagAction.getBuild is deprecated in favor of getRun; Jelly views should be updated accordingly. --- .../resources/hudson/scm/AbstractScmTagAction/badge.jelly | 2 +- .../hudson/scm/AbstractScmTagAction/inProgress.jelly | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/resources/hudson/scm/AbstractScmTagAction/badge.jelly b/core/src/main/resources/hudson/scm/AbstractScmTagAction/badge.jelly index 268bc70992..2cc2b6391e 100644 --- a/core/src/main/resources/hudson/scm/AbstractScmTagAction/badge.jelly +++ b/core/src/main/resources/hudson/scm/AbstractScmTagAction/badge.jelly @@ -24,7 +24,7 @@ THE SOFTWARE. - + \ No newline at end of file diff --git a/core/src/main/resources/hudson/scm/AbstractScmTagAction/inProgress.jelly b/core/src/main/resources/hudson/scm/AbstractScmTagAction/inProgress.jelly index eb5a259847..344a9c0859 100644 --- a/core/src/main/resources/hudson/scm/AbstractScmTagAction/inProgress.jelly +++ b/core/src/main/resources/hudson/scm/AbstractScmTagAction/inProgress.jelly @@ -25,9 +25,9 @@ THE SOFTWARE. - + -

    Build ${it.build.displayName}

    +

    Build ${it.run.displayName}

    ${%Tagging is in progress:}

    From 1d2e91a114720a3d0f692d83e7ccc02f0339220a Mon Sep 17 00:00:00 2001 From: Muhammed Akbulut Date: Wed, 24 Jun 2015 09:28:04 +0200 Subject: [PATCH 0242/2573] Grammer fix --- .../resources/hudson/model/Computer/sidepanel_nl.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/hudson/model/Computer/sidepanel_nl.properties b/core/src/main/resources/hudson/model/Computer/sidepanel_nl.properties index 8c6eea983d..bc7f5949bd 100644 --- a/core/src/main/resources/hudson/model/Computer/sidepanel_nl.properties +++ b/core/src/main/resources/hudson/model/Computer/sidepanel_nl.properties @@ -24,6 +24,6 @@ Back\ to\ List=Terug naar overzicht Build\ History=Bouwhistorie Configure=Configureren Delete\ Slave=Verwijderen -Load\ Statistics=Belasting statistieken +Load\ Statistics=Belastings statistieken Script\ Console=Scriptconsole Status=Status From 078d3c7c4b5ffc5eae2f8c300a681bc340dfec60 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Tue, 17 Feb 2015 10:56:03 +0000 Subject: [PATCH 0243/2573] Build history pagination and search --- core/src/main/java/hudson/model/Queue.java | 27 ++ .../hudson/widgets/BuildHistoryWidget.java | 17 + .../java/hudson/widgets/HistoryPageEntry.java | 67 ++++ .../hudson/widgets/HistoryPageFilter.java | 280 +++++++++++++++ .../java/hudson/widgets/HistoryWidget.java | 156 ++++++--- .../BuildSearchParamProcessor.java | 91 +++++ .../BuildSearchParamProcessorFactory.java | 109 ++++++ .../BuildSearchParamProcessorList.java | 91 +++++ .../buildsearch/BuildSearchParams.java | 174 ++++++++++ .../java/hudson/widgets/buildsearch/README.md | 34 ++ .../processors/DateProcessorFactory.java | 212 ++++++++++++ .../DescriptionProcessorFactory.java | 87 +++++ .../processors/NameProcessorFactory.java | 86 +++++ .../processors/ResultProcessorFactory.java | 93 +++++ .../widgets/BuildHistoryWidget/entries.jelly | 50 +-- .../HistoryPageFilter/ajaxBuildHistory.jelly | 41 +++ .../widgets/HistoryPageFilter/entries.jelly | 29 ++ .../HistoryPageFilter/queue-items.jelly | 77 +++++ .../HistoryWidget/ajaxBuildHistory.jelly | 8 +- .../widgets/HistoryWidget/entries.jelly | 6 +- .../hudson/widgets/HistoryWidget/entry.jelly | 14 +- .../hudson/widgets/HistoryWidget/index.jelly | 37 +- .../hudson/widgets/HistoryPageFilterTest.java | 320 ++++++++++++++++++ .../BuildSearchParamProcessorTest.java | 178 ++++++++++ .../buildsearch/BuildSearchParamsTest.java | 73 ++++ war/src/main/webapp/css/style.css | 83 +++++ war/src/main/webapp/images/16x16/bullseye.png | Bin 0 -> 2615 bytes war/src/main/webapp/images/16x16/find.png | Bin 0 -> 5100 bytes war/src/main/webapp/images/16x16/go_down.png | Bin 0 -> 567 bytes war/src/main/webapp/images/16x16/go_up.png | Bin 0 -> 537 bytes .../main/webapp/scripts/hudson-behavior.js | 206 ++++++++++- 31 files changed, 2514 insertions(+), 132 deletions(-) create mode 100644 core/src/main/java/hudson/widgets/HistoryPageEntry.java create mode 100644 core/src/main/java/hudson/widgets/HistoryPageFilter.java create mode 100644 core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessor.java create mode 100644 core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessorFactory.java create mode 100644 core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessorList.java create mode 100644 core/src/main/java/hudson/widgets/buildsearch/BuildSearchParams.java create mode 100644 core/src/main/java/hudson/widgets/buildsearch/README.md create mode 100644 core/src/main/java/hudson/widgets/buildsearch/processors/DateProcessorFactory.java create mode 100644 core/src/main/java/hudson/widgets/buildsearch/processors/DescriptionProcessorFactory.java create mode 100644 core/src/main/java/hudson/widgets/buildsearch/processors/NameProcessorFactory.java create mode 100644 core/src/main/java/hudson/widgets/buildsearch/processors/ResultProcessorFactory.java create mode 100644 core/src/main/resources/hudson/widgets/HistoryPageFilter/ajaxBuildHistory.jelly create mode 100644 core/src/main/resources/hudson/widgets/HistoryPageFilter/entries.jelly create mode 100644 core/src/main/resources/hudson/widgets/HistoryPageFilter/queue-items.jelly create mode 100644 core/src/test/java/hudson/widgets/HistoryPageFilterTest.java create mode 100644 core/src/test/java/hudson/widgets/buildsearch/BuildSearchParamProcessorTest.java create mode 100644 core/src/test/java/hudson/widgets/buildsearch/BuildSearchParamsTest.java create mode 100644 war/src/main/webapp/images/16x16/bullseye.png create mode 100644 war/src/main/webapp/images/16x16/find.png create mode 100644 war/src/main/webapp/images/16x16/go_down.png create mode 100644 war/src/main/webapp/images/16x16/go_up.png diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index 12d3078927..47fc2c6ad3 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -2478,6 +2478,33 @@ public class Queue extends ResourceController implements Saveable { } } + /** + * Mock queue Item used for unit testing. + *

    + * No other clean way to effectively mock Item. + */ + @SuppressWarnings("unchecked") + public static final class MockItem extends Item { + + public MockItem(long id) { + super(null, Collections.EMPTY_LIST, id, null); + } + + @Override + public CauseOfBlockage getCauseOfBlockage() { + return null; + } + + @Override + void enter(Queue q) { + } + + @Override + boolean leave(Queue q) { + return true; + } + } + private static final Logger LOGGER = Logger.getLogger(Queue.class.getName()); /** diff --git a/core/src/main/java/hudson/widgets/BuildHistoryWidget.java b/core/src/main/java/hudson/widgets/BuildHistoryWidget.java index ec80e138a8..871e888a6f 100644 --- a/core/src/main/java/hudson/widgets/BuildHistoryWidget.java +++ b/core/src/main/java/hudson/widgets/BuildHistoryWidget.java @@ -23,10 +23,13 @@ */ package hudson.widgets; +import hudson.model.ModelObject; import jenkins.model.Jenkins; import hudson.model.Queue.Item; import hudson.model.Queue.Task; +import org.apache.commons.collections.IteratorUtils; +import java.util.Collection; import java.util.LinkedList; import java.util.List; @@ -67,4 +70,18 @@ public class BuildHistoryWidget extends HistoryWidget { } return list; } + + @Override + public HistoryPageFilter getPage() { + final HistoryPageFilter historyPageFilter = newPageFilter(); + + List items = new LinkedList(); + + items.addAll((Collection) getQueuedItems()); + items.addAll(IteratorUtils.toList(baseList.iterator())); + historyPageFilter.add(items); + historyPageFilter.widget = this; + + return historyPageFilter; + } } diff --git a/core/src/main/java/hudson/widgets/HistoryPageEntry.java b/core/src/main/java/hudson/widgets/HistoryPageEntry.java new file mode 100644 index 0000000000..d819650301 --- /dev/null +++ b/core/src/main/java/hudson/widgets/HistoryPageEntry.java @@ -0,0 +1,67 @@ +/* + * The MIT License + * + * Copyright (c) 2013-2014, 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.widgets; + +import hudson.model.Queue; +import hudson.model.Run; + +import javax.annotation.Nonnull; + +/** + * @author tom.fennelly@gmail.com + */ +public class HistoryPageEntry { + + private final T entry; + + public HistoryPageEntry(T entry) { + this.entry = entry; + } + + public T getEntry() { + return entry; + } + + public long getEntryId() { + return getEntryId(entry); + } + + protected static long getEntryId(@Nonnull Object entry) { + if (entry instanceof Queue.Item) { + return ((Queue.Item) entry).getId(); + } else if (entry instanceof Run) { + Run run = (Run) entry; + long queueId = run.getQueueId(); + if (queueId == Run.QUEUE_ID_UNKNOWN) { + // Backward compatibility. This is a run from before the Queue.Item IDs + // were mapped onto their resulting Run instance. + return (Integer.MIN_VALUE + run.getNumber()); + } else { + return queueId; + } + } else { + return Run.QUEUE_ID_UNKNOWN; + } + } +} diff --git a/core/src/main/java/hudson/widgets/HistoryPageFilter.java b/core/src/main/java/hudson/widgets/HistoryPageFilter.java new file mode 100644 index 0000000000..b5ac6cfaf9 --- /dev/null +++ b/core/src/main/java/hudson/widgets/HistoryPageFilter.java @@ -0,0 +1,280 @@ +/* + * The MIT License + * + * Copyright (c) 2013-2014, 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.widgets; + +import hudson.model.Job; +import hudson.model.Queue; +import hudson.model.Run; +import hudson.widgets.buildsearch.BuildSearchParamProcessor; +import hudson.widgets.buildsearch.BuildSearchParamProcessorList; +import hudson.widgets.buildsearch.BuildSearchParams; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * History page filter. + * + * @author tom.fennelly@gmail.com + */ +public class HistoryPageFilter { + + private final int maxEntries; + private Long newerThan; + private Long olderThan; + private BuildSearchParamProcessorList searchParamProcessorList; + + // Need to use different Lists for Queue.Items and Runs because + // we need access to them separately in the jelly files for rendering. + public final List> queueItems = new ArrayList>(); + public final List> runs = new ArrayList>(); + + public boolean hasUpPage = false; // there are newer builds than on this page + public boolean hasDownPage = false; // there are older builds than on this page + public long nextBuildNumber; + public HistoryWidget widget; + + public long newestOnPage = Long.MIN_VALUE; // see updateNewestOldest() + public long oldestOnPage = Long.MAX_VALUE; // see updateNewestOldest() + + /** + * Create a history page filter instance. + * + * @param maxEntries The max number of entries allowed for the page. + */ + public HistoryPageFilter(int maxEntries) { + this.maxEntries = maxEntries; + } + + /** + * Set the 'newerThan' queue ID. + * @param newerThan Queue IDs newer/greater than this queue ID take precedence on this page. + */ + public void setNewerThan(Long newerThan) { + if (olderThan != null) { + throw new UnsupportedOperationException("Cannot set 'newerThan'. 'olderThan' already set."); + } + this.newerThan = newerThan; + } + + /** + * Set the 'olderThan' queue ID. + * @param olderThan Queue IDs older/less than this queue ID take precedence on this page. + */ + public void setOlderThan(Long olderThan) { + if (newerThan != null) { + throw new UnsupportedOperationException("Cannot set 'olderThan'. 'newerThan' already set."); + } + this.olderThan = olderThan; + } + + /** + * Set the search string used to narrow the filtered set of builds. + * @param searchString The search string. + */ + public void setSearchString(@Nonnull String searchString) { + BuildSearchParams searchParams = new BuildSearchParams(searchString); + this.searchParamProcessorList = new BuildSearchParamProcessorList(searchParams); + } + + /** + * Add build items to the History page. + * + * @param items The items to be added. Assumes the list of items are in descending queue ID order i.e. newest first. + */ + public void add(@Nonnull List items) { + if (items.isEmpty()) { + return; + } + + sort(items); + + nextBuildNumber = getNextBuildNumber(items.get(0)); + + if (newerThan == null && olderThan == null) { + // Just return the first page of entries (newest) + for (T item : items) { + add(item); + if (isFull()) { + break; + } + } + hasDownPage = (items.size() > maxEntries); + } else if (newerThan != null) { + int toFillCount = getFillCount(); + if (toFillCount > 0) { + // Locate the point in the items list where the 'newerThan' build item is. Once located, + // add a max of 'getFillCount' build items before that build item. + long newestInList = HistoryPageEntry.getEntryId(items.get(0)); + long oldestInList = HistoryPageEntry.getEntryId(items.get(items.size() - 1)); + int newerThanIdx = -1; + + if (newerThan > newestInList) { + // Nothing newer + } else if (newerThan >= oldestInList) { + // newerThan is within the range of items in the item list. + // go through the list and locate the cut-off point. + for (int i = 0; i < items.size(); i++) { + T item = items.get(i); + if (HistoryPageEntry.getEntryId(item) <= newerThan) { + newerThanIdx = i; + break; + } + } + } else if (newerThan < oldestInList) { + newerThanIdx = items.size(); + } + + if (newerThanIdx != -1) { + if (newerThanIdx <= maxEntries) { + // If there's less than a full page of items newer than "newerThan", then it's ok to + // fill the page with items older than "newerThan". + int itemCountToAdd = Math.min(toFillCount, items.size()); + for (int i = 0; i < itemCountToAdd; i++) { + add(items.get(i)); + } + } else { + // There's more than a full page of items newer than "newerThan". + for (int i = (newerThanIdx - toFillCount); i < newerThanIdx; i++) { + add(items.get(i)); + } + hasUpPage = true; + } + // if there are items after the "newerThan" item, then we + // can page down. + hasDownPage = (items.size() > newerThanIdx + 1); + } else { + // All builds are older than newerThan ? + hasDownPage = true; + } + } + } else if (olderThan != null) { + for (int i = 0; i < items.size(); i++) { + T item = items.get(i); + if (HistoryPageEntry.getEntryId(item) >= olderThan) { + hasUpPage = true; + } else { + add(item); + if (isFull()) { + // This page is full but there may be more builds older + // than the oldest on this page. + hasDownPage = (i + 1 < items.size()); + break; + } + } + } + } + } + + public int size() { + return queueItems.size() + runs.size(); + } + + private void sort(List items) { + // Queue items can start building out of order with how they got added to the queue. Sorting them + // before adding to the page. They'll still get displayed before the building items coz they end + // up in a different list in HistoryPageFilter. + Collections.sort(items, new Comparator() { + @Override + public int compare(T o1, T o2) { + long o1QID = HistoryPageEntry.getEntryId(o1); + long o2QID = HistoryPageEntry.getEntryId(o2); + + if (o1QID < o2QID) { + return 1; + } else if (o1QID == o2QID) { + return 0; + } else { + return -1; + } + } + }); + } + + private long getNextBuildNumber(@Nonnull T entry) { + if (entry instanceof Queue.Item) { + Queue.Task task = ((Queue.Item) entry).task; + if (task instanceof Job) { + return ((Job) task).getNextBuildNumber(); + } + } else if (entry instanceof Run) { + return ((Run) entry).getParent().getNextBuildNumber(); + } + + // TODO maybe this should be an error? + return HistoryPageEntry.getEntryId(entry) + 1; + } + + private void addQueueItem(Queue.Item item) { + updateNewestOldest(item.getId()); + queueItems.add(new HistoryPageEntry(item)); + } + + private void addRun(Run run) { + updateNewestOldest(run.getQueueId()); + runs.add(new HistoryPageEntry(run)); + } + + private void updateNewestOldest(long queueId) { + newestOnPage = Math.max(newestOnPage, queueId); + oldestOnPage = Math.min(oldestOnPage, queueId); + } + + private boolean add(T entry) { + // Purposely not calling isFull(). May need to add a greater number of entries + // to the page initially, newerThan then cutting it back down to size using cutLeading() + if (entry instanceof Queue.Item) { + Queue.Item item = (Queue.Item) entry; + if (searchParamProcessorList != null && !searchParamProcessorList.fitsSearchParams(item)) { + return false; + } + addQueueItem(item); + return true; + } else if (entry instanceof Run) { + Run run = (Run) entry; + if (searchParamProcessorList != null && !searchParamProcessorList.fitsSearchParams(run)) { + return false; + } + addRun(run); + return true; + } + return false; + } + + private boolean isFull() { + return (size() >= maxEntries); + } + + /** + * Get the number of items required to fill the page. + * + * @return The number of items required to fill the page. + */ + private int getFillCount() { + return Math.max(0, (maxEntries - size())); + } +} diff --git a/core/src/main/java/hudson/widgets/HistoryWidget.java b/core/src/main/java/hudson/widgets/HistoryWidget.java index a2ec051839..90f86d3fcf 100644 --- a/core/src/main/java/hudson/widgets/HistoryWidget.java +++ b/core/src/main/java/hudson/widgets/HistoryWidget.java @@ -28,6 +28,7 @@ import hudson.model.ModelObject; import hudson.model.Run; import hudson.util.Iterators; +import org.apache.commons.collections.IteratorUtils; import org.kohsuke.stapler.Header; import org.kohsuke.stapler.HttpResponses; import org.kohsuke.stapler.Stapler; @@ -37,6 +38,7 @@ import org.kohsuke.stapler.StaplerResponse; import javax.servlet.ServletException; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -73,6 +75,10 @@ public class HistoryWidget extends Widget { public final Adapter adapter; + final Long newerThan; + final Long olderThan; + final String searchString; + /** * First transient build record. Everything >= this will be discarded when AJAX call is made. */ @@ -83,10 +89,14 @@ public class HistoryWidget extends Widget { * The parent model object that owns this widget. */ public HistoryWidget(O owner, Iterable baseList, Adapter adapter) { + StaplerRequest currentRequest = Stapler.getCurrentRequest(); this.adapter = adapter; this.baseList = baseList; - this.baseUrl = Functions.getNearestAncestorUrl(Stapler.getCurrentRequest(),owner); + this.baseUrl = Functions.getNearestAncestorUrl(currentRequest,owner); this.owner = owner; + this.newerThan = getPagingParam(currentRequest, "newer-than"); + this.olderThan = getPagingParam(currentRequest, "older-than"); + this.searchString = currentRequest.getParameter("search");; } /** @@ -105,11 +115,13 @@ public class HistoryWidget extends Widget { return firstTransientBuildKey; } - private Iterable updateFirstTransientBuildKey(Iterable source) { + private Iterable> updateFirstTransientBuildKey(Iterable> source) { String key=null; - for (T t : source) - if(adapter.isBuilding(t)) - key = adapter.getKey(t); + for (HistoryPageEntry t : source) { + if(adapter.isBuilding(t.getEntry())) { + key = adapter.getKey(t.getEntry()); + } + } firstTransientBuildKey = key; return source; } @@ -117,29 +129,63 @@ public class HistoryWidget extends Widget { /** * The records to be rendered this time. */ - public Iterable getRenderList() { + public Iterable> getRenderList() { if(trimmed) { - List lst; - if (baseList instanceof List) { - lst = (List) baseList; - if(lst.size()>THRESHOLD) - return updateFirstTransientBuildKey(lst.subList(0,THRESHOLD)); - trimmed=false; - return updateFirstTransientBuildKey(lst); + List> pageEntries = toPageEntries(baseList); + if(pageEntries.size() > THRESHOLD) { + return updateFirstTransientBuildKey(pageEntries.subList(0,THRESHOLD)); } else { - lst = new ArrayList(THRESHOLD); - Iterator itr = baseList.iterator(); - while(lst.size()<=THRESHOLD && itr.hasNext()) - lst.add(itr.next()); - trimmed = itr.hasNext(); // if we don't have enough items in the base list, setting this to false will optimize the next getRenderList() invocation. - return updateFirstTransientBuildKey(lst); + trimmed=false; + return updateFirstTransientBuildKey(pageEntries); } } else { - // to prevent baseList's concrete type from getting picked up by in view - return updateFirstTransientBuildKey(Iterators.wrap(baseList)); + // to prevent baseList's concrete type from getting picked up by in view + return updateFirstTransientBuildKey(toPageEntries(baseList)); } } + private List> toPageEntries(Iterable historyItemList) { + Iterator iterator = historyItemList.iterator(); + + if (!iterator.hasNext()) { + return Collections.EMPTY_LIST; + } + + List> pageEntries = new ArrayList>(); + while (iterator.hasNext()) { + pageEntries.add(new HistoryPageEntry(iterator.next())); + } + + return pageEntries; + } + + /** + * Render a "page" of records. + */ + public HistoryPageFilter getPage() { + HistoryPageFilter historyPageFilter = newPageFilter(); + + historyPageFilter.add(IteratorUtils.toList(baseList.iterator())); + historyPageFilter.widget = this; + return historyPageFilter; + } + + protected HistoryPageFilter newPageFilter() { + HistoryPageFilter historyPageFilter = new HistoryPageFilter(THRESHOLD); + + if (newerThan != null) { + historyPageFilter.setNewerThan(newerThan); + } else if (olderThan != null) { + historyPageFilter.setOlderThan(olderThan); + } + + if (searchString != null) { + historyPageFilter.setSearchString(searchString); + } + + return historyPageFilter; + } + public boolean isTrimmed() { return trimmed; } @@ -156,46 +202,48 @@ public class HistoryWidget extends Widget { * uses non-numbers as the build key. */ public void doAjax( StaplerRequest req, StaplerResponse rsp, - @Header("n") String n ) throws IOException, ServletException { - - if (n==null) throw HttpResponses.error(SC_BAD_REQUEST,new Exception("Missing the 'n' HTTP header")); + @Header("n") String n ) throws IOException, ServletException { rsp.setContentType("text/html;charset=UTF-8"); // pick up builds to send back List items = new ArrayList(); - String nn=null; // we'll compute next n here + if (n != null) { + String nn=null; // we'll compute next n here - // list up all builds >=n. - for (T t : baseList) { - if(adapter.compare(t,n)>=0) { - items.add(t); - if(adapter.isBuilding(t)) + // list up all builds >=n. + for (T t : baseList) { + if(adapter.compare(t,n)>=0) { + items.add(t); + if(adapter.isBuilding(t)) nn = adapter.getKey(t); // the next fetch should start from youngest build in progress - } else - break; - } - - if (nn==null) { - if (items.isEmpty()) { - // nothing to report back. next fetch should retry the same 'n' - nn=n; - } else { - // every record fetched this time is frozen. next fetch should start from the next build - nn=adapter.getNextKey(adapter.getKey(items.get(0))); + } else + break; } + + if (nn==null) { + if (items.isEmpty()) { + // nothing to report back. next fetch should retry the same 'n' + nn=n; + } else { + // every record fetched this time is frozen. next fetch should start from the next build + nn=adapter.getNextKey(adapter.getKey(items.get(0))); + } + } + + baseList = items; + + rsp.setHeader("n",nn); + firstTransientBuildKey = nn; // all builds >= nn should be marked transient } - baseList = items; - - rsp.setHeader("n",nn); - firstTransientBuildKey = nn; // all builds >= nn should be marked transient - - req.getView(this,"ajaxBuildHistory.jelly").forward(req,rsp); + HistoryPageFilter page = getPage(); + updateFirstTransientBuildKey(page.runs); + req.getView(page,"ajaxBuildHistory.jelly").forward(req,rsp); } - private static final int THRESHOLD = Integer.getInteger(HistoryWidget.class.getName()+".threshold",30); + static final int THRESHOLD = Integer.getInteger(HistoryWidget.class.getName()+".threshold",30); public String getNextBuildNumberToFetch() { return nextBuildNumberToFetch; @@ -214,4 +262,16 @@ public class HistoryWidget extends Widget { boolean isBuilding(T record); String getNextKey(String key); } + + private Long getPagingParam(StaplerRequest currentRequest, String name) { + String paramVal = currentRequest.getParameter(name); + if (paramVal == null) { + return null; + } + try { + return new Long(paramVal); + } catch (NumberFormatException nfe) { + return null; + } + } } diff --git a/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessor.java b/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessor.java new file mode 100644 index 0000000000..14a2063ea8 --- /dev/null +++ b/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessor.java @@ -0,0 +1,91 @@ +/* + * The MIT License + * + * Copyright (c) 2013-2014, 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.widgets.buildsearch; + +import hudson.model.Queue; +import hudson.model.Run; + +import java.util.ArrayList; +import java.util.List; + +/** + * Search param/term processor. + * + *

    + * Implementations created through a {@link BuildSearchParamProcessorFactory} implementation. + * + * @author tom.fennelly@gmail.com + */ +public abstract class BuildSearchParamProcessor { + + /** + * Does the supplied {@link Queue.Item} fit the {@link BuildSearchParams} used to create this + * + *

    + * Implementations should call {@link #fitsSearchParams(Object)} after extracting the appropriate data from + * the {@link Queue.Item}. + * + * {@link BuildSearchParamProcessor} instance. + * @param item The {@link Queue.Item} to test. + * @return {@code true} if the {@link Queue.Item} fits, otherwise {@code false}. + */ + public abstract boolean fitsSearchParams(Queue.Item item); + + /** + * Does the supplied {@link Run} fit the {@link BuildSearchParams} used to create this + * + *

    + * Implementations should call {@link #fitsSearchParams(Object)} after extracting the appropriate data from + * the {@link Run}. + * + * {@link BuildSearchParamProcessor} instance. + * @param run The {@link Run} to test. + * @return {@code true} if the {@link Run} fits, otherwise {@code false}. + */ + public abstract boolean fitsSearchParams(Run run); + + /** + * Does the supplied "data" (extracted from a {@link Queue.Item} or {@link Run}) fit the {@link BuildSearchParams} + * used to create this {@link BuildSearchParamProcessor} instance. + * + *

    + * This method implementation should do all of the work in terms of testing the extracted {@link Queue.Item} + * or {@link Run} data against the search criteria used to create the instance. The + * {@link #fitsSearchParams(hudson.model.Queue.Item)} and {@link #fitsSearchParams(hudson.model.Run)} + * implementations should call this function after extracting the appropriate data from the {@link Queue.Item} + * or {@link Run}. + * + *

    + * This method makes unit testing of the {@link BuildSearchParamProcessor} implementation a little easier in + * that it allows the implementation to be hidden in the parent {@link BuildSearchParamProcessorFactory factory} + * class, plus allows testing without the need to create {@link Queue.Item} or {@link Run} instances, which can't + * be created without spinning a {@link jenkins.model.Jenkins} instance via a JenkinsRule (which in turn requires + * test classes to be in the test harness etc). + * + * + * @param data The data to test. + * @return {@code true} if the {@link Run} fits, otherwise {@code false}. + */ + public abstract boolean fitsSearchParams(T data); +} diff --git a/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessorFactory.java b/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessorFactory.java new file mode 100644 index 0000000000..6d8e2d8cd1 --- /dev/null +++ b/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessorFactory.java @@ -0,0 +1,109 @@ +/* + * The MIT License + * + * Copyright (c) 2013-2014, 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.widgets.buildsearch; + +import hudson.ExtensionList; +import hudson.ExtensionPoint; +import hudson.widgets.buildsearch.processors.DateProcessorFactory; +import hudson.widgets.buildsearch.processors.DescriptionProcessorFactory; +import hudson.widgets.buildsearch.processors.NameProcessorFactory; +import hudson.widgets.buildsearch.processors.ResultProcessorFactory; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +/** + * Implementations of this class create {@link BuildSearchParamProcessor} instances from a set + * of {@link BuildSearchParams}. The set of {@link BuildSearchParamProcessor} instances are then used + * by the {@link hudson.widgets.HistoryPageFilter} class to filter the build history (via an instance of + * {@link BuildSearchParamProcessorList}). + * + *

    + * Each {@link BuildSearchParamProcessor} implementation processes one or more search terms e.g. the + * {@link BuildSearchParamProcessor} instance created by the {@link NameProcessorFactory} checks the + * build {@link hudson.model.Queue.Item} or {@link hudson.model.Run} name using the "name:" search token(s) + * provided in the search, while the {@link DateProcessorFactory} checks date using one or both of the + * "date-from:" and "date-to:" tokens. + * + * @author tom.fennelly@gmail.com + */ +public abstract class BuildSearchParamProcessorFactory implements ExtensionPoint { + + private static List coreParamProcessorFactories = new ArrayList(); + + static { + // Statically adding the core BuildSearchParamProcessorFactory impls Vs adding via @Extension. + // Makes testing easier coz no need to create a JenkinsRule instance + put in test harness etc. + // Plugins etc can still contribute via @Extension. + coreParamProcessorFactories.add(new NameProcessorFactory()); + coreParamProcessorFactories.add(new DescriptionProcessorFactory()); + coreParamProcessorFactories.add(new ResultProcessorFactory()); + coreParamProcessorFactories.add(new DateProcessorFactory()); + } + + /** + * Get the list of search terms that this processor is interested in. + * + * @return List of search terms. + */ + public abstract String[] getSearchTerms(); + + /** + * Create the {@link BuildSearchParamProcessor} instance using the supplied set of search parameters. + * + * @param searchParams The parsed search parameters. + * @return The {@link BuildSearchParamProcessor} instance to be used for searching, or {@code null} if the search + * parameters are such that {@link BuildSearchParamProcessor} instance of this type is not needed. + */ + public abstract @CheckForNull BuildSearchParamProcessor createProcessor(@Nonnull BuildSearchParams searchParams); + + public static List all() { + + // TODO: Not convinced we want to bother with @Extension + + ExtensionList extensions = ExtensionList.lookup(BuildSearchParamProcessorFactory.class); + if (extensions.isEmpty()) { + // No BuildSearchParamProcessorFactory defined by @Extension + return coreParamProcessorFactories; + } else { + // One or more BuildSearchParamProcessorFactory defined by @Extension. + List combined = new ArrayList(coreParamProcessorFactories); + combined.addAll(extensions); + return combined; + } + } + + public static Set getAllSearchTerms() { + Set allSearchTerms = new LinkedHashSet(); + for (BuildSearchParamProcessorFactory paramProcessorFactory : all()) { + allSearchTerms.addAll(Arrays.asList(paramProcessorFactory.getSearchTerms())); + } + return allSearchTerms; + } +} diff --git a/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessorList.java b/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessorList.java new file mode 100644 index 0000000000..2c0dee50cf --- /dev/null +++ b/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessorList.java @@ -0,0 +1,91 @@ +/* + * The MIT License + * + * Copyright (c) 2013-2014, 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.widgets.buildsearch; + +import hudson.model.Queue; +import hudson.model.Run; + +import javax.annotation.Nonnull; +import java.util.ArrayList; + +/** + * Wrapper class for the list of {@link hudson.widgets.buildsearch.BuildSearchParamProcessor} needed to process/apply + * a set of {@link hudson.widgets.buildsearch.BuildSearchParams}. + * + * @author tom.fennelly@gmail.com + */ +public class BuildSearchParamProcessorList { + + private final ArrayList processors; + + /** + * Create a {@link BuildSearchParamProcessorList} instance from a set of {@link hudson.widgets.buildsearch.BuildSearchParams}. + * @param searchParams The search parameters to use for creating the {@link BuildSearchParamProcessorList}. + */ + public BuildSearchParamProcessorList(@Nonnull BuildSearchParams searchParams) { + processors = new ArrayList(); + for (BuildSearchParamProcessorFactory factory : BuildSearchParamProcessorFactory.all()) { + BuildSearchParamProcessor processor = factory.createProcessor(searchParams); + if (processor != null) { + processors.add(processor); + } + } + } + + public ArrayList getProcessors() { + return processors; + } + + /** + * Does the supplied {@link hudson.model.Queue.Item} fit the {@link BuildSearchParams} used to create this + * {@link BuildSearchParamProcessorList} instance. + * @param item The {@link hudson.model.Queue.Item} to test. + * @return {@code true} if the {@link hudson.model.Queue.Item} fits all of the {@link BuildSearchParamProcessor}s + * on this {@link BuildSearchParamProcessorList}, otherwise {@code false}. + */ + public boolean fitsSearchParams(@Nonnull Queue.Item item) { + for (BuildSearchParamProcessor processor : processors) { + if (!processor.fitsSearchParams(item)) { + return false; + } + } + return true; + } + + /** + * Does the supplied {@link hudson.model.Run} fit the {@link BuildSearchParams} used to create this + * {@link BuildSearchParamProcessorList} instance. + * @param run The {@link hudson.model.Run} to test. + * @return {@code true} if the {@link hudson.model.Run} fits all of the {@link BuildSearchParamProcessor}s + * on this {@link BuildSearchParamProcessorList}, otherwise {@code false}. + */ + public boolean fitsSearchParams(@Nonnull Run run) { + for (BuildSearchParamProcessor processor : processors) { + if (!processor.fitsSearchParams(run)) { + return false; + } + } + return true; + } +} diff --git a/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParams.java b/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParams.java new file mode 100644 index 0000000000..277bd43b29 --- /dev/null +++ b/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParams.java @@ -0,0 +1,174 @@ +/* + * The MIT License + * + * Copyright (c) 2013-2014, 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.widgets.buildsearch; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * @author tom.fennelly@gmail.com + */ +public class BuildSearchParams { + + private final String searchString; + private final Map> searchParamsSets = newParamMap(); + private boolean parsingComplete = false; + + private static Map> newParamMap() { + Map> map = new LinkedHashMap>(); + for (String searchTerm: BuildSearchParamProcessorFactory.getAllSearchTerms()) { + map.put(searchTerm, new ArrayList()); + } + return Collections.unmodifiableMap(map); + } + + public class BuildSearchParam { + + public String searchTerm; + public String searchTermToken; + + private String param; + // The start index (in this.searchString) of the search parameter (including the searchTermToken itself). + int startIndex; + // The end index (in this.searchString) of the search parameter, -1 being the end of the string. + int endIndex = -1; + + BuildSearchParam(String searchTerm, String searchTermToken, int startIndex) { + this.searchTerm = searchTerm; + this.searchTermToken = searchTermToken; + this.startIndex = startIndex; + } + + public String get() { + if (this.param != null) { + return this.param; + } + + String param = searchString.substring(getEndOfTokenIndex(), getParamEndIndex()); + param = param.trim(); + + if (parsingComplete) { + // We can cache the value if parsing is complete. + this.param = param; + } + + return param; + } + + private boolean isWhitespace() { + int paramStartIndex = getEndOfTokenIndex(); + int paramEndIndex = getParamEndIndex(); + for (int i = paramStartIndex; i < paramEndIndex; i++) { + if (!Character.isWhitespace(searchString.charAt(i))) { + return false; + } + } + return true; + } + + private int getEndOfTokenIndex() { + return (startIndex + searchTermToken.length()); + } + + private int getParamEndIndex() { + return (endIndex != -1 ? endIndex : searchString.length()); + } + + @Override + public String toString() { + return searchTerm + ":'" + get() + "'"; + } + } + + public BuildSearchParams(@Nonnull String searchString) { + this.searchString = searchString; + if (searchString.trim().length() > 0) { + parseSearchString(); + } + } + + public List getParams(@Nonnull String searchTerm) { + List params = searchParamsSets.get(searchTerm); + if (params == null) { + throw new IllegalArgumentException(String.format("Unknown search term '%s'.", searchTerm)); + } + return params; + } + + @Override + public String toString() { + return searchParamsSets.toString(); + } + + private void parseSearchString() { + // Step 1: find all search params in the searchString, recording their startIndex + List allSearchParams = new ArrayList(); + String searchStringLower = searchString.toLowerCase(); + for (String searchTerm : BuildSearchParamProcessorFactory.getAllSearchTerms()) { + String searchTermToken = searchTerm + ":"; + + int startIndex = 0; + while((startIndex = searchStringLower.indexOf(searchTermToken, startIndex)) != -1) { + allSearchParams.add(new BuildSearchParam(searchTerm, searchTermToken, startIndex)); + startIndex += searchTerm.length(); + } + } + + // Step 2: Remove all empty/whitespace params i.e. token defined but no param + + // Step 2: sort all search params by their startIndex. This will then make it easy to find the endIndexes (step 3) + Collections.sort(allSearchParams, new Comparator() { + @Override + public int compare(BuildSearchParam param1, BuildSearchParam param2) { + return param1.startIndex - param2.startIndex; + } + }); + + // Step 3: find the endIndex for each search param. + // That's easy: it's the startIndex of the next search param, or the end of the searchString for the last. + int numParams = allSearchParams.size(); + for (int i = 0; i < numParams; i++) { + BuildSearchParam searchParam = allSearchParams.get(i); + + if (i == numParams - 1) { + // last one, so leave endIndex as -1 + } else { + BuildSearchParam nextSearchParam = allSearchParams.get(i + 1); + searchParam.endIndex = nextSearchParam.startIndex; + } + + // And add it to the top level searchParamsSets Map, but only if it's not whitespace. + if (!searchParam.isWhitespace()) { + searchParamsSets.get(searchParam.searchTerm).add(searchParam); + } + } + + parsingComplete = true; + } +} diff --git a/core/src/main/java/hudson/widgets/buildsearch/README.md b/core/src/main/java/hudson/widgets/buildsearch/README.md new file mode 100644 index 0000000000..f539a9fda3 --- /dev/null +++ b/core/src/main/java/hudson/widgets/buildsearch/README.md @@ -0,0 +1,34 @@ +__TODO__: Move to jenkins-ci web/wiki if changes accepted. + +## Search Terms + +* [__name:__] : Is contained in the name of the build. +* [__desc:__] : Is contained in the description of the build.d. +* [__result:__] : Is the "result" of the build (SUCCESS, UNSTABLE, FAILURE, NOT_BUILT, ABORTED). +* [__date-from:__] and/or [__date-to:__] : Build date is before, after or between. Date format is *yyyy-MM-yy*. Date is start of day i.e. 00:00. Also supports some shorthands e.g. "today", "yesterday", "1 day", "2 days", "2 weeks", "2 months". + +Different search terms are __AND__ together to result in a matching Build, while multiples of the same search term are __OR__'d together e.g. + +* result: FAILURE desc: staging desc: production + +Is interpreted as: + +* (result: FAILURE) AND (desc: staging OR desc: production) + +## Examples + +Builds that contain the words "staging" or "production" in the description: + +* desc: staging desc: production + +Failed builds in last week (7 days): + +* result: FAILURE date-from: 1 week + +Failed builds since a specific date: + +* result: FAILURE date-from: 2015-03-31 + +Unstable builds in March: + +* result: UNSTABLE date-from: 2015-03-01 date-to: 2015-04-01 diff --git a/core/src/main/java/hudson/widgets/buildsearch/processors/DateProcessorFactory.java b/core/src/main/java/hudson/widgets/buildsearch/processors/DateProcessorFactory.java new file mode 100644 index 0000000000..95a5679298 --- /dev/null +++ b/core/src/main/java/hudson/widgets/buildsearch/processors/DateProcessorFactory.java @@ -0,0 +1,212 @@ +/* + * The MIT License + * + * Copyright (c) 2013-2014, 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.widgets.buildsearch.processors; + +import hudson.model.Queue; +import hudson.model.Run; +import hudson.widgets.buildsearch.BuildSearchParamProcessor; +import hudson.widgets.buildsearch.BuildSearchParamProcessorFactory; +import hudson.widgets.buildsearch.BuildSearchParams; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +/** + * Search build history by {@link hudson.model.Queue.Item#getInQueueSince()} + * or {@link hudson.model.Run#getTimeInMillis()} using one or both of the + * "date-from:" and "date-to:" tokens. Also supports some shorthands such as "today" + * + * @author tom.fennelly@gmail.com + */ +public class DateProcessorFactory extends BuildSearchParamProcessorFactory { + + public static String LONG_DATE_FORMAT = "yyyy-MM-dd"; + public static String MEDIUM_DATE_FORMAT = "yy-MM-dd"; + public static String SHORT_DATE_FORMAT = "MM-dd"; + + public static final long DAY = 1000 * 60 * 60 * 24; + public static final long WEEK = DAY * 7; + public static final long MONTH = WEEK * 4; + + private static final String[] SEARCH_TERMS = new String[] {"date-from", "date-to"}; + + /** + * {@inheritDoc} + */ + @Override + public String[] getSearchTerms() { + return SEARCH_TERMS; + } + + /** + * {@inheritDoc} + */ + @Override + public BuildSearchParamProcessor createProcessor(BuildSearchParams searchParams) { + final DateFromTo dateFromTo = new DateFromTo(searchParams); + + if (dateFromTo.dateFrom == null && dateFromTo.dateTo == null) { + return null; + } + + return new BuildSearchParamProcessor() { + + @Override + public boolean fitsSearchParams(Long timeInMillis) { + if (dateFromTo.dateFrom != null && timeInMillis < dateFromTo.dateFrom) { + return false; + } + if (dateFromTo.dateTo != null && timeInMillis > dateFromTo.dateTo) { + return false; + } + return true; + } + + @Override + public boolean fitsSearchParams(Queue.Item item) { + return fitsSearchParams(item.getInQueueSince()); + } + @Override + public boolean fitsSearchParams(Run run) { + return fitsSearchParams(run.getTimeInMillis()); + } + }; + } + + private class DateFromTo { + + private Long dateFrom; + private Long dateTo; + + private DateFromTo(BuildSearchParams searchParams) { + final List dateFromParams = searchParams.getParams(SEARCH_TERMS[0]); + final List dateToParams = searchParams.getParams(SEARCH_TERMS[1]); + + if (dateFromParams.isEmpty() && dateToParams.isEmpty()) { + // none of the date search terms are specified + return; + } + + // Only supports spec of a single pair of "date-from:" and "date-to:" search params. + if (!dateFromParams.isEmpty()) { + dateFrom = toTimeInMillis(dateFromParams.get(0).get()); + } else { + dateFrom = null; + } + + if (!dateToParams.isEmpty()) { + dateTo = toTimeInMillis(dateToParams.get(0).get()); + } else { + dateTo = null; + } + + if (dateFrom != null && dateTo != null && dateFrom > dateTo) { + dateTo = null; + } + } + } + + // make this available to test code too + public static Long toTimeInMillis(String date) { + date = date.toLowerCase(); + + if (date.equals("today")) { + return getToday(); + } else if (date.equals("yesterday")) { + return getYesterday(); + } else if (date.endsWith("day") || date.endsWith("days")) { + return getToday() - (extractMultiple(date) * DAY); + } else if (date.endsWith("week") || date.endsWith("weeks")) { + return getToday() - (extractMultiple(date) * WEEK); + } else if (date.endsWith("month") || date.endsWith("months")) { + return getToday() - (extractMultiple(date) * MONTH); + } + + try { + // SimpleDateFormat is not thread safe. What a PITA !!! + date = normalize(date); + if (date.length() == LONG_DATE_FORMAT.length()) { + return new SimpleDateFormat(LONG_DATE_FORMAT).parse(date).getTime(); + } else if (date.length() == MEDIUM_DATE_FORMAT.length()) { + return new SimpleDateFormat(MEDIUM_DATE_FORMAT).parse(date).getTime(); + } else { + return null; + } + } catch (ParseException e) { + return null; + } + } + + private static long extractMultiple(String date) { + if (Character.isDigit(date.charAt(0))) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < date.length(); i++) { + char c = date.charAt(i); + if (!Character.isDigit(c)) { + break; + } + builder.append(c); + } + return new Long(builder.toString()); + } + return 1; + } + + // make this available to test code too + public static String normalize(String date) { + // In case the user forgot the format and used '/' instead of '-' as the delimiter. + date = date.replace('/', '-'); + // In case there are spaces + date = date.replace(" ", ""); + date = date.toLowerCase(); + + if (date.length() == SHORT_DATE_FORMAT.length()) { + date = getCurrentYearString() + "-" + date; + } + + return date; + } + + public static String getCurrentYearString() { + return new SimpleDateFormat("yyyy").format(new Date()); + } + + public static long getToday() { + long now = System.currentTimeMillis(); + long partOfToday = now % DAY; + long startOfToday = now - partOfToday; + + return startOfToday; + } + + public static long getTomorrow() { + return getToday() + DAY; + } + + public static long getYesterday() { + return getToday() - DAY; + } +} diff --git a/core/src/main/java/hudson/widgets/buildsearch/processors/DescriptionProcessorFactory.java b/core/src/main/java/hudson/widgets/buildsearch/processors/DescriptionProcessorFactory.java new file mode 100644 index 0000000000..60b917df16 --- /dev/null +++ b/core/src/main/java/hudson/widgets/buildsearch/processors/DescriptionProcessorFactory.java @@ -0,0 +1,87 @@ +/* + * The MIT License + * + * Copyright (c) 2013-2014, 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.widgets.buildsearch.processors; + +import hudson.model.Queue; +import hudson.model.Run; +import hudson.widgets.buildsearch.BuildSearchParamProcessor; +import hudson.widgets.buildsearch.BuildSearchParamProcessorFactory; +import hudson.widgets.buildsearch.BuildSearchParams; + +import java.util.List; + +/** + * Search build history by {@link hudson.model.Run} description. + * + * @author tom.fennelly@gmail.com + */ +public class DescriptionProcessorFactory extends BuildSearchParamProcessorFactory { + + private static final String[] SEARCH_TERMS = new String[] {"desc"}; // Build description + + /** + * {@inheritDoc} + */ + @Override + public String[] getSearchTerms() { + return SEARCH_TERMS; + } + + /** + * {@inheritDoc} + */ + @Override + public BuildSearchParamProcessor createProcessor(BuildSearchParams searchParams) { + final List descParams = searchParams.getParams(SEARCH_TERMS[0]); + + if (descParams.isEmpty()) { + // "desc" search term not specified in search + return null; + } + + return new BuildSearchParamProcessor() { + + @Override + public boolean fitsSearchParams(String description) { + // It fits if it contains any of the specified "desc" search terms. + for (BuildSearchParams.BuildSearchParam nameParam : descParams) { + if (description.contains(nameParam.get())) { + return true; + } + } + return false; + } + + @Override + public boolean fitsSearchParams(Queue.Item item) { + // Queue items don't have a description. + return false; + } + @Override + public boolean fitsSearchParams(Run run) { + return fitsSearchParams(run.getDescription()); + } + }; + } +} diff --git a/core/src/main/java/hudson/widgets/buildsearch/processors/NameProcessorFactory.java b/core/src/main/java/hudson/widgets/buildsearch/processors/NameProcessorFactory.java new file mode 100644 index 0000000000..fff9f24747 --- /dev/null +++ b/core/src/main/java/hudson/widgets/buildsearch/processors/NameProcessorFactory.java @@ -0,0 +1,86 @@ +/* + * The MIT License + * + * Copyright (c) 2013-2014, 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.widgets.buildsearch.processors; + +import hudson.model.Queue; +import hudson.model.Run; +import hudson.widgets.buildsearch.BuildSearchParamProcessor; +import hudson.widgets.buildsearch.BuildSearchParamProcessorFactory; +import hudson.widgets.buildsearch.BuildSearchParams; + +import java.util.List; + +/** + * Search build history by {@link hudson.model.Queue.Item} or {@link hudson.model.Run} name. + * + * @author tom.fennelly@gmail.com + */ +public class NameProcessorFactory extends BuildSearchParamProcessorFactory { + + private static final String[] SEARCH_TERMS = new String[] {"name"}; // Build name + + /** + * {@inheritDoc} + */ + @Override + public String[] getSearchTerms() { + return SEARCH_TERMS; + } + + /** + * {@inheritDoc} + */ + @Override + public BuildSearchParamProcessor createProcessor(BuildSearchParams searchParams) { + final List nameParams = searchParams.getParams(SEARCH_TERMS[0]); + + if (nameParams.isEmpty()) { + // "name" search term not specified in search + return null; + } + + return new BuildSearchParamProcessor() { + + @Override + public boolean fitsSearchParams(String name) { + // It fits if it contains any of the specified "name" search terms. + for (BuildSearchParams.BuildSearchParam nameParam : nameParams) { + if (name.contains(nameParam.get())) { + return true; + } + } + return false; + } + + @Override + public boolean fitsSearchParams(Queue.Item item) { + return fitsSearchParams(item.getDisplayName()); + } + @Override + public boolean fitsSearchParams(Run run) { + return fitsSearchParams(run.getDisplayName()); + } + }; + } +} diff --git a/core/src/main/java/hudson/widgets/buildsearch/processors/ResultProcessorFactory.java b/core/src/main/java/hudson/widgets/buildsearch/processors/ResultProcessorFactory.java new file mode 100644 index 0000000000..e7e69a912b --- /dev/null +++ b/core/src/main/java/hudson/widgets/buildsearch/processors/ResultProcessorFactory.java @@ -0,0 +1,93 @@ +/* + * The MIT License + * + * Copyright (c) 2013-2014, 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.widgets.buildsearch.processors; + +import hudson.model.Queue; +import hudson.model.Result; +import hudson.model.Run; +import hudson.widgets.buildsearch.BuildSearchParamProcessor; +import hudson.widgets.buildsearch.BuildSearchParamProcessorFactory; +import hudson.widgets.buildsearch.BuildSearchParams; + +import java.util.ArrayList; +import java.util.List; + +/** + * Search build history by {@link hudson.model.Run} result. + * + * @author tom.fennelly@gmail.com + */ +public class ResultProcessorFactory extends BuildSearchParamProcessorFactory { + + private static final String[] SEARCH_TERMS = new String[] {"result"}; // Build result. TODO: Could do "status" too or maybe that's different + + /** + * {@inheritDoc} + */ + @Override + public String[] getSearchTerms() { + return SEARCH_TERMS; + } + + /** + * {@inheritDoc} + */ + @Override + public BuildSearchParamProcessor createProcessor(BuildSearchParams searchParams) { + List resultParams = searchParams.getParams(SEARCH_TERMS[0]); + + if (resultParams.isEmpty()) { + // "result" search term not specified in search + return null; + } + + final List interestingResults = new ArrayList(); + for (BuildSearchParams.BuildSearchParam resultParam : resultParams) { + Result result = Result.fromString(resultParam.get()); + // Result.fromString returns Result.FAILURE if there's no match. We don't want that. + if (result.toString().equalsIgnoreCase(resultParam.get())) { + interestingResults.add(result); + } + } + + return new BuildSearchParamProcessor() { + + @Override + public boolean fitsSearchParams(Result result) { + // It fits if it's any of the specified "result" search terms. + return interestingResults.contains(result); + } + + @Override + public boolean fitsSearchParams(Queue.Item item) { + // Queue items don't have a Result. + return false; + } + @Override + public boolean fitsSearchParams(Run run) { + return fitsSearchParams(run.getResult()); + } + }; + } +} diff --git a/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly b/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly index 639002d537..54309319f0 100644 --- a/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly +++ b/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly @@ -27,52 +27,6 @@ THE SOFTWARE. Render build histories. --> - - - - - - -

    - - - - - - + + diff --git a/core/src/main/resources/hudson/widgets/HistoryPageFilter/ajaxBuildHistory.jelly b/core/src/main/resources/hudson/widgets/HistoryPageFilter/ajaxBuildHistory.jelly new file mode 100644 index 0000000000..6fdf095c51 --- /dev/null +++ b/core/src/main/resources/hudson/widgets/HistoryPageFilter/ajaxBuildHistory.jelly @@ -0,0 +1,41 @@ + + + + + + + + +
    ${%User}:
    ${%Password}:
    -
    -
    - -
    - -
    - #${queuedItems.size()==1 ? it.owner.nextBuildNumber - : it.owner.nextBuildNumber+queuedItems.size()-i-1} -
    +
    + + + + #${queuedItems.size()==1 ? it.owner.nextBuildNumber + : it.owner.nextBuildNumber+queuedItems.size()-i-1} + +
    + + +
    -
    - - - - (${%pending}—) - - - (${%pending}) - - - ${item.params} -
    -
    -
    - - - -
    -
    -
    + + + + (${%pending}—) + + + (${%pending}) + + + ${item.params}
    - -
    - - - - - - - -
    -
    -
    - - - - - - - -
    - -
    - - - - -
    -
    -
    +
    + + ${build.displayName} + + + + + + + + -
    +
    -
    +
    + + + + + + + + + + + + + +
    -
    -
    - -
    - -
    - #${queuedItems.size()==1 ? it.owner.nextBuildNumber - : it.owner.nextBuildNumber+queuedItems.size()-i-1} -
    -
    -
    - - - - (${%pending}—) - - - (${%pending}) - - - -
    - -
    -
    -
    -
    -
    - - - -
    -
    -
    -
    + +
    + + +
    +
    + + + \ No newline at end of file diff --git a/core/src/main/resources/hudson/widgets/HistoryPageFilter/entries.jelly b/core/src/main/resources/hudson/widgets/HistoryPageFilter/entries.jelly new file mode 100644 index 0000000000..622a838738 --- /dev/null +++ b/core/src/main/resources/hudson/widgets/HistoryPageFilter/entries.jelly @@ -0,0 +1,29 @@ + + + + + + + \ No newline at end of file diff --git a/core/src/main/resources/hudson/widgets/HistoryPageFilter/queue-items.jelly b/core/src/main/resources/hudson/widgets/HistoryPageFilter/queue-items.jelly new file mode 100644 index 0000000000..be46285a13 --- /dev/null +++ b/core/src/main/resources/hudson/widgets/HistoryPageFilter/queue-items.jelly @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + +
    +
    + +
    + +
    + #${queuedItems.size()==1 ? it.widget.owner.nextBuildNumber + : it.widget.owner.nextBuildNumber+queuedItems.size()-i-1} +
    +
    +
    + + + + (${%pending}—) + + + (${%pending}) + + + +
    + +
    +
    +
    +
    +
    + + + +
    +
    +
    + + +
    +
    +
    diff --git a/core/src/main/resources/hudson/widgets/HistoryWidget/ajaxBuildHistory.jelly b/core/src/main/resources/hudson/widgets/HistoryWidget/ajaxBuildHistory.jelly index 1011d9510e..6684873987 100644 --- a/core/src/main/resources/hudson/widgets/HistoryWidget/ajaxBuildHistory.jelly +++ b/core/src/main/resources/hudson/widgets/HistoryWidget/ajaxBuildHistory.jelly @@ -25,10 +25,6 @@ THE SOFTWARE. - - - - -
    -
    + + \ No newline at end of file diff --git a/core/src/main/resources/hudson/widgets/HistoryWidget/entries.jelly b/core/src/main/resources/hudson/widgets/HistoryWidget/entries.jelly index 2a49d5a698..8c07368d68 100644 --- a/core/src/main/resources/hudson/widgets/HistoryWidget/entries.jelly +++ b/core/src/main/resources/hudson/widgets/HistoryWidget/entries.jelly @@ -27,9 +27,9 @@ THE SOFTWARE. --> - + - - + + \ No newline at end of file diff --git a/core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly b/core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly index 44e3f664e3..215cb4d54a 100644 --- a/core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly +++ b/core/src/main/resources/hudson/widgets/HistoryWidget/entry.jelly @@ -26,10 +26,12 @@ THE SOFTWARE. Render a single build history entry indicated by ${build} --> - - - - + + + + + +
    @@ -42,7 +44,7 @@ THE SOFTWARE. - +
    @@ -59,7 +61,7 @@ THE SOFTWARE.
    - +
    diff --git a/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly b/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly index f43ba94068..d42b56abb2 100644 --- a/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly +++ b/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly @@ -51,10 +51,33 @@ THE SOFTWARE. - + +
    +
    + + + +
    + - - + + + + + + + +
    + x + + + +
    + + + + + - ${%More ...} -
    +
    +
    diff --git a/core/src/test/java/hudson/widgets/HistoryPageFilterTest.java b/core/src/test/java/hudson/widgets/HistoryPageFilterTest.java new file mode 100644 index 0000000000..ab9eeb51c2 --- /dev/null +++ b/core/src/test/java/hudson/widgets/HistoryPageFilterTest.java @@ -0,0 +1,320 @@ +/* + * The MIT License + * + * Copyright (c) 2013-2014, 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.widgets; + +import hudson.model.Job; +import hudson.model.ModelObject; +import hudson.model.Queue; +import hudson.model.Result; +import hudson.model.Run; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * @author tom.fennelly@gmail.com + */ +public class HistoryPageFilterTest { + + /** + * No items. + */ + @Test + public void test_latest_empty_page() { + HistoryPageFilter historyPageFilter = newPage(5, null, null); + List itemList = new ArrayList(); + + historyPageFilter.add(itemList); + Assert.assertEquals(false, historyPageFilter.hasUpPage); + Assert.assertEquals(false, historyPageFilter.hasDownPage); + Assert.assertEquals(true, historyPageFilter.queueItems.isEmpty()); + Assert.assertEquals(true, historyPageFilter.runs.isEmpty()); + } + + /** + * Latest/top page where total number of items < the max page size. + */ + @Test + public void test_latest_partial_page() throws IOException { + HistoryPageFilter historyPageFilter = newPage(5, null, null); + List itemList = new ArrayList(); + + itemList.addAll(newRuns(1, 2)); + itemList.addAll(newQueueItems(3, 4)); + + // want to make sure the list items are ordered by id in descending order + Assert.assertEquals(1, HistoryPageEntry.getEntryId(itemList.get(0))); + historyPageFilter.add(itemList); + Assert.assertEquals(4, HistoryPageEntry.getEntryId(itemList.get(0))); + + Assert.assertEquals(false, historyPageFilter.hasUpPage); + Assert.assertEquals(false, historyPageFilter.hasDownPage); + Assert.assertEquals(2, historyPageFilter.queueItems.size()); + Assert.assertEquals(2, historyPageFilter.runs.size()); + + Assert.assertEquals(4, historyPageFilter.queueItems.get(0).getEntryId()); + Assert.assertEquals(4, historyPageFilter.newestOnPage); + Assert.assertEquals(3, historyPageFilter.queueItems.get(1).getEntryId()); + Assert.assertEquals(2, historyPageFilter.runs.get(0).getEntryId()); + Assert.assertEquals(1, historyPageFilter.runs.get(1).getEntryId()); + Assert.assertEquals(1, historyPageFilter.oldestOnPage); + } + + /** + * Latest/top page where total number of items > the max page size. + */ + @Test + public void test_latest_longer_list() throws IOException { + HistoryPageFilter historyPageFilter = newPage(5, null, null); + List itemList = new ArrayList(); + + itemList.addAll(newRuns(1, 10)); + itemList.addAll(newQueueItems(11, 12)); + + historyPageFilter.add(itemList); + + Assert.assertEquals(false, historyPageFilter.hasUpPage); + Assert.assertEquals(true, historyPageFilter.hasDownPage); + Assert.assertEquals(2, historyPageFilter.queueItems.size()); + Assert.assertEquals(3, historyPageFilter.runs.size()); + + Assert.assertEquals(12, historyPageFilter.queueItems.get(0).getEntryId()); + Assert.assertEquals(12, historyPageFilter.newestOnPage); + Assert.assertEquals(10, historyPageFilter.runs.get(0).getEntryId()); + } + + /** + * Test olderThan (page down) when set to id greater than newest (should never happen). Should be same as not + * specifying newerThan/olderThan. + */ + @Test + public void test_olderThan_gt_newest() throws IOException { + HistoryPageFilter historyPageFilter = newPage(5, null, 11L); + List itemList = new ArrayList(); + + itemList.addAll(newRuns(1, 10)); + historyPageFilter.add(itemList); + + Assert.assertEquals(false, historyPageFilter.hasUpPage); + Assert.assertEquals(true, historyPageFilter.hasDownPage); + Assert.assertEquals(5, historyPageFilter.runs.size()); + + Assert.assertEquals(10, historyPageFilter.newestOnPage); + Assert.assertEquals(6, historyPageFilter.oldestOnPage); + } + + /** + * Test olderThan (page down) when set to id less than the oldest (should never happen). Should just give an + * empty list of builds. + */ + @Test + public void test_olderThan_lt_oldest() throws IOException { + HistoryPageFilter historyPageFilter = newPage(5, null, 0L); + List itemList = new ArrayList(); + + itemList.addAll(newRuns(1, 10)); + historyPageFilter.add(itemList); + + Assert.assertEquals(true, historyPageFilter.hasUpPage); + Assert.assertEquals(false, historyPageFilter.hasDownPage); + Assert.assertEquals(0, historyPageFilter.runs.size()); + } + + /** + * Test olderThan (page down) when set to an id close to the oldest in the list (where + * there's less than a full page older than the supplied olderThan arg). + */ + @Test + public void test_olderThan_leaving_part_page() throws IOException { + HistoryPageFilter historyPageFilter = newPage(5, null, 4L); + List itemList = new ArrayList(); + + itemList.addAll(newRuns(1, 10)); + historyPageFilter.add(itemList); + + Assert.assertEquals(true, historyPageFilter.hasUpPage); + Assert.assertEquals(false, historyPageFilter.hasDownPage); + + // Should only be 3 runs on the page (oldest 3) + Assert.assertEquals(3, historyPageFilter.runs.size()); + + Assert.assertEquals(3, historyPageFilter.newestOnPage); + Assert.assertEquals(1, historyPageFilter.oldestOnPage); + } + + /** + * Test olderThan (page down) when set to an id in the middle. Should be a page up and a page down. + */ + @Test + public void test_olderThan_mid_page() throws IOException { + HistoryPageFilter historyPageFilter = newPage(5, null, 8L); + List itemList = new ArrayList(); + + itemList.addAll(newRuns(1, 10)); + historyPageFilter.add(itemList); + + Assert.assertEquals(true, historyPageFilter.hasUpPage); + Assert.assertEquals(true, historyPageFilter.hasDownPage); + Assert.assertEquals(5, historyPageFilter.runs.size()); + + Assert.assertEquals(7, historyPageFilter.newestOnPage); + Assert.assertEquals(3, historyPageFilter.oldestOnPage); + } + + /** + * Test newerThan (page up) when set to id greater than newest (should never happen). Should be an empty list. + */ + @Test + public void test_newerThan_gt_newest() throws IOException { + HistoryPageFilter historyPageFilter = newPage(5, 11L, null); + List itemList = new ArrayList(); + + itemList.addAll(newRuns(1, 10)); + historyPageFilter.add(itemList); + + Assert.assertEquals(false, historyPageFilter.hasUpPage); + Assert.assertEquals(true, historyPageFilter.hasDownPage); + Assert.assertEquals(0, historyPageFilter.runs.size()); + } + + /** + * Test newerThan (page up) when set to id less than the oldest (should never happen). Should give the oldest + * set of builds. + */ + @Test + public void test_newerThan_lt_oldest() throws IOException { + HistoryPageFilter historyPageFilter = newPage(5, 0L, null); + List itemList = new ArrayList(); + + itemList.addAll(newRuns(1, 10)); + historyPageFilter.add(itemList); + + Assert.assertEquals(true, historyPageFilter.hasUpPage); + Assert.assertEquals(false, historyPageFilter.hasDownPage); + Assert.assertEquals(5, historyPageFilter.runs.size()); + + Assert.assertEquals(5, historyPageFilter.newestOnPage); + Assert.assertEquals(1, historyPageFilter.oldestOnPage); + } + + /** + * Test newerThan (page up) mid range nearer the oldest build in the list. + */ + @Test + public void test_newerThan_near_oldest() throws IOException { + HistoryPageFilter historyPageFilter = newPage(5, 3L, null); + List itemList = new ArrayList(); + + itemList.addAll(newRuns(1, 10)); + historyPageFilter.add(itemList); + + Assert.assertEquals(true, historyPageFilter.hasUpPage); + Assert.assertEquals(true, historyPageFilter.hasDownPage); + Assert.assertEquals(5, historyPageFilter.runs.size()); + + Assert.assertEquals(8, historyPageFilter.newestOnPage); + Assert.assertEquals(4, historyPageFilter.oldestOnPage); + } + + /** + * Test newerThan (page up) mid range nearer the newest build in the list. This works a little different + * in that it will put the 2 builds newer than newerThan on the page and then fill the remaining slots on the + * page with builds equal to and older i.e. it return the newest/latest builds. + */ + @Test + public void test_newerThan_near_newest() throws IOException { + HistoryPageFilter historyPageFilter = newPage(5, 8L, null); + List itemList = new ArrayList(); + + itemList.addAll(newRuns(1, 10)); + historyPageFilter.add(itemList); + + Assert.assertEquals(false, historyPageFilter.hasUpPage); + Assert.assertEquals(true, historyPageFilter.hasDownPage); + Assert.assertEquals(5, historyPageFilter.runs.size()); + + Assert.assertEquals(10, historyPageFilter.newestOnPage); + Assert.assertEquals(6, historyPageFilter.oldestOnPage); + } + + private List newQueueItems(long startId, long endId) { + List items = new ArrayList(); + for (long queueId = startId; queueId <= endId; queueId++) { + items.add(new Queue.MockItem(queueId)); + } + return items; + } + + private List newRuns(long startId, long endId) throws IOException { + List runs = new ArrayList(); + for (long queueId = startId; queueId <= endId; queueId++) { + runs.add(new MockRun(queueId)); + } + return runs; + } + + private HistoryPageFilter newPage(int maxEntries, Long newerThan, Long olderThan) { + HistoryPageFilter pageFilter = new HistoryPageFilter(maxEntries); + if (newerThan != null) { + pageFilter.setNewerThan(newerThan); + } else if (olderThan != null) { + pageFilter.setOlderThan(olderThan); + } + return pageFilter; + } + + @SuppressWarnings("unchecked") + private static class MockRun extends Run { + private final long queueId; + + public MockRun(long queueId) throws IOException { + super(Mockito.mock(Job.class)); + this.queueId = queueId; + } + + @Override + public int compareTo(Run o) { + return 0; + } + + @Override + public Result getResult() { + return result; + } + + @Override + public boolean isBuilding() { + return false; + } + + @Override + public long getQueueId() { + return queueId; + } + } +} diff --git a/core/src/test/java/hudson/widgets/buildsearch/BuildSearchParamProcessorTest.java b/core/src/test/java/hudson/widgets/buildsearch/BuildSearchParamProcessorTest.java new file mode 100644 index 0000000000..12baebc656 --- /dev/null +++ b/core/src/test/java/hudson/widgets/buildsearch/BuildSearchParamProcessorTest.java @@ -0,0 +1,178 @@ +/* + * The MIT License + * + * Copyright (c) 2013-2014, 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.widgets.buildsearch; + +import hudson.model.Result; +import hudson.widgets.buildsearch.processors.DateProcessorFactory; +import org.junit.Assert; +import org.junit.Test; + +import java.util.List; + +/** + * @author tom.fennelly@gmail.com + */ +public class BuildSearchParamProcessorTest { + + @Test + public void test_name() { + BuildSearchParams searchParams = new BuildSearchParams(" name: Build1 name: Build2 "); + List processors = new BuildSearchParamProcessorList(searchParams).getProcessors(); + + Assert.assertEquals(1, processors.size()); + + BuildSearchParamProcessor processor = processors.get(0); + Assert.assertTrue(processor.fitsSearchParams("Build1 was good")); + Assert.assertTrue(processor.fitsSearchParams("The Build2 not so good")); + Assert.assertFalse(processor.fitsSearchParams("Build3")); + } + + @Test + public void test_description() { + BuildSearchParams searchParams = new BuildSearchParams(" desc: Build1 desc: Build2 "); + List processors = new BuildSearchParamProcessorList(searchParams).getProcessors(); + + Assert.assertEquals(1, processors.size()); + + BuildSearchParamProcessor processor = processors.get(0); + Assert.assertTrue(processor.fitsSearchParams("Build1 was good")); + Assert.assertTrue(processor.fitsSearchParams("The Build2 not so good")); + Assert.assertFalse(processor.fitsSearchParams("Build3")); + } + + @Test + public void test_result() { + BuildSearchParams searchParams = new BuildSearchParams(" result: UNSTABLE result: aborted result: BLAH "); + List processors = new BuildSearchParamProcessorList(searchParams).getProcessors(); + + Assert.assertEquals(1, processors.size()); + + BuildSearchParamProcessor processor = processors.get(0); + Assert.assertTrue(processor.fitsSearchParams(Result.UNSTABLE)); + Assert.assertTrue(processor.fitsSearchParams(Result.ABORTED)); + Assert.assertFalse(processor.fitsSearchParams(Result.SUCCESS)); + Assert.assertFalse(processor.fitsSearchParams(Result.FAILURE)); // need to make sure "BLAH" is not interpreted as FAILURE. See Result.fromString. + } + + @Test + public void test_date_from_and_to_ok() { + BuildSearchParams searchParams = new BuildSearchParams("date-from: 2015-02-20 date-to: 2015-03-20"); + + List processors = new BuildSearchParamProcessorList(searchParams).getProcessors(); + + Assert.assertEquals(1, processors.size()); + + BuildSearchParamProcessor processor = processors.get(0); + + Assert.assertFalse(processor.fitsSearchParams(DateProcessorFactory.toTimeInMillis("2015-02-19"))); + Assert.assertTrue(processor.fitsSearchParams(DateProcessorFactory.toTimeInMillis("2015-02-20"))); + Assert.assertTrue(processor.fitsSearchParams(DateProcessorFactory.toTimeInMillis("2015-02-21"))); + Assert.assertTrue(processor.fitsSearchParams(DateProcessorFactory.toTimeInMillis("2015-03-19"))); + Assert.assertFalse(processor.fitsSearchParams(DateProcessorFactory.toTimeInMillis("2015-03-21"))); + } + + /** + * date-to: set to a date before date-from: should result in the date-to: being ignored. + */ + @Test + public void test_date_from_and_to_with_to_before_from() { + BuildSearchParams searchParams = new BuildSearchParams("date-from:2015-02-20 date-to:2015-02-10"); + + List processors = new BuildSearchParamProcessorList(searchParams).getProcessors(); + + Assert.assertEquals(1, processors.size()); + + BuildSearchParamProcessor processor = processors.get(0); + + Assert.assertFalse(processor.fitsSearchParams(DateProcessorFactory.toTimeInMillis("2015-02-19"))); + Assert.assertTrue(processor.fitsSearchParams(DateProcessorFactory.toTimeInMillis("2015-02-20"))); + Assert.assertTrue(processor.fitsSearchParams(DateProcessorFactory.toTimeInMillis("2015-02-21"))); + Assert.assertTrue(processor.fitsSearchParams(DateProcessorFactory.toTimeInMillis("2015-03-21"))); + } + + @Test + public void test_date_short() { + List processors = new BuildSearchParamProcessorList(new BuildSearchParams("date-from: 02-20")).getProcessors(); + BuildSearchParamProcessor processor = processors.get(0); + + Assert.assertFalse(processor.fitsSearchParams(DateProcessorFactory.toTimeInMillis(DateProcessorFactory.getCurrentYearString() + "-02-19"))); + Assert.assertTrue(processor.fitsSearchParams(DateProcessorFactory.toTimeInMillis(DateProcessorFactory.getCurrentYearString() + "-02-20"))); + } + + @Test + public void test_date_today() { + List processors = new BuildSearchParamProcessorList(new BuildSearchParams("date-from: today")).getProcessors(); + BuildSearchParamProcessor processor = processors.get(0); + + long now = System.currentTimeMillis(); + Assert.assertFalse(processor.fitsSearchParams(now - DateProcessorFactory.DAY)); + Assert.assertTrue(processor.fitsSearchParams(now)); + Assert.assertTrue(processor.fitsSearchParams(now + DateProcessorFactory.DAY)); + } + + @Test + public void test_date_last_week_to_today() { + List processors = new BuildSearchParamProcessorList(new BuildSearchParams("date-from: week date-to: today")).getProcessors(); + BuildSearchParamProcessor processor = processors.get(0); + + long now = System.currentTimeMillis(); + Assert.assertFalse(processor.fitsSearchParams(now - (DateProcessorFactory.DAY * 8))); + Assert.assertTrue(processor.fitsSearchParams(now - (DateProcessorFactory.DAY * 7))); + Assert.assertTrue(processor.fitsSearchParams(now - (DateProcessorFactory.DAY * 1))); + Assert.assertFalse(processor.fitsSearchParams(now)); + } + + @Test + public void test_date_days() { + List processors = new BuildSearchParamProcessorList(new BuildSearchParams("date-from: 5 days date-to: 1 day")).getProcessors(); + BuildSearchParamProcessor processor = processors.get(0); + + long now = System.currentTimeMillis(); + Assert.assertFalse(processor.fitsSearchParams(now - (DateProcessorFactory.DAY * 6))); + Assert.assertTrue(processor.fitsSearchParams(now - (DateProcessorFactory.DAY * 5))); + Assert.assertFalse(processor.fitsSearchParams(now)); + } + + @Test + public void test_date_weeks() { + List processors = new BuildSearchParamProcessorList(new BuildSearchParams("date-from: 5 weeks date-to: 1 week")).getProcessors(); + BuildSearchParamProcessor processor = processors.get(0); + + long now = System.currentTimeMillis(); + Assert.assertFalse(processor.fitsSearchParams(now - (DateProcessorFactory.WEEK * 6))); + Assert.assertTrue(processor.fitsSearchParams(now - (DateProcessorFactory.WEEK * 5))); + Assert.assertFalse(processor.fitsSearchParams(now - (DateProcessorFactory.DAY * 6))); + } + + @Test + public void test_date_months() { + List processors = new BuildSearchParamProcessorList(new BuildSearchParams("date-from: 5 months date-to: 1 month")).getProcessors(); + BuildSearchParamProcessor processor = processors.get(0); + + long now = System.currentTimeMillis(); + Assert.assertFalse(processor.fitsSearchParams(now - (DateProcessorFactory.MONTH * 6))); + Assert.assertTrue(processor.fitsSearchParams(now - (DateProcessorFactory.MONTH * 5))); + Assert.assertFalse(processor.fitsSearchParams(now - (DateProcessorFactory.MONTH - DateProcessorFactory.DAY))); + } +} diff --git a/core/src/test/java/hudson/widgets/buildsearch/BuildSearchParamsTest.java b/core/src/test/java/hudson/widgets/buildsearch/BuildSearchParamsTest.java new file mode 100644 index 0000000000..a71f827ed9 --- /dev/null +++ b/core/src/test/java/hudson/widgets/buildsearch/BuildSearchParamsTest.java @@ -0,0 +1,73 @@ +/* + * The MIT License + * + * Copyright (c) 2013-2014, 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.widgets.buildsearch; + +import org.junit.Assert; +import org.junit.Test; + +/** + * @author tom.fennelly@gmail.com + */ +public class BuildSearchParamsTest { + + @Test + public void test_no_params() { + Assert.assertEquals("{name=[], desc=[], result=[], date-from=[], date-to=[]}", new BuildSearchParams("").toString()); + Assert.assertEquals("{name=[], desc=[], result=[], date-from=[], date-to=[]}", new BuildSearchParams("blah").toString()); + Assert.assertEquals("{name=[], desc=[], result=[], date-from=[], date-to=[]}", new BuildSearchParams("name: desc: ").toString()); // whitespace only params should be ignored + } + + @Test + public void test_unknown_search_term() { + try { + new BuildSearchParams("").getParams("blah"); + Assert.fail("Expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + Assert.assertEquals("Unknown search term 'blah'.", e.getMessage()); + } + } + + @Test + public void test_with_params_one_of_each() { + Assert.assertEquals( + "{name=[name:'Build1'], desc=[desc:'something big'], result=[result:'FAILED'], date-from=[], date-to=[]}", + new BuildSearchParams(" result: FAILED Name: Build1 desc: something big ").toString()); + } + + @Test + public void test_with_params_multiples_of_each() { + BuildSearchParams searchParams = + new BuildSearchParams(" result: FAILED name: Build1 desc: something big result:SUCCESS desc: something middle "); + + Assert.assertEquals("[name:'Build1']", + searchParams.getParams("name").toString()); + Assert.assertEquals("[desc:'something big', desc:'something middle']", + searchParams.getParams("desc").toString()); + Assert.assertEquals("[result:'FAILED', result:'SUCCESS']", + searchParams.getParams("result").toString()); + Assert.assertEquals( + "{name=[name:'Build1'], desc=[desc:'something big', desc:'something middle'], result=[result:'FAILED', result:'SUCCESS'], date-from=[], date-to=[]}", + searchParams.toString()); + } +} diff --git a/war/src/main/webapp/css/style.css b/war/src/main/webapp/css/style.css index 31480a0fdc..a1867ea6c4 100644 --- a/war/src/main/webapp/css/style.css +++ b/war/src/main/webapp/css/style.css @@ -967,6 +967,89 @@ table.parameters > tbody:hover { float: right; } +#buildHistoryPage { + position: relative; +} + +#buildHistoryPage .build-search-row td { + position: relative; +} +#buildHistoryPage .build-search-row .clear { + position: absolute; + padding: 0px 4px; + cursor: pointer; + top: 7px; + right: 6px; + opacity: 0.5; +} +#buildHistoryPage .build-search-row .clear:hover { + background-color: #d3d3d3; + border: 1px solid #bbb; + top: 6px; + padding-right: 3px; + border-top-right-radius: 2px; +} +#buildHistoryPage .build-search-row input { + width: 100%; + padding-left: 5px; + padding-right: 20px; +} +#buildHistoryPage .build-search-row table { + width: 100%; +} +#buildHistoryPage .build-search-row .build-search-help { + width: 20px; +} +#buildHistoryPage .build-search-row .icon-help { + position: absolute; + cursor: pointer; + top: 6px; +} + +#buildHistoryPageNav { + position: absolute; + right: -21px; + top: 41px; + border: 1px solid; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + visibility: hidden; +} + +#buildHistoryPageNav .nav { + width: 16px; + height: 16px; + background: no-repeat; + background-position: center; + background-size: 16px 16px; + margin: 4px 2px; + cursor: pointer; +} + +#buildHistoryPageNav.mouseOverSidePanel { + visibility: visible; + border-color: #f0f0f0 !important; +} +#buildHistoryPageNav.mouseOverSidePanelBuildHistory { + border-color: #bbb !important; +} +#buildHistoryPageNav:hover { + border-color: #bbb !important; +} + +#buildHistoryPageNav .pageOne { + background-image: url(../images/16x16/bullseye.png); +} +#buildHistoryPageNav .pageUp { + background-image: url(../images/16x16/go_up.png); +} +#buildHistoryPageNav .pageDown { + background-image: url(../images/16x16/go_down.png); +} +#buildHistoryPageNav .find { + background-image: url(../images/16x16/find.png); +} + .build-row { padding: 3px 4px 3px 4px; } diff --git a/war/src/main/webapp/images/16x16/bullseye.png b/war/src/main/webapp/images/16x16/bullseye.png new file mode 100644 index 0000000000000000000000000000000000000000..442ccf26ddb0e67eb5082451737d70658916d99d GIT binary patch literal 2615 zcmV-73dr?|P)A3ClyUDVJgv#21$2g z!li5n&eP^DT=X=h1&N-iR&i8sAmQ*U0 z;y*xY_>a(EApbTR_NzPW>gqyWT^$-48pzY!+zc+43qGF@eSLlK`F!yCeCX=x{=0zm z_xGc)un@Oz-$rq9vC`j7ojMhcj*eKpdNnjOG=?+>)=;#TNF+i=Mh4Q;)6vw_^wX2j z*4D=Q_3Po_-~fGn{XYvNGcyyBk&)=>=^1o_JRT1^Iy&g=>_kgT3)Feu*Kp?=QM~{%7 zpN~(UKFPFMym&D}LqnmXqw{-!)Ya9&$Hxcn-@m8ICrp?C4-XGmTU)EVlBK1kh>eX! zSy>rXK6dO_golS?#*7)i7RbAI@8It4j;^jQ>gafSdSdO`wP3T^LlV~f{Cvd3#Gs*} z;U7&jY#5@VqF`lZ^=p81b#=kX$q99Jb)?M1#01gN(J(MDpxR2MQdCq_ps1(_A3l75 zP$)!4M+Z0@4!B${jEsz6VPSzebLL>!Fj{H0x3|OJ-ybhuz9eNF4hPq+T?3!bA36{p zA0Iq=^oa0QR#rHD`ZPw497&!1J9q9NDJcmpEiFG>K@Nw5ty{Ok$;k;LMvS2PIdkR= z($mu^HJzB4C|Bl`26FZ4Rh&J0mhjW2O~a*2mngme`t@rB2M43JwpQgMHG1@D1Ox=Y z#>R%)RbO9UYVqvt?GX?V@N+=kzI}@wJ9ePIzaIdgr>BS1)Ku_zJksXgy?Y1^4aL{5 zUuC}6)YOEjsVR(&jnUB1fXd2BO2(M9Z{I$+y1EixB9UO{&Yh^Lsv>2Pk&#%we7WjC zf`Wo@|Nec#$H&KG!GZ;ZPft%rSXh|Mg(%KQc{BR=g*_9 zt&OU4a&p3L}ZuaBIDD_5?l<}|jpwjwt-m+%%A78Ho$;$lQbMpEC* znKK7BZ{EbVZQEdMY%Bu;0QB|sv2NWuq@|@{#flX&$2c=HlkkRyhOoD{CwxUk1>U@Q zqZ*Kmj1008EEWp~4jdqL9UUF;_xC494gmJ<-HU{T1Q{)+h;(#x5D^i9kdP3{_JoCn z;lqaygm-guqm)WoTAK1e`uqDStzl_t2~$&3!Y3yuqobpP@XMAh!>(Pss2wOTFUP4< zr{L`Dj3rB!VDsk9IDY&%o;-O%jb&?Vi|yODQ(Ei7g$sn&)z!s@4I2pm@Zm$Wx3?Ozqhv+4<0;F4oG!%^*;^N)L?CGO<7>3h6)S} zq~eP3@Ngt0CE?q*Zwil9R#p~{963UqM|E{|oIH7w@(yxxawyqj`d!SUHz<(C#zx8* zF(+D7R7ANb%+)F?Dx!pSFnaas6}7WdrcA-qsZ$C6`0-f>FJ^B6ar!TQB1)eK72UU?(^r*$vPfbmYI@U}e@)8tsfiN3>ue0aRpHImJ^XU2c`Kh!k$BrGNc!5Ab-e=94 zMfJs;$M>34sU4}Ut)(;z(>V6__98Jcky>GIZ*QgIb{7{Hn46muK07-bA3uJig0}(s z^5qL&ym+Ddj!d6Eo#L4Rj)jESqh>MF0@pnv3O>yJK4azeRSv$K^F^k>hW!O_u? zia<3rH4zgN0}h8H*X?1m+1R*oqul=3Cr+F=A-96fhFB~{X=y15rnI!QFl*K=-Z!hxm^HEk-hW7S$^!E0G!{IM^@WB*K<0TZlWrX0s6&7l(QC=22Sh@ZrOhW|NmG z5s5?!bG}?I7tzttm^pJMDXXcefs2a^iCZ)@G?0>#f=QDmseaMJ<#G`g7DlXje}6yx z{QRgyouQ#2E?>S32L}g**~Zq^R)ru|u3U-K)Km&YXJ;q8yu7I3DeXU{FpIg5FH&&#Sa6ncS=eM3JVKmG9*kIHEI+VFJ261XJ;8z-_XziFE1}D4P<9$ zhoGRKp=TPUQYpN>y-`q5KslDd!NFLwW{phyZ{NP5qM`!T)zxTiZ6)%hr>6%40|U9~ zQUE9^DS@xAFBOxUnVBIeDd~q7K}sjFJ3Bk!>FG%YRs#aKfB$}rA3y%56WBtb5D5th z$jr>70xcsWBgDqWDs}mz(zQZgUmwn$J4YGE0VQB(X9oud2P)g5%r!+;Ru-;bzmD$i zZmMp@iWLYB4purm_^BJK+}vD*goIG)lj#QyT=ejGJn(ot=<4c1EEc1sr3FHv5as3N z$j{HGXM%Yem1`UzX18u^!KNlzd(Ky Z{SS?I=b8y5K~w+$002ovPDHLkV1iQqC|?=_NnB z_x|5^XZ|yD>V2Q*tvNIAoKQ6tSppyx5C8xW$jeD--0y<-lOGrRer*l!n*;#xAHyUi z)#N25L2Awp7BE{V03a6{pNOLs+e6m1$<7)SME1ciZa4+hsBl2LZOp)k1_`Aj)Y{$p z5@174MEdwGnz|#WABP}^t}f>8yYkG63NA9+uMP5O-c2=|X)iYW6OH!gJvSwe2fQq? z0n(lcFQdZQ(4yLh$YpRYc}QYol5!*f=;MAg!`OlxF6k{IY;5?~X6~*S9_`K(8mY*P zn_C<84aehY07yMbQ`mi%rdt-!A~1t)A`S?$w|en8mYeX{pt}IVLI|MO>)+OxB!(Bn z6+aU%A8CrZ0f031I849*;L3GBx(m2J8{}s@uz7e98_9PMLMFVH} zPk)GR-zD(96J`DwFFrV0E(e^6Ol0o17`T$iU-eB)wH?uYdReBy7xZdm<$1e%;XpDi zo5fdJ*lNCv6hz10%fBo7;v-5Wn1w}UL!x`|_&pq(0+8v~euVcPf0G#cp<<;0YTHMw zV45XC)!O$cBHpRM(WQz*Lce9;IFfP|-`?>v$EJdh%TJ2exxdi^=-T6hpRo3SP>$M> z8X`MfVF0ne+#l=$r#L1G`_hq2K-a8Hf-R-!&2yUCQ0`=+W1Aoq2sSUh z{xl7OaU^sPDB@F(buM3`6a|cFxFl5aC<6=onDxmFIJzTZP-fcmyDe7RqGmY9K+{fB z&*NqE*g=dlme|L{&n6-pN!DaL6snhna50)%9`X3&PHOQ`o1+^}86ShLne83`I6#=& zes~wEh=W@<$^_&Jms;vc$1;DB!8g|+08lMRL=s~QfME>m zGRLFwr#?i#1z}1B=tf~$wCN22gw;-I$^aZ#9hsy>7%8u?rqNsi^&J5;=mVJqso0yX z&|!j-z#oowCxPU~xD6N#xB*dwR1jHy!nZ$h%U{|OS^mWME!!4l#rQz})hLlTJ%kL@ z7o}m2q2a#^*@-fWHtUA1(T@hs%RHgS=(brS3Cq&bdORT$KGO4*ZznwXOZgT)Kka}t z-pKkERTWLK%z3u*7VL!AgLY5SD6^fSW$ih3UWlIQ;Ad{K&}U|_&x8g+@y1YHfl0sW zHdpV*$ad`VNFk#9Ri%02k|B`jL(A2=3wkdBL;tB2`n7Lu5^+q#3}!$1~023>v|k^uW+weFSWb7ySFf4bh z>ev1+r?YSw?_ zFH(B_T|Gi;P~EV&K^67o2>v)GtURn4C=0FYwU6gxi`=GI@Y`3k97`NIA08UH(he

    h=Bo@8M)yUOITK+aIiH^HEw9Dow=wBt(Py8&ysKK5z|cmmJcg|Rc{OM zeMzd+OPFz~w1Bfqhvd!7oGfU2yB0(ZWj#jQ0D_d(U2wO)QM_z=2)9eOfOm9NC*S-1}i#*_CWS?oG zU}9uRL_c!Ask1e48{W%!gQvr)EtIQwZ8Jd zVrFyWa`hB_xhuG4)lOXW+A1d3XZsR4e6KZssh)NKJK9!K*ynY2bwf+nig)#)HP*<2 z(r2kLin)`y(A3#Rr7YT~SEEdmyk{af<2b)?das+Ta~crTl+0b$(PyuCUPakSCM`a;0FdZgMC znYy!c2HP_*h@AYmgL9_3wB+4#@KP}l+Fl|fW48UuQ4Mi8WTffS=)`iOc4e~JP9Xa! z!d65pXPfPwMo{@2a&0bjU&TD4dTK2J_T9aRJKUb>P94e_S~u!%s`4SY@o?a` zL};}TS1`(=;p^~o68KFC0ET0J&7du=vH(Y~5_3SKBH2ML66GfmOso-raW^!=8caVP zH<@n%6S%yOZ^I&&$_)Y4mDHsbF^LwI>;uy8Ybe@6Mn+!D0;2TMF6e1!X=lX2m(WL~ zp45Jtb)%jcwS>!*zWKqQ!44Xvt&i4?TJ3GLT#Hti@Bax89Od-j007yuKNC$}gYggm zKudvX=^}KMmB3~Wc3dXr4yI5pH#^6BGyov#2EISqK@lb(H#=K}R-Ts-vRKoAHd>TGTS){v6bc{%S9oN#x0gozucJ)GfhBmZYd3JN!KhB+c&4)&lwc1=tj z-XX;3>Hj$T@Ax}Ts2l8mp6ucOq;;Pl_a6=Sb1ok4|JuH%ivE#;)nIN=TU{xb9n>Cv z??YUGU-U2d|5N0j`gj9EY3&D9gP$_*Om3{k%V zb&P+ho~+WSY{>s)@li^@T|=t8%<6M>b#(cj>r{5v>YGg;_a`@YH>IQSrKvgL=BreA z8uCrZLaBt*9cbn*@H4609mdt1%$Xmj$n|nN4izP3R&MUI%aiTcBjnnel(@J!;^NTc z==3!A>sOYe!^1LYCB#SvBjxkw%#so=kDE(@f&PA6>gSfTb8}-ovCOP=bpA0hF{HyA z&IV$0l;L53--pYR9;Z9;%S}QeB4fFViCew#>}xwa*3*&QYA?#Fs|5;*igNPum}cka zNm1hiB8V-*^|iHO)bZxKIcMy8KTZw~HABNECYO6yxp{e`#RfIqBO@c$=gIz!zITRb z)fE+{@3MJum{n3U!@_`t7@wGoD=RAzs3Yj*IgUHEinoRr(2tJDk_s{ zj(GlASVF5`YibhH#XLJh-~Co^`{8}{ou6DuRds5eq?e=YBRO|Wem*mj5T`#q{fSPA zv|n*{Lqn>09ZX6p$eCqgW#~-^mdoLC8c;$_f*1%Nhi^TllQ&SVMH!ILa zo4U^&IcT*W%)5dd>~Sw!brh_?Nnh zC=`k;@8~sSpKkVahFaY7b}M_#e~gm$XBc1zN!8_^y z%4WP#?0bC?9R-Svh_E**S`~_nii| zj|rb|!o=nWyw=gloB!TDY!d#Z$w4n^l2+6_d|D%z)$4r!Z5vkRr>GI*aD&k%tl)^` zmY$u<;gpPwuAzssQ!T@qem~%w5htS%1k2)iOMh$V?IX;&&Y4O}*G~zi$ClBzvmFav zpU%!)cDA-ayIHkAyLvG0md)g^1ljamv<|L}od01O5Xu5Uq6p literal 0 HcmV?d00001 diff --git a/war/src/main/webapp/images/16x16/go_down.png b/war/src/main/webapp/images/16x16/go_down.png new file mode 100644 index 0000000000000000000000000000000000000000..54de8f7ec29e69911d1b36653fb27d023e1bc8b8 GIT binary patch literal 567 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1rX+877lwZyI{s(^d7K3vkw8)2 zYaq-xA-{4CNU*HHF&#*Q^)giWEM3OHz-aI3;uvCa`s}2QUd)aHZTmfsXiQ9C=~lR| z!RXkc&GMLAL-Xi8t)=}F**y|-C&sDxcC=1#GH7jKR=&Z}xPVPDq3KX;Vc*rt>T<;; zmv5#$|NngU-BhuEu^urOW++(+2PF3XS-+~rpi7Cn)A+OY_Qay%9rj(fJRSDkJFN0u zcKc+89S_R_(;2iH6e=c~ce%~mmoO!N1IwCO2a5W94_uwjAjrJo&F6G(yLe}XXn~tj z7U?`f3>mj9b!96h&s2LKdmVGT^dqxkYQ?_0E39@@94lJgcbDUIa&vIv`v*IMIi_B^ zeOL7Rvll^X3SQgqo%U<`chhsPySdd%4u(hKv$xhUT={i$S>;?!27`55PCMJ|`Ly9u zn#^|L{h}te7B}yx_|x9oBj8`Khue*DE@kS?v#mA zZwp^dp0up4+UIdQOX;$`PbWw;E5`9H-y6He$y3yC@9Z}dz8-tH!&B-*%Kos8O}C{| zeTB|EQ;FPcdgw2c=Uh+wH$u6GdD}GJ`28}QcEjTMb^Y~g?(6K_b}aMSQH(J!i(a})sl6BM_4e6JcdG1G8I@Zq? zc>Q^svFfd<-lweNhoV92SKxJHzuB$lLFB^RXvDF!10Ljzp{ z3tdBl5JOWd14Aog6Kw+{D+2@X&}dLRAT;FWr(~v8;?`ir@pvjwgCxj?;QX|b^2DN4 lhVt@qz0ADq;^f4FRK5J7^x5xhq=1STJYD@<);T3K0RW-7&}IMt literal 0 HcmV?d00001 diff --git a/war/src/main/webapp/scripts/hudson-behavior.js b/war/src/main/webapp/scripts/hudson-behavior.js index 270ab19cbc..270195fd53 100644 --- a/war/src/main/webapp/scripts/hudson-behavior.js +++ b/war/src/main/webapp/scripts/hudson-behavior.js @@ -1583,11 +1583,12 @@ function fireBuildHistoryChanged() { function updateBuildHistory(ajaxUrl,nBuild) { if(isRunAsTest) return; var bh = $('buildHistory'); + var buildHistoryPage = $('buildHistoryPage'); bh.headers = ["n",nBuild]; function getDataTable(buildHistoryDiv) { - return $(buildHistoryDiv).getElementsBySelector('table.pane')[0]; + return $(buildHistoryDiv).getElementsBySelector('table.pane')[0]; } var leftRightPadding = 4; @@ -1884,7 +1885,6 @@ function updateBuildHistory(ajaxUrl,nBuild) { } } - var updateBuildsRefreshInterval = 5000; function updateBuilds() { if(isPageVisible()){ if (bh.headers == null) { @@ -1898,8 +1898,12 @@ function updateBuildHistory(ajaxUrl,nBuild) { var rows = dataTable.rows; //delete rows with transitive data - while (rows.length > 0 && Element.hasClassName(rows[0], "transitive")) { - Element.remove(rows[0]); + var firstBuildRow = 0; + if (Element.hasClassName(rows[firstBuildRow], "build-search-row")) { + firstBuildRow++; + } + while (rows.length > 0 && Element.hasClassName(rows[firstBuildRow], "transitive")) { + Element.remove(rows[firstBuildRow]); } // insert new rows @@ -1907,8 +1911,9 @@ function updateBuildHistory(ajaxUrl,nBuild) { div.innerHTML = rsp.responseText; Behaviour.applySubtree(div); - var pivot = rows[0]; - var newRows = getDataTable(div).rows; + var pivot = rows[firstBuildRow]; + var newDataTable = getDataTable(div); + var newRows = newDataTable.rows; while (newRows.length > 0) { if (pivot !== undefined) { // The data table has rows. Insert before a "pivot" row (first row). @@ -1917,26 +1922,201 @@ function updateBuildHistory(ajaxUrl,nBuild) { // The data table has no rows. In this case, we just add all new rows directly to the // table, one after the other i.e. we don't insert before a "pivot" row (first row). dataTable.appendChild(newRows[0]); - } + } + } + + if (Element.hasClassName(newDataTable, 'hasPageData')) { + buildHistoryPage.setAttribute('page-entry-newest', newDataTable.getAttribute('page-entry-newest')); } // next update bh.headers = ["n",rsp.getResponseHeader("n")]; - window.setTimeout(updateBuilds, updateBuildsRefreshInterval); - checkAllRowCellOverflows(); + createRefreshTimeout(); } - }); - } else { + }); + } else { // Reschedule again - window.setTimeout(updateBuilds, updateBuildsRefreshInterval); + createRefreshTimeout(); } } - window.setTimeout(updateBuilds, updateBuildsRefreshInterval); + + var updateBuildsRefreshInterval = 5000; + var buildRefreshTimeout; + function createRefreshTimeout() { + cancelRefreshTimeout(); + buildRefreshTimeout = window.setTimeout(updateBuilds, updateBuildsRefreshInterval); + } + function cancelRefreshTimeout() { + if (buildRefreshTimeout) { + window.clearTimeout(buildRefreshTimeout); + buildRefreshTimeout = undefined; + } + } + + createRefreshTimeout(); onBuildHistoryChange(function() { checkAllRowCellOverflows(); }); + + function setupHistoryNav() { + var sidePanel = $('side-panel'); + var buildHistoryPageNav = $('buildHistoryPageNav'); + + // Show/hide the nav as the mouse moves into the sidepanel and build history. + sidePanel.observe('mouseover', function() { + Element.addClassName($(buildHistoryPageNav), "mouseOverSidePanel"); + }); + sidePanel.observe('mouseout', function() { + Element.removeClassName($(buildHistoryPageNav), "mouseOverSidePanel"); + }); + bh.observe('mouseover', function() { + Element.addClassName($(buildHistoryPageNav), "mouseOverSidePanelBuildHistory"); + }); + bh.observe('mouseout', function() { + Element.removeClassName($(buildHistoryPageNav), "mouseOverSidePanelBuildHistory"); + }); + + var pageSearchInput = Element.getElementsBySelector(bh, '.build-search-row input')[0]; + var pageSearchClear = Element.getElementsBySelector(bh, '.build-search-row .clear')[0]; + var pageOne = Element.getElementsBySelector(buildHistoryPageNav, '.pageOne')[0]; + var pageUp = Element.getElementsBySelector(buildHistoryPageNav, '.pageUp')[0]; + var pageDown = Element.getElementsBySelector(buildHistoryPageNav, '.pageDown')[0]; + + function hasPageUp() { + return buildHistoryPage.getAttribute('page-has-up') === 'true'; + } + function hasPageDown() { + return buildHistoryPage.getAttribute('page-has-down') === 'true'; + } + function getNewestEntryId() { + return parseInt(buildHistoryPage.getAttribute('page-entry-newest')); + } + function getOldestEntryId() { + return parseInt(buildHistoryPage.getAttribute('page-entry-oldest')); + } + function updatePageParams(dataTable) { + buildHistoryPage.setAttribute('page-has-up', dataTable.getAttribute('page-has-up')); + buildHistoryPage.setAttribute('page-has-down', dataTable.getAttribute('page-has-down')); + buildHistoryPage.setAttribute('page-entry-newest', dataTable.getAttribute('page-entry-newest')); + buildHistoryPage.setAttribute('page-entry-oldest', dataTable.getAttribute('page-entry-oldest')); + } + function togglePageUpDown() { + Element.removeClassName($(buildHistoryPageNav), "hasUpPage"); + Element.removeClassName($(buildHistoryPageNav), "hasDownPage"); + if (hasPageUp()) { + Element.addClassName($(buildHistoryPageNav), "hasUpPage"); + } + if (hasPageDown()) { + Element.addClassName($(buildHistoryPageNav), "hasDownPage"); + } + } + function logPageParams() { + console.log('-----'); + console.log('Has up: ' + hasPageUp()); + console.log('Has down: ' + hasPageDown()); + console.log('Newest: ' + getNewestEntryId()); + console.log('Oldest: ' + getOldestEntryId()); + console.log('-----'); + } + + function loadPage(params, focusOnSearch) { + var searchString = pageSearchInput.value; + + if (searchString !== '') { + if (params === undefined) { + params = {}; + } + params.search = searchString; + } + + new Ajax.Request(ajaxUrl + toQueryString(params), { + onSuccess: function(rsp) { + var dataTable = getDataTable(bh); + var rows = dataTable.rows; + + // delete all rows + var searchRow; + if (Element.hasClassName(rows[0], "build-search-row")) { + searchRow = rows[0]; + } + while (rows.length > 0) { + Element.remove(rows[0]); + } + if (searchRow) { + dataTable.appendChild(searchRow); + } + + // insert new rows + var div = document.createElement('div'); + div.innerHTML = rsp.responseText; + Behaviour.applySubtree(div); + + var newDataTable = getDataTable(div); + var newRows = newDataTable.rows; + while (newRows.length > 0) { + dataTable.appendChild(newRows[0]); + } + + checkAllRowCellOverflows(); + updatePageParams(newDataTable); + togglePageUpDown(); + if (!hasPageUp()) { + createRefreshTimeout(); + } + + if (focusOnSearch) { + pageSearchInput.focus(); + } + //logPageParams(); + } + }); + } + + pageSearchInput.observe('keypress', function(e) { + var key = e.which || e.keyCode; + // On enter + if (key === 13) { + loadPage({}, true); + } + }); + pageSearchClear.observe('click', function() { + pageSearchInput.value = ''; + loadPage({}, true); + }); + pageOne.observe('click', function() { + loadPage(); + }); + pageUp.observe('click', function() { + loadPage({'newer-than': getNewestEntryId()}); + }); + pageDown.observe('click', function() { + cancelRefreshTimeout(); + loadPage({'older-than': getOldestEntryId()}); + }); + + togglePageUpDown(); + //logPageParams(); + } + setupHistoryNav(); +} + +function toQueryString(params) { + var query = ''; + if (params) { + for (var paramName in params) { + if (params.hasOwnProperty(paramName)) { + if (query === '') { + query = '?'; + } else { + query += '&'; + } + query += paramName + '=' + encodeURIComponent(params[paramName]); + } + } + } + return query; } function getElementOverflowParams(element) { From 85b3b1bc983304caa32ff0833ea7ef0a011c3e0e Mon Sep 17 00:00:00 2001 From: tfennelly Date: Sat, 11 Apr 2015 14:07:07 +0100 Subject: [PATCH 0244/2573] Fixed screwy indent --- core/src/main/java/hudson/model/Queue.java | 29 +++++++++++----------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index 47fc2c6ad3..f2d675932c 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -2485,24 +2485,23 @@ public class Queue extends ResourceController implements Saveable { */ @SuppressWarnings("unchecked") public static final class MockItem extends Item { + public MockItem(long id) { + super(null, Collections.EMPTY_LIST, id, null); + } - public MockItem(long id) { - super(null, Collections.EMPTY_LIST, id, null); - } + @Override + public CauseOfBlockage getCauseOfBlockage() { + return null; + } - @Override - public CauseOfBlockage getCauseOfBlockage() { - return null; - } + @Override + void enter(Queue q) { + } - @Override - void enter(Queue q) { - } - - @Override - boolean leave(Queue q) { - return true; - } + @Override + boolean leave(Queue q) { + return true; + } } private static final Logger LOGGER = Logger.getLogger(Queue.class.getName()); From 7c28ed8b7d34a7c3f3fc42d8e2683a1e04395cc0 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Sun, 12 Apr 2015 00:24:28 +0100 Subject: [PATCH 0245/2573] Moved Mock Queue.Item out into test/java Not sure why I ever had it in Queue.MockItem. I must have wrongly though it was private/protected in some way that did not allow it to live anywhere else. --- core/src/main/java/hudson/model/Queue.java | 26 -------- core/src/test/java/hudson/model/MockItem.java | 66 +++++++++++++++++++ .../hudson/widgets/HistoryPageFilterTest.java | 4 +- 3 files changed, 68 insertions(+), 28 deletions(-) create mode 100644 core/src/test/java/hudson/model/MockItem.java diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index f2d675932c..12d3078927 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -2478,32 +2478,6 @@ public class Queue extends ResourceController implements Saveable { } } - /** - * Mock queue Item used for unit testing. - *

    - * No other clean way to effectively mock Item. - */ - @SuppressWarnings("unchecked") - public static final class MockItem extends Item { - public MockItem(long id) { - super(null, Collections.EMPTY_LIST, id, null); - } - - @Override - public CauseOfBlockage getCauseOfBlockage() { - return null; - } - - @Override - void enter(Queue q) { - } - - @Override - boolean leave(Queue q) { - return true; - } - } - private static final Logger LOGGER = Logger.getLogger(Queue.class.getName()); /** diff --git a/core/src/test/java/hudson/model/MockItem.java b/core/src/test/java/hudson/model/MockItem.java new file mode 100644 index 0000000000..f0b244be7e --- /dev/null +++ b/core/src/test/java/hudson/model/MockItem.java @@ -0,0 +1,66 @@ +/* + * The MIT License + * + * Copyright (c) 2013-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.model; + +import hudson.model.queue.CauseOfBlockage; + +import java.util.Collections; +import java.util.List; + +/** + * @author tom.fennelly@gmail.com + */ +public class MockItem extends Queue.Item { + + public MockItem(long id) { + super(null, Collections.emptyList(), id, null); + } + + public MockItem(Queue.Task task, List actions, long id) { + super(task, actions, id, null); + } + + /** + * Override as needed. + */ + @Override + public CauseOfBlockage getCauseOfBlockage() { + return null; + } + + /** + * Override as needed. + */ + @Override + void enter(Queue q) { + } + + /** + * Override as needed. + */ + @Override + boolean leave(Queue q) { + return true; + } +} diff --git a/core/src/test/java/hudson/widgets/HistoryPageFilterTest.java b/core/src/test/java/hudson/widgets/HistoryPageFilterTest.java index ab9eeb51c2..de1def0ce9 100644 --- a/core/src/test/java/hudson/widgets/HistoryPageFilterTest.java +++ b/core/src/test/java/hudson/widgets/HistoryPageFilterTest.java @@ -24,8 +24,8 @@ package hudson.widgets; import hudson.model.Job; +import hudson.model.MockItem; import hudson.model.ModelObject; -import hudson.model.Queue; import hudson.model.Result; import hudson.model.Run; import org.junit.Assert; @@ -265,7 +265,7 @@ public class HistoryPageFilterTest { private List newQueueItems(long startId, long endId) { List items = new ArrayList(); for (long queueId = startId; queueId <= endId; queueId++) { - items.add(new Queue.MockItem(queueId)); + items.add(new MockItem(queueId)); } return items; } From c9a6c3f8de327f089820dbbcc7e0207a3b734918 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Sun, 26 Apr 2015 09:39:14 +0100 Subject: [PATCH 0246/2573] Build History pagination/search tweaks based on feedback from @oleg-nenashev --- .../java/hudson/widgets/BuildHistoryWidget.java | 2 +- .../java/hudson/widgets/HistoryPageEntry.java | 7 +++++++ .../main/java/hudson/widgets/HistoryWidget.java | 17 +++++++++-------- .../processors/DateProcessorFactory.java | 15 ++++++++++++--- .../processors/DescriptionProcessorFactory.java | 9 +++++++-- .../processors/NameProcessorFactory.java | 9 +++++++-- .../processors/ResultProcessorFactory.java | 9 +++++++-- .../java/hudson/tasks/BuildTriggerTest.java | 2 +- 8 files changed, 51 insertions(+), 19 deletions(-) diff --git a/core/src/main/java/hudson/widgets/BuildHistoryWidget.java b/core/src/main/java/hudson/widgets/BuildHistoryWidget.java index 871e888a6f..7410f5ca93 100644 --- a/core/src/main/java/hudson/widgets/BuildHistoryWidget.java +++ b/core/src/main/java/hudson/widgets/BuildHistoryWidget.java @@ -72,7 +72,7 @@ public class BuildHistoryWidget extends HistoryWidget { } @Override - public HistoryPageFilter getPage() { + public HistoryPageFilter getHistoryPageFilter() { final HistoryPageFilter historyPageFilter = newPageFilter(); List items = new LinkedList(); diff --git a/core/src/main/java/hudson/widgets/HistoryPageEntry.java b/core/src/main/java/hudson/widgets/HistoryPageEntry.java index d819650301..c71eb60c41 100644 --- a/core/src/main/java/hudson/widgets/HistoryPageEntry.java +++ b/core/src/main/java/hudson/widgets/HistoryPageEntry.java @@ -29,6 +29,13 @@ import hudson.model.Run; import javax.annotation.Nonnull; /** + * Represents an entry used by the {@link HistoryPageFilter}. + * + *

    + * Wraps {@link Queue.Item} and {@link Run} instances from the build queue, normalizing + * access to the info required for pagination. + * + * * @author tom.fennelly@gmail.com */ public class HistoryPageEntry { diff --git a/core/src/main/java/hudson/widgets/HistoryWidget.java b/core/src/main/java/hudson/widgets/HistoryWidget.java index 90f86d3fcf..3fe3aa43b4 100644 --- a/core/src/main/java/hudson/widgets/HistoryWidget.java +++ b/core/src/main/java/hudson/widgets/HistoryWidget.java @@ -26,15 +26,14 @@ package hudson.widgets; import hudson.Functions; import hudson.model.ModelObject; import hudson.model.Run; -import hudson.util.Iterators; import org.apache.commons.collections.IteratorUtils; import org.kohsuke.stapler.Header; -import org.kohsuke.stapler.HttpResponses; import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; +import javax.annotation.CheckForNull; import javax.servlet.ServletException; import java.io.IOException; import java.util.ArrayList; @@ -42,8 +41,6 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; -import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; - /** * Displays the history of records (normally {@link Run}s) on the side panel. * @@ -160,9 +157,9 @@ public class HistoryWidget extends Widget { } /** - * Render a "page" of records. + * Get a {@link HistoryPageFilter} for rendering a page of queue items. */ - public HistoryPageFilter getPage() { + public HistoryPageFilter getHistoryPageFilter() { HistoryPageFilter historyPageFilter = newPageFilter(); historyPageFilter.add(IteratorUtils.toList(baseList.iterator())); @@ -238,7 +235,7 @@ public class HistoryWidget extends Widget { firstTransientBuildKey = nn; // all builds >= nn should be marked transient } - HistoryPageFilter page = getPage(); + HistoryPageFilter page = getHistoryPageFilter(); updateFirstTransientBuildKey(page.runs); req.getView(page,"ajaxBuildHistory.jelly").forward(req,rsp); } @@ -263,7 +260,11 @@ public class HistoryWidget extends Widget { String getNextKey(String key); } - private Long getPagingParam(StaplerRequest currentRequest, String name) { + private Long getPagingParam(@CheckForNull StaplerRequest currentRequest, @CheckForNull String name) { + if (currentRequest == null || name == null) { + return null; + } + String paramVal = currentRequest.getParameter(name); if (paramVal == null) { return null; diff --git a/core/src/main/java/hudson/widgets/buildsearch/processors/DateProcessorFactory.java b/core/src/main/java/hudson/widgets/buildsearch/processors/DateProcessorFactory.java index 95a5679298..001bffb079 100644 --- a/core/src/main/java/hudson/widgets/buildsearch/processors/DateProcessorFactory.java +++ b/core/src/main/java/hudson/widgets/buildsearch/processors/DateProcessorFactory.java @@ -51,7 +51,16 @@ public class DateProcessorFactory extends BuildSearchParamProcessorFactory { public static final long WEEK = DAY * 7; public static final long MONTH = WEEK * 4; - private static final String[] SEARCH_TERMS = new String[] {"date-from", "date-to"}; + /** + * "date-from" search term. + */ + public static final String DATE_FROM_ST = "date-from"; + /** + * "date-to" search term. + */ + public static final String DATE_TO_ST = "date-to"; + + private static final String[] SEARCH_TERMS = new String[] {DATE_FROM_ST, DATE_TO_ST}; /** * {@inheritDoc} @@ -102,8 +111,8 @@ public class DateProcessorFactory extends BuildSearchParamProcessorFactory { private Long dateTo; private DateFromTo(BuildSearchParams searchParams) { - final List dateFromParams = searchParams.getParams(SEARCH_TERMS[0]); - final List dateToParams = searchParams.getParams(SEARCH_TERMS[1]); + final List dateFromParams = searchParams.getParams(DATE_FROM_ST); + final List dateToParams = searchParams.getParams(DATE_TO_ST); if (dateFromParams.isEmpty() && dateToParams.isEmpty()) { // none of the date search terms are specified diff --git a/core/src/main/java/hudson/widgets/buildsearch/processors/DescriptionProcessorFactory.java b/core/src/main/java/hudson/widgets/buildsearch/processors/DescriptionProcessorFactory.java index 60b917df16..82ee4a5315 100644 --- a/core/src/main/java/hudson/widgets/buildsearch/processors/DescriptionProcessorFactory.java +++ b/core/src/main/java/hudson/widgets/buildsearch/processors/DescriptionProcessorFactory.java @@ -38,7 +38,12 @@ import java.util.List; */ public class DescriptionProcessorFactory extends BuildSearchParamProcessorFactory { - private static final String[] SEARCH_TERMS = new String[] {"desc"}; // Build description + /** + * "desc" (description) search term. + */ + public static final String DESC_ST = "desc"; + + private static final String[] SEARCH_TERMS = new String[] {DESC_ST}; // Build description /** * {@inheritDoc} @@ -53,7 +58,7 @@ public class DescriptionProcessorFactory extends BuildSearchParamProcessorFactor */ @Override public BuildSearchParamProcessor createProcessor(BuildSearchParams searchParams) { - final List descParams = searchParams.getParams(SEARCH_TERMS[0]); + final List descParams = searchParams.getParams(DESC_ST); if (descParams.isEmpty()) { // "desc" search term not specified in search diff --git a/core/src/main/java/hudson/widgets/buildsearch/processors/NameProcessorFactory.java b/core/src/main/java/hudson/widgets/buildsearch/processors/NameProcessorFactory.java index fff9f24747..a94e14cc97 100644 --- a/core/src/main/java/hudson/widgets/buildsearch/processors/NameProcessorFactory.java +++ b/core/src/main/java/hudson/widgets/buildsearch/processors/NameProcessorFactory.java @@ -38,7 +38,12 @@ import java.util.List; */ public class NameProcessorFactory extends BuildSearchParamProcessorFactory { - private static final String[] SEARCH_TERMS = new String[] {"name"}; // Build name + /** + * "name" search term. + */ + public static final String NAME_ST = "name"; + + private static final String[] SEARCH_TERMS = new String[] {NAME_ST}; // Build name /** * {@inheritDoc} @@ -53,7 +58,7 @@ public class NameProcessorFactory extends BuildSearchParamProcessorFactory { */ @Override public BuildSearchParamProcessor createProcessor(BuildSearchParams searchParams) { - final List nameParams = searchParams.getParams(SEARCH_TERMS[0]); + final List nameParams = searchParams.getParams(NAME_ST); if (nameParams.isEmpty()) { // "name" search term not specified in search diff --git a/core/src/main/java/hudson/widgets/buildsearch/processors/ResultProcessorFactory.java b/core/src/main/java/hudson/widgets/buildsearch/processors/ResultProcessorFactory.java index e7e69a912b..8c6987674d 100644 --- a/core/src/main/java/hudson/widgets/buildsearch/processors/ResultProcessorFactory.java +++ b/core/src/main/java/hudson/widgets/buildsearch/processors/ResultProcessorFactory.java @@ -40,7 +40,12 @@ import java.util.List; */ public class ResultProcessorFactory extends BuildSearchParamProcessorFactory { - private static final String[] SEARCH_TERMS = new String[] {"result"}; // Build result. TODO: Could do "status" too or maybe that's different + /** + * "result" search term. + */ + public static final String RESULT_ST = "result"; + + private static final String[] SEARCH_TERMS = new String[] {RESULT_ST}; // TODO: Could do "status" too or maybe that's different /** * {@inheritDoc} @@ -55,7 +60,7 @@ public class ResultProcessorFactory extends BuildSearchParamProcessorFactory { */ @Override public BuildSearchParamProcessor createProcessor(BuildSearchParams searchParams) { - List resultParams = searchParams.getParams(SEARCH_TERMS[0]); + List resultParams = searchParams.getParams(RESULT_ST); if (resultParams.isEmpty()) { // "result" search term not specified in search diff --git a/test/src/test/java/hudson/tasks/BuildTriggerTest.java b/test/src/test/java/hudson/tasks/BuildTriggerTest.java index efd9e474cc..0a55bf6ff6 100644 --- a/test/src/test/java/hudson/tasks/BuildTriggerTest.java +++ b/test/src/test/java/hudson/tasks/BuildTriggerTest.java @@ -209,7 +209,7 @@ public class BuildTriggerTest { /* The long way: WebClient wc = createWebClient(); wc.login("alice"); - HtmlPage page = wc.getPage(upstream, "configure"); + HtmlPage page = wc.getHistoryPageFilter(upstream, "configure"); HtmlForm config = page.getFormByName("config"); config.getButtonByCaption("Add post-build action").click(); // lib/hudson/project/config-publishers2.jelly page.getAnchorByText("Build other projects").click(); From 5dfe78d2fcda17d92226af141c9522942b228330 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Sun, 26 Apr 2015 09:52:18 +0100 Subject: [PATCH 0247/2573] Moved Build History pagination and search classes to jenkins as requested by @jglick I understand the motivation for this but I think it creates a bit of a maint/comprehension issue in that splits related classes across 2 different package hierarchies. I know we'll say that's ok but I don't like it. Just say'n. --- .../main/java/hudson/widgets/BuildHistoryWidget.java | 2 +- core/src/main/java/hudson/widgets/HistoryWidget.java | 4 +++- .../widgets/HistoryPageEntry.java | 2 +- .../widgets/HistoryPageFilter.java | 8 ++++---- .../buildsearch/BuildSearchParamProcessor.java | 5 +---- .../BuildSearchParamProcessorFactory.java | 12 ++++++------ .../buildsearch/BuildSearchParamProcessorList.java | 8 ++++---- .../widgets/buildsearch/BuildSearchParams.java | 2 +- .../widgets/buildsearch/README.md | 0 .../buildsearch/processors/DateProcessorFactory.java | 8 ++++---- .../processors/DescriptionProcessorFactory.java | 8 ++++---- .../buildsearch/processors/NameProcessorFactory.java | 8 ++++---- .../processors/ResultProcessorFactory.java | 8 ++++---- .../widgets/HistoryPageFilterTest.java | 4 +++- .../buildsearch/BuildSearchParamProcessorTest.java | 4 ++-- .../widgets/buildsearch/BuildSearchParamsTest.java | 2 +- 16 files changed, 43 insertions(+), 42 deletions(-) rename core/src/main/java/{hudson => jenkins}/widgets/HistoryPageEntry.java (99%) rename core/src/main/java/{hudson => jenkins}/widgets/HistoryPageFilter.java (98%) rename core/src/main/java/{hudson => jenkins}/widgets/buildsearch/BuildSearchParamProcessor.java (97%) rename core/src/main/java/{hudson => jenkins}/widgets/buildsearch/BuildSearchParamProcessorFactory.java (91%) rename core/src/main/java/{hudson => jenkins}/widgets/buildsearch/BuildSearchParamProcessorList.java (92%) rename core/src/main/java/{hudson => jenkins}/widgets/buildsearch/BuildSearchParams.java (99%) rename core/src/main/java/{hudson => jenkins}/widgets/buildsearch/README.md (100%) rename core/src/main/java/{hudson => jenkins}/widgets/buildsearch/processors/DateProcessorFactory.java (96%) rename core/src/main/java/{hudson => jenkins}/widgets/buildsearch/processors/DescriptionProcessorFactory.java (92%) rename core/src/main/java/{hudson => jenkins}/widgets/buildsearch/processors/NameProcessorFactory.java (92%) rename core/src/main/java/{hudson => jenkins}/widgets/buildsearch/processors/ResultProcessorFactory.java (93%) rename core/src/test/java/{hudson => jenkins}/widgets/HistoryPageFilterTest.java (99%) rename core/src/test/java/{hudson => jenkins}/widgets/buildsearch/BuildSearchParamProcessorTest.java (98%) rename core/src/test/java/{hudson => jenkins}/widgets/buildsearch/BuildSearchParamsTest.java (98%) diff --git a/core/src/main/java/hudson/widgets/BuildHistoryWidget.java b/core/src/main/java/hudson/widgets/BuildHistoryWidget.java index 7410f5ca93..c55da23e57 100644 --- a/core/src/main/java/hudson/widgets/BuildHistoryWidget.java +++ b/core/src/main/java/hudson/widgets/BuildHistoryWidget.java @@ -23,10 +23,10 @@ */ package hudson.widgets; -import hudson.model.ModelObject; import jenkins.model.Jenkins; import hudson.model.Queue.Item; import hudson.model.Queue.Task; +import jenkins.widgets.HistoryPageFilter; import org.apache.commons.collections.IteratorUtils; import java.util.Collection; diff --git a/core/src/main/java/hudson/widgets/HistoryWidget.java b/core/src/main/java/hudson/widgets/HistoryWidget.java index 3fe3aa43b4..0059680ef5 100644 --- a/core/src/main/java/hudson/widgets/HistoryWidget.java +++ b/core/src/main/java/hudson/widgets/HistoryWidget.java @@ -27,6 +27,8 @@ import hudson.Functions; import hudson.model.ModelObject; import hudson.model.Run; +import jenkins.widgets.HistoryPageEntry; +import jenkins.widgets.HistoryPageFilter; import org.apache.commons.collections.IteratorUtils; import org.kohsuke.stapler.Header; import org.kohsuke.stapler.Stapler; @@ -157,7 +159,7 @@ public class HistoryWidget extends Widget { } /** - * Get a {@link HistoryPageFilter} for rendering a page of queue items. + * Get a {@link jenkins.widgets.HistoryPageFilter} for rendering a page of queue items. */ public HistoryPageFilter getHistoryPageFilter() { HistoryPageFilter historyPageFilter = newPageFilter(); diff --git a/core/src/main/java/hudson/widgets/HistoryPageEntry.java b/core/src/main/java/jenkins/widgets/HistoryPageEntry.java similarity index 99% rename from core/src/main/java/hudson/widgets/HistoryPageEntry.java rename to core/src/main/java/jenkins/widgets/HistoryPageEntry.java index c71eb60c41..97451f93b7 100644 --- a/core/src/main/java/hudson/widgets/HistoryPageEntry.java +++ b/core/src/main/java/jenkins/widgets/HistoryPageEntry.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package hudson.widgets; +package jenkins.widgets; import hudson.model.Queue; import hudson.model.Run; diff --git a/core/src/main/java/hudson/widgets/HistoryPageFilter.java b/core/src/main/java/jenkins/widgets/HistoryPageFilter.java similarity index 98% rename from core/src/main/java/hudson/widgets/HistoryPageFilter.java rename to core/src/main/java/jenkins/widgets/HistoryPageFilter.java index b5ac6cfaf9..30f2596aed 100644 --- a/core/src/main/java/hudson/widgets/HistoryPageFilter.java +++ b/core/src/main/java/jenkins/widgets/HistoryPageFilter.java @@ -21,14 +21,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package hudson.widgets; +package jenkins.widgets; import hudson.model.Job; import hudson.model.Queue; import hudson.model.Run; -import hudson.widgets.buildsearch.BuildSearchParamProcessor; -import hudson.widgets.buildsearch.BuildSearchParamProcessorList; -import hudson.widgets.buildsearch.BuildSearchParams; +import hudson.widgets.HistoryWidget; +import jenkins.widgets.buildsearch.BuildSearchParamProcessorList; +import jenkins.widgets.buildsearch.BuildSearchParams; import javax.annotation.Nonnull; import java.util.ArrayList; diff --git a/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessor.java b/core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParamProcessor.java similarity index 97% rename from core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessor.java rename to core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParamProcessor.java index 14a2063ea8..dbc5a784bb 100644 --- a/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessor.java +++ b/core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParamProcessor.java @@ -21,14 +21,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package hudson.widgets.buildsearch; +package jenkins.widgets.buildsearch; import hudson.model.Queue; import hudson.model.Run; -import java.util.ArrayList; -import java.util.List; - /** * Search param/term processor. * diff --git a/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessorFactory.java b/core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParamProcessorFactory.java similarity index 91% rename from core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessorFactory.java rename to core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParamProcessorFactory.java index 6d8e2d8cd1..5b6f84b1b6 100644 --- a/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessorFactory.java +++ b/core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParamProcessorFactory.java @@ -21,14 +21,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package hudson.widgets.buildsearch; +package jenkins.widgets.buildsearch; import hudson.ExtensionList; import hudson.ExtensionPoint; -import hudson.widgets.buildsearch.processors.DateProcessorFactory; -import hudson.widgets.buildsearch.processors.DescriptionProcessorFactory; -import hudson.widgets.buildsearch.processors.NameProcessorFactory; -import hudson.widgets.buildsearch.processors.ResultProcessorFactory; +import jenkins.widgets.buildsearch.processors.DateProcessorFactory; +import jenkins.widgets.buildsearch.processors.DescriptionProcessorFactory; +import jenkins.widgets.buildsearch.processors.NameProcessorFactory; +import jenkins.widgets.buildsearch.processors.ResultProcessorFactory; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; @@ -41,7 +41,7 @@ import java.util.Set; /** * Implementations of this class create {@link BuildSearchParamProcessor} instances from a set * of {@link BuildSearchParams}. The set of {@link BuildSearchParamProcessor} instances are then used - * by the {@link hudson.widgets.HistoryPageFilter} class to filter the build history (via an instance of + * by the {@link jenkins.widgets.HistoryPageFilter} class to filter the build history (via an instance of * {@link BuildSearchParamProcessorList}). * *

    diff --git a/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessorList.java b/core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParamProcessorList.java similarity index 92% rename from core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessorList.java rename to core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParamProcessorList.java index 2c0dee50cf..99c56bc8e2 100644 --- a/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParamProcessorList.java +++ b/core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParamProcessorList.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package hudson.widgets.buildsearch; +package jenkins.widgets.buildsearch; import hudson.model.Queue; import hudson.model.Run; @@ -30,8 +30,8 @@ import javax.annotation.Nonnull; import java.util.ArrayList; /** - * Wrapper class for the list of {@link hudson.widgets.buildsearch.BuildSearchParamProcessor} needed to process/apply - * a set of {@link hudson.widgets.buildsearch.BuildSearchParams}. + * Wrapper class for the list of {@link jenkins.widgets.buildsearch.BuildSearchParamProcessor} needed to process/apply + * a set of {@link jenkins.widgets.buildsearch.BuildSearchParams}. * * @author tom.fennelly@gmail.com */ @@ -40,7 +40,7 @@ public class BuildSearchParamProcessorList { private final ArrayList processors; /** - * Create a {@link BuildSearchParamProcessorList} instance from a set of {@link hudson.widgets.buildsearch.BuildSearchParams}. + * Create a {@link BuildSearchParamProcessorList} instance from a set of {@link jenkins.widgets.buildsearch.BuildSearchParams}. * @param searchParams The search parameters to use for creating the {@link BuildSearchParamProcessorList}. */ public BuildSearchParamProcessorList(@Nonnull BuildSearchParams searchParams) { diff --git a/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParams.java b/core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParams.java similarity index 99% rename from core/src/main/java/hudson/widgets/buildsearch/BuildSearchParams.java rename to core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParams.java index 277bd43b29..f7112c585f 100644 --- a/core/src/main/java/hudson/widgets/buildsearch/BuildSearchParams.java +++ b/core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParams.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package hudson.widgets.buildsearch; +package jenkins.widgets.buildsearch; import javax.annotation.Nonnull; import java.util.ArrayList; diff --git a/core/src/main/java/hudson/widgets/buildsearch/README.md b/core/src/main/java/jenkins/widgets/buildsearch/README.md similarity index 100% rename from core/src/main/java/hudson/widgets/buildsearch/README.md rename to core/src/main/java/jenkins/widgets/buildsearch/README.md diff --git a/core/src/main/java/hudson/widgets/buildsearch/processors/DateProcessorFactory.java b/core/src/main/java/jenkins/widgets/buildsearch/processors/DateProcessorFactory.java similarity index 96% rename from core/src/main/java/hudson/widgets/buildsearch/processors/DateProcessorFactory.java rename to core/src/main/java/jenkins/widgets/buildsearch/processors/DateProcessorFactory.java index 001bffb079..e1fc9b9f3a 100644 --- a/core/src/main/java/hudson/widgets/buildsearch/processors/DateProcessorFactory.java +++ b/core/src/main/java/jenkins/widgets/buildsearch/processors/DateProcessorFactory.java @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package hudson.widgets.buildsearch.processors; +package jenkins.widgets.buildsearch.processors; import hudson.model.Queue; import hudson.model.Run; -import hudson.widgets.buildsearch.BuildSearchParamProcessor; -import hudson.widgets.buildsearch.BuildSearchParamProcessorFactory; -import hudson.widgets.buildsearch.BuildSearchParams; +import jenkins.widgets.buildsearch.BuildSearchParamProcessor; +import jenkins.widgets.buildsearch.BuildSearchParamProcessorFactory; +import jenkins.widgets.buildsearch.BuildSearchParams; import java.text.ParseException; import java.text.SimpleDateFormat; diff --git a/core/src/main/java/hudson/widgets/buildsearch/processors/DescriptionProcessorFactory.java b/core/src/main/java/jenkins/widgets/buildsearch/processors/DescriptionProcessorFactory.java similarity index 92% rename from core/src/main/java/hudson/widgets/buildsearch/processors/DescriptionProcessorFactory.java rename to core/src/main/java/jenkins/widgets/buildsearch/processors/DescriptionProcessorFactory.java index 82ee4a5315..fd598fb88d 100644 --- a/core/src/main/java/hudson/widgets/buildsearch/processors/DescriptionProcessorFactory.java +++ b/core/src/main/java/jenkins/widgets/buildsearch/processors/DescriptionProcessorFactory.java @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package hudson.widgets.buildsearch.processors; +package jenkins.widgets.buildsearch.processors; import hudson.model.Queue; import hudson.model.Run; -import hudson.widgets.buildsearch.BuildSearchParamProcessor; -import hudson.widgets.buildsearch.BuildSearchParamProcessorFactory; -import hudson.widgets.buildsearch.BuildSearchParams; +import jenkins.widgets.buildsearch.BuildSearchParamProcessor; +import jenkins.widgets.buildsearch.BuildSearchParamProcessorFactory; +import jenkins.widgets.buildsearch.BuildSearchParams; import java.util.List; diff --git a/core/src/main/java/hudson/widgets/buildsearch/processors/NameProcessorFactory.java b/core/src/main/java/jenkins/widgets/buildsearch/processors/NameProcessorFactory.java similarity index 92% rename from core/src/main/java/hudson/widgets/buildsearch/processors/NameProcessorFactory.java rename to core/src/main/java/jenkins/widgets/buildsearch/processors/NameProcessorFactory.java index a94e14cc97..3d67e0d00c 100644 --- a/core/src/main/java/hudson/widgets/buildsearch/processors/NameProcessorFactory.java +++ b/core/src/main/java/jenkins/widgets/buildsearch/processors/NameProcessorFactory.java @@ -21,13 +21,13 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package hudson.widgets.buildsearch.processors; +package jenkins.widgets.buildsearch.processors; import hudson.model.Queue; import hudson.model.Run; -import hudson.widgets.buildsearch.BuildSearchParamProcessor; -import hudson.widgets.buildsearch.BuildSearchParamProcessorFactory; -import hudson.widgets.buildsearch.BuildSearchParams; +import jenkins.widgets.buildsearch.BuildSearchParamProcessor; +import jenkins.widgets.buildsearch.BuildSearchParamProcessorFactory; +import jenkins.widgets.buildsearch.BuildSearchParams; import java.util.List; diff --git a/core/src/main/java/hudson/widgets/buildsearch/processors/ResultProcessorFactory.java b/core/src/main/java/jenkins/widgets/buildsearch/processors/ResultProcessorFactory.java similarity index 93% rename from core/src/main/java/hudson/widgets/buildsearch/processors/ResultProcessorFactory.java rename to core/src/main/java/jenkins/widgets/buildsearch/processors/ResultProcessorFactory.java index 8c6987674d..e8553858a2 100644 --- a/core/src/main/java/hudson/widgets/buildsearch/processors/ResultProcessorFactory.java +++ b/core/src/main/java/jenkins/widgets/buildsearch/processors/ResultProcessorFactory.java @@ -21,14 +21,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package hudson.widgets.buildsearch.processors; +package jenkins.widgets.buildsearch.processors; import hudson.model.Queue; import hudson.model.Result; import hudson.model.Run; -import hudson.widgets.buildsearch.BuildSearchParamProcessor; -import hudson.widgets.buildsearch.BuildSearchParamProcessorFactory; -import hudson.widgets.buildsearch.BuildSearchParams; +import jenkins.widgets.buildsearch.BuildSearchParamProcessor; +import jenkins.widgets.buildsearch.BuildSearchParamProcessorFactory; +import jenkins.widgets.buildsearch.BuildSearchParams; import java.util.ArrayList; import java.util.List; diff --git a/core/src/test/java/hudson/widgets/HistoryPageFilterTest.java b/core/src/test/java/jenkins/widgets/HistoryPageFilterTest.java similarity index 99% rename from core/src/test/java/hudson/widgets/HistoryPageFilterTest.java rename to core/src/test/java/jenkins/widgets/HistoryPageFilterTest.java index de1def0ce9..61d89f9da3 100644 --- a/core/src/test/java/hudson/widgets/HistoryPageFilterTest.java +++ b/core/src/test/java/jenkins/widgets/HistoryPageFilterTest.java @@ -21,13 +21,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package hudson.widgets; +package jenkins.widgets; import hudson.model.Job; import hudson.model.MockItem; import hudson.model.ModelObject; import hudson.model.Result; import hudson.model.Run; +import jenkins.widgets.HistoryPageEntry; +import jenkins.widgets.HistoryPageFilter; import org.junit.Assert; import org.junit.Test; import org.mockito.Mockito; diff --git a/core/src/test/java/hudson/widgets/buildsearch/BuildSearchParamProcessorTest.java b/core/src/test/java/jenkins/widgets/buildsearch/BuildSearchParamProcessorTest.java similarity index 98% rename from core/src/test/java/hudson/widgets/buildsearch/BuildSearchParamProcessorTest.java rename to core/src/test/java/jenkins/widgets/buildsearch/BuildSearchParamProcessorTest.java index 12baebc656..62a30f2553 100644 --- a/core/src/test/java/hudson/widgets/buildsearch/BuildSearchParamProcessorTest.java +++ b/core/src/test/java/jenkins/widgets/buildsearch/BuildSearchParamProcessorTest.java @@ -21,10 +21,10 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package hudson.widgets.buildsearch; +package jenkins.widgets.buildsearch; import hudson.model.Result; -import hudson.widgets.buildsearch.processors.DateProcessorFactory; +import jenkins.widgets.buildsearch.processors.DateProcessorFactory; import org.junit.Assert; import org.junit.Test; diff --git a/core/src/test/java/hudson/widgets/buildsearch/BuildSearchParamsTest.java b/core/src/test/java/jenkins/widgets/buildsearch/BuildSearchParamsTest.java similarity index 98% rename from core/src/test/java/hudson/widgets/buildsearch/BuildSearchParamsTest.java rename to core/src/test/java/jenkins/widgets/buildsearch/BuildSearchParamsTest.java index a71f827ed9..787bb04731 100644 --- a/core/src/test/java/hudson/widgets/buildsearch/BuildSearchParamsTest.java +++ b/core/src/test/java/jenkins/widgets/buildsearch/BuildSearchParamsTest.java @@ -21,7 +21,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package hudson.widgets.buildsearch; +package jenkins.widgets.buildsearch; import org.junit.Assert; import org.junit.Test; From 7106d2cba9ef2e6e9673046cce48fde11e3d62f2 Mon Sep 17 00:00:00 2001 From: tfennelly Date: Fri, 26 Jun 2015 13:10:09 +0100 Subject: [PATCH 0248/2573] Fix jelly refs to historyPageFilter --- .../hudson/widgets/HistoryWidget/ajaxBuildHistory.jelly | 2 +- .../src/main/resources/hudson/widgets/HistoryWidget/index.jelly | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/resources/hudson/widgets/HistoryWidget/ajaxBuildHistory.jelly b/core/src/main/resources/hudson/widgets/HistoryWidget/ajaxBuildHistory.jelly index 6684873987..4d01266f09 100644 --- a/core/src/main/resources/hudson/widgets/HistoryWidget/ajaxBuildHistory.jelly +++ b/core/src/main/resources/hudson/widgets/HistoryWidget/ajaxBuildHistory.jelly @@ -26,5 +26,5 @@ THE SOFTWARE. --> - + \ No newline at end of file diff --git a/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly b/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly index d42b56abb2..4c665be3f8 100644 --- a/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly +++ b/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly @@ -51,7 +51,7 @@ THE SOFTWARE. - +

    From 986530a7802e47486a79d4490be2681d15a6f7cd Mon Sep 17 00:00:00 2001 From: tfennelly Date: Fri, 26 Jun 2015 14:47:52 +0100 Subject: [PATCH 0249/2573] Moved some jelly files to match earlier Java package move --- .../java/jenkins/widgets/buildsearch/README.md | 14 ++++++-------- .../hudson/widgets/HistoryWidget/index.jelly | 2 +- .../HistoryPageFilter/ajaxBuildHistory.jelly | 0 .../widgets/HistoryPageFilter/entries.jelly | 0 .../widgets/HistoryPageFilter/queue-items.jelly | 0 5 files changed, 7 insertions(+), 9 deletions(-) rename core/src/main/resources/{hudson => jenkins}/widgets/HistoryPageFilter/ajaxBuildHistory.jelly (100%) rename core/src/main/resources/{hudson => jenkins}/widgets/HistoryPageFilter/entries.jelly (100%) rename core/src/main/resources/{hudson => jenkins}/widgets/HistoryPageFilter/queue-items.jelly (100%) diff --git a/core/src/main/java/jenkins/widgets/buildsearch/README.md b/core/src/main/java/jenkins/widgets/buildsearch/README.md index f539a9fda3..38345b433c 100644 --- a/core/src/main/java/jenkins/widgets/buildsearch/README.md +++ b/core/src/main/java/jenkins/widgets/buildsearch/README.md @@ -9,26 +9,24 @@ __TODO__: Move to jenkins-ci web/wiki if changes accepted. Different search terms are __AND__ together to result in a matching Build, while multiples of the same search term are __OR__'d together e.g. -* result: FAILURE desc: staging desc: production +* `result: FAILURE desc: staging desc: production` -Is interpreted as: - -* (result: FAILURE) AND (desc: staging OR desc: production) +Is interpreted as: "(result: FAILURE) AND (desc: staging OR desc: production)" ## Examples Builds that contain the words "staging" or "production" in the description: -* desc: staging desc: production +* `desc: staging desc: production` Failed builds in last week (7 days): -* result: FAILURE date-from: 1 week +* `result: FAILURE date-from: 1 week` Failed builds since a specific date: -* result: FAILURE date-from: 2015-03-31 +* `result: FAILURE date-from: 2015-03-31` Unstable builds in March: -* result: UNSTABLE date-from: 2015-03-01 date-to: 2015-04-01 +* `result: UNSTABLE date-from: 2015-03-01 date-to: 2015-04-01` diff --git a/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly b/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly index 4c665be3f8..e384a99544 100644 --- a/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly +++ b/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly @@ -69,7 +69,7 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/hudson/widgets/HistoryPageFilter/ajaxBuildHistory.jelly b/core/src/main/resources/jenkins/widgets/HistoryPageFilter/ajaxBuildHistory.jelly similarity index 100% rename from core/src/main/resources/hudson/widgets/HistoryPageFilter/ajaxBuildHistory.jelly rename to core/src/main/resources/jenkins/widgets/HistoryPageFilter/ajaxBuildHistory.jelly diff --git a/core/src/main/resources/hudson/widgets/HistoryPageFilter/entries.jelly b/core/src/main/resources/jenkins/widgets/HistoryPageFilter/entries.jelly similarity index 100% rename from core/src/main/resources/hudson/widgets/HistoryPageFilter/entries.jelly rename to core/src/main/resources/jenkins/widgets/HistoryPageFilter/entries.jelly diff --git a/core/src/main/resources/hudson/widgets/HistoryPageFilter/queue-items.jelly b/core/src/main/resources/jenkins/widgets/HistoryPageFilter/queue-items.jelly similarity index 100% rename from core/src/main/resources/hudson/widgets/HistoryPageFilter/queue-items.jelly rename to core/src/main/resources/jenkins/widgets/HistoryPageFilter/queue-items.jelly From 60c64a2047ae81004d7633c8bb185db19e733ed1 Mon Sep 17 00:00:00 2001 From: ikedam Date: Sun, 28 Jun 2015 12:10:11 +0900 Subject: [PATCH 0250/2573] [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 0251/2573] [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 0254/2573] 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 0255/2573] 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 0256/2573] [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 0257/2573] 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 0258/2573] 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 0259/2573] 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 0260/2573] [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 0261/2573] 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 0262/2573] 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 0263/2573] 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 0264/2573] 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 0265/2573] [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 23528253f0204298ebf2e9bdbaf487a37a033fab Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Tue, 7 Jul 2015 08:38:30 +0200 Subject: [PATCH 0268/2573] Add new plugin labels to clean up Plugin Manager --- .../main/resources/hudson/model/Messages.properties | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/src/main/resources/hudson/model/Messages.properties b/core/src/main/resources/hudson/model/Messages.properties index 3537e9978a..445939f472 100644 --- a/core/src/main/resources/hudson/model/Messages.properties +++ b/core/src/main/resources/hudson/model/Messages.properties @@ -276,20 +276,33 @@ UpdateCenter.Status.ConnectionFailed=\ Failed to connect to {0}. \ Perhaps you need to configure HTTP proxy? UpdateCenter.init=Initialing update center +UpdateCenter.PluginCategory.android=Android Development UpdateCenter.PluginCategory.builder=Build Tools UpdateCenter.PluginCategory.buildwrapper=Build Wrappers UpdateCenter.PluginCategory.cli=Command Line Interface UpdateCenter.PluginCategory.cluster=Cluster Management and Distributed Build +UpdateCenter.PluginCategory.database=Database +UpdateCenter.PluginCategory.deployment=Deployment +UpdateCenter.PluginCategory.devops=DevOps +UpdateCenter.PluginCategory.dotnet=.NET Development UpdateCenter.PluginCategory.external=External Site/Tool Integrations +UpdateCenter.PluginCategory.groovy-related=Groovy-related +UpdateCenter.PluginCategory.ios=iOS Development +UpdateCenter.PluginCategory.library=Library plugins (for use by other plugins) UpdateCenter.PluginCategory.listview-column=List view columns UpdateCenter.PluginCategory.maven=Maven UpdateCenter.PluginCategory.misc=Miscellaneous UpdateCenter.PluginCategory.notifier=Build Notifiers UpdateCenter.PluginCategory.page-decorator=Page Decorators +UpdateCenter.PluginCategory.parameter=Build Parameters UpdateCenter.PluginCategory.post-build=Other Post-Build Actions +UpdateCenter.PluginCategory.publisher=Other Post-Build Actions UpdateCenter.PluginCategory.report=Build Reports +UpdateCenter.PluginCategory.ruby=Ruby +UpdateCenter.PluginCategory.runcondition=RunConditions for use by the Run Condition plugin UpdateCenter.PluginCategory.scm=Source Code Management UpdateCenter.PluginCategory.scm-related=Source Code Management related +UpdateCenter.PluginCategory.security=Security UpdateCenter.PluginCategory.slaves=Slave Launchers and Controllers UpdateCenter.PluginCategory.trigger=Build Triggers UpdateCenter.PluginCategory.ui=User Interface From c24c3236917cfac2ae7c536b5fd6ad737fa2253c Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Mon, 8 Jun 2015 14:38:49 +0100 Subject: [PATCH 0269/2573] [FIXED JENKINS-28690] Deadlock in hudson.model.Executor - Rather fun one here. The Lock code relies on assuming that Thread.interrupted() is clear on entry - If it then sees Thread.interrupted() set, it will interrupt the current thread in order to set the flag again. - Executor is a thread that does funky things with an overridden interrupt method - Executor.abortResult() is used to track a build be interrupted or aborted in some other way - As a result the abortResult can cause a deadlockif there is a genuine interruption - This fix clears the interrupt flag in abortResult() and uses the write lock in order to ensure: - The same lock as used in interrupt() is helf - The interrupt flag is clear - Clearing the interrupt flag should be safe as the only time it is called is immediately after an interruption and the resulting exception is caught and rethrown/logged anyway (cherry picked from commit ddb0a472ad44fcbce31fb565d477901575e3c581) --- core/src/main/java/hudson/model/Executor.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/hudson/model/Executor.java b/core/src/main/java/hudson/model/Executor.java index bc35f557ec..1901b534e3 100644 --- a/core/src/main/java/hudson/model/Executor.java +++ b/core/src/main/java/hudson/model/Executor.java @@ -205,7 +205,14 @@ public class Executor extends Thread implements ModelObject { } public Result abortResult() { - lock.readLock().lock(); + // this method is almost always called as a result of the current thread being interrupted + // as a result we need to clean the interrupt flag so that the lock's lock method doesn't + // get confused and think it was interrupted while awaiting the lock + Thread.interrupted(); + // we need to use a write lock as we may be repeatedly interrupted while processing and + // we need the same lock as used in void interrupt(Result,boolean,CauseOfInterruption...) + // JENKINS-28690 + lock.writeLock().lock(); try { Result r = interruptStatus; if (r == null) r = @@ -213,7 +220,7 @@ public class Executor extends Thread implements ModelObject { return r; } finally { - lock.readLock().unlock(); + lock.writeLock().unlock(); } } From 119fcbbf98c27f0257ac1be02104e0d87acc8728 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Mon, 15 Jun 2015 12:12:00 +0100 Subject: [PATCH 0270/2573] [FIXED JENKINS-28840] Deadlock between Queue.maintain and Executor.interrupt More fun here: - All this originates from Executor extending Thread. - There is funky logic in the lock handling code of the JVM that makes assumptions about how it might proceed with the lock when the thread holding the lock has its interrupt flag set. - Really it would be better if Executor did not extend Thread as that way we wouldn't have to deal with some of that complexity. But OTOH we are where we are and backwards compatibility may make such a change not possible without a lot of breakage. - Fixing the issue at hand, firstly requires that interrupting a Computer happens with the Queue lock held (to speed up tests we have Jenkins.cleanup get the lock for all Computers) That prevents the Queue maintain thread from getting caught - Secondly, when removing an executor from a computer we process the removal while holding the Queue lock, but we move the removal itself to a separate thread if we cannot get the Queue lock in order to avoid deadlock. - Also add helper methods to wrap tasks to be performed while holding the lock and a helper method for Runnables that exposes the tryLock functionality (cherry picked from commit 6f343dc7c2f0c32e9eb1a0b5d588a2e7ad6f62ba) --- core/src/main/java/hudson/model/Computer.java | 22 ++- core/src/main/java/hudson/model/Queue.java | 129 +++++++++++++++++- core/src/main/java/jenkins/model/Jenkins.java | 18 ++- 3 files changed, 154 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index 71182ee98c..f3fa40a971 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -975,20 +975,23 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces * Called by {@link Executor} to kill excessive executors from this computer. */ /*package*/ void removeExecutor(final Executor e) { - Queue.withLock(new Runnable() { + final Runnable task = new Runnable() { @Override public void run() { synchronized (Computer.this) { executors.remove(e); addNewExecutorIfNecessary(); - if (!isAlive()) // TODO except from interrupt/doYank this is called while the executor still isActive(), so how could !this.isAlive()? - { + if (!isAlive()) { AbstractCIBase ciBase = Jenkins.getInstance(); ciBase.removeComputer(Computer.this); } } } - }); + }; + if (!Queue.tryWithLock(task)) { + // JENKINS-28840 if we couldn't get the lock push the operation to a separate thread to avoid deadlocks + threadPoolForRemoting.submit(Queue.wrapWithLock(task)); + } } /** @@ -1011,9 +1014,14 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces * Called from {@link Jenkins#cleanUp}. */ public void interrupt() { - for (Executor e : executors) { - e.interruptForShutdown(); - } + Queue.withLock(new Runnable() { + @Override + public void run() { + for (Executor e : executors) { + e.interruptForShutdown(); + } + } + }); } public String getSearchUrl() { diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index a15b0af34b..a4e50816e8 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -99,7 +99,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import java.util.logging.Logger; @@ -113,6 +112,7 @@ import jenkins.util.AtmostOneTaskExecutor; import org.acegisecurity.AccessDeniedException; import org.acegisecurity.Authentication; import org.jenkinsci.bytecode.AdaptField; +import org.jenkinsci.remoting.RoleChecker; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponses; import org.kohsuke.stapler.export.Exported; @@ -337,7 +337,7 @@ public class Queue extends ResourceController implements Saveable { } }); - private transient final Lock lock = new ReentrantLock(); + private transient final ReentrantLock lock = new ReentrantLock(); private transient final Condition condition = lock.newCondition(); @@ -1214,6 +1214,59 @@ public class Queue extends ResourceController implements Saveable { } } + /** + * Some operations require to be performed with the {@link Queue} lock held. Use one of these methods rather + * than locking directly on Queue in order to allow for future refactoring. + * @param runnable the operation to perform. + * @return {@code true} if the lock available and the operation performed. + * @since 1.FIXME + */ + public static boolean tryWithLock(Runnable runnable) { + final Jenkins jenkins = Jenkins.getInstance(); + final Queue queue = jenkins == null ? null : jenkins.getQueue(); + if (queue == null) { + runnable.run(); + return true; + } else { + return queue._tryWithLock(runnable); + } + } + /** + * Wraps a {@link Runnable} with the {@link Queue} lock held. + * + * @param runnable the operation to wrap. + * @since 1.FIXME + */ + public static Runnable wrapWithLock(Runnable runnable) { + final Jenkins jenkins = Jenkins.getInstance(); + final Queue queue = jenkins == null ? null : jenkins.getQueue(); + return queue == null ? runnable : new LockedRunnable(runnable); + } + + /** + * Wraps a {@link hudson.remoting.Callable} with the {@link Queue} lock held. + * + * @param callable the operation to wrap. + * @since 1.FIXME + */ + public static hudson.remoting.Callable wrapWithLock(hudson.remoting.Callable callable) { + final Jenkins jenkins = Jenkins.getInstance(); + final Queue queue = jenkins == null ? null : jenkins.getQueue(); + return queue == null ? callable : new LockedHRCallable<>(callable); + } + + /** + * Wraps a {@link java.util.concurrent.Callable} with the {@link Queue} lock held. + * + * @param callable the operation to wrap. + * @since 1.FIXME + */ + public static java.util.concurrent.Callable wrapWithLock(java.util.concurrent.Callable callable) { + final Jenkins jenkins = Jenkins.getInstance(); + final Queue queue = jenkins == null ? null : jenkins.getQueue(); + return queue == null ? callable : new LockedJUCCallable(callable); + } + @Override protected void _await() throws InterruptedException { condition.await(); @@ -1239,6 +1292,26 @@ public class Queue extends ResourceController implements Saveable { } } + /** + * Some operations require to be performed with the {@link Queue} lock held. Use one of these methods rather + * than locking directly on Queue in order to allow for future refactoring. + * @param runnable the operation to perform. + * @return {@code true} if the lock available and the operation performed. + * @since 1.FIXME + */ + protected boolean _tryWithLock(Runnable runnable) { + if (lock.tryLock()) { + try { + runnable.run(); + } finally { + lock.unlock(); + } + return true; + } else { + return false; + } + } + /** * Some operations require to be performed with the {@link Queue} lock held. Use one of these methods rather * than locking directly on Queue in order to allow for future refactoring. @@ -1303,6 +1376,13 @@ public class Queue extends ResourceController implements Saveable { List lostPendings = new ArrayList(pendings); for (Computer c : Jenkins.getInstance().getComputers()) { for (Executor e : c.getExecutors()) { + if (e.isInterrupted()) { + // JENKINS-28840 we will deadlock if we try to touch this executor while interrupt flag set + // we need to clear lost pendings as we cannot know what work unit was on this executor + // while it is interrupted. (All this dancing is a result of Executor extending Thread) + lostPendings.clear(); // we'll get them next time around when the flag is cleared. + continue; + } if (e.isParking()) { parked.put(e, new JobOffer(e)); } @@ -2564,6 +2644,51 @@ public class Queue extends ResourceController implements Saveable { this.pendings = new ArrayList(pendings); } } + + private static class LockedRunnable implements Runnable { + private final Runnable delegate; + + private LockedRunnable(Runnable delegate) { + this.delegate = delegate; + } + + @Override + public void run() { + withLock(delegate); + } + } + + private static class LockedJUCCallable implements java.util.concurrent.Callable { + private final java.util.concurrent.Callable delegate; + + private LockedJUCCallable(java.util.concurrent.Callable delegate) { + this.delegate = delegate; + } + + @Override + public V call() throws Exception { + return withLock(delegate); + } + } + + private static class LockedHRCallable implements hudson.remoting.Callable { + private static final long serialVersionUID = 1L; + private final hudson.remoting.Callable delegate; + + private LockedHRCallable(hudson.remoting.Callable delegate) { + this.delegate = delegate; + } + + @Override + public V call() throws T { + return withLock(delegate); + } + + @Override + public void checkRoles(RoleChecker checker) throws SecurityException { + delegate.checkRoles(checker); + } + } @CLIResolver public static Queue getInstance() { diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 8b024f018e..4278f9a6c6 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -2763,13 +2763,19 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve LOGGER.log(SEVERE, "Failed to execute termination",e); } - Set> pending = new HashSet>(); + final Set> pending = new HashSet>(); terminating = true; - for( Computer c : computers.values() ) { - c.interrupt(); - killComputer(c); - pending.add(c.disconnect(null)); - } + // JENKINS-28840 we know we will be interrupting all the Computers so get the Queue lock once for all + Queue.withLock(new Runnable() { + @Override + public void run() { + for( Computer c : computers.values() ) { + c.interrupt(); + killComputer(c); + pending.add(c.disconnect(null)); + } + } + }); if(udpBroadcastThread!=null) udpBroadcastThread.shutdown(); if(dnsMultiCast!=null) From 0fcb58813b78cf698726a4987e8edcedea130acd Mon Sep 17 00:00:00 2001 From: liorha Date: Mon, 1 Jun 2015 18:06:41 +0300 Subject: [PATCH 0271/2573] Contine the JENKINS-27289 ticket: update the getResources as well (cherry picked from commit 40e75129f40675f8a71b489b38c5911b37cb8559) --- .../java/hudson/util/MaskingClassLoader.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/hudson/util/MaskingClassLoader.java b/core/src/main/java/hudson/util/MaskingClassLoader.java index 4a85d76d0f..43550f0228 100644 --- a/core/src/main/java/hudson/util/MaskingClassLoader.java +++ b/core/src/main/java/hudson/util/MaskingClassLoader.java @@ -23,11 +23,9 @@ */ package hudson.util; +import java.io.IOException; import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; +import java.util.*; /** * {@link ClassLoader} that masks a specified set of classes @@ -82,6 +80,16 @@ public class MaskingClassLoader extends ClassLoader { return super.getResource(name); } + @Override + public Enumeration getResources(String name) throws IOException { + for (String mask : masksResources) { + if(name.startsWith(mask)) + return null; + } + + return super.getResources(name); + } + public synchronized void add(String prefix) { masksClasses.add(prefix); if(prefix !=null){ From c3dcaeb8d55fe8a8065fb60cecef23d23eb9b87c Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Wed, 10 Jun 2015 00:49:22 +0200 Subject: [PATCH 0272/2573] [FIX JENKINS-14899] Don't use truncating LargeText for /consoleText (cherry picked from commit 20bd4e304976dc64fa6abc165823425ba524ccb2) --- core/src/main/java/hudson/model/Run.java | 25 ++++++++---------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/core/src/main/java/hudson/model/Run.java b/core/src/main/java/hudson/model/Run.java index a8c557c3f2..1c22e65d92 100644 --- a/core/src/main/java/hudson/model/Run.java +++ b/core/src/main/java/hudson/model/Run.java @@ -39,10 +39,7 @@ import hudson.Functions; import hudson.Util; import hudson.XmlFile; import hudson.cli.declarative.CLIMethod; -import hudson.console.AnnotatedLargeText; -import hudson.console.ConsoleLogFilter; -import hudson.console.ConsoleNote; -import hudson.console.ModelHyperlinkNote; +import hudson.console.*; import hudson.model.Descriptor.FormException; import hudson.model.Run.RunExecution; import hudson.model.listeners.RunListener; @@ -2086,19 +2083,13 @@ public abstract class Run ,RunT extends Run Date: Wed, 17 Jun 2015 12:04:33 +0100 Subject: [PATCH 0273/2573] [FIXED JENKINS-28926] Block while upstream/downstream building cycles never complete - One could argue that without this change the system is functioning correctly and that previous behaviour was a bug. On the other hand, people have come to rely on the previous behaviour. - The issue really centeres around state changes in the blocked tasks. Since blocking on upstream/downstream relies on checking the building projects and the queued (excluding blocked) tasks we need any change in the blocked task list to be visible immediately (i.e. update the snapshot) - I was able to reliably reproduce this behaviour with a convoluted set of manually configured projects but turning this into a test case has not proved quite as easy. Manual testing confirms that the issue is fixed for my manual test case - I have also added a sorting of the blocked list when probing for tasks to unblock. This should prioritise tasks as intended by the QueueSorter (cherry picked from commit de87736795898e57f7aca140124c2b1a3d1daf40) --- core/src/main/java/hudson/model/Queue.java | 20 +++++++++++-- .../java/hudson/model/queue/QueueSorter.java | 28 +++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index a4e50816e8..f59eb52703 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -1403,15 +1403,29 @@ public class Queue extends ResourceController implements Saveable { } } + final QueueSorter s = sorter; {// blocked -> buildable - for (BlockedItem p : new ArrayList(blockedProjects.values())) {// copy as we'll mutate the list + // copy as we'll mutate the list and we want to process in a potentially different order + // TODO replace with <> operator after backporting to 1.609.3 + List blockedItems = new ArrayList(blockedProjects.values()); + // if facing a cycle of blocked tasks, ensure we process in the desired sort order + if (s != null) { + s.sortBlockedItems(blockedItems); + } else { + Collections.sort(blockedItems, QueueSorter.DEFAULT_BLOCKED_ITEM_COMPARATOR); + } + for (BlockedItem p : blockedItems) { if (!isBuildBlocked(p) && allowNewBuildableTask(p.task)) { // ready to be executed Runnable r = makeBuildable(new BuildableItem(p)); if (r != null) { p.leave(this); r.run(); + // JENKINS-28926 we have removed a task from the blocked projects and added to building + // thus we should update the snapshot so that subsequent blocked projects can correctly + // determine if they are blocked by the lucky winner + updateSnapshot(); } } } @@ -1441,7 +1455,6 @@ public class Queue extends ResourceController implements Saveable { } } - final QueueSorter s = sorter; if (s != null) s.sortBuildableItems(buildables); @@ -1456,6 +1469,9 @@ public class Queue extends ResourceController implements Saveable { p.leave(this); new BlockedItem(p).enter(this); LOGGER.log(Level.FINE, "Catching that {0} is blocked in the last minute", p); + // JENKINS-28926 we have moved an unblocked task into the blocked state, update snapshot + // so that other buildables which might have been blocked by this can see the state change + updateSnapshot(); continue; } diff --git a/core/src/main/java/hudson/model/queue/QueueSorter.java b/core/src/main/java/hudson/model/queue/QueueSorter.java index fafd9b0c1c..296312b73b 100644 --- a/core/src/main/java/hudson/model/queue/QueueSorter.java +++ b/core/src/main/java/hudson/model/queue/QueueSorter.java @@ -8,6 +8,8 @@ import hudson.model.LoadBalancer; import hudson.model.Queue; import hudson.model.Queue.BuildableItem; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.logging.Logger; @@ -19,6 +21,20 @@ import static hudson.init.InitMilestone.JOB_LOADED; * @since 1.343 */ public abstract class QueueSorter implements ExtensionPoint { + /** + * A comparator that sorts {@link Queue.BlockedItem} instances based on how long they have been in the queue. + * (We want the time since in queue by default as blocking on upstream/downstream considers waiting items + * also and thus the blocking starts once the task is in the queue not once the task is buildable) + * + * @since 1.FIXME + */ + public static final Comparator DEFAULT_BLOCKED_ITEM_COMPARATOR = new Comparator() { + @Override + public int compare(Queue.BlockedItem o1, Queue.BlockedItem o2) { + return Long.compare(o1.getInQueueSince(), o2.getInQueueSince()); + } + }; + /** * Sorts the buildable items list. The items at the beginning will be executed * before the items at the end of the list. @@ -28,6 +44,18 @@ public abstract class QueueSorter implements ExtensionPoint { */ public abstract void sortBuildableItems(List buildables); + /** + * Sorts the blocked items list. The items at the beginning will be considered for removal from the blocked state + * before the items at the end of the list. + * + * @param blockedItems + * List of blocked items in the queue. Never null. + * @since 1.FIXME + */ + public void sortBlockedItems(List blockedItems) { + Collections.sort(blockedItems, DEFAULT_BLOCKED_ITEM_COMPARATOR); + } + /** * All registered {@link QueueSorter}s. Only the first one will be picked up, * unless explicitly overridden by {@link Queue#setSorter(QueueSorter)}. From 8596004024e9d8a00a99c459b4d7c82c004d1724 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Wed, 17 Jun 2015 12:30:46 +0100 Subject: [PATCH 0274/2573] [JENKINS-28926] Adding test case - I was forgetting the call to `rebuildDependencyGraph()` which was why the test didn't work for me (cherry picked from commit c44c088442e1821f8cd44f4fdaa146d94dd85910) --- .../src/test/java/hudson/model/QueueTest.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/test/src/test/java/hudson/model/QueueTest.java b/test/src/test/java/hudson/model/QueueTest.java index 65a6761102..283b771a2c 100644 --- a/test/src/test/java/hudson/model/QueueTest.java +++ b/test/src/test/java/hudson/model/QueueTest.java @@ -75,6 +75,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import jenkins.model.Jenkins; import jenkins.security.QueueItemAuthenticatorConfiguration; +import jenkins.triggers.ReverseBuildTrigger; import org.acegisecurity.Authentication; import org.acegisecurity.GrantedAuthority; import org.acegisecurity.acls.sid.PrincipalSid; @@ -83,6 +84,9 @@ import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.FileUtils; + +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.*; import org.junit.Assert; @@ -442,6 +446,38 @@ public class QueueTest { String tagName = queueItem.getDocumentElement().getTagName(); assertTrue(tagName.equals("blockedItem") || tagName.equals("buildableItem")); } + + @Issue("JENKINS-28926") + @Test + public void upstreamDownstreamCycle() throws Exception { + FreeStyleProject trigger = r.createFreeStyleProject(); + FreeStyleProject chain1 = r.createFreeStyleProject(); + FreeStyleProject chain2a = r.createFreeStyleProject(); + FreeStyleProject chain2b = r.createFreeStyleProject(); + FreeStyleProject chain3 = r.createFreeStyleProject(); + trigger.getPublishersList().add(new BuildTrigger(String.format("%s, %s, %s, %s", chain1.getName(), chain2a.getName(), chain2b.getName(), chain3.getName()), true)); + trigger.setQuietPeriod(0); + chain1.setQuietPeriod(1); + chain2a.setQuietPeriod(1); + chain2b.setQuietPeriod(1); + chain3.setQuietPeriod(1); + chain1.getPublishersList().add(new BuildTrigger(String.format("%s, %s", chain2a.getName(), chain2b.getName()), true)); + chain2a.getPublishersList().add(new BuildTrigger(chain3.getName(), true)); + chain2b.getPublishersList().add(new BuildTrigger(chain3.getName(), true)); + chain1.setBlockBuildWhenDownstreamBuilding(true); + chain2a.setBlockBuildWhenDownstreamBuilding(true); + chain2b.setBlockBuildWhenDownstreamBuilding(true); + chain3.setBlockBuildWhenUpstreamBuilding(true); + r.jenkins.rebuildDependencyGraph(); + r.buildAndAssertSuccess(trigger); + // the trigger should build immediately and schedule the cycle + r.waitUntilNoActivity(); + final Queue queue = r.getInstance().getQueue(); + assertThat("The cycle should have been defanged and chain1 executed", queue.getItem(chain1), nullValue()); + assertThat("The cycle should have been defanged and chain2a executed", queue.getItem(chain2a), nullValue()); + assertThat("The cycle should have been defanged and chain2b executed", queue.getItem(chain2b), nullValue()); + assertThat("The cycle should have been defanged and chain3 executed", queue.getItem(chain3), nullValue()); + } private static class TestFlyweightTask extends TestTask implements Queue.FlyweightTask { Executor exec; From 260b0947cd10bae186fe9f5688d6f9bfa739087c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Tue, 7 Jul 2015 13:33:31 +0200 Subject: [PATCH 0275/2573] Avoid diamonds for now --- core/src/main/java/hudson/model/Queue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index f59eb52703..ff579a5728 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -1252,7 +1252,7 @@ public class Queue extends ResourceController implements Saveable { public static hudson.remoting.Callable wrapWithLock(hudson.remoting.Callable callable) { final Jenkins jenkins = Jenkins.getInstance(); final Queue queue = jenkins == null ? null : jenkins.getQueue(); - return queue == null ? callable : new LockedHRCallable<>(callable); + return queue == null ? callable : new LockedHRCallable(callable); } /** From 3005532a94561ac597c6debbb65f1c3dece442f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Tue, 7 Jul 2015 13:45:56 +0200 Subject: [PATCH 0276/2573] Avoid Long#compare for now --- core/src/main/java/hudson/model/queue/QueueSorter.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/queue/QueueSorter.java b/core/src/main/java/hudson/model/queue/QueueSorter.java index 296312b73b..37b20319e2 100644 --- a/core/src/main/java/hudson/model/queue/QueueSorter.java +++ b/core/src/main/java/hudson/model/queue/QueueSorter.java @@ -31,7 +31,9 @@ public abstract class QueueSorter implements ExtensionPoint { public static final Comparator DEFAULT_BLOCKED_ITEM_COMPARATOR = new Comparator() { @Override public int compare(Queue.BlockedItem o1, Queue.BlockedItem o2) { - return Long.compare(o1.getInQueueSince(), o2.getInQueueSince()); + long x = o1.getInQueueSince(); + long y = o2.getInQueueSince(); + return (x < y) ? -1 : ((x == y) ? 0 : 1); } }; From df4bb2de2d22bfa8a0e1beed14615a40786e3942 Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Mon, 23 Mar 2015 22:23:49 +0300 Subject: [PATCH 0277/2573] 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 0278/2573] 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 0279/2573] 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 0280/2573] 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 0281/2573] 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 0282/2573] 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 0283/2573] 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 0284/2573] 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 0285/2573] [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 0286/2573] 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 0287/2573] [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 0290/2573] [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 0291/2573] 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 0292/2573] [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 0293/2573] 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 0294/2573] [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 0295/2573] 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 0296/2573] [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 0298/2573] [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 0299/2573] 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 0300/2573] [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 0303/2573] 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 0304/2573] 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 0305/2573] 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 0306/2573] 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 0307/2573] [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 0308/2573] 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 0309/2573] [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 88f9f4c8fcf23ebe14abe550e849a46504aa9131 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Tue, 28 Jul 2015 08:46:47 -0700 Subject: [PATCH 0312/2573] [maven-release-plugin] prepare release jenkins-1.609.2 --- 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 c03e70d5ec..c45bc7da74 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.609.2-SNAPSHOT + 1.609.2 cli diff --git a/core/pom.xml b/core/pom.xml index 89b5a33fd6..02e0349525 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.609.2-SNAPSHOT + 1.609.2 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index 6fb611ca8b..08b71a42f6 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.609.2-SNAPSHOT + 1.609.2 pom

        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 8f5bdcb414cd70227f7e768f8b23ddfc328250b0 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 0315/2573] [FIXED JENKINS-29376] Rename help texts as well Amends eec43983a3bdfce6de45ca0559d8a9f8a1250b71. (cherry picked from commit 1c1d5a95d9d5aa86b5ae890942553fbcb0f1a641) --- .../{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 132b915615bed822a14d751667c4a0842ed6ffa6 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 0316/2573] [FIXED JENKINS-29286] Use byte size to sort disk space monitor columns (cherry picked from commit fabec0eef00212109a1ad5c2bedcb8c55de4f38a) --- .../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 b591a241b4a437863bf48ebbd6aa4d3f2c0f831c Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Thu, 23 Apr 2015 10:17:50 +0100 Subject: [PATCH 0317/2573] [FIXED JENKINS-28058] Don't send a reference to Computer.class over remoting channels - Logging added to help diagnose was actually causing Jenkins.class to be initialized on the remoting side (cherry picked from commit df831325b6623c479dcf4b215415f4523d10530b) --- core/src/main/java/hudson/model/Computer.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index f3fa40a971..8612d6517e 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -1159,11 +1159,11 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces try { InetAddress ia = InetAddress.getByName(address); if(!(ia instanceof Inet4Address)) { - LOGGER.fine(address+" is not an IPv4 address"); + LOGGER.log(Level.FINE, "{0} is not an IPv4 address", address); continue; } if(!ComputerPinger.checkIsReachable(ia, 3)) { - LOGGER.fine(address+" didn't respond to ping"); + LOGGER.log(Level.FINE, "{0} didn't respond to ping", address); continue; } cachedHostName = ia.getCanonicalHostName(); @@ -1171,7 +1171,10 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces return cachedHostName; } catch (IOException e) { // if a given name fails to parse on this host, we get this error - LOGGER.log(Level.FINE, "Failed to parse "+address,e); + LogRecord lr = new LogRecord(Level.FINE, "Failed to parse {0}"); + lr.setThrown(e); + lr.setParameters(new Object[]{address}); + LOGGER.log(lr); } } @@ -1195,27 +1198,29 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces } private static class ListPossibleNames extends MasterToSlaveCallable,IOException> { + private static final Logger LOGGER = Logger.getLogger(ListPossibleNames.class.getName()); + public List call() throws IOException { List names = new ArrayList(); Enumeration nis = NetworkInterface.getNetworkInterfaces(); while (nis.hasMoreElements()) { NetworkInterface ni = nis.nextElement(); - LOGGER.fine("Listing up IP addresses for "+ni.getDisplayName()); + LOGGER.log(Level.FINE, "Listing up IP addresses for {0}", ni.getDisplayName()); Enumeration e = ni.getInetAddresses(); while (e.hasMoreElements()) { InetAddress ia = e.nextElement(); if(ia.isLoopbackAddress()) { - LOGGER.fine(ia+" is a loopback address"); + LOGGER.log(Level.FINE, "{0} is a loopback address", ia); continue; } if(!(ia instanceof Inet4Address)) { - LOGGER.fine(ia+" is not an IPv4 address"); + LOGGER.log(Level.FINE, "{0} is not an IPv4 address", ia); continue; } - LOGGER.fine(ia+" is a viable candidate"); + LOGGER.log(Level.FINE, "{0} is a viable candidate", ia); names.add(ia.getHostAddress()); } } From 2906718ff53dd781a1248fff5dd56ac729438558 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Tue, 14 Jul 2015 15:22:15 +0100 Subject: [PATCH 0318/2573] [FIXED JENKINS-28844] The curious case of the Channel memory cycles Pick up the remoting 2.52 release (cherry picked from commit aac20468ff5511ea6c58de07f3bcf3ae108b9cb0) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3d7334803e..5428993d62 100644 --- a/pom.xml +++ b/pom.xml @@ -176,7 +176,7 @@ THE SOFTWARE. org.jenkins-ci.main remoting - 2.50 + 2.52 From db559bd6f5f611c588e127ff20852c81f45bc989 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 30 Jul 2015 16:28:12 -0400 Subject: [PATCH 0319/2573] =?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 0320/2573] 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 0321/2573] [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 0322/2573] 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 0323/2573] [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 0326/2573] 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 0327/2573] 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 0328/2573] =?UTF-8?q?prefer=20Computer#isUnix=20to=20be=20?= =?UTF-8?q?abstract=20few=20chances=20there=E2=80=99s=20another=20implemen?= =?UTF-8?q?tation=20but=20if=20one=20exists=20Function.isWindows=20would?= =?UTF-8?q?=20probably=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 0329/2573] [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 0330/2573] 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 0331/2573] [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 0332/2573] 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 0333/2573] [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 0334/2573] 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 0335/2573] [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 0336/2573] [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 0339/2573] 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 0340/2573] 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 0341/2573] 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 0342/2573] 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 0343/2573] [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 0344/2573] 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 0345/2573] 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 0346/2573] 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 0347/2573] 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 0348/2573] 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 b75cc47c978eed4c02ca9f9161533319eaac17bf Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Mon, 17 Aug 2015 21:19:42 -0700 Subject: [PATCH 0349/2573] [maven-release-plugin] prepare for next development iteration --- 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 c9e09db28e..637a343c8d 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.625 + 1.626-SNAPSHOT cli diff --git a/core/pom.xml b/core/pom.xml index e560e4cceb..b451812954 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.625 + 1.626-SNAPSHOT jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index e210b609a6..201ef80105 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.625 + 1.626-SNAPSHOT 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 0352/2573] [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 0353/2573] [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 0354/2573] 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 0355/2573] 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 0356/2573] 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 0357/2573] @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 0358/2573] 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 0359/2573] 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 0360/2573] 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 f2500bd51b715de5191dad1b7ed58090b63da50f Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Wed, 22 Jul 2015 10:34:37 +0100 Subject: [PATCH 0361/2573] 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 (cherry picked from commit 252e1296099e838b8fba52221910442e0a757db4) --- 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 25d23c47c9..8ce37b958e 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 db1e2d2a199f7231f85809234cc1c703d3cb67a0 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Thu, 23 Jul 2015 09:07:52 +0100 Subject: [PATCH 0362/2573] [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. (cherry picked from commit 4f0ca16b01abcd5ac84a9259736c2d96b1712354) --- .../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 8ce37b958e..c0db79480e 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 9a63d6f8cb734d99597c12263f232fc49604eeb0 Mon Sep 17 00:00:00 2001 From: James Nord Date: Thu, 13 Aug 2015 19:10:51 +0100 Subject: [PATCH 0363/2573] [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). (cherry picked from commit 8a077a801960aa74da455441cfb12d300c6d6e3a) --- .../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 06f690dbb9f491d592d42f5b911ae9d49f6e1290 Mon Sep 17 00:00:00 2001 From: James Nord Date: Thu, 20 Aug 2015 15:27:53 +0100 Subject: [PATCH 0364/2573] [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 0365/2573] 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 0366/2573] 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 0367/2573] 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 0368/2573] 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 0369/2573] 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 0370/2573] 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 0371/2573] 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 0372/2573] 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 0373/2573] 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 0374/2573] 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 0375/2573] @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 0376/2573] [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 0381/2573] [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 0382/2573] 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 0383/2573] 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 0384/2573] 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 0385/2573] 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 0386/2573] 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 0387/2573] 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 0388/2573] 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 0389/2573] 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 0390/2573] 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 0391/2573] 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 0392/2573] 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 0393/2573] 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 0394/2573] 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 0395/2573] 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 0396/2573] 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 0397/2573] 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 0398/2573] 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 0399/2573] 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 0400/2573] 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 0401/2573] 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 0402/2573] 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 0403/2573] 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 0404/2573] 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 0405/2573] 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 0406/2573] 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 0407/2573] 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 0408/2573] 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 0409/2573] 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 0410/2573] 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 0411/2573] 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 0412/2573] 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 0413/2573] 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 0414/2573] 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 0415/2573] 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 0416/2573] 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 0417/2573] 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 0418/2573] 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 0419/2573] 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 0420/2573] 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 0421/2573] 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 0422/2573] 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 0423/2573] 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 0424/2573] 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 0425/2573] 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 0426/2573] 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 0427/2573] 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 0428/2573] 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 0476/2573] 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 0477/2573] 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 0478/2573] 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 0479/2573] 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 0480/2573] 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 0481/2573] [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 0482/2573] [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 7e053afbfd2e4c38c4d7ee2fc5b42f2d33bf37c6 Mon Sep 17 00:00:00 2001 From: Peter Major Date: Sun, 30 Aug 2015 10:52:34 +0100 Subject: [PATCH 0483/2573] Make changelog URL a build parameter --- .../UpdateCenter/CoreUpdateMonitor/message.properties | 2 +- .../CoreUpdateMonitor/message_cs.properties | 2 +- .../CoreUpdateMonitor/message_da.properties | 2 +- .../CoreUpdateMonitor/message_de.properties | 2 +- .../CoreUpdateMonitor/message_es.properties | 10 +++++----- .../CoreUpdateMonitor/message_et.properties | 2 +- .../CoreUpdateMonitor/message_fi.properties | 2 +- .../CoreUpdateMonitor/message_fr.properties | 2 +- .../CoreUpdateMonitor/message_hu.properties | 2 +- .../CoreUpdateMonitor/message_id.properties | 2 +- .../CoreUpdateMonitor/message_it.properties | 2 +- .../CoreUpdateMonitor/message_ja.properties | 2 +- .../CoreUpdateMonitor/message_ko.properties | 2 +- .../CoreUpdateMonitor/message_lt.properties | 2 +- .../CoreUpdateMonitor/message_lv.properties | 2 +- .../CoreUpdateMonitor/message_nb_NO.properties | 2 +- .../CoreUpdateMonitor/message_nl.properties | 2 +- .../CoreUpdateMonitor/message_pl.properties | 2 +- .../CoreUpdateMonitor/message_pt_BR.properties | 2 +- .../CoreUpdateMonitor/message_pt_PT.properties | 2 +- .../CoreUpdateMonitor/message_ru.properties | 2 +- .../CoreUpdateMonitor/message_sk.properties | 2 +- .../CoreUpdateMonitor/message_sl.properties | 2 +- .../CoreUpdateMonitor/message_sv_SE.properties | 0 .../CoreUpdateMonitor/message_uk.properties | 2 +- .../CoreUpdateMonitor/message_zh_CN.properties | 2 +- .../CoreUpdateMonitor/message_zh_TW.properties | 2 +- pom.xml | 8 ++++++++ 28 files changed, 38 insertions(+), 30 deletions(-) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties (95%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_cs.properties (93%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_da.properties (96%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_de.properties (93%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_es.properties (66%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_et.properties (52%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fi.properties (58%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fr.properties (94%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_hu.properties (90%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_id.properties (64%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_it.properties (93%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ja.properties (93%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ko.properties (93%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lt.properties (62%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lv.properties (93%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nb_NO.properties (92%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nl.properties (93%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pl.properties (74%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_BR.properties (96%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_PT.properties (55%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ru.properties (92%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sk.properties (92%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sl.properties (61%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sv_SE.properties (100%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_uk.properties (92%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_CN.properties (77%) rename core/src/{main => filter}/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_TW.properties (92%) diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties similarity index 95% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties index d303a63fc3..c2f487f7b5 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties @@ -21,7 +21,7 @@ # THE SOFTWARE. NewVersionAvailable=New version of Jenkins ({0}) is available for download \ - (changelog). + (changelog). UpgradeComplete=Upgrade to Jenkins {0} is complete, awaiting restart. UpgradeCompleteRestartNotSupported=Upgrade to Jenkins {0} is complete, awaiting restart. UpgradeProgress=Upgrade to Jenkins {0} is in progress or failed. diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_cs.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_cs.properties similarity index 93% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_cs.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_cs.properties index 0627dbf1e4..691b46b7f0 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_cs.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_cs.properties @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -NewVersionAvailable=Nov\u00E1 verze Jenkins-u ({0}) je k dispozici ke sta\u017Een\u00ED (changelog). +NewVersionAvailable=Nov\u00E1 verze Jenkins-u ({0}) je k dispozici ke sta\u017Een\u00ED (changelog). Or\ Upgrade\ Automatically=Nebo Upgradovat Automaticky UpgradeComplete=Upgrade na Jenkinse {0} je hotov, \u010Dek\u00E1 na restart. UpgradeCompleteRestartNotSupported=Upgrade na Jenkinse {0} je hotov, \u010Dek\u00E1 na restart. diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_da.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_da.properties similarity index 96% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_da.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_da.properties index 37285e900f..8b5776e534 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_da.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_da.properties @@ -25,4 +25,4 @@ UpgradeCompleteRestartNotSupported=Opdatering til Jenkins {0} er fuldf\u00f8rt, UpgradeProgress=Opdatering til Jenkins {0} er i gang eller er fejlet. Or\ Upgrade\ Automatically=Eller opdater automatisk NewVersionAvailable=En ny version af Jenkins ({0}) er tilg\u00e6ngelig til hentning \ - (changelog). + (changelog). diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_de.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_de.properties similarity index 93% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_de.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_de.properties index 5eb9dc4079..344e457118 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_de.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_de.properties @@ -23,5 +23,5 @@ UpgradeComplete=Aktualisierung auf Jenkins {0} abgeschlossen. Neustart von Jenkins erforderlich. UpgradeCompleteRestartNotSupported=Aktualisierung auf Jenkins {0} abgeschlossen. Neustart von Jenkins erforderlich. UpgradeProgress=Aktualisierung auf Jenkins {0} in Arbeit oder fehlgeschlagen. -NewVersionAvailable=Eine neue Version von Jenkins ({0}) kann hier heruntergeladen werden (Was ist neu?). +NewVersionAvailable=Eine neue Version von Jenkins ({0}) kann hier heruntergeladen werden (Was ist neu?). Or\ Upgrade\ Automatically=Automatisch aktualisieren diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_es.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_es.properties similarity index 66% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_es.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_es.properties index f3bd1ba6f4..6016d4d17c 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_es.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_es.properties @@ -20,8 +20,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -NewVersionAvailable=Hay una nueva versión de Jenkins disponible ({0}). descargar (listado de cambios). -Or\ Upgrade\ Automatically=O actualizar automáticamente -UpgradeComplete=La actualización a Jenkins {0} se ha completado, esperando para reiniciar. -UpgradeCompleteRestartNotSupported=La actualización a Jenkins {0} se ha completado, esperando para reiniciar. -UpgradeProgress=La actualización a Jenkins {0} está en ejecución o ha fallado. +NewVersionAvailable=Hay una nueva versi\u00f3n de Jenkins disponible ({0}). descargar (listado de cambios). +Or\ Upgrade\ Automatically=O actualizar autom\u00e1ticamente +UpgradeComplete=La actualizaci\u00f3n a Jenkins {0} se ha completado, esperando para reiniciar. +UpgradeCompleteRestartNotSupported=La actualizaci\u00f3n a Jenkins {0} se ha completado, esperando para reiniciar. +UpgradeProgress=La actualizaci\u00f3n a Jenkins {0} est\u00e1 en ejecuci\u00f3n o ha fallado. diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_et.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_et.properties similarity index 52% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_et.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_et.properties index 7cd8b01f2a..1df6054b14 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_et.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_et.properties @@ -1,3 +1,3 @@ # This file is under the MIT License by authors -NewVersionAvailable=Jenkinsi uus versioon ({0}) on saadaval allalaadimiseks (muudatuste nimekiri). +NewVersionAvailable=Jenkinsi uus versioon ({0}) on saadaval allalaadimiseks (muudatuste nimekiri). diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fi.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fi.properties similarity index 58% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fi.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fi.properties index 4822e11895..8243a6f685 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fi.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fi.properties @@ -1,3 +1,3 @@ # This file is under the MIT License by authors -NewVersionAvailable=Uusi Jenkinsin versio ({0}) on saatavana (muutosloki). +NewVersionAvailable=Uusi Jenkinsin versio ({0}) on saatavana (muutosloki). diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fr.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fr.properties similarity index 94% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fr.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fr.properties index f009876578..0dbdae69d7 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fr.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fr.properties @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -NewVersionAvailable=Une nouvelle version de Jenkins ({0}) est disponible (changelog). +NewVersionAvailable=Une nouvelle version de Jenkins ({0}) est disponible (changelog). Or\ Upgrade\ Automatically=Ou mettre \u00E0 jour automatiquement UpgradeProgress=Mise \u00E0 jour vers Jenkins {0} est en cours ou en \u00E9chec. UpgradeComplete=La mise \u00E0 jour de Jenkins en {0} est termin\u00E9e, en attente de red\u00E9marrage. diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_hu.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_hu.properties similarity index 90% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_hu.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_hu.properties index c28160d659..19587285ca 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_hu.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_hu.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -NewVersionAvailable=A Jenkins \u00FAj verzi\u00F3ja ({0}) el\u00E9rhet\u0151 let\u00F6lt\u00E9sre (v\u00E1ltoz\u00E1sok). +NewVersionAvailable=A Jenkins \u00FAj verzi\u00F3ja ({0}) el\u00E9rhet\u0151 let\u00F6lt\u00E9sre (v\u00E1ltoz\u00E1sok). Or\ Upgrade\ Automatically=Vagy friss\u00EDtsen automatikusan diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_id.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_id.properties similarity index 64% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_id.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_id.properties index aa157c3f69..c28903b2dd 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_id.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_id.properties @@ -1,4 +1,4 @@ # This file is under the MIT License by authors -NewVersionAvailable=Versi baru Jenkins ({0}) tersedia untuk diunduh (catatan perubahan). +NewVersionAvailable=Versi baru Jenkins ({0}) tersedia untuk diunduh (catatan perubahan). Or\ Upgrade\ Automatically=Atau Perbarui Secara Otomatis diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_it.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_it.properties similarity index 93% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_it.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_it.properties index f6538f878e..7378e405c7 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_it.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_it.properties @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -NewVersionAvailable=C''\u00E8 una nuova versione di Jenkins ({0}) disponibile per il download (changelog). +NewVersionAvailable=C''\u00E8 una nuova versione di Jenkins ({0}) disponibile per il download (changelog). Or\ Upgrade\ Automatically=Oppure aggiorna automaticamente UpgradeComplete=Aggiornamento a Jenkins {0} completato, in attesa di riavvio. UpgradeCompleteRestartNotSupported=Aggiornamento a Jenkins {0} completato, in attesa di riavvio. diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ja.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ja.properties similarity index 93% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ja.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ja.properties index 91ea7ae49a..5738b71b76 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ja.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ja.properties @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -NewVersionAvailable=Jenkins\u306E\u65B0\u3057\u3044\u30D0\u30FC\u30B8\u30E7\u30F3({0})\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3067\u304D\u307E\u3059 (\u5909\u66F4\u5C65\u6B74)\u3002 +NewVersionAvailable=Jenkins\u306E\u65B0\u3057\u3044\u30D0\u30FC\u30B8\u30E7\u30F3({0})\u3092\u30C0\u30A6\u30F3\u30ED\u30FC\u30C9\u3067\u304D\u307E\u3059 (\u5909\u66F4\u5C65\u6B74)\u3002 Or\ Upgrade\ Automatically=\u81EA\u52D5\u3067\u30A2\u30C3\u30D7\u30B0\u30EC\u30FC\u30C9 UpgradeComplete=Jenkins {0} \u3078\u306E\u30A2\u30C3\u30D7\u30B0\u30EC\u30FC\u30C9\u306F\u5B8C\u4E86\u3057\u307E\u3057\u305F\u3002\u518D\u8D77\u52D5\u5F85\u3061\u3067\u3059\u3002 UpgradeProgress=Jenkins {0}\u3078\u306E\u30A2\u30C3\u30D7\u30B0\u30EC\u30FC\u30C9\u306F\u5B9F\u884C\u4E2D\u304B\u3001\u5931\u6557\u3057\u307E\u3057\u305F\u3002 diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ko.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ko.properties similarity index 93% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ko.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ko.properties index 3e54bb7c12..f5f6a77276 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ko.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ko.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -NewVersionAvailable=Jenkins \uC2E0\uADDC\uBC84\uC804({0})\uC744 \uC5EC\uAE30\uC11C \uBC1B\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.(\uBCC0\uACBD\uC0AC\uD56D). +NewVersionAvailable=Jenkins \uC2E0\uADDC\uBC84\uC804({0})\uC744 \uC5EC\uAE30\uC11C \uBC1B\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.(\uBCC0\uACBD\uC0AC\uD56D). Or\ Upgrade\ Automatically=\uB610\uB294 \uC790\uB3D9 \uC5C5\uADF8\uB808\uC774\uB4DC diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lt.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lt.properties similarity index 62% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lt.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lt.properties index b9995fe88b..2a16d979f6 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lt.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lt.properties @@ -1,4 +1,4 @@ # This file is under the MIT License by authors -NewVersionAvailable=Galima parsisi\u0173sti nauj\u0105 ({0}) Jenkins versij\u0105. (pakeitimai). +NewVersionAvailable=Galima parsisi\u0173sti nauj\u0105 ({0}) Jenkins versij\u0105. (pakeitimai). Or\ Upgrade\ Automatically=Parsi\u0173sti automati\u0161kai diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lv.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lv.properties similarity index 93% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lv.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lv.properties index cf14b56b6f..9193a28385 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lv.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lv.properties @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -NewVersionAvailable=Jauna Jenkins ({0}) versija ir pieejama lejupl\u0101dei (izmai\u0146as). +NewVersionAvailable=Jauna Jenkins ({0}) versija ir pieejama lejupl\u0101dei (izmai\u0146as). Or\ Upgrade\ Automatically=Vai atjaunin\u0101t autom\u0101tiski UpgradeComplete=Atjaunin\u0101s\u0101na uz Jenkins {0} ir pabeigta; gaidu p\u0101rstart\u0113\u0161anos. UpgradeCompleteRestartNotSupported=Atjaunin\u0101s\u0101na uz Jenkins {0} ir pabeigta; gaidu p\u0101rstart\u0113\u0161anos. diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nb_NO.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nb_NO.properties similarity index 92% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nb_NO.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nb_NO.properties index d86c6788e0..b15161b442 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nb_NO.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nb_NO.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -NewVersionAvailable=En ny versjon av Jenkins ({0}) er n\u00E5 tilgjengelig (Endringer). +NewVersionAvailable=En ny versjon av Jenkins ({0}) er n\u00E5 tilgjengelig (Endringer). diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nl.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nl.properties similarity index 93% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nl.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nl.properties index d3a0df68e5..9c291b0fdd 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nl.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nl.properties @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -NewVersionAvailable=Er is een nieuwere versie van Jenkins ({0}) beschikbaar. downloaden (changelog). +NewVersionAvailable=Er is een nieuwere versie van Jenkins ({0}) beschikbaar. downloaden (changelog). Or\ Upgrade\ Automatically=Of werk automatisch bij UpgradeComplete=Upgrade naar Jenkins {0} is volledig; aan het wachten op herstart. UpgradeCompleteRestartNotSupported=Upgrade naar Jenkins {0} is volledig; aan het wachten op herstart. diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pl.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pl.properties similarity index 74% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pl.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pl.properties index d22c58b0cc..0ec4e8637b 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pl.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pl.properties @@ -1,5 +1,5 @@ # This file is under the MIT License by authors -NewVersionAvailable=Nowa wersja Jenkinsa ({0}) jest dost\u0119pna do pobrania (changelog). +NewVersionAvailable=Nowa wersja Jenkinsa ({0}) jest dost\u0119pna do pobrania (changelog). Or\ Upgrade\ Automatically=Albo uaktualnij automatycznie UpgradeProgress=Aktualizacja Jenkinsa do wersji {0} trwa lub nie powiod\u0142a si\u0119. diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_BR.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_BR.properties similarity index 96% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_BR.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_BR.properties index 96e622fc3b..216eee44d9 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_BR.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_BR.properties @@ -27,5 +27,5 @@ UpgradeCompleteRestartNotSupported=Atualiza\u00e7\u00e3o do Jenkins {0} completa UpgradeProgress=Atualiza\u00e7\u00e3o para Jenkins {0} est\u00e1 em andamento ou falhou. Or\ Upgrade\ Automatically=Ou fazer a atualiza\u00e7\u00e3o automaticamente. # New version of Jenkins ({0}) is available for download \ -# (changelog). +# (changelog). NewVersionAvailable=Nova vers\u00e3o do Jenkins ({0}) est\u00e1 dispon\u00edvel em download diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_PT.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_PT.properties similarity index 55% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_PT.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_PT.properties index ad3dcdcaef..dd2d81456d 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_PT.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_PT.properties @@ -1,4 +1,4 @@ # This file is under the MIT License by authors -NewVersionAvailable=Uma nova vers\u00E3o do Jenkins ({0}) est\u00E1 dispon\u00EDvel para download (registo de altera\u00E7\u00F5es). +NewVersionAvailable=Uma nova vers\u00E3o do Jenkins ({0}) est\u00E1 dispon\u00EDvel para download (registo de altera\u00E7\u00F5es). Or\ Upgrade\ Automatically=Ou atualizar automaticamente diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ru.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ru.properties similarity index 92% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ru.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ru.properties index c3cd495635..97659c57c7 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ru.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ru.properties @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -NewVersionAvailable=\u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F Jenkins ({0}) \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u0434\u043B\u044F \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438 (\u0441\u043F\u0438\u0441\u043E\u043A \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0439). +NewVersionAvailable=\u041D\u043E\u0432\u0430\u044F \u0432\u0435\u0440\u0441\u0438\u044F Jenkins ({0}) \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u0434\u043B\u044F \u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438 (\u0441\u043F\u0438\u0441\u043E\u043A \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u0439). Or\ Upgrade\ Automatically=\u0418\u043B\u0438 \u043E\u0431\u043D\u043E\u0432\u0438\u0442\u044C \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438 UpgradeComplete=\u041E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u0434\u043E Jenkins {0} \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E, \u043E\u0436\u0438\u0434\u0430\u0435\u0442 \u043F\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438. UpgradeCompleteRestartNotSupported=\u041E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u0434\u043E Jenkins {0} \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E, \u043E\u0436\u0438\u0434\u0430\u0435\u0442 \u043F\u0435\u0440\u0435\u0437\u0430\u0433\u0440\u0443\u0437\u043A\u0438. diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sk.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sk.properties similarity index 92% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sk.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sk.properties index bca3d05fab..96543df586 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sk.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sk.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -NewVersionAvailable=Nov\u00E1 verzia Jenkins ({0}) je dostupn\u00E1 na stiahnutie (zoznam zmien). +NewVersionAvailable=Nov\u00E1 verzia Jenkins ({0}) je dostupn\u00E1 na stiahnutie (zoznam zmien). diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sl.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sl.properties similarity index 61% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sl.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sl.properties index b69224ebd3..649104bcf5 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sl.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sl.properties @@ -1,4 +1,4 @@ # This file is under the MIT License by authors -NewVersionAvailable=Nova razli\u010Dica Jenkins-a ({0}) je na voljo za prenos (seznam sprememb). +NewVersionAvailable=Nova razli\u010Dica Jenkins-a ({0}) je na voljo za prenos (seznam sprememb). Or\ Upgrade\ Automatically=ali posodobi samodejno diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sv_SE.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sv_SE.properties similarity index 100% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sv_SE.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sv_SE.properties diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_uk.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_uk.properties similarity index 92% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_uk.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_uk.properties index 3379d20367..625195c351 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_uk.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_uk.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -NewVersionAvailable=\u041D\u043E\u0432\u0430 \u0432\u0435\u0440\u0441\u0456\u044F \u0414\u0436\u0435\u043D\u043A\u0456\u043D\u0441 ({0}) \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u0434\u043B\u044F \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F (\u0437\u043C\u0456\u043D\u0438). +NewVersionAvailable=\u041D\u043E\u0432\u0430 \u0432\u0435\u0440\u0441\u0456\u044F \u0414\u0436\u0435\u043D\u043A\u0456\u043D\u0441 ({0}) \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u0430 \u0434\u043B\u044F \u0437\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F (\u0437\u043C\u0456\u043D\u0438). Or\ Upgrade\ Automatically=\u0410\u0431\u043E \u043E\u043D\u043E\u0432\u0456\u0442\u044C \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u043D\u043E diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_CN.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_CN.properties similarity index 77% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_CN.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_CN.properties index 1ddf921908..0ef79b530b 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_CN.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_CN.properties @@ -1,6 +1,6 @@ # This file is under the MIT License by authors -NewVersionAvailable=Jenkins\u65B0\u7248\u672C ({0})\u53EF\u70B9\u51FB download (\u53D8\u66F4\u8BF4\u660E)\u4E0B\u8F7D\u3002 +NewVersionAvailable=Jenkins\u65B0\u7248\u672C ({0})\u53EF\u70B9\u51FB download (\u53D8\u66F4\u8BF4\u660E)\u4E0B\u8F7D\u3002 Or\ Upgrade\ Automatically=\u6216 \u81EA\u52A8\u5347\u7EA7\u7248\u672C UpgradeComplete=Jenkins {0} \u7248\u672C\u5347\u7EA7\u5DF2\u5B8C\u6210,\u7B49\u5F85\u91CD\u542F\u4E2D. UpgradeCompleteRestartNotSupported=Jenkins {0} \u7248\u672C\u5347\u7EA7\u5DF2\u5B8C\u6210,\u7B49\u5F85\u91CD\u542F\u4E2D. diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_TW.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_TW.properties similarity index 92% rename from core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_TW.properties rename to core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_TW.properties index 0423c94c73..76967e8ea1 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_TW.properties +++ b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_TW.properties @@ -24,5 +24,5 @@ UpgradeComplete=Jenkins {0} \u5347\u7248\u5b8c\u6210\uff0c\u7b49\u5019\u91cd\u65b0\u555f\u52d5\u3002 UpgradeCompleteRestartNotSupported=Jenkins {0} \u5347\u7248\u5b8c\u6210\uff0c\u7b49\u5019\u91cd\u65b0\u555f\u52d5\u3002 UpgradeProgress=Jenkins {0} \u5347\u7d1a\u4f5c\u696d\u6b63\u5728\u9032\u884c\u4e2d\u6216\u662f\u5df2\u7d93\u5931\u6557\u3002 -NewVersionAvailable=\u65b0\u7248\u7684 Jenkins ({0}) \u5df2\u7d93\u53ef\u4ee5\u4e0b\u8f09 (\u6539\u7248\u8a18\u9304)\u3002 +NewVersionAvailable=\u65b0\u7248\u7684 Jenkins ({0}) \u5df2\u7d93\u53ef\u4ee5\u4e0b\u8f09 (\u6539\u7248\u8a18\u9304)\u3002 Or\ Upgrade\ Automatically=\u6216\u662f\u81ea\u52d5\u5347\u7248 diff --git a/pom.xml b/pom.xml index 3268fddcfd..0d0cc293fb 100644 --- a/pom.xml +++ b/pom.xml @@ -104,6 +104,8 @@ THE SOFTWARE. 1.2 7 + + https://jenkins-ci.org/changelog @@ -844,6 +846,12 @@ THE SOFTWARE. + + lts-release + + https://jenkins-ci.org/changelog-stable + + m2e From 51d13389c0f4949d506997726c8e690f118ddef0 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 30 Aug 2015 14:58:07 -0700 Subject: [PATCH 0484/2573] [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 8fc5b5f161de2481f781d03f95256c920ec3feb2 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Tue, 1 Sep 2015 11:14:20 -0700 Subject: [PATCH 0487/2573] Add new plugin labels to clean up Plugin Manager --- core/src/main/resources/hudson/model/Messages.properties | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/src/main/resources/hudson/model/Messages.properties b/core/src/main/resources/hudson/model/Messages.properties index 445939f472..cedfbd4440 100644 --- a/core/src/main/resources/hudson/model/Messages.properties +++ b/core/src/main/resources/hudson/model/Messages.properties @@ -280,6 +280,7 @@ UpdateCenter.PluginCategory.android=Android Development UpdateCenter.PluginCategory.builder=Build Tools UpdateCenter.PluginCategory.buildwrapper=Build Wrappers UpdateCenter.PluginCategory.cli=Command Line Interface +UpdateCenter.PluginCategory.cloud=Cloud Providers UpdateCenter.PluginCategory.cluster=Cluster Management and Distributed Build UpdateCenter.PluginCategory.database=Database UpdateCenter.PluginCategory.deployment=Deployment @@ -296,18 +297,21 @@ UpdateCenter.PluginCategory.notifier=Build Notifiers UpdateCenter.PluginCategory.page-decorator=Page Decorators UpdateCenter.PluginCategory.parameter=Build Parameters UpdateCenter.PluginCategory.post-build=Other Post-Build Actions -UpdateCenter.PluginCategory.publisher=Other Post-Build Actions +UpdateCenter.PluginCategory.python=Python Development UpdateCenter.PluginCategory.report=Build Reports -UpdateCenter.PluginCategory.ruby=Ruby +UpdateCenter.PluginCategory.ruby=Ruby Development UpdateCenter.PluginCategory.runcondition=RunConditions for use by the Run Condition plugin +UpdateCenter.PluginCategory.scala=Scala Development UpdateCenter.PluginCategory.scm=Source Code Management UpdateCenter.PluginCategory.scm-related=Source Code Management related UpdateCenter.PluginCategory.security=Security UpdateCenter.PluginCategory.slaves=Slave Launchers and Controllers +UpdateCenter.PluginCategory.test=Testing UpdateCenter.PluginCategory.trigger=Build Triggers UpdateCenter.PluginCategory.ui=User Interface UpdateCenter.PluginCategory.upload=Artifact Uploaders UpdateCenter.PluginCategory.user=Authentication and User Management +UpdateCenter.PluginCategory.view=Views UpdateCenter.PluginCategory.must-be-labeled=Uncategorized UpdateCenter.PluginCategory.unrecognized=Misc ({0}) From b61a4095904f3d1b148a3546c573f04c53c1019e Mon Sep 17 00:00:00 2001 From: Mirko Friedenhagen Date: Tue, 1 Sep 2015 22:47:13 +0200 Subject: [PATCH 0488/2573] 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 0489/2573] 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 0490/2573] 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 0491/2573] 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 0492/2573] 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 0493/2573] 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 e2d62f84b117a6b07f6136391420f0c0f89a4f19 Mon Sep 17 00:00:00 2001 From: szczechp Date: Wed, 2 Sep 2015 11:58:47 +0200 Subject: [PATCH 0494/2573] Add task-icon-link class to left menu remove and wipe workspace navigation links. --- core/src/main/resources/lib/layout/task.jelly | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/layout/task.jelly b/core/src/main/resources/lib/layout/task.jelly index d120faa495..fa08cc56fa 100644 --- a/core/src/main/resources/lib/layout/task.jelly +++ b/core/src/main/resources/lib/layout/task.jelly @@ -167,7 +167,7 @@ THE SOFTWARE. - + From c105ce5ab430708226cdab3bfa407b9b680c4e73 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Wed, 2 Sep 2015 22:50:11 -0700 Subject: [PATCH 0495/2573] [maven-release-plugin] prepare release jenkins-1.609.3 --- 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 171ce97509..4b64ad0bdf 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.609.3-SNAPSHOT + 1.609.3 cli diff --git a/core/pom.xml b/core/pom.xml index 38fb0192aa..ae5b592048 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.609.3-SNAPSHOT + 1.609.3 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index 112379ba4d..f27baf7afe 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.609.3-SNAPSHOT + 1.609.3 pom 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 0498/2573] 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 0499/2573] [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 0502/2573] [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 f53802bb82a25b295b6dfa3bf2a591a6c8552183 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Mon, 7 Sep 2015 15:36:27 +0300 Subject: [PATCH 0503/2573] [SECURITY-169] - Convert crumb issuer salt to the confidential key --- .../main/java/hudson/security/csrf/DefaultCrumbIssuer.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java b/core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java index f23699b758..b801866fa6 100644 --- a/core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java +++ b/core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java @@ -17,6 +17,7 @@ import hudson.model.ModelObject; import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; +import jenkins.security.HexStringConfidentialKey; import net.sf.json.JSONObject; @@ -117,9 +118,10 @@ public class DefaultCrumbIssuer extends CrumbIssuer { @Extension public static final class DescriptorImpl extends CrumbIssuerDescriptor implements ModelObject { + private final static HexStringConfidentialKey CRUMB_SALT = new HexStringConfidentialKey(Jenkins.class,"crumbSalt",16); + public DescriptorImpl() { - // salt just needs to be unique, and it doesn't have to be a secret - super(Jenkins.getInstance().getLegacyInstanceId(), System.getProperty("hudson.security.csrf.requestfield", ".crumb")); + super(CRUMB_SALT.get(), System.getProperty("hudson.security.csrf.requestfield", ".crumb")); load(); } From 2c5deeb6c061a91aeac232e978756de3b1d0be98 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Thu, 10 Sep 2015 14:25:04 +0100 Subject: [PATCH 0504/2573] [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 1002ada4ddef9109b3d9775c911eea6d9c1330db Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Fri, 4 Sep 2015 11:46:08 +0300 Subject: [PATCH 0505/2573] [SECURITY-195] - Direct unit test for the issue --- .../test/java/hudson/model/SlaveTest2.java | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 test/src/test/java/hudson/model/SlaveTest2.java diff --git a/test/src/test/java/hudson/model/SlaveTest2.java b/test/src/test/java/hudson/model/SlaveTest2.java new file mode 100644 index 0000000000..532fa858c5 --- /dev/null +++ b/test/src/test/java/hudson/model/SlaveTest2.java @@ -0,0 +1,66 @@ +/* + * 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.model; + +import java.net.MalformedURLException; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; + +import static org.junit.Assert.*; +import org.jvnet.hudson.test.Bug; + +/** + * Tests for the {@link Slave} class. + * There is also a Groovy implementation of such test file, hence the class name + * has an index. + * @author Oleg Nenashev + */ +public class SlaveTest2 { + + @Rule + public JenkinsRule rule = new JenkinsRule(); + + @Test + //TODO: uncomment after upgrading to the new core version (1.580+) + //@Issue("SECURITY-195") + public void shouldNotEscapeJnlpSlavesResources() throws Exception { + Slave slave = rule.createSlave(); + + // Raw access to API + Slave.JnlpJar jnlpJar = slave.getComputer().getJnlpJars("../"); + try { + jnlpJar.getURL(); + } catch (MalformedURLException ex) { + // we expect the exception here + ex.printStackTrace(); + return; + } + fail("Expected the MalformedURLException"); + + // Access from a Web client + JenkinsRule.WebClient client = rule.createWebClient(); + client.assertFails("jnlpJars/..%f", 500); + } +} From 5431e397216b4ab80e58bdabcb06a0066bce6592 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Fri, 4 Sep 2015 11:47:14 +0300 Subject: [PATCH 0506/2573] [SECURITY-195] - Throw the MalformedURLException if the request includes the relative addressing --- core/src/main/java/hudson/model/Slave.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/src/main/java/hudson/model/Slave.java b/core/src/main/java/hudson/model/Slave.java index 5c1a204796..3b20de4ad0 100644 --- a/core/src/main/java/hudson/model/Slave.java +++ b/core/src/main/java/hudson/model/Slave.java @@ -323,6 +323,13 @@ public abstract class Slave extends Node implements Serializable { public URL getURL() throws MalformedURLException { String name = fileName; if (name.equals("hudson-cli.jar")) name="jenkins-cli.jar"; + + // Prevent the sandbox escaping (SECURITY-195) + if (name.contains("..")) { + throw new MalformedURLException("The specified file path " + fileName + " contains '..'. " + + "The path is not allowed due to security reasons"); + } + URL res = Jenkins.getInstance().servletContext.getResource("/WEB-INF/" + name); if(res==null) { // during the development this path doesn't have the files. From f22db8a7fab9f83dade918dda77e4eb92913f920 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Fri, 4 Sep 2015 14:23:17 +0300 Subject: [PATCH 0507/2573] Update the implementation and tests according to comments from @stephenc --- core/src/main/java/hudson/model/Slave.java | 3 +- .../test/java/hudson/model/SlaveTest2.java | 36 +++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/hudson/model/Slave.java b/core/src/main/java/hudson/model/Slave.java index 3b20de4ad0..d2c3bb871b 100644 --- a/core/src/main/java/hudson/model/Slave.java +++ b/core/src/main/java/hudson/model/Slave.java @@ -325,7 +325,8 @@ public abstract class Slave extends Node implements Serializable { if (name.equals("hudson-cli.jar")) name="jenkins-cli.jar"; // Prevent the sandbox escaping (SECURITY-195) - if (name.contains("..")) { + if (name.equals("..") || name.startsWith("../") || name.startsWith("..\\") || + name.replace('\\','/').contains("/../")) { throw new MalformedURLException("The specified file path " + fileName + " contains '..'. " + "The path is not allowed due to security reasons"); } diff --git a/test/src/test/java/hudson/model/SlaveTest2.java b/test/src/test/java/hudson/model/SlaveTest2.java index 532fa858c5..7df721afcc 100644 --- a/test/src/test/java/hudson/model/SlaveTest2.java +++ b/test/src/test/java/hudson/model/SlaveTest2.java @@ -24,6 +24,8 @@ package hudson.model; import java.net.MalformedURLException; +import java.net.URLEncoder; +import javax.annotation.Nonnull; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; @@ -48,8 +50,23 @@ public class SlaveTest2 { public void shouldNotEscapeJnlpSlavesResources() throws Exception { Slave slave = rule.createSlave(); + // Spot-check correct requests + assertJnlpJarUrlIsAllowed(slave, "slave.jar"); + assertJnlpJarUrlIsAllowed(slave, "jenkins-cli.jar"); + + // Go to the upper level + assertJnlpJarUrlFails(slave, "../"); + assertJnlpJarUrlFails(slave, ".."); + assertJnlpJarUrlFails(slave, "..\\"); + assertJnlpJarUrlFails(slave, "../foo/bar"); + assertJnlpJarUrlFails(slave, "..\\foo\\bar"); + assertJnlpJarUrlFails(slave, "foo/../../bar"); + assertJnlpJarUrlFails(slave, "./../foo/bar"); + } + + private void assertJnlpJarUrlFails(@Nonnull Slave slave, @Nonnull String url) throws Exception { // Raw access to API - Slave.JnlpJar jnlpJar = slave.getComputer().getJnlpJars("../"); + Slave.JnlpJar jnlpJar = slave.getComputer().getJnlpJars(url); try { jnlpJar.getURL(); } catch (MalformedURLException ex) { @@ -57,10 +74,23 @@ public class SlaveTest2 { ex.printStackTrace(); return; } - fail("Expected the MalformedURLException"); + fail("Expected the MalformedURLException for " + url); // Access from a Web client JenkinsRule.WebClient client = rule.createWebClient(); - client.assertFails("jnlpJars/..%f", 500); + client.assertFails("jnlpJars/" + URLEncoder.encode(url, "UTF-8"), 500); + } + + private void assertJnlpJarUrlIsAllowed(@Nonnull Slave slave, @Nonnull String url) throws Exception { + // Raw access to API + Slave.JnlpJar jnlpJar = slave.getComputer().getJnlpJars(url); + assertNotNull(jnlpJar.getURL()); + + + // Access from a Web client + JenkinsRule.WebClient client = rule.createWebClient(); + client.getPage(client.getContextPath() + "jnlpJars/" + URLEncoder.encode(url, "UTF-8")).getWebResponse().getContentAsString(); + client.getPage(jnlpJar.getURL()).getWebResponse().getContentAsString(); + } } From 9a57858a925aea1a01da9061d60e91e37d319873 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Thu, 10 Sep 2015 14:49:57 +0100 Subject: [PATCH 0508/2573] [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 8af3ab5ae8f9dac3367f31b351fa414a70d412f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Thu, 10 Sep 2015 16:14:42 +0200 Subject: [PATCH 0509/2573] Towards 1.625.1 --- 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 c9e09db28e..29896a6570 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.625 + 1.625.1-SNAPSHOT cli diff --git a/core/pom.xml b/core/pom.xml index e560e4cceb..079099f59b 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.625 + 1.625.1-SNAPSHOT jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index e210b609a6..2acfb16364 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.625 + 1.625.1-SNAPSHOT pom +

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

                    +
                      +
                    • +

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

                    • From d68bbfcf86531f0b27cc2ba3bf0b8b8666ee4813 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Thu, 10 Sep 2015 14:25:04 +0100 Subject: [PATCH 0519/2573] [JENKINS-30139] Switch from a big fat lock to a concurrent collection (cherry picked from commit 2c5deeb6c061a91aeac232e978756de3b1d0be98) --- .../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 108f2c4b23aa0fd4fc8343a446a5de46b7ac87dc Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Thu, 10 Sep 2015 14:49:57 +0100 Subject: [PATCH 0520/2573] [JENKINS-30139] Add @Restricted to prevent external use of internal data (cherry picked from commit 9a57858a925aea1a01da9061d60e91e37d319873) --- .../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 52b265b18688ce9142024d1bc2b3b986d9b066f9 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Thu, 10 Sep 2015 15:54:10 +0100 Subject: [PATCH 0521/2573] [JENKINS-30139] Forgot to change this one (cherry picked from commit 67cce20291be4d4002d7e293f1e0de6ee60058f3) --- 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 806f529d8fcd3f91a2fef49c63a2274c8d3f2228 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Fri, 11 Sep 2015 09:25:56 +0100 Subject: [PATCH 0522/2573] [JENKINS-30139] Oleg wants to keep the data accessible so we have to go for immutable (cherry picked from commit e9471744338546539ed163d106763be021f278f8) --- .../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 9f5f292f3fe1dac2689c5d5437cca13c5b395473 Mon Sep 17 00:00:00 2001 From: David Hoover Date: Tue, 15 Sep 2015 10:02:06 -0700 Subject: [PATCH 0523/2573] Improve readability of Jenkins.getTarget() The ~dozen inlined options and braceless conditional weren't the easiest to read, especially with the one compound statement in there. Took me a minute to convince myself that operator precedence & associativity really made that work as intended. I *think* those strings could drop their slashes and be combined with the other loop (e.g. go over Sets.concat(ALWAYS_READABLE_PATHS, getUnprotectedRootActions()), but without spending more time confirming that, I'm leaving the behavior exactly the same as it was before. --- core/src/main/java/jenkins/model/Jenkins.java | 45 +++++++++++++------ 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index ade0908991..4a156ab862 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -28,6 +28,7 @@ package jenkins.model; import antlr.ANTLRException; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.inject.Injector; import com.thoughtworks.xstream.XStream; @@ -3843,26 +3844,24 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve checkPermission(READ); } catch (AccessDeniedException e) { String rest = Stapler.getCurrentRequest().getRestOfPath(); - if(rest.startsWith("/login") - || rest.startsWith("/logout") - || rest.startsWith("/accessDenied") - || rest.startsWith("/adjuncts/") - || rest.startsWith("/error") - || rest.startsWith("/oops") - || rest.startsWith("/signup") - || rest.startsWith("/tcpSlaveAgentListener") - // TODO SlaveComputer.doSlaveAgentJnlp; there should be an annotation to request unprotected access - || rest.matches("/computer/[^/]+/slave-agent[.]jnlp") && "true".equals(Stapler.getCurrentRequest().getParameter("encrypt")) - || rest.startsWith("/federatedLoginService/") - || rest.startsWith("/securityRealm")) - return this; // URLs that are always visible without READ permission - + for (String name : ALWAYS_READABLE_PATHS) { + if (rest.startsWith(name)) { + return this; + } + } for (String name : getUnprotectedRootActions()) { if (rest.startsWith("/" + name + "/") || rest.equals("/" + name)) { return this; } } + // TODO SlaveComputer.doSlaveAgentJnlp; there should be an annotation to request unprotected access + if (rest.matches("/computer/[^/]+/slave-agent[.]jnlp") + && "true".equals(Stapler.getCurrentRequest().getParameter("encrypt"))) { + return this; + } + + throw e; } return this; @@ -4242,6 +4241,24 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve public static final Permission READ = new Permission(PERMISSIONS,"Read",Messages._Hudson_ReadPermission_Description(),Permission.READ,PermissionScope.JENKINS); public static final Permission RUN_SCRIPTS = new Permission(PERMISSIONS, "RunScripts", Messages._Hudson_RunScriptsPermission_Description(),ADMINISTER,PermissionScope.JENKINS); + /** + * Urls that are always visible without READ permission. + * + *

                      See also:{@link #getUnprotectedRootActions}. + */ + private static final ImmutableSet ALWAYS_READABLE_PATHS = ImmutableSet.of( + "/login", + "/logout", + "/accessDenied", + "/adjuncts/", + "/error", + "/oops", + "/signup", + "/tcpSlaveAgentListener", + "/federatedLoginService/", + "/securityRealm" + ); + /** * {@link Authentication} object that represents the anonymous user. * Because Acegi creates its own {@link AnonymousAuthenticationToken} instances, the code must not From 72dc7c9bd72b5c9d54945a3aa7048eccc4cdbbc5 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Tue, 15 Sep 2015 23:19:09 +0200 Subject: [PATCH 0524/2573] 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 0525/2573] 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)

                      From 6f249667777928ce4ecfb2c33bd8b0cc0a0dfb9d Mon Sep 17 00:00:00 2001 From: tfennelly Date: Wed, 16 Sep 2015 12:12:57 +0100 Subject: [PATCH 0526/2573] Added a fuzzy search for when search terms are not used Easier for users - nothing to learn --- .../jenkins/widgets/HistoryPageFilter.java | 9 +- .../BuildSearchParamProcessorList.java | 97 ++++++++++++++----- .../buildsearch/BuildSearchParams.java | 22 +++++ .../jenkins/widgets/buildsearch/README.md | 10 +- .../DescriptionProcessorFactory.java | 3 + .../processors/NameProcessorFactory.java | 3 + .../processors/ResultProcessorFactory.java | 3 + .../hudson/widgets/HistoryWidget/index.jelly | 2 +- 8 files changed, 116 insertions(+), 33 deletions(-) diff --git a/core/src/main/java/jenkins/widgets/HistoryPageFilter.java b/core/src/main/java/jenkins/widgets/HistoryPageFilter.java index 30f2596aed..04e0c222ab 100644 --- a/core/src/main/java/jenkins/widgets/HistoryPageFilter.java +++ b/core/src/main/java/jenkins/widgets/HistoryPageFilter.java @@ -27,6 +27,7 @@ import hudson.model.Job; import hudson.model.Queue; import hudson.model.Run; import hudson.widgets.HistoryWidget; +import jenkins.widgets.buildsearch.BuildSearchParamProcessor; import jenkins.widgets.buildsearch.BuildSearchParamProcessorList; import jenkins.widgets.buildsearch.BuildSearchParams; @@ -46,7 +47,7 @@ public class HistoryPageFilter { private final int maxEntries; private Long newerThan; private Long olderThan; - private BuildSearchParamProcessorList searchParamProcessorList; + private BuildSearchParamProcessor searchProcessor; // Need to use different Lists for Queue.Items and Runs because // we need access to them separately in the jelly files for rendering. @@ -98,7 +99,7 @@ public class HistoryPageFilter { */ public void setSearchString(@Nonnull String searchString) { BuildSearchParams searchParams = new BuildSearchParams(searchString); - this.searchParamProcessorList = new BuildSearchParamProcessorList(searchParams); + this.searchProcessor = new BuildSearchParamProcessorList(searchParams); } /** @@ -249,14 +250,14 @@ public class HistoryPageFilter { // to the page initially, newerThan then cutting it back down to size using cutLeading() if (entry instanceof Queue.Item) { Queue.Item item = (Queue.Item) entry; - if (searchParamProcessorList != null && !searchParamProcessorList.fitsSearchParams(item)) { + if (searchProcessor != null && !searchProcessor.fitsSearchParams(item)) { return false; } addQueueItem(item); return true; } else if (entry instanceof Run) { Run run = (Run) entry; - if (searchParamProcessorList != null && !searchParamProcessorList.fitsSearchParams(run)) { + if (searchProcessor != null && !searchProcessor.fitsSearchParams(run)) { return false; } addRun(run); diff --git a/core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParamProcessorList.java b/core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParamProcessorList.java index 99c56bc8e2..aa453823bb 100644 --- a/core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParamProcessorList.java +++ b/core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParamProcessorList.java @@ -28,6 +28,8 @@ import hudson.model.Run; import javax.annotation.Nonnull; import java.util.ArrayList; +import java.util.Collections; +import java.util.List; /** * Wrapper class for the list of {@link jenkins.widgets.buildsearch.BuildSearchParamProcessor} needed to process/apply @@ -35,57 +37,100 @@ import java.util.ArrayList; * * @author tom.fennelly@gmail.com */ -public class BuildSearchParamProcessorList { +public class BuildSearchParamProcessorList extends BuildSearchParamProcessor { - private final ArrayList processors; + private final String searchString; + private final List processors; /** * Create a {@link BuildSearchParamProcessorList} instance from a set of {@link jenkins.widgets.buildsearch.BuildSearchParams}. * @param searchParams The search parameters to use for creating the {@link BuildSearchParamProcessorList}. */ public BuildSearchParamProcessorList(@Nonnull BuildSearchParams searchParams) { - processors = new ArrayList(); - for (BuildSearchParamProcessorFactory factory : BuildSearchParamProcessorFactory.all()) { - BuildSearchParamProcessor processor = factory.createProcessor(searchParams); - if (processor != null) { - processors.add(processor); + this.searchString = searchParams.getSearchString().toLowerCase(); + if (searchParams.size() != 0) { + processors = new ArrayList(); + for (BuildSearchParamProcessorFactory factory : BuildSearchParamProcessorFactory.all()) { + BuildSearchParamProcessor processor = factory.createProcessor(searchParams); + if (processor != null) { + processors.add(processor); + } } + } else { + processors = Collections.emptyList(); } } - public ArrayList getProcessors() { + public List getProcessors() { return processors; } /** - * Does the supplied {@link hudson.model.Queue.Item} fit the {@link BuildSearchParams} used to create this - * {@link BuildSearchParamProcessorList} instance. - * @param item The {@link hudson.model.Queue.Item} to test. - * @return {@code true} if the {@link hudson.model.Queue.Item} fits all of the {@link BuildSearchParamProcessor}s - * on this {@link BuildSearchParamProcessorList}, otherwise {@code false}. + * {@inheritDoc} */ + @Override public boolean fitsSearchParams(@Nonnull Queue.Item item) { - for (BuildSearchParamProcessor processor : processors) { - if (!processor.fitsSearchParams(item)) { - return false; + if (!processors.isEmpty()) { + for (BuildSearchParamProcessor processor : processors) { + if (!processor.fitsSearchParams(item)) { + return false; + } } + // All the selected processors "liked" the search term. + return true; + } else { + if (fitsSearchParams(item.getDisplayName())) { + return true; + } else if (fitsSearchParams(item.getId())) { + return true; + } + // Non of the fuzzy matches "liked" the search term. + return false; } - return true; } /** - * Does the supplied {@link hudson.model.Run} fit the {@link BuildSearchParams} used to create this - * {@link BuildSearchParamProcessorList} instance. - * @param run The {@link hudson.model.Run} to test. - * @return {@code true} if the {@link hudson.model.Run} fits all of the {@link BuildSearchParamProcessor}s - * on this {@link BuildSearchParamProcessorList}, otherwise {@code false}. + * {@inheritDoc} */ + @Override public boolean fitsSearchParams(@Nonnull Run run) { - for (BuildSearchParamProcessor processor : processors) { - if (!processor.fitsSearchParams(run)) { - return false; + if (!processors.isEmpty()) { + for (BuildSearchParamProcessor processor : processors) { + if (!processor.fitsSearchParams(run)) { + return false; + } + } + // All the selected processors "liked" the search term. + return true; + } else { + if (fitsSearchParams(run.getDisplayName())) { + return true; + } else if (fitsSearchParams(run.getDescription())) { + return true; + } else if (fitsSearchParams(run.getNumber())) { + return true; + } else if (fitsSearchParams(run.getQueueId())) { + return true; + } else if (fitsSearchParams(run.getResult())) { + return true; + } + // Non of the fuzzy matches "liked" the search term. + return false; + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean fitsSearchParams(Object data) { + if (data != null) { + if (data instanceof Number) { + return data.toString().equals(searchString); + } else { + return data.toString().toLowerCase().contains(searchString); } } - return true; + return false; } } diff --git a/core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParams.java b/core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParams.java index f7112c585f..ce9496b5b1 100644 --- a/core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParams.java +++ b/core/src/main/java/jenkins/widgets/buildsearch/BuildSearchParams.java @@ -25,6 +25,7 @@ package jenkins.widgets.buildsearch; import javax.annotation.Nonnull; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; @@ -113,6 +114,27 @@ public class BuildSearchParams { } } + /** + * Get the underlying/raw search string as entered by the user. + * @return The underlying/raw search string as entered by the user. + */ + public String getSearchString() { + return searchString; + } + + /** + * Get the total parameter count across all search terms. + * @return The total parameter count across all search terms. + */ + public int size() { + int paramCount = 0; + Collection> searchParams = searchParamsSets.values(); + for (List searchParam : searchParams) { + paramCount += searchParam.size(); + } + return paramCount; + } + public List getParams(@Nonnull String searchTerm) { List params = searchParamsSets.get(searchTerm); if (params == null) { diff --git a/core/src/main/java/jenkins/widgets/buildsearch/README.md b/core/src/main/java/jenkins/widgets/buildsearch/README.md index 38345b433c..4c0d3fe342 100644 --- a/core/src/main/java/jenkins/widgets/buildsearch/README.md +++ b/core/src/main/java/jenkins/widgets/buildsearch/README.md @@ -1,6 +1,12 @@ __TODO__: Move to jenkins-ci web/wiki if changes accepted. -## Search Terms +# Fuzzy Search +This is obviously the easiest form of build item search. Just enter a string in the "find" box and build +items/runs will be matched across a number of predefined fields (number, name, status description etc). + +For more control, see the next section. + +# Search Terms * [__name:__] : Is contained in the name of the build. * [__desc:__] : Is contained in the description of the build.d. @@ -13,7 +19,7 @@ Different search terms are __AND__ together to result in a matching Build, while Is interpreted as: "(result: FAILURE) AND (desc: staging OR desc: production)" -## Examples +# Examples Builds that contain the words "staging" or "production" in the description: diff --git a/core/src/main/java/jenkins/widgets/buildsearch/processors/DescriptionProcessorFactory.java b/core/src/main/java/jenkins/widgets/buildsearch/processors/DescriptionProcessorFactory.java index fd598fb88d..65e95030e7 100644 --- a/core/src/main/java/jenkins/widgets/buildsearch/processors/DescriptionProcessorFactory.java +++ b/core/src/main/java/jenkins/widgets/buildsearch/processors/DescriptionProcessorFactory.java @@ -69,6 +69,9 @@ public class DescriptionProcessorFactory extends BuildSearchParamProcessorFactor @Override public boolean fitsSearchParams(String description) { + if (description == null) { + return false; + } // It fits if it contains any of the specified "desc" search terms. for (BuildSearchParams.BuildSearchParam nameParam : descParams) { if (description.contains(nameParam.get())) { diff --git a/core/src/main/java/jenkins/widgets/buildsearch/processors/NameProcessorFactory.java b/core/src/main/java/jenkins/widgets/buildsearch/processors/NameProcessorFactory.java index 3d67e0d00c..8b1655b440 100644 --- a/core/src/main/java/jenkins/widgets/buildsearch/processors/NameProcessorFactory.java +++ b/core/src/main/java/jenkins/widgets/buildsearch/processors/NameProcessorFactory.java @@ -69,6 +69,9 @@ public class NameProcessorFactory extends BuildSearchParamProcessorFactory { @Override public boolean fitsSearchParams(String name) { + if (name == null) { + return false; + } // It fits if it contains any of the specified "name" search terms. for (BuildSearchParams.BuildSearchParam nameParam : nameParams) { if (name.contains(nameParam.get())) { diff --git a/core/src/main/java/jenkins/widgets/buildsearch/processors/ResultProcessorFactory.java b/core/src/main/java/jenkins/widgets/buildsearch/processors/ResultProcessorFactory.java index e8553858a2..dd7cf7d756 100644 --- a/core/src/main/java/jenkins/widgets/buildsearch/processors/ResultProcessorFactory.java +++ b/core/src/main/java/jenkins/widgets/buildsearch/processors/ResultProcessorFactory.java @@ -80,6 +80,9 @@ public class ResultProcessorFactory extends BuildSearchParamProcessorFactory { @Override public boolean fitsSearchParams(Result result) { + if (result == null) { + return false; + } // It fits if it's any of the specified "result" search terms. return interestingResults.contains(result); } diff --git a/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly b/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly index e384a99544..b8ba9069bb 100644 --- a/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly +++ b/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly @@ -69,7 +69,7 @@ THE SOFTWARE. - + From 63e6ac6d64542ccff20cbaf0b4399a00178336cb Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Thu, 17 Sep 2015 09:57:41 +0100 Subject: [PATCH 0527/2573] Oops forgot to convert the `@since TODO`s after merge --- core/src/main/java/hudson/model/TopLevelItemDescriptor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/hudson/model/TopLevelItemDescriptor.java b/core/src/main/java/hudson/model/TopLevelItemDescriptor.java index 7aa4145a1a..0b5e97f2d7 100644 --- a/core/src/main/java/hudson/model/TopLevelItemDescriptor.java +++ b/core/src/main/java/hudson/model/TopLevelItemDescriptor.java @@ -66,7 +66,7 @@ public abstract class TopLevelItemDescriptor extends Descriptor { * {@link TopLevelItemDescriptor}s often may want to limit the scope within which they can be created. * This method allows the subtype of {@link TopLevelItemDescriptor}s to filter them out. * - * @since TODO + * @since 1.607 */ public boolean isApplicableIn(ItemGroup parent) { return true; @@ -76,7 +76,7 @@ public abstract class TopLevelItemDescriptor extends Descriptor { * Checks if this top level item is applicable within the specified item group. *

                      * This is just a convenience function. - * @since TODO + * @since 1.607 */ public final void checkApplicableIn(ItemGroup parent) { if (!isApplicableIn(parent)) { From 8f29260b177957a4082bffb271c9835adfa79bff Mon Sep 17 00:00:00 2001 From: Vojtech Juranek Date: Tue, 18 Aug 2015 12:58:03 +0200 Subject: [PATCH 0528/2573] [FIXED JENKINS-29507] Make JenkinsRule useable on systems without glibc --- core/src/main/java/hudson/Functions.java | 10 ++++++++++ .../main/java/org/jvnet/hudson/test/JenkinsRule.java | 6 +++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/hudson/Functions.java b/core/src/main/java/hudson/Functions.java index 4ecd7721d8..f9dcb93654 100644 --- a/core/src/main/java/hudson/Functions.java +++ b/core/src/main/java/hudson/Functions.java @@ -75,6 +75,7 @@ import hudson.tasks.UserAvatarResolver; import hudson.util.Area; import hudson.util.FormValidation.CheckMethod; import hudson.util.Iterators; +import hudson.util.jna.GNUCLibrary; import hudson.util.Secret; import hudson.views.MyViewsTabBar; import hudson.views.ViewsTabBar; @@ -459,6 +460,15 @@ public class Functions { public static boolean isWindows() { return File.pathSeparatorChar==';'; } + + public static boolean isGlibcSupported() { + try { + GNUCLibrary.LIBC.getpid(); + return true; + } catch(Throwable t) { + return false; + } + } public static List getLogRecords() { return Jenkins.logRecords; 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 20bb06a033..79324f9d64 100644 --- a/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -696,7 +696,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { mvn.copyFrom(JenkinsRule.class.getClassLoader().getResource(mavenVersion + "-bin.zip")); mvn.unzip(new FilePath(buildDirectory)); // TODO: switch to tar that preserves file permissions more easily - if(!Functions.isWindows()) + if(Functions.isGlibcSupported()) GNUCLibrary.LIBC.chmod(new File(mvnHome, "bin/mvn").getPath(),0755); Maven.MavenInstallation mavenInstallation = new Maven.MavenInstallation("default", @@ -720,7 +720,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { File antHome = createTmpDir(); ant.unzip(new FilePath(antHome)); // TODO: switch to tar that preserves file permissions more easily - if(!Functions.isWindows()) + if(Functions.isGlibcSupported()) GNUCLibrary.LIBC.chmod(new File(antHome,"apache-ant-1.8.1/bin/ant").getPath(),0755); antInstallation = new Ant.AntInstallation("default", new File(antHome,"apache-ant-1.8.1").getAbsolutePath(),NO_PROPERTIES); @@ -2318,7 +2318,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { // this also prevents tests from falsely advertising Hudson DNSMultiCast.disabled = true; - if (!Functions.isWindows()) { + if (Functions.isGlibcSupported()) { try { GNUCLibrary.LIBC.unsetenv("MAVEN_OPTS"); GNUCLibrary.LIBC.unsetenv("MAVEN_DEBUG_OPTS"); From 1716bf4c3ada0fe4fb6c76029b585203d7ef8265 Mon Sep 17 00:00:00 2001 From: Vojtech Juranek Date: Thu, 17 Sep 2015 20:03:39 +0200 Subject: [PATCH 0529/2573] Add changelog record for PR #1803 --- changelog.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.html b/changelog.html index 4a165300ef..48c73a0420 100644 --- a/changelog.html +++ b/changelog.html @@ -55,7 +55,9 @@ Upcoming changes

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

                      From d86a88ab042cc55530d91e745af9e0886e8eeb79 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Tue, 11 Aug 2015 18:52:14 +0200 Subject: [PATCH 0530/2573] Windows installer improvement --- war/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/war/pom.xml b/war/pom.xml index 4aa40ba7d6..7387bdef31 100644 --- a/war/pom.xml +++ b/war/pom.xml @@ -119,7 +119,7 @@ THE SOFTWARE. org.jenkins-ci.modules windows-slave-installer - 1.4 + 1.5 org.jenkins-ci.modules From 22d9db09d56c1caa2a8a3e008e6bd29f5c9ed395 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Fri, 18 Sep 2015 17:11:30 +0300 Subject: [PATCH 0531/2573] Update windows-slave-installer dependency to 1.5.1 Jenkins issues: JENKINS-10547, JENKINS-22685 Changes in winsw: * https://github.com/kohsuke/winsw/issues?q=milestone%3Awinsw-1.17 * kohsuke/winsw@2bf9e85 Changes in the module: * https://github.com/jenkinsci/windows-slave-installer-module/commit/a4d2121812fe9fe1b38bbe9d2cb57b9cd5435a0d * https://github.com/jenkinsci/windows-slave-installer-module/commit/3fbc8434aba05d5d36f52f345d9d0176e98459be --- war/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/war/pom.xml b/war/pom.xml index 7387bdef31..9d8f09214c 100644 --- a/war/pom.xml +++ b/war/pom.xml @@ -119,7 +119,7 @@ THE SOFTWARE. org.jenkins-ci.modules windows-slave-installer - 1.5 + 1.5.1 org.jenkins-ci.modules From 4e3e2a6bb0e78965c0f44cc32a8fb4362c9221cd Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 20 Sep 2015 11:59:38 -0700 Subject: [PATCH 0532/2573] [maven-release-plugin] prepare release jenkins-1.630 --- 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 8ba4ce91c6..af3ec8f71a 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.630-SNAPSHOT + 1.630 cli diff --git a/core/pom.xml b/core/pom.xml index 82db02b555..ca1bb253b3 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.630-SNAPSHOT + 1.630 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index 9f7960f5d4..06e47f3549 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.630-SNAPSHOT + 1.630 pom +

                      What's new in 1.630 (2015/09/20)

                      • Make JenkinsRule useable on systems which don't support JNA (issue 29507)
                      -

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

                      • From ecab74af2062711a6b14b157d709b2c1df0e9b55 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Mon, 21 Sep 2015 13:45:21 +0300 Subject: [PATCH 0535/2573] Do not print stacktraces --- test/src/test/java/hudson/model/SlaveTest2.java | 1 - 1 file changed, 1 deletion(-) diff --git a/test/src/test/java/hudson/model/SlaveTest2.java b/test/src/test/java/hudson/model/SlaveTest2.java index 7df721afcc..d60ba017b0 100644 --- a/test/src/test/java/hudson/model/SlaveTest2.java +++ b/test/src/test/java/hudson/model/SlaveTest2.java @@ -71,7 +71,6 @@ public class SlaveTest2 { jnlpJar.getURL(); } catch (MalformedURLException ex) { // we expect the exception here - ex.printStackTrace(); return; } fail("Expected the MalformedURLException for " + url); From 9e439d462c28fe1c96799c89709dc5d0cb8ab8fa Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Fri, 4 Sep 2015 15:22:38 +0300 Subject: [PATCH 0536/2573] [FIXED SECURITY-192] - Require Jenkins.READ permissions to access CLI pages --- core/src/main/resources/hudson/cli/CLIAction/command.jelly | 2 +- core/src/main/resources/hudson/cli/CLIAction/index.jelly | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/resources/hudson/cli/CLIAction/command.jelly b/core/src/main/resources/hudson/cli/CLIAction/command.jelly index dab20f2867..16294b14ad 100644 --- a/core/src/main/resources/hudson/cli/CLIAction/command.jelly +++ b/core/src/main/resources/hudson/cli/CLIAction/command.jelly @@ -24,7 +24,7 @@ THE SOFTWARE. - +

                        diff --git a/core/src/main/resources/hudson/cli/CLIAction/index.jelly b/core/src/main/resources/hudson/cli/CLIAction/index.jelly index 8164710908..94ecddfb23 100644 --- a/core/src/main/resources/hudson/cli/CLIAction/index.jelly +++ b/core/src/main/resources/hudson/cli/CLIAction/index.jelly @@ -24,7 +24,7 @@ THE SOFTWARE. - +

                        From a41fcd560d7104c495f48ae613ea303d7cc91d53 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Mon, 21 Sep 2015 20:28:32 +0300 Subject: [PATCH 0537/2573] Fix the failing test (a new one for CLI access would be useful) --- test/src/test/groovy/hudson/cli/CLIActionTest.groovy | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/src/test/groovy/hudson/cli/CLIActionTest.groovy b/test/src/test/groovy/hudson/cli/CLIActionTest.groovy index 3a304aa4e0..e3c61e14a3 100644 --- a/test/src/test/groovy/hudson/cli/CLIActionTest.groovy +++ b/test/src/test/groovy/hudson/cli/CLIActionTest.groovy @@ -41,6 +41,7 @@ class CLIActionTest { @PresetData(DataSet.NO_ANONYMOUS_READACCESS) public void serveCliActionToAnonymousUser() throws Exception { def wc = j.createWebClient(); - wc.goTo("cli"); + // The behavior changed due to SECURITY-192. index page is no longer accessible to anonymous + wc.assertFails(new URL(j.URL,"cli").toString(), HttpURLConnection.HTTP_FORBIDDEN); } } From 251bdb00ab3cf4435416f0a55fa3bccf7f58896a Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Wed, 23 Sep 2015 12:50:18 +0300 Subject: [PATCH 0538/2573] [SECURITY-192] - Ensure that CLI can connect to CliAction without overall Jenkins.READ --- .../test/java/hudson/cli/CLIActionTest2.java | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 test/src/test/java/hudson/cli/CLIActionTest2.java diff --git a/test/src/test/java/hudson/cli/CLIActionTest2.java b/test/src/test/java/hudson/cli/CLIActionTest2.java new file mode 100644 index 0000000000..debe5b4ce7 --- /dev/null +++ b/test/src/test/java/hudson/cli/CLIActionTest2.java @@ -0,0 +1,67 @@ +/* + * The MIT License + * + * Copyright (c) 2015 Oleg Nenashev. + * + * 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.cli; + +import com.gargoylesoftware.htmlunit.HttpMethod; +import com.gargoylesoftware.htmlunit.Page; +import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebResponse; +import java.net.URL; +import java.util.UUID; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.recipes.PresetData; +import org.jvnet.hudson.test.recipes.PresetData.DataSet; + +import static org.junit.Assert.*; + +/** + * Tests for {@link CLIAction}. + * CLIActionTest is being generated from Groovy, hence here we specify another one. + * @author Oleg Nenashev + */ +public class CLIActionTest2 { + + @Rule + public final JenkinsRule j = new JenkinsRule(); + + @Test + @PresetData(DataSet.NO_ANONYMOUS_READACCESS) + public void serveCliActionToAnonymousUser() throws Exception { + JenkinsRule.WebClient wc = j.createWebClient(); + + // The behavior changed due to SECURITY-192. index page is no longer accessible to anonymous + WebRequestSettings settings = new WebRequestSettings(new URL(j.getURL(), "cli")); + settings.setHttpMethod(HttpMethod.POST); + settings.setAdditionalHeader("Session", UUID.randomUUID().toString()); + settings.setAdditionalHeader("Side", "download"); // We try to download something to init the duplex channel + settings = wc.addCrumb(settings); + + Page page = wc.getPage(settings); + WebResponse webResponse = page.getWebResponse(); + assertEquals("We expect that the proper POST request from CLI gets processed successfully", + 200, webResponse.getStatusCode()); + } +} From 9588a09610999caac45b0e75f375202be5ba7dfe Mon Sep 17 00:00:00 2001 From: "Ing. Pavel Janousek" Date: Wed, 23 Sep 2015 15:40:32 +0200 Subject: [PATCH 0539/2573] [JENKINS-30613] Code clean-up --- core/src/main/resources/hudson/cli/Messages.properties | 3 +-- test/src/test/java/hudson/cli/DeleteJobCommandTest.java | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/core/src/main/resources/hudson/cli/Messages.properties b/core/src/main/resources/hudson/cli/Messages.properties index b942dfc91f..2a6d1ec066 100644 --- a/core/src/main/resources/hudson/cli/Messages.properties +++ b/core/src/main/resources/hudson/cli/Messages.properties @@ -81,6 +81,5 @@ Cannot build {0} because its configuration has not been saved. BuildCommand.CLICause.CannotBuildUnknownReasons=\ Cannot build {0} for unknown reasons. -DeleteNodeCommand.ShortDescription=\ - Deletes node(s) +DeleteNodeCommand.ShortDescription=Deletes node(s) diff --git a/test/src/test/java/hudson/cli/DeleteJobCommandTest.java b/test/src/test/java/hudson/cli/DeleteJobCommandTest.java index e8621a5f8e..1f540c9e28 100644 --- a/test/src/test/java/hudson/cli/DeleteJobCommandTest.java +++ b/test/src/test/java/hudson/cli/DeleteJobCommandTest.java @@ -33,7 +33,9 @@ import org.jvnet.hudson.test.JenkinsRule; import java.io.IOException; -import static hudson.cli.CLICommandInvoker.Matcher.*; +import static hudson.cli.CLICommandInvoker.Matcher.failedWith; +import static hudson.cli.CLICommandInvoker.Matcher.hasNoStandardOutput; +import static hudson.cli.CLICommandInvoker.Matcher.succeededSilently; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.nullValue; From ed0bfe3014d3c96b0d05af2952662ee88947f4ae Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Fri, 25 Sep 2015 10:52:53 +0300 Subject: [PATCH 0540/2573] Restrict everything excepting the predefined list of entries. --- core/src/main/java/hudson/model/Slave.java | 21 +++++++++++++------ .../test/java/hudson/model/SlaveTest2.java | 15 ++++++++++--- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/core/src/main/java/hudson/model/Slave.java b/core/src/main/java/hudson/model/Slave.java index d2c3bb871b..e5f5eebd97 100644 --- a/core/src/main/java/hudson/model/Slave.java +++ b/core/src/main/java/hudson/model/Slave.java @@ -51,8 +51,10 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Set; +import java.util.TreeSet; import javax.servlet.ServletException; @@ -322,13 +324,14 @@ public abstract class Slave extends Node implements Serializable { public URL getURL() throws MalformedURLException { String name = fileName; - if (name.equals("hudson-cli.jar")) name="jenkins-cli.jar"; - // Prevent the sandbox escaping (SECURITY-195) - if (name.equals("..") || name.startsWith("../") || name.startsWith("..\\") || - name.replace('\\','/').contains("/../")) { - throw new MalformedURLException("The specified file path " + fileName + " contains '..'. " - + "The path is not allowed due to security reasons"); + // Prevent the access to war contents & prevent the folder escaping (SECURITY-195) + if (!ALLOWED_JNLPJARS_FILES.contains(name)) { + throw new MalformedURLException("The specified file path " + fileName + " is not allowed due to security reasons"); + } + + if (name.equals("hudson-cli.jar")) { + name="jenkins-cli.jar"; } URL res = Jenkins.getInstance().servletContext.getResource("/WEB-INF/" + name); @@ -505,4 +508,10 @@ public abstract class Slave extends Node implements Serializable { * Determines the workspace root file name for those who really really need the shortest possible path name. */ private static final String WORKSPACE_ROOT = System.getProperty(Slave.class.getName()+".workspaceRoot","workspace"); + + /** + * Provides a collection of file names, which are accessible via /jnlpJars link. + */ + private static final Set ALLOWED_JNLPJARS_FILES = new TreeSet + (Arrays.asList("slave.jar", "remoting.jar", "jenkins-cli.jar", "hudson-cli.jar")); } diff --git a/test/src/test/java/hudson/model/SlaveTest2.java b/test/src/test/java/hudson/model/SlaveTest2.java index d60ba017b0..bc57f7ec99 100644 --- a/test/src/test/java/hudson/model/SlaveTest2.java +++ b/test/src/test/java/hudson/model/SlaveTest2.java @@ -52,9 +52,19 @@ public class SlaveTest2 { // Spot-check correct requests assertJnlpJarUrlIsAllowed(slave, "slave.jar"); + assertJnlpJarUrlIsAllowed(slave, "remoting.jar"); assertJnlpJarUrlIsAllowed(slave, "jenkins-cli.jar"); + assertJnlpJarUrlIsAllowed(slave, "hudson-cli.jar"); - // Go to the upper level + // Check that requests to other WEB-INF contents fail + assertJnlpJarUrlFails(slave, "web.xml"); + assertJnlpJarUrlFails(slave, "web.xml"); + assertJnlpJarUrlFails(slave, "classes/bundled-plugins.txt"); + assertJnlpJarUrlFails(slave, "classes/dependencies.txt"); + assertJnlpJarUrlFails(slave, "plugins/ant.hpi"); + assertJnlpJarUrlFails(slave, "nonexistentfolder/something.txt"); + + // Try various kinds of folder escaping (SECURITY-195) assertJnlpJarUrlFails(slave, "../"); assertJnlpJarUrlFails(slave, ".."); assertJnlpJarUrlFails(slave, "..\\"); @@ -89,7 +99,6 @@ public class SlaveTest2 { // Access from a Web client JenkinsRule.WebClient client = rule.createWebClient(); client.getPage(client.getContextPath() + "jnlpJars/" + URLEncoder.encode(url, "UTF-8")).getWebResponse().getContentAsString(); - client.getPage(jnlpJar.getURL()).getWebResponse().getContentAsString(); - + client.getPage(jnlpJar.getURL()).getWebResponse().getContentAsString(); } } From e78e9e8144f7304cf274cd4b756f458cf63a3556 Mon Sep 17 00:00:00 2001 From: Valentina Armenise Date: Mon, 7 Sep 2015 14:49:40 +0200 Subject: [PATCH 0541/2573] [SECURITY-173] use XMlUtils safe transformation to create a job from xml --- .../java/hudson/model/ItemGroupMixIn.java | 25 +++++++++++++-- .../java/hudson/model/ItemGroupMixInTest.java | 31 +++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/hudson/model/ItemGroupMixIn.java b/core/src/main/java/hudson/model/ItemGroupMixIn.java index d34b5e7f93..3660ba0e91 100644 --- a/core/src/main/java/hudson/model/ItemGroupMixIn.java +++ b/core/src/main/java/hudson/model/ItemGroupMixIn.java @@ -27,15 +27,20 @@ import hudson.Util; import hudson.XmlFile; import hudson.model.listeners.ItemListener; import hudson.security.AccessControlled; +import hudson.util.AtomicFileWriter; import hudson.util.CopyOnWriteMap; import hudson.util.Function1; -import hudson.util.IOUtils; import jenkins.model.Jenkins; +import jenkins.util.xml.XMLUtils; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerException; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; import java.io.File; import java.io.FileFilter; import java.io.IOException; @@ -44,6 +49,7 @@ import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import jenkins.security.NotReallyRoleSensitiveCallable; +import org.xml.sax.SAXException; /** * Defines a bunch of static methods to be used as a "mix-in" for {@link ItemGroup} @@ -249,8 +255,12 @@ public abstract class ItemGroupMixIn { File configXml = Items.getConfigFile(getRootDirFor(name)).getFile(); final File dir = configXml.getParentFile(); dir.mkdirs(); + final AtomicFileWriter out = new AtomicFileWriter(configXml); + try { - IOUtils.copy(xml,configXml); + XMLUtils.safeTransform((Source)new StreamSource(xml), new StreamResult(out)); + out.close(); + out.commit(); // load it TopLevelItem result = Items.whileUpdatingByXml(new NotReallyRoleSensitiveCallable() { @@ -264,10 +274,21 @@ public abstract class ItemGroupMixIn { Jenkins.getInstance().rebuildDependencyGraphAsync(); return result; + } catch (TransformerException e) { + // if anything fails, delete the config file to avoid further confusion + Util.deleteRecursive(dir); + throw new IOException("Failed to persist config.xml", e); + } catch (SAXException e) { + // if anything fails, delete the config file to avoid further confusion + Util.deleteRecursive(dir); + throw new IOException("Failed to persist config.xml", e); } catch (IOException e) { // if anything fails, delete the config file to avoid further confusion Util.deleteRecursive(dir); throw e; + } finally { + // don't leave anything behind + out.abort(); } } diff --git a/test/src/test/java/hudson/model/ItemGroupMixInTest.java b/test/src/test/java/hudson/model/ItemGroupMixInTest.java index ddf14573db..b782645a2b 100644 --- a/test/src/test/java/hudson/model/ItemGroupMixInTest.java +++ b/test/src/test/java/hudson/model/ItemGroupMixInTest.java @@ -24,8 +24,13 @@ package hudson.model; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + import java.util.Collection; import static org.junit.Assert.*; + import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Bug; @@ -33,6 +38,9 @@ import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.MockFolder; import org.jvnet.hudson.test.recipes.LocalData; +import static org.hamcrest.core.StringContains.containsString; + + public class ItemGroupMixInTest { @Rule public JenkinsRule r = new JenkinsRule(); @@ -47,4 +55,27 @@ public class ItemGroupMixInTest { assertEquals("valid", items.iterator().next().getName()); } + @Test public void createProjectFromXMLShouldNoCreateEntities() throws IOException { + + final String xml = "\n" + + "\n" + + "]>\n" + + "\n" + + " \n" + + " &foo;\n" + + " false\n" + + " \n" + + " \n" + + " true\n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + + Item foo = r.jenkins.createProjectFromXML("foo", new ByteArrayInputStream(xml.getBytes())); + // if no exception then JAXP is swallowing these - so there should be no entity in the description. + assertThat(Items.getConfigFile(foo).asString(), containsString("")); + } } From cbf437d8e3925f227da2faa78d44cebeabd1d233 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 27 Sep 2015 18:04:30 -0700 Subject: [PATCH 0542/2573] [maven-release-plugin] prepare for next development iteration --- 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 7f6d9af25e..93fd4915f9 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.631 + 1.632-SNAPSHOT cli diff --git a/core/pom.xml b/core/pom.xml index 0792be8ebf..f7ce894edc 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.631 + 1.632-SNAPSHOT jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index c8061e20ac..571b73f006 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.631 + 1.632-SNAPSHOT pom +

                        What's new in 1.631 (2015/09/27)

                        +
                          +
                        • +

                        What's new in 1.630 (2015/09/20)

                        • From 7e072b6abc0b510f2d0adcaa2bd8ce82b21e2d54 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Mon, 28 Sep 2015 11:40:19 +0200 Subject: [PATCH 0545/2573] Noting #1758 --- changelog.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.html b/changelog.html index 20e73945c9..077f180001 100644 --- a/changelog.html +++ b/changelog.html @@ -60,7 +60,9 @@ Upcoming changes

                          What's new in 1.631 (2015/09/27)

                            -
                          • +
                          • + Add proper labels for plugin categories assigned to some plugins. + (PR 1758)

                          What's new in 1.630 (2015/09/20)

                            From 6ea4534001a684fc1e1821fde020eb35e8e4f16d Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Mon, 28 Sep 2015 23:04:42 +0300 Subject: [PATCH 0546/2573] Update the unit test --- test/src/test/groovy/hudson/cli/CLIActionTest.groovy | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/src/test/groovy/hudson/cli/CLIActionTest.groovy b/test/src/test/groovy/hudson/cli/CLIActionTest.groovy index e3c61e14a3..e22d79aec2 100644 --- a/test/src/test/groovy/hudson/cli/CLIActionTest.groovy +++ b/test/src/test/groovy/hudson/cli/CLIActionTest.groovy @@ -39,9 +39,15 @@ class CLIActionTest { @Test @PresetData(DataSet.NO_ANONYMOUS_READACCESS) - public void serveCliActionToAnonymousUser() throws Exception { + public void serveCliActionToAnonymousUserWithoutPermissions() throws Exception { def wc = j.createWebClient(); // The behavior changed due to SECURITY-192. index page is no longer accessible to anonymous - wc.assertFails(new URL(j.URL,"cli").toString(), HttpURLConnection.HTTP_FORBIDDEN); + wc.assertFails("cli", HttpURLConnection.HTTP_FORBIDDEN); + } + + @Test + public void serveCliActionToAnonymousUser() throws Exception { + def wc = j.createWebClient(); + wc.goTo("cli"); } } From 672f8deb6859bb32e428e33ae83aafa04a196f38 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Tue, 29 Sep 2015 12:15:11 +0300 Subject: [PATCH 0547/2573] Remove the dead code --- test/src/test/java/hudson/model/SlaveTest2.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/src/test/java/hudson/model/SlaveTest2.java b/test/src/test/java/hudson/model/SlaveTest2.java index bc57f7ec99..a88824ff55 100644 --- a/test/src/test/java/hudson/model/SlaveTest2.java +++ b/test/src/test/java/hudson/model/SlaveTest2.java @@ -84,10 +84,6 @@ public class SlaveTest2 { return; } fail("Expected the MalformedURLException for " + url); - - // Access from a Web client - JenkinsRule.WebClient client = rule.createWebClient(); - client.assertFails("jnlpJars/" + URLEncoder.encode(url, "UTF-8"), 500); } private void assertJnlpJarUrlIsAllowed(@Nonnull Slave slave, @Nonnull String url) throws Exception { From 3fa9ce5845727edec8181d7f1523340a9fa25764 Mon Sep 17 00:00:00 2001 From: "Ing. Pavel Janousek" Date: Thu, 24 Sep 2015 15:44:35 +0200 Subject: [PATCH 0548/2573] [JENKINS-30629] Fixed NPE in AbstractItem.resolveForCLI() --- core/src/main/java/hudson/model/AbstractItem.java | 7 +++++-- core/src/main/resources/hudson/model/Messages.properties | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/hudson/model/AbstractItem.java b/core/src/main/java/hudson/model/AbstractItem.java index 1e1f9f4666..0c8acf2efa 100644 --- a/core/src/main/java/hudson/model/AbstractItem.java +++ b/core/src/main/java/hudson/model/AbstractItem.java @@ -723,8 +723,11 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet @Argument(required=true,metaVar="NAME",usage="Job name") String name) throws CmdLineException { // TODO can this (and its pseudo-override in AbstractProject) share code with GenericItemOptionHandler, used for explicit CLICommand’s rather than CLIMethod’s? AbstractItem item = Jenkins.getInstance().getItemByFullName(name, AbstractItem.class); - if (item==null) - throw new CmdLineException(null,Messages.AbstractItem_NoSuchJobExists(name,AbstractProject.findNearest(name).getFullName())); + if (item==null) { + AbstractProject project = AbstractProject.findNearest(name); + throw new CmdLineException(null, project == null ? Messages.AbstractItem_NoSuchJobExistsWithoutSuggestion(name) + : Messages.AbstractItem_NoSuchJobExists(name, project.getFullName())); + } return item; } diff --git a/core/src/main/resources/hudson/model/Messages.properties b/core/src/main/resources/hudson/model/Messages.properties index 8e6420c92b..7737be9eab 100644 --- a/core/src/main/resources/hudson/model/Messages.properties +++ b/core/src/main/resources/hudson/model/Messages.properties @@ -29,6 +29,7 @@ AbstractBuild.BuildingInWorkspace=\ in workspace {0} AbstractBuild.KeptBecause=This build is kept because of {0}. AbstractItem.NoSuchJobExists=No such job \u2018{0}\u2019 exists. Perhaps you meant \u2018{1}\u2019? +AbstractItem.NoSuchJobExistsWithoutSuggestion=No such job \u2018{0}\u2019 exists. AbstractItem.Pronoun=Item AbstractProject.AssignedLabelString_NoMatch_DidYouMean=There\u2019s no slave/cloud that matches this assignment. Did you mean \u2018{1}\u2019 instead of \u2018{0}\u2019? AbstractProject.NewBuildForWorkspace=Scheduling a new build to get a workspace. From 28eea5b0834c4e80b6a4894d2ce407be75b15161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Tue, 29 Sep 2015 15:49:24 +0200 Subject: [PATCH 0549/2573] Revert "Dont start onLoad and after submit for disabled" This reverts commit 3c471f1fd26fd893726e3f7216de38a2fd3f7c5d. --- .../java/hudson/model/AbstractProject.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java index 70e115b190..df7b1a47af 100644 --- a/core/src/main/java/hudson/model/AbstractProject.java +++ b/core/src/main/java/hudson/model/AbstractProject.java @@ -325,13 +325,11 @@ public abstract class AbstractProject

                            ,R extends A buildMixIn.onLoad(parent, name); builds = buildMixIn.getRunMap(); triggers().setOwner(this); - 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); - } + 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) @@ -1874,10 +1872,8 @@ public abstract class AbstractProject

                            ,R extends A for (Trigger t : triggers()) t.stop(); triggers.replaceBy(buildDescribable(req, Trigger.for_(this))); - if (isBuildable()) { - for (Trigger t : triggers()) - t.start(this, true); - } + for (Trigger t : triggers()) + t.start(this,true); } /** From c110cccace509c4814d45ccc61a4c3998027333c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Tue, 29 Sep 2015 15:49:52 +0200 Subject: [PATCH 0550/2573] Revert "Don't run disabled/copied projects" This reverts commit df4bb2de2d22bfa8a0e1beed14615a40786e3942. --- core/src/main/java/hudson/triggers/Trigger.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/core/src/main/java/hudson/triggers/Trigger.java b/core/src/main/java/hudson/triggers/Trigger.java index a6b6443a0a..afad8235c3 100644 --- a/core/src/main/java/hudson/triggers/Trigger.java +++ b/core/src/main/java/hudson/triggers/Trigger.java @@ -243,10 +243,6 @@ 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()); @@ -262,12 +258,6 @@ 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 c6c8836fd2711a46b31fbce08f37271f3f5f3a2f Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Thu, 10 Sep 2015 18:10:57 -0400 Subject: [PATCH 0551/2573] [FIXED JENKINS-30395] Occasional ClosedByInterruptException. (cherry picked from commit aaa71d4feb1f4ce1c477ac03c9fc6df543cca84b) --- test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java | 7 ++++++- 1 file changed, 6 insertions(+), 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 7309c8acb5..afdaf2c8a8 100644 --- a/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -190,6 +190,7 @@ import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; +import java.nio.channels.ClosedByInterruptException; import org.jvnet.hudson.test.recipes.Recipe; import org.jvnet.hudson.test.rhino.JavaScriptDebugger; import org.kohsuke.stapler.ClassDescriptor; @@ -1668,7 +1669,11 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { File dst = new File(home, "plugins/" + artifactId + ".jpi"); if(!dst.exists() || dst.lastModified()!=dependencyJar.lastModified()) { - FileUtils.copyFile(dependencyJar, dst); + try { + FileUtils.copyFile(dependencyJar, dst); + } catch (ClosedByInterruptException x) { + throw new AssumptionViolatedException("copying dependencies was interrupted", x); + } } } } From 1b852010568dc3b21c0c296e2f0a2d6ff0b8bed3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Tue, 29 Sep 2015 21:20:03 +0200 Subject: [PATCH 0552/2573] [FIXED JENKINS-30705] Optimize TagCloud calculation --- core/src/main/java/hudson/model/Label.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/Label.java b/core/src/main/java/hudson/model/Label.java index f0a2df2474..30c3905c53 100644 --- a/core/src/main/java/hudson/model/Label.java +++ b/core/src/main/java/hudson/model/Label.java @@ -85,6 +85,7 @@ public abstract class Label extends Actionable implements Comparable

                            Updated
                            +ApiTokenProperty.ChangeToken.TokenIsHidden=Token is hidden +ApiTokenProperty.ChangeToken.Success=
                            Updated. See the new token in the field above
                            +ApiTokenProperty.ChangeToken.SuccessHidden=
                            Updated. You need to login as the user to see the token
                            RekeySecretAdminMonitor.DisplayName=Re-keying \ No newline at end of file diff --git a/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java b/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java index cf4e85dcfe..06b88c09ee 100644 --- a/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java +++ b/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java @@ -5,6 +5,7 @@ import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; import hudson.Util; import hudson.model.User; +import hudson.security.ACL; import jenkins.model.Jenkins; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.HttpClient; @@ -16,6 +17,8 @@ import org.apache.commons.httpclient.auth.CredentialsProvider; import org.jvnet.hudson.test.HudsonTestCase; import java.util.concurrent.Callable; +import javax.annotation.Nonnull; +import org.jvnet.hudson.test.Issue; /** * @author Kohsuke Kawaguchi @@ -27,40 +30,33 @@ public class ApiTokenPropertyTest extends HudsonTestCase { public void testBasics() throws Exception { jenkins.setSecurityRealm(createDummySecurityRealm()); User u = User.get("foo"); - ApiTokenProperty t = u.getProperty(ApiTokenProperty.class); + final ApiTokenProperty t = u.getProperty(ApiTokenProperty.class); final String token = t.getApiToken(); - // make sure the UI shows the token - HtmlPage config = createWebClient().goTo(u.getUrl() + "/configure"); + // Make sure that user is able to get the token via the interface + ACL.impersonate(u.impersonate(), new Runnable() { + @Override + public void run() { + assertEquals("User is unable to get its own token", token, t.getApiToken()); + } + }); + + // test the authentication via Token + WebClient wc = createClientForUser("foo"); + assertEquals(u,wc.executeOnServer(new Callable() { + public User call() throws Exception { + return User.current(); + } + })); + + // Make sure the UI shows the token to the user + HtmlPage config = wc.goTo(u.getUrl() + "/configure"); HtmlForm form = config.getFormByName("config"); assertEquals(token, form.getInputByName("_.apiToken").getValueAttribute()); // round-trip shouldn't change the API token submit(form); assertSame(t, u.getProperty(ApiTokenProperty.class)); - - WebClient wc = 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", localPort, AuthScope.ANY_REALM), new UsernamePasswordCredentials("foo", token)); - return c; - } - }); - - // test the authentication - assertEquals(u,wc.executeOnServer(new Callable() { - public User call() throws Exception { - return User.current(); - } - })); } public void testSecurity49Upgrade() throws Exception { @@ -85,4 +81,61 @@ public class ApiTokenPropertyTest extends HudsonTestCase { assertTrue(t.getApiToken().equals(Util.getDigestOf(historicalInitialValue+"somethingElse"))); } + + @Issue("SECURITY-200") + public void testAdminsShouldBeUnableToSeeTokensByDefault() throws Exception { + jenkins.setSecurityRealm(createDummySecurityRealm()); + User u = User.get("foo"); + final ApiTokenProperty t = u.getProperty(ApiTokenProperty.class); + final String token = t.getApiToken(); + + // Make sure the UI does not show the token to another user + WebClient wc = createClientForUser("bar"); + HtmlPage config = wc.goTo(u.getUrl() + "/configure"); + HtmlForm form = config.getFormByName("config"); + assertEquals(Messages.ApiTokenProperty_ChangeToken_TokenIsHidden(), form.getInputByName("_.apiToken").getValueAttribute()); + } + + @Issue("SECURITY-200") + public void testAdminsShouldBeUnableToChangeTokensByDefault() throws Exception { + jenkins.setSecurityRealm(createDummySecurityRealm()); + User foo = User.get("foo"); + User bar = User.get("bar"); + final ApiTokenProperty t = foo.getProperty(ApiTokenProperty.class); + final ApiTokenProperty.DescriptorImpl descriptor = (ApiTokenProperty.DescriptorImpl) t.getDescriptor(); + + // Make sure that Admin can reset a token of another user + WebClient wc = createClientForUser("bar"); + HtmlPage res = wc.goTo(foo.getUrl() + "/" + descriptor.getDescriptorUrl()+ "/changeToken"); + assertEquals("Update token response is incorrect", + Messages.ApiTokenProperty_ChangeToken_SuccessHidden(), "
                            " + res.getBody().asText() + "
                            "); + } + + @Nonnull + private WebClient createClientForUser(final String username) { + User u = User.get(username); + final ApiTokenProperty t = u.getProperty(ApiTokenProperty.class); + // Yes, we use the insecure call in the test stuff + final String token = t.getApiTokenInsecure(); + + WebClient wc = createWebClient(); + wc.setCredentialsProvider(new CredentialsProvider() { + @Override + public Credentials getCredentials(AuthScheme scheme, String host, int port, boolean proxy) + throws CredentialsNotAvailableException { + return new UsernamePasswordCredentials(username, token); + } + }); + wc.setWebConnection(new HttpWebConnection(wc) { + @Override + protected HttpClient getHttpClient() { + HttpClient c = super.getHttpClient(); + c.getParams().setAuthenticationPreemptive(true); + c.getState().setCredentials(new AuthScope("localhost", localPort, AuthScope.ANY_REALM), + new UsernamePasswordCredentials(username, token)); + return c; + } + }); + return wc; + } } From 1d437f475ed8df0075cf0e9601a4cfcfa66524ac Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Tue, 29 Sep 2015 18:26:22 -0400 Subject: [PATCH 0556/2573] Judging by #1774, WebRequest is the replacement for WebRequestSettings. --- test/src/test/java/hudson/cli/CLIActionTest2.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/test/java/hudson/cli/CLIActionTest2.java b/test/src/test/java/hudson/cli/CLIActionTest2.java index 14ac8dfe92..cfe7cf0555 100644 --- a/test/src/test/java/hudson/cli/CLIActionTest2.java +++ b/test/src/test/java/hudson/cli/CLIActionTest2.java @@ -25,7 +25,7 @@ package hudson.cli; 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 java.net.URL; import java.util.UUID; @@ -56,7 +56,7 @@ public class CLIActionTest2 { // The behavior changed due to SECURITY-192. index page is no longer accessible to anonymous, // so we check the access by emulating the CLI connection post request - WebRequestSettings settings = new WebRequestSettings(new URL(j.getURL(), "cli")); + WebRequest settings = new WebRequest(new URL(j.getURL(), "cli")); settings.setHttpMethod(HttpMethod.POST); settings.setAdditionalHeader("Session", UUID.randomUUID().toString()); settings.setAdditionalHeader("Side", "download"); // We try to download something to init the duplex channel From e1cdc2a6f0517217cfa8a0c0afc25592cea1e655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Wed, 30 Sep 2015 13:19:16 +0200 Subject: [PATCH 0557/2573] [JENKINS-30705] Update the Label#getTiedJobCount javadoc --- core/src/main/java/hudson/model/Label.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/Label.java b/core/src/main/java/hudson/model/Label.java index 30c3905c53..ff32c1f940 100644 --- a/core/src/main/java/hudson/model/Label.java +++ b/core/src/main/java/hudson/model/Label.java @@ -370,7 +370,9 @@ public abstract class Label extends Actionable implements Comparable

                          What's new in 1.632 (2015/10/05)

                          From 4bfc8cda65e1641a6375a0dc9a7d9cc5ee3dc61c Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 11 Oct 2015 20:07:42 -0700 Subject: [PATCH 0639/2573] [maven-release-plugin] prepare release jenkins-1.633 --- 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 f4d76304d5..eb33d03c1d 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.633-SNAPSHOT + 1.633 cli diff --git a/core/pom.xml b/core/pom.xml index 739eb80c82..a9687e242d 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.633-SNAPSHOT + 1.633 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index 8805b4bc27..83bdb4f0e9 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.633-SNAPSHOT + 1.633 pom +

                          What's new in 1.633 (2015/10/11)

                          • Added safari pinned tab icon. @@ -84,7 +89,6 @@ Upcoming changes Build history pagination and search. (issue 26445)
                          -

                          What's new in 1.632 (2015/10/05)

                          • From 7d6b0c5fdac1ad14b2eda81b7528e07aa7f99de9 Mon Sep 17 00:00:00 2001 From: Fernando Boaglio Date: Mon, 12 Oct 2015 00:43:03 -0300 Subject: [PATCH 0642/2573] pt_BR translation --- .../hudson/security/Messages_pt_BR.properties | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/main/resources/hudson/security/Messages_pt_BR.properties b/core/src/main/resources/hudson/security/Messages_pt_BR.properties index ff13158025..25d7726132 100644 --- a/core/src/main/resources/hudson/security/Messages_pt_BR.properties +++ b/core/src/main/resources/hudson/security/Messages_pt_BR.properties @@ -22,7 +22,7 @@ GlobalSecurityConfiguration.DisplayName=Configurar seguran\u00e7a global GlobalSecurityConfiguration.Description=Fa\u00e7a a seguran\u00e7a no Jenkins; defina quem pode usar/acessar o sistema. -HudsonPrivateSecurityRealm.WouldYouLikeToSignUp=This {0} {1} is new to Jenkins. Would you like to sign up? +HudsonPrivateSecurityRealm.WouldYouLikeToSignUp=O {0} {1} \u00e9 novo no Jenkins. Voc\u00ea deseja se cadastrar ? LegacyAuthorizationStrategy.DisplayName=Modo legado HudsonPrivateSecurityRealm.Details.DisplayName=Senha @@ -35,17 +35,17 @@ Permission.Permissions.Title=N/A # Success PAMSecurityRealm.Success=Sucesso # Unable to connect to {0} : {1} -LDAPSecurityRealm.UnableToConnect=Não foi possível conectar {0} : {1} +LDAPSecurityRealm.UnableToConnect=N\u00e3o foi poss\u00edvel conectar {0} : {1} # Logged-in users can do anything -FullControlOnceLoggedInAuthorizationStrategy.DisplayName=Usu\u00e1rios logados n\u00e3o conseguem fazer nada +FullControlOnceLoggedInAuthorizationStrategy.DisplayName=Usu\u00e1rios logados conseguem fazer qualquer coisa # Unix user/group database -PAMSecurityRealm.DisplayName=Usu\u00e1rio Unix / grupo banco da dados +PAMSecurityRealm.DisplayName=Usu\u00e1rio ou grupo do UNIX # User ''{0}'' PAMSecurityRealm.User=Usu\u00e1rio ''{0}'' # {0} needs to belong to group {1} to read /etc/shadow PAMSecurityRealm.BelongToGroup= {0} precisa pertencer ao grupo {1} para ler /etc/shadow # Anyone can do anything -AuthorizationStrategy.DisplayName=Ningu\u00e9m consegue fazer nada +AuthorizationStrategy.DisplayName=Qualquer um pode fazer qualquer coisa # Invalid port number LDAPSecurityRealm.InvalidPortNumber=N\u00famero de porta inv\u00e1lido # Unknown host: {0} @@ -62,7 +62,7 @@ AccessDeniedException2.MissingPermission= {0} est\u00e1 faltando a permiss\u00e3 # Manage Users HudsonPrivateSecurityRealm.ManageUserLinks.DisplayName=Gerenciar usu\u00e1rios # Delegate to servlet container -LegacySecurityRealm.Displayname=Delegar para o container servlet +LegacySecurityRealm.Displayname=Delegar para o servlet container # LDAP LDAPSecurityRealm.DisplayName=LDAP # Jenkins''s own user database From dd4256af209ba0218a410ffb5870ddea8391d770 Mon Sep 17 00:00:00 2001 From: christ66 Date: Mon, 12 Oct 2015 01:09:52 -0700 Subject: [PATCH 0643/2573] Add more logging to Queue.maintain in order to understand why potential builds could be blocked queue and never executed. --- core/src/main/java/hudson/model/Queue.java | 31 +++++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index c265e477df..cba47d30a2 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -1385,9 +1385,13 @@ public class Queue extends ResourceController implements Saveable { // we need to clear lost pendings as we cannot know what work unit was on this executor // while it is interrupted. (All this dancing is a result of Executor extending Thread) lostPendings.clear(); // we'll get them next time around when the flag is cleared. + LOGGER.log(Level.FINEST, + "Interrupt thread for executor {0} is set and we do not know what work unit was on the executor.", + e.getDisplayName()); continue; } if (e.isParking()) { + LOGGER.log(Level.FINEST, "{0} is parking and is waiting for a job to execute.", e.getDisplayName()); parked.put(e, new JobOffer(e)); } final WorkUnit workUnit = e.getCurrentWorkUnit(); @@ -1419,7 +1423,12 @@ public class Queue extends ResourceController implements Saveable { Collections.sort(blockedItems, QueueSorter.DEFAULT_BLOCKED_ITEM_COMPARATOR); } for (BlockedItem p : blockedItems) { + LOGGER.log(Level.FINER, "Current blocked item: {0}", p.task.getFullDisplayName()); if (!isBuildBlocked(p) && allowNewBuildableTask(p.task)) { + LOGGER.log(Level.INFO, + "BlockedItem {0}: blocked -> buildable as the build is not blocked and new tasks are allowed", + p.task.getFullDisplayName()); + // ready to be executed Runnable r = makeBuildable(new BuildableItem(p)); if (r != null) { @@ -1438,8 +1447,10 @@ public class Queue extends ResourceController implements Saveable { while (!waitingList.isEmpty()) { WaitingItem top = peek(); - if (top.timestamp.compareTo(new GregorianCalendar()) > 0) + if (top.timestamp.compareTo(new GregorianCalendar()) > 0) { + LOGGER.log(Level.FINE, "Finished moving all ready items from queue."); break; // finished moving all ready items from queue + } top.leave(this); Task p = top.task; @@ -1447,8 +1458,10 @@ public class Queue extends ResourceController implements Saveable { // ready to be executed immediately Runnable r = makeBuildable(new BuildableItem(top)); if (r != null) { + LOGGER.log(Level.FINE, "Executing runnable {0}", top.task.getFullDisplayName()); r.run(); } else { + LOGGER.log(Level.FINEST, "Item {0} was unable to be made a buildable and is now a blocked item.", top.task.getFullDisplayName()); new BlockedItem(top).enter(this); } } else { @@ -1482,15 +1495,19 @@ public class Queue extends ResourceController implements Saveable { Runnable r = makeFlyWeightTaskBuildable(new BuildableItem(p)); if (r != null) { p.leave(this); + LOGGER.log(Level.FINEST, "Executing flyweight task {0}", p.task.getFullDisplayName()); r.run(); updateSnapshot(); } } else { List candidates = new ArrayList(parked.size()); - for (JobOffer j : parked.values()) - if (j.canTake(p)) + for (JobOffer j : parked.values()) { + if (j.canTake(p)) { + LOGGER.log(Level.FINEST, "Potential candidate for "); candidates.add(j); + } + } MappingWorksheet ws = new MappingWorksheet(p, candidates); Mapping m = loadBalancer.map(p.task, ws); @@ -1505,10 +1522,12 @@ public class Queue extends ResourceController implements Saveable { // found a matching executor. use it. WorkUnitContext wuc = new WorkUnitContext(p); + LOGGER.log(Level.FINER, "Found a matching executor for {0}. Using it.", p.task.getFullDisplayName()); m.execute(wuc); p.leave(this); if (!wuc.getWorkUnits().isEmpty()) { + LOGGER.log(Level.FINE, "BuildableItem {0} marked as pending.", p.task.getFullDisplayName()); makePending(p); } else @@ -1542,7 +1561,7 @@ public class Queue extends ResourceController implements Saveable { if (!isBlockedByShutdown(p.task)) { Runnable runnable = makeFlyWeightTaskBuildable(p); - + LOGGER.log(Level.FINE, "Converting flyweight task: {0} into a BuildableRunnable", p.task.getFullDisplayName()); if(runnable != null){ return runnable; } @@ -1551,9 +1570,11 @@ public class Queue extends ResourceController implements Saveable { //if the execution gets here, it means the task could not be scheduled since the node //the task is supposed to run on is offline or not available. //Thus, the flyweighttask enters the buildables queue and will ask Jenkins to provision a node + LOGGER.log(Level.FINEST, "Flyweight task {0} is entering as buildable to provision a node.", p.task.getFullDisplayName()); return new BuildableRunnable(p); } // if the execution gets here, it means the task is blocked by shutdown and null is returned. + LOGGER.log(Level.FINE, "Task {0} is blocked by shutdown.", p.task.getFullDisplayName()); return null; } else { // regular heavyweight task @@ -1595,6 +1616,8 @@ public class Queue extends ResourceController implements Saveable { if (n.canTake(p) != null) { continue; } + + LOGGER.log(Level.FINE, "Creating flyweight task {0} for machine {1}", new Object[]{p.task, c.getName()}); return new Runnable() { @Override public void run() { c.startFlyWeightTask(new WorkUnitContext(p).createWorkUnit(p.task)); From 8d897edfdf6e20c726af5a1501770c4f656abd22 Mon Sep 17 00:00:00 2001 From: christ66 Date: Mon, 12 Oct 2015 01:21:22 -0700 Subject: [PATCH 0644/2573] Fixed incomplete log message where there is a potential candidate for a task. --- core/src/main/java/hudson/model/Queue.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index cba47d30a2..e751b536fe 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -1504,7 +1504,9 @@ public class Queue extends ResourceController implements Saveable { List candidates = new ArrayList(parked.size()); for (JobOffer j : parked.values()) { if (j.canTake(p)) { - LOGGER.log(Level.FINEST, "Potential candidate for "); + LOGGER.log(Level.FINEST, + "{0} is a potential candidate for task {1}", + new Object[]{j.executor.getDisplayName(), p.task.getFullDisplayName()}); candidates.add(j); } } From 5164133c9bebbb550ddca36585293a3dfd5a5bd0 Mon Sep 17 00:00:00 2001 From: christ66 Date: Mon, 12 Oct 2015 01:24:16 -0700 Subject: [PATCH 0645/2573] Change from printing the task object to the full display name. --- core/src/main/java/hudson/model/Queue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index e751b536fe..e365b4923f 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -1619,7 +1619,7 @@ public class Queue extends ResourceController implements Saveable { continue; } - LOGGER.log(Level.FINE, "Creating flyweight task {0} for machine {1}", new Object[]{p.task, c.getName()}); + LOGGER.log(Level.FINE, "Creating flyweight task {0} for computer {1}", new Object[]{p.task.getFullDisplayName(), c.getName()}); return new Runnable() { @Override public void run() { c.startFlyWeightTask(new WorkUnitContext(p).createWorkUnit(p.task)); From 8ef443d57f0229d7a91b24d4d2d451104897d2e9 Mon Sep 17 00:00:00 2001 From: christ66 Date: Mon, 12 Oct 2015 01:33:18 -0700 Subject: [PATCH 0646/2573] Reduce the amount of times Task.getFullDisplayName is invoked. --- core/src/main/java/hudson/model/Queue.java | 27 +++++++++++++--------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index e365b4923f..af11e8cd80 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -1423,11 +1423,12 @@ public class Queue extends ResourceController implements Saveable { Collections.sort(blockedItems, QueueSorter.DEFAULT_BLOCKED_ITEM_COMPARATOR); } for (BlockedItem p : blockedItems) { - LOGGER.log(Level.FINER, "Current blocked item: {0}", p.task.getFullDisplayName()); + String taskDisplayName = p.task.getFullDisplayName(); + LOGGER.log(Level.FINER, "Current blocked item: {0}", taskDisplayName); if (!isBuildBlocked(p) && allowNewBuildableTask(p.task)) { LOGGER.log(Level.INFO, "BlockedItem {0}: blocked -> buildable as the build is not blocked and new tasks are allowed", - p.task.getFullDisplayName()); + taskDisplayName); // ready to be executed Runnable r = makeBuildable(new BuildableItem(p)); @@ -1457,11 +1458,12 @@ public class Queue extends ResourceController implements Saveable { if (!isBuildBlocked(top) && allowNewBuildableTask(p)) { // ready to be executed immediately Runnable r = makeBuildable(new BuildableItem(top)); + String topTaskDisplayName = top.task.getFullDisplayName(); if (r != null) { - LOGGER.log(Level.FINE, "Executing runnable {0}", top.task.getFullDisplayName()); + LOGGER.log(Level.FINE, "Executing runnable {0}", topTaskDisplayName); r.run(); } else { - LOGGER.log(Level.FINEST, "Item {0} was unable to be made a buildable and is now a blocked item.", top.task.getFullDisplayName()); + LOGGER.log(Level.FINEST, "Item {0} was unable to be made a buildable and is now a blocked item.", topTaskDisplayName); new BlockedItem(top).enter(this); } } else { @@ -1491,11 +1493,13 @@ public class Queue extends ResourceController implements Saveable { continue; } + String taskDisplayName = p.task.getFullDisplayName(); + if (p.task instanceof FlyweightTask) { Runnable r = makeFlyWeightTaskBuildable(new BuildableItem(p)); if (r != null) { p.leave(this); - LOGGER.log(Level.FINEST, "Executing flyweight task {0}", p.task.getFullDisplayName()); + LOGGER.log(Level.FINEST, "Executing flyweight task {0}", taskDisplayName); r.run(); updateSnapshot(); } @@ -1506,7 +1510,7 @@ public class Queue extends ResourceController implements Saveable { if (j.canTake(p)) { LOGGER.log(Level.FINEST, "{0} is a potential candidate for task {1}", - new Object[]{j.executor.getDisplayName(), p.task.getFullDisplayName()}); + new Object[]{j.executor.getDisplayName(), taskDisplayName}); candidates.add(j); } } @@ -1524,12 +1528,12 @@ public class Queue extends ResourceController implements Saveable { // found a matching executor. use it. WorkUnitContext wuc = new WorkUnitContext(p); - LOGGER.log(Level.FINER, "Found a matching executor for {0}. Using it.", p.task.getFullDisplayName()); + LOGGER.log(Level.FINER, "Found a matching executor for {0}. Using it.", taskDisplayName); m.execute(wuc); p.leave(this); if (!wuc.getWorkUnits().isEmpty()) { - LOGGER.log(Level.FINE, "BuildableItem {0} marked as pending.", p.task.getFullDisplayName()); + LOGGER.log(Level.FINE, "BuildableItem {0} marked as pending.", taskDisplayName); makePending(p); } else @@ -1560,10 +1564,11 @@ public class Queue extends ResourceController implements Saveable { */ private @CheckForNull Runnable makeBuildable(final BuildableItem p) { if (p.task instanceof FlyweightTask) { + String taskDisplayName = p.task.getFullDisplayName(); if (!isBlockedByShutdown(p.task)) { Runnable runnable = makeFlyWeightTaskBuildable(p); - LOGGER.log(Level.FINE, "Converting flyweight task: {0} into a BuildableRunnable", p.task.getFullDisplayName()); + LOGGER.log(Level.FINE, "Converting flyweight task: {0} into a BuildableRunnable", taskDisplayName); if(runnable != null){ return runnable; } @@ -1572,11 +1577,11 @@ public class Queue extends ResourceController implements Saveable { //if the execution gets here, it means the task could not be scheduled since the node //the task is supposed to run on is offline or not available. //Thus, the flyweighttask enters the buildables queue and will ask Jenkins to provision a node - LOGGER.log(Level.FINEST, "Flyweight task {0} is entering as buildable to provision a node.", p.task.getFullDisplayName()); + LOGGER.log(Level.FINEST, "Flyweight task {0} is entering as buildable to provision a node.", taskDisplayName); return new BuildableRunnable(p); } // if the execution gets here, it means the task is blocked by shutdown and null is returned. - LOGGER.log(Level.FINE, "Task {0} is blocked by shutdown.", p.task.getFullDisplayName()); + LOGGER.log(Level.FINE, "Task {0} is blocked by shutdown.", taskDisplayName); return null; } else { // regular heavyweight task From a69542a553aec41264d0ee03b3e56a381e09b88c Mon Sep 17 00:00:00 2001 From: Fritz Elfert Date: Mon, 12 Oct 2015 11:21:30 +0200 Subject: [PATCH 0647/2573] Firing SaveableListener, fix formatting --- core/src/main/java/jenkins/model/Nodes.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/jenkins/model/Nodes.java b/core/src/main/java/jenkins/model/Nodes.java index 4a2267c057..76593dc570 100644 --- a/core/src/main/java/jenkins/model/Nodes.java +++ b/core/src/main/java/jenkins/model/Nodes.java @@ -155,6 +155,7 @@ public class Nodes implements Saveable { XmlFile xmlFile = new XmlFile(Jenkins.XSTREAM, new File(new File(getNodesDir(), node.getNodeName()), "config.xml")); xmlFile.write(node); + SaveableListener.fireOnChange(this, xmlFile); } } @@ -170,7 +171,7 @@ public class Nodes implements Saveable { Queue.withLock(new Runnable() { @Override public void run() { - jenkins.trimLabels(); + jenkins.trimLabels(); } }); persistNode(node); From 006de46f9203ea9b86962f9db21e20a0665a423d Mon Sep 17 00:00:00 2001 From: Fritz Elfert Date: Mon, 12 Oct 2015 12:26:05 +0200 Subject: [PATCH 0648/2573] Return boolean as suggested. --- core/src/main/java/jenkins/model/Nodes.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/jenkins/model/Nodes.java b/core/src/main/java/jenkins/model/Nodes.java index 76593dc570..5202c3b640 100644 --- a/core/src/main/java/jenkins/model/Nodes.java +++ b/core/src/main/java/jenkins/model/Nodes.java @@ -160,13 +160,14 @@ public class Nodes implements Saveable { } /** - * Updates an existing node on disk. If the node instance is not in the list of nodes, then this will be a no-op, even if - * there is another instance with the same {@link Node#getNodeName()}. + * Updates an existing node on disk. If the node instance is not in the list of nodes, then this + * will be a no-op, even if there is another instance with the same {@link Node#getNodeName()}. * * @param node the node to be updated. + * @return {@code true}, if the node was updated. {@code false}, if the node was not in the list of nodes. * @throws IOException if the node could not be persisted. */ - public void updateNode(final @Nonnull Node node) throws IOException { + public boolean updateNode(final @Nonnull Node node) throws IOException { if (node == nodes.get(node.getNodeName())) { Queue.withLock(new Runnable() { @Override @@ -175,7 +176,9 @@ public class Nodes implements Saveable { } }); persistNode(node); + return true; } + return false; } /** From 2355c34dbcc6e670d62c890f907a800a001d7f3c Mon Sep 17 00:00:00 2001 From: Fritz Elfert Date: Mon, 12 Oct 2015 13:28:49 +0200 Subject: [PATCH 0649/2573] Return boolean as suggested. --- core/src/main/java/jenkins/model/Jenkins.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index cde5dc5b54..97f7d136b7 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -1737,9 +1737,10 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve /** * Updates an existing {@link Node} on disk. + * @see Nodes#updateNode */ - public void updateNode(Node n) throws IOException { - nodes.updateNode(n); + public boolean updateNode(Node n) throws IOException { + return nodes.updateNode(n); } public void setNodes(final List n) throws IOException { From 0594c4cbccd24d4883fc0150e8fc511c9da63eb4 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Tue, 6 Oct 2015 14:13:24 +0300 Subject: [PATCH 0650/2573] [SECURITY-153] Hide references to inaccessible jobs in fingerprints. --- .../main/java/hudson/model/Fingerprint.java | 119 +++++- .../hudson/model/Fingerprint/index.jelly | 28 +- .../jvnet/hudson/test/CreateFileBuilder.java | 99 +++++ .../org/jvnet/hudson/test/MockFolder.java | 2 +- .../jvnet/hudson/test/SecuredMockFolder.java | 125 ++++++ .../hudson/test/WorkspaceCopyFileBuilder.java | 116 ++++++ .../java/hudson/model/FingerprintTest.java | 379 ++++++++++++++++++ 7 files changed, 841 insertions(+), 27 deletions(-) create mode 100644 test/src/main/java/org/jvnet/hudson/test/CreateFileBuilder.java create mode 100644 test/src/main/java/org/jvnet/hudson/test/SecuredMockFolder.java create mode 100644 test/src/main/java/org/jvnet/hudson/test/WorkspaceCopyFileBuilder.java create mode 100644 test/src/test/java/hudson/model/FingerprintTest.java diff --git a/core/src/main/java/hudson/model/Fingerprint.java b/core/src/main/java/hudson/model/Fingerprint.java index 22fac5bb8d..4e02e8f6ec 100644 --- a/core/src/main/java/hudson/model/Fingerprint.java +++ b/core/src/main/java/hudson/model/Fingerprint.java @@ -39,7 +39,9 @@ import hudson.BulkChange; import hudson.Extension; import hudson.model.listeners.ItemListener; import hudson.model.listeners.SaveableListener; +import hudson.remoting.Callable; import hudson.security.ACL; +import hudson.security.Permission; import hudson.util.AtomicFileWriter; import hudson.util.HexBinaryConverter; import hudson.util.Iterators; @@ -71,6 +73,9 @@ import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; +import org.acegisecurity.AccessDeniedException; +import org.acegisecurity.Authentication; import org.xmlpull.v1.XmlPullParserException; /** @@ -103,15 +108,37 @@ public class Fingerprint implements ModelObject, Saveable { /** * Gets {@link Job#getFullName() the full name of the job}. - *

                            - * Such job could be since then removed, - * so there might not be a corresponding - * {@link Job}. + * Such job could be since then removed, so there might not be a corresponding {@link Job}. + * + * @return A name of the job */ @Exported + @Nonnull public String getName() { return name; } + + /** + * Checks if the current user has permission to see this pointer. + * @return {@code true} if the job exists and user has {@link Item#READ} permissions + * or if the current user has {@link Jenkins#ADMINISTER} permissions. + * If the job exists, but the current user has no permission to discover it, + * {@code false} will be returned. + * If the job has been deleted and the user has no {@link Jenkins#ADMINISTER} permissions, + * it also returns {@code false} in order to avoid the job existence fact exposure. + */ + private boolean hasPermissionToDiscoverBuild() { + // We expose the data to Jenkins administrators in order to + // let them manage the data for deleted jobs (also works for SYSTEM) + final Jenkins instance = Jenkins.getInstance(); + if (instance != null && instance.hasPermission(Jenkins.ADMINISTER)) { + return true; + } + + return canDiscoverItem(name); + } + + void setName(String newName) { name = newName; @@ -129,10 +156,11 @@ public class Fingerprint implements ModelObject, Saveable { /** * Gets the project build number. *

                            - * Such {@link Run} could be since then - * discarded. + * Such {@link Run} could be since then discarded. + * @return A build number */ @Exported + @Nonnull public int getNumber() { return number; } @@ -806,11 +834,15 @@ public class Fingerprint implements ModelObject, Saveable { * this file. * * @return null - * if the file is apparently created outside Hudson. + * if the file is apparently created outside Hudson or if the current + * user has no permission to discover the job. */ @Exported public BuildPtr getOriginal() { - return original; + if (original != null && original.hasPermissionToDiscoverBuild()) { + return original; + } + return null; } public String getDisplayName() { @@ -899,8 +931,17 @@ public class Fingerprint implements ModelObject, Saveable { @Exported(name="usage") public List _getUsages() { List r = new ArrayList(); - for (Entry e : usages.entrySet()) - r.add(new RangeItem(e.getKey(),e.getValue())); + final Jenkins instance = Jenkins.getInstance(); + if (instance == null) { + return r; + } + + for (Entry e : usages.entrySet()) { + final String itemName = e.getKey(); + if (instance.hasPermission(Jenkins.ADMINISTER) || canDiscoverItem(itemName)) { + r.add(new RangeItem(itemName, e.getValue())); + } + } return r; } @@ -1292,6 +1333,64 @@ public class Fingerprint implements ModelObject, Saveable { @Override public String toString() { return "Fingerprint[original=" + original + ",hash=" + getHashString() + ",fileName=" + fileName + ",timestamp=" + DATE_CONVERTER.toString(timestamp) + ",usages=" + new TreeMap(usages) + ",facets=" + facets + "]"; } + + /** + * Checks if the current user can Discover the item. + * If yes, it may be displayed as a text in Fingerprint UIs. + * @param fullName Full name of the job + * @return {@code true} if the user can discover the item + */ + private static boolean canDiscoverItem(@Nonnull final String fullName) { + final Jenkins jenkins = Jenkins.getInstance(); + if (jenkins == null) { + return false; + } + + // Fast check to avoid security context switches + Item item = null; + try { + item = jenkins.getItemByFullName(fullName); + } catch (AccessDeniedException ex) { + // ignore, we will fall-back later + } + if (item != null) { + return true; + } + + // Probably it failed due to the missing Item.DISCOVER + // We try to retrieve the job using SYSTEM user and to check permissions manually. + final Authentication userAuth = Jenkins.getAuthentication(); + final boolean[] res = new boolean[] {false}; + ACL.impersonate(ACL.SYSTEM, new Runnable() { + @Override + public void run() { + final Item itemBySystemUser = jenkins.getItemByFullName(fullName); + if (itemBySystemUser == null) { + return; + } + + // To get the item existence fact, a user needs Item.DISCOVER for the item + // and Item.READ for all container folders. + boolean canDiscoverTheItem = itemBySystemUser.getACL().hasPermission(userAuth, Item.DISCOVER); + if (canDiscoverTheItem) { + ItemGroup current = itemBySystemUser.getParent(); + do { + if (current instanceof Item) { + final Item item = (Item) current; + current = item.getParent(); + if (!item.getACL().hasPermission(userAuth, Item.READ)) { + canDiscoverTheItem = false; + } + } else { + current = null; + } + } while (canDiscoverTheItem && current != null); + } + res[0] = canDiscoverTheItem; + } + }); + return res[0]; + } private static final XStream XSTREAM = new XStream2(); static { diff --git a/core/src/main/resources/hudson/model/Fingerprint/index.jelly b/core/src/main/resources/hudson/model/Fingerprint/index.jelly index 88cf473961..e76741d3ee 100644 --- a/core/src/main/resources/hudson/model/Fingerprint/index.jelly +++ b/core/src/main/resources/hudson/model/Fingerprint/index.jelly @@ -66,24 +66,20 @@ THE SOFTWARE. ${%This file has been used in the following places}:

                            + - - - - - + + + + + + +
                            - - - ${j} - - - ${j} - - - - -
                            + ${j} + + +
                            diff --git a/test/src/main/java/org/jvnet/hudson/test/CreateFileBuilder.java b/test/src/main/java/org/jvnet/hudson/test/CreateFileBuilder.java new file mode 100644 index 0000000000..ad82193e01 --- /dev/null +++ b/test/src/main/java/org/jvnet/hudson/test/CreateFileBuilder.java @@ -0,0 +1,99 @@ +/* + * The MIT License + * + * Copyright (c) 2015 Oleg Nenashev. + * + * 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; + +import hudson.AbortException; +import hudson.Extension; +import hudson.FilePath; +import hudson.Launcher; +import hudson.model.AbstractBuild; +import hudson.model.BuildListener; +import hudson.model.Descriptor; +import hudson.tasks.Builder; +import java.io.IOException; +import javax.annotation.Nonnull; +import net.sf.json.JSONObject; +import org.kohsuke.stapler.StaplerRequest; + +/** + * Creates a test builder, which creates a file in the workspace. + * @author Oleg Nenashev + * @since TODO + */ +public class CreateFileBuilder extends Builder { + + @Nonnull + private final String fileName; + + @Nonnull + private final String fileContent; + + public CreateFileBuilder(@Nonnull String fileName, @Nonnull String fileContent) { + this.fileName = fileName; + this.fileContent = fileContent; + } + + @Nonnull + public String getFileName() { + return fileName; + } + + @Nonnull + public String getFileContent() { + return fileContent; + } + + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + listener.getLogger().println("Creating a file " + fileName); + + FilePath workspace = build.getWorkspace(); + if (workspace == null) { + throw new AbortException("Cannot get the workspace of the build"); + } + workspace.child(fileName).write(fileContent, "UTF-8"); + + return true; + } + + @Override + public Descriptor getDescriptor() { + return new DescriptorImpl(); + } + + @Extension + public static final class DescriptorImpl extends Descriptor { + + @Override + public Builder newInstance(StaplerRequest req, JSONObject data) { + throw new UnsupportedOperationException("This is a temporarytest class, " + + "which should not be configured from UI"); + } + + @Override + public String getDisplayName() { + return "Create a file"; + } + } +} diff --git a/test/src/main/java/org/jvnet/hudson/test/MockFolder.java b/test/src/main/java/org/jvnet/hudson/test/MockFolder.java index af96c50bc2..60009ccf4f 100644 --- a/test/src/main/java/org/jvnet/hudson/test/MockFolder.java +++ b/test/src/main/java/org/jvnet/hudson/test/MockFolder.java @@ -77,7 +77,7 @@ public class MockFolder extends AbstractItem implements DirectlyModifiableTopLev private String primaryView; private ViewsTabBar viewsTabBar; - private MockFolder(ItemGroup parent, String name) { + protected MockFolder(ItemGroup parent, String name) { super(parent, name); } diff --git a/test/src/main/java/org/jvnet/hudson/test/SecuredMockFolder.java b/test/src/main/java/org/jvnet/hudson/test/SecuredMockFolder.java new file mode 100644 index 0000000000..8a7d7dd808 --- /dev/null +++ b/test/src/main/java/org/jvnet/hudson/test/SecuredMockFolder.java @@ -0,0 +1,125 @@ +/* + * The MIT License + * + * Copyright (c) 2015 Oleg Nenashev. + * + * 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; + +import hudson.Extension; +import hudson.model.Item; +import hudson.model.ItemGroup; +import hudson.model.TopLevelItem; +import hudson.model.TopLevelItemDescriptor; +import hudson.security.ACL; +import hudson.security.Permission; +import hudson.security.SidACL; +import hudson.security.SparseACL; +import java.util.HashSet; +import java.util.Set; +import javax.annotation.Nonnull; +import jenkins.model.Jenkins; +import org.acegisecurity.Authentication; +import org.acegisecurity.acls.sid.Sid; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + +/** + * Folder stub with a configurable permission control. + * The implementation secures the access to the item and to its children. + * @author Oleg Nenashev + * @since TODO + */ +@Restricted(NoExternalUse.class) // Unrestrict after integrating into Jenkins trunk +public class SecuredMockFolder extends MockFolder { + + private String grantedUser; + private Set grantedPermissions; + + private SecuredMockFolder(ItemGroup parent, String name) { + super(parent, name); + } + + @Override + public TopLevelItem getItem(String name) { + final TopLevelItem item = super.getItem(name); + if (item != null && item.hasPermission(Item.READ)) { + return item; + } + return null; + } + + @Override + public boolean hasPermission(Permission p) { + if (super.hasPermission(p)) { + return true; + } + return hasPermissionInField(Jenkins.getAuthentication().getName(), p); + } + + private boolean hasPermissionInField(String sid, @Nonnull Permission p) { + if (sid.equals(grantedUser)) { + if (grantedPermissions != null && grantedPermissions.contains(p.getId())) { + return true; + } + } + return false; + } + + @Override + public ACL getACL() { + return new ACLWrapper(); + } + + public void setPermissions(String username, Permission... permissions) { + this.grantedUser = username; + if (grantedPermissions == null) { + grantedPermissions = new HashSet(); + } else { + grantedPermissions.clear(); + } + for (Permission p : permissions) { + grantedPermissions.add(p.getId()); + } + } + + @Extension + public static class DescriptorImpl extends TopLevelItemDescriptor { + + @Override + public String getDisplayName() { + return "MockFolder with security control"; + } + + @Override + public TopLevelItem newInstance(ItemGroup parent, String name) { + return new SecuredMockFolder(parent, name); + } + } + + private class ACLWrapper extends SidACL { + + @Override + protected Boolean hasPermission(Sid p, Permission permission) { + //TODO: Handle globally defined permissions? + return SecuredMockFolder.this.hasPermissionInField(toString(p), permission); + } + } +} diff --git a/test/src/main/java/org/jvnet/hudson/test/WorkspaceCopyFileBuilder.java b/test/src/main/java/org/jvnet/hudson/test/WorkspaceCopyFileBuilder.java new file mode 100644 index 0000000000..9a7b5c95d7 --- /dev/null +++ b/test/src/main/java/org/jvnet/hudson/test/WorkspaceCopyFileBuilder.java @@ -0,0 +1,116 @@ +/* + * The MIT License + * + * Copyright (c) 2015 Oleg Nenashev. + * + * 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; + +import hudson.AbortException; +import hudson.Extension; +import hudson.FilePath; +import hudson.Launcher; +import hudson.model.AbstractBuild; +import hudson.model.AbstractProject; +import hudson.model.BuildListener; +import hudson.model.Descriptor; +import hudson.tasks.Builder; +import java.io.IOException; +import jenkins.model.Jenkins; +import net.sf.json.JSONObject; +import org.kohsuke.stapler.StaplerRequest; + +/** + * Test Builder, which copies a file from a workspace of another job. + * Supports {@link AbstractProject}s only. + * @author Oleg Nenashev + */ +public class WorkspaceCopyFileBuilder extends Builder { + + private final String fileName; + private final String jobName; + private final int buildNumber; + + public WorkspaceCopyFileBuilder(String fileName, String jobName, int buildNumber) { + this.fileName = fileName; + this.jobName = jobName; + this.buildNumber = buildNumber; + } + + public int getBuildNumber() { + return buildNumber; + } + + public String getFileName() { + return fileName; + } + + public String getJobName() { + return jobName; + } + + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + listener.getLogger().println("Copying a " + fileName + " from " + jobName + "#" + buildNumber); + + Jenkins inst = Jenkins.getInstance(); + AbstractProject item = inst.getItemByFullName(jobName, AbstractProject.class); + if (item == null) { + throw new AbortException("Cannot find a source job: " + jobName); + } + + AbstractBuild sourceBuild = item.getBuildByNumber(buildNumber); + if (sourceBuild == null) { + throw new AbortException("Cannot find a source build: " + jobName + "#" + buildNumber); + } + + FilePath sourceWorkspace = sourceBuild.getWorkspace(); + if (sourceWorkspace == null) { + throw new AbortException("Cannot get the source workspace from " + sourceBuild.getDisplayName()); + } + + FilePath workspace = build.getWorkspace(); + if (workspace == null) { + throw new IOException("Cannot get the workspace of the build"); + } + workspace.child(fileName).copyFrom(sourceWorkspace.child(fileName)); + + return true; + } + + @Override + public Descriptor getDescriptor() { + return new DescriptorImpl(); + } + + @Extension + public static final class DescriptorImpl extends Descriptor { + + @Override + public Builder newInstance(StaplerRequest req, JSONObject data) { + throw new UnsupportedOperationException(); + } + + @Override + public String getDisplayName() { + return "Copy a file from the workspace of another build"; + } + } +} \ No newline at end of file diff --git a/test/src/test/java/hudson/model/FingerprintTest.java b/test/src/test/java/hudson/model/FingerprintTest.java new file mode 100644 index 0000000000..d1b9d23dd1 --- /dev/null +++ b/test/src/test/java/hudson/model/FingerprintTest.java @@ -0,0 +1,379 @@ +/* + * 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.model; + +import hudson.security.ACL; +import hudson.security.AuthorizationMatrixProperty; +import hudson.security.Permission; +import hudson.security.ProjectMatrixAuthorizationStrategy; +import hudson.tasks.ArtifactArchiver; +import hudson.tasks.Fingerprinter; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Map; +import java.util.Set; +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; +import jenkins.model.Jenkins; +import org.junit.Rule; +import org.junit.Test; +import org.junit.Before; +import org.jvnet.hudson.test.CreateFileBuilder; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.MockFolder; +import org.jvnet.hudson.test.SecuredMockFolder; +import org.jvnet.hudson.test.WorkspaceCopyFileBuilder; + +import static org.junit.Assert.*; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + + +//TODO: Refactoring: Tests should be exchanged with FingerprinterTest somehow +/** + * Tests for the {@link Fingerprint} class. + * @author Oleg Nenashev + */ +public class FingerprintTest { + + @Rule + public JenkinsRule rule = new JenkinsRule(); + + @Before + public void setupRealm() { + rule.jenkins.setSecurityRealm(rule.createDummySecurityRealm()); + } + + @Test + public void shouldCreateFingerprintsForWorkspace() throws Exception { + FreeStyleProject project = rule.createFreeStyleProject(); + project.getBuildersList().add(new CreateFileBuilder("test.txt", "Hello, world!")); + project.getPublishersList().add(new Fingerprinter("test.txt", false)); + FreeStyleBuild build = rule.buildAndAssertSuccess(project); + + Fingerprint fp = getFingerprint(build, "test.txt"); + } + + @Test + public void shouldCreateFingerprintsForArtifacts() throws Exception { + FreeStyleProject project = rule.createFreeStyleProject(); + project.getBuildersList().add(new CreateFileBuilder("test.txt", "Hello, world!")); + ArtifactArchiver archiver = new ArtifactArchiver("test.txt"); + archiver.setFingerprint(true); + project.getPublishersList().add(archiver); + FreeStyleBuild build = rule.buildAndAssertSuccess(project); + + Fingerprint fp = getFingerprint(build, "test.txt"); + } + + @Test + public void shouldCreateUsageLinks() throws Exception { + // Project 1 + FreeStyleProject project = createAndRunProjectWithPublisher("fpProducer", "test.txt"); + final FreeStyleBuild build = project.getLastBuild(); + + // Project 2 + FreeStyleProject project2 = rule.createFreeStyleProject(); + project2.getBuildersList().add(new WorkspaceCopyFileBuilder("test.txt", project.getName(), build.getNumber())); + project2.getPublishersList().add(new Fingerprinter("test.txt")); + FreeStyleBuild build2 = rule.buildAndAssertSuccess(project2); + + Fingerprint fp = getFingerprint(build, "test.txt"); + + // Check references + Fingerprint.BuildPtr original = fp.getOriginal(); + assertEquals("Original reference contains a wrong job name", project.getName(), original.getName()); + assertEquals("Original reference contains a wrong build number", build.getNumber(), original.getNumber()); + + Hashtable usages = fp.getUsages(); + assertTrue("Usages do not have a reference to " + project, usages.containsKey(project.getName())); + assertTrue("Usages do not have a reference to " + project2, usages.containsKey(project2.getName())); + } + + @Test + @Issue("SECURITY-153") + public void shouldBeUnableToSeeJobsIfNoPermissions() throws Exception { + // Project 1 + final FreeStyleProject project1 = createAndRunProjectWithPublisher("fpProducer", "test.txt"); + final FreeStyleBuild build = project1.getLastBuild(); + + // Project 2 + final FreeStyleProject project2 = rule.createFreeStyleProject("project2"); + project2.getBuildersList().add(new WorkspaceCopyFileBuilder("test.txt", project1.getName(), build.getNumber())); + project2.getPublishersList().add(new Fingerprinter("test.txt")); + final FreeStyleBuild build2 = rule.buildAndAssertSuccess(project2); + + // Get fingerprint + final Fingerprint fp = getFingerprint(build, "test.txt"); + + // Init Users + User user1 = User.get("user1"); // can access project1 + User user2 = User.get("user2"); // can access project2 + User user3 = User.get("user3"); // cannot access anything + + // Project permissions + setupProjectMatrixAuthStrategy(Jenkins.READ); + setJobPermissionsOnce(project1, "user1", Item.READ, Item.DISCOVER); + setJobPermissionsOnce(project2, "user2", Item.READ, Item.DISCOVER); + + ACL.impersonate(user1.impersonate(), new Runnable() { + @Override + public void run() { + Fingerprint.BuildPtr original = fp.getOriginal(); + assertThat("user1 should be able to see the origin", fp.getOriginal(), notNullValue()); + assertEquals("user1 should be able to see the origin's project name", project1.getName(), original.getName()); + assertEquals("user1 should be able to see the origin's build number", build.getNumber(), original.getNumber()); + assertEquals("Only one usage should be visible to user1", 1, fp._getUsages().size()); + assertEquals("Only project1 should be visible to user1", project1.getFullName(), fp._getUsages().get(0).name); + } + }); + + ACL.impersonate(user2.impersonate(), new Runnable() { + @Override + public void run() { + assertThat("user2 should be unable to see the origin", fp.getOriginal(), nullValue()); + assertEquals("Only one usage should be visible to user2", 1, fp._getUsages().size()); + assertEquals("Only project2 should be visible to user2", project2.getFullName(), fp._getUsages().get(0).name); + } + }); + + ACL.impersonate(user3.impersonate(), new Runnable() { + @Override + public void run() { + Fingerprint.BuildPtr original = fp.getOriginal(); + assertThat("user3 should be unable to see the origin", fp.getOriginal(), nullValue()); + assertEquals("All usages should be invisible for user3", 0, fp._getUsages().size()); + } + }); + } + + @Test + public void shouldBeAbleToSeeOriginalWithDiscoverPermissionOnly() throws Exception { + // Setup the environment + final FreeStyleProject project = createAndRunProjectWithPublisher("project", "test.txt"); + final FreeStyleBuild build = project.getLastBuild(); + final Fingerprint fingerprint = getFingerprint(build, "test.txt"); + + // Init Users and security + User user1 = User.get("user1"); + setupProjectMatrixAuthStrategy(Jenkins.READ, Item.DISCOVER); + + ACL.impersonate(user1.impersonate(), new Runnable() { + @Override + public void run() { + Fingerprint.BuildPtr original = fingerprint.getOriginal(); + assertThat("user1 should able to see the origin", fingerprint.getOriginal(), notNullValue()); + assertEquals("user1 sees the wrong original name with Item.DISCOVER", project.getFullName(), original.getName()); + assertEquals("user1 sees the wrong original number with Item.DISCOVER", build.getNumber(), original.getNumber()); + assertEquals("Usage ref in fingerprint should be visible to user1", 1, fingerprint._getUsages().size()); + } + }); + } + + @Test + public void shouldBeAbleToSeeFingerprintsInReadableFolder() throws Exception { + final SecuredMockFolder folder = rule.jenkins.createProject(SecuredMockFolder.class, "folder"); + final FreeStyleProject project = createAndRunProjectWithPublisher(folder, "project", "test.txt"); + final FreeStyleBuild build = project.getLastBuild(); + final Fingerprint fingerprint = getFingerprint(build, "test.txt"); + + // Init Users and security + User user1 = User.get("user1"); + setupProjectMatrixAuthStrategy(false, Jenkins.READ, Item.DISCOVER); + setJobPermissionsOnce(project, "user1", Item.DISCOVER); // Prevents the fallback to the folder ACL + folder.setPermissions("user1", Item.READ); + + // Ensure we can read the original from user account + ACL.impersonate(user1.impersonate(), new Runnable() { + @Override + public void run() { + assertTrue("Test framework issue: User1 should be able to read the folder", folder.hasPermission(Item.READ)); + + Fingerprint.BuildPtr original = fingerprint.getOriginal(); + assertThat("user1 should able to see the origin", fingerprint.getOriginal(), notNullValue()); + assertEquals("user1 sees the wrong original name with Item.DISCOVER", project.getFullName(), original.getName()); + assertEquals("user1 sees the wrong original number with Item.DISCOVER", build.getNumber(), original.getNumber()); + assertEquals("user1 should be able to see the job", 1, fingerprint._getUsages().size()); + + assertThat("User should be unable do retrieve the job due to the missing read", original.getJob(), nullValue()); + } + }); + } + + @Test + public void shouldBeUnableToSeeFingerprintsInUnreadableFolder() throws Exception { + final SecuredMockFolder folder = rule.jenkins.createProject(SecuredMockFolder.class, "folder"); + final FreeStyleProject project = createAndRunProjectWithPublisher(folder, "project", "test.txt"); + final FreeStyleBuild build = project.getLastBuild(); + final Fingerprint fingerprint = getFingerprint(build, "test.txt"); + + // Init Users and security + User user1 = User.get("user1"); // can access project1 + setupProjectMatrixAuthStrategy(Jenkins.READ, Item.DISCOVER); + + // Ensure we can read the original from user account + ACL.impersonate(user1.impersonate(), new Runnable() { + @Override + public void run() { + assertFalse("Test framework issue: User1 should be unable to read the folder", folder.hasPermission(Item.READ)); + assertThat("user1 should be unable to see the origin", fingerprint.getOriginal(), nullValue()); + assertEquals("No jobs should be visible to user1", 0, fingerprint._getUsages().size()); + } + }); + } + + /** + * A common non-admin user should not be able to see references to a + * deleted job even if he used to have READ permissions before the deletion. + * @throws Exception Test error + */ + @Test + @Issue("SECURITY-153") + public void commonUserShouldBeUnableToSeeReferencesOfDeletedJobs() throws Exception { + // Setup the environment + FreeStyleProject project = createAndRunProjectWithPublisher("project", "test.txt"); + FreeStyleBuild build = project.getLastBuild(); + final Fingerprint fp = getFingerprint(build, "test.txt"); + + // Init Users and security + User user1 = User.get("user1"); + setupProjectMatrixAuthStrategy(Jenkins.READ, Item.READ, Item.DISCOVER); + project.delete(); + + ACL.impersonate(user1.impersonate(), new Runnable() { + @Override + public void run() { + assertThat("user1 should be unable to see the origin", fp.getOriginal(), nullValue()); + assertEquals("No jobs should be visible to user1", 0, fp._getUsages().size()); + } + }); + } + + @Test + public void adminShouldBeAbleToSeeReferencesOfDeletedJobs() throws Exception { + // Setup the environment + final FreeStyleProject project = createAndRunProjectWithPublisher("project", "test.txt"); + final FreeStyleBuild build = project.getLastBuild(); + final Fingerprint fingerprint = getFingerprint(build, "test.txt"); + + // Init Users and security + User user1 = User.get("user1"); + setupProjectMatrixAuthStrategy(Jenkins.ADMINISTER); + project.delete(); + + ACL.impersonate(user1.impersonate(), new Runnable() { + @Override + public void run() { + Fingerprint.BuildPtr original = fingerprint.getOriginal(); + assertThat("user1 should able to see the origin", fingerprint.getOriginal(), notNullValue()); + assertThat("Job has been deleted, so Job reference shoud return null", fingerprint.getOriginal().getJob(), nullValue()); + assertEquals("user1 sees the wrong original name with Item.DISCOVER", project.getFullName(), original.getName()); + assertEquals("user1 sees the wrong original number with Item.DISCOVER", build.getNumber(), original.getNumber()); + assertEquals("user1 should be able to see the job in usages", 1, fingerprint._getUsages().size()); + } + }); + } + + @Nonnull + private Fingerprint getFingerprint(@CheckForNull Run run, @Nonnull String filename) { + assertNotNull("Input run is null", run); + Fingerprinter.FingerprintAction action = run.getAction(Fingerprinter.FingerprintAction.class); + assertNotNull("Fingerprint action has not been created in " + run, action); + Map fingerprints = action.getFingerprints(); + final Fingerprint fp = fingerprints.get(filename); + assertNotNull("No reference to '" + filename + "' from the Fingerprint action", fp); + return fp; + } + + @Nonnull + private FreeStyleProject createAndRunProjectWithPublisher(String projectName, String fpFileName) + throws Exception { + return createAndRunProjectWithPublisher(null, projectName, fpFileName); + } + + @Nonnull + private FreeStyleProject createAndRunProjectWithPublisher(@CheckForNull MockFolder folder, + String projectName, String fpFileName) throws Exception { + final FreeStyleProject project; + if (folder == null) { + project = rule.createFreeStyleProject(projectName); + } else { + project = folder.createProject(FreeStyleProject.class, projectName); + } + project.getBuildersList().add(new CreateFileBuilder(fpFileName, "Hello, world!")); + ArtifactArchiver archiver = new ArtifactArchiver(fpFileName); + archiver.setFingerprint(true); + project.getPublishersList().add(archiver); + rule.buildAndAssertSuccess(project); + return project; + } + + private void setupProjectMatrixAuthStrategy(@Nonnull Permission ... permissions) { + setupProjectMatrixAuthStrategy(true, permissions); + } + + private void setupProjectMatrixAuthStrategy(boolean inheritFromFolders, @Nonnull Permission ... permissions) { + ProjectMatrixAuthorizationStrategy str = inheritFromFolders + ? new ProjectMatrixAuthorizationStrategy() + : new NoInheritanceProjectMatrixAuthorizationStrategy(); + for (Permission p : permissions) { + str.add(p, "anonymous"); + } + rule.jenkins.setAuthorizationStrategy(str); + } + //TODO: could be reworked to support multiple assignments + private void setJobPermissionsOnce(Job job, String username, @Nonnull Permission ... s) + throws IOException { + assertThat("Cannot assign the property twice", job.getProperty(AuthorizationMatrixProperty.class), nullValue()); + + Map> permissions = new HashMap>(); + HashSet userSpec = new HashSet(Arrays.asList(username)); + + for (Permission p : s) { + permissions.put(p, userSpec); + } + AuthorizationMatrixProperty property = new AuthorizationMatrixProperty(permissions); + job.addProperty(property); + } + + /** + * Security strategy, which prevents the permission inheritance from upper folders. + */ + private static class NoInheritanceProjectMatrixAuthorizationStrategy extends ProjectMatrixAuthorizationStrategy { + + @Override + public ACL getACL(Job project) { + AuthorizationMatrixProperty amp = project.getProperty(AuthorizationMatrixProperty.class); + if (amp != null) { + return amp.getACL().newInheritingACL(getRootACL()); + } else { + return getRootACL(); + } + } + } +} From 09fadd58b56f8504fab414a9414d081918461d1a Mon Sep 17 00:00:00 2001 From: christ66 Date: Mon, 12 Oct 2015 16:37:18 -0700 Subject: [PATCH 0651/2573] Use Level.FINEST for logging all queue information. --- core/src/main/java/hudson/model/Queue.java | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index af11e8cd80..d6e1c79d5c 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -1424,9 +1424,9 @@ public class Queue extends ResourceController implements Saveable { } for (BlockedItem p : blockedItems) { String taskDisplayName = p.task.getFullDisplayName(); - LOGGER.log(Level.FINER, "Current blocked item: {0}", taskDisplayName); + LOGGER.log(Level.FINEST, "Current blocked item: {0}", taskDisplayName); if (!isBuildBlocked(p) && allowNewBuildableTask(p.task)) { - LOGGER.log(Level.INFO, + LOGGER.log(Level.FINEST, "BlockedItem {0}: blocked -> buildable as the build is not blocked and new tasks are allowed", taskDisplayName); @@ -1449,7 +1449,7 @@ public class Queue extends ResourceController implements Saveable { WaitingItem top = peek(); if (top.timestamp.compareTo(new GregorianCalendar()) > 0) { - LOGGER.log(Level.FINE, "Finished moving all ready items from queue."); + LOGGER.log(Level.FINEST, "Finished moving all ready items from queue."); break; // finished moving all ready items from queue } @@ -1460,7 +1460,7 @@ public class Queue extends ResourceController implements Saveable { Runnable r = makeBuildable(new BuildableItem(top)); String topTaskDisplayName = top.task.getFullDisplayName(); if (r != null) { - LOGGER.log(Level.FINE, "Executing runnable {0}", topTaskDisplayName); + LOGGER.log(Level.FINEST, "Executing runnable {0}", topTaskDisplayName); r.run(); } else { LOGGER.log(Level.FINEST, "Item {0} was unable to be made a buildable and is now a blocked item.", topTaskDisplayName); @@ -1528,16 +1528,16 @@ public class Queue extends ResourceController implements Saveable { // found a matching executor. use it. WorkUnitContext wuc = new WorkUnitContext(p); - LOGGER.log(Level.FINER, "Found a matching executor for {0}. Using it.", taskDisplayName); + LOGGER.log(Level.FINEST, "Found a matching executor for {0}. Using it.", taskDisplayName); m.execute(wuc); p.leave(this); if (!wuc.getWorkUnits().isEmpty()) { - LOGGER.log(Level.FINE, "BuildableItem {0} marked as pending.", taskDisplayName); + LOGGER.log(Level.FINEST, "BuildableItem {0} marked as pending.", taskDisplayName); makePending(p); } else - LOGGER.log(Level.FINE, "BuildableItem {0} with empty work units!?", p); + LOGGER.log(Level.FINEST, "BuildableItem {0} with empty work units!?", p); // Ensure that identification of blocked tasks is using the live state: JENKINS-27708 & JENKINS-27871 // The creation of a snapshot itself should be relatively cheap given the expected rate of @@ -1568,7 +1568,7 @@ public class Queue extends ResourceController implements Saveable { if (!isBlockedByShutdown(p.task)) { Runnable runnable = makeFlyWeightTaskBuildable(p); - LOGGER.log(Level.FINE, "Converting flyweight task: {0} into a BuildableRunnable", taskDisplayName); + LOGGER.log(Level.FINEST, "Converting flyweight task: {0} into a BuildableRunnable", taskDisplayName); if(runnable != null){ return runnable; } @@ -1581,7 +1581,7 @@ public class Queue extends ResourceController implements Saveable { return new BuildableRunnable(p); } // if the execution gets here, it means the task is blocked by shutdown and null is returned. - LOGGER.log(Level.FINE, "Task {0} is blocked by shutdown.", taskDisplayName); + LOGGER.log(Level.FINEST, "Task {0} is blocked by shutdown.", taskDisplayName); return null; } else { // regular heavyweight task @@ -1624,7 +1624,7 @@ public class Queue extends ResourceController implements Saveable { continue; } - LOGGER.log(Level.FINE, "Creating flyweight task {0} for computer {1}", new Object[]{p.task.getFullDisplayName(), c.getName()}); + LOGGER.log(Level.FINEST, "Creating flyweight task {0} for computer {1}", new Object[]{p.task.getFullDisplayName(), c.getName()}); return new Runnable() { @Override public void run() { c.startFlyWeightTask(new WorkUnitContext(p).createWorkUnit(p.task)); From 581eb9ceb354b8a55c010d0547ff73cb6fd67a75 Mon Sep 17 00:00:00 2001 From: Valentina Armenise Date: Fri, 4 Sep 2015 15:45:43 +0200 Subject: [PATCH 0652/2573] [SECURITY-186] check user permissions when calling QUEUE API --- core/src/main/java/hudson/model/Queue.java | 108 ++++++++++++++++-- .../src/test/java/hudson/model/QueueTest.java | 77 ++++++++++++- 2 files changed, 174 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index 830eb851f6..6727ab16c9 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -109,6 +109,7 @@ import jenkins.security.QueueItemAuthenticatorConfiguration; import jenkins.util.AtmostOneTaskExecutor; import org.acegisecurity.AccessDeniedException; import org.acegisecurity.Authentication; +import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponses; import org.kohsuke.stapler.export.Exported; @@ -694,15 +695,68 @@ public class Queue extends ResourceController implements Saveable { */ @Exported(inline=true) public synchronized Item[] getItems() { - Item[] r = new Item[waitingList.size() + blockedProjects.size() + buildables.size() + pendings.size()]; - waitingList.toArray(r); - int idx = waitingList.size(); - for (BlockedItem p : blockedProjects.values()) - r[idx++] = p; - for (BuildableItem p : reverse(buildables.values())) - r[idx++] = p; - for (BuildableItem p : reverse(pendings.values())) - r[idx++] = p; + List r = new ArrayList(); + + for(WaitingItem p : waitingList) { + r = filterItemListBasedOnPermissions(r, p); + } + for (BlockedItem p : blockedProjects.values()){ + r = filterItemListBasedOnPermissions(r, p); + } + for (BuildableItem p : reverse(buildables.values())) { + r = filterItemListBasedOnPermissions(r, p); + } + for (BuildableItem p : reverse(pendings.values())) { + r= filterItemListBasedOnPermissions(r, p); + } + Item[] items = new Item[r.size()]; + r.toArray(items); + return items; + } + + private List filterItemListBasedOnPermissions(List r, Item t) { + if (t.task instanceof hudson.model.Item) { + if (((hudson.model.Item)t.task).hasPermission(hudson.model.Item.READ)) { + r.add(t); + } + } + return r; + } + + /** + * Returns an array of Item for which it is only visible the name of the task. + * + * Generally speaking the array is sorted such that the items that are most likely built sooner are + * at the end. + */ + @Restricted(NoExternalUse.class) + @Exported(inline=true) + public synchronized StubItem[] getDiscoverableItems() { + List r = new ArrayList(); + + for(WaitingItem p : waitingList) { + r = filterDiscoverableItemListBasedOnPermissions(r, p); + } + for (BlockedItem p : blockedProjects.values()){ + r = filterDiscoverableItemListBasedOnPermissions(r, p); + } + for (BuildableItem p : reverse(buildables.values())) { + r = filterDiscoverableItemListBasedOnPermissions(r, p); + } + for (BuildableItem p : reverse(pendings.values())) { + r= filterDiscoverableItemListBasedOnPermissions(r, p); + } + StubItem[] items = new StubItem[r.size()]; + r.toArray(items); + return items; + } + + private List filterDiscoverableItemListBasedOnPermissions(List r, Item t) { + if (t.task instanceof hudson.model.Item) { + if (!((hudson.model.Item)t.task).hasPermission(hudson.model.Item.READ) && ((hudson.model.Item)t.task).hasPermission(hudson.model.Item.DISCOVER)) { + r.add(new StubItem(new StubTask(t.task))); + } + } return r; } @@ -1581,6 +1635,42 @@ public class Queue extends ResourceController implements Saveable { } } + + /** + * A Stub class for {@link Task} which exposes only the name of the Task to be displayed when the user + * has DISCOVERY permissions only. + */ + @Restricted(NoExternalUse.class) + @ExportedBean(defaultVisibility = 999) + public static class StubTask { + + private String name; + + public StubTask(@Nonnull Queue.Task base) { + this.name = base.getName(); + } + + @Exported + public String getName() { + return name; + } + } + + /** + * A Stub class for {@link Item} which exposes only the name of the Task to be displayed when the user + * has DISCOVERY permissions only. + */ + @Restricted(NoExternalUse.class) + @ExportedBean(defaultVisibility = 999) + public class StubItem { + + @Exported public StubTask task; + + public StubItem(StubTask task) { + this.task = task; + } + + } /** * An optional interface for actions on Queue.Item. diff --git a/test/src/test/java/hudson/model/QueueTest.java b/test/src/test/java/hudson/model/QueueTest.java index 93bcb5ba05..2af2d61507 100644 --- a/test/src/test/java/hudson/model/QueueTest.java +++ b/test/src/test/java/hudson/model/QueueTest.java @@ -23,9 +23,12 @@ */ package hudson.model; +import com.gargoylesoftware.htmlunit.html.DomElement; +import com.gargoylesoftware.htmlunit.html.DomNode; import com.gargoylesoftware.htmlunit.html.HtmlFileInput; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.xml.XmlPage; import hudson.Launcher; import hudson.matrix.AxisList; import hudson.matrix.LabelAxis; @@ -39,11 +42,16 @@ import hudson.model.Queue.BlockedItem; import hudson.model.Queue.Executable; import hudson.model.Queue.WaitingItem; import hudson.model.queue.AbstractQueueTask; +import hudson.model.queue.CauseOfBlockage; +import hudson.model.queue.QueueTaskDispatcher; import hudson.model.queue.QueueTaskFuture; import hudson.model.queue.ScheduleResult; import hudson.model.queue.SubTask; import hudson.security.ACL; +import hudson.security.AuthorizationMatrixProperty; import hudson.security.GlobalMatrixAuthorizationStrategy; +import hudson.security.Permission; +import hudson.security.ProjectMatrixAuthorizationStrategy; import hudson.security.SparseACL; import hudson.slaves.DumbSlave; import hudson.slaves.DummyCloudImpl; @@ -58,7 +66,10 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -84,7 +95,9 @@ import org.jvnet.hudson.test.Bug; import org.jvnet.hudson.test.HudsonTestCase; import org.jvnet.hudson.test.MockQueueItemAuthenticator; import org.jvnet.hudson.test.SequenceLock; +import org.jvnet.hudson.test.SleepBuilder; import org.jvnet.hudson.test.TestBuilder; +import org.jvnet.hudson.test.TestExtension; import org.mortbay.jetty.Server; import org.mortbay.jetty.bio.SocketConnector; import org.mortbay.jetty.servlet.ServletHandler; @@ -413,11 +426,11 @@ public class QueueTest extends HudsonTestCase { FreeStyleBuild b = v.waitForStart(); assertEquals(1,b.getNumber()); assertTrue(b.isBuilding()); - assertSame(p,b.getProject()); + assertSame(p, b.getProject()); ev.signal(); // let the build complete FreeStyleBuild b2 = assertBuildStatusSuccess(v); - assertSame(b,b2); + assertSame(b, b2); } @Inject @@ -579,4 +592,64 @@ public class QueueTest extends HudsonTestCase { } catch (CancellationException e) { } } + + public void testQueueApiOutputShouldBeFilteredByUserPermission() throws Exception { + + jenkins.setSecurityRealm(createDummySecurityRealm()); + ProjectMatrixAuthorizationStrategy str = new ProjectMatrixAuthorizationStrategy(); + str.add(Jenkins.READ, "bob"); + str.add(Jenkins.READ, "alice"); + str.add(Jenkins.READ, "james"); + jenkins.setAuthorizationStrategy(str); + + FreeStyleProject project = createFreeStyleProject("project"); + + Map> permissions = new HashMap>(); + permissions.put(Item.READ, Collections.singleton("bob")); + permissions.put(Item.DISCOVER, Collections.singleton("james")); + AuthorizationMatrixProperty prop1 = new AuthorizationMatrixProperty(permissions); + project.addProperty(prop1); + project.getBuildersList().add(new SleepBuilder(10)); + project.scheduleBuild2(0); + + WebClient webClient = new WebClient(); + webClient.login("bob", "bob"); + XmlPage p = webClient.goToXml("/queue/api/xml"); + + //bob has permission on the project and will be able to see it in the queue together with information such as the URL and the name. + for (DomNode element: p.getFirstChild().getFirstChild().getChildNodes()){ + if(element.getNodeName().equals("task")){ + assertEquals(((DomElement)element).getElementsByTagName("name").size(),1); + assertEquals(((DomElement) element).getElementsByTagName("name").item(0).getFirstChild().toString(), "project"); + assertEquals(((DomElement)element).getElementsByTagName("url").size(),1); + } + } + WebClient webClient2 = new WebClient(); + webClient2.login("alice"); + XmlPage p2 = webClient2.goToXml("/queue/api/xml"); + //alice does not have permission on the project and will not see it in the queue. + assertEquals("", p2.getContent()); + + WebClient webClient3 = new WebClient(); + webClient3.login("james"); + XmlPage p3 = webClient3.goToXml("/queue/api/xml"); + //james has DISCOVER permission on the project and will only be able to see the task name. + assertEquals("project", + p3.getContent()); + + } + + //we force the project not to be executed so that it stays in the queue + @TestExtension("testQueueApiOutputShouldBeFilteredByUserPermission") + public static class MyQueueTaskDispatcher extends QueueTaskDispatcher { + @Override + public CauseOfBlockage canTake(Node node, Queue.BuildableItem item) { + return new CauseOfBlockage() { + @Override + public String getShortDescription() { + return "blocked by canTake"; + } + }; + } + } } From e18cf4d9815558d79948278086e2dbf7f659b5ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20He=CC=81ritier?= Date: Tue, 13 Oct 2015 15:32:31 +0200 Subject: [PATCH 0653/2573] Nodes.updateNode(): Call Jenkins.getQueue().scheduleMaintenance() to be sure to update builds in the queue with the change done in the node (+ Add since 1.634) --- core/src/main/java/jenkins/model/Jenkins.java | 1 + core/src/main/java/jenkins/model/Nodes.java | 1 + 2 files changed, 2 insertions(+) diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 6c291f3144..ab03785899 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -1754,6 +1754,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve /** * Updates an existing {@link Node} on disk. * @see Nodes#updateNode + * @since 1.634 */ public boolean updateNode(Node n) throws IOException { return nodes.updateNode(n); diff --git a/core/src/main/java/jenkins/model/Nodes.java b/core/src/main/java/jenkins/model/Nodes.java index 5202c3b640..d6066bf224 100644 --- a/core/src/main/java/jenkins/model/Nodes.java +++ b/core/src/main/java/jenkins/model/Nodes.java @@ -176,6 +176,7 @@ public class Nodes implements Saveable { } }); persistNode(node); + jenkins.getQueue().scheduleMaintenance(); return true; } return false; From 30f1401266a0cad8b79dbce360f6d8642b58454c Mon Sep 17 00:00:00 2001 From: Carbenium Date: Wed, 14 Oct 2015 18:25:15 +0200 Subject: [PATCH 0654/2573] [FIXED JENKINS-30605] Improve de translation of config-publishers2 --- .../lib/hudson/project/config-publishers2_de.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/hudson/project/config-publishers2_de.properties b/core/src/main/resources/lib/hudson/project/config-publishers2_de.properties index e078564074..0fbb6ddfcd 100644 --- a/core/src/main/resources/lib/hudson/project/config-publishers2_de.properties +++ b/core/src/main/resources/lib/hudson/project/config-publishers2_de.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Add\ post-build\ action=Post-Build-Schritt hinzuf\u00FCgen +Add\ post-build\ action=Post-Build-Aktion hinzuf\u00FCgen Post-build\ Actions=Post-Build-Aktionen From 87a6999b350aaeed9b825f04bb5eeda36bb7e170 Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Wed, 14 Oct 2015 19:30:36 +0300 Subject: [PATCH 0655/2573] Revert "Don't run disabled/copied projects" This reverts commit df4bb2de2d22bfa8a0e1beed14615a40786e3942. --- core/src/main/java/hudson/triggers/Trigger.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/core/src/main/java/hudson/triggers/Trigger.java b/core/src/main/java/hudson/triggers/Trigger.java index dade0854c3..65350e48ca 100644 --- a/core/src/main/java/hudson/triggers/Trigger.java +++ b/core/src/main/java/hudson/triggers/Trigger.java @@ -247,10 +247,6 @@ 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()); @@ -266,12 +262,6 @@ 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 cd18d080fdc3a0302a46ccb3a502ec0587e19bec Mon Sep 17 00:00:00 2001 From: Kanstantsin Shautsou Date: Wed, 14 Oct 2015 19:30:52 +0300 Subject: [PATCH 0656/2573] Revert "Dont start onLoad and after submit for disabled" This reverts commit 3c471f1fd26fd893726e3f7216de38a2fd3f7c5d. --- .../java/hudson/model/AbstractProject.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java index f294a15d69..9fda67dba5 100644 --- a/core/src/main/java/hudson/model/AbstractProject.java +++ b/core/src/main/java/hudson/model/AbstractProject.java @@ -325,13 +325,11 @@ public abstract class AbstractProject

                            ,R extends A buildMixIn.onLoad(parent, name); builds = buildMixIn.getRunMap(); triggers().setOwner(this); - 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); - } + 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) @@ -1874,10 +1872,8 @@ public abstract class AbstractProject

                            ,R extends A for (Trigger t : triggers()) t.stop(); triggers.replaceBy(buildDescribable(req, Trigger.for_(this))); - if (isBuildable()) { - for (Trigger t : triggers()) - t.start(this, true); - } + for (Trigger t : triggers()) + t.start(this,true); } /** From f07f5ae673a6187ad0ad896b820cf44d7b8b0a97 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Wed, 14 Oct 2015 15:11:33 -0700 Subject: [PATCH 0657/2573] [maven-release-plugin] prepare release jenkins-1.625.1 --- 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 29896a6570..d5a6e2bf60 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.625.1-SNAPSHOT + 1.625.1 cli diff --git a/core/pom.xml b/core/pom.xml index 079099f59b..f85e53b766 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.625.1-SNAPSHOT + 1.625.1 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index 2acfb16364..4160018f70 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.625.1-SNAPSHOT + 1.625.1 pom + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Rodney Dawes + + + + + Jakub Steiner, Garrett LeSage + + + + + + + + + + + + + + + + + + + + + + + diff --git a/war/images/go-top.svg b/war/images/go-top.svg new file mode 100644 index 0000000000..bd3a6f2946 --- /dev/null +++ b/war/images/go-top.svg @@ -0,0 +1,523 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Rodney Dawes + + + + + Jakub Steiner, Garrett LeSage + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/war/images/go-up.svg b/war/images/go-up.svg new file mode 100644 index 0000000000..bb6dc8c268 --- /dev/null +++ b/war/images/go-up.svg @@ -0,0 +1,513 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Rodney Dawes + + + + + Jakub Steiner, Garrett LeSage + + + + + + + + + + + + + + + + + + + + + + + diff --git a/war/src/main/webapp/css/style.css b/war/src/main/webapp/css/style.css index c7a449913e..dd3d1489ac 100644 --- a/war/src/main/webapp/css/style.css +++ b/war/src/main/webapp/css/style.css @@ -1041,7 +1041,7 @@ table.parameters > tbody:hover { } #buildHistoryPageNav .pageOne { - background-image: url(../images/16x16/bullseye.png); + background-image: url(../images/16x16/go_top.png); } #buildHistoryPageNav .pageUp { background-image: url(../images/16x16/go_up.png); diff --git a/war/src/main/webapp/images/16x16/bullseye.png b/war/src/main/webapp/images/16x16/bullseye.png deleted file mode 100644 index 442ccf26ddb0e67eb5082451737d70658916d99d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2615 zcmV-73dr?|P)A3ClyUDVJgv#21$2g z!li5n&eP^DT=X=h1&N-iR&i8sAmQ*U0 z;y*xY_>a(EApbTR_NzPW>gqyWT^$-48pzY!+zc+43qGF@eSLlK`F!yCeCX=x{=0zm z_xGc)un@Oz-$rq9vC`j7ojMhcj*eKpdNnjOG=?+>)=;#TNF+i=Mh4Q;)6vw_^wX2j z*4D=Q_3Po_-~fGn{XYvNGcyyBk&)=>=^1o_JRT1^Iy&g=>_kgT3)Feu*Kp?=QM~{%7 zpN~(UKFPFMym&D}LqnmXqw{-!)Ya9&$Hxcn-@m8ICrp?C4-XGmTU)EVlBK1kh>eX! zSy>rXK6dO_golS?#*7)i7RbAI@8It4j;^jQ>gafSdSdO`wP3T^LlV~f{Cvd3#Gs*} z;U7&jY#5@VqF`lZ^=p81b#=kX$q99Jb)?M1#01gN(J(MDpxR2MQdCq_ps1(_A3l75 zP$)!4M+Z0@4!B${jEsz6VPSzebLL>!Fj{H0x3|OJ-ybhuz9eNF4hPq+T?3!bA36{p zA0Iq=^oa0QR#rHD`ZPw497&!1J9q9NDJcmpEiFG>K@Nw5ty{Ok$;k;LMvS2PIdkR= z($mu^HJzB4C|Bl`26FZ4Rh&J0mhjW2O~a*2mngme`t@rB2M43JwpQgMHG1@D1Ox=Y z#>R%)RbO9UYVqvt?GX?V@N+=kzI}@wJ9ePIzaIdgr>BS1)Ku_zJksXgy?Y1^4aL{5 zUuC}6)YOEjsVR(&jnUB1fXd2BO2(M9Z{I$+y1EixB9UO{&Yh^Lsv>2Pk&#%we7WjC zf`Wo@|Nec#$H&KG!GZ;ZPft%rSXh|Mg(%KQc{BR=g*_9 zt&OU4a&p3L}ZuaBIDD_5?l<}|jpwjwt-m+%%A78Ho$;$lQbMpEC* znKK7BZ{EbVZQEdMY%Bu;0QB|sv2NWuq@|@{#flX&$2c=HlkkRyhOoD{CwxUk1>U@Q zqZ*Kmj1008EEWp~4jdqL9UUF;_xC494gmJ<-HU{T1Q{)+h;(#x5D^i9kdP3{_JoCn z;lqaygm-guqm)WoTAK1e`uqDStzl_t2~$&3!Y3yuqobpP@XMAh!>(Pss2wOTFUP4< zr{L`Dj3rB!VDsk9IDY&%o;-O%jb&?Vi|yODQ(Ei7g$sn&)z!s@4I2pm@Zm$Wx3?Ozqhv+4<0;F4oG!%^*;^N)L?CGO<7>3h6)S} zq~eP3@Ngt0CE?q*Zwil9R#p~{963UqM|E{|oIH7w@(yxxawyqj`d!SUHz<(C#zx8* zF(+D7R7ANb%+)F?Dx!pSFnaas6}7WdrcA-qsZ$C6`0-f>FJ^B6ar!TQB1)eK72UU?(^r*$vPfbmYI@U}e@)8tsfiN3>ue0aRpHImJ^XU2c`Kh!k$BrGNc!5Ab-e=94 zMfJs;$M>34sU4}Ut)(;z(>V6__98Jcky>GIZ*QgIb{7{Hn46muK07-bA3uJig0}(s z^5qL&ym+Ddj!d6Eo#L4Rj)jESqh>MF0@pnv3O>yJK4azeRSv$K^F^k>hW!O_u? zia<3rH4zgN0}h8H*X?1m+1R*oqul=3Cr+F=A-96fhFB~{X=y15rnI!QFl*K=-Z!hxm^HEk-hW7S$^!E0G!{IM^@WB*K<0TZlWrX0s6&7l(QC=22Sh@ZrOhW|NmG z5s5?!bG}?I7tzttm^pJMDXXcefs2a^iCZ)@G?0>#f=QDmseaMJ<#G`g7DlXje}6yx z{QRgyouQ#2E?>S32L}g**~Zq^R)ru|u3U-K)Km&YXJ;q8yu7I3DeXU{FpIg5FH&&#Sa6ncS=eM3JVKmG9*kIHEI+VFJ261XJ;8z-_XziFE1}D4P<9$ zhoGRKp=TPUQYpN>y-`q5KslDd!NFLwW{phyZ{NP5qM`!T)zxTiZ6)%hr>6%40|U9~ zQUE9^DS@xAFBOxUnVBIeDd~q7K}sjFJ3Bk!>FG%YRs#aKfB$}rA3y%56WBtb5D5th z$jr>70xcsWBgDqWDs}mz(zQZgUmwn$J4YGE0VQB(X9oud2P)g5%r!+;Ru-;bzmD$i zZmMp@iWLYB4purm_^BJK+}vD*goIG)lj#QyT=ejGJn(ot=<4c1EEc1sr3FHv5as3N z$j{HGXM%Yem1`UzX18u^!KNlzd(Ky Z{SS?I=b8y5K~w+$002ovPDHLkV1iQq7X7cm6or{twpD!3$;rxx?wsFMZi`r_&0 z7-G?zoFI{Lpu^WdRds2EhsOz)$Tx3qZ(siG+}zv!>!z{JW>ivA+9e|+BdB3!XjFG} z*|g4z<4Np?4=_B5c+lI|=O+dP&!0apPfbfRa|`?N{QP|5_`;-L>9z?mhxp9`vj);ix`SJ7T(|NYlVqBNc8~}ozH7`z0)$UhS zRqf~I=B_q2GWw)&`tSe$|F3?1ecd^HZB!{oq|8wU6=y$3-iK{jb%k$lZJls+b-27+ zcz+_pl?m>XCQUlt(%QOLQbJ;%R_y*dTb|izO$sV1M-(+QPV}YpmasAi8wV)YsV?~q P3;_mDS3j3^P6T<;; zmv5#$|NngU-BhuEu^urOW++(+2PF3XS-+~rpi7Cn)A+OY_Qay%9rj(fJRSDkJFN0u zcKc+89S_R_(;2iH6e=c~ce%~mmoO!N1IwCO2a5W94_uwjAjrJo&F6G(yLe}XXn~tj z7U?`f3>mj9b!96h&s2LKdmVGT^dqxkYQ?_0E39@@94lJgcbDUIa&vIv`v*IMIi_B^ zeOL7Rvll^X3SQgqo%U<`chhsPySdd%4u(hKv$xhUT={i$S>;?!27`55PCMJ|`Ly9u zn#^|L{h}te7B}yx_|x2>u z=YlX}jY;-GprB-lYeY$Kep*R+Vo@qXd3m{BW?pu2a$-TMUVc&f>~}U&Kt;kJMUJH< z8TmyFLHQ|psg(*YiRG!qd^hT3fzn?*T^vI!dhbr!=yk+F#P$4b&m_U^0$-Tld}0<; z%w*kvph3Y*Y~^R}X-=<9nv%9oC_8Ah_wTirTQ?XmN~WwSJ9+M0Uf7$Os|A+ddGaNG zJU;O$AoOZ$N6h|b}>XS_&Wz=*D^f#{crlyh@3SE z{jyU^9^d+YR-$;4%1K*;*tT=-I;TGw@*JL>c&+rVbD+p}GwY4b_s`i2RICfg tUfam8{kv@A?R}pVAKZ?6aG9;1!MZ<8ZxPQGZ=nAfJYD@<);T3K0RUEnr5gYM literal 0 HcmV?d00001 diff --git a/war/src/main/webapp/images/16x16/go_up.png b/war/src/main/webapp/images/16x16/go_up.png index 242309a6316b056a99302eebefb0540d064d3329..9dc1c738ee4ef29c112bb77f223d2911bea0cd3f 100644 GIT binary patch delta 362 zcmbQq(#Gu88Q|y6%O%Cdz`(%k>ERLtqy<2jgAGW^fBv5cq*#ibJVQ8upoSx*1IXtr z@Q5r13eN>$#u}6Cg_B<}YSastxJHyXmX>7X7cm6or{twpD!3$;rxx?wsFMZidgAHg z7-G?zoFI{LpvT`xMdgU2v$ONNUteGI7p_b^s46HZn7DM^x_xsdPMkP%?p)iFpP!zx zca}N2xU{U@wd?<{(%=*PTZ)^#HzBd-P0XHJ|rp{t|wrZta4c#>3HT3XuX@9*#H|M>m= zePjvqzdt{VpFKX_&uw90kpncW;vriycXL-)7pshn%*PW+_xIP&zkT!O%%*kIIAa?^ z40w1B%o4i4r?NQG!y|)r(~aBP^VdrSWl82TFq~_1=)Wk<4hm2PPgg&ebxsLQ09c}k A;{X5v literal 537 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1rX+877lwZyI{s(^d7K3vkw8)2 zYaq-xA-{4CNU*HHF&#*Q^)giWEM3OHz^Lfy;uvCa`s!pu|3d)+$LrHMx3IB44q`Wd z%#o-j;I@y0vorQDi%QFpt0&(de8--!xU+L{cVUKA!Yw=HdEA%6qeRX3Zom8g-QD;1 z?l%8V($c!x71CbJ9oBj8`Khue*DE@kS?v#mA zZwp^dp0up4+UIdQOX;$`PbWw;E5`9H-y6He$y3yC@9Z}dz8-tH!&B-*%Kos8O}C{| zeTB|EQ;FPcdgw2c=Uh+wH$u6GdD}GJ`28}QcEjTMb^Y~g?(6K_b}aMSQH(J!i(a})sl6BM_4e6JcdG1G8I@Zq? zc>Q^svFfd<-lweNhoV92SKxJHzuB$lLFB^RXvDF!10Ljzp{ z3tdBl5JOWd14Aog6Kw+{D+2@X&}dLRAT;FWr(~v8;?`ir@pvjwgCxj?;QX|b^2DN4 lhVt@qz0ADq;^f4FRK5J7^x5xhq=1STJYD@<);T3K0RW-7&}IMt From 67e2637a57be9b6817621dbfcdec2b2dc27afdb9 Mon Sep 17 00:00:00 2001 From: Valentina Armenise Date: Thu, 15 Oct 2015 18:24:23 +0200 Subject: [PATCH 0663/2573] [JENKINS-30456]Executable can be null in getEstimatedDurationFor --- .../main/java/hudson/model/queue/Executables.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/hudson/model/queue/Executables.java b/core/src/main/java/hudson/model/queue/Executables.java index a8a524bc8e..39bd48ea36 100644 --- a/core/src/main/java/hudson/model/queue/Executables.java +++ b/core/src/main/java/hudson/model/queue/Executables.java @@ -27,6 +27,7 @@ import hudson.model.Queue.Executable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import javax.annotation.CheckForNull; import javax.annotation.Nonnull; /** @@ -61,14 +62,19 @@ public class Executables { /** * Returns the estimated duration for the executable. + * If the Executable is null the Estimated Duration can't be evaluated, then -1 is returned. + * This can happen if Computer.getIdleStartMilliseconds() is called before the executable is set to non-null in Computer.run() + * or if the executor thread exits prematurely, see JENKINS-30456 * Protects against {@link AbstractMethodError}s if the {@link Executable} implementation * was compiled against Hudson < 1.383 + * + * @return the estimated duration for a given executable, -1 if the executable is null */ - public static long getEstimatedDurationFor(Executable e) { + public static long getEstimatedDurationFor(@CheckForNull Executable e) { try { - return e.getEstimatedDuration(); + return (e != null) ? e.getEstimatedDuration() : -1; } catch (AbstractMethodError error) { - return e.getParent().getEstimatedDuration(); + return (e != null) ? e.getParent().getEstimatedDuration() : -1; } } From 21f36fb22196d1352c2abe89cb692d92b457d029 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Fri, 16 Oct 2015 15:39:47 +0200 Subject: [PATCH 0664/2573] Noting #1872 --- changelog.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.html b/changelog.html index 50e941c6a0..b402997651 100644 --- a/changelog.html +++ b/changelog.html @@ -55,7 +55,9 @@ Upcoming changes

                            What's new in 1.633 (2015/10/11)

                            From 4c6dd0135ad9e4f108b2bf7527d34dabddd16fb7 Mon Sep 17 00:00:00 2001 From: James Nord Date: Tue, 13 Oct 2015 16:27:55 +0200 Subject: [PATCH 0665/2573] [JENKINS-30820] pick up the new bytecode-compat-t. The new version of the BCT does not generate stackMap if the original code did not contain stack maps. Further more the new version takes a classloader to use so that it can load classes when searching for the common parent class. --- core/pom.xml | 2 +- core/src/main/java/hudson/ClassicPluginStrategy.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/pom.xml b/core/pom.xml index 91e4294b8a..dadd3bd6a5 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -200,7 +200,7 @@ THE SOFTWARE. org.jenkins-ci bytecode-compatibility-transformer - 1.6.2 + 1.7 org.jenkins-ci diff --git a/core/src/main/java/hudson/ClassicPluginStrategy.java b/core/src/main/java/hudson/ClassicPluginStrategy.java index 040e4cf98d..b90e6fcfda 100644 --- a/core/src/main/java/hudson/ClassicPluginStrategy.java +++ b/core/src/main/java/hudson/ClassicPluginStrategy.java @@ -797,7 +797,7 @@ public class ClassicPluginStrategy implements PluginStrategy { @Override protected Class defineClassFromData(File container, byte[] classData, String classname) throws IOException { if (!DISABLE_TRANSFORMER) - classData = pluginManager.getCompatibilityTransformer().transform(classname, classData); + classData = pluginManager.getCompatibilityTransformer().transform(classname, classData, this); return super.defineClassFromData(container, classData, classname); } } From 0a36f743f1fd2264f8562e6fbea54712567be556 Mon Sep 17 00:00:00 2001 From: James Nord Date: Fri, 16 Oct 2015 21:14:38 +0200 Subject: [PATCH 0666/2573] Noting JENKINS-30820 --- changelog.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.html b/changelog.html index b402997651..3952fd7f7b 100644 --- a/changelog.html +++ b/changelog.html @@ -58,6 +58,9 @@ Upcoming changes
                          • Fix order of builds in new builds history widget introduced in 1.633. (issue 30899) +
                          • + bytecode compatability transforer would fail to transform some classes with ClassNotFoundException. + (issue 30820)

                          What's new in 1.633 (2015/10/11)

                          From 725b6afeac4ac5b8821c095f3b093cd0daa3a526 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 17 Oct 2015 20:53:22 +0300 Subject: [PATCH 0667/2573] [FIXED JENKINS-30730] Prevent ClassCastException in Abstractbuild::reportError() if the build step is not Publisher. This pull request integrates https://github.com/jenkinsci/jenkins/pulls/1851, which is a reworked version of https://github.com/jenkinsci/jenkins/pull/1846 from @fbelzunc (no original codelines left) --- .../main/java/hudson/model/AbstractBuild.java | 14 +++- .../java/hudson/model/AbstractBuildTest2.java | 82 +++++++++++++++++++ 2 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 test/src/test/java/hudson/model/AbstractBuildTest2.java diff --git a/core/src/main/java/hudson/model/AbstractBuild.java b/core/src/main/java/hudson/model/AbstractBuild.java index aa1f9626e6..c017c716e7 100644 --- a/core/src/main/java/hudson/model/AbstractBuild.java +++ b/core/src/main/java/hudson/model/AbstractBuild.java @@ -742,13 +742,19 @@ public abstract class AbstractBuild

                          ,R extends Abs } private void reportError(BuildStep bs, Throwable e, BuildListener listener, boolean phase) { - final String publisher = ((Publisher) bs).getDescriptor().getDisplayName(); + final String buildStep; + + if (bs instanceof Describable) { + buildStep = ((Describable) bs).getDescriptor().getDisplayName(); + } else { + buildStep = bs.getClass().getName(); + } if (e instanceof AbortException) { - LOGGER.log(Level.FINE, "{0} : {1} failed", new Object[] {AbstractBuild.this, publisher}); - listener.error("Publisher '" + publisher + "' failed: " + e.getMessage()); + LOGGER.log(Level.FINE, "{0} : {1} failed", new Object[] {AbstractBuild.this, buildStep}); + listener.error("Step ‘" + buildStep + "’ failed: " + e.getMessage()); } else { - String msg = "Publisher '" + publisher + "' aborted due to exception: "; + String msg = "Step ‘" + buildStep + "’ aborted due to exception: "; e.printStackTrace(listener.error(msg)); LOGGER.log(WARNING, msg, e); } diff --git a/test/src/test/java/hudson/model/AbstractBuildTest2.java b/test/src/test/java/hudson/model/AbstractBuildTest2.java new file mode 100644 index 0000000000..830d491758 --- /dev/null +++ b/test/src/test/java/hudson/model/AbstractBuildTest2.java @@ -0,0 +1,82 @@ +/* + * 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.model; + +import hudson.Launcher; +import hudson.model.queue.QueueTaskFuture; +import java.io.IOException; +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.TestExtension; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; + +/** + * Unit tests of {@link AbstractBuild}. + * @author Oleg Nenashev + */ +public class AbstractBuildTest2 { + + @Rule + public JenkinsRule rule = new JenkinsRule(); + + @Test + @Issue("JENKINS-30730") + @SuppressWarnings("deprecation") + public void reportErrorShouldNotFailForNonPublisherClass() throws Exception { + FreeStyleProject prj = rule.createFreeStyleProject(); + ErrorneousJobProperty errorneousJobProperty = new ErrorneousJobProperty(); + prj.addProperty(errorneousJobProperty); + QueueTaskFuture future = prj.scheduleBuild2(0); + assertThat("Build should be actually scheduled by Jenkins", future, notNullValue()); + FreeStyleBuild build = future.get(); + rule.assertLogContains(ErrorneousJobProperty.ERROR_MESSAGE, build); + rule.assertLogNotContains(ClassCastException.class.getName(), build); + } + + /** + * Job property, which always fails with an exception. + */ + public static class ErrorneousJobProperty extends JobProperty { + + public static final String ERROR_MESSAGE = "This publisher fails by design"; + + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + throw new IOException(ERROR_MESSAGE); + } + + @TestExtension("reportErrorShouldNotFailForNonPublisherClass") + public static class DescriptorImpl extends JobPropertyDescriptor { + + @Override + public String getDisplayName() { + return "Always throws exception in perform()"; + } + } + } +} From 6a65371e5beb74d113557eaed5c51c33b8130984 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 17 Oct 2015 20:59:02 +0300 Subject: [PATCH 0668/2573] Noting JENKINS-30730 from #1851 --- changelog.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.html b/changelog.html index 3952fd7f7b..58a877571c 100644 --- a/changelog.html +++ b/changelog.html @@ -61,6 +61,9 @@ Upcoming changes

                        • bytecode compatability transforer would fail to transform some classes with ClassNotFoundException. (issue 30820) +
                        • + Prevent ClassCastException in AbstractBuild::reportError() if the build step is not Publisher. + (issue 30730)

                        What's new in 1.633 (2015/10/11)

                        From a0eb564cf930ef6c5891e69fd2f059df0b32fd2a Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Sat, 17 Oct 2015 20:11:17 +0200 Subject: [PATCH 0669/2573] Typos --- changelog.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.html b/changelog.html index 58a877571c..ce771f23f1 100644 --- a/changelog.html +++ b/changelog.html @@ -59,7 +59,7 @@ Upcoming changes Fix order of builds in new builds history widget introduced in 1.633. (issue 30899)
                      • - bytecode compatability transforer would fail to transform some classes with ClassNotFoundException. + Bytecode Compatibility Transformer would fail to transform some classes resulting in ClassNotFoundException. (issue 30820)
                      • Prevent ClassCastException in AbstractBuild::reportError() if the build step is not Publisher. From 3bc0f447efd5b5abca466881949106f19c8b9ebf Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 17 Oct 2015 22:04:00 +0300 Subject: [PATCH 0670/2573] Noting JENKINS-30502 from #1855 --- changelog.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.html b/changelog.html index ce771f23f1..e53835d25e 100644 --- a/changelog.html +++ b/changelog.html @@ -64,6 +64,9 @@ Upcoming changes
                      • Prevent ClassCastException in AbstractBuild::reportError() if the build step is not Publisher. (issue 30730) +
                      • + Trim job names during the rename operation (it is impossible to delete or rename jobs with trailing spaces). + (issue 30502)

                      What's new in 1.633 (2015/10/11)

                      From c68c19aa9317f7ad52bea250d65f050a3d055779 Mon Sep 17 00:00:00 2001 From: Mads Rolsdorph Date: Sat, 17 Oct 2015 22:06:42 +0300 Subject: [PATCH 0671/2573] [PR-1769] - Add background color options to plot URLs. This pull request integrates https://github.com/jenkinsci/jenkins/pull/1769 --- core/src/main/java/hudson/util/Graph.java | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/core/src/main/java/hudson/util/Graph.java b/core/src/main/java/hudson/util/Graph.java index 8009286eac..bef25b2d9e 100644 --- a/core/src/main/java/hudson/util/Graph.java +++ b/core/src/main/java/hudson/util/Graph.java @@ -26,6 +26,7 @@ package hudson.util; import org.jfree.chart.JFreeChart; import org.jfree.chart.ChartRenderingInfo; import org.jfree.chart.ChartUtilities; +import org.jfree.chart.plot.Plot; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; @@ -35,6 +36,8 @@ import java.io.IOException; import java.util.Calendar; import java.awt.image.BufferedImage; import java.awt.*; +import javax.annotation.Nonnull; +import javax.annotation.CheckForNull; /** * A JFreeChart-generated graph that's bound to UI. @@ -84,10 +87,29 @@ public abstract class Graph { String h = req.getParameter("height"); if(h==null) h=String.valueOf(defaultH); + Color graphBg = stringToColor(req.getParameter("graphBg")); + Color plotBg = stringToColor(req.getParameter("plotBg")); + if (graph==null) graph = createGraph(); + graph.setBackgroundPaint(graphBg); + Plot p = graph.getPlot(); + p.setBackgroundPaint(plotBg); + return graph.createBufferedImage(Integer.parseInt(w),Integer.parseInt(h),info); } + @Nonnull private static Color stringToColor(@CheckForNull String s) { + if (s != null) { + try { + return Color.decode("0x" + s); + } catch (NumberFormatException e) { + return Color.WHITE; + } + } else { + return Color.WHITE; + } + } + /** * Renders a graph. */ From 0c1b508cc4e8c534e9ddc72ce2ec84262ef258db Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 17 Oct 2015 22:09:12 +0300 Subject: [PATCH 0672/2573] Noting https://github.com/jenkinsci/jenkins/pull/1769 --- changelog.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.html b/changelog.html index e53835d25e..8f5335310a 100644 --- a/changelog.html +++ b/changelog.html @@ -67,6 +67,9 @@ Upcoming changes
                    • Trim job names during the rename operation (it is impossible to delete or rename jobs with trailing spaces). (issue 30502) +
                    • + Add "graphBg" and "plothBg" background color options to plot URLs + (PR 1769)

                    What's new in 1.633 (2015/10/11)

                    From efa1487e85241f7ca604b305bd1f436404cd75c2 Mon Sep 17 00:00:00 2001 From: Lucie Votypkova Date: Sat, 17 Oct 2015 22:11:46 +0300 Subject: [PATCH 0673/2573] [PR-1712] - Add get method for causes of interruption. This pull request integrates https://github.com/jenkinsci/jenkins/pull/1712 --- core/src/main/java/hudson/model/Executor.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/src/main/java/hudson/model/Executor.java b/core/src/main/java/hudson/model/Executor.java index 5f021cfe80..9310ca6df2 100644 --- a/core/src/main/java/hudson/model/Executor.java +++ b/core/src/main/java/hudson/model/Executor.java @@ -54,6 +54,7 @@ import java.io.StringWriter; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Vector; import java.util.concurrent.locks.ReadWriteLock; @@ -62,6 +63,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import static hudson.model.queue.Executables.*; +import java.util.Collection; import static java.util.logging.Level.*; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; @@ -506,6 +508,16 @@ public class Executor extends Thread implements ModelObject { lock.readLock().unlock(); } } + + /** + * Returns causes of interruption. + * + * @return Unmodifiable collection of causes of interruption. + * @since 1.617 + */ + public @Nonnull Collection getCausesOfInterruption() { + return Collections.unmodifiableCollection(causes); + } /** * Returns the current {@link WorkUnit} (of {@link #getCurrentExecutable() the current executable}) From c3a68975584da677b3ed3ed7bbf9bf357052e457 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 17 Oct 2015 22:13:16 +0300 Subject: [PATCH 0674/2573] Noting #1712 --- changelog.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.html b/changelog.html index 8f5335310a..e53d96d08c 100644 --- a/changelog.html +++ b/changelog.html @@ -70,6 +70,9 @@ Upcoming changes
                  • Add "graphBg" and "plothBg" background color options to plot URLs (PR 1769) +
                  • + API changes: Add get method for causes of interruption in hudson.model.Executor + (PR 1712)

                  What's new in 1.633 (2015/10/11)

                  From 858849ef42ab2e1da66e1017ca1b6c86fa92c080 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 17 Oct 2015 22:26:12 +0300 Subject: [PATCH 0675/2573] Noting JENKINS-5253 from https://github.com/jenkinsci/jenkins/pull/1429 --- changelog.html | 3 +++ core/src/test/java/hudson/FilePathTest.java | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/changelog.html b/changelog.html index e53d96d08c..fdba8014cb 100644 --- a/changelog.html +++ b/changelog.html @@ -73,6 +73,9 @@ Upcoming changes
                • API changes: Add get method for causes of interruption in hudson.model.Executor (PR 1712) +
                • + Allow case insensitive file patterns in Artifacts Archiving. + (issue 5253)

                What's new in 1.633 (2015/10/11)

                diff --git a/core/src/test/java/hudson/FilePathTest.java b/core/src/test/java/hudson/FilePathTest.java index e7491ca274..69ead86bb8 100644 --- a/core/src/test/java/hudson/FilePathTest.java +++ b/core/src/test/java/hudson/FilePathTest.java @@ -541,7 +541,7 @@ public class FilePathTest { } } - @Issue("5253") + @Issue("JENKINS-5253") public void testValidateCaseSensitivity() throws Exception { File tmp = Util.createTempDir(); try { From bc254648870c1d7602b8218909b11c47d1cadb49 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 17 Oct 2015 22:43:12 +0300 Subject: [PATCH 0676/2573] Noting JENKINS-30456 from https://github.com/jenkinsci/jenkins/pull/1873 --- changelog.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.html b/changelog.html index fdba8014cb..a19dd20c11 100644 --- a/changelog.html +++ b/changelog.html @@ -76,6 +76,9 @@ Upcoming changes
              • Allow case insensitive file patterns in Artifacts Archiving. (issue 5253) +
              • + Prevent NullPointerException while estimating duration of Queue executable items. + (issue 30456)

              What's new in 1.633 (2015/10/11)

              From 37f641733fd0186f30607f19100a6c19e0a6210f Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 17 Oct 2015 22:53:17 +0300 Subject: [PATCH 0677/2573] Noting JENKINS-28192 from https://github.com/jenkinsci/jenkins/pull/1731 --- changelog.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.html b/changelog.html index a19dd20c11..fe9dd197e7 100644 --- a/changelog.html +++ b/changelog.html @@ -79,6 +79,9 @@ Upcoming changes
            • Prevent NullPointerException while estimating duration of Queue executable items. (issue 30456) +
            • + Fix the resolution of Windows symbolic links in SecretRewriter. + (issue 30456)

            What's new in 1.633 (2015/10/11)

            From deecdb38d08e7e5f16fd9fd8ba161f020d26f047 Mon Sep 17 00:00:00 2001 From: ikedam Date: Sat, 17 Oct 2015 23:08:33 +0300 Subject: [PATCH 0678/2573] [JENKINS-26278] Let a combobox display its drop-down when focused. This pull request integrates https://github.com/jenkinsci/jenkins/pull/1510 --- war/src/main/webapp/scripts/combobox.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/war/src/main/webapp/scripts/combobox.js b/war/src/main/webapp/scripts/combobox.js index 8608a0d516..9dc2c21fe9 100644 --- a/war/src/main/webapp/scripts/combobox.js +++ b/war/src/main/webapp/scripts/combobox.js @@ -118,6 +118,8 @@ function ComboBox(idOrField, callback, config) { if (this.oldonsubmit) this.oldonsubmit(); return true; }; + // repopulate and display the dropdown + this.comboBox.valueChanged(); } this.field.onblur = function() { var cb = this.comboBox; From 3b5a68b04f6107186e5c10a7052c9addf17e54d3 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 17 Oct 2015 23:12:10 +0300 Subject: [PATCH 0679/2573] Noting JENKINS-26278 from https://github.com/jenkinsci/jenkins/pull/1510 --- changelog.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.html b/changelog.html index fe9dd197e7..163ad279df 100644 --- a/changelog.html +++ b/changelog.html @@ -82,6 +82,9 @@ Upcoming changes
          • Fix the resolution of Windows symbolic links in SecretRewriter. (issue 30456) +
          • + Let a combobox display its drop-down when focused, so users can see candidates without entering a letter. + (issue 26278)

          What's new in 1.633 (2015/10/11)

          From 32ef5900c2a08af7d8b06478d3bfe0e36f03736b Mon Sep 17 00:00:00 2001 From: Christopher Simons Date: Sat, 17 Oct 2015 21:06:11 -0400 Subject: [PATCH 0680/2573] add '*.swp' (Vim recovery files) to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 103caf1535..60ba89065c 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ build # vim *~ +*.swp # ctags tags From 1024299a0f8b7289b1e1f7a6009a0a376bad69a3 Mon Sep 17 00:00:00 2001 From: Marco Wulf Date: Wed, 7 Oct 2015 15:12:51 +0200 Subject: [PATCH 0681/2573] Add de translations for TimerTrigger --- core/src/main/resources/hudson/triggers/Messages_de.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/main/resources/hudson/triggers/Messages_de.properties b/core/src/main/resources/hudson/triggers/Messages_de.properties index 2e0701017c..21ba55b1f0 100644 --- a/core/src/main/resources/hudson/triggers/Messages_de.properties +++ b/core/src/main/resources/hudson/triggers/Messages_de.properties @@ -25,5 +25,8 @@ SCMTrigger.getDisplayName={0} Abfrage-Protokoll SCMTrigger.BuildAction.DisplayName=Abfrage-Protokoll SCMTrigger.SCMTriggerCause.ShortDescription=Build wurde durch eine SCM-Änderung ausgelöst. TimerTrigger.DisplayName=Builds zeitgesteuert starten +TimerTrigger.MissingWhitespace=Es scheinen Leerzeichen zwischen * und * zu fehlen. +TimerTrigger.no_schedules_so_will_never_run=Keine zeitgesteuerten Builds, somit wird Job nie laufen TimerTrigger.TimerTriggerCause.ShortDescription=Build wurde zeitgesteuert ausgelöst. +TimerTrigger.would_last_have_run_at_would_next_run_at=Letzter Lauf am {0}; Nächster Lauf am {1}. Trigger.init=Initialsiere Timer für Build-Auslöser \ No newline at end of file From 14781ecc72a7344cf37ed260c76d391be2bab294 Mon Sep 17 00:00:00 2001 From: marco Date: Sun, 18 Oct 2015 20:05:43 +0200 Subject: [PATCH 0682/2573] Fix translation TimerTrigger.no_schedules_so_will_never_run --- core/src/main/resources/hudson/triggers/Messages_de.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/hudson/triggers/Messages_de.properties b/core/src/main/resources/hudson/triggers/Messages_de.properties index 21ba55b1f0..980049540a 100644 --- a/core/src/main/resources/hudson/triggers/Messages_de.properties +++ b/core/src/main/resources/hudson/triggers/Messages_de.properties @@ -26,7 +26,7 @@ SCMTrigger.BuildAction.DisplayName=Abfrage-Protokoll SCMTrigger.SCMTriggerCause.ShortDescription=Build wurde durch eine SCM-Änderung ausgelöst. TimerTrigger.DisplayName=Builds zeitgesteuert starten TimerTrigger.MissingWhitespace=Es scheinen Leerzeichen zwischen * und * zu fehlen. -TimerTrigger.no_schedules_so_will_never_run=Keine zeitgesteuerten Builds, somit wird Job nie laufen +TimerTrigger.no_schedules_so_will_never_run=Kein Zeitplan vorhanden, somit wird der Job nie ausgef\u00fchrt werden. TimerTrigger.TimerTriggerCause.ShortDescription=Build wurde zeitgesteuert ausgelöst. TimerTrigger.would_last_have_run_at_would_next_run_at=Letzter Lauf am {0}; Nächster Lauf am {1}. Trigger.init=Initialsiere Timer für Build-Auslöser \ No newline at end of file From 647d85ff7a938874fc94db3e26801fe4f1d1ac37 Mon Sep 17 00:00:00 2001 From: Kohsuke Kawaguchi Date: Sun, 18 Oct 2015 20:18:28 -0700 Subject: [PATCH 0683/2573] [maven-release-plugin] prepare release jenkins-1.634 --- 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 4910aa4deb..274838e0bd 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.634-SNAPSHOT + 1.634 cli diff --git a/core/pom.xml b/core/pom.xml index dadd3bd6a5..97f068b356 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.634-SNAPSHOT + 1.634 jenkins-core diff --git a/plugins/pom.xml b/plugins/pom.xml index be4329f160..51d6dbc88e 100644 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -12,7 +12,7 @@ org.jenkins-ci.plugins plugin Jenkins plugin POM - 1.634-SNAPSHOT + 1.634 pom +

          What's new in 1.634 (2015/10/18)

          • Fix order of builds in new builds history widget introduced in 1.633. @@ -86,7 +91,6 @@ Upcoming changes Let a combobox display its drop-down when focused, so users can see candidates without entering a letter. (issue 26278)
          -

          What's new in 1.633 (2015/10/11)

          • From 3af6c6b815e7599e6f1bc59555ee6db9fdb36392 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 17 Oct 2015 20:53:22 +0300 Subject: [PATCH 0686/2573] [FIXED JENKINS-30730] Prevent ClassCastException in Abstractbuild::reportError() if the build step is not Publisher. This pull request integrates https://github.com/jenkinsci/jenkins/pulls/1851, which is a reworked version of https://github.com/jenkinsci/jenkins/pull/1846 from @fbelzunc (no original codelines left) (cherry picked from commit 725b6afeac4ac5b8821c095f3b093cd0daa3a526) --- .../main/java/hudson/model/AbstractBuild.java | 14 +++- .../java/hudson/model/AbstractBuildTest2.java | 82 +++++++++++++++++++ 2 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 test/src/test/java/hudson/model/AbstractBuildTest2.java diff --git a/core/src/main/java/hudson/model/AbstractBuild.java b/core/src/main/java/hudson/model/AbstractBuild.java index aa1f9626e6..c017c716e7 100644 --- a/core/src/main/java/hudson/model/AbstractBuild.java +++ b/core/src/main/java/hudson/model/AbstractBuild.java @@ -742,13 +742,19 @@ public abstract class AbstractBuild

            ,R extends Abs } private void reportError(BuildStep bs, Throwable e, BuildListener listener, boolean phase) { - final String publisher = ((Publisher) bs).getDescriptor().getDisplayName(); + final String buildStep; + + if (bs instanceof Describable) { + buildStep = ((Describable) bs).getDescriptor().getDisplayName(); + } else { + buildStep = bs.getClass().getName(); + } if (e instanceof AbortException) { - LOGGER.log(Level.FINE, "{0} : {1} failed", new Object[] {AbstractBuild.this, publisher}); - listener.error("Publisher '" + publisher + "' failed: " + e.getMessage()); + LOGGER.log(Level.FINE, "{0} : {1} failed", new Object[] {AbstractBuild.this, buildStep}); + listener.error("Step ‘" + buildStep + "’ failed: " + e.getMessage()); } else { - String msg = "Publisher '" + publisher + "' aborted due to exception: "; + String msg = "Step ‘" + buildStep + "’ aborted due to exception: "; e.printStackTrace(listener.error(msg)); LOGGER.log(WARNING, msg, e); } diff --git a/test/src/test/java/hudson/model/AbstractBuildTest2.java b/test/src/test/java/hudson/model/AbstractBuildTest2.java new file mode 100644 index 0000000000..830d491758 --- /dev/null +++ b/test/src/test/java/hudson/model/AbstractBuildTest2.java @@ -0,0 +1,82 @@ +/* + * 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.model; + +import hudson.Launcher; +import hudson.model.queue.QueueTaskFuture; +import java.io.IOException; +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.TestExtension; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; + +/** + * Unit tests of {@link AbstractBuild}. + * @author Oleg Nenashev + */ +public class AbstractBuildTest2 { + + @Rule + public JenkinsRule rule = new JenkinsRule(); + + @Test + @Issue("JENKINS-30730") + @SuppressWarnings("deprecation") + public void reportErrorShouldNotFailForNonPublisherClass() throws Exception { + FreeStyleProject prj = rule.createFreeStyleProject(); + ErrorneousJobProperty errorneousJobProperty = new ErrorneousJobProperty(); + prj.addProperty(errorneousJobProperty); + QueueTaskFuture future = prj.scheduleBuild2(0); + assertThat("Build should be actually scheduled by Jenkins", future, notNullValue()); + FreeStyleBuild build = future.get(); + rule.assertLogContains(ErrorneousJobProperty.ERROR_MESSAGE, build); + rule.assertLogNotContains(ClassCastException.class.getName(), build); + } + + /** + * Job property, which always fails with an exception. + */ + public static class ErrorneousJobProperty extends JobProperty { + + public static final String ERROR_MESSAGE = "This publisher fails by design"; + + @Override + public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { + throw new IOException(ERROR_MESSAGE); + } + + @TestExtension("reportErrorShouldNotFailForNonPublisherClass") + public static class DescriptorImpl extends JobPropertyDescriptor { + + @Override + public String getDisplayName() { + return "Always throws exception in perform()"; + } + } + } +} From acd341d5db724bc49fdbc52220f9e938813f5663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mu=C3=B1iz?= Date: Mon, 5 Oct 2015 21:16:33 +0200 Subject: [PATCH 0687/2573] [JENKINS-21720] JS alert preventig to leave a configuration page even without formulary changes (cherry picked from commit f63407a87e9dc1c1f79c9a7d885cdd58a55ed657) --- core/src/main/resources/lib/form/confirm.js | 4 ---- .../main/resources/lib/form/select/select.js | 17 ++++++++++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/core/src/main/resources/lib/form/confirm.js b/core/src/main/resources/lib/form/confirm.js index d5948c3aa2..64f40eb267 100644 --- a/core/src/main/resources/lib/form/confirm.js +++ b/core/src/main/resources/lib/form/confirm.js @@ -33,9 +33,6 @@ } function initConfirm() { - // Timeout is needed since some events get sent on page load for some reason. - // Shouldn't hurt anything for this to only start monitoring events after a few millis;. - setTimeout(function() { var configForm = document.getElementsByName("config"); if (configForm.length > 0) { configForm = configForm[0] @@ -78,7 +75,6 @@ for ( var i = 0; i < inputs.length; i++) { $(inputs[i]).on('input', confirm); } - }, 100); } window.onbeforeunload = confirmExit; diff --git a/core/src/main/resources/lib/form/select/select.js b/core/src/main/resources/lib/form/select/select.js index 6ea7a1e4c6..0b7ce9b2c6 100644 --- a/core/src/main/resources/lib/form/select/select.js +++ b/core/src/main/resources/lib/form/select/select.js @@ -41,6 +41,19 @@ function updateListBox(listBox,url,config) { } Behaviour.specify("SELECT.select", 'select', 1000, function(e) { + + function hasChanged(selectEl, originalValue) { + var firstValue = selectEl.options[0].value; + var selectedValue = selectEl.value; + if (originalValue == "" && selectedValue == firstValue) { + // There was no value pre-selected but after the call to updateListBox the first value is selected by + // default. This must not be considered a change. + return false; + } else { + return originalValue != selectedValue; + } + }; + // controls that this SELECT box depends on refillOnChange(e,function(params) { var value = e.value; @@ -60,7 +73,9 @@ Behaviour.specify("SELECT.select", 'select', 1000, function(e) { fireEvent(e,"filled"); // let other interested parties know that the items have changed // if the update changed the current selection, others listening to this control needs to be notified. - if (e.value!=value) fireEvent(e,"change"); + if (hasChanged(e, value)) { + fireEvent(e,"change"); + } } }); }); From a8f518e098ac255a420eee977fb1e7cf38ccf289 Mon Sep 17 00:00:00 2001 From: marco Date: Tue, 20 Oct 2015 10:24:57 +0200 Subject: [PATCH 0688/2573] Use of class Base64 in a static way --- cli/src/main/java/hudson/cli/FullDuplexHttpStream.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/main/java/hudson/cli/FullDuplexHttpStream.java b/cli/src/main/java/hudson/cli/FullDuplexHttpStream.java index 941dc4b0ae..abde9bb202 100644 --- a/cli/src/main/java/hudson/cli/FullDuplexHttpStream.java +++ b/cli/src/main/java/hudson/cli/FullDuplexHttpStream.java @@ -44,7 +44,7 @@ public class FullDuplexHttpStream { private static String basicAuth(String userInfo) { if (userInfo != null) - return "Basic "+new String(new Base64().encodeBase64(userInfo.getBytes())); + return "Basic "+new String(Base64.encodeBase64(userInfo.getBytes())); return null; } From 16c30cdc4c79800adea70760d6f4f9d9bcd858d0 Mon Sep 17 00:00:00 2001 From: Tom Fennelly Date: Wed, 26 Aug 2015 19:48:14 +0100 Subject: [PATCH 0689/2573] Merge pull request #1774 from tfennelly/upgrade-htmlunit Upgrade HtmlUnit to v2.18 (from forked version) (cherry picked from commit f552d48f5047e42810cc0e999cb33fbf9519d284) --- test/pom.xml | 21 +-- .../com/gargoylesoftware/htmlunit/README.md | 39 +++++ .../htmlunit/WebClientUtil.java | 139 +++++++++++++++++ .../htmlunit/WebResponseListener.java | 40 +++++ .../htmlunit/html/DomNodeUtil.java | 68 +++++++++ .../htmlunit/html/HtmlElementUtil.java | 61 ++++++++ .../htmlunit/html/HtmlFormUtil.java | 142 ++++++++++++++++++ .../jvnet/hudson/test/HudsonPageCreator.java | 13 ++ .../org/jvnet/hudson/test/HudsonTestCase.java | 58 ++++--- .../org/jvnet/hudson/test/JenkinsRule.java | 121 ++++++++++----- .../jvnet/hudson/test/junit/FailedTest.java | 2 +- .../hudson/model/AbstractProjectTest.groovy | 20 +-- .../TokenBasedRememberMeServices2Test.groovy | 2 +- .../jenkins/bugs/Jenkins19124Test.groovy | 3 + test/src/test/java/hudson/ExceptionTest.java | 16 +- .../bugs/JnlpAccessWithSecuredHudsonTest.java | 2 +- .../java/hudson/bugs/LoginRedirectTest.java | 6 +- .../hudson/console/ConsoleAnnotatorTest.java | 10 +- .../ReverseProxySetupMonitorTest.java | 5 +- .../diagnosis/TooManyJobsButNoViewTest.java | 2 +- .../java/hudson/model/AsynchPeopleTest.java | 4 +- .../model/DirectlyModifiableViewTest.java | 6 +- .../test/java/hudson/model/HelpLinkTest.java | 35 +++-- .../test/java/hudson/model/HudsonTest.java | 13 +- test/src/test/java/hudson/model/JobTest.java | 3 +- .../java/hudson/model/ManagementLinkTest.java | 3 +- .../java/hudson/model/ParametersTest.java | 50 +++--- .../src/test/java/hudson/model/QueueTest.java | 3 +- test/src/test/java/hudson/model/UserTest.java | 5 +- .../java/hudson/model/ViewPropertyTest.java | 3 +- test/src/test/java/hudson/model/ViewTest.java | 14 +- .../test/java/hudson/search/SearchTest.java | 4 +- .../test/java/hudson/security/LoginTest.java | 7 +- .../hudson/security/pages/SignupPage.java | 2 +- .../java/hudson/slaves/JNLPLauncherTest.java | 2 +- .../java/hudson/slaves/NodePropertyTest.java | 3 +- .../java/hudson/tools/JDKInstallerTest.java | 3 +- .../hudson/util/FormFieldValidatorTest.java | 19 ++- .../util/RobustReflectionConverterTest.java | 8 +- .../test/java/jenkins/model/JenkinsTest.java | 19 ++- .../security/ApiTokenPropertyTest.java | 119 ++++++++++++--- .../security/BasicHeaderProcessorTest.java | 5 +- .../FrameOptionsPageDecoratorTest.java | 2 +- .../security/RekeySecretAdminMonitorTest.java | 9 +- .../jenkins/security/Security177Test.java | 2 +- .../jenkins/widgets/BuildListTableTest.java | 4 +- .../java/lib/form/AdvancedButtonTest.java | 3 +- .../java/lib/form/ExpandableTextboxTest.java | 5 +- .../test/java/lib/form/RepeatableTest.java | 28 ++-- .../java/lib/form/RowVisibilityGroupTest.java | 13 +- .../java/lib/form/ValidateButtonTest.java | 6 +- .../java/lib/hudson/ListScmBrowsersTest.java | 3 +- test/src/test/java/lib/layout/IconTest.java | 24 ++- test/src/test/java/lib/layout/LayoutTest.java | 4 +- .../java/lib/layout/RenderOnDemandTest.java | 11 +- test/src/test/java/lib/layout/TaskTest.java | 3 +- .../main/UseRecipesWithJenkinsRuleTest.java | 2 +- .../main/webapp/scripts/hudson-behavior.js | 5 + war/src/main/webapp/scripts/prototype.js | 8 +- 59 files changed, 953 insertions(+), 279 deletions(-) create mode 100644 test/src/main/java/com/gargoylesoftware/htmlunit/README.md create mode 100644 test/src/main/java/com/gargoylesoftware/htmlunit/WebClientUtil.java create mode 100644 test/src/main/java/com/gargoylesoftware/htmlunit/WebResponseListener.java create mode 100644 test/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java create mode 100644 test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlElementUtil.java create mode 100644 test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java diff --git a/test/pom.xml b/test/pom.xml index 995f6acb06..fb827050d0 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 @@ -127,16 +137,9 @@ THE SOFTWARE. 1.3 - org.jenkins-ci + net.sourceforge.htmlunit htmlunit - 2.6-jenkins-6 - - - - xml-apis - xml-apis - - + 2.18 xalan 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..5aadb8e293 --- /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. + +```java +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/WebClientUtil.java b/test/src/main/java/com/gargoylesoftware/htmlunit/WebClientUtil.java new file mode 100644 index 0000000000..d330c77a4a --- /dev/null +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/WebClientUtil.java @@ -0,0 +1,139 @@ +/* + * 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; + +import com.gargoylesoftware.htmlunit.javascript.JavaScriptErrorListener; +import org.junit.Assert; + +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; + private ScriptException scriptException; + + private ExceptionListener(WebClient webClient) { + 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/WebResponseListener.java b/test/src/main/java/com/gargoylesoftware/htmlunit/WebResponseListener.java new file mode 100644 index 0000000000..75cd37e2fa --- /dev/null +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/WebResponseListener.java @@ -0,0 +1,40 @@ +package com.gargoylesoftware.htmlunit; + +import org.junit.Assert; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * @author tom.fennelly@gmail.com + */ +public interface WebResponseListener { + + void onLoadWebResponse(WebRequest webRequest, WebResponse webResponse) throws IOException; + + public final class StatusListener implements WebResponseListener { + + private final int statusCode; + private final List responses = new CopyOnWriteArrayList<>(); + + public StatusListener(final int statusCode) { + this.statusCode = statusCode; + } + + @Override + public void onLoadWebResponse(WebRequest webRequest, WebResponse webResponse) throws IOException { + if (webResponse.getStatusCode() == statusCode) { + responses.add(webResponse); + } + } + + public void assertHasResponses() { + Assert.assertTrue(!responses.isEmpty()); + } + + public List getResponses() { + return responses; + } + } +} diff --git a/test/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java b/test/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java new file mode 100644 index 0000000000..a70716b852 --- /dev/null +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/html/DomNodeUtil.java @@ -0,0 +1,68 @@ +/* + * 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.WebClientUtil; +import com.gargoylesoftware.htmlunit.html.xpath.XPathUtils; + +import java.util.List; + +/** + * {@link DomNode} helper methods. + * + * @author tom.fennelly@gmail.com + */ +public class DomNodeUtil { + + /** + * 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); + } + + /** + * 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 new file mode 100644 index 0000000000..c8d599b11f --- /dev/null +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlElementUtil.java @@ -0,0 +1,61 @@ +/* + * 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.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 { + + /** + * 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 new file mode 100644 index 0000000000..af95c37cdf --- /dev/null +++ b/test/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFormUtil.java @@ -0,0 +1,142 @@ +/* + * 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.WebClient; +import com.gargoylesoftware.htmlunit.WebClientUtil; + +import java.io.IOException; +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 + */ +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(); + + try { + if (submitElement != null && !(submitElement instanceof SubmittableElement)) { + // Just click and return + return submitElement.click(); + } + + try { + htmlForm.submit((SubmittableElement) submitElement); + } finally { + // The HtmlForm submit doesn't really do anything. It just adds a "LoadJob" + // to an internal queue. What we are doing here is manually forcing the load of + // the response for that submit LoadJob and then getting the enclosing page + // from the current window on the WebClient, allowing us to return the correct + // HtmlPage object to the test. + webClient.loadDownloadedResponses(); + Page resultPage = webClient.getCurrentWindow().getEnclosedPage(); + + if (resultPage == htmlPage) { + return HtmlElementUtil.click(submitElement); + } else { + return resultPage; + } + } + } finally { + // Make sure all background JS has executed. + WebClientUtil.waitForJSExec(webClient); + } + } + + /** + * 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()) { + list.add(elt); + } + + return list; + } + + /** + * Gets the first <input type="submit"> element in this form. + */ + public static HtmlElement getSubmitButton(final HtmlForm htmlForm) throws ElementNotFoundException { + List submitButtons = getSubmitButtons(htmlForm); + if (!submitButtons.isEmpty()) { + return submitButtons.get(0); + } + for (HtmlElement element : htmlForm.getHtmlElementsByTagName("button")) { + if(element instanceof HtmlButton) { + return element; + } + } + 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)) { + return (HtmlButton) b; + } + } + throw new ElementNotFoundException("button", "caption", caption); + } +} diff --git a/test/src/main/java/org/jvnet/hudson/test/HudsonPageCreator.java b/test/src/main/java/org/jvnet/hudson/test/HudsonPageCreator.java index 07f2fafe5c..f50c04f351 100644 --- a/test/src/main/java/org/jvnet/hudson/test/HudsonPageCreator.java +++ b/test/src/main/java/org/jvnet/hudson/test/HudsonPageCreator.java @@ -28,8 +28,10 @@ import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.WebResponse; import com.gargoylesoftware.htmlunit.WebWindow; import com.gargoylesoftware.htmlunit.PageCreator; +import org.apache.commons.lang3.StringUtils; import java.io.IOException; +import java.io.InputStream; import java.util.Locale; /** @@ -46,5 +48,16 @@ public class HudsonPageCreator extends DefaultPageCreator { return super.createPage(webResponse, webWindow); } + @Override + protected String determineContentType(String contentType, InputStream contentAsStream) throws IOException { + // Need to sidestep HtmlUnit default behaviour here. It defaults the response type to + // being text/plain (and so creates a TextPage) if the content type in the response is + // blank + is an empty response. + if (StringUtils.isEmpty(contentType)) { + return "text/html"; + } + return super.determineContentType(contentType, contentAsStream); + } + public static final HudsonPageCreator INSTANCE = new HudsonPageCreator(); } 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..e17372122c 100644 --- a/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java +++ b/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java @@ -25,6 +25,10 @@ package org.jvnet.hudson.test; import com.gargoylesoftware.htmlunit.AlertHandler; +import com.gargoylesoftware.htmlunit.WebClientUtil; +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.google.inject.Injector; @@ -120,6 +124,7 @@ import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; +import javax.annotation.Nonnull; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; @@ -175,7 +180,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 +1046,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 +1102,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 +1164,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, last(form.getHtmlElementsByTagName("button"))); } /** @@ -1172,24 +1176,15 @@ 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)) { - // 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); + 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); } 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) { @@ -1629,19 +1624,19 @@ 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, // 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) { + private static final long serialVersionUID = 6730107519583349963L; + public boolean processSynchron(HtmlPage page, WebRequest settings, boolean async) { return false; } }); @@ -1689,7 +1684,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 +1696,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 +1762,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); } /** @@ -1821,7 +1816,11 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { @SuppressWarnings("unchecked") @Override public Page getPage(String url) throws IOException, FailingHttpStatusCodeException { - return super.getPage(url); + try { + return super.getPage(url); + } finally { + WebClientUtil.waitForJSExec(this); + } } /** @@ -1845,6 +1844,7 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { Page p; try { p = super.getPage(getContextPath() + relative); + WebClientUtil.waitForJSExec(this); } catch (IOException x) { if (x.getCause() != null) { x.getCause().printStackTrace(); @@ -1895,12 +1895,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/main/java/org/jvnet/hudson/test/JenkinsRule.java b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java index afdaf2c8a8..69d0e6bbba 100644 --- a/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -30,8 +30,10 @@ 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.WebClientUtil; +import com.gargoylesoftware.htmlunit.WebRequest; import com.gargoylesoftware.htmlunit.WebResponse; +import com.gargoylesoftware.htmlunit.WebResponseListener; import com.gargoylesoftware.htmlunit.html.DomNode; import com.gargoylesoftware.htmlunit.html.HtmlButton; import com.gargoylesoftware.htmlunit.html.HtmlElement; @@ -41,6 +43,7 @@ import com.gargoylesoftware.htmlunit.html.HtmlInput; import com.gargoylesoftware.htmlunit.html.HtmlPage; 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; @@ -99,6 +102,7 @@ import hudson.slaves.CommandLauncher; import hudson.slaves.ComputerConnector; import hudson.slaves.ComputerListener; import hudson.slaves.DumbSlave; +import hudson.slaves.OfflineCause; import hudson.slaves.RetentionStrategy; import hudson.tasks.Ant; import hudson.tasks.BuildWrapper; @@ -173,7 +177,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; @@ -191,6 +194,8 @@ import org.junit.runner.Description; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.Statement; import java.nio.channels.ClosedByInterruptException; +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; @@ -793,6 +798,31 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { return env.temporaryDirectoryAllocator.allocate(); } + public DumbSlave createSlave(boolean waitForChannelConnect) throws Exception { + DumbSlave slave = createSlave(); + if (waitForChannelConnect) { + long start = System.currentTimeMillis(); + while (slave.getChannel() == null) { + if (System.currentTimeMillis() > (start + 10000)) { + throw new IllegalStateException("Timed out waiting on DumbSlave channel to connect."); + } + Thread.sleep(200); + } + } + return slave; + } + + public void disconnectSlave(DumbSlave slave) throws Exception { + slave.getComputer().disconnect(new OfflineCause.ChannelTermination(new Exception("terminate"))); + long start = System.currentTimeMillis(); + while (slave.getChannel() != null) { + if (System.currentTimeMillis() > (start + 10000)) { + throw new IllegalStateException("Timed out waiting on DumbSlave channel to disconnect."); + } + Thread.sleep(200); + } + } + public DumbSlave createSlave() throws Exception { return createSlave("",null); } @@ -1180,8 +1210,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 @@ -1237,7 +1268,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) { @@ -1300,7 +1331,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,24 +1343,15 @@ 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)) { - // 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); + 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); } 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,20 +1861,22 @@ 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<>(); 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); 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) { + private static final long serialVersionUID = -76034615893907856L; + public boolean processSynchron(HtmlPage page, WebRequest settings, boolean async) { return false; } }); @@ -1897,7 +1921,23 @@ 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); + } + + + public void addWebResponseListener(WebResponseListener listener) { + webResponseListeners.add(listener); + } + + @Override + public WebResponse loadWebResponse(final WebRequest webRequest) throws IOException { + WebResponse webResponse = super.loadWebResponse(webRequest); + if (!webResponseListeners.isEmpty()) { + for (WebResponseListener listener : webResponseListeners) { + listener.onLoadWebResponse(webRequest, webResponse); + } + } + return webResponse; } /** @@ -1907,6 +1947,14 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { return login(username,password,false); } + public boolean isJavaScriptEnabled() { + return getOptions().isJavaScriptEnabled(); + } + + public void setJavaScriptEnabled(boolean enabled) { + getOptions().setJavaScriptEnabled(enabled); + } + /** * Logs in to Jenkins. */ @@ -1923,7 +1971,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; } @@ -1935,7 +1983,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { * and passwords. All the test accounts have the same user name and password. */ public WebClient login(String username) throws Exception { - login(username,username); + login(username, username); return this; } @@ -1989,7 +2037,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); } /** @@ -2018,7 +2066,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { } public HtmlPage getPage(Node item) throws IOException, SAXException { - return getPage(item,""); + return getPage(item, ""); } public HtmlPage getPage(Node item, String relative) throws IOException, SAXException { @@ -2043,7 +2091,11 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { @SuppressWarnings("unchecked") @Override public Page getPage(String url) throws IOException, FailingHttpStatusCodeException { - return super.getPage(url); + try { + return super.getPage(url); + } finally { + WebClientUtil.waitForJSExec(this); + } } /** @@ -2075,6 +2127,7 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { Page p; try { p = super.getPage(getContextPath() + relative); + WebClientUtil.waitForJSExec(this); } catch (IOException x) { Throwable cause = x.getCause(); if (cause instanceof SocketTimeoutException) { @@ -2131,15 +2184,13 @@ 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 )); - - req.setRequestParameters(Arrays.asList( crumb )); + public WebRequest addCrumb(WebRequest req) { + NameValuePair crumb = new NameValuePair( + jenkins.getCrumbIssuer().getDescriptor().getCrumbRequestField(), + jenkins.getCrumbIssuer().getCrumb( null )); + req.setRequestParameters(Arrays.asList(crumb)); return req; } 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 index 364364ef8d..670a9d4e1e 100644 --- a/test/src/main/java/org/jvnet/hudson/test/junit/FailedTest.java +++ b/test/src/main/java/org/jvnet/hudson/test/junit/FailedTest.java @@ -51,4 +51,4 @@ public class FailedTest extends TestCase { if (problem!=null) throw problem; } -} +} \ No newline at end of file diff --git a/test/src/test/groovy/hudson/model/AbstractProjectTest.groovy b/test/src/test/groovy/hudson/model/AbstractProjectTest.groovy index f40a32ed3a..fe6c39351b 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 @@ -127,10 +117,10 @@ public class AbstractProjectTest extends HudsonTestCase { def webClient = createWebClient(); HtmlPage page = webClient.getPage(jenkins.getItem("test0")); - page = (HtmlPage)page.getFirstAnchorByText("Workspace").click(); + page = (HtmlPage)page.getAnchorByText("Workspace").click(); try { String wipeOutLabel = ResourceBundle.getBundle("hudson/model/AbstractProject/sidepanel").getString("Wipe Out Workspace"); - page.getFirstAnchorByText(wipeOutLabel); + page.getAnchorByText(wipeOutLabel); fail("shouldn't find a link"); } catch (ElementNotFoundException e) { // OK @@ -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))).getUrl().toString(); assert loc.startsWith(base): loc; return loc.substring(base.length()); } diff --git a/test/src/test/groovy/hudson/security/TokenBasedRememberMeServices2Test.groovy b/test/src/test/groovy/hudson/security/TokenBasedRememberMeServices2Test.groovy index 92d202a862..435eb4fbb7 100644 --- a/test/src/test/groovy/hudson/security/TokenBasedRememberMeServices2Test.groovy +++ b/test/src/test/groovy/hudson/security/TokenBasedRememberMeServices2Test.groovy @@ -9,7 +9,7 @@ import org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices import org.acegisecurity.userdetails.User import org.acegisecurity.userdetails.UserDetails import org.acegisecurity.userdetails.UsernameNotFoundException -import org.apache.commons.httpclient.Cookie +import com.gargoylesoftware.htmlunit.util.Cookie import org.junit.After import org.junit.Before import org.junit.Rule diff --git a/test/src/test/groovy/jenkins/bugs/Jenkins19124Test.groovy b/test/src/test/groovy/jenkins/bugs/Jenkins19124Test.groovy index 5e7d248be9..b4c5c5fc9c 100644 --- a/test/src/test/groovy/jenkins/bugs/Jenkins19124Test.groovy +++ b/test/src/test/groovy/jenkins/bugs/Jenkins19124Test.groovy @@ -1,5 +1,6 @@ package jenkins.bugs +import com.gargoylesoftware.htmlunit.WebClientUtil import hudson.Launcher import hudson.model.AbstractBuild import hudson.model.AbstractProject @@ -40,10 +41,12 @@ class Jenkins19124Test { def wc = j.createWebClient(); def c = wc.getPage(p, "configure"); c.getElementByName("_.alpha").valueAttribute = "hello"; + WebClientUtil.waitForJSExec(wc); assert d.alpha=="hello"; assert d.bravo=="2"; c.getElementByName("_.bravo").setSelectedAttribute("1",true); + WebClientUtil.waitForJSExec(wc); assert d.alpha=="hello"; assert d.bravo=="1"; } diff --git a/test/src/test/java/hudson/ExceptionTest.java b/test/src/test/java/hudson/ExceptionTest.java index 907a2e30e7..1e68673c82 100644 --- a/test/src/test/java/hudson/ExceptionTest.java +++ b/test/src/test/java/hudson/ExceptionTest.java @@ -1,6 +1,8 @@ package hudson; import com.gargoylesoftware.htmlunit.ScriptException; +import com.gargoylesoftware.htmlunit.WebClientUtil; +import org.junit.Assert; import org.jvnet.hudson.test.HudsonTestCase; /** @@ -11,14 +13,12 @@ public class ExceptionTest extends HudsonTestCase { * Makes sure that an AJAX handler error results in a fatal problem in the unit test. */ public void testAjaxError() throws Exception { - try { - createWebClient().goTo("/self/ajaxError"); - fail("should have resulted in a ScriptException"); - } catch (ScriptException e) { - if (e.getMessage().contains("simulated error")) - return; // as expected - throw e; + WebClient webClient = createWebClient(); + WebClientUtil.ExceptionListener exceptionListener = WebClientUtil.addExceptionListener(webClient); + webClient.goTo("/self/ajaxError"); - } + // Check for the error. + ScriptException e = exceptionListener.getExpectedScriptException(); + Assert.assertTrue(e.getMessage().contains("simulated error")); } } 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")); diff --git a/test/src/test/java/hudson/bugs/LoginRedirectTest.java b/test/src/test/java/hudson/bugs/LoginRedirectTest.java index d26ab3c11a..af63ad9380 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,15 +48,14 @@ 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()); assertEquals(200, p.getWebResponse().getStatusCode()); 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); } diff --git a/test/src/test/java/hudson/console/ConsoleAnnotatorTest.java b/test/src/test/java/hudson/console/ConsoleAnnotatorTest.java index 7ab76e9170..83827f4860 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,8 @@ 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:""))); + req.setEncodingType(null); Map headers = new HashMap(); if (consoleAnnotator!=null) headers.put("X-ConsoleAnnotator",consoleAnnotator); diff --git a/test/src/test/java/hudson/diagnosis/ReverseProxySetupMonitorTest.java b/test/src/test/java/hudson/diagnosis/ReverseProxySetupMonitorTest.java index 2e2d8dd6f1..d44b77734b 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,8 @@ 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.setEncodingType(null); wrs.setAdditionalHeader("Referer", r.getURL() + "manage"); r.createWebClient().getPage(wrs); } 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 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")); diff --git a/test/src/test/java/hudson/model/DirectlyModifiableViewTest.java b/test/src/test/java/hudson/model/DirectlyModifiableViewTest.java index f6f62d935f..459862efa6 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.getOptions().setThrowExceptionOnFailingStatusCode(false); + WebRequest req = new WebRequest( new URL(j.jenkins.getRootUrl() + view.getUrl() + path), HttpMethod.POST ); diff --git a/test/src/test/java/hudson/model/HelpLinkTest.java b/test/src/test/java/hudson/model/HelpLinkTest.java index 907f127cc9..92bbaacc14 100644 --- a/test/src/test/java/hudson/model/HelpLinkTest.java +++ b/test/src/test/java/hudson/model/HelpLinkTest.java @@ -1,9 +1,12 @@ package hudson.model; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import com.gargoylesoftware.htmlunit.WebResponseListener; +import com.gargoylesoftware.htmlunit.html.DomNodeUtil; +import com.gargoylesoftware.htmlunit.html.HtmlElementUtil; import hudson.tasks.BuildStepMonitor; +import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import com.gargoylesoftware.htmlunit.html.HtmlPage; @@ -48,16 +51,22 @@ public class HelpLinkTest { private void clickAllHelpLinks(AbstractProject p) throws Exception { // TODO: how do we add all the builders and publishers so that we can test this meaningfully? - clickAllHelpLinks(j.createWebClient().getPage(p, "configure")); + clickAllHelpLinks(j.createWebClient(), p); + } + + private void clickAllHelpLinks(JenkinsRule.WebClient webClient, AbstractProject p) throws Exception { + // TODO: how do we add all the builders and publishers so that we can test this meaningfully? + clickAllHelpLinks(webClient.getPage(p, "configure")); } 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"); - for (HtmlAnchor helpLink : (List)helpLinks) - helpLink.click(); + for (HtmlAnchor helpLink : (List)helpLinks) { + HtmlElementUtil.click(helpLink); + } } public static class HelpNotFoundBuilder extends Publisher { @@ -92,13 +101,15 @@ public class HelpLinkTest { try { FreeStyleProject p = j.createFreeStyleProject(); p.getPublishersList().add(new HelpNotFoundBuilder()); - clickAllHelpLinks(p); - fail("should detect a failure"); - } catch(AssertionError e) { - if(e.getMessage().contains(d.getHelpFile())) - ; // expected - else - throw e; + JenkinsRule.WebClient webclient = j.createWebClient(); + WebResponseListener.StatusListener statusListener = new WebResponseListener.StatusListener(404); + webclient.addWebResponseListener(statusListener); + + clickAllHelpLinks(webclient, p); + + statusListener.assertHasResponses(); + String contentAsString = statusListener.getResponses().get(0).getContentAsString(); + Assert.assertTrue(contentAsString.contains(d.getHelpFile())); } finally { Publisher.all().remove(d); } 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"); 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()); 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(); 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")); } } 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(); } diff --git a/test/src/test/java/hudson/model/UserTest.java b/test/src/test/java/hudson/model/UserTest.java index 800d1862a9..c26239cdff 100644 --- a/test/src/test/java/hudson/model/UserTest.java +++ b/test/src/test/java/hudson/model/UserTest.java @@ -25,6 +25,7 @@ package hudson.model; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; +import com.gargoylesoftware.htmlunit.ScriptException; import com.gargoylesoftware.htmlunit.WebAssert; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; @@ -51,11 +52,12 @@ import org.acegisecurity.context.SecurityContextHolder; import static org.junit.Assert.*; import static org.junit.Assume.*; + +import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.FakeChangeLogSCM; -import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.TestExtension; import org.jvnet.hudson.test.recipes.LocalData; @@ -452,6 +454,7 @@ public class UserTest { } catch(FailingHttpStatusCodeException e){ //ok exception should be thrown + Assert.assertEquals(400, e.getStatusCode()); } assertTrue("User should not delete himself from memory.", User.getAll().contains(user)); assertTrue("User should not delete his persistent data.", user.getConfigFile().exists()); 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); diff --git a/test/src/test/java/hudson/model/ViewTest.java b/test/src/test/java/hudson/model/ViewTest.java index 1b37513e6c..3cbc8904cd 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,8 +195,9 @@ 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); + req.setEncodingType(null); wc.getPage(req); assertEquals("two", view.getDescription()); xml = new XmlFile(Jenkins.XSTREAM, new File(j.jenkins.getRootDir(), "config.xml")).asString(); @@ -401,7 +401,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)); } 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())); } 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)); } 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)); } } diff --git a/test/src/test/java/hudson/slaves/JNLPLauncherTest.java b/test/src/test/java/hudson/slaves/JNLPLauncherTest.java index 26e7c1a1a2..7184b1e147 100644 --- a/test/src/test/java/hudson/slaves/JNLPLauncherTest.java +++ b/test/src/test/java/hudson/slaves/JNLPLauncherTest.java @@ -137,7 +137,7 @@ public class JNLPLauncherTest extends HudsonTestCase { private String getJnlpLink(Computer c) throws Exception { HtmlPage p = new WebClient().goTo("computer/"+c.getName()+"/"); String href = ((HtmlAnchor) p.getElementById("jnlp-link")).getHrefAttribute(); - href = new URL(new URL(p.getDocumentURI()),href).toExternalForm(); + href = new URL(new URL(p.getUrl().toExternalForm()),href).toExternalForm(); return href; } 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); 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()); diff --git a/test/src/test/java/hudson/util/FormFieldValidatorTest.java b/test/src/test/java/hudson/util/FormFieldValidatorTest.java index bcdd0ecde0..521ee8c70e 100644 --- a/test/src/test/java/hudson/util/FormFieldValidatorTest.java +++ b/test/src/test/java/hudson/util/FormFieldValidatorTest.java @@ -25,11 +25,13 @@ package hudson.util; import static org.junit.Assert.fail; +import com.gargoylesoftware.htmlunit.WebResponseListener; import hudson.model.FreeStyleProject; import hudson.tasks.BuildStepMonitor; import hudson.tasks.BuildStepDescriptor; import hudson.tasks.Publisher; import hudson.util.FormFieldValidatorTest.BrokenFormValidatorBuilder.DescriptorImpl; +import org.junit.Assert; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Issue; @@ -83,13 +85,16 @@ public class FormFieldValidatorTest { try { FreeStyleProject p = j.createFreeStyleProject(); p.getPublishersList().add(new BrokenFormValidatorBuilder()); - j.createWebClient().getPage(p, "configure"); - fail("should have failed"); - } catch(AssertionError e) { - if(e.getMessage().contains("doCheckXyz is broken")) - ; // expected - else - throw e; + + JenkinsRule.WebClient webclient = j.createWebClient(); + WebResponseListener.StatusListener statusListener = new WebResponseListener.StatusListener(500); + webclient.addWebResponseListener(statusListener); + + webclient.getPage(p, "configure"); + + statusListener.assertHasResponses(); + String contentAsString = statusListener.getResponses().get(0).getContentAsString(); + Assert.assertTrue(contentAsString.contains("doCheckXyz is broken")); } finally { Publisher.all().remove(d); } diff --git a/test/src/test/java/hudson/util/RobustReflectionConverterTest.java b/test/src/test/java/hudson/util/RobustReflectionConverterTest.java index fa3d3ad1cf..f929d6b2bc 100644 --- a/test/src/test/java/hudson/util/RobustReflectionConverterTest.java +++ b/test/src/test/java/hudson/util/RobustReflectionConverterTest.java @@ -58,7 +58,7 @@ import org.kohsuke.stapler.StaplerRequest; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.HttpMethod; -import com.gargoylesoftware.htmlunit.WebRequestSettings; +import com.gargoylesoftware.htmlunit.WebRequest; public class RobustReflectionConverterTest { @@ -201,10 +201,11 @@ public class RobustReflectionConverterTest { r.jenkins.setSecurityRealm(r.createDummySecurityRealm()); WebClient wc = r.createWebClient(); wc.login("test", "test"); - WebRequestSettings req = new WebRequestSettings( + WebRequest req = new WebRequest( wc.createCrumbedUrl(String.format("%s/config.xml", p.getUrl())), HttpMethod.POST ); + req.setEncodingType(null); req.setRequestBody(String.format(CONFIGURATION_TEMPLATE, "badvalue", AcceptOnlySpecificKeyword.ACCEPT_KEYWORD)); wc.getPage(req); @@ -233,10 +234,11 @@ public class RobustReflectionConverterTest { r.jenkins.setSecurityRealm(r.createDummySecurityRealm()); WebClient wc = r.createWebClient(); wc.login("test", "test"); - WebRequestSettings req = new WebRequestSettings( + WebRequest req = new WebRequest( wc.createCrumbedUrl(String.format("%s/config.xml", p.getUrl())), HttpMethod.POST ); + req.setEncodingType(null); req.setRequestBody(String.format(CONFIGURATION_TEMPLATE, AcceptOnlySpecificKeyword.ACCEPT_KEYWORD, "badvalue")); try { diff --git a/test/src/test/java/jenkins/model/JenkinsTest.java b/test/src/test/java/jenkins/model/JenkinsTest.java index 4b4bc7422d..6664193d57 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,8 @@ 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.setEncodingType(null); req.setRequestBody("${1+2}"); return wc.getPage(req).getWebResponse().getContentAsString(); } @@ -393,7 +394,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 @@ -436,13 +437,15 @@ public class JenkinsTest { @Test public void runScriptOnOfflineComputer() throws Exception { - DumbSlave slave = j.createSlave(); + DumbSlave slave = j.createSlave(true); + j.disconnectSlave(slave); + 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(); diff --git a/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java b/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java index a28c0582a0..906431328c 100644 --- a/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java +++ b/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java @@ -5,24 +5,45 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import com.gargoylesoftware.htmlunit.DownloadedContent; import com.gargoylesoftware.htmlunit.HttpWebConnection; +import com.gargoylesoftware.htmlunit.WebConnection; +import com.gargoylesoftware.htmlunit.WebRequest; +import com.gargoylesoftware.htmlunit.WebResponse; +import com.gargoylesoftware.htmlunit.WebResponseData; import com.gargoylesoftware.htmlunit.html.HtmlForm; import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.util.NameValuePair; +import com.gargoylesoftware.htmlunit.util.UrlUtils; 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.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScheme; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.Credentials; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.AuthCache; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.protocol.HttpClientContext; +import org.apache.http.impl.auth.BasicScheme; +import org.apache.http.impl.client.BasicAuthCache; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule.WebClient; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.Callable; /** @@ -53,23 +74,10 @@ 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; - } - }); + configureWebConnection(wc, token); // test the authentication - assertEquals(u,wc.executeOnServer(new Callable() { + assertEquals(u, wc.executeOnServer(new Callable() { public User call() throws Exception { return User.current(); } @@ -98,4 +106,71 @@ public class ApiTokenPropertyTest { u.addProperty(t); assertTrue(t.getApiToken().equals(Util.getDigestOf(historicalInitialValue+"somethingElse"))); } + + private void configureWebConnection(final WebClient wc, final String token) throws IOException { + // See https://hc.apache.org/httpcomponents-client-ga/tutorial/html/authentication.html + final UsernamePasswordCredentials fooCreds = new UsernamePasswordCredentials("foo", token); + + URL hostUrl = j.getURL(); + final HttpHost targetHost = new HttpHost(hostUrl.getHost(), hostUrl.getPort(), hostUrl.getProtocol()); + CredentialsProvider credsProvider = new BasicCredentialsProvider() { + @Override + public Credentials getCredentials(AuthScope authscope) { + return fooCreds; + } + }; + credsProvider.setCredentials( + new AuthScope("localhost", AuthScope.ANY_PORT, AuthScope.ANY_REALM), + fooCreds); + + // Create AuthCache instance + AuthCache authCache = new BasicAuthCache(); + // Generate BASIC scheme object and add it to the local auth cache + AuthScheme authScheme = new BasicScheme(); + authCache.put(targetHost, authScheme); + + // Add AuthCache to the execution context + final HttpClientContext context = HttpClientContext.create(); + context.setCredentialsProvider(credsProvider); + context.setAuthCache(authCache); + + wc.setCredentialsProvider(credsProvider); + + // Need to create our own WebConnection that gives us control of HttpClient execution, + // allowing us to pass our own HttpClientContext etc. HttpWebConnection has its own + // private HttpClientContext instance, which means we can't authenticate properly. + wc.setWebConnection(new WebConnection() { + @Override + public WebResponse getResponse(WebRequest request) throws IOException { + try { + long startTime = System.currentTimeMillis(); + + HttpClientBuilder builder = HttpClientBuilder.create(); + CloseableHttpClient httpClient = builder.build(); + URL url = UrlUtils.encodeUrl(request.getUrl(), false, request.getCharset()); + HttpGet method = new HttpGet(url.toURI()); + + CloseableHttpResponse response = httpClient.execute(targetHost, method, context); + + HttpEntity httpEntity = response.getEntity(); + DownloadedContent responseBody = HttpWebConnection.downloadContent(httpEntity.getContent(), wc.getOptions().getMaxInMemory()); + + String statusMessage = response.getStatusLine().getReasonPhrase(); + if (statusMessage == null) { + statusMessage = "Unknown status message"; + } + int statusCode = response.getStatusLine().getStatusCode(); + List headers = new ArrayList<>(); + for (final Header header : response.getAllHeaders()) { + headers.add(new NameValuePair(header.getName(), header.getValue())); + } + + WebResponseData responseData = new WebResponseData(responseBody, statusCode, statusMessage, headers); + return new WebResponse(responseData, request, (System.currentTimeMillis() - startTime)); + } catch (Exception e) { + throw new AssertionError("Failed to execute WebRequest.", e); + } + } + }); + } } diff --git a/test/src/test/java/jenkins/security/BasicHeaderProcessorTest.java b/test/src/test/java/jenkins/security/BasicHeaderProcessorTest.java index b83327a118..9b334db55e 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,8 @@ 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")); + req.setEncodingType(null); if (userAndPass!=null) req.setAdditionalHeader("Authorization","Basic "+Scrambler.scramble(userAndPass)); Page p = wc.getPage(req); 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; diff --git a/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java b/test/src/test/java/jenkins/security/RekeySecretAdminMonitorTest.java index 0797dc396f..ea7a08ba45 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 { 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"))); diff --git a/test/src/test/java/jenkins/widgets/BuildListTableTest.java b/test/src/test/java/jenkins/widgets/BuildListTableTest.java index bfdbaf60d1..cc8992d042 100644 --- a/test/src/test/java/jenkins/widgets/BuildListTableTest.java +++ b/test/src/test/java/jenkins/widgets/BuildListTableTest.java @@ -59,14 +59,14 @@ public class BuildListTableTest { assertEquals(0, wc.waitForBackgroundJavaScript(120000)); HtmlAnchor anchor = page.getAnchorByText("d » d2 » p"); String href = anchor.getHrefAttribute(); - URL target = URI.create(page.getDocumentURI()).resolve(href).toURL(); + URL target = URI.create(page.getUrl().toExternalForm()).resolve(href).toURL(); wc.getPage(target); assertEquals(href, r.getURL() + "view/v1/job/d/view/v2/job/d2/job/p/", target.toString()); page = wc.goTo("job/d/view/All/builds?suppressTimelineControl=true"); assertEquals(0, wc.waitForBackgroundJavaScript(120000)); anchor = page.getAnchorByText("d » d2 » p"); href = anchor.getHrefAttribute(); - target = URI.create(page.getDocumentURI()).resolve(href).toURL(); + target = URI.create(page.getUrl().toExternalForm()).resolve(href).toURL(); wc.getPage(target); assertEquals(href, r.getURL() + "job/d/job/d2/job/p/", target.toString()); } 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); } diff --git a/test/src/test/java/lib/form/ExpandableTextboxTest.java b/test/src/test/java/lib/form/ExpandableTextboxTest.java index b930652d15..75f24b9177 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,8 @@ 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.setEncodingType(null); req.setRequestBody(""+jellyScript+""); Page page = wc.getPage(req); return (HtmlPage) page; diff --git a/test/src/test/java/lib/form/RepeatableTest.java b/test/src/test/java/lib/form/RepeatableTest.java index 48ee7bf5e3..f96bac13bf 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); 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()); diff --git a/test/src/test/java/lib/form/ValidateButtonTest.java b/test/src/test/java/lib/form/ValidateButtonTest.java index 6cd1e5fc92..fe786090ed 100644 --- a/test/src/test/java/lib/form/ValidateButtonTest.java +++ b/test/src/test/java/lib/form/ValidateButtonTest.java @@ -23,6 +23,9 @@ */ package lib.form; +import com.gargoylesoftware.htmlunit.html.HtmlButton; +import com.gargoylesoftware.htmlunit.html.HtmlElementUtil; +import com.gargoylesoftware.htmlunit.html.HtmlFormUtil; import org.jvnet.hudson.test.HudsonTestCase; import org.kohsuke.stapler.QueryParameter; import hudson.model.Describable; @@ -41,7 +44,8 @@ public class ValidateButtonTest extends HudsonTestCase implements Describable selects = page.selectNodes("//select"); + List selects = DomNodeUtil.selectNodes(page, "//select"); assertTrue(selects.size()>0); for (HtmlSelect select : selects) { Set title = new HashSet(); 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) { 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); diff --git a/test/src/test/java/lib/layout/RenderOnDemandTest.java b/test/src/test/java/lib/layout/RenderOnDemandTest.java index 7e450063e4..8f4a41e33a 100644 --- a/test/src/test/java/lib/layout/RenderOnDemandTest.java +++ b/test/src/test/java/lib/layout/RenderOnDemandTest.java @@ -24,6 +24,8 @@ package lib.layout; import com.gargoylesoftware.htmlunit.ScriptResult; +import com.gargoylesoftware.htmlunit.WebClientUtil; +import com.gargoylesoftware.htmlunit.html.HtmlElement; import com.gargoylesoftware.htmlunit.html.HtmlPage; import org.jvnet.hudson.test.HudsonTestCase; @@ -41,9 +43,11 @@ public class RenderOnDemandTest extends HudsonTestCase { HtmlPage p = createWebClient().goTo("self/testBehaviour"); p.executeJavaScript("renderOnDemand(document.getElementsBySelector('.lazy')[0])"); + WebClientUtil.waitForJSExec(p.getWebClient()); // all AJAX calls complete before the above method returns ScriptResult r = p.executeJavaScript("var r=document.getElementsBySelector('DIV.a'); r[0].innerHTML+r[1].innerHTML+r[2].innerHTML"); + WebClientUtil.waitForJSExec(p.getWebClient()); assertEquals("AlphaBravoCharlie",r.getJavaScriptResult().toString()); } @@ -75,14 +79,17 @@ public class RenderOnDemandTest extends HudsonTestCase { HtmlPage p = createWebClient().goTo("self/testScript"); assertNull(p.getElementById("loaded")); - p.getElementById("button").click(); + ((HtmlElement)p.getElementById("button")).click(); + WebClientUtil.waitForJSExec(p.getWebClient()); // all AJAX calls complete before the above method returns - assertNotNull(p.getElementById("loaded")); ScriptResult r = p.executeJavaScript("x"); + WebClientUtil.waitForJSExec(p.getWebClient()); + assertEquals("xxx",r.getJavaScriptResult().toString()); r = p.executeJavaScript("y"); + WebClientUtil.waitForJSExec(p.getWebClient()); assertEquals("yyy",r.getJavaScriptResult().toString()); // if you want to test this in the browser diff --git a/test/src/test/java/lib/layout/TaskTest.java b/test/src/test/java/lib/layout/TaskTest.java index f56b61c4d8..916b36c4c8 100644 --- a/test/src/test/java/lib/layout/TaskTest.java +++ b/test/src/test/java/lib/layout/TaskTest.java @@ -29,6 +29,7 @@ import java.io.IOException; import javax.servlet.ServletException; +import com.gargoylesoftware.htmlunit.html.HtmlElementUtil; import hudson.model.UnprotectedRootAction; import org.junit.Rule; @@ -49,7 +50,7 @@ public class TaskTest { @Test public void postLink() throws Exception { WebClient wc = j.createWebClient(); HtmlPage page = wc.goTo(postLink.getUrlName()); - page.getAnchorByText("POST").click(); + HtmlElementUtil.click(page.getAnchorByText("POST")); assertTrue("Action method should be invoked", postLink.called); } 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")); } diff --git a/war/src/main/webapp/scripts/hudson-behavior.js b/war/src/main/webapp/scripts/hudson-behavior.js index eeeb1172e1..434c64be77 100644 --- a/war/src/main/webapp/scripts/hudson-behavior.js +++ b/war/src/main/webapp/scripts/hudson-behavior.js @@ -29,6 +29,11 @@ // for memory leak patterns and how to prevent them. // +if (window.isRunAsTest) { + // Disable postMessage when running in test mode (HtmlUnit). + window.postMessage = false; +} + // create a new object whose prototype is the given object function object(o) { function F() {} diff --git a/war/src/main/webapp/scripts/prototype.js b/war/src/main/webapp/scripts/prototype.js index 79e009d86f..63644c0a5c 100644 --- a/war/src/main/webapp/scripts/prototype.js +++ b/war/src/main/webapp/scripts/prototype.js @@ -1923,13 +1923,7 @@ if (!Node.ELEMENT_NODE) { } var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){ - try { - var el = document.createElement(''); - return el.tagName.toLowerCase() === 'input' && el.name === 'x'; - } - catch(err) { - return false; - } + return false; })(); var element = global.Element; From e4b1aab4acab93d638624c7705cfe6eea2d01786 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Tue, 20 Oct 2015 11:48:27 +0100 Subject: [PATCH 0690/2573] [FIXED JENKINS-31055] Make Node implement Saveable - Also tidy up some of the mess logic in both #1866 and #1860 --- changelog.html | 3 ++ core/src/main/java/hudson/model/Computer.java | 1 - core/src/main/java/hudson/model/Node.java | 29 ++++++++++++++----- core/src/main/java/jenkins/model/Jenkins.java | 9 ++++-- core/src/main/java/jenkins/model/Nodes.java | 22 ++++++++++---- 5 files changed, 48 insertions(+), 16 deletions(-) diff --git a/changelog.html b/changelog.html index 5783315003..8436b79e42 100644 --- a/changelog.html +++ b/changelog.html @@ -56,6 +56,9 @@ Upcoming changes

            What's new in 1.634 (2015/10/18)

            diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index 003162eafe..a3ddb20720 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -695,7 +695,6 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces if (node != null) { node.setTemporaryOfflineCause(offlineCause); } - Jenkins.getInstance().getQueue().scheduleMaintenance(); synchronized (statusChangeLock) { statusChangeLock.notifyAll(); } diff --git a/core/src/main/java/hudson/model/Node.java b/core/src/main/java/hudson/model/Node.java index 6a5ceb990c..c2e729ec66 100644 --- a/core/src/main/java/hudson/model/Node.java +++ b/core/src/main/java/hudson/model/Node.java @@ -25,7 +25,12 @@ package hudson.model; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; -import hudson.*; +import hudson.Extension; +import hudson.ExtensionPoint; +import hudson.FilePath; +import hudson.FileSystemProvisioner; +import hudson.Launcher; +import hudson.Util; import hudson.model.Descriptor.FormException; import hudson.model.Queue.Task; import hudson.model.labels.LabelAtom; @@ -46,17 +51,15 @@ import hudson.util.DescribableList; import hudson.util.EnumConverter; import hudson.util.TagCloud; import hudson.util.TagCloud.WeightFunction; - import java.io.IOException; import java.lang.reflect.Type; import java.util.Collections; import java.util.HashSet; -import java.util.Set; import java.util.List; +import java.util.Set; import java.util.logging.Logger; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; - import jenkins.model.Jenkins; import jenkins.util.io.OnMaster; import net.sf.json.JSONObject; @@ -65,8 +68,8 @@ import org.jvnet.localizer.Localizable; import org.kohsuke.stapler.BindInterceptor; import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.export.ExportedBean; import org.kohsuke.stapler.export.Exported; +import org.kohsuke.stapler.export.ExportedBean; /** * Base type of Jenkins slaves (although in practice, you probably extend {@link Slave} to define a new slave type). @@ -88,7 +91,7 @@ import org.kohsuke.stapler.export.Exported; * @see Computer */ @ExportedBean -public abstract class Node extends AbstractModelObject implements ReconfigurableDescribable, ExtensionPoint, AccessControlled, OnMaster { +public abstract class Node extends AbstractModelObject implements ReconfigurableDescribable, ExtensionPoint, AccessControlled, OnMaster, Saveable { private static final Logger LOGGER = Logger.getLogger(Node.class.getName()); @@ -114,6 +117,18 @@ public abstract class Node extends AbstractModelObject implements Reconfigurable return holdOffLaunchUntilSave; } + /** + * {@inheritDoc} + * @since 1.635 + */ + @Override + public void save() throws IOException { + final Jenkins jenkins = Jenkins.getInstance(); + if (jenkins != null) { + jenkins.updateNode(this); + } + } + /** * Name of this node. * @@ -237,7 +252,7 @@ public abstract class Node extends AbstractModelObject implements Reconfigurable try { if (temporaryOfflineCause != cause) { temporaryOfflineCause = cause; - Jenkins.getInstance().save(); // Gotta be a better way to do this + save(); } } catch (java.io.IOException e) { LOGGER.warning("Unable to complete save, temporary offline status will not be persisted: " + e.getMessage()); diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index ab03785899..1e0c92c941 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -147,7 +147,6 @@ import hudson.security.csrf.CrumbIssuer; import hudson.slaves.Cloud; import hudson.slaves.ComputerListener; import hudson.slaves.DumbSlave; -import hudson.slaves.EphemeralNode; import hudson.slaves.NodeDescriptor; import hudson.slaves.NodeList; import hudson.slaves.NodeProperty; @@ -289,7 +288,6 @@ import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.logging.Level; import java.util.logging.LogRecord; import java.util.logging.Logger; @@ -1752,7 +1750,12 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } /** - * Updates an existing {@link Node} on disk. + * Saves an existing {@link Node} on disk, called by {@link Node#save()}. This method is preferred in those cases + * where you need to determine atomically that the node being saved is actually in the list of nodes. + * + * @param n the node to be updated. + * @return {@code true}, if the node was updated. {@code false}, if the node was not in the list of nodes. + * @throws IOException if the node could not be persisted. * @see Nodes#updateNode * @since 1.634 */ diff --git a/core/src/main/java/jenkins/model/Nodes.java b/core/src/main/java/jenkins/model/Nodes.java index d6066bf224..58d364eae2 100644 --- a/core/src/main/java/jenkins/model/Nodes.java +++ b/core/src/main/java/jenkins/model/Nodes.java @@ -34,6 +34,7 @@ import hudson.model.Saveable; import hudson.model.listeners.SaveableListener; import hudson.slaves.EphemeralNode; import hudson.slaves.OfflineCause; +import java.util.concurrent.Callable; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -157,6 +158,7 @@ public class Nodes implements Saveable { xmlFile.write(node); SaveableListener.fireOnChange(this, xmlFile); } + jenkins.getQueue().scheduleMaintenance(); } /** @@ -166,17 +168,27 @@ public class Nodes implements Saveable { * @param node the node to be updated. * @return {@code true}, if the node was updated. {@code false}, if the node was not in the list of nodes. * @throws IOException if the node could not be persisted. + * @since 1.634 */ public boolean updateNode(final @Nonnull Node node) throws IOException { - if (node == nodes.get(node.getNodeName())) { - Queue.withLock(new Runnable() { + boolean exists; + try { + exists = Queue.withLock(new Callable() { @Override - public void run() { - jenkins.trimLabels(); + public Boolean call() throws Exception { + if (node == nodes.get(node.getNodeName())) { + jenkins.trimLabels(); + return true; + } + return false; } }); + } catch (Exception e) { + // can never happen + exists = false; + } + if (exists) { persistNode(node); - jenkins.getQueue().scheduleMaintenance(); return true; } return false; From 8645978bfbe272a494d2bc65cf47104255cfb3fb Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Wed, 21 Oct 2015 09:37:02 +0100 Subject: [PATCH 0691/2573] [JENKINS-31055] Finessing the exception handling --- core/src/main/java/jenkins/model/Nodes.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/main/java/jenkins/model/Nodes.java b/core/src/main/java/jenkins/model/Nodes.java index 58d364eae2..342e2a5ba9 100644 --- a/core/src/main/java/jenkins/model/Nodes.java +++ b/core/src/main/java/jenkins/model/Nodes.java @@ -183,6 +183,9 @@ public class Nodes implements Saveable { return false; } }); + } catch (RuntimeException e) { + // should never happen, but if it does let's do the right thing + throw e; } catch (Exception e) { // can never happen exists = false; From db37c76327748261c3b01eebd13369a1ca733282 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Wed, 21 Oct 2015 09:38:05 +0100 Subject: [PATCH 0692/2573] [JENKINS-31055] Replacing @since tag with placeholder to be restored on merge --- core/src/main/java/hudson/model/Node.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/Node.java b/core/src/main/java/hudson/model/Node.java index c2e729ec66..a3dd3b44d4 100644 --- a/core/src/main/java/hudson/model/Node.java +++ b/core/src/main/java/hudson/model/Node.java @@ -119,7 +119,7 @@ public abstract class Node extends AbstractModelObject implements Reconfigurable /** * {@inheritDoc} - * @since 1.635 + * @since 1.FIXME */ @Override public void save() throws IOException { From 8e24f69013e96e8b7f8b86e9b7a9133e2412c638 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Wed, 21 Oct 2015 09:52:26 +0100 Subject: [PATCH 0693/2573] [JENKINS-31055] The intent of Node.save() is a no-op when not in Jenkins list of nodes --- core/src/main/java/hudson/model/Node.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/src/main/java/hudson/model/Node.java b/core/src/main/java/hudson/model/Node.java index a3dd3b44d4..807c26a7e3 100644 --- a/core/src/main/java/hudson/model/Node.java +++ b/core/src/main/java/hudson/model/Node.java @@ -123,6 +123,12 @@ public abstract class Node extends AbstractModelObject implements Reconfigurable */ @Override public void save() throws IOException { + // this should be a no-op unless this node instance is the node instance in Jenkins' list of nodes + // thus where Jenkins.getInstance() == null there is no list of nodes, so we do a no-op + // Nodes.updateNode(n) will only persist the node record if the node instance is in the list of nodes + // so either path results in the same behaviour: the node instance is only saved if it is in the list of nodes + // for all other cases we do not know where to persist the node record and hence we follow the default + // no-op of a Saveable.NOOP final Jenkins jenkins = Jenkins.getInstance(); if (jenkins != null) { jenkins.updateNode(this); From d2276c3c9b16fd46a3912ab8d58c418e67d8ce3e Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Wed, 21 Oct 2015 10:01:49 +0100 Subject: [PATCH 0694/2573] [JENKINS-31055] Note theoretical race condtion Seems rather unlikely, but none the less it is a possibility. Not sure how we should handle this though: * We do not want to hold the Queue lock while performing I/O as that will grind everything to a halt * We do not want a big fat lock on all nodes * If we have a per-node lock then the save everything method may have to grab them all In short, it gets ugly real fast. For now, I believe that the risk is very low as releasing a lock does not intrinsically deschedule a currently running thread so the likely course of events is that the thread will release the lock and at least start the save before a competing thread could acquire the lock update remove the node release the lock and delete the node's directory --- core/src/main/java/jenkins/model/Nodes.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/src/main/java/jenkins/model/Nodes.java b/core/src/main/java/jenkins/model/Nodes.java index 342e2a5ba9..9c199a6b1d 100644 --- a/core/src/main/java/jenkins/model/Nodes.java +++ b/core/src/main/java/jenkins/model/Nodes.java @@ -138,6 +138,7 @@ public class Nodes implements Saveable { jenkins.trimLabels(); } }); + // TODO there is a theoretical race whereby the node instance is updated/removed after lock release persistNode(node); } } @@ -191,6 +192,7 @@ public class Nodes implements Saveable { exists = false; } if (exists) { + // TODO there is a theoretical race whereby the node instance is updated/removed after lock release persistNode(node); return true; } From 07e83a0e8ce7fbf2f97969eb909c9f2e2512e176 Mon Sep 17 00:00:00 2001 From: Vincent Latombe Date: Wed, 21 Oct 2015 12:24:07 +0200 Subject: [PATCH 0695/2573] Trim display name before applying it and add tests The current implementation is not robust against blank display name --- .../main/java/hudson/model/AbstractItem.java | 2 +- .../hudson/model/AbstractBuildTest.groovy | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/AbstractItem.java b/core/src/main/java/hudson/model/AbstractItem.java index 7b3818d0f1..f9a7283514 100644 --- a/core/src/main/java/hudson/model/AbstractItem.java +++ b/core/src/main/java/hudson/model/AbstractItem.java @@ -164,7 +164,7 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet } public void setDisplayName(String displayName) throws IOException { - this.displayName = Util.fixEmpty(displayName); + this.displayName = Util.fixEmptyAndTrim(displayName); save(); } diff --git a/test/src/test/groovy/hudson/model/AbstractBuildTest.groovy b/test/src/test/groovy/hudson/model/AbstractBuildTest.groovy index 8ce911b9da..27e688a62c 100644 --- a/test/src/test/groovy/hudson/model/AbstractBuildTest.groovy +++ b/test/src/test/groovy/hudson/model/AbstractBuildTest.groovy @@ -151,6 +151,30 @@ public class AbstractBuildTest { assertThat(log, containsString("Build step 'Bogus' marked build as failure")); } + @Test void fixEmptyDisplayName() { + FreeStyleProject p = j.createFreeStyleProject("foo"); + p.setDisplayName(""); + assertEquals("An empty display name should be ignored.", "foo", p.getDisplayName()); + } + + @Test void fixBlankDisplayName() { + FreeStyleProject p = j.createFreeStyleProject("foo"); + p.setDisplayName(" "); + assertEquals("A blank display name should be ignored.", "foo", p.getDisplayName()); + } + + @Test void validDisplayName() { + FreeStyleProject p = j.createFreeStyleProject("foo"); + p.setDisplayName("bar"); + assertEquals("A non-blank display name should be used.", "bar", p.getDisplayName()); + } + + @Test void trimValidDisplayName() { + FreeStyleProject p = j.createFreeStyleProject("foo"); + p.setDisplayName(" bar "); + assertEquals("A non-blank display name with whitespace should be trimmed.", "bar", p.getDisplayName()); + } + private static class ThrowBuilder extends org.jvnet.hudson.test.TestBuilder { @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { throw new NullPointerException(); From 6aabbbd282083716d631be7f2fa07ce93b93ee23 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 21 Oct 2015 12:38:25 -0400 Subject: [PATCH 0696/2573] Provide a default implementation of Descriptor.getDisplayName. --- .../console/ConsoleAnnotationDescriptor.java | 5 ++++- .../main/java/hudson/model/ComputerSet.java | 5 ----- .../main/java/hudson/model/Descriptor.java | 5 ++++- .../main/java/hudson/model/PageDecorator.java | 8 -------- .../hudson/model/PaneStatusProperties.java | 5 ----- .../hudson/model/TopLevelItemDescriptor.java | 5 ++++- .../java/hudson/model/ViewDescriptor.java | 5 ++++- .../java/hudson/slaves/RetentionStrategy.java | 7 +------ .../jenkins/model/GlobalConfiguration.java | 8 -------- core/src/main/java/jenkins/model/Jenkins.java | 4 ---- .../LastGrantedAuthoritiesProperty.java | 4 ---- .../hudson/test/ComputerConnectorTester.java | 7 +------ .../test/ExtractResourceWithChangesSCM.java | 6 +----- .../org/jvnet/hudson/test/FailureBuilder.java | 3 --- .../jvnet/hudson/test/FakeChangeLogSCM.java | 6 +----- .../org/jvnet/hudson/test/HudsonTestCase.java | 5 ----- .../test/JenkinsComputerConnectorTester.java | 7 +------ .../org/jvnet/hudson/test/JenkinsRule.java | 5 ----- .../org/jvnet/hudson/test/MockBuilder.java | 4 ---- .../org/jvnet/hudson/test/MockFolder.java | 4 ---- .../test/MockQueueItemAuthenticator.java | 8 +------- .../org/jvnet/hudson/test/PretendSlave.java | 6 +----- .../org/jvnet/hudson/test/SleepBuilder.java | 6 +----- .../org/jvnet/hudson/test/TestBuilder.java | 5 ----- .../jvnet/hudson/test/TestCrumbIssuer.java | 5 ----- .../org/jvnet/hudson/test/TestNotifier.java | 5 ----- .../jvnet/hudson/test/UnstableBuilder.java | 3 --- .../groovy/hudson/RelativePathTest.groovy | 12 +---------- .../groovy/hudson/cli/BuildCommandTest.groovy | 8 +------- .../hudson/model/AbstractProjectTest.groovy | 11 +--------- .../jenkins/bugs/Jenkins19124Test.groovy | 5 ----- .../test/groovy/lib/form/TextAreaTest.groovy | 5 ----- .../test/java/hudson/ExtensionListTest.java | 6 +----- .../src/test/java/hudson/ProcStarterTest.java | 6 +----- .../hudson/console/ConsoleAnnotatorTest.java | 17 ++-------------- .../hudson/markup/MarkupFormatterTest.java | 7 +------ .../java/hudson/model/AbstractBuildTest2.java | 8 +------- .../java/hudson/model/DescriptorTest.java | 16 ++------------- .../test/java/hudson/model/HelpLinkTest.java | 4 ---- .../test/java/hudson/model/HudsonTest.java | 6 +----- .../java/hudson/model/ItemGroupMixInTest.java | 15 -------------- .../java/hudson/model/JobPropertyTest.java | 15 ++------------ .../test/java/hudson/model/ProjectTest.java | 6 +----- .../src/test/java/hudson/model/QueueTest.java | 12 +---------- .../model/RunParameterDefinitionTest.java | 6 +----- .../java/hudson/model/UserPropertyTest.java | 8 -------- test/src/test/java/hudson/model/UserTest.java | 9 --------- .../test/java/hudson/model/ViewJobTest.java | 4 ---- .../java/hudson/model/ViewPropertyTest.java | 14 ++----------- .../model/labels/LabelAtomPropertyTest.java | 7 +------ .../model/utils/AbortExceptionPublisher.java | 2 -- .../model/utils/IOExceptionPublisher.java | 2 -- .../model/utils/ResultWriterPublisher.java | 2 -- .../model/utils/TrueFalsePublisher.java | 2 -- .../pages/SystemConfigurationTestCase.java | 5 ----- .../java/hudson/slaves/NodePropertyTest.java | 14 ++----------- .../java/hudson/tasks/LogRotatorTest.java | 6 +----- .../hudson/triggers/TriggerStartTest.java | 4 ---- .../hudson/util/FormFieldValidatorTest.java | 4 ---- .../jenkins/scm/SCMCheckoutStrategyTest.java | 5 ----- .../jenkins/tasks/SimpleBuildWrapperTest.java | 12 ----------- test/src/test/java/lib/form/ComboBoxTest.java | 8 +------- test/src/test/java/lib/form/PasswordTest.java | 6 +----- .../java/lib/form/RepeatablePropertyTest.java | 11 +--------- .../test/java/lib/form/RepeatableTest.java | 3 --- .../java/lib/form/RowVisibilityGroupTest.java | 20 +++---------------- .../java/lib/form/ValidateButtonTest.java | 4 ---- 67 files changed, 53 insertions(+), 410 deletions(-) diff --git a/core/src/main/java/hudson/console/ConsoleAnnotationDescriptor.java b/core/src/main/java/hudson/console/ConsoleAnnotationDescriptor.java index b4e260b6af..d5ac508136 100644 --- a/core/src/main/java/hudson/console/ConsoleAnnotationDescriptor.java +++ b/core/src/main/java/hudson/console/ConsoleAnnotationDescriptor.java @@ -55,7 +55,10 @@ public abstract class ConsoleAnnotationDescriptor extends Descriptor { - @Override - public String getDisplayName() { - return ""; - } - /** * Auto-completion for the "copy from" field in the new job page. */ diff --git a/core/src/main/java/hudson/model/Descriptor.java b/core/src/main/java/hudson/model/Descriptor.java index 4c5693b933..29ee1e4dd5 100644 --- a/core/src/main/java/hudson/model/Descriptor.java +++ b/core/src/main/java/hudson/model/Descriptor.java @@ -293,8 +293,11 @@ public abstract class Descriptor> implements Saveable { /** * Human readable name of this kind of configurable object. + * By default, it uses {@link Class#getSimpleName} on {@link #clazz}, but this should be overridden for visible descriptors. */ - public abstract String getDisplayName(); + public String getDisplayName() { + return clazz.getSimpleName(); + } /** * Uniquely identifies this {@link Descriptor} among all the other {@link Descriptor}s. diff --git a/core/src/main/java/hudson/model/PageDecorator.java b/core/src/main/java/hudson/model/PageDecorator.java index 849ef199fc..550db5805d 100644 --- a/core/src/main/java/hudson/model/PageDecorator.java +++ b/core/src/main/java/hudson/model/PageDecorator.java @@ -96,14 +96,6 @@ public abstract class PageDecorator extends Descriptor implements return this; } - /** - * Unless this object has additional web presence, display name is not used at all. - * So default to "". - */ - public String getDisplayName() { - return ""; - } - /** * Obtains the URL of this object, excluding the context path. * diff --git a/core/src/main/java/hudson/model/PaneStatusProperties.java b/core/src/main/java/hudson/model/PaneStatusProperties.java index 9f8be77227..8ee6cd3539 100644 --- a/core/src/main/java/hudson/model/PaneStatusProperties.java +++ b/core/src/main/java/hudson/model/PaneStatusProperties.java @@ -51,11 +51,6 @@ public class PaneStatusProperties extends UserProperty implements Saveable { return new PaneStatusProperties(); } - @Override - public String getDisplayName() { - return null; - } - @Override public boolean isEnabled() { return false; diff --git a/core/src/main/java/hudson/model/TopLevelItemDescriptor.java b/core/src/main/java/hudson/model/TopLevelItemDescriptor.java index 44c4201573..272c609c2b 100644 --- a/core/src/main/java/hudson/model/TopLevelItemDescriptor.java +++ b/core/src/main/java/hudson/model/TopLevelItemDescriptor.java @@ -108,7 +108,10 @@ public abstract class TopLevelItemDescriptor extends Descriptor { * script, which will be used to render the text below the caption * that explains the item type. */ - public abstract String getDisplayName(); + @Override + public String getDisplayName() { + return super.getDisplayName(); + } /** * @deprecated since 2007-01-19. diff --git a/core/src/main/java/hudson/model/ViewDescriptor.java b/core/src/main/java/hudson/model/ViewDescriptor.java index b8e6344365..2f304fa90f 100644 --- a/core/src/main/java/hudson/model/ViewDescriptor.java +++ b/core/src/main/java/hudson/model/ViewDescriptor.java @@ -45,7 +45,10 @@ public abstract class ViewDescriptor extends Descriptor { * in the view creation screen. The string should look like * "Abc Def Ghi". */ - public abstract String getDisplayName(); + @Override + public String getDisplayName() { + return super.getDisplayName(); + } /** * Some special views are not instantiable, and for those diff --git a/core/src/main/java/hudson/slaves/RetentionStrategy.java b/core/src/main/java/hudson/slaves/RetentionStrategy.java index 106d1a90c2..7b9f945577 100644 --- a/core/src/main/java/hudson/slaves/RetentionStrategy.java +++ b/core/src/main/java/hudson/slaves/RetentionStrategy.java @@ -28,7 +28,6 @@ import hudson.Util; import hudson.DescriptorExtensionList; import hudson.Extension; import hudson.model.*; -import hudson.model.Queue.*; import hudson.util.DescriptorList; import java.util.Collections; import java.util.HashMap; @@ -139,11 +138,7 @@ public abstract class RetentionStrategy extends AbstractDesc private final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); - class DescriptorImpl extends Descriptor> { - public String getDisplayName() { - return ""; - } - } + class DescriptorImpl extends Descriptor> {} }; /** diff --git a/core/src/main/java/jenkins/model/GlobalConfiguration.java b/core/src/main/java/jenkins/model/GlobalConfiguration.java index 92eabc4ea7..15cc69f831 100644 --- a/core/src/main/java/jenkins/model/GlobalConfiguration.java +++ b/core/src/main/java/jenkins/model/GlobalConfiguration.java @@ -51,14 +51,6 @@ public abstract class GlobalConfiguration extends Descriptor { - @Override - public String getDisplayName() { - return ""; - } - } + public static class DescriptorImpl extends Descriptor {} } diff --git a/test/src/main/java/org/jvnet/hudson/test/ExtractResourceWithChangesSCM.java b/test/src/main/java/org/jvnet/hudson/test/ExtractResourceWithChangesSCM.java index 52d2cffea3..0c01c35a98 100644 --- a/test/src/main/java/org/jvnet/hudson/test/ExtractResourceWithChangesSCM.java +++ b/test/src/main/java/org/jvnet/hudson/test/ExtractResourceWithChangesSCM.java @@ -142,11 +142,7 @@ public class ExtractResourceWithChangesSCM extends NullSCM { private Object writeReplace() { return new Object(); } @Override public SCMDescriptor getDescriptor() { - return new SCMDescriptor(ExtractResourceWithChangesSCM.class, null) { - @Override public String getDisplayName() { - return "ExtractResourceWithChangesSCM"; - } - }; + return new SCMDescriptor(ExtractResourceWithChangesSCM.class, null) {}; } } diff --git a/test/src/main/java/org/jvnet/hudson/test/FailureBuilder.java b/test/src/main/java/org/jvnet/hudson/test/FailureBuilder.java index 7caa45305c..ec74d11280 100644 --- a/test/src/main/java/org/jvnet/hudson/test/FailureBuilder.java +++ b/test/src/main/java/org/jvnet/hudson/test/FailureBuilder.java @@ -42,9 +42,6 @@ public class FailureBuilder extends MockBuilder { @Extension public static final class DescriptorImpl extends Descriptor { - public String getDisplayName() { - return "Always fail"; - } public FailureBuilder newInstance(StaplerRequest req, JSONObject data) { return new FailureBuilder(); } diff --git a/test/src/main/java/org/jvnet/hudson/test/FakeChangeLogSCM.java b/test/src/main/java/org/jvnet/hudson/test/FakeChangeLogSCM.java index e569e35ac8..0ad8d74f3b 100644 --- a/test/src/main/java/org/jvnet/hudson/test/FakeChangeLogSCM.java +++ b/test/src/main/java/org/jvnet/hudson/test/FakeChangeLogSCM.java @@ -77,11 +77,7 @@ public class FakeChangeLogSCM extends NullSCM { } @Override public SCMDescriptor getDescriptor() { - return new SCMDescriptor(null) { - @Override public String getDisplayName() { - return ""; - } - }; + return new SCMDescriptor(null) {}; } public static class ChangelogAction extends InvisibleAction { 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 e17372122c..dc394fd38e 100644 --- a/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java +++ b/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java @@ -2049,11 +2049,6 @@ public abstract class HudsonTestCase extends TestCase implements RootAction { public BuildWrapper newInstance(StaplerRequest req, JSONObject formData) { throw new UnsupportedOperationException(); } - - @Override - public String getDisplayName() { - return this.getClass().getName(); - } } } } diff --git a/test/src/main/java/org/jvnet/hudson/test/JenkinsComputerConnectorTester.java b/test/src/main/java/org/jvnet/hudson/test/JenkinsComputerConnectorTester.java index 1acdb2b2a2..f3a2e98f3d 100644 --- a/test/src/main/java/org/jvnet/hudson/test/JenkinsComputerConnectorTester.java +++ b/test/src/main/java/org/jvnet/hudson/test/JenkinsComputerConnectorTester.java @@ -58,10 +58,5 @@ public class JenkinsComputerConnectorTester extends AbstractDescribableImpl { - @Override - public String getDisplayName() { - return ""; - } - } + public static class DescriptorImpl extends Descriptor {} } 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 58b305b860..75d06ab872 100644 --- a/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java +++ b/test/src/main/java/org/jvnet/hudson/test/JenkinsRule.java @@ -2358,11 +2358,6 @@ public class JenkinsRule implements TestRule, MethodRule, RootAction { public BuildWrapper newInstance(StaplerRequest req, JSONObject formData) { throw new UnsupportedOperationException(); } - - @Override - public String getDisplayName() { - return this.getClass().getName(); - } } } diff --git a/test/src/main/java/org/jvnet/hudson/test/MockBuilder.java b/test/src/main/java/org/jvnet/hudson/test/MockBuilder.java index fad81e9d5c..2a57ad33bb 100644 --- a/test/src/main/java/org/jvnet/hudson/test/MockBuilder.java +++ b/test/src/main/java/org/jvnet/hudson/test/MockBuilder.java @@ -41,10 +41,6 @@ public class MockBuilder extends Builder { public Builder newInstance(StaplerRequest req, JSONObject data) { throw new UnsupportedOperationException(); } - - public String getDisplayName() { - return "Force the build result"; - } } } diff --git a/test/src/main/java/org/jvnet/hudson/test/MockFolder.java b/test/src/main/java/org/jvnet/hudson/test/MockFolder.java index af96c50bc2..c3b94cbbc9 100644 --- a/test/src/main/java/org/jvnet/hudson/test/MockFolder.java +++ b/test/src/main/java/org/jvnet/hudson/test/MockFolder.java @@ -271,10 +271,6 @@ public class MockFolder extends AbstractItem implements DirectlyModifiableTopLev @Extension public static class DescriptorImpl extends TopLevelItemDescriptor { - @Override public String getDisplayName() { - return "MockFolder"; - } - @Override public TopLevelItem newInstance(ItemGroup parent, String name) { return new MockFolder(parent, name); } diff --git a/test/src/main/java/org/jvnet/hudson/test/MockQueueItemAuthenticator.java b/test/src/main/java/org/jvnet/hudson/test/MockQueueItemAuthenticator.java index 844281afac..c0202908c9 100644 --- a/test/src/main/java/org/jvnet/hudson/test/MockQueueItemAuthenticator.java +++ b/test/src/main/java/org/jvnet/hudson/test/MockQueueItemAuthenticator.java @@ -61,12 +61,6 @@ public final class MockQueueItemAuthenticator extends QueueItemAuthenticator { } } - @Extension public static final class DescriptorImpl extends QueueItemAuthenticatorDescriptor { - - @Override public String getDisplayName() { - return "MockQueueItemAuthenticator"; - } - - } + @Extension public static final class DescriptorImpl extends QueueItemAuthenticatorDescriptor {} } diff --git a/test/src/main/java/org/jvnet/hudson/test/PretendSlave.java b/test/src/main/java/org/jvnet/hudson/test/PretendSlave.java index 13f05d427f..c284aefe89 100644 --- a/test/src/main/java/org/jvnet/hudson/test/PretendSlave.java +++ b/test/src/main/java/org/jvnet/hudson/test/PretendSlave.java @@ -53,9 +53,5 @@ public class PretendSlave extends Slave { } @Extension - public static final class DescriptorImpl extends SlaveDescriptor { - public String getDisplayName() { - return "Test mock up slave"; - } - } + public static final class DescriptorImpl extends SlaveDescriptor {} } diff --git a/test/src/main/java/org/jvnet/hudson/test/SleepBuilder.java b/test/src/main/java/org/jvnet/hudson/test/SleepBuilder.java index 9d2176aede..ce2052f3a1 100644 --- a/test/src/main/java/org/jvnet/hudson/test/SleepBuilder.java +++ b/test/src/main/java/org/jvnet/hudson/test/SleepBuilder.java @@ -53,9 +53,5 @@ public class SleepBuilder extends Builder { } @Extension - public static final class DescriptorImpl extends Descriptor { - public String getDisplayName() { - return "Sleep"; - } - } + public static final class DescriptorImpl extends Descriptor {} } diff --git a/test/src/main/java/org/jvnet/hudson/test/TestBuilder.java b/test/src/main/java/org/jvnet/hudson/test/TestBuilder.java index f0d0983254..a466e4d4ab 100644 --- a/test/src/main/java/org/jvnet/hudson/test/TestBuilder.java +++ b/test/src/main/java/org/jvnet/hudson/test/TestBuilder.java @@ -53,11 +53,6 @@ public abstract class TestBuilder extends Builder { public boolean isApplicable(Class jobType) { return true; } - - @Override - public String getDisplayName() { - return "Bogus"; - } }; } diff --git a/test/src/main/java/org/jvnet/hudson/test/TestCrumbIssuer.java b/test/src/main/java/org/jvnet/hudson/test/TestCrumbIssuer.java index 93e081330e..3160f0f413 100644 --- a/test/src/main/java/org/jvnet/hudson/test/TestCrumbIssuer.java +++ b/test/src/main/java/org/jvnet/hudson/test/TestCrumbIssuer.java @@ -42,11 +42,6 @@ public class TestCrumbIssuer extends CrumbIssuer load(); } - @Override - public String getDisplayName() { - return "Test Crumb"; - } - public TestCrumbIssuer newInstance(StaplerRequest req, JSONObject formData) throws FormException { return new TestCrumbIssuer(); } diff --git a/test/src/main/java/org/jvnet/hudson/test/TestNotifier.java b/test/src/main/java/org/jvnet/hudson/test/TestNotifier.java index 7e138ee2a6..91fd8a4862 100644 --- a/test/src/main/java/org/jvnet/hudson/test/TestNotifier.java +++ b/test/src/main/java/org/jvnet/hudson/test/TestNotifier.java @@ -41,11 +41,6 @@ public abstract class TestNotifier extends Notifier { public boolean isApplicable(Class jobType) { return true; } - - @Override - public String getDisplayName() { - return "Bogus"; - } }; } diff --git a/test/src/main/java/org/jvnet/hudson/test/UnstableBuilder.java b/test/src/main/java/org/jvnet/hudson/test/UnstableBuilder.java index 0bf6d0a1c9..cca54539e9 100644 --- a/test/src/main/java/org/jvnet/hudson/test/UnstableBuilder.java +++ b/test/src/main/java/org/jvnet/hudson/test/UnstableBuilder.java @@ -42,9 +42,6 @@ public class UnstableBuilder extends MockBuilder { @Extension public static final class DescriptorImpl extends Descriptor { - public String getDisplayName() { - return "Make build unstable"; - } public UnstableBuilder newInstance(StaplerRequest req, JSONObject data) { return new UnstableBuilder(); } diff --git a/test/src/test/groovy/hudson/RelativePathTest.groovy b/test/src/test/groovy/hudson/RelativePathTest.groovy index a6a865f6a0..25902f811c 100644 --- a/test/src/test/groovy/hudson/RelativePathTest.groovy +++ b/test/src/test/groovy/hudson/RelativePathTest.groovy @@ -38,23 +38,13 @@ class RelativePathTest extends HudsonTestCase implements Describable { - @Override - String getDisplayName() { - return ""; - } - } + static class DescriptorImpl extends Descriptor {} static class Model extends AbstractDescribableImpl { @TestExtension static class DescriptorImpl extends Descriptor { boolean touched; - @Override - String getDisplayName() { - return "test"; - } - ListBoxModel doFillAbcItems(@RelativePath("..") @QueryParameter String name) { assert name=="Alice"; touched = true; diff --git a/test/src/test/groovy/hudson/cli/BuildCommandTest.groovy b/test/src/test/groovy/hudson/cli/BuildCommandTest.groovy index bec4c67584..733726b553 100644 --- a/test/src/test/groovy/hudson/cli/BuildCommandTest.groovy +++ b/test/src/test/groovy/hudson/cli/BuildCommandTest.groovy @@ -292,12 +292,6 @@ public class BuildCommandTest { } @Extension - public static class DescriptorImpl extends ParameterDescriptor { - - @Override - public String getDisplayName() { - return "Parameter with the default NULL value"; - } - } + public static class DescriptorImpl extends ParameterDescriptor {} } } diff --git a/test/src/test/groovy/hudson/model/AbstractProjectTest.groovy b/test/src/test/groovy/hudson/model/AbstractProjectTest.groovy index a273a8bfaf..c25abfa5e6 100644 --- a/test/src/test/groovy/hudson/model/AbstractProjectTest.groovy +++ b/test/src/test/groovy/hudson/model/AbstractProjectTest.groovy @@ -193,11 +193,7 @@ public class AbstractProjectTest extends HudsonTestCase { return true; } @Override public SCMDescriptor getDescriptor() { - return new SCMDescriptor(null) { - @Override public String getDisplayName() { - return ""; - } - }; + return new SCMDescriptor(null) {}; } }; Thread t = new Thread() { @@ -626,11 +622,6 @@ public class AbstractProjectTest extends HudsonTestCase { public boolean isApplicable(hudson.model.Item item) { return false; } - - @Override - String getDisplayName() { - return "test"; - } } } } diff --git a/test/src/test/groovy/jenkins/bugs/Jenkins19124Test.groovy b/test/src/test/groovy/jenkins/bugs/Jenkins19124Test.groovy index b4c5c5fc9c..352b3144f0 100644 --- a/test/src/test/groovy/jenkins/bugs/Jenkins19124Test.groovy +++ b/test/src/test/groovy/jenkins/bugs/Jenkins19124Test.groovy @@ -71,11 +71,6 @@ class Jenkins19124Test { super(Foo.class) } - @Override - String getDisplayName() { - return "---"; - } - FormValidation doCheckAlpha(@QueryParameter String value, @QueryParameter String bravo) { this.alpha = value; this.bravo = bravo; diff --git a/test/src/test/groovy/lib/form/TextAreaTest.groovy b/test/src/test/groovy/lib/form/TextAreaTest.groovy index d3bc537212..02275f68e0 100644 --- a/test/src/test/groovy/lib/form/TextAreaTest.groovy +++ b/test/src/test/groovy/lib/form/TextAreaTest.groovy @@ -62,11 +62,6 @@ class TextAreaTest { this.text2 = "Received "+text1; return FormValidation.ok(); } - - @Override - String getDisplayName() { - return this.class.name; - } } } diff --git a/test/src/test/java/hudson/ExtensionListTest.java b/test/src/test/java/hudson/ExtensionListTest.java index 791eef3e40..398b7502ad 100644 --- a/test/src/test/java/hudson/ExtensionListTest.java +++ b/test/src/test/java/hudson/ExtensionListTest.java @@ -90,11 +90,7 @@ public class ExtensionListTest { // // - public static abstract class FishDescriptor extends Descriptor { - public String getDisplayName() { - return clazz.getName(); - } - } + public static abstract class FishDescriptor extends Descriptor {} public static abstract class Fish implements Describable { public Descriptor getDescriptor() { diff --git a/test/src/test/java/hudson/ProcStarterTest.java b/test/src/test/java/hudson/ProcStarterTest.java index e93dd71d1f..6122655802 100644 --- a/test/src/test/java/hudson/ProcStarterTest.java +++ b/test/src/test/java/hudson/ProcStarterTest.java @@ -33,6 +33,7 @@ import hudson.tasks.BuildWrapperDescriptor; import java.io.IOException; import org.jvnet.hudson.test.Issue; import hudson.Launcher.DecoratedLauncher; +import hudson.Launcher.ProcStarter; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; @@ -72,11 +73,6 @@ public class ProcStarterTest { public boolean isApplicable(AbstractProject ap) { return true; } - - @Override - public String getDisplayName() { - return "testStub"; - } } /** diff --git a/test/src/test/java/hudson/console/ConsoleAnnotatorTest.java b/test/src/test/java/hudson/console/ConsoleAnnotatorTest.java index 83827f4860..b2315702e0 100644 --- a/test/src/test/java/hudson/console/ConsoleAnnotatorTest.java +++ b/test/src/test/java/hudson/console/ConsoleAnnotatorTest.java @@ -272,11 +272,7 @@ public class ConsoleAnnotatorTest { } @TestExtension - public static final class DescriptorImpl extends ConsoleAnnotationDescriptor { - public String getDisplayName() { - return "Dollar mark"; - } - } + public static final class DescriptorImpl extends ConsoleAnnotationDescriptor {} } @@ -299,11 +295,7 @@ public class ConsoleAnnotatorTest { } @TestExtension("scriptInclusion") - public static final class DescriptorImpl extends ConsoleAnnotationDescriptor { - public String getDisplayName() { - return "just to include a script"; - } - } + public static final class DescriptorImpl extends ConsoleAnnotationDescriptor {} } @TestExtension("scriptInclusion") @@ -374,11 +366,6 @@ public class ConsoleAnnotatorTest { public DescriptorImpl() { super(PollingSCM.class, RepositoryBrowser.class); } - - @Override - public String getDisplayName() { - return "Test SCM"; - } } } } diff --git a/test/src/test/java/hudson/markup/MarkupFormatterTest.java b/test/src/test/java/hudson/markup/MarkupFormatterTest.java index 9410ffe5ba..7252bf6ca5 100644 --- a/test/src/test/java/hudson/markup/MarkupFormatterTest.java +++ b/test/src/test/java/hudson/markup/MarkupFormatterTest.java @@ -67,11 +67,6 @@ public class MarkupFormatterTest { } @TestExtension - public static class DescriptorImpl extends MarkupFormatterDescriptor { - @Override - public String getDisplayName() { - return "dummy"; - } - } + public static class DescriptorImpl extends MarkupFormatterDescriptor {} } } diff --git a/test/src/test/java/hudson/model/AbstractBuildTest2.java b/test/src/test/java/hudson/model/AbstractBuildTest2.java index 830d491758..9f3504be0a 100644 --- a/test/src/test/java/hudson/model/AbstractBuildTest2.java +++ b/test/src/test/java/hudson/model/AbstractBuildTest2.java @@ -71,12 +71,6 @@ public class AbstractBuildTest2 { } @TestExtension("reportErrorShouldNotFailForNonPublisherClass") - public static class DescriptorImpl extends JobPropertyDescriptor { - - @Override - public String getDisplayName() { - return "Always throws exception in perform()"; - } - } + public static class DescriptorImpl extends JobPropertyDescriptor {} } } diff --git a/test/src/test/java/hudson/model/DescriptorTest.java b/test/src/test/java/hudson/model/DescriptorTest.java index e3b1dba053..6c1707b8e8 100644 --- a/test/src/test/java/hudson/model/DescriptorTest.java +++ b/test/src/test/java/hudson/model/DescriptorTest.java @@ -107,9 +107,6 @@ public class DescriptorTest { @Override public Builder newInstance(StaplerRequest req, JSONObject formData) throws Descriptor.FormException { return new BuilderImpl(id); } - @Override public String getDisplayName() { - return id; - } @Override public boolean isApplicable(Class jobType) { return true; } @@ -130,14 +127,12 @@ public class DescriptorTest { public static class D1 extends D { @DataBoundConstructor public D1() {} @TestExtension("nestedDescribableOverridingId") public static class DescriptorImpl extends Descriptor { - @Override public String getDisplayName() {return "D 1";} @Override public String getId() {return "D1-id";} } } public static class D2 extends D { @DataBoundConstructor public D2() {} @TestExtension("nestedDescribableOverridingId") public static class DescriptorImpl extends Descriptor { - @Override public String getDisplayName() {return "D 2";} @Override public String getId() {return "D2-id";} } } @@ -150,9 +145,7 @@ public class DescriptorTest { listener.getLogger().println(ds); return true; } - @TestExtension("nestedDescribableOverridingId") public static class DescriptorImpl extends Descriptor { - @Override public String getDisplayName() {return "B1";} - } + @TestExtension("nestedDescribableOverridingId") public static class DescriptorImpl extends Descriptor {} } @Ignore("never worked: TypePair.convertJSON looks for @DataBoundConstructor on D3 (Stapler does not grok Descriptor)") @@ -187,9 +180,6 @@ public class DescriptorTest { @Override public D3 newInstance(StaplerRequest req, JSONObject formData) throws Descriptor.FormException { return new D3(id); } - @Override public String getDisplayName() { - return id; - } } @TestExtension("nestedDescribableSharingClass") public static final Descriptor d3a = new D3D("d3a"); @TestExtension("nestedDescribableSharingClass") public static final Descriptor d3b = new D3D("d3b"); @@ -202,9 +192,7 @@ public class DescriptorTest { listener.getLogger().println(ds); return true; } - @TestExtension("nestedDescribableSharingClass") public static class DescriptorImpl extends Descriptor { - @Override public String getDisplayName() {return "B2";} - } + @TestExtension("nestedDescribableSharingClass") public static class DescriptorImpl extends Descriptor {} } } diff --git a/test/src/test/java/hudson/model/HelpLinkTest.java b/test/src/test/java/hudson/model/HelpLinkTest.java index 92bbaacc14..2ec0eca93a 100644 --- a/test/src/test/java/hudson/model/HelpLinkTest.java +++ b/test/src/test/java/hudson/model/HelpLinkTest.java @@ -79,10 +79,6 @@ public class HelpLinkTest { public String getHelpFile() { return "no-such-file/exists"; } - - public String getDisplayName() { - return "I don't have the help file"; - } } public BuildStepMonitor getRequiredMonitorService() { diff --git a/test/src/test/java/hudson/model/HudsonTest.java b/test/src/test/java/hudson/model/HudsonTest.java index 5f5c006b59..97e3576b14 100644 --- a/test/src/test/java/hudson/model/HudsonTest.java +++ b/test/src/test/java/hudson/model/HudsonTest.java @@ -184,11 +184,7 @@ public class HudsonTest { @Test @Email("http://www.nabble.com/1.286-version-and-description-The-requested-resource-%28%29-is-not--available.-td22233801.html") public void legacyDescriptorLookup() throws Exception { - Descriptor dummy = new Descriptor(HudsonTest.class) { - public String getDisplayName() { - return "dummy"; - } - }; + Descriptor dummy = new Descriptor(HudsonTest.class) {}; BuildStep.PUBLISHERS.addRecorder(dummy); assertSame(dummy, j.jenkins.getDescriptor(HudsonTest.class.getName())); diff --git a/test/src/test/java/hudson/model/ItemGroupMixInTest.java b/test/src/test/java/hudson/model/ItemGroupMixInTest.java index 8b26e332f1..0eb876d925 100644 --- a/test/src/test/java/hudson/model/ItemGroupMixInTest.java +++ b/test/src/test/java/hudson/model/ItemGroupMixInTest.java @@ -129,11 +129,6 @@ public class ItemGroupMixInTest { public boolean isApplicable(AbstractProject item) { return true; } - - @Override - public String getDisplayName() { - return null; - } } } @@ -150,11 +145,6 @@ public class ItemGroupMixInTest { public boolean isApplicable(Class jobType) { return false; } - - @Override - public String getDisplayName() { - return null; - } } } @@ -187,11 +177,6 @@ public class ItemGroupMixInTest { public boolean isApplicable(Class jobType) { return false; } - - @Override - public String getDisplayName() { - return null; - } } } } diff --git a/test/src/test/java/hudson/model/JobPropertyTest.java b/test/src/test/java/hudson/model/JobPropertyTest.java index f8d7cdf5d8..63e57834d8 100644 --- a/test/src/test/java/hudson/model/JobPropertyTest.java +++ b/test/src/test/java/hudson/model/JobPropertyTest.java @@ -89,11 +89,6 @@ public class JobPropertyTest { public boolean isApplicable(Class jobType) { return false; } - - @Override - public String getDisplayName() { - return "Fake job property"; - } } } @@ -120,10 +115,7 @@ public class JobPropertyTest { } @TestExtension("configRoundtrip") - public static class DescriptorImpl extends JobPropertyDescriptor { - @Override - public String getDisplayName() { return null; } - } + public static class DescriptorImpl extends JobPropertyDescriptor {} } @Test @@ -147,9 +139,6 @@ public class JobPropertyTest { } @TestExtension("invisibleProperty") - public static class DescriptorImpl extends JobPropertyDescriptor { - @Override - public String getDisplayName() { return null; } - } + public static class DescriptorImpl extends JobPropertyDescriptor {} } } diff --git a/test/src/test/java/hudson/model/ProjectTest.java b/test/src/test/java/hudson/model/ProjectTest.java index 209e162117..88e7a1304f 100644 --- a/test/src/test/java/hudson/model/ProjectTest.java +++ b/test/src/test/java/hudson/model/ProjectTest.java @@ -836,11 +836,7 @@ public class ProjectTest { return true; } @Override public SCMDescriptor getDescriptor() { - return new SCMDescriptor(null) { - @Override public String getDisplayName() { - return ""; - } - }; + return new SCMDescriptor(null) {}; } @Override diff --git a/test/src/test/java/hudson/model/QueueTest.java b/test/src/test/java/hudson/model/QueueTest.java index 56a23a7839..3cc1ebf872 100644 --- a/test/src/test/java/hudson/model/QueueTest.java +++ b/test/src/test/java/hudson/model/QueueTest.java @@ -658,11 +658,6 @@ public class QueueTest { } }; } - - @Override - public String getDisplayName() { - return "simulate-error"; - } }; FreeStyleProject projectError = (FreeStyleProject) r.jenkins.createProject(descriptor, "throw-error"); project1.setAssignedLabel(r.jenkins.getSelfLabel()); @@ -894,11 +889,6 @@ public class QueueTest { } @TestExtension("shouldBeAbleToBlockFlyWeightTaskOnLastMinute") - public static class DescriptorImpl extends NodePropertyDescriptor { - @Override - public String getDisplayName() { - return "Some Property"; - } - } + public static class DescriptorImpl extends NodePropertyDescriptor {} } } diff --git a/test/src/test/java/hudson/model/RunParameterDefinitionTest.java b/test/src/test/java/hudson/model/RunParameterDefinitionTest.java index dde065fcae..971f5ff98b 100644 --- a/test/src/test/java/hudson/model/RunParameterDefinitionTest.java +++ b/test/src/test/java/hudson/model/RunParameterDefinitionTest.java @@ -279,11 +279,7 @@ public class RunParameterDefinitionTest { } public Descriptor getDescriptor() { - return new Descriptor(ResultPublisher.class) { - public String getDisplayName() { - return "ResultPublisher"; - } - }; + return new Descriptor(ResultPublisher.class) {}; } } } diff --git a/test/src/test/java/hudson/model/UserPropertyTest.java b/test/src/test/java/hudson/model/UserPropertyTest.java index 650dbc3073..db57529a4e 100644 --- a/test/src/test/java/hudson/model/UserPropertyTest.java +++ b/test/src/test/java/hudson/model/UserPropertyTest.java @@ -29,10 +29,6 @@ public class UserPropertyTest { public static class UserProperty1 extends UserProperty { @TestExtension public static class DescriptorImpl extends UserPropertyDescriptor { - public String getDisplayName() { - return "UserProperty1"; - } - @Override public UserProperty newInstance(User user) { return new UserProperty1(); @@ -43,10 +39,6 @@ public class UserPropertyTest { public static class UserProperty2 extends UserProperty { @TestExtension public static class DescriptorImpl extends UserPropertyDescriptor { - public String getDisplayName() { - return "UserProperty2"; - } - @Override public boolean isEnabled() { return false; diff --git a/test/src/test/java/hudson/model/UserTest.java b/test/src/test/java/hudson/model/UserTest.java index afc67d0131..a823b21098 100644 --- a/test/src/test/java/hudson/model/UserTest.java +++ b/test/src/test/java/hudson/model/UserTest.java @@ -101,11 +101,6 @@ public class UserTest { public UserProperty newInstance(User user) { return null; } - - @Override - public String getDisplayName() { - return "Property"; - } } } @@ -546,10 +541,6 @@ public class UserTest { @TestExtension public static class DescriptorImpl extends UserPropertyDescriptor { - public String getDisplayName() { - return "UserProperty1"; - } - @Override public UserProperty newInstance(User user) { return new SomeUserProperty(); diff --git a/test/src/test/java/hudson/model/ViewJobTest.java b/test/src/test/java/hudson/model/ViewJobTest.java index 6432631ea7..5328530847 100644 --- a/test/src/test/java/hudson/model/ViewJobTest.java +++ b/test/src/test/java/hudson/model/ViewJobTest.java @@ -69,10 +69,6 @@ public class ViewJobTest { @TestExtension public static final class DescriptorImpl extends TopLevelItemDescriptor { - @Override public String getDisplayName() { - return "J"; - } - @Override public TopLevelItem newInstance(ItemGroup parent, String name) { return new J(parent, name); } diff --git a/test/src/test/java/hudson/model/ViewPropertyTest.java b/test/src/test/java/hudson/model/ViewPropertyTest.java index 7524865984..5ca1352149 100644 --- a/test/src/test/java/hudson/model/ViewPropertyTest.java +++ b/test/src/test/java/hudson/model/ViewPropertyTest.java @@ -65,12 +65,7 @@ public class ViewPropertyTest extends HudsonTestCase { } @TestExtension - public static class DescriptorImpl extends ViewPropertyDescriptor { - @Override - public String getDisplayName() { - return "Debug Property"; - } - } + public static class DescriptorImpl extends ViewPropertyDescriptor {} } public void testInvisibleProperty() throws Exception { @@ -98,11 +93,6 @@ public class ViewPropertyTest extends HudsonTestCase { } @TestExtension - public static class DescriptorImpl extends ViewPropertyDescriptor { - @Override - public String getDisplayName() { - return null; - } - } + public static class DescriptorImpl extends ViewPropertyDescriptor {} } } diff --git a/test/src/test/java/hudson/model/labels/LabelAtomPropertyTest.java b/test/src/test/java/hudson/model/labels/LabelAtomPropertyTest.java index 4f8c0b9301..a92fc185d9 100644 --- a/test/src/test/java/hudson/model/labels/LabelAtomPropertyTest.java +++ b/test/src/test/java/hudson/model/labels/LabelAtomPropertyTest.java @@ -49,12 +49,7 @@ public class LabelAtomPropertyTest { } @TestExtension - public static class DescriptorImpl extends LabelAtomPropertyDescriptor { - @Override - public String getDisplayName() { - return "Test label atom property"; - } - } + public static class DescriptorImpl extends LabelAtomPropertyDescriptor {} } /** diff --git a/test/src/test/java/hudson/model/utils/AbortExceptionPublisher.java b/test/src/test/java/hudson/model/utils/AbortExceptionPublisher.java index f634a07a1f..2efbb9e874 100644 --- a/test/src/test/java/hudson/model/utils/AbortExceptionPublisher.java +++ b/test/src/test/java/hudson/model/utils/AbortExceptionPublisher.java @@ -27,8 +27,6 @@ public class AbortExceptionPublisher extends Recorder { @Extension public static class DescriptorImpl extends BuildStepDescriptor { - @Override - public String getDisplayName() { return "ThrowAbortExceptionRecorder"; } @Override public boolean isApplicable(Class jobType) { return true; } } diff --git a/test/src/test/java/hudson/model/utils/IOExceptionPublisher.java b/test/src/test/java/hudson/model/utils/IOExceptionPublisher.java index 9e2ac8f208..72fd450a66 100644 --- a/test/src/test/java/hudson/model/utils/IOExceptionPublisher.java +++ b/test/src/test/java/hudson/model/utils/IOExceptionPublisher.java @@ -27,8 +27,6 @@ public class IOExceptionPublisher extends Recorder { @Extension public static class DescriptorImpl extends BuildStepDescriptor { - @Override - public String getDisplayName() { return "Throw IOException Publisher"; } @Override public boolean isApplicable(Class jobType) { return true; } } diff --git a/test/src/test/java/hudson/model/utils/ResultWriterPublisher.java b/test/src/test/java/hudson/model/utils/ResultWriterPublisher.java index 699baecc3b..4da1504e11 100644 --- a/test/src/test/java/hudson/model/utils/ResultWriterPublisher.java +++ b/test/src/test/java/hudson/model/utils/ResultWriterPublisher.java @@ -39,8 +39,6 @@ public class ResultWriterPublisher extends Recorder { @Extension public static class DescriptorImpl extends BuildStepDescriptor { - @Override - public String getDisplayName() { return "wrote result to file"; } @Override public boolean isApplicable(Class jobType) { return true; } } diff --git a/test/src/test/java/hudson/model/utils/TrueFalsePublisher.java b/test/src/test/java/hudson/model/utils/TrueFalsePublisher.java index 29393fcec4..e0b2d728f6 100644 --- a/test/src/test/java/hudson/model/utils/TrueFalsePublisher.java +++ b/test/src/test/java/hudson/model/utils/TrueFalsePublisher.java @@ -34,8 +34,6 @@ public class TrueFalsePublisher extends Recorder { @Extension public static class DescriptorImpl extends BuildStepDescriptor { - @Override - public String getDisplayName() { return "return true or false"; } @Override public boolean isApplicable(Class jobType) { return true; } } diff --git a/test/src/test/java/hudson/pages/SystemConfigurationTestCase.java b/test/src/test/java/hudson/pages/SystemConfigurationTestCase.java index 1cf5bb9253..d724a49927 100644 --- a/test/src/test/java/hudson/pages/SystemConfigurationTestCase.java +++ b/test/src/test/java/hudson/pages/SystemConfigurationTestCase.java @@ -74,11 +74,6 @@ public class SystemConfigurationTestCase { return true; } - @Override - public String getDisplayName() { - return "PageDecoratorImpl"; - } - public String getDecoratorId() { return decoratorId; } diff --git a/test/src/test/java/hudson/slaves/NodePropertyTest.java b/test/src/test/java/hudson/slaves/NodePropertyTest.java index 27e88fc58a..27cd4a73e3 100644 --- a/test/src/test/java/hudson/slaves/NodePropertyTest.java +++ b/test/src/test/java/hudson/slaves/NodePropertyTest.java @@ -52,12 +52,7 @@ public class NodePropertyTest { } @TestExtension("invisibleProperty") - public static class DescriptorImpl extends NodePropertyDescriptor { - @Override - public String getDisplayName() { - return null; - } - } + public static class DescriptorImpl extends NodePropertyDescriptor {} } @Test @@ -86,11 +81,6 @@ public class NodePropertyTest { } @TestExtension("basicConfigRoundtrip") - public static class DescriptorImpl extends NodePropertyDescriptor { - @Override - public String getDisplayName() { - return "Some Property"; - } - } + public static class DescriptorImpl extends NodePropertyDescriptor {} } } diff --git a/test/src/test/java/hudson/tasks/LogRotatorTest.java b/test/src/test/java/hudson/tasks/LogRotatorTest.java index e1df27f89c..d45259e23c 100644 --- a/test/src/test/java/hudson/tasks/LogRotatorTest.java +++ b/test/src/test/java/hudson/tasks/LogRotatorTest.java @@ -220,11 +220,7 @@ public class LogRotatorTest { } public Descriptor getDescriptor() { - return new Descriptor(TestsFail.class) { - public String getDisplayName() { - return "TestsFail"; - } - }; + return new Descriptor(TestsFail.class) {}; } } diff --git a/test/src/test/java/hudson/triggers/TriggerStartTest.java b/test/src/test/java/hudson/triggers/TriggerStartTest.java index 5946d8c799..981fcbe2b6 100644 --- a/test/src/test/java/hudson/triggers/TriggerStartTest.java +++ b/test/src/test/java/hudson/triggers/TriggerStartTest.java @@ -127,10 +127,6 @@ public class TriggerStartTest { return true; } - @Override public String getDisplayName() { - return "mock trigger"; - } - } } diff --git a/test/src/test/java/hudson/util/FormFieldValidatorTest.java b/test/src/test/java/hudson/util/FormFieldValidatorTest.java index 521ee8c70e..2bb203b078 100644 --- a/test/src/test/java/hudson/util/FormFieldValidatorTest.java +++ b/test/src/test/java/hudson/util/FormFieldValidatorTest.java @@ -63,10 +63,6 @@ public class FormFieldValidatorTest { public void doCheckXyz() { throw new Error("doCheckXyz is broken"); } - - public String getDisplayName() { - return "I have broken form field validation"; - } } public BuildStepMonitor getRequiredMonitorService() { diff --git a/test/src/test/java/jenkins/scm/SCMCheckoutStrategyTest.java b/test/src/test/java/jenkins/scm/SCMCheckoutStrategyTest.java index ccf3a506e9..53040ea328 100644 --- a/test/src/test/java/jenkins/scm/SCMCheckoutStrategyTest.java +++ b/test/src/test/java/jenkins/scm/SCMCheckoutStrategyTest.java @@ -74,11 +74,6 @@ public class SCMCheckoutStrategyTest { public boolean isApplicable(AbstractProject project) { return true; } - - @Override - public String getDisplayName() { - return getClass().getName(); - } } } } diff --git a/test/src/test/java/jenkins/tasks/SimpleBuildWrapperTest.java b/test/src/test/java/jenkins/tasks/SimpleBuildWrapperTest.java index 09869387cc..b6c086c061 100644 --- a/test/src/test/java/jenkins/tasks/SimpleBuildWrapperTest.java +++ b/test/src/test/java/jenkins/tasks/SimpleBuildWrapperTest.java @@ -87,9 +87,6 @@ public class SimpleBuildWrapperTest { context.env("PATH+STUFF", workspace.child("bin").getRemote()); } @TestExtension("envOverride") public static class DescriptorImpl extends BuildWrapperDescriptor { - @Override public String getDisplayName() { - return "WrapperWithEnvOverride"; - } @Override public boolean isApplicable(AbstractProject item) { return true; } @@ -123,9 +120,6 @@ public class SimpleBuildWrapperTest { context.env("PATH+EXTRA", "${EXTRA}/bin"); } @TestExtension("envOverrideExpand") public static class DescriptorImpl extends BuildWrapperDescriptor { - @Override public String getDisplayName() { - return "WrapperWithEnvOverrideExpand"; - } @Override public boolean isApplicable(AbstractProject item) { return true; } @@ -167,9 +161,6 @@ public class SimpleBuildWrapperTest { } } @TestExtension("disposer") public static class DescriptorImpl extends BuildWrapperDescriptor { - @Override public String getDisplayName() { - return "WrapperWithDisposer"; - } @Override public boolean isApplicable(AbstractProject item) { return true; } @@ -205,9 +196,6 @@ public class SimpleBuildWrapperTest { } } @TestExtension("loggerDecorator") public static class DescriptorImpl extends BuildWrapperDescriptor { - @Override public String getDisplayName() { - return "WrapperWithLogger"; - } @Override public boolean isApplicable(AbstractProject item) { return true; } diff --git a/test/src/test/java/lib/form/ComboBoxTest.java b/test/src/test/java/lib/form/ComboBoxTest.java index f038d59dba..e522adea0a 100644 --- a/test/src/test/java/lib/form/ComboBoxTest.java +++ b/test/src/test/java/lib/form/ComboBoxTest.java @@ -71,10 +71,6 @@ public class ComboBoxTest extends HudsonTestCase { } return new ComboBoxModel(abc, xyz); } - - public String getDisplayName() { - return "Compound Field used to populate combobox"; - } } public CompoundField getCompoundField() { @@ -109,9 +105,7 @@ public class ComboBoxTest extends HudsonTestCase { } @Extension - public static final class DescriptorImpl extends Descriptor { - public String getDisplayName() { return ""; } - } + public static final class DescriptorImpl extends Descriptor {} } /** diff --git a/test/src/test/java/lib/form/PasswordTest.java b/test/src/test/java/lib/form/PasswordTest.java index 030c38f504..36d24a51d4 100644 --- a/test/src/test/java/lib/form/PasswordTest.java +++ b/test/src/test/java/lib/form/PasswordTest.java @@ -50,9 +50,5 @@ public class PasswordTest extends HudsonTestCase implements Describable { - public String getDisplayName() { - return null; - } - } + public static final class DescriptorImpl extends Descriptor {} } diff --git a/test/src/test/java/lib/form/RepeatablePropertyTest.java b/test/src/test/java/lib/form/RepeatablePropertyTest.java index de4192e4a6..405a6f339b 100644 --- a/test/src/test/java/lib/form/RepeatablePropertyTest.java +++ b/test/src/test/java/lib/form/RepeatablePropertyTest.java @@ -107,12 +107,7 @@ public class RepeatablePropertyTest extends HudsonTestCase implements Describabl } @Extension - public static final class DescriptorImpl extends Descriptor { - @Override - public String getDisplayName() { - return "RepeatablePropertyTest"; - } - } + public static final class DescriptorImpl extends Descriptor {} public static final class ExcitingObject implements Describable { private final String greatProperty; @@ -149,10 +144,6 @@ public class RepeatablePropertyTest extends HudsonTestCase implements Describabl public ExcitingDescriptor() { super(ExcitingObject.class); } - @Override - public String getDisplayName() { - return "This is an awesome thing!"; - } } } diff --git a/test/src/test/java/lib/form/RepeatableTest.java b/test/src/test/java/lib/form/RepeatableTest.java index 395e4b886f..353ae65792 100644 --- a/test/src/test/java/lib/form/RepeatableTest.java +++ b/test/src/test/java/lib/form/RepeatableTest.java @@ -268,9 +268,6 @@ public class RepeatableTest extends HudsonTestCase { public FruitDescriptor(Class clazz) { super(clazz); } - public String getDisplayName() { - return clazz.getSimpleName(); - } } public static class Apple extends Fruit { diff --git a/test/src/test/java/lib/form/RowVisibilityGroupTest.java b/test/src/test/java/lib/form/RowVisibilityGroupTest.java index 1c00a255db..ab7c120e7c 100644 --- a/test/src/test/java/lib/form/RowVisibilityGroupTest.java +++ b/test/src/test/java/lib/form/RowVisibilityGroupTest.java @@ -115,11 +115,7 @@ public class RowVisibilityGroupTest extends HudsonTestCase implements Describabl } @TestExtension - public static final class DescriptorImpl extends Descriptor { - public String getDisplayName() { - return null; - } - } + public static final class DescriptorImpl extends Descriptor {} public static class Nested { public String textbox2; @@ -147,12 +143,7 @@ public class RowVisibilityGroupTest extends HudsonTestCase implements Describabl } @TestExtension - public static class DescriptorImpl extends Descriptor { - @Override - public String getDisplayName() { - return "Beer"; - } - } + public static class DescriptorImpl extends Descriptor {} } public static class Coke extends Drink { @@ -162,11 +153,6 @@ public class RowVisibilityGroupTest extends HudsonTestCase implements Describabl } @TestExtension - public static class DescriptorImpl extends Descriptor { - @Override - public String getDisplayName() { - return "Coke"; - } - } + public static class DescriptorImpl extends Descriptor {} } } diff --git a/test/src/test/java/lib/form/ValidateButtonTest.java b/test/src/test/java/lib/form/ValidateButtonTest.java index fe786090ed..503a5c9693 100644 --- a/test/src/test/java/lib/form/ValidateButtonTest.java +++ b/test/src/test/java/lib/form/ValidateButtonTest.java @@ -58,10 +58,6 @@ public class ValidateButtonTest extends HudsonTestCase implements Describable { private Exception test1Outcome; - public String getDisplayName() { - return null; - } - public void doValidateTest1(@QueryParameter("a") String a, @QueryParameter("b") boolean b, @QueryParameter("c") boolean c, @QueryParameter("d") String d, @QueryParameter("e") String e) { From c465c56c7376b88e542bbfa7bb75ecb9a0202a6c Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 21 Oct 2015 13:25:55 -0400 Subject: [PATCH 0697/2573] Emphasizing that the default name is taken from the clazz, not getClass(). --- core/src/main/java/hudson/model/Descriptor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/Descriptor.java b/core/src/main/java/hudson/model/Descriptor.java index 29ee1e4dd5..c8ff033246 100644 --- a/core/src/main/java/hudson/model/Descriptor.java +++ b/core/src/main/java/hudson/model/Descriptor.java @@ -293,7 +293,8 @@ public abstract class Descriptor> implements Saveable { /** * Human readable name of this kind of configurable object. - * By default, it uses {@link Class#getSimpleName} on {@link #clazz}, but this should be overridden for visible descriptors. + * Should be overridden for most descriptors, if the display name is visible somehow. + * As a fallback it uses {@link Class#getSimpleName} on {@link #clazz}, so for example {@code MyThing} from {@code some.pkg.MyThing.DescriptorImpl}. */ public String getDisplayName() { return clazz.getSimpleName(); From 50cde4b8e7d1c9f8160e2282347218555697b71d Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 21 Oct 2015 14:36:25 -0400 Subject: [PATCH 0698/2573] Returning null from getDisplayName was an abuse of the APIs. --- core/src/main/java/hudson/model/Descriptor.java | 3 +++ .../java/hudson/security/HudsonPrivateSecurityRealm.java | 8 +++----- .../jenkins/security/LastGrantedAuthoritiesProperty.java | 6 +++--- .../HudsonPrivateSecurityRealm/Details/config.jelly | 4 +--- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/hudson/model/Descriptor.java b/core/src/main/java/hudson/model/Descriptor.java index c8ff033246..d7b83bd952 100644 --- a/core/src/main/java/hudson/model/Descriptor.java +++ b/core/src/main/java/hudson/model/Descriptor.java @@ -295,7 +295,10 @@ public abstract class Descriptor> implements Saveable { * Human readable name of this kind of configurable object. * Should be overridden for most descriptors, if the display name is visible somehow. * As a fallback it uses {@link Class#getSimpleName} on {@link #clazz}, so for example {@code MyThing} from {@code some.pkg.MyThing.DescriptorImpl}. + * Historically some implementations returned null as a way of hiding the descriptor from the UI, + * but this is generally managed by an explicit method such as {@code isEnabled} or {@code isApplicable}. */ + @Nonnull public String getDisplayName() { return clazz.getSimpleName(); } diff --git a/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java b/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java index ad09166da5..ffaf8311d7 100644 --- a/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java +++ b/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java @@ -541,12 +541,9 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea @Extension public static final class DescriptorImpl extends UserPropertyDescriptor { + @Override public String getDisplayName() { - // this feature is only when HudsonPrivateSecurityRealm is enabled - if(isEnabled()) - return Messages.HudsonPrivateSecurityRealm_Details_DisplayName(); - else - return null; + return Messages.HudsonPrivateSecurityRealm_Details_DisplayName(); } @Override @@ -568,6 +565,7 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea @Override public boolean isEnabled() { + // this feature is only when HudsonPrivateSecurityRealm is enabled return Jenkins.getInstance().getSecurityRealm() instanceof HudsonPrivateSecurityRealm; } diff --git a/core/src/main/java/jenkins/security/LastGrantedAuthoritiesProperty.java b/core/src/main/java/jenkins/security/LastGrantedAuthoritiesProperty.java index 4b4dcbe3e8..3f5924cabd 100644 --- a/core/src/main/java/jenkins/security/LastGrantedAuthoritiesProperty.java +++ b/core/src/main/java/jenkins/security/LastGrantedAuthoritiesProperty.java @@ -149,10 +149,10 @@ public class LastGrantedAuthoritiesProperty extends UserProperty { @Extension public static final class DescriptorImpl extends UserPropertyDescriptor { @Override - public LastGrantedAuthoritiesProperty newInstance(StaplerRequest req, JSONObject formData) throws FormException { - return new LastGrantedAuthoritiesProperty(); + public boolean isEnabled() { + return false; } - + public UserProperty newInstance(User user) { return null; } diff --git a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/Details/config.jelly b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/Details/config.jelly index f97a4c9e9e..02c43b5764 100644 --- a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/Details/config.jelly +++ b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/Details/config.jelly @@ -24,12 +24,10 @@ THE SOFTWARE. - - - \ No newline at end of file + From fcb94afd0de60971c3194367259f252180dc3c5c Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Wed, 21 Oct 2015 15:03:10 -0400 Subject: [PATCH 0699/2573] Updated some tests. --- .../test/groovy/hudson/model/AbstractBuildTest.groovy | 11 ++++++++--- test/src/test/java/hudson/model/DescriptorTest.java | 2 +- test/src/test/java/hudson/model/ExecutorTest.java | 10 ++++++---- test/src/test/java/hudson/model/ViewPropertyTest.java | 2 +- .../src/test/java/hudson/slaves/NodePropertyTest.java | 2 +- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/test/src/test/groovy/hudson/model/AbstractBuildTest.groovy b/test/src/test/groovy/hudson/model/AbstractBuildTest.groovy index 27e688a62c..d50fb513d0 100644 --- a/test/src/test/groovy/hudson/model/AbstractBuildTest.groovy +++ b/test/src/test/groovy/hudson/model/AbstractBuildTest.groovy @@ -28,13 +28,16 @@ import java.io.IOException; import com.gargoylesoftware.htmlunit.Page import hudson.Launcher; +import hudson.model.Descriptor; import hudson.slaves.EnvironmentVariablesNodeProperty import hudson.slaves.EnvironmentVariablesNodeProperty.Entry +import hudson.tasks.Builder import org.jvnet.hudson.test.CaptureEnvironmentBuilder import org.jvnet.hudson.test.GroovyJenkinsRule import org.jvnet.hudson.test.FakeChangeLogSCM import org.jvnet.hudson.test.FailureBuilder +import org.jvnet.hudson.test.TestExtension import org.jvnet.hudson.test.UnstableBuilder import static org.junit.Assert.* @@ -140,7 +143,7 @@ public class AbstractBuildTest { assertEquals(null, b1.getNextBuild()); } - @Test void doNotInteruptBuildAbruptlyWhenExceptionThrownFromBuildStep() { + @Test void doNotInterruptBuildAbruptlyWhenExceptionThrownFromBuildStep() { FreeStyleProject p = j.createFreeStyleProject(); p.getBuildersList().add(new ThrowBuilder()); def build = p.scheduleBuild2(0).get(); @@ -148,7 +151,7 @@ public class AbstractBuildTest { def log = build.log; assertThat(log, containsString("Finished: FAILURE")); - assertThat(log, containsString("Build step 'Bogus' marked build as failure")); + assertThat(log, containsString("Build step 'ThrowBuilder' marked build as failure")); } @Test void fixEmptyDisplayName() { @@ -175,9 +178,11 @@ public class AbstractBuildTest { assertEquals("A non-blank display name with whitespace should be trimmed.", "bar", p.getDisplayName()); } - private static class ThrowBuilder extends org.jvnet.hudson.test.TestBuilder { + private static class ThrowBuilder extends Builder { @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { throw new NullPointerException(); } + @TestExtension("doNotInterruptBuildAbruptlyWhenExceptionThrownFromBuildStep") + public static class DescriptorImpl extends Descriptor {} } } diff --git a/test/src/test/java/hudson/model/DescriptorTest.java b/test/src/test/java/hudson/model/DescriptorTest.java index 6c1707b8e8..ef669bef1b 100644 --- a/test/src/test/java/hudson/model/DescriptorTest.java +++ b/test/src/test/java/hudson/model/DescriptorTest.java @@ -119,7 +119,7 @@ public class DescriptorTest { FreeStyleProject p = rule.createFreeStyleProject("p"); p.getBuildersList().add(new B1(Arrays.asList(new D1(), new D2()))); rule.configRoundtrip(p); - rule.assertLogContains("[D 1, D 2]", rule.buildAndAssertSuccess(p)); + rule.assertLogContains("[D1, D2]", rule.buildAndAssertSuccess(p)); } public static abstract class D extends AbstractDescribableImpl { @Override public String toString() {return getDescriptor().getDisplayName();} diff --git a/test/src/test/java/hudson/model/ExecutorTest.java b/test/src/test/java/hudson/model/ExecutorTest.java index c6fde4572b..25da5ebaea 100644 --- a/test/src/test/java/hudson/model/ExecutorTest.java +++ b/test/src/test/java/hudson/model/ExecutorTest.java @@ -9,6 +9,7 @@ import hudson.Launcher; import hudson.remoting.VirtualChannel; import hudson.slaves.DumbSlave; import hudson.slaves.OfflineCause; +import hudson.tasks.Builder; import hudson.util.OneShotEvent; import jenkins.model.CauseOfInterruption.UserInterruption; import jenkins.model.InterruptedBuildAction; @@ -17,11 +18,10 @@ 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.TestBuilder; import java.io.IOException; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import org.jvnet.hudson.test.TestExtension; /** * @author Kohsuke Kawaguchi @@ -139,7 +139,7 @@ public class ExecutorTest { String log = b.getLog(); assertEquals(b.getResult(), Result.FAILURE); assertThat(log, containsString("Finished: FAILURE")); - assertThat(log, containsString("Build step 'Bogus' marked build as failure")); + assertThat(log, containsString("Build step 'BlockingBuilder' marked build as failure")); assertThat(log, containsString("Slave went offline during the build")); assertThat(log, containsString("Disconnected by Johnny : Taking offline to break your buil")); } @@ -156,7 +156,7 @@ public class ExecutorTest { return r; } - private static final class BlockingBuilder extends TestBuilder { + private static final class BlockingBuilder extends Builder { private final OneShotEvent e; private BlockingBuilder(OneShotEvent e) { @@ -175,5 +175,7 @@ public class ExecutorTest { Thread.sleep(100); } } + @TestExtension("disconnectCause") + public static class DescriptorImpl extends Descriptor {} } } diff --git a/test/src/test/java/hudson/model/ViewPropertyTest.java b/test/src/test/java/hudson/model/ViewPropertyTest.java index 5ca1352149..976b2fa9d9 100644 --- a/test/src/test/java/hudson/model/ViewPropertyTest.java +++ b/test/src/test/java/hudson/model/ViewPropertyTest.java @@ -43,7 +43,7 @@ public class ViewPropertyTest extends HudsonTestCase { // make sure it renders as optionalBlock HtmlForm f = createWebClient().getPage(foo, "configure").getFormByName("viewConfig"); - ((HtmlLabel) DomNodeUtil.selectSingleNode(f, ".//LABEL[text()='Debug Property']")).click(); + ((HtmlLabel) DomNodeUtil.selectSingleNode(f, ".//LABEL[text()='ViewPropertyImpl']")).click(); submit(f); ViewPropertyImpl vp = foo.getProperties().get(ViewPropertyImpl.class); assertEquals("Duke",vp.name); diff --git a/test/src/test/java/hudson/slaves/NodePropertyTest.java b/test/src/test/java/hudson/slaves/NodePropertyTest.java index 27cd4a73e3..a18280aa94 100644 --- a/test/src/test/java/hudson/slaves/NodePropertyTest.java +++ b/test/src/test/java/hudson/slaves/NodePropertyTest.java @@ -59,7 +59,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)DomNodeUtil.selectSingleNode(f, ".//LABEL[text()='Some Property']")).click(); + ((HtmlLabel)DomNodeUtil.selectSingleNode(f, ".//LABEL[text()='PropertyImpl']")).click(); j.submit(f); PropertyImpl p = j.jenkins.getNode(s.getNodeName()).getNodeProperties().get(PropertyImpl.class); assertEquals("Duke",p.name); From 04a874ac9572245314208fdeea485383d621fcf6 Mon Sep 17 00:00:00 2001 From: "Ing. Pavel Janousek" Date: Thu, 22 Oct 2015 12:27:33 +0200 Subject: [PATCH 0700/2573] [JENKINS-31098] Deletage remove a node back to Computer.doDoDelete() --- .../main/java/hudson/cli/DeleteNodeCommand.java | 16 +++++++--------- .../java/hudson/cli/DeleteNodeCommandTest.java | 2 +- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/core/src/main/java/hudson/cli/DeleteNodeCommand.java b/core/src/main/java/hudson/cli/DeleteNodeCommand.java index fb35bf3dac..81e7a74003 100644 --- a/core/src/main/java/hudson/cli/DeleteNodeCommand.java +++ b/core/src/main/java/hudson/cli/DeleteNodeCommand.java @@ -29,6 +29,7 @@ import hudson.model.Node; import jenkins.model.Jenkins; import org.kohsuke.args4j.Argument; +import java.nio.file.AccessDeniedException; import java.util.HashSet; import java.util.List; import java.util.logging.Logger; @@ -77,15 +78,12 @@ public class DeleteNodeCommand extends CLICommand { continue; } - try { - node.checkPermission(Computer.DELETE); - } catch (Exception e) { - stderr.println(e.getMessage()); - errorOccurred = true; - continue; - } - - jenkins.removeNode(node); + node.toComputer().doDoDelete(); + } catch (AccessDeniedException e) { + stderr.println(e.getMessage()); + errorOccurred = true; + //noinspection UnnecessaryContinue + continue; } catch (Exception e) { final String errorMsg = String.format("Unexpected exception occurred during deletion of node '%s': %s", node == null ? "(null)" : node.toComputer().getName(), diff --git a/test/src/test/java/hudson/cli/DeleteNodeCommandTest.java b/test/src/test/java/hudson/cli/DeleteNodeCommandTest.java index 641768a054..60b3494e0a 100644 --- a/test/src/test/java/hudson/cli/DeleteNodeCommandTest.java +++ b/test/src/test/java/hudson/cli/DeleteNodeCommandTest.java @@ -48,7 +48,7 @@ public class DeleteNodeCommandTest { @Before public void setUp() { - command = new CLICommandInvoker(j, new DeleteNodeCommand()); + command = new CLICommandInvoker(j, "delete-node"); } @Test public void deleteNodeShouldFailWithoutNodeDeletePermission() throws Exception { From 86f8574ff5bbe82fc4931c29dbd55319e96a8e06 Mon Sep 17 00:00:00 2001 From: Stephen Connolly Date: Fri, 23 Oct 2015 09:31:36 +0100 Subject: [PATCH 0701/2573] [JENKINS-31055] Update @since tag --- core/src/main/java/hudson/model/Node.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/Node.java b/core/src/main/java/hudson/model/Node.java index 807c26a7e3..bdb4f8660f 100644 --- a/core/src/main/java/hudson/model/Node.java +++ b/core/src/main/java/hudson/model/Node.java @@ -119,7 +119,7 @@ public abstract class Node extends AbstractModelObject implements Reconfigurable /** * {@inheritDoc} - * @since 1.FIXME + * @since 1.635. */ @Override public void save() throws IOException { From 008f4d939bb39228dbb8b40600b658a28e18c083 Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 24 Oct 2015 14:18:19 +0300 Subject: [PATCH 0702/2573] Update JNA to 4.2.1 It's a follow-up to https://github.com/jenkinsci/jenkins/pull/1861 Fixes the regression on linux-arm: https://github.com/java-native-access/jna/issues/507 --- core/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/pom.xml b/core/pom.xml index 6771abf64f..05d22c5973 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -514,7 +514,7 @@ THE SOFTWARE. net.java.dev.jna jna - 4.2.0 + 4.2.1 org.kohsuke From f53b529fa0f7abb3e936b3c19214ee20116b811c Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 24 Oct 2015 20:06:55 +0300 Subject: [PATCH 0703/2573] Noting the revert of https://github.com/jenkinsci/jenkins/pull/1617 in #1870 (JENKINS-30745) --- changelog.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.html b/changelog.html index 8436b79e42..ed43849a28 100644 --- a/changelog.html +++ b/changelog.html @@ -59,6 +59,9 @@ Upcoming changes
          • Make Node implement Saveable. (issue 31055) +
          • + Revert trigger optimizations made in 1.621 by PR 1617. + (issue 30745)

          What's new in 1.634 (2015/10/18)

          From e3b3638f76107c020fa43d545890329d92e2bcdf Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 24 Oct 2015 20:13:09 +0300 Subject: [PATCH 0704/2573] Noting fix of JENKINS-31098 in #1882 --- changelog.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/changelog.html b/changelog.html index ed43849a28..99a6398d7f 100644 --- a/changelog.html +++ b/changelog.html @@ -62,6 +62,10 @@ Upcoming changes
        • Revert trigger optimizations made in 1.621 by PR 1617. (issue 30745) +
        • + Delegate CLI's delete-node command to the overridable Computer.doDoDelete() method. + Fixes the issue in OpenStack and JClouds plugins. + (issue 31098, regression in 1.618)

        What's new in 1.634 (2015/10/18)

        From 64b92b82f8d5aabba246232ae2da89ab0c616f7a Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 24 Oct 2015 20:15:38 +0300 Subject: [PATCH 0705/2573] Noting #1531 --- changelog.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.html b/changelog.html index 99a6398d7f..4efd32030a 100644 --- a/changelog.html +++ b/changelog.html @@ -66,6 +66,9 @@ Upcoming changes Delegate CLI's delete-node command to the overridable Computer.doDoDelete() method. Fixes the issue in OpenStack and JClouds plugins. (issue 31098, regression in 1.618) +
      • + Prevent autocorrect of username on mobile devices in login forms. + (PR 1531)

      What's new in 1.634 (2015/10/18)

      From 0cc465e706f69b7ee0389749233ab2f33ca47eed Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sat, 24 Oct 2015 20:18:45 +0300 Subject: [PATCH 0706/2573] Noting fix of JENKINS-755 in https://github.com/jenkinsci/jenkins/pull/1528 --- changelog.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.html b/changelog.html index 4efd32030a..33fc5d0879 100644 --- a/changelog.html +++ b/changelog.html @@ -69,6 +69,9 @@ Upcoming changes
    • Prevent autocorrect of username on mobile devices in login forms. (PR 1531) +
    • + Describe the built-in JDK as "(System)". + (issue 755)

    What's new in 1.634 (2015/10/18)

    From 846ec90dd396416d70a50086a357950d1d9e2bcf Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sun, 25 Oct 2015 16:06:19 +0300 Subject: [PATCH 0707/2573] Noting fix of #1861 and #1884 --- changelog.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/changelog.html b/changelog.html index 33fc5d0879..6f7b279f6e 100644 --- a/changelog.html +++ b/changelog.html @@ -72,6 +72,9 @@ Upcoming changes
  • Describe the built-in JDK as "(System)". (issue 755) +
  • + Update JNA library to 4.2.1 in order to integrate fixes for linux-ppc64 and linux-arm platforms. + (issue 15792)

    What's new in 1.634 (2015/10/18)

    From dc7cf2dc1f16f2b7ef14b2ab5cd62c929835d2cb Mon Sep 17 00:00:00 2001 From: Oleg Nenashev Date: Sun, 25 Oct 2015 16:13:23 +0300 Subject: [PATCH 0708/2573] Changelog: remove empty stub --- changelog.html | 1 - 1 file changed, 1 deletion(-) diff --git a/changelog.html b/changelog.html index 6f7b279f6e..1f663f58ba 100644 --- a/changelog.html +++ b/changelog.html @@ -55,7 +55,6 @@ Upcoming changes

    What's new in 1.634 (2015/10/18)

    • From 65f88cce61aa006f2d2d63fa5f75a0b87c1f180b Mon Sep 17 00:00:00 2001 From: Daniel Spilker Date: Mon, 26 Oct 2015 20:50:05 +0100 Subject: [PATCH 0714/2573] allow @WithPlugin to install multiple plugins --- .../jvnet/hudson/test/recipes/WithPlugin.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/test/src/main/java/org/jvnet/hudson/test/recipes/WithPlugin.java b/test/src/main/java/org/jvnet/hudson/test/recipes/WithPlugin.java index 9700e17851..1dfafea490 100644 --- a/test/src/main/java/org/jvnet/hudson/test/recipes/WithPlugin.java +++ b/test/src/main/java/org/jvnet/hudson/test/recipes/WithPlugin.java @@ -39,7 +39,7 @@ import java.lang.annotation.Target; import java.net.URL; /** - * Installs the specified plugin before launching Hudson. + * Installs the specified plugins before launching Jenkins. * * @author Kohsuke Kawaguchi */ @@ -50,9 +50,9 @@ import java.net.URL; @Retention(RUNTIME) public @interface WithPlugin { /** - * Name of the plugin. + * Whitespace separated list of plugin names. * - * For now, this has to be one of the plugins statically available in resources + * For now, this has to be one or more of the plugins statically available in resources * "/plugins/NAME". TODO: support retrieval through Maven repository. * TODO: load the HPI file from $M2_REPO or $USER_HOME/.m2 by naming e.g. org.jvnet.hudson.plugins:monitoring:hpi:1.34.0 * (used in conjunction with the depepdency in POM to ensure it's available) @@ -70,8 +70,10 @@ public @interface WithPlugin { @Override public void decorateHome(HudsonTestCase testCase, File home) throws Exception { - URL res = getClass().getClassLoader().getResource("plugins/" + a.value()); - FileUtils.copyURLToFile(res,new File(home,"plugins/"+a.value())); + for (String plugin : a.value().split("\\s+")) { + URL res = getClass().getClassLoader().getResource("plugins/" + plugin); + FileUtils.copyURLToFile(res, new File(home, "plugins/" + plugin)); + } } } @@ -86,8 +88,10 @@ public @interface WithPlugin { @Override public void decorateHome(JenkinsRule jenkinsRule, File home) throws Exception { - URL res = getClass().getClassLoader().getResource("plugins/" + a.value()); - FileUtils.copyURLToFile(res,new File(home,"plugins/"+a.value())); + for (String plugin : a.value().split("\\s+")) { + URL res = getClass().getClassLoader().getResource("plugins/" + plugin); + FileUtils.copyURLToFile(res, new File(home, "plugins/" + plugin)); + } } } } From 18d4a29aa47f37481d53614eefaa624ade60faf6 Mon Sep 17 00:00:00 2001 From: Daniel Spilker Date: Tue, 27 Oct 2015 09:24:18 +0100 Subject: [PATCH 0715/2573] changed regex to parse CSV --- .../main/java/org/jvnet/hudson/test/recipes/WithPlugin.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/src/main/java/org/jvnet/hudson/test/recipes/WithPlugin.java b/test/src/main/java/org/jvnet/hudson/test/recipes/WithPlugin.java index 1dfafea490..7d019f78fc 100644 --- a/test/src/main/java/org/jvnet/hudson/test/recipes/WithPlugin.java +++ b/test/src/main/java/org/jvnet/hudson/test/recipes/WithPlugin.java @@ -50,7 +50,7 @@ import java.net.URL; @Retention(RUNTIME) public @interface WithPlugin { /** - * Whitespace separated list of plugin names. + * Comma separated list of plugin names. * * For now, this has to be one or more of the plugins statically available in resources * "/plugins/NAME". TODO: support retrieval through Maven repository. @@ -70,7 +70,7 @@ public @interface WithPlugin { @Override public void decorateHome(HudsonTestCase testCase, File home) throws Exception { - for (String plugin : a.value().split("\\s+")) { + for (String plugin : a.value().split("\\s*,\\s*")) { URL res = getClass().getClassLoader().getResource("plugins/" + plugin); FileUtils.copyURLToFile(res, new File(home, "plugins/" + plugin)); } @@ -88,7 +88,7 @@ public @interface WithPlugin { @Override public void decorateHome(JenkinsRule jenkinsRule, File home) throws Exception { - for (String plugin : a.value().split("\\s+")) { + for (String plugin : a.value().split("\\s*,\\s*")) { URL res = getClass().getClassLoader().getResource("plugins/" + plugin); FileUtils.copyURLToFile(res, new File(home, "plugins/" + plugin)); } From 8a9546408bef7c34b7d2310bbe303aad5fa807d6 Mon Sep 17 00:00:00 2001 From: Daniel Spilker Date: Tue, 27 Oct 2015 17:38:47 +0100 Subject: [PATCH 0716/2573] use array instead of CSV --- .../java/org/jvnet/hudson/test/recipes/WithPlugin.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/src/main/java/org/jvnet/hudson/test/recipes/WithPlugin.java b/test/src/main/java/org/jvnet/hudson/test/recipes/WithPlugin.java index 7d019f78fc..d538ce0565 100644 --- a/test/src/main/java/org/jvnet/hudson/test/recipes/WithPlugin.java +++ b/test/src/main/java/org/jvnet/hudson/test/recipes/WithPlugin.java @@ -50,14 +50,14 @@ import java.net.URL; @Retention(RUNTIME) public @interface WithPlugin { /** - * Comma separated list of plugin names. + * Name of the plugins. * * For now, this has to be one or more of the plugins statically available in resources * "/plugins/NAME". TODO: support retrieval through Maven repository. * TODO: load the HPI file from $M2_REPO or $USER_HOME/.m2 by naming e.g. org.jvnet.hudson.plugins:monitoring:hpi:1.34.0 * (used in conjunction with the depepdency in POM to ensure it's available) */ - String value(); + String[] value(); class RunnerImpl extends Recipe.Runner { private WithPlugin a; @@ -70,7 +70,7 @@ public @interface WithPlugin { @Override public void decorateHome(HudsonTestCase testCase, File home) throws Exception { - for (String plugin : a.value().split("\\s*,\\s*")) { + for (String plugin : a.value()) { URL res = getClass().getClassLoader().getResource("plugins/" + plugin); FileUtils.copyURLToFile(res, new File(home, "plugins/" + plugin)); } @@ -88,7 +88,7 @@ public @interface WithPlugin { @Override public void decorateHome(JenkinsRule jenkinsRule, File home) throws Exception { - for (String plugin : a.value().split("\\s*,\\s*")) { + for (String plugin : a.value()) { URL res = getClass().getClassLoader().getResource("plugins/" + plugin); FileUtils.copyURLToFile(res, new File(home, "plugins/" + plugin)); } From 53c86ec857a49609613ed1871a01830d51a89265 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Tue, 27 Oct 2015 14:38:42 -0400 Subject: [PATCH 0717/2573] Introduced OptionalJobProperty. --- .../main/java/hudson/model/JobProperty.java | 3 + .../hudson/model/JobPropertyDescriptor.java | 3 +- .../jenkins/model/OptionalJobProperty.java | 61 +++++++++++++++++++ .../model/OptionalJobProperty/config.jelly | 33 ++++++++++ 4 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/jenkins/model/OptionalJobProperty.java create mode 100644 core/src/main/resources/jenkins/model/OptionalJobProperty/config.jelly diff --git a/core/src/main/java/hudson/model/JobProperty.java b/core/src/main/java/hudson/model/JobProperty.java index 600c5e1fb1..b5d505da01 100644 --- a/core/src/main/java/hudson/model/JobProperty.java +++ b/core/src/main/java/hudson/model/JobProperty.java @@ -38,6 +38,7 @@ import java.util.Collection; import java.util.Collections; import jenkins.model.Jenkins; +import jenkins.model.OptionalJobProperty; import net.sf.json.JSONObject; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.export.ExportedBean; @@ -63,6 +64,8 @@ import org.kohsuke.stapler.export.ExportedBean; * and {@link #prebuild(AbstractBuild, BuildListener)} are invoked after those * of {@link Publisher}s. * + *

      Consider extending {@link OptionalJobProperty} instead. + * * @param * When you restrict your job property to be only applicable to a certain * subtype of {@link Job}, you can use this type parameter to improve diff --git a/core/src/main/java/hudson/model/JobPropertyDescriptor.java b/core/src/main/java/hudson/model/JobPropertyDescriptor.java index a894370fb8..2af8f74bc1 100644 --- a/core/src/main/java/hudson/model/JobPropertyDescriptor.java +++ b/core/src/main/java/hudson/model/JobPropertyDescriptor.java @@ -32,6 +32,7 @@ import java.util.ArrayList; import java.util.Collection; import java.lang.reflect.Type; import java.lang.reflect.ParameterizedType; +import jenkins.model.OptionalJobProperty; import net.sf.json.JSONObject; @@ -60,7 +61,7 @@ public abstract class JobPropertyDescriptor extends Descriptor> { * {@inheritDoc} * * @return - * null to avoid setting an instance of {@link JobProperty} to the target project. + * null to avoid setting an instance of {@link JobProperty} to the target project (or just use {@link OptionalJobProperty}) */ @Override public JobProperty newInstance(StaplerRequest req, JSONObject formData) throws FormException { diff --git a/core/src/main/java/jenkins/model/OptionalJobProperty.java b/core/src/main/java/jenkins/model/OptionalJobProperty.java new file mode 100644 index 0000000000..b4d738c65e --- /dev/null +++ b/core/src/main/java/jenkins/model/OptionalJobProperty.java @@ -0,0 +1,61 @@ +/* + * 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 jenkins.model; + +import hudson.model.Job; +import hudson.model.JobProperty; +import hudson.model.JobPropertyDescriptor; +import net.sf.json.JSONObject; +import org.kohsuke.stapler.StaplerRequest; + +/** + * Job property which may or may not be present. + * Must define {@code config-details.jelly} or {@code config-details.groovy}. + * May define {@code help.html}. + * @since TODO + */ +public abstract class OptionalJobProperty> extends JobProperty { + + @Override + public OptionalJobPropertyDescriptor getDescriptor() { + return (OptionalJobPropertyDescriptor) super.getDescriptor(); + } + + public static abstract class OptionalJobPropertyDescriptor extends JobPropertyDescriptor { + + protected OptionalJobPropertyDescriptor(Class> clazz) { + super(clazz); + } + + protected OptionalJobPropertyDescriptor() {} + + @Override + public JobProperty newInstance(StaplerRequest req, JSONObject formData) throws FormException { + return formData.optBoolean("specified") ? super.newInstance(req, formData) : null; + } + + } + +} diff --git a/core/src/main/resources/jenkins/model/OptionalJobProperty/config.jelly b/core/src/main/resources/jenkins/model/OptionalJobProperty/config.jelly new file mode 100644 index 0000000000..6f46063fb5 --- /dev/null +++ b/core/src/main/resources/jenkins/model/OptionalJobProperty/config.jelly @@ -0,0 +1,33 @@ + + + + + + + + + + + From 600b1f075ab6b9425aa3507347ff8fc5d0571010 Mon Sep 17 00:00:00 2001 From: Jesse Glick Date: Tue, 27 Oct 2015 14:39:39 -0400 Subject: [PATCH 0718/2573] Simplified ParametersDefinitionProperty by extending OptionalJobProperty. --- .../model/ParametersDefinitionProperty.java | 28 ++++--------------- .../hudson/model/Messages.properties | 2 +- .../hudson/model/Messages_bg.properties | 1 + .../hudson/model/Messages_da.properties | 1 + .../hudson/model/Messages_de.properties | 1 + .../hudson/model/Messages_en_GB.properties | 1 + .../hudson/model/Messages_es.properties | 1 + .../hudson/model/Messages_fr.properties | 1 + .../hudson/model/Messages_he.properties | 1 + .../hudson/model/Messages_hu.properties | 1 + .../hudson/model/Messages_it.properties | 1 + .../hudson/model/Messages_ja.properties | 1 + .../hudson/model/Messages_ko.properties | 1 + .../hudson/model/Messages_lt.properties | 1 + .../hudson/model/Messages_nb_NO.properties | 1 + .../hudson/model/Messages_nl.properties | 1 + .../hudson/model/Messages_pl.properties | 1 + .../hudson/model/Messages_pt_BR.properties | 1 + .../hudson/model/Messages_ro.properties | 1 + .../hudson/model/Messages_ru.properties | 1 + .../hudson/model/Messages_sk.properties | 1 + .../hudson/model/Messages_sv_SE.properties | 1 + .../hudson/model/Messages_tr.properties | 1 + .../hudson/model/Messages_uk.properties | 1 + .../hudson/model/Messages_zh_CN.properties | 1 + .../hudson/model/Messages_zh_TW.properties | 1 + .../{config.jelly => config-details.jelly} | 13 ++------- .../config-details_bg.properties | 23 +++++++++++++++ ...roperties => config-details_ca.properties} | 0 ...roperties => config-details_da.properties} | 1 - .../config-details_de.properties | 1 + ...roperties => config-details_es.properties} | 1 - ...roperties => config-details_fi.properties} | 0 ...roperties => config-details_fr.properties} | 1 - .../config-details_he.properties | 3 ++ ...roperties => config-details_hu.properties} | 1 - ...roperties => config-details_it.properties} | 1 - ...roperties => config-details_ja.properties} | 3 +- .../config-details_ko.properties | 3 ++ ...roperties => config-details_lt.properties} | 1 - ...roperties => config-details_lv.properties} | 0 ...erties => config-details_nb_NO.properties} | 1 - ...roperties => config-details_nl.properties} | 1 - ...roperties => config-details_pl.properties} | 1 - ...erties => config-details_pt_BR.properties} | 1 - ...roperties => config-details_ro.properties} | 1 - .../config-details_ru.properties | 23 +++++++++++++++ ...roperties => config-details_sk.properties} | 1 - ...erties => config-details_sv_SE.properties} | 1 - ...roperties => config-details_tr.properties} | 1 - .../config-details_uk.properties | 3 ++ ...erties => config-details_zh_CN.properties} | 1 - ...erties => config-details_zh_TW.properties} | 1 - .../config_bg.properties | 24 ---------------- .../config_de.properties | 2 -- .../config_en_GB.properties | 3 -- .../config_he.properties | 4 --- .../config_ko.properties | 4 --- .../config_ru.properties | 24 ---------------- .../config_uk.properties | 4 --- .../ParametersDefinitionProperty/help.html | 0 .../ParametersDefinitionProperty/help_de.html | 0 .../ParametersDefinitionProperty/help_fr.html | 0 .../ParametersDefinitionProperty/help_ja.html | 0 .../ParametersDefinitionProperty/help_tr.html | 0 .../help_zh_TW.html | 0 66 files changed, 90 insertions(+), 117 deletions(-) create mode 100644 core/src/main/resources/hudson/model/Messages_bg.properties create mode 100644 core/src/main/resources/hudson/model/Messages_en_GB.properties create mode 100644 core/src/main/resources/hudson/model/Messages_he.properties create mode 100644 core/src/main/resources/hudson/model/Messages_lt.properties create mode 100644 core/src/main/resources/hudson/model/Messages_pl.properties create mode 100644 core/src/main/resources/hudson/model/Messages_ro.properties create mode 100644 core/src/main/resources/hudson/model/Messages_sk.properties create mode 100644 core/src/main/resources/hudson/model/Messages_uk.properties rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config.jelly => config-details.jelly} (67%) create mode 100644 core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_bg.properties rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_ca.properties => config-details_ca.properties} (100%) rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_da.properties => config-details_da.properties} (95%) create mode 100644 core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_de.properties rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_es.properties => config-details_es.properties} (94%) rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_fi.properties => config-details_fi.properties} (100%) rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_fr.properties => config-details_fr.properties} (95%) create mode 100644 core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_he.properties rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_hu.properties => config-details_hu.properties} (69%) rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_it.properties => config-details_it.properties} (94%) rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_ja.properties => config-details_ja.properties} (88%) create mode 100644 core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_ko.properties rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_lt.properties => config-details_lt.properties} (57%) rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_lv.properties => config-details_lv.properties} (100%) rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_nb_NO.properties => config-details_nb_NO.properties} (95%) rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_nl.properties => config-details_nl.properties} (55%) rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_pl.properties => config-details_pl.properties} (94%) rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_pt_BR.properties => config-details_pt_BR.properties} (95%) rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_ro.properties => config-details_ro.properties} (57%) create mode 100644 core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_ru.properties rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_sk.properties => config-details_sk.properties} (53%) rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_sv_SE.properties => config-details_sv_SE.properties} (94%) rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_tr.properties => config-details_tr.properties} (92%) create mode 100644 core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_uk.properties rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_zh_CN.properties => config-details_zh_CN.properties} (94%) rename core/src/main/resources/hudson/model/ParametersDefinitionProperty/{config_zh_TW.properties => config-details_zh_TW.properties} (95%) delete mode 100644 core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_bg.properties delete mode 100644 core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_de.properties delete mode 100644 core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_en_GB.properties delete mode 100644 core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_he.properties delete mode 100644 core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_ko.properties delete mode 100644 core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_ru.properties delete mode 100644 core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_uk.properties rename war/src/main/webapp/help/project-config/parameterized-build.html => core/src/main/resources/hudson/model/ParametersDefinitionProperty/help.html (100%) rename war/src/main/webapp/help/project-config/parameterized-build_de.html => core/src/main/resources/hudson/model/ParametersDefinitionProperty/help_de.html (100%) rename war/src/main/webapp/help/project-config/parameterized-build_fr.html => core/src/main/resources/hudson/model/ParametersDefinitionProperty/help_fr.html (100%) rename war/src/main/webapp/help/project-config/parameterized-build_ja.html => core/src/main/resources/hudson/model/ParametersDefinitionProperty/help_ja.html (100%) rename war/src/main/webapp/help/project-config/parameterized-build_tr.html => core/src/main/resources/hudson/model/ParametersDefinitionProperty/help_tr.html (100%) rename war/src/main/webapp/help/project-config/parameterized-build_zh_TW.html => core/src/main/resources/hudson/model/ParametersDefinitionProperty/help_zh_TW.html (100%) diff --git a/core/src/main/java/hudson/model/ParametersDefinitionProperty.java b/core/src/main/java/hudson/model/ParametersDefinitionProperty.java index 13a6156b5c..1bcd8e325a 100644 --- a/core/src/main/java/hudson/model/ParametersDefinitionProperty.java +++ b/core/src/main/java/hudson/model/ParametersDefinitionProperty.java @@ -38,12 +38,14 @@ import javax.annotation.CheckForNull; import javax.servlet.ServletException; import static javax.servlet.http.HttpServletResponse.SC_CREATED; import jenkins.model.Jenkins; +import jenkins.model.OptionalJobProperty; import jenkins.model.ParameterizedJobMixIn; import jenkins.util.TimeDuration; import net.sf.json.JSONArray; import net.sf.json.JSONObject; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; @@ -60,11 +62,12 @@ import org.kohsuke.stapler.export.ExportedBean; * The builds also need a {@code sidepanel.jelly}. */ @ExportedBean(defaultVisibility=2) -public class ParametersDefinitionProperty extends JobProperty> +public class ParametersDefinitionProperty extends OptionalJobProperty> implements Action { private final List parameterDefinitions; + @DataBoundConstructor public ParametersDefinitionProperty(List parameterDefinitions) { this.parameterDefinitions = parameterDefinitions; } @@ -203,33 +206,12 @@ public class ParametersDefinitionProperty extends JobProperty> } @Extension - public static class DescriptorImpl extends JobPropertyDescriptor { + public static class DescriptorImpl extends OptionalJobPropertyDescriptor { @Override public boolean isApplicable(Class jobType) { return ParameterizedJobMixIn.ParameterizedJob.class.isAssignableFrom(jobType); } - @Override - public JobProperty newInstance(StaplerRequest req, - JSONObject formData) throws FormException { - if (formData.isNullObject()) { - return null; - } - - JSONObject parameterized = formData.getJSONObject("parameterized"); - - if (parameterized.isNullObject()) { - return null; - } - - List parameterDefinitions = Descriptor.newInstancesFromHeteroList( - req, parameterized, "parameter", ParameterDefinition.all()); - if(parameterDefinitions.isEmpty()) - return null; - - return new ParametersDefinitionProperty(parameterDefinitions); - } - @Override public String getDisplayName() { return Messages.ParametersDefinitionProperty_DisplayName(); diff --git a/core/src/main/resources/hudson/model/Messages.properties b/core/src/main/resources/hudson/model/Messages.properties index e81652a8d9..004154e1a1 100644 --- a/core/src/main/resources/hudson/model/Messages.properties +++ b/core/src/main/resources/hudson/model/Messages.properties @@ -319,7 +319,7 @@ Permalink.LastSuccessfulBuild=Last successful build Permalink.LastFailedBuild=Last failed build ParameterAction.DisplayName=Parameters -ParametersDefinitionProperty.DisplayName=Parameters +ParametersDefinitionProperty.DisplayName=This build is parameterized StringParameterDefinition.DisplayName=String Parameter TextParameterDefinition.DisplayName=Text Parameter FileParameterDefinition.DisplayName=File Parameter diff --git a/core/src/main/resources/hudson/model/Messages_bg.properties b/core/src/main/resources/hudson/model/Messages_bg.properties new file mode 100644 index 0000000000..b9c6f20f19 --- /dev/null +++ b/core/src/main/resources/hudson/model/Messages_bg.properties @@ -0,0 +1 @@ +ParametersDefinitionProperty.DisplayName=\u0422\u043E\u0437\u0438 \u0431\u0438\u043B\u0434 \u0435 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0438\u0437\u0438\u0440\u0430\u043D diff --git a/core/src/main/resources/hudson/model/Messages_da.properties b/core/src/main/resources/hudson/model/Messages_da.properties index e27f7a4826..1ff2ebb813 100644 --- a/core/src/main/resources/hudson/model/Messages_da.properties +++ b/core/src/main/resources/hudson/model/Messages_da.properties @@ -237,3 +237,4 @@ LoadStatistics.Legends.BusyExecutors=Optagede afviklere HealthReport.EmptyString= MultiStageTimeSeries.EMPTY_STRING= ManageJenkinsAction.DisplayName=Bestyr Jenkins +ParametersDefinitionProperty.DisplayName=Dette byg er parameteriseret diff --git a/core/src/main/resources/hudson/model/Messages_de.properties b/core/src/main/resources/hudson/model/Messages_de.properties index 7a8d5b1bf7..89b4ea70ef 100644 --- a/core/src/main/resources/hudson/model/Messages_de.properties +++ b/core/src/main/resources/hudson/model/Messages_de.properties @@ -304,3 +304,4 @@ Cause.RemoteCause.ShortDescription=Gestartet durch entfernten Rechner {0} Cause.RemoteCause.ShortDescriptionWithNote=Gestartet durch entfernten Rechner {0} mit Hinweis: {1} ManageJenkinsAction.DisplayName=Jenkins verwalten +ParametersDefinitionProperty.DisplayName=Dieser Build ist parametrisiert. diff --git a/core/src/main/resources/hudson/model/Messages_en_GB.properties b/core/src/main/resources/hudson/model/Messages_en_GB.properties new file mode 100644 index 0000000000..9e18978be2 --- /dev/null +++ b/core/src/main/resources/hudson/model/Messages_en_GB.properties @@ -0,0 +1 @@ +ParametersDefinitionProperty.DisplayName=This build is parameterised diff --git a/core/src/main/resources/hudson/model/Messages_es.properties b/core/src/main/resources/hudson/model/Messages_es.properties index cd201a0246..366ccfd159 100644 --- a/core/src/main/resources/hudson/model/Messages_es.properties +++ b/core/src/main/resources/hudson/model/Messages_es.properties @@ -311,3 +311,4 @@ UpdateCenter.DownloadButNotActivated=Descarga correcta. Se activar Computer.ConnectPermission.Description=Este permiso permite que los usuarios puedan conectar nodos o marcarlos como activos. BallColor.NotBuilt=Sin ejecutar. AbstractBuild_Building=Ejecutando. +ParametersDefinitionProperty.DisplayName=Esta ejecución debe parametrizarse diff --git a/core/src/main/resources/hudson/model/Messages_fr.properties b/core/src/main/resources/hudson/model/Messages_fr.properties index 37d121a887..035343bf8c 100644 --- a/core/src/main/resources/hudson/model/Messages_fr.properties +++ b/core/src/main/resources/hudson/model/Messages_fr.properties @@ -192,3 +192,4 @@ MyViewsProperty.DisplayName=Mes vues MyViewsProperty.GlobalAction.DisplayName=Mes vues ManageJenkinsAction.DisplayName=Administrer Jenkins +ParametersDefinitionProperty.DisplayName=Ce build a des paramètres diff --git a/core/src/main/resources/hudson/model/Messages_he.properties b/core/src/main/resources/hudson/model/Messages_he.properties new file mode 100644 index 0000000000..749fbe732d --- /dev/null +++ b/core/src/main/resources/hudson/model/Messages_he.properties @@ -0,0 +1 @@ +ParametersDefinitionProperty.DisplayName=\u05D1\u05E0\u05D9\u05D4 \u05DE\u05DB\u05D9\u05DC\u05D4 \u05DE\u05E9\u05EA\u05E0\u05D9\u05DD diff --git a/core/src/main/resources/hudson/model/Messages_hu.properties b/core/src/main/resources/hudson/model/Messages_hu.properties index ed0c34be08..949132eb7f 100644 --- a/core/src/main/resources/hudson/model/Messages_hu.properties +++ b/core/src/main/resources/hudson/model/Messages_hu.properties @@ -1 +1,2 @@ ManageJenkinsAction.DisplayName=Jenkins Kezel\u00E9se +ParametersDefinitionProperty.DisplayName=Hozz\u00E1ad diff --git a/core/src/main/resources/hudson/model/Messages_it.properties b/core/src/main/resources/hudson/model/Messages_it.properties index cb1fb51eca..c975784188 100644 --- a/core/src/main/resources/hudson/model/Messages_it.properties +++ b/core/src/main/resources/hudson/model/Messages_it.properties @@ -310,3 +310,4 @@ CLI.cancel-quiet-down.shortDescription=Cancel the effect of the "quiet-down" com 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. BuildAuthorizationToken.InvalidTokenProvided=Invalid token provided. +ParametersDefinitionProperty.DisplayName=Questa build \u00E8 parametrizzata diff --git a/core/src/main/resources/hudson/model/Messages_ja.properties b/core/src/main/resources/hudson/model/Messages_ja.properties index e689c3945c..af6dcdc49c 100644 --- a/core/src/main/resources/hudson/model/Messages_ja.properties +++ b/core/src/main/resources/hudson/model/Messages_ja.properties @@ -332,3 +332,4 @@ Jenkins.CheckDisplayName.NameNotUniqueWarning=\u8868\u793a\u7528\u30d7\u30ed\u30 Jenkins.CheckDisplayName.DisplayNameNotUniqueWarning=\u8868\u793a\u7528\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u540d "{0}" \u306f\u4ed6\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3067\u4f7f\u7528\u3055\u308c\u3066\u3044\u308b\u305f\u3081\u3001 \u533a\u5225\u3067\u304d\u306a\u3044\u3053\u3068\u304c\u3042\u308a\u307e\u3059\u3002 Jenkins.NotAllowedName="{0}" \u306f\u8a31\u53ef\u3055\u308c\u306a\u3044\u540d\u524d\u3067\u3059\u3002 +ParametersDefinitionProperty.DisplayName=\u30d3\u30eb\u30c9\u306e\u30d1\u30e9\u30e1\u30fc\u30bf\u5316 diff --git a/core/src/main/resources/hudson/model/Messages_ko.properties b/core/src/main/resources/hudson/model/Messages_ko.properties index a19ef38f99..70020b26be 100644 --- a/core/src/main/resources/hudson/model/Messages_ko.properties +++ b/core/src/main/resources/hudson/model/Messages_ko.properties @@ -1 +1,2 @@ ManageJenkinsAction.DisplayName=Jenkins \uAD00\uB9AC +ParametersDefinitionProperty.DisplayName=\uC774 \uBE4C\uB4DC\uB294 \uB9E4\uAC1C\uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 diff --git a/core/src/main/resources/hudson/model/Messages_lt.properties b/core/src/main/resources/hudson/model/Messages_lt.properties new file mode 100644 index 0000000000..4dac83724a --- /dev/null +++ b/core/src/main/resources/hudson/model/Messages_lt.properties @@ -0,0 +1 @@ +ParametersDefinitionProperty.DisplayName=\u0160is darbas yra parametrizuotas diff --git a/core/src/main/resources/hudson/model/Messages_nb_NO.properties b/core/src/main/resources/hudson/model/Messages_nb_NO.properties index 02c96d9830..e475df644f 100644 --- a/core/src/main/resources/hudson/model/Messages_nb_NO.properties +++ b/core/src/main/resources/hudson/model/Messages_nb_NO.properties @@ -1,2 +1,3 @@ ManageJenkinsAction.DisplayName=Konfigurer Jenkins ManageJenkinsAction.DisplayName=Konfigurer Jenkins +ParametersDefinitionProperty.DisplayName=Denne build har parametre diff --git a/core/src/main/resources/hudson/model/Messages_nl.properties b/core/src/main/resources/hudson/model/Messages_nl.properties index b00c75ebbf..e7b5b57aa6 100644 --- a/core/src/main/resources/hudson/model/Messages_nl.properties +++ b/core/src/main/resources/hudson/model/Messages_nl.properties @@ -101,3 +101,4 @@ Permalink.LastStableBuild=Laatste stabiele bouwpoging Permalink.LastSuccessfulBuild=Laatste succesvolle bouwpoging Permalink.LastFailedBuild=Laatst gefaalde bouwpoging ManageJenkinsAction.DisplayName=Beheer Jenkins +ParametersDefinitionProperty.DisplayName=Deze bouwpoging is geparametriseerd diff --git a/core/src/main/resources/hudson/model/Messages_pl.properties b/core/src/main/resources/hudson/model/Messages_pl.properties new file mode 100644 index 0000000000..e36ad43a25 --- /dev/null +++ b/core/src/main/resources/hudson/model/Messages_pl.properties @@ -0,0 +1 @@ +ParametersDefinitionProperty.DisplayName=Ten build jest sparametryzowany 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 ff16f1e0f6..f02d007044 100644 --- a/core/src/main/resources/hudson/model/Messages_pt_BR.properties +++ b/core/src/main/resources/hudson/model/Messages_pt_BR.properties @@ -512,3 +512,4 @@ Item.CONFIGURE.description=Mudar a configura\u00e7\u00e3o de um job. Item.DELETE.description=Excuir um job. HealthReport.EmptyString= MultiStageTimeSeries.EMPTY_STRING= +ParametersDefinitionProperty.DisplayName=Este build \u00E9 parametrizado diff --git a/core/src/main/resources/hudson/model/Messages_ro.properties b/core/src/main/resources/hudson/model/Messages_ro.properties new file mode 100644 index 0000000000..106056997c --- /dev/null +++ b/core/src/main/resources/hudson/model/Messages_ro.properties @@ -0,0 +1 @@ +ParametersDefinitionProperty.DisplayName=Acest build este parametrizat diff --git a/core/src/main/resources/hudson/model/Messages_ru.properties b/core/src/main/resources/hudson/model/Messages_ru.properties index ee5b0d00f5..b966716ec0 100644 --- a/core/src/main/resources/hudson/model/Messages_ru.properties +++ b/core/src/main/resources/hudson/model/Messages_ru.properties @@ -101,3 +101,4 @@ Permalink.LastStableBuild=\u041f\u043e\u0441\u043b\u0435\u0434\u043d\u044f\u044f 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 ManageJenkinsAction.DisplayName=\u041d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c Jenkins +ParametersDefinitionProperty.DisplayName=\u042d\u0442\u043e - \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0441\u0431\u043e\u0440\u043a\u0430 diff --git a/core/src/main/resources/hudson/model/Messages_sk.properties b/core/src/main/resources/hudson/model/Messages_sk.properties new file mode 100644 index 0000000000..d3cf7721e0 --- /dev/null +++ b/core/src/main/resources/hudson/model/Messages_sk.properties @@ -0,0 +1 @@ +ParametersDefinitionProperty.DisplayName=Toto zostavenie je parametrizovan\u00E9 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 763f29cdd2..278c419304 100644 --- a/core/src/main/resources/hudson/model/Messages_sv_SE.properties +++ b/core/src/main/resources/hudson/model/Messages_sv_SE.properties @@ -4,3 +4,4 @@ AbstractProject.Pronoun=Projekt Job.Pronoun=Projekt ManageJenkinsAction.DisplayName=Hantera Jenkins +ParametersDefinitionProperty.DisplayName=Detta bygge \u00E4r parametriserat diff --git a/core/src/main/resources/hudson/model/Messages_tr.properties b/core/src/main/resources/hudson/model/Messages_tr.properties index ccfc340cd4..2d3aaf2179 100644 --- a/core/src/main/resources/hudson/model/Messages_tr.properties +++ b/core/src/main/resources/hudson/model/Messages_tr.properties @@ -102,3 +102,4 @@ 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 ManageJenkinsAction.DisplayName=Jenkins''\u0131 Y\u00f6net +ParametersDefinitionProperty.DisplayName=Bu yap\u0131land\u0131rma parametrele\u015ftirilmi\u015ftir. diff --git a/core/src/main/resources/hudson/model/Messages_uk.properties b/core/src/main/resources/hudson/model/Messages_uk.properties new file mode 100644 index 0000000000..e48bfb0375 --- /dev/null +++ b/core/src/main/resources/hudson/model/Messages_uk.properties @@ -0,0 +1 @@ +ParametersDefinitionProperty.DisplayName=\u0426\u044F \u0431\u0443\u0434\u043E\u0432\u0430 \u043C\u0430\u0454 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0438 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 c9945468dd..cf982c020e 100644 --- a/core/src/main/resources/hudson/model/Messages_zh_CN.properties +++ b/core/src/main/resources/hudson/model/Messages_zh_CN.properties @@ -269,3 +269,4 @@ CLI.quiet-down.shortDescription=Quiet down Jenkins, in preparation for a restart 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. ManageJenkinsAction.DisplayName=\u7cfb\u7edf\u7ba1\u7406 +ParametersDefinitionProperty.DisplayName=\u53C2\u6570\u5316\u6784\u5EFA\u8FC7\u7A0B 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 7acb779f2d..d3058a2b70 100644 --- a/core/src/main/resources/hudson/model/Messages_zh_TW.properties +++ b/core/src/main/resources/hudson/model/Messages_zh_TW.properties @@ -325,3 +325,4 @@ Jenkins.CheckDisplayName.NameNotUniqueWarning=\u5df2\u7d93\u6709\u4f5c\u696d\u53 Jenkins.CheckDisplayName.DisplayNameNotUniqueWarning=\u5df2\u7d93\u6709\u4f5c\u696d\u7684\u986f\u793a\u540d\u7a31\u662f "{0}"\uff0c\u53ef\u80fd\u6703\u9020\u6210\u6df7\u6dc6\u53ca\u5ef6\u9072\u3002 Jenkins.NotAllowedName="{0}" \u4e26\u4e0d\u662f\u53ef\u4ee5\u4f7f\u7528\u7684\u540d\u7a31 +ParametersDefinitionProperty.DisplayName=\u53c3\u6578\u5316\u5efa\u7f6e diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config.jelly b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details.jelly similarity index 67% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config.jelly rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details.jelly index b2a1f6ba10..a2d545e0d3 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config.jelly +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details.jelly @@ -23,15 +23,8 @@ THE SOFTWARE. --> - - + - + - - \ No newline at end of file + diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_bg.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_bg.properties new file mode 100644 index 0000000000..3669d14533 --- /dev/null +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_bg.properties @@ -0,0 +1,23 @@ +# The MIT License +# +# Copyright (c) 2004-2010, 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. + +Add\ Parameter=\u0414\u043E\u0431\u0430\u0432\u0438 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u044A\u0440 diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_ca.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_ca.properties similarity index 100% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_ca.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_ca.properties diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_da.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_da.properties similarity index 95% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_da.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_da.properties index f18767a9ff..3b313b6542 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_da.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_da.properties @@ -21,4 +21,3 @@ # THE SOFTWARE. Add\ Parameter=Tilf\u00f8j Parametre -This\ build\ is\ parameterized=Dette byg er parameteriseret diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_de.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_de.properties new file mode 100644 index 0000000000..315117f2c3 --- /dev/null +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_de.properties @@ -0,0 +1 @@ +Add\ Parameter=Parameter hinzufügen diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_es.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_es.properties similarity index 94% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_es.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_es.properties index 29bf30e759..dbfed3fa25 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_es.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_es.properties @@ -20,5 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -This\ build\ is\ parameterized=Esta ejecución debe parametrizarse Add\ Parameter=Añadir un parámetro diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_fi.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_fi.properties similarity index 100% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_fi.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_fi.properties diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_fr.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_fr.properties similarity index 95% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_fr.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_fr.properties index 6c9fe1823c..bab6b2cbea 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_fr.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_fr.properties @@ -20,5 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -This\ build\ is\ parameterized=Ce build a des paramètres Add\ Parameter=Ajouter un paramètre diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_he.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_he.properties new file mode 100644 index 0000000000..3ffb627eec --- /dev/null +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_he.properties @@ -0,0 +1,3 @@ +# This file is under the MIT License by authors + +Add\ Parameter=\u05D4\u05D5\u05E1\u05E3 \u05DE\u05E9\u05EA\u05E0\u05D4 diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_hu.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_hu.properties similarity index 69% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_hu.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_hu.properties index 7eb7f4cee3..265e1c7a5c 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_hu.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_hu.properties @@ -1,4 +1,3 @@ # This file is under the MIT License by authors Add\ Parameter=Param\u00E9ter hozz\u00E1ad\u00E1sa -This\ build\ is\ parameterized=Hozz\u00E1ad diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_it.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_it.properties similarity index 94% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_it.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_it.properties index df1251f2fd..a362612239 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_it.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_it.properties @@ -21,4 +21,3 @@ # THE SOFTWARE. Add\ Parameter=Aggiungi Parametro -This\ build\ is\ parameterized=Questa build \u00E8 parametrizzata diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_ja.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_ja.properties similarity index 88% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_ja.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_ja.properties index c466a762ce..c4fabe7ca9 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_ja.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_ja.properties @@ -20,5 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -This\ build\ is\ parameterized=\u30d3\u30eb\u30c9\u306e\u30d1\u30e9\u30e1\u30fc\u30bf\u5316 -Add\ Parameter=\u30d1\u30e9\u30e1\u30fc\u30bf\u306e\u8ffd\u52a0 \ No newline at end of file +Add\ Parameter=\u30d1\u30e9\u30e1\u30fc\u30bf\u306e\u8ffd\u52a0 diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_ko.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_ko.properties new file mode 100644 index 0000000000..6ebd2a13ec --- /dev/null +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_ko.properties @@ -0,0 +1,3 @@ +# This file is under the MIT License by authors + +Add\ Parameter=\uB9E4\uAC1C\uBCC0\uC218 \uCD94\uAC00 diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_lt.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_lt.properties similarity index 57% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_lt.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_lt.properties index 4c66949799..d1aace2dae 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_lt.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_lt.properties @@ -1,4 +1,3 @@ # This file is under the MIT License by authors Add\ Parameter=Prid\u0117ti parametr\u0105 -This\ build\ is\ parameterized=\u0160is darbas yra parametrizuotas diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_lv.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_lv.properties similarity index 100% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_lv.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_lv.properties diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_nb_NO.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_nb_NO.properties similarity index 95% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_nb_NO.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_nb_NO.properties index 7a09188ef8..0e081ccb9f 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_nb_NO.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_nb_NO.properties @@ -21,4 +21,3 @@ # THE SOFTWARE. Add\ Parameter=Legg til parameter -This\ build\ is\ parameterized=Denne build har parametre diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_nl.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_nl.properties similarity index 55% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_nl.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_nl.properties index 7b7fe50685..dcdd5a5287 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_nl.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_nl.properties @@ -1,4 +1,3 @@ # This file is under the MIT License by authors Add\ Parameter=Instelling toevoegen -This\ build\ is\ parameterized=Deze bouwpoging is geparametriseerd diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_pl.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_pl.properties similarity index 94% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_pl.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_pl.properties index 3fccb98d7a..e929a96a2c 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_pl.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_pl.properties @@ -21,4 +21,3 @@ # THE SOFTWARE. Add\ Parameter=Dodaj parametr -This\ build\ is\ parameterized=Ten build jest sparametryzowany diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_pt_BR.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_pt_BR.properties similarity index 95% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_pt_BR.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_pt_BR.properties index 602308ba22..0f269cfdd6 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_pt_BR.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_pt_BR.properties @@ -20,5 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -This\ build\ is\ parameterized=Este build \u00E9 parametrizado Add\ Parameter=Adicionar par\u00e2metro diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_ro.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_ro.properties similarity index 57% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_ro.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_ro.properties index 1f84c50491..bda5b182eb 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_ro.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_ro.properties @@ -1,4 +1,3 @@ # This file is under the MIT License by authors Add\ Parameter=Adauga Parametru -This\ build\ is\ parameterized=Acest build este parametrizat diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_ru.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_ru.properties new file mode 100644 index 0000000000..af02f213e5 --- /dev/null +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_ru.properties @@ -0,0 +1,23 @@ +# The MIT License +# +# Copyright (c) 2004-2010, 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. + +Add\ Parameter=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_sk.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_sk.properties similarity index 53% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_sk.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_sk.properties index bcc1f6c9c4..2dbb26fa03 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_sk.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_sk.properties @@ -1,4 +1,3 @@ # This file is under the MIT License by authors Add\ Parameter=Pridaj parameter -This\ build\ is\ parameterized=Toto zostavenie je parametrizovan\u00E9 diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_sv_SE.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_sv_SE.properties similarity index 94% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_sv_SE.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_sv_SE.properties index d2cac0e4bb..9c8d2bc116 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_sv_SE.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_sv_SE.properties @@ -21,4 +21,3 @@ # THE SOFTWARE. Add\ Parameter=L\u00E4gg till parameter -This\ build\ is\ parameterized=Detta bygge \u00E4r parametriserat diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_tr.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_tr.properties similarity index 92% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_tr.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_tr.properties index 269e5de81b..3ce3029f74 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_tr.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_tr.properties @@ -20,5 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -This\ build\ is\ parameterized=Bu yap\u0131land\u0131rma parametrele\u015ftirilmi\u015ftir. Add\ Parameter=Parametre ekle diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_uk.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_uk.properties new file mode 100644 index 0000000000..0c6b712511 --- /dev/null +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_uk.properties @@ -0,0 +1,3 @@ +# This file is under the MIT License by authors + +Add\ Parameter=\u0414\u043E\u0434\u0430\u0442\u0438 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_zh_CN.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_zh_CN.properties similarity index 94% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_zh_CN.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_zh_CN.properties index b760379d98..572578efad 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_zh_CN.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_zh_CN.properties @@ -21,4 +21,3 @@ # THE SOFTWARE. Add\ Parameter=\u6DFB\u52A0\u53C2\u6570 -This\ build\ is\ parameterized=\u53C2\u6570\u5316\u6784\u5EFA\u8FC7\u7A0B diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_zh_TW.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_zh_TW.properties similarity index 95% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_zh_TW.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_zh_TW.properties index 2e4dc6bcca..1ba5e442e0 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_zh_TW.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_zh_TW.properties @@ -20,5 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -This\ build\ is\ parameterized=\u53c3\u6578\u5316\u5efa\u7f6e Add\ Parameter=\u65B0\u589E\u53C3\u6578 diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_bg.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_bg.properties deleted file mode 100644 index de74757cf3..0000000000 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_bg.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, 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. - -Add\ Parameter=\u0414\u043E\u0431\u0430\u0432\u0438 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u044A\u0440 -This\ build\ is\ parameterized=\u0422\u043E\u0437\u0438 \u0431\u0438\u043B\u0434 \u0435 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0438\u0437\u0438\u0440\u0430\u043D diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_de.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_de.properties deleted file mode 100644 index b095c4e880..0000000000 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_de.properties +++ /dev/null @@ -1,2 +0,0 @@ -This\ build\ is\ parameterized=Dieser Build ist parametrisiert. -Add\ Parameter=Parameter hinzufügen diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_en_GB.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_en_GB.properties deleted file mode 100644 index 76261e71cd..0000000000 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_en_GB.properties +++ /dev/null @@ -1,3 +0,0 @@ -# This file is under the MIT License by authors - -This\ build\ is\ parameterized=This build is parameterised diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_he.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_he.properties deleted file mode 100644 index 9417ad6eef..0000000000 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_he.properties +++ /dev/null @@ -1,4 +0,0 @@ -# This file is under the MIT License by authors - -Add\ Parameter=\u05D4\u05D5\u05E1\u05E3 \u05DE\u05E9\u05EA\u05E0\u05D4 -This\ build\ is\ parameterized=\u05D1\u05E0\u05D9\u05D4 \u05DE\u05DB\u05D9\u05DC\u05D4 \u05DE\u05E9\u05EA\u05E0\u05D9\u05DD diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_ko.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_ko.properties deleted file mode 100644 index daaae005f8..0000000000 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_ko.properties +++ /dev/null @@ -1,4 +0,0 @@ -# This file is under the MIT License by authors - -Add\ Parameter=\uB9E4\uAC1C\uBCC0\uC218 \uCD94\uAC00 -This\ build\ is\ parameterized=\uC774 \uBE4C\uB4DC\uB294 \uB9E4\uAC1C\uBCC0\uC218\uAC00 \uC788\uC2B5\uB2C8\uB2E4 diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_ru.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_ru.properties deleted file mode 100644 index 52c610189d..0000000000 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_ru.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, 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. - -Add\ Parameter=\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 -This\ build\ is\ parameterized=\u042d\u0442\u043e - \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u0430\u044f \u0441\u0431\u043e\u0440\u043a\u0430 diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_uk.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_uk.properties deleted file mode 100644 index a0875e36a5..0000000000 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_uk.properties +++ /dev/null @@ -1,4 +0,0 @@ -# This file is under the MIT License by authors - -Add\ Parameter=\u0414\u043E\u0434\u0430\u0442\u0438 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 -This\ build\ is\ parameterized=\u0426\u044F \u0431\u0443\u0434\u043E\u0432\u0430 \u043C\u0430\u0454 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u0438 diff --git a/war/src/main/webapp/help/project-config/parameterized-build.html b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/help.html similarity index 100% rename from war/src/main/webapp/help/project-config/parameterized-build.html rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/help.html diff --git a/war/src/main/webapp/help/project-config/parameterized-build_de.html b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/help_de.html similarity index 100% rename from war/src/main/webapp/help/project-config/parameterized-build_de.html rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/help_de.html diff --git a/war/src/main/webapp/help/project-config/parameterized-build_fr.html b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/help_fr.html similarity index 100% rename from war/src/main/webapp/help/project-config/parameterized-build_fr.html rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/help_fr.html diff --git a/war/src/main/webapp/help/project-config/parameterized-build_ja.html b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/help_ja.html similarity index 100% rename from war/src/main/webapp/help/project-config/parameterized-build_ja.html rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/help_ja.html diff --git a/war/src/main/webapp/help/project-config/parameterized-build_tr.html b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/help_tr.html similarity index 100% rename from war/src/main/webapp/help/project-config/parameterized-build_tr.html rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/help_tr.html diff --git a/war/src/main/webapp/help/project-config/parameterized-build_zh_TW.html b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/help_zh_TW.html similarity index 100% rename from war/src/main/webapp/help/project-config/parameterized-build_zh_TW.html rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/help_zh_TW.html From 4f7073f8a38a363b764be1f43c3455d27afb4702 Mon Sep 17 00:00:00 2001 From: szczechp Date: Wed, 2 Sep 2015 11:58:47 +0200 Subject: [PATCH 0719/2573] Add task-icon-link class to left menu remove and wipe workspace navigation links. (cherry picked from commit e2d62f84b117a6b07f6136391420f0c0f89a4f19) --- core/src/main/resources/lib/layout/task.jelly | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/resources/lib/layout/task.jelly b/core/src/main/resources/lib/layout/task.jelly index d120faa495..fa08cc56fa 100644 --- a/core/src/main/resources/lib/layout/task.jelly +++ b/core/src/main/resources/lib/layout/task.jelly @@ -167,7 +167,7 @@ THE SOFTWARE. - + From 9bebf2101c00e8c41c60853849cb1b3361bf8444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gond=C5=BEa?= Date: Tue, 29 Sep 2015 21:20:03 +0200 Subject: [PATCH 0720/2573] [FIXED JENKINS-30705] Optimize TagCloud calculation (cherry picked from commit 1b852010568dc3b21c0c296e2f0a2d6ff0b8bed3) --- core/src/main/java/hudson/model/Label.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/hudson/model/Label.java b/core/src/main/java/hudson/model/Label.java index f0a2df2474..30c3905c53 100644 --- a/core/src/main/java/hudson/model/Label.java +++ b/core/src/main/java/hudson/model/Label.java @@ -85,6 +85,7 @@ public abstract class Label extends Actionable implements Comparable

    • Update JNA library to 4.2.1 in order to integrate fixes for linux-ppc64 and linux-arm platforms. (issue 15792) +
    • + Added "lastCompletedBuild" job permalink. + (issue 26270)

    What's new in 1.634 (2015/10/18)

      From 6a44c98541a8f04b427eba5f9193c6fa0494ac28 Mon Sep 17 00:00:00 2001 From: Daniel Beck Date: Sat, 31 Oct 2015 13:10:35 +0100 Subject: [PATCH 0735/2573] Noting #1508 in the correct release --- changelog.html | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/changelog.html b/changelog.html index c34295a200..efa363cc37 100644 --- a/changelog.html +++ b/changelog.html @@ -55,7 +55,9 @@ Upcoming changes

      What's new in 1.635 (2015/10/25)

      @@ -79,9 +81,6 @@ Upcoming changes
    • Update JNA library to 4.2.1 in order to integrate fixes for linux-ppc64 and linux-arm platforms. (issue 15792) -
    • - Added "lastCompletedBuild" job permalink. - (issue 26270)

    What's new in 1.634 (2015/10/18)