diff --git a/cli/pom.xml b/cli/pom.xml index 3741777f4d92cbdcf1df394ffc382462d7b67fc9..e1876fcf11548bc82dbdbbfcd78c52b1335c1814 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 2.56-SNAPSHOT + 2.57-SNAPSHOT cli diff --git a/cli/src/main/java/hudson/cli/PrivateKeyProvider.java b/cli/src/main/java/hudson/cli/PrivateKeyProvider.java index a1f6b3389030fe8e13a990cc5c0e3eabd5ad647f..d7753a750498aff78325fc04326eb63b7e45209d 100644 --- a/cli/src/main/java/hudson/cli/PrivateKeyProvider.java +++ b/cli/src/main/java/hudson/cli/PrivateKeyProvider.java @@ -32,6 +32,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.security.GeneralSecurityException; import java.security.KeyFactory; import java.security.KeyPair; @@ -134,6 +135,8 @@ public class PrivateKeyProvider { byte[] bytes = new byte[(int) f.length()]; dis.readFully(bytes); return new String(bytes); + } catch (InvalidPathException e) { + throw new IOException(e); } } diff --git a/core/pom.xml b/core/pom.xml index 6a44b41d4ca3337ebf0858609266667d990753b2..48731794d006e1b1c0ee5c7a76a38ed02b11d620 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 2.56-SNAPSHOT + 2.57-SNAPSHOT jenkins-core diff --git a/core/src/main/java/hudson/ClassicPluginStrategy.java b/core/src/main/java/hudson/ClassicPluginStrategy.java index 2744f537e66a267e0d8f536b8aeaee615e6fdd71..c64f331b9baa68d6db14f27b4088a4ac58f9d1ff 100644 --- a/core/src/main/java/hudson/ClassicPluginStrategy.java +++ b/core/src/main/java/hudson/ClassicPluginStrategy.java @@ -25,6 +25,7 @@ package hudson; import java.io.InputStream; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import jenkins.util.SystemProperties; import com.google.common.collect.Lists; import hudson.Plugin.DummyImpl; @@ -127,6 +128,8 @@ public class ClassicPluginStrategy implements PluginStrategy { String firstLine; try (InputStream manifestHeaderInput = Files.newInputStream(archive.toPath())) { firstLine = IOUtils.readFirstLine(manifestHeaderInput, "UTF-8"); + } catch (InvalidPathException e) { + throw new IOException(e); } if (firstLine.startsWith("Manifest-Version:")) { // this is the manifest already @@ -138,6 +141,8 @@ public class ClassicPluginStrategy implements PluginStrategy { // Read the manifest try (InputStream manifestInput = Files.newInputStream(archive.toPath())) { return new Manifest(manifestInput); + } catch (InvalidPathException e) { + throw new IOException(e); } } catch (IOException e) { throw new IOException("Failed to load " + archive, e); @@ -171,6 +176,8 @@ public class ClassicPluginStrategy implements PluginStrategy { } try (InputStream fin = Files.newInputStream(manifestFile.toPath())) { manifest = new Manifest(fin); + } catch (InvalidPathException e) { + throw new IOException(e); } } diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index 985bf56e33349231420d9bc2909651e2466cd317..3ba026d7971226f2be4cbf9e7dcd1289a5c5a535 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -78,6 +78,7 @@ import java.net.URI; import java.net.URL; import java.net.URLConnection; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -1469,8 +1470,13 @@ public final class FilePath implements Serializable { act(new SecureFileCallable() { private static final long serialVersionUID = -5094638816500738429L; public Void invoke(File f, VirtualChannel channel) throws IOException { - if(!f.exists()) - Files.newOutputStream(creating(f).toPath()).close(); + if(!f.exists()) { + try { + Files.newOutputStream(creating(f).toPath()).close(); + } catch (InvalidPathException e) { + throw new IOException(e); + } + } if(!stating(f).setLastModified(timestamp)) throw new IOException("Failed to set the timestamp of "+f+" to "+timestamp); return null; @@ -1750,8 +1756,13 @@ public final class FilePath implements Serializable { * Reads this file. */ public InputStream read() throws IOException, InterruptedException { - if(channel==null) - return Files.newInputStream(reading(new File(remote)).toPath()); + if(channel==null) { + try { + return Files.newInputStream(reading(new File(remote)).toPath()); + } catch (InvalidPathException e) { + throw new IOException(e); + } + } final Pipe p = Pipe.createRemoteToLocal(); actAsync(new SecureFileCallable() { @@ -1762,6 +1773,8 @@ public final class FilePath implements Serializable { try (InputStream fis = Files.newInputStream(reading(f).toPath()); OutputStream out = p.getOut()) { org.apache.commons.io.IOUtils.copy(fis, out); + } catch (InvalidPathException e) { + p.error(new IOException(e)); } catch (Exception x) { p.error(x); } @@ -1862,7 +1875,11 @@ public final class FilePath implements Serializable { if(channel==null) { File f = new File(remote).getAbsoluteFile(); mkdirs(f.getParentFile()); - return Files.newOutputStream(writing(f).toPath()); + try { + return Files.newOutputStream(writing(f).toPath()); + } catch (InvalidPathException e) { + throw new IOException(e); + } } return act(new SecureFileCallable() { @@ -1870,8 +1887,12 @@ public final class FilePath implements Serializable { public OutputStream invoke(File f, VirtualChannel channel) throws IOException, InterruptedException { f = f.getAbsoluteFile(); mkdirs(f.getParentFile()); - OutputStream fos = Files.newOutputStream(writing(f).toPath()); - return new RemoteOutputStream(fos); + try { + OutputStream fos = Files.newOutputStream(writing(f).toPath()); + return new RemoteOutputStream(fos); + } catch (InvalidPathException e) { + throw new IOException(e); + } } }); } @@ -1891,6 +1912,8 @@ public final class FilePath implements Serializable { try (OutputStream fos = Files.newOutputStream(writing(f).toPath()); Writer w = encoding != null ? new OutputStreamWriter(fos, encoding) : new OutputStreamWriter(fos)) { w.write(content); + } catch (InvalidPathException e) { + throw new IOException(e); } return null; } @@ -1994,6 +2017,8 @@ public final class FilePath implements Serializable { try (InputStream fis = Files.newInputStream(reading(f).toPath())) { org.apache.commons.io.IOUtils.copy(fis, out); return null; + } catch (InvalidPathException e) { + throw new IOException(e); } finally { out.close(); } diff --git a/core/src/main/java/hudson/FileSystemProvisioner.java b/core/src/main/java/hudson/FileSystemProvisioner.java index 5b13241fbe998303df80215d2309db56ed6b8565..13f55b7370028832eba66ea7e16af84cb19547aa 100644 --- a/core/src/main/java/hudson/FileSystemProvisioner.java +++ b/core/src/main/java/hudson/FileSystemProvisioner.java @@ -32,6 +32,7 @@ import hudson.model.Job; import hudson.model.TaskListener; import hudson.util.io.ArchiverFactory; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import jenkins.model.Jenkins; import hudson.model.listeners.RunListener; import hudson.scm.SCM; @@ -218,6 +219,8 @@ public abstract class FileSystemProvisioner implements ExtensionPoint, Describab File wss = new File(build.getRootDir(),"workspace.tgz"); try (OutputStream os = new BufferedOutputStream(Files.newOutputStream(wss.toPath()))) { ws.archive(ArchiverFactory.TARGZ, os, glob); + } catch (InvalidPathException e) { + throw new IOException(e); } return new WorkspaceSnapshotImpl(); } diff --git a/core/src/main/java/hudson/Main.java b/core/src/main/java/hudson/Main.java index 4abcf5c291449ae8be31e7957956467be9113afd..f341c88d30fb96a44b60165a3573dc78829c42e0 100644 --- a/core/src/main/java/hudson/Main.java +++ b/core/src/main/java/hudson/Main.java @@ -26,6 +26,7 @@ package hudson; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import jenkins.util.SystemProperties; import hudson.util.DualOutputStream; import hudson.util.EncodingStream; @@ -155,6 +156,8 @@ public class Main { ret = proc.join(); w.write(""+ret+""+(System.currentTimeMillis()-start)+""); + } catch (InvalidPathException e) { + throw new IOException(e); } URL location = new URL(jobURL, "postBuildResult"); @@ -173,6 +176,8 @@ public class Main { // send the data try (InputStream in = Files.newInputStream(tmpFile.toPath())) { org.apache.commons.io.IOUtils.copy(in, con.getOutputStream()); + } catch (InvalidPathException e) { + throw new IOException(e); } if(con.getResponseCode()!=200) { diff --git a/core/src/main/java/hudson/PluginWrapper.java b/core/src/main/java/hudson/PluginWrapper.java index 1a55bbc1bd248c792c113874ac47ff140b7319f7..9ca85b04aa4e694e57b3357c49a86172dbda8d03 100644 --- a/core/src/main/java/hudson/PluginWrapper.java +++ b/core/src/main/java/hudson/PluginWrapper.java @@ -30,6 +30,7 @@ import hudson.model.AdministrativeMonitor; import hudson.model.Api; import hudson.model.ModelObject; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import jenkins.YesNoMaybe; import jenkins.model.Jenkins; import hudson.model.UpdateCenter; @@ -496,8 +497,11 @@ public class PluginWrapper implements Comparable, ModelObject { */ public void disable() throws IOException { // creates an empty file - OutputStream os = Files.newOutputStream(disableFile.toPath()); - os.close(); + try (OutputStream os = Files.newOutputStream(disableFile.toPath())) { + os.close(); + } catch (InvalidPathException e) { + throw new IOException(e); + } } /** diff --git a/core/src/main/java/hudson/Util.java b/core/src/main/java/hudson/Util.java index f7758cbedb92bef602e9b8af7feb1729d57d9a6b..07ff96fb007f9939cddc122f56ef8351c33c321b 100644 --- a/core/src/main/java/hudson/Util.java +++ b/core/src/main/java/hudson/Util.java @@ -23,6 +23,7 @@ */ package hudson; +import java.nio.file.InvalidPathException; import jenkins.util.SystemProperties; import com.sun.jna.Native; @@ -202,6 +203,8 @@ public class Util { int len; while ((len = r.read(buf, 0, buf.length)) > 0) str.append(buf, 0, len); + } catch (InvalidPathException e) { + throw new IOException(e); } return str.toString(); @@ -283,7 +286,11 @@ public class Util { if(!f.delete() && f.exists()) { // trouble-shooting. - Files.deleteIfExists(f.toPath()); + try { + Files.deleteIfExists(f.toPath()); + } catch (InvalidPathException e) { + throw new IOException(e); + } // see https://java.net/projects/hudson/lists/users/archive/2008-05/message/357 // I suspect other processes putting files in this directory @@ -811,6 +818,8 @@ public class Util { public static String getDigestOf(@Nonnull File file) throws IOException { try (InputStream is = Files.newInputStream(file.toPath())) { return getDigestOf(new BufferedInputStream(is)); + } catch (InvalidPathException e) { + throw new IOException(e); } } @@ -1143,7 +1152,11 @@ public class Util { * Creates an empty file. */ public static void touch(@Nonnull File file) throws IOException { - Files.newOutputStream(file.toPath()).close(); + try { + Files.newOutputStream(file.toPath()).close(); + } catch (InvalidPathException e) { + throw new IOException(e); + } } /** diff --git a/core/src/main/java/hudson/WebAppMain.java b/core/src/main/java/hudson/WebAppMain.java index 2081a685fd5f28ea71e81550d9f653fadcd5e379..d9b11ccfb53877ee3df9488d221ef8a1c20417d4 100644 --- a/core/src/main/java/hudson/WebAppMain.java +++ b/core/src/main/java/hudson/WebAppMain.java @@ -26,6 +26,7 @@ package hudson; import hudson.security.ACLContext; import java.io.OutputStream; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.StandardOpenOption; import jenkins.util.SystemProperties; import com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider; @@ -278,7 +279,7 @@ public class WebAppMain implements ServletContextListener { private void recordBootAttempt(File home) { try (OutputStream o=Files.newOutputStream(BootFailure.getBootFailureFile(home).toPath(), StandardOpenOption.CREATE, StandardOpenOption.APPEND)) { o.write((new Date().toString() + System.getProperty("line.separator", "\n")).toString().getBytes()); - } catch (IOException e) { + } catch (IOException | InvalidPathException e) { LOGGER.log(WARNING, "Failed to record boot attempts",e); } } diff --git a/core/src/main/java/hudson/XmlFile.java b/core/src/main/java/hudson/XmlFile.java index ba1434b8f76ab2498852d620dfcd3fa34098f4f3..72d4d6c128ac605d4abd74d0d0587fb2d39af508 100644 --- a/core/src/main/java/hudson/XmlFile.java +++ b/core/src/main/java/hudson/XmlFile.java @@ -34,6 +34,7 @@ import hudson.model.Descriptor; import hudson.util.AtomicFileWriter; import hudson.util.XStream2; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.Locator; @@ -140,7 +141,7 @@ public final class XmlFile { } try (InputStream in = new BufferedInputStream(Files.newInputStream(file.toPath()))) { return xs.fromXML(in); - } catch (XStreamException | Error e) { + } catch (XStreamException | Error | InvalidPathException e) { throw new IOException("Unable to read "+file,e); } } @@ -157,7 +158,7 @@ public final class XmlFile { try (InputStream in = new BufferedInputStream(Files.newInputStream(file.toPath()))) { // TODO: expose XStream the driver from XStream return xs.unmarshal(DEFAULT_DRIVER.createReader(in), o); - } catch (XStreamException | Error e) { + } catch (XStreamException | Error | InvalidPathException e) { throw new IOException("Unable to read "+file,e); } } @@ -201,14 +202,18 @@ public final class XmlFile { * @return Reader for the file. should be close externally once read. */ public Reader readRaw() throws IOException { - InputStream fileInputStream = Files.newInputStream(file.toPath()); try { - return new InputStreamReader(fileInputStream, sniffEncoding()); - } catch(IOException ex) { - // Exception may happen if we fail to find encoding or if this encoding is unsupported. - // In such case we close the underlying stream and rethrow. - Util.closeAndLogFailures(fileInputStream, LOGGER, "FileInputStream", file.toString()); - throw ex; + InputStream fileInputStream = Files.newInputStream(file.toPath()); + try { + return new InputStreamReader(fileInputStream, sniffEncoding()); + } catch (IOException ex) { + // Exception may happen if we fail to find encoding or if this encoding is unsupported. + // In such case we close the underlying stream and rethrow. + Util.closeAndLogFailures(fileInputStream, LOGGER, "FileInputStream", file.toString()); + throw ex; + } + } catch (InvalidPathException e) { + throw new IOException(e); } } @@ -288,7 +293,9 @@ public final class XmlFile { // in such a case, assume UTF-8 rather than fail, since Jenkins internally always write XML in UTF-8 return "UTF-8"; } catch (SAXException e) { - throw new IOException("Failed to detect encoding of "+file,e); + throw new IOException("Failed to detect encoding of " + file, e); + } catch (InvalidPathException e) { + throw new IOException(e); } catch (ParserConfigurationException e) { throw new AssertionError(e); // impossible } diff --git a/core/src/main/java/hudson/console/ConsoleAnnotator.java b/core/src/main/java/hudson/console/ConsoleAnnotator.java index eab2376ddde655485a4879b7a523cb52f40b65aa..c19ac974b686064cd0adb7767065c7d04a6a3af4 100644 --- a/core/src/main/java/hudson/console/ConsoleAnnotator.java +++ b/core/src/main/java/hudson/console/ConsoleAnnotator.java @@ -30,6 +30,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.ListIterator; +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; /** * Annotates one line of console output. @@ -71,15 +73,16 @@ public abstract class ConsoleAnnotator implements Serializable { * Annotates one line. * * @param context - * The object that owns the console output. Never null. + * The object that owns the console output. Never {@code null}. * @param text * Contains a single line of console output, and defines convenient methods to add markup. - * The callee should put markup into this object. Never null. + * The callee should put markup into this object. Never {@code null}. * @return * The {@link ConsoleAnnotator} object that will annotate the next line of the console output. - * To indicate that you are not interested in the following lines, return null. + * To indicate that you are not interested in the following lines, return {@code null}. */ - public abstract ConsoleAnnotator annotate(T context, MarkupText text ); + @CheckForNull + public abstract ConsoleAnnotator annotate(@Nonnull T context, @Nonnull MarkupText text ); /** * Cast operation that restricts T. diff --git a/core/src/main/java/hudson/console/HudsonExceptionNote.java b/core/src/main/java/hudson/console/HudsonExceptionNote.java index c442dff2fdb48d4caf42e692e8231bb27c76246f..83511694ceca4028e4b58011bba677d508846d23 100644 --- a/core/src/main/java/hudson/console/HudsonExceptionNote.java +++ b/core/src/main/java/hudson/console/HudsonExceptionNote.java @@ -1,7 +1,7 @@ /* * The MIT License * - * Copyright (c) 2010-2011, CloudBees, Inc. + * Copyright (c) 2010-2017, 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 @@ -27,73 +27,31 @@ import hudson.Extension; import hudson.MarkupText; import org.jenkinsci.Symbol; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - +// TODO: the implementation has been deprecated due to JENKINS-42861 +// Consider providing alternate search mechanisms (JIRA, grepcode, etc.) as proposed in +// https://github.com/jenkinsci/jenkins/pull/2808#pullrequestreview-27467560 (JENKINS-43612) /** - * Placed on the beginning of the exception stack trace produced by Hudson, which in turn produces hyperlinked stack trace. + * Placed on the beginning of the exception stack trace produced by Jenkins, + * which in turn produces hyperlinked stack trace. * *

* Exceptions in the user code (like junit etc) should be handled differently. This is only for exceptions - * that occur inside Hudson. + * that occur inside Jenkins. * * @author Kohsuke Kawaguchi - * @since 1.349 + * @since 1.349 - produces search hyperlinks to the http://stacktrace.jenkins-ci.org service + * @since TODO - does nothing due to JENKINS-42861 + * @deprecated This ConsoleNote used to provide hyperlinks to the + * http://stacktrace.jenkins-ci.org/ service, which is dead now (JENKINS-42861). + * This console note does nothing right now. */ +@Deprecated public class HudsonExceptionNote extends ConsoleNote { @Override public ConsoleAnnotator annotate(Object context, MarkupText text, int charPos) { - // An exception stack trace looks like this: - // org.acme.FooBarException: message - // at org.acme.Foo.method(Foo.java:123) - // Caused by: java.lang.ClassNotFoundException: - String line = text.getText(); - int end = line.indexOf(':',charPos); - if (end<0) { - if (CLASSNAME.matcher(line.substring(charPos)).matches()) - end = line.length(); - else - return null; // unexpected format. abort. - } - text.addHyperlinkLowKey(charPos,end,annotateClassName(line.substring(charPos,end))); - - return new ConsoleAnnotator() { - public ConsoleAnnotator annotate(Object context, MarkupText text) { - String line = text.getText(); - - Matcher m = STACK_TRACE_ELEMENT.matcher(line); - if (m.find()) {// allow the match to happen in the middle of a line to cope with prefix. Ant and Maven put them, among many other tools. - text.addHyperlinkLowKey(m.start()+4,m.end(),annotateMethodName(m.group(1),m.group(2),m.group(3),Integer.parseInt(m.group(4)))); - return this; - } - - int idx = line.indexOf(CAUSED_BY); - if (idx>=0) { - int s = idx + CAUSED_BY.length(); - int e = line.indexOf(':', s); - if (e<0) e = line.length(); - text.addHyperlinkLowKey(s,e,annotateClassName(line.substring(s,e))); - return this; - } - - if (AND_MORE.matcher(line).matches()) - return this; - - // looks like we are done with the stack trace - return null; - } - }; - } - // TODO; separate out the annotations and mark up - - private String annotateMethodName(String className, String methodName, String sourceFileName, int lineNumber) { - return "http://stacktrace.jenkins-ci.org/search/?query="+className+'.'+methodName+"&entity=method"; - } - - private String annotateClassName(String className) { - return "http://stacktrace.jenkins-ci.org/search?query="+className; + return null; } @Extension @Symbol("stackTrace") @@ -103,21 +61,4 @@ public class HudsonExceptionNote extends ConsoleNote { return "Exception Stack Trace"; } } - - /** - * Regular expression that represents a valid class name. - */ - private static final String CLASSNAME_PATTERN = "[\\p{L}0-9$_.]+"; - - private static final Pattern CLASSNAME = Pattern.compile(CLASSNAME_PATTERN+"\r?\n?"); - - /** - * Matches to the line like "\tat org.acme.Foo.method(File.java:123)" - * and captures class name, method name, source file name, and line number separately. - */ - private static final Pattern STACK_TRACE_ELEMENT = Pattern.compile("\tat ("+CLASSNAME_PATTERN+")\\.([\\p{L}0-9$_<>]+)\\((\\S+):([0-9]+)\\)"); - - private static final String CAUSED_BY = "Caused by: "; - - private static final Pattern AND_MORE = Pattern.compile("\t... [0-9]+ more\n"); } diff --git a/core/src/main/java/hudson/init/impl/InstallUncaughtExceptionHandler.java b/core/src/main/java/hudson/init/impl/InstallUncaughtExceptionHandler.java index be55c08ff4eb094724468d15ac4e0f69d4ed45d5..d8412f6ad45c3c0a8fda8c3c1fd3e00da87cc1f4 100644 --- a/core/src/main/java/hudson/init/impl/InstallUncaughtExceptionHandler.java +++ b/core/src/main/java/hudson/init/impl/InstallUncaughtExceptionHandler.java @@ -20,11 +20,18 @@ import org.kohsuke.stapler.Stapler; * @author Kohsuke Kawaguchi */ public class InstallUncaughtExceptionHandler { + + private static final Logger LOGGER = Logger.getLogger(InstallUncaughtExceptionHandler.class.getName()); + @Initializer public static void init(final Jenkins j) throws IOException { CompressionFilter.setUncaughtExceptionHandler(j.servletContext, new UncaughtExceptionHandler() { @Override public void reportException(Throwable e, ServletContext context, HttpServletRequest req, HttpServletResponse rsp) throws ServletException, IOException { + if (rsp.isCommitted()) { + LOGGER.log(Level.WARNING, null, e); + return; + } req.setAttribute("javax.servlet.error.exception",e); try { WebApp.get(j.servletContext).getSomeStapler() @@ -38,10 +45,10 @@ public class InstallUncaughtExceptionHandler { }); try { Thread.setDefaultUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler()); - DefaultUncaughtExceptionHandler.LOGGER.log(Level.FINE, "Successfully installed a global UncaughtExceptionHandler."); + LOGGER.log(Level.FINE, "Successfully installed a global UncaughtExceptionHandler."); } catch (SecurityException ex) { - DefaultUncaughtExceptionHandler.LOGGER.log(Level.SEVERE, + LOGGER.log(Level.SEVERE, "Failed to set the default UncaughtExceptionHandler. " + "If any threads die due to unhandled coding errors then there will be no logging of this information. " + "The lack of this diagnostic information will make it harder to track down issues which will reduce the supportability of Jenkins. " + @@ -53,8 +60,6 @@ public class InstallUncaughtExceptionHandler { /** An UncaughtExceptionHandler that just logs the exception */ private static class DefaultUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { - private static final Logger LOGGER = Logger.getLogger(InstallUncaughtExceptionHandler.class.getName()); - @Override public void uncaughtException(Thread t, Throwable ex) { // if this was an OutOfMemoryError then all bets about logging are off - but in the absence of anything else... @@ -65,4 +70,7 @@ public class InstallUncaughtExceptionHandler { } } + + private InstallUncaughtExceptionHandler() {} + } diff --git a/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java b/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java index 803a02b3b67d4a733c0dc10b840f74a7465626fe..db7ca365a722e6c0215fcf642875c881970e92ff 100644 --- a/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java +++ b/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java @@ -33,6 +33,7 @@ import hudson.util.jna.SHELLEXECUTEINFO; import hudson.util.jna.Shell32; import java.io.InputStream; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import jenkins.model.Jenkins; import hudson.AbortException; import hudson.Extension; @@ -313,6 +314,8 @@ public class WindowsInstallerLink extends ManagementLink { } finally { try (InputStream fin = Files.newInputStream(new File(pwd,"redirect.log").toPath())) { IOUtils.copy(fin, out.getLogger()); + } catch (InvalidPathException e) { + // ignore; } } } diff --git a/core/src/main/java/hudson/model/AbstractItem.java b/core/src/main/java/hudson/model/AbstractItem.java index e09158340bd8a6bb8a7094cb9a59af686aa39873..dde9b636122ac3c9b8b1a7fda4186c77807b35f6 100644 --- a/core/src/main/java/hudson/model/AbstractItem.java +++ b/core/src/main/java/hudson/model/AbstractItem.java @@ -31,6 +31,7 @@ import hudson.Util; import hudson.Functions; import hudson.BulkChange; import hudson.cli.declarative.CLIResolver; +import hudson.model.Queue.Executable; import hudson.model.listeners.ItemListener; import hudson.model.listeners.SaveableListener; import hudson.model.queue.Tasks; @@ -87,6 +88,8 @@ import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import static hudson.model.queue.Executables.getParentOf; +import hudson.model.queue.SubTask; +import java.lang.reflect.InvocationTargetException; import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; import org.apache.commons.io.FileUtils; import org.kohsuke.accmod.Restricted; @@ -621,9 +624,12 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet Map buildsInProgress = new LinkedHashMap<>(); for (Computer c : Jenkins.getInstance().getComputers()) { for (Executor e : c.getAllExecutors()) { - WorkUnit workUnit = e.getCurrentWorkUnit(); - if (workUnit != null) { - Item item = Tasks.getItemOf(getParentOf(workUnit.getExecutable())); + final WorkUnit workUnit = e.getCurrentWorkUnit(); + final Executable executable = workUnit != null ? workUnit.getExecutable() : null; + final SubTask subtask = executable != null ? getParentOf(executable) : null; + + if (subtask != null) { + Item item = Tasks.getItemOf(subtask); if (item != null) { while (item != null) { if (item == this) { diff --git a/core/src/main/java/hudson/model/Executor.java b/core/src/main/java/hudson/model/Executor.java index df08c72a2504d9f4bf58e010e710dff0c7c966fc..6281c43443806a6efaadb77dc2d0bcd838569925 100644 --- a/core/src/main/java/hudson/model/Executor.java +++ b/core/src/main/java/hudson/model/Executor.java @@ -511,6 +511,7 @@ public class Executor extends Thread implements ModelObject { * null if the executor is idle. */ @Exported + @CheckForNull public WorkUnit getCurrentWorkUnit() { lock.readLock().lock(); try { diff --git a/core/src/main/java/hudson/model/FileParameterValue.java b/core/src/main/java/hudson/model/FileParameterValue.java index edb59a8b8a782072cb233a9dd2caa12c1788b94d..85bfb043874998fc2e743a8019a4a062e186e599 100644 --- a/core/src/main/java/hudson/model/FileParameterValue.java +++ b/core/src/main/java/hudson/model/FileParameterValue.java @@ -35,6 +35,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import javax.servlet.ServletException; import org.apache.commons.fileupload.FileItem; @@ -212,6 +213,8 @@ public class FileParameterValue extends ParameterValue { } else { response.serveFile(request, data, lastModified, contentLength, originalFileName); } + } catch (InvalidPathException e) { + throw new IOException(e); } } } @@ -241,7 +244,11 @@ public class FileParameterValue extends ParameterValue { } public InputStream getInputStream() throws IOException { - return Files.newInputStream(file.toPath()); + try { + return Files.newInputStream(file.toPath()); + } catch (InvalidPathException e) { + throw new IOException(e); + } } public String getContentType() { @@ -265,7 +272,7 @@ public class FileParameterValue extends ParameterValue { try (InputStream inputStream = Files.newInputStream(file.toPath())) { return IOUtils.toByteArray(inputStream); } - } catch (IOException e) { + } catch (IOException | InvalidPathException e) { throw new Error(e); } } @@ -302,7 +309,11 @@ public class FileParameterValue extends ParameterValue { @Deprecated public OutputStream getOutputStream() throws IOException { - return Files.newOutputStream(file.toPath()); + try { + return Files.newOutputStream(file.toPath()); + } catch (InvalidPathException e) { + throw new IOException(e); + } } @Override diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index cac26bab22cfcff995546b9a01b7febd199644ad..4e524ed1a90c651f9e04e8bc5d8db473e541d313 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -64,6 +64,7 @@ import hudson.model.queue.WorkUnitContext; import hudson.security.ACL; import hudson.security.AccessControlled; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import jenkins.security.QueueItemAuthenticatorProvider; import jenkins.util.Timer; import hudson.triggers.SafeTimerTask; @@ -384,6 +385,8 @@ public class Queue extends ResourceController implements Saveable { if (j != null) j.scheduleBuild(); } + } catch (InvalidPathException e) { + throw new IOException(e); } // discard the queue file now that we are done queueFile.delete(); diff --git a/core/src/main/java/hudson/model/Run.java b/core/src/main/java/hudson/model/Run.java index c5adc86c750a9120ea16b86bfa9e8296035829bd..b2153447338d0878b6fa2dc2204a5f6317cf9511 100644 --- a/core/src/main/java/hudson/model/Run.java +++ b/core/src/main/java/hudson/model/Run.java @@ -42,6 +42,7 @@ import hudson.console.ConsoleNote; import hudson.console.ModelHyperlinkNote; import hudson.console.PlainTextConsoleOutputStream; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.StandardOpenOption; import jenkins.util.SystemProperties; import hudson.Util; @@ -1367,12 +1368,16 @@ public abstract class Run ,RunT extends Run,RunT extends Run= 0) { tar.write(buf, 0, len); } - } catch (IOException e) {// log the exception in any case + } catch (IOException | InvalidPathException e) {// log the exception in any case IOException ioE = new IOException("Error writing to tar file from: " + file, e); throw ioE; } diff --git a/core/src/main/java/hudson/util/io/ZipArchiver.java b/core/src/main/java/hudson/util/io/ZipArchiver.java index d58a5c292f242a61ea374b0f723751fcfd5ef0f0..9bd58808b28315d5c7468d8ce401fda92d5ede8b 100644 --- a/core/src/main/java/hudson/util/io/ZipArchiver.java +++ b/core/src/main/java/hudson/util/io/ZipArchiver.java @@ -28,6 +28,7 @@ import hudson.util.FileVisitor; import hudson.util.IOUtils; import java.io.InputStream; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import org.apache.tools.zip.ZipEntry; import org.apache.tools.zip.ZipOutputStream; @@ -75,6 +76,8 @@ final class ZipArchiver extends Archiver { int len; while((len=in.read(buf))>=0) zip.write(buf,0,len); + } catch (InvalidPathException e) { + throw new IOException(e); } zip.closeEntry(); } diff --git a/core/src/main/java/hudson/views/GlobalDefaultViewConfiguration.java b/core/src/main/java/hudson/views/GlobalDefaultViewConfiguration.java index 40a045a0844ca6d4c27213fac6d5d6474299618a..c76ae404c383f3e7d98019429fc71795253bf792 100644 --- a/core/src/main/java/hudson/views/GlobalDefaultViewConfiguration.java +++ b/core/src/main/java/hudson/views/GlobalDefaultViewConfiguration.java @@ -24,6 +24,7 @@ package hudson.views; import hudson.Extension; +import hudson.model.View; import jenkins.model.GlobalConfiguration; import jenkins.model.Jenkins; import net.sf.json.JSONObject; @@ -41,7 +42,18 @@ public class GlobalDefaultViewConfiguration extends GlobalConfiguration { public boolean configure(StaplerRequest req, JSONObject json) throws FormException { // for compatibility reasons, the actual value is stored in Jenkins Jenkins j = Jenkins.getInstance(); - j.setPrimaryView(json.has("primaryView") ? j.getView(json.getString("primaryView")) : j.getViews().iterator().next()); + if (json.has("primaryView")) { + final String viewName = json.getString("primaryView"); + final View newPrimaryView = j.getView(viewName); + if (newPrimaryView == null) { + throw new FormException(Messages.GlobalDefaultViewConfiguration_ViewDoesNotExist(viewName), "primaryView"); + } + j.setPrimaryView(newPrimaryView); + } else { + // Fallback if the view is not specified + j.setPrimaryView(j.getViews().iterator().next()); + } + return true; } } diff --git a/core/src/main/java/jenkins/diagnosis/HsErrPidList.java b/core/src/main/java/jenkins/diagnosis/HsErrPidList.java index df8a287b5269c23f9b82ee7a739f1a7711df877c..da7f0cde60ec1375e4f6a9ef6fb1d015bac9e2e3 100644 --- a/core/src/main/java/jenkins/diagnosis/HsErrPidList.java +++ b/core/src/main/java/jenkins/diagnosis/HsErrPidList.java @@ -7,6 +7,7 @@ import hudson.Util; import hudson.model.AdministrativeMonitor; import hudson.util.jna.Kernel32Utils; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.OpenOption; import java.nio.file.StandardOpenOption; import jenkins.model.Jenkins; @@ -55,6 +56,8 @@ public class HsErrPidList extends AdministrativeMonitor { try { try (FileChannel ch = FileChannel.open(getSecretKeyFile().toPath(), StandardOpenOption.READ)) { map = ch.map(MapMode.READ_ONLY,0,1); + } catch (InvalidPathException e) { + throw new IOException(e); } scan("./hs_err_pid%p.log"); diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index dd666a638525939a6941dbd24a8a7f5cc42d7a1a..0bd879b298238f109b4ab1d399875752c8bcedca 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -1824,7 +1824,14 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve return names; } - public View getView(String name) { + /** + * Gets a view by the specified name. + * The method iterates through {@link hudson.model.ViewGroup}s if required. + * @param name Name of the view + * @return View instance or {@code null} if it is missing + */ + @CheckForNull + public View getView(@CheckForNull String name) { return viewGroupMixIn.getView(name); } @@ -1883,7 +1890,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve return viewGroupMixIn.getPrimaryView(); } - public void setPrimaryView(View v) { + public void setPrimaryView(@Nonnull View v) { this.primaryView = v.getViewName(); } diff --git a/core/src/main/java/jenkins/security/DefaultConfidentialStore.java b/core/src/main/java/jenkins/security/DefaultConfidentialStore.java index 8b224cf36384c0d93e77ac104cc4cb16ce6aa925..a8e96c045f8720d3fd13c2efeac31beee823dd8c 100644 --- a/core/src/main/java/jenkins/security/DefaultConfidentialStore.java +++ b/core/src/main/java/jenkins/security/DefaultConfidentialStore.java @@ -7,6 +7,7 @@ import hudson.util.TextFile; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import jenkins.model.Jenkins; import javax.crypto.Cipher; @@ -82,6 +83,8 @@ public class DefaultConfidentialStore extends ConfidentialStore { } } catch (GeneralSecurityException e) { throw new IOException("Failed to persist the key: "+key.getId(),e); + } catch (InvalidPathException e) { + throw new IOException(e); } } @@ -106,6 +109,8 @@ public class DefaultConfidentialStore extends ConfidentialStore { } } catch (GeneralSecurityException e) { throw new IOException("Failed to load the key: "+key.getId(),e); + } catch (InvalidPathException e) { + throw new IOException(e); } catch (IOException x) { if (x.getCause() instanceof BadPaddingException) { return null; // broken somehow diff --git a/core/src/main/java/jenkins/util/JSONSignatureValidator.java b/core/src/main/java/jenkins/util/JSONSignatureValidator.java index 2567a4807120deb9a37dcaed462485b614684114..1d23b709847c6cdbaa6f006ee5f2c56d73910e8c 100644 --- a/core/src/main/java/jenkins/util/JSONSignatureValidator.java +++ b/core/src/main/java/jenkins/util/JSONSignatureValidator.java @@ -3,6 +3,7 @@ package jenkins.util; import com.trilead.ssh2.crypto.Base64; import hudson.util.FormValidation; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import jenkins.model.Jenkins; import net.sf.json.JSONObject; import org.apache.commons.io.output.NullOutputStream; @@ -177,6 +178,8 @@ public class JSONSignatureValidator { Certificate certificate; try (InputStream in = Files.newInputStream(cert.toPath())) { certificate = cf.generateCertificate(in); + } catch (InvalidPathException e) { + throw new IOException(e); } catch (CertificateException e) { LOGGER.log(Level.WARNING, String.format("Files in %s are expected to be either " + "certificates or .txt files documenting the certificates, " diff --git a/core/src/main/java/jenkins/util/VirtualFile.java b/core/src/main/java/jenkins/util/VirtualFile.java index a7379c3d0631b724d5eee7c3c548cdace9df9c2b..6c70fedcea054e4ee2568b214b12f0ef05b759c1 100644 --- a/core/src/main/java/jenkins/util/VirtualFile.java +++ b/core/src/main/java/jenkins/util/VirtualFile.java @@ -295,7 +295,11 @@ public abstract class VirtualFile implements Comparable, Serializab if (isIllegalSymlink()) { throw new FileNotFoundException(f.getPath()); } - return Files.newInputStream(f.toPath()); + try { + return Files.newInputStream(f.toPath()); + } catch (InvalidPathException e) { + throw new IOException(e); + } } private boolean isIllegalSymlink() { // TODO JENKINS-26838 try { diff --git a/core/src/main/java/jenkins/util/io/FileBoolean.java b/core/src/main/java/jenkins/util/io/FileBoolean.java index 3f652875b6f29477d7538baecb6507794976c820..7caa25e9e39a57ba3b0dea0a0009664b656520e8 100644 --- a/core/src/main/java/jenkins/util/io/FileBoolean.java +++ b/core/src/main/java/jenkins/util/io/FileBoolean.java @@ -1,6 +1,7 @@ package jenkins.util.io; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import jenkins.model.Jenkins; import java.io.File; @@ -59,7 +60,7 @@ public class FileBoolean { file.getParentFile().mkdirs(); Files.newOutputStream(file.toPath()).close(); get(); // update state - } catch (IOException e) { + } catch (IOException | InvalidPathException e) { LOGGER.log(Level.WARNING, "Failed to touch "+file); } } diff --git a/core/src/main/java/jenkins/util/xml/XMLUtils.java b/core/src/main/java/jenkins/util/xml/XMLUtils.java index 6b756729c53ae1d3e3f5d134f892c2a6e67ed0c2..85d37f30eaabf7b5aeefd4598cec9a113ff3f532 100644 --- a/core/src/main/java/jenkins/util/xml/XMLUtils.java +++ b/core/src/main/java/jenkins/util/xml/XMLUtils.java @@ -2,6 +2,7 @@ package jenkins.util.xml; import java.io.InputStream; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import jenkins.util.SystemProperties; import org.apache.commons.io.IOUtils; import org.kohsuke.accmod.Restricted; @@ -142,6 +143,8 @@ public final class XMLUtils { try (InputStream fileInputStream = Files.newInputStream(file.toPath()); InputStreamReader fileReader = new InputStreamReader(fileInputStream, encoding)) { return parse(fileReader); + } catch (InvalidPathException e) { + throw new IOException(e); } } diff --git a/core/src/main/resources/hudson/views/Messages.properties b/core/src/main/resources/hudson/views/Messages.properties index eef88e72663ed764506e094b2adf5dddfc1137b6..34cfb87fbd2e9051e9cf743f7a6912031807e227 100644 --- a/core/src/main/resources/hudson/views/Messages.properties +++ b/core/src/main/resources/hudson/views/Messages.properties @@ -30,3 +30,5 @@ StatusColumn.DisplayName=Status WeatherColumn.DisplayName=Weather DefaultViewsTabsBar.DisplayName=Default Views TabBar DefaultMyViewsTabsBar.DisplayName=Default My Views TabBar + +GlobalDefaultViewConfiguration.ViewDoesNotExist=The specified view does not exist: {0} diff --git a/pom.xml b/pom.xml index 454c99d6b8e8605186c6a7d7ec126c63327f29f3..135285de61f7769a92e89ef338529d2694f24a80 100644 --- a/pom.xml +++ b/pom.xml @@ -33,7 +33,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 2.56-SNAPSHOT + 2.57-SNAPSHOT pom Jenkins main module diff --git a/rc.changelog.rb b/rc.changelog.rb deleted file mode 100644 index 7f3051b461197ca2b7a4440e3651930c42a4bd58..0000000000000000000000000000000000000000 --- a/rc.changelog.rb +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/ruby -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi -# -# 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. - - -# Moves the changelog from the trunk section to the release section -# Usage: rc.changelog.rb < changelog.html > output.html - -changelog = [] -inside = false; - -ARGF.each do |line| - if /=TRUNK-BEGIN=/ =~ line - inside = true; - puts line - # new template - puts "
    " - puts "
  • " - puts "
" - next - end - if /=TRUNK-END=/ =~ line - inside = false; - puts line - next - end - if inside - changelog << line - next - end - if /=RC-CHANGES=/ =~ line - changelog.each { |line| puts line } - next - end - puts line -end diff --git a/test/pom.xml b/test/pom.xml index 8376faac3c7d7445cacf7cd03843e373c2041f47..48b38e1ee40603479d3cf2cd464367832a9ef2f3 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -28,7 +28,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 2.56-SNAPSHOT + 2.57-SNAPSHOT test diff --git a/test/src/test/java/hudson/views/GlobalDefaultViewConfigurationTest.java b/test/src/test/java/hudson/views/GlobalDefaultViewConfigurationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..41e9bf89257e05c7b56c3ce778d943787a0d495f --- /dev/null +++ b/test/src/test/java/hudson/views/GlobalDefaultViewConfigurationTest.java @@ -0,0 +1,66 @@ +/* + * The MIT License + * + * Copyright (c) 2017 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.views; + +import hudson.model.Descriptor; +import net.sf.json.JSONObject; +import static org.hamcrest.Matchers.*; +import org.junit.Assert; +import static org.junit.Assert.assertThat; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.JenkinsRule; +import org.kohsuke.stapler.MockStaplerRequestBuilder; +import org.kohsuke.stapler.StaplerRequest; + +/** + * Tests of {@link GlobalDefaultViewConfiguration}. + * @author Oleg Nenashev + */ +public class GlobalDefaultViewConfigurationTest { + + @Rule + public JenkinsRule j = new JenkinsRule(); + + @Test + @Issue("JENKINS-42717") + public void shouldNotFailIfTheDefaultViewIsMissing() { + String viewName = "NonExistentView"; + GlobalDefaultViewConfiguration c = new GlobalDefaultViewConfiguration(); + + StaplerRequest create = new MockStaplerRequestBuilder(j, "/configure").build(); + JSONObject params = new JSONObject(); + params.accumulate("primaryView", viewName); + try { + c.configure(create, params); + } catch(Descriptor.FormException ex) { + assertThat("Wrong exception message for the form failure", + ex.getMessage(), containsString(Messages.GlobalDefaultViewConfiguration_ViewDoesNotExist(viewName))); + return; + } + Assert.fail("Expected FormException"); + } + +} diff --git a/test/src/test/java/org/kohsuke/stapler/MockStaplerRequestBuilder.java b/test/src/test/java/org/kohsuke/stapler/MockStaplerRequestBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..2825314a91acd12e24fce807ae1ea56219c13d5c --- /dev/null +++ b/test/src/test/java/org/kohsuke/stapler/MockStaplerRequestBuilder.java @@ -0,0 +1,81 @@ +/* + * The MIT License + * + * Copyright (c) 2017 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.kohsuke.stapler; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import javax.annotation.Nonnull; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import jenkins.model.Jenkins; +import org.eclipse.jetty.server.Request; +import org.jvnet.hudson.test.JenkinsRule; +import org.mockito.Mockito; +import org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest; + +/** + * Mocked version of {@link StaplerRequest}. + * @author Oleg Nenashev + */ +public class MockStaplerRequestBuilder{ + + private final JenkinsRule r; + + private final List ancestors = new ArrayList<>(); + private final TokenList tokens; + final Map getters = new HashMap<>(); + private Stapler stapler; + + public MockStaplerRequestBuilder(@Nonnull JenkinsRule r, String url) { + this.r = r; + this.tokens = new TokenList(url); + } + + public MockStaplerRequestBuilder withStapler(Stapler stapler) { + this.stapler = stapler; + return this; + } + + public MockStaplerRequestBuilder withGetter(String objectName, Object object) { + this.getters.put(objectName, object); + return this; + } + + public MockStaplerRequestBuilder withAncestor(AncestorImpl ancestor) { + this.ancestors.add(ancestor); + return this; + } + + public StaplerRequest build() throws AssertionError { + HttpServletRequest rawRequest = Mockito.mock(HttpServletRequest.class); + return new RequestImpl(stapler != null ? stapler : new Stapler(), rawRequest, ancestors, tokens); + } + +} diff --git a/war/pom.xml b/war/pom.xml index d7dbeef83ccd5f21beec97e90578a95766eb2b9c..c0891ef5cae74ee1f89cdaf085f1cb9e920b8a80 100644 --- a/war/pom.xml +++ b/war/pom.xml @@ -28,7 +28,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 2.56-SNAPSHOT + 2.57-SNAPSHOT jenkins-war