diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 17935bd2a35a9bf74c8634ddf4924117647f5bc8..0000000000000000000000000000000000000000 --- a/.editorconfig +++ /dev/null @@ -1,32 +0,0 @@ -# This file is for unifying the coding style for different editors and IDEs -# editorconfig.org -# -# Subline Text: https://github.com/editorconfig/editorconfig-sublime -# Emacs: https://github.com/editorconfig/editorconfig-emacs -# Jetbrains (IntelliJ etc): https://github.com/editorconfig/editorconfig-jetbrains -# Eclipse: ?? -# - - -root = true - -[*] -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[**.jelly] -indent_style = space -indent_size = 2 - -[**.js] -indent_style = space -indent_size = 4 - -[**.css] -indent_style = space -indent_size = 2 - -[*.md] -trim_trailing_whitespace = false~ \ No newline at end of file diff --git a/.gitignore b/.gitignore index edb353a62a64f1d0081206585a1e63101d579717..60ba89065c90d09f0cc1ea8935b0bf08b691b0e9 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,10 @@ build # vim *~ +*.swp + +# ctags +tags # OS X .DS_Store diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000000000000000000000000000000000..7bd3f7a8f7b30738a6187c17454f431a84f6e45f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,3 @@ +# Contributing to Jenkins +For information on contributing to Jenkins, check out the https://wiki.jenkins-ci.org/display/JENKINS/contributing and https://wiki.jenkins-ci.org/display/JENKINS/Extend+Jenkins wiki pages over at the official https://wiki.jenkins-ci.org . They will help you get started with contributing to Jenkins. + diff --git a/README.md b/README.md index f021c54d33f7f4b31d48b1b13474a7ffa3d1caa9..4ecfdb2c3738bd3ca3f83b442ecbb8b315e1e29c 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,51 @@ [![][ButlerImage]][website] -Jenkins CI -========== -Copyright © 2004–, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributors. Licensed under [MIT License]. +# About +In a nutshell, Jenkins CI is the leading open-source continuous integration server. Built with Java, it provides over 1000 plugins to support building and testing virtually any project. -About ------ -In a nutshell Jenkins CI is the leading open-source continuous integration server. Built with Java, it provides over 1000 plugins to support building and testing virtually any project. +# Downloads +Non-source downloads such as WAR files and several Linux packages can be found on our [Mirrors]. -Downloads ---------- -Non-source downloads such as WAR file and several Linux packages can be found on our [Mirrors]. - -Source ------- +# Source Our latest and greatest source of Jenkins CI can be found on [GitHub]. Fork us! -News and Website ----------------- -All about Jenkins CI can be found on our [website]. Follow us on Twitter @[jenkinsci]. +# Contributing to Jenkins +Follow [contributing](CONTRIBUTING.md) file. + +# News and Website +All information about Jenkins CI can be found on our [website]. Follow us on Twitter [@jenkinsci]. + +# License +Jenkins is **licensed** under the **[MIT License]**. The terms of the license are as follows: + + The MIT License (MIT) + + Copyright (c) 2004 Kohsuke Kawaguchi, Sun Microsystems Inc., and a number of other 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 + 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. [ButlerImage]: http://jenkins-ci.org/sites/default/files/jenkins_logo.png [MIT License]: https://github.com/jenkinsci/jenkins/raw/master/LICENSE.txt [Mirrors]: http://mirrors.jenkins-ci.org [GitHub]: https://github.com/jenkinsci/jenkins [website]: http://jenkins-ci.org -[jenkinsci]: http://twitter.com/jenkinsci +[@jenkinsci]: http://twitter.com/jenkinsci +[Contributing]: https://wiki.jenkins-ci.org/display/JENKINS/contributing +[Extend Jenkins]: https://wiki.jenkins-ci.org/display/JENKINS/Extend+Jenkins +[wiki]: https://wiki.jenkins-ci.org diff --git a/changelog.html b/changelog.html index 3531343470a7fad1d6ac43530d1dd88cda2a25b0..c40bd5ef0aa3e210d8d6abbbb79f52cc155f795c 100644 --- a/changelog.html +++ b/changelog.html @@ -20,7 +20,7 @@ Some tips: Changelog - + @@ -29,8 +29,8 @@ Some tips:
Legend: - major RFEmajor enhancement RFEenhancement - major bugmajor bug fix bugbug fix + major RFEmajor enhancement RFEenhancement + major bugmajor bug fix bugbug fix xxxxx
@@ -39,168 +39,863 @@ Some tips: Help other Jenkins users by letting the community know which releases you've used, and whether they had any significant issues.
Legend:
- Sunny = I use it on my production site without major issues.
- Cloudy = I don't recommend it.
- Lightning = I tried it but rolled back to a previous version.
View ratings below, and click one of the icons next to your version to provide your input. - + Upcoming changes Community ratings +

What's new in 1.647 (2016/02/04)

+ +

What's new in 1.646 (2016/01/25)

+ +

What's new in 1.645 (2016/01/18)

+ +

What's new in 1.644 (2016/01/10)

+ +

What's new in 1.643 (2015/12/20)

+ +

What's new in 1.642 (2015/12/13)

+ +

What's new in 1.641 (2015/12/09)

+ +

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

+ +

What's new in 1.639 (2015/11/29)

+ +

What's new in 1.638 (2015/11/11)

+ +

What's new in 1.637 (2015/11/08)

+ +

What's new in 1.636 (2015/11/01)

+ +

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

+ +

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

+ +

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

+ +

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

+ +

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

+ +

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

+ +

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

+ +

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

+ +

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

+ - - - - -

What's new in 1.597 (2015/01/19)

- +

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

+ -

What's new in 1.596 (2015/01/04)

+

What's new in 1.616 (2015/05/31)

+

What's new in 1.615 (2015/05/25)

+ -

What's new in 1.595 (2014/12/21)

+

What's new in 1.614 (2015/05/17)

-

What's new in 1.594 (2014/12/14)

+

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

-

What's new in 1.593 (2014/12/07)

+

What's new in 1.612 (2015/05/03)

-

What's new in 1.592 (2014/11/30)

+

What's new in 1.611 (2015/04/26)

-

What's new in 1.591 (2014/11/25)

+

What's new in 1.610 (2015/04/19)

-

What's new in 1.590 (2014/11/16)

+

What's new in 1.609 (2015/04/12)

+ +

What's new in 1.608 (2015/04/05)

+ +

What's new in 1.607 (2015/03/30)

+ +

What's new in 1.606 (2015/03/23)

+ +

What's new in 1.605 (2015/03/16)

+ +

What's new in 1.604 (2015/03/15)

+ +

What's new in 1.602 (2015/03/08)

+ +

What's new in 1.601 (2015/03/03)

+ +

What's new in 1.600 (2015/02/28)

+ +

What's new in 1.599 (2015/02/16)

+ +

What's new in 1.598 (2015/01/25)

+ +

What's new in 1.597 (2015/01/19)

+ +

What's new in 1.596 (2015/01/04)

+ +

What's new in 1.595 (2014/12/21)

+ +

What's new in 1.594 (2014/12/14)

+ +

What's new in 1.593 (2014/12/07)

+ +

What's new in 1.592 (2014/11/30)

+ +

What's new in 1.591 (2014/11/25)

+ +

What's new in 1.590 (2014/11/16)

-

What's new in 1.566 (2014/06/01)

- -

What's new in 1.565 (2014/05/26)

- -

What's new in 1.564 (2014/05/19)

- -

What's new in 1.563 (2014/05/11)

- -

What's new in 1.562 (2014/05/03)

- -

What's new in 1.561 (2014/04/27)

- -

What's new in 1.560 (2014/04/20)

- -

What's new in 1.559 (2014/04/13)

- -

What's new in 1.558 (2014/04/06)

- -

What's new in 1.557 (2014/03/31)

- -

What's new in 1.556 (2014/03/23)

- -

What's new in 1.555 (2014/03/16)

- -

What's new in 1.554 (2014/03/09)

- -

What's new in 1.553 (2014/03/02)

- -

What's new in 1.552 (2014/02/24)

- -

What's new in 1.551 (2014/02/14)

- -

What's new in 1.550 (2014/02/09)

- -

What's new in 1.549 (2014/01/25)

- -

What's new in 1.548 (2014/01/20)

- -

What's new in 1.547 (2014/01/12)

- -

What's new in 1.546 (2014/01/06)

- -

What's new in 1.545 (2013/12/31)

- -

What's new in 1.544 (2013/12/15)

- -

What's new in 1.543 (2013/12/10)

- -

What's new in 1.542 (2013/12/02)

- -

What's new in 1.541 (2013/11/24)

- -

What's new in 1.540 (2013/11/17)

- -

What's new in 1.539 (2013/11/11)

- -

What's new in 1.538 (2013/11/03)

- -

What's new in 1.537 (2013/10/27)

- -

What's new in 1.536 (2013/10/20)

- -

What's new in 1.535 (2013/10/14)

- -

What's new in 1.534 (2013/10/07)

- -

What's new in 1.533 (2013/09/29)

- -

What's new in 1.532 (2013/09/23)

- -

What's new in 1.531 (2013/09/16)

- -

What's new in 1.530 (2013/09/09)

- -

What's new in 1.529 (2013/08/26)

- -

What's new in 1.528 (2013/08/18)

- -

What's new in 1.527 (2013/08/12)

+

What's new in 1.566 (2014/06/01)

-

What's new in 1.526 (2013/08/05)

+

What's new in 1.565 (2014/05/26)

-

What's new in 1.525 (2013/07/29)

-

Same as 1.524; botched release.

-

What's new in 1.524 (2013/07/23)

+

What's new in 1.564 (2014/05/19)

-

What's new in 1.523 (2013/07/14)

+

What's new in 1.563 (2014/05/11)

-

What's new in 1.522 (2013/07/06)

+

What's new in 1.562 (2014/05/03)

-

What's new in 1.521 (2013/07/02)

+

What's new in 1.561 (2014/04/27)

-

What's new in 1.520 (2013/06/25)

- -

What's new in 1.519 (2013/06/17)

- -

What's new in 1.518 (2013/06/11)

- -

What's new in 1.517 (2013/06/02)

- -

What's new in 1.516 (2013/05/27)

- -

What's new in 1.515 (2013/05/18)

- -

What's new in 1.514 (2013/05/01)

+

What's new in 1.560 (2014/04/20)

-

What's new in 1.513 (2013/04/28)

- -

What's new in 1.512 (2013/04/21)

- -

What's new in 1.511 (2013/04/14)

+

What's new in 1.559 (2014/04/13)

-

What's new in 1.510 (2013/04/06)

- -

What's new in 1.509 (2013/04/02)

+

What's new in 1.558 (2014/04/06)

-

What's new in 1.508 (2013/03/25)

- -

What's new in 1.507 (2013/03/24)

+

What's new in 1.557 (2014/03/31)

-

What's new in 1.506 (2013/03/17)

+

What's new in 1.556 (2014/03/23)

-

What's new in 1.505 (2013/03/10)

+

What's new in 1.555 (2014/03/16)

-

What's new in 1.504 (2013/03/03)

+

What's new in 1.554 (2014/03/09)

-

What's new in 1.503 (2013/02/26)

+

What's new in 1.553 (2014/03/02)

-

What's new in 1.502 (2013/02/16)

+

What's new in 1.552 (2014/02/24)

-

What's new in 1.501 (2013/02/10)

+

What's new in 1.551 (2014/02/14)

-

What's new in 1.500 (2013/01/26)

- +

What's new in 1.550 (2014/02/09)

+ +

What's new in 1.549 (2014/01/25)

+ -

What's new in 1.499 (2013/01/13)

+

What's new in 1.548 (2014/01/20)

-

What's new in 1.498 (2013/01/07)

+

What's new in 1.547 (2014/01/12)

-

What's new in 1.497 (2013/01/06)

+

What's new in 1.546 (2014/01/06)

-Older changelogs can be found in a separate file +Older changelogs can be found in a separate file diff --git a/cli/pom.xml b/cli/pom.xml index 67da3a05cde3c7a7c0743f1281b4ade6acd6efba..bdc0fa749c34544e07a6068910088d0346028da3 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -5,7 +5,7 @@ org.jenkins-ci.main pom - 1.599-SNAPSHOT + 1.648-SNAPSHOT cli @@ -42,7 +42,7 @@ org.jvnet.localizer localizer - 1.10 + 1.23 org.jenkins-ci diff --git a/cli/src/main/java/hudson/cli/CLI.java b/cli/src/main/java/hudson/cli/CLI.java index 6a3a05c28773b3bd56e4f93341b9c29df589df0f..de2d2bd7950a3a7a73993dc6581213a3f4ca01ca 100644 --- a/cli/src/main/java/hudson/cli/CLI.java +++ b/cli/src/main/java/hudson/cli/CLI.java @@ -97,6 +97,7 @@ public class CLI { * @deprecated * Use {@link CLIConnectionFactory} to create {@link CLI} */ + @Deprecated public CLI(URL jenkins, ExecutorService exec) throws IOException, InterruptedException { this(jenkins,exec,null); } @@ -105,6 +106,7 @@ public class CLI { * @deprecated * Use {@link CLIConnectionFactory} to create {@link CLI} */ + @Deprecated public CLI(URL jenkins, ExecutorService exec, String httpsProxyTunnel) throws IOException, InterruptedException { this(new CLIConnectionFactory().url(jenkins).executorService(exec).httpsProxyTunnel(httpsProxyTunnel)); } @@ -169,12 +171,18 @@ public class CLI { private Channel connectViaCliPort(URL jenkins, CliPort clip) throws IOException { LOGGER.log(FINE, "Trying to connect directly via TCP/IP to {0}", clip.endpoint); - final Socket s; + final Socket s = new Socket(); + // this prevents a connection from silently terminated by the router in between or the other peer + // and that goes without unnoticed. However, the time out is often very long (for example 2 hours + // by default in Linux) that this alone is enough to prevent that. + s.setKeepAlive(true); + // we take care of buffering on our own + s.setTcpNoDelay(true); OutputStream out; if (httpsProxyTunnel!=null) { String[] tokens = httpsProxyTunnel.split(":"); - s = new Socket(tokens[0], Integer.parseInt(tokens[1])); + s.connect(new InetSocketAddress(tokens[0], Integer.parseInt(tokens[1]))); PrintStream o = new PrintStream(s.getOutputStream()); o.print("CONNECT " + clip.endpoint.getHostName() + ":" + clip.endpoint.getPort() + " HTTP/1.0\r\n\r\n"); @@ -199,7 +207,6 @@ public class CLI { } }; } else { - s = new Socket(); s.connect(clip.endpoint,3000); out = SocketChannelStream.out(s); } @@ -379,7 +386,13 @@ public class CLI { // h.setLevel(ALL); // l.addHandler(h); // - System.exit(_main(_args)); + try { + System.exit(_main(_args)); + } catch (Throwable t) { + // if the CLI main thread die, make sure to kill the JVM. + t.printStackTrace(); + System.exit(-1); + } } public static int _main(String[] _args) throws Exception { diff --git a/cli/src/main/java/hudson/cli/CliPort.java b/cli/src/main/java/hudson/cli/CliPort.java index 1507704d9c0e79dc40c88aa25d8bbe369c159e2a..8faab7de41bee0c88fa90cdaa0cbb8c9599f6a97 100644 --- a/cli/src/main/java/hudson/cli/CliPort.java +++ b/cli/src/main/java/hudson/cli/CliPort.java @@ -11,7 +11,7 @@ import java.security.spec.X509EncodedKeySpec; /** * @author Kohsuke Kawaguchi */ -final class CliPort { +public final class CliPort { /** * The TCP endpoint to talk to. */ @@ -27,7 +27,7 @@ final class CliPort { */ final String identity; - CliPort(InetSocketAddress endpoint, String identity, int version) { + public CliPort(InetSocketAddress endpoint, String identity, int version) { this.endpoint = endpoint; this.identity = identity; this.version = version; diff --git a/cli/src/main/java/hudson/cli/Connection.java b/cli/src/main/java/hudson/cli/Connection.java index 165a6deb7e6af83adf0ccda8cbe86a474414a65e..1c1ada471fdbaaded6f2203ec130a7e69a671a6f 100644 --- a/cli/src/main/java/hudson/cli/Connection.java +++ b/cli/src/main/java/hudson/cli/Connection.java @@ -23,6 +23,8 @@ */ package hudson.cli; +import hudson.remoting.ClassFilter; +import hudson.remoting.ObjectInputStreamEx; import hudson.remoting.SocketChannelStream; import org.apache.commons.codec.binary.Base64; @@ -107,7 +109,8 @@ public class Connection { * Receives an object sent by {@link #writeObject(Object)} */ public T readObject() throws IOException, ClassNotFoundException { - ObjectInputStream ois = new ObjectInputStream(in); + ObjectInputStream ois = new ObjectInputStreamEx(in, + getClass().getClassLoader(), ClassFilter.DEFAULT); return (T)ois.readObject(); } diff --git a/cli/src/main/java/hudson/cli/FullDuplexHttpStream.java b/cli/src/main/java/hudson/cli/FullDuplexHttpStream.java index 941dc4b0ae532f71ddd00c61e09b422a138d689a..abde9bb2022664eda42f5b28d91e9d58fbcfe04f 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; } diff --git a/cli/src/main/resources/hudson/cli/client/Messages_bg.properties b/cli/src/main/resources/hudson/cli/client/Messages_bg.properties new file mode 100644 index 0000000000000000000000000000000000000000..df0d2b57e1ac7b168809824f735bec1b102b27c4 --- /dev/null +++ b/cli/src/main/resources/hudson/cli/client/Messages_bg.properties @@ -0,0 +1,44 @@ +# The MIT License +# +# Bulgarian translation copyright 2015 Alexander Shopov . +# +# 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. + +CLI.Usage=\ + \u041f\u0440\u043e\u0433\u0440\u0430\u043c\u0430 \u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u0438\u044f \u0440\u0435\u0434 \u043d\u0430 Jenkins\n\ + \u0423\u043f\u043e\u0442\u0440\u0435\u0431\u0430: java -jar jenkins-cli.jar [-s \u0410\u0414\u0420\u0415\u0421] \u041a\u041e\u041c\u0410\u041d\u0414\u0410 [\u041e\u041f\u0426\u0418\u042f\u2026] \u0410\u0420\u0413\u0423\u041c\u0415\u041d\u0422\u2026\n\ + \u041e\u043f\u0446\u0438\u0438:\n\ + -s \u0410\u0414\u0420\u0415\u0421 : \u0430\u0434\u0440\u0435\u0441\u044a\u0442 \u043d\u0430 \u0441\u044a\u0440\u0432\u044a\u0440\u0430 (\u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e \u0441\u0435 \u0432\u0437\u0438\u043c\u0430 \u043e\u0442 \u043f\u0440\u043e\u043c\u0435\u043d\u043b\u0438\u0432\u0430\u0442\u0430 \u043d\u0430\n\ + \u0441\u0440\u0435\u0434\u0430\u0442\u0430 \u201eJENKINS_URL\u201c)\n\ + -i \u041a\u041b\u042e\u0427 : \u0447\u0430\u0441\u0442\u0435\u043d \u043a\u043b\u044e\u0447 \u0437\u0430 SSH \u0437\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f\n\ + -p \u0425\u041e\u0421\u0422:\u041f\u041e\u0420\u0422 : \u0445\u043e\u0441\u0442 \u0438 \u043f\u043e\u0440\u0442 \u0437\u0430 \u0441\u044a\u0440\u0432\u044a\u0440-\u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a \u043f\u043e HTTP \u0437\u0430 \u0442\u0443\u043d\u0435\u043b \u043f\u043e HTTPS.\n\ + \u0417\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f: http://jenkins-ci.org/https-proxy-tunnel\n\ + -noCertificateCheck : \u0431\u0435\u0437 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0441\u0435\u0440\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u0430 \u0437\u0430 HTTPS (\u0412\u041d\u0418\u041c\u0410\u041d\u0418\u0415!)\n\ + -noKeyAuth : \u0431\u0435\u0437 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0441 \u0447\u0430\u0441\u0442\u0435\u043d \u043a\u043b\u044e\u0447 \u0437\u0430 SSH, \u043e\u043f\u0446\u0438\u044f\u0442\u0430 \u0435\n\ + \u043d\u0435\u0441\u044a\u0432\u043c\u0435\u0441\u0442\u0438\u043c\u0430 \u0441 \u043e\u043f\u0446\u0438\u044f\u0442\u0430 \u201e-i\u201c\n\n\ + \u041d\u0430\u043b\u0438\u0447\u043d\u0438\u0442\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0438 \u0437\u0430\u0432\u0438\u0441\u044f\u0442 \u043e\u0442 \u0432\u0435\u0440\u0441\u0438\u044f\u0442\u0430 \u043d\u0430 \u0441\u044a\u0440\u0432\u044a\u0440\u0430. \u0417\u0430 \u0438\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0441\u043f\u0438\u0441\u044a\u043a\u0430\n\ + \u0438\u043c \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0439\u0442\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u0442\u0430 \u201ehelp\u201c.\n +CLI.NoURL=\ + \u0410\u0434\u0440\u0435\u0441\u044a\u0442 \u043d\u0435 \u0435 \u0437\u0430\u0434\u0430\u0434\u0435\u043d \u043d\u0438\u0442\u043e \u0447\u0440\u0435\u0437 \u043e\u043f\u0446\u0438\u044f\u0442\u0430 \u201e-s\u201c, \u043d\u0438\u0442\u043e \u0447\u0440\u0435\u0437 \u043f\u0440\u043e\u043c\u0435\u043d\u043b\u0438\u0432\u0430\u0442\u0430 \u043d\u0430\ + \u0441\u0440\u0435\u0434\u0430\u0442\u0430 \u201eJENKINS_URL\u201c. +CLI.VersionMismatch=\ + \u0412\u0435\u0440\u0441\u0438\u0438\u0442\u0435 \u043d\u0435 \u0441\u044a\u0432\u043f\u0430\u0434\u0430\u0442. \u0422\u0430\u0437\u0438 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u0430 \u0437\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0435\u043d \u0440\u0435\u0434 \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0438 \u0441 \u0442\u043e\u0437\u0438 \u0441\u044a\u0440\u0432\u044a\u0440\ + Jenkins. +CLI.NoSuchFileExists=\ + \u0422\u0430\u043a\u044a\u0432 \u0444\u0430\u0439\u043b \u043d\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430: {0} diff --git a/cli/src/test/java/hudson/cli/ConnectionTest.java b/cli/src/test/java/hudson/cli/ConnectionTest.java index 8cfac14fb4bc07eac67bca5370967bc47de94c84..f4cb0e8b1d595516130553bbe6568f8255324327 100644 --- a/cli/src/test/java/hudson/cli/ConnectionTest.java +++ b/cli/src/test/java/hudson/cli/ConnectionTest.java @@ -1,9 +1,11 @@ package hudson.cli; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import hudson.remoting.FastPipedInputStream; import hudson.remoting.FastPipedOutputStream; +import org.codehaus.groovy.runtime.Security218; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -71,4 +73,15 @@ public class ConnectionTest { throw new Error("thread is still alive"); } } + + @Test + public void testSecurity218() throws Exception { + c1.writeObject(new Security218()); + try { + c2.readObject(); + fail(); + } catch (SecurityException e) { + assertTrue(e.getMessage().contains(Security218.class.getName())); + } + } } diff --git a/cli/src/test/java/org/codehaus/groovy/runtime/Security218.java b/cli/src/test/java/org/codehaus/groovy/runtime/Security218.java new file mode 100644 index 0000000000000000000000000000000000000000..cc3dfeef041c6ac07b91f80d3dc98a5f1530e4c7 --- /dev/null +++ b/cli/src/test/java/org/codehaus/groovy/runtime/Security218.java @@ -0,0 +1,11 @@ +package org.codehaus.groovy.runtime; + +import java.io.Serializable; + +/** + * Test payload in a prohibited package name. + * + * @author Kohsuke Kawaguchi + */ +public class Security218 implements Serializable { +} diff --git a/core/pom.xml b/core/pom.xml index 66905e2196d3f0d8c7439dc501688093f8f3ad13..59be9513829c152b023923cc8aeb677e734a88da 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -29,7 +29,7 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.599-SNAPSHOT + 1.648-SNAPSHOT jenkins-core @@ -39,7 +39,7 @@ THE SOFTWARE. true - 1.234 + 1.237 2.5.6.SEC03 1.8.9 @@ -190,7 +190,7 @@ THE SOFTWARE. args4j args4j - 2.0.23 + 2.0.31 org.jenkins-ci @@ -200,7 +200,7 @@ THE SOFTWARE. org.jenkins-ci bytecode-compatibility-transformer - 1.5 + 1.8 org.jenkins-ci @@ -210,7 +210,7 @@ THE SOFTWARE. org.jvnet.localizer localizer - 1.10 + 1.23 antlr @@ -276,6 +276,11 @@ THE SOFTWARE. commons-beanutils 1.8.3 + + org.apache.commons + commons-compress + 1.10 + javax.mail mail @@ -403,10 +408,10 @@ THE SOFTWARE. groovy-all ${groovy.version} - + jline jline - 0.9.94 + 1.0 compile @@ -464,8 +469,17 @@ THE SOFTWARE. 1.1.0 - commons-logging - commons-logging + org.slf4j + jcl-over-slf4j + + + org.slf4j + log4j-over-slf4j + + + org.slf4j + slf4j-jdk14 + test com.sun.xml.txw2 @@ -500,12 +514,12 @@ THE SOFTWARE. net.java.dev.jna jna - 4.1.0 + 4.2.1 org.kohsuke akuma - 1.9 + 1.10 org.kohsuke @@ -558,9 +572,9 @@ THE SOFTWARE. - findbugs + com.google.code.findbugs annotations - 1.0.0 + 3.0.0 provided @@ -618,7 +632,7 @@ THE SOFTWARE. - + org.jenkins-ci.tools maven-hpi-plugin @@ -749,7 +763,7 @@ THE SOFTWARE. 0.5C true - -XX:MaxPermSize=128m + -XX:MaxPermSize=128m -noverify @@ -865,7 +879,6 @@ THE SOFTWARE. org.codehaus.mojo findbugs-maven-plugin - 2.5.2 Max High 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 92% 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 d303a63fc3e91e9b1a55c3b395f71c8d94c79e48..fffef47e59cd5c72bb4ac44cd9f2d6bc2ca5cee4 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,8 @@ # 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. +UpgradeProgress=Upgrade to Jenkins {0} is in progress. +UpgradeFailed=Upgrade to Jenkins {0} failed: {1}. 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 0627dbf1e4e6eb9c5e980357fc146aaa4cd3e8b6..691b46b7f011fea7b7006332205079333c537c84 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 37285e900f14f4efd15dd43e9fb13957cdb3bdb5..8b5776e534c4c7b1976cc64e6cf05be51b585d9f 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 5eb9dc40793c4bff153407d10ba9b3ffa0cee571..344e4571183a7eaa3becaab2ef851cd3ac008099 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 f3bd1ba6f4c69fac5de1ded01f4d7c998d39935a..6016d4d17c127ce0247010aad57455532ffcd8e4 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 versin de Jenkins disponible ({0}). descargar (listado de cambios). -Or\ Upgrade\ Automatically=O actualizar automticamente -UpgradeComplete=La actualizacin a Jenkins {0} se ha completado, esperando para reiniciar. -UpgradeCompleteRestartNotSupported=La actualizacin a Jenkins {0} se ha completado, esperando para reiniciar. -UpgradeProgress=La actualizacin a Jenkins {0} est en ejecucin 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 7cd8b01f2a7a4eaeeed6bc01da9c269b27517f8c..1df6054b1428d863d5b65a19a2da234fa6cf08b3 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 4822e11895de090d17bbdec6b2ddb85d1a22e01c..8243a6f68555eec617915e558122db1d0033ae49 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 f00987657878298f54bcca2660ce3e1e701f066e..0dbdae69d7d8df9097c1df2db7ded0102902c8ae 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 c28160d6590d5656ff448260dac92953c8e19d35..19587285cae841957f0c83b526dcf3cf6750c815 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 aa157c3f69813a8b798ed70b83f1ceefc2d71a68..c28903b2ddf3ae2e9e532bb7006518699b72bf77 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 f6538f878eacab3b00e9c5fc5a997ba9dfc5fb8f..7378e405c76f9e21a930a2e698b8baf8f024a484 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 91ea7ae49a31a5ef876403f6d732286efb4764ce..5738b71b7682a2f7f0039aac4f593df8a9dce103 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 3e54bb7c1204196e3c8ee28c652046b67ca14ef8..f5f6a772762aa34cd55aa6893fae4bc67c0aa073 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 b9995fe88bebe7f6236de20f5278c8d81b2155ed..2a16d979f6579860244892c408238e5e5ea6de66 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 cf14b56b6fe54478da5e1bb04fa84d46c2dce5f2..9193a28385403d2933853f0dec5069a038406fa6 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 d86c6788e0fa80a045bf9ba845f7ef3f4eb3bd8a..b15161b4421813795e09b62fb4c26d00a4c7a858 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 d3a0df68e52fa4e22955eb330fb708d7451e20d1..9c291b0fddb44854da763828b29e37eaad0e1534 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 54% 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 d22c58b0cc96b9f86675e87f7ea2d4889663bb21..6f5ff479b3092c96f38a93a2f6fb46a126fead29 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,6 @@ # 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 (historia zmian). Or\ Upgrade\ Automatically=Albo uaktualnij automatycznie +UpgradeCompleteRestartNotSupported=Aktualizacja Jenkinsa do wersji {0} zako\u0144czy\u0142a si\u0119 pomy\u015Blnie, oczekiwanie na ponowne uruchomienie. 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 96e622fc3bed40133241ed18a2860e57d3d21a29..216eee44d9e947331dd3e7cf1737cb1c88f56f8f 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 ad3dcdcaef7c7ca02225f7327bf19b7e9ec9dda3..dd2d81456d153cad42b32e5d27a0ceea7bea71c2 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 c3cd495635173c5de7b5114ded24a6597be99498..97659c57c7def17ad08d3af7af2b9eba4e7b8fee 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 bca3d05fab39593ad4e321072d0956ee6988a40b..96543df586253a9821c3057b38d334cc733e9b25 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 b69224ebd301faa0d6441f52535fc50fa973d86b..649104bcf5a3aa6702a824ed73c0c5195550f13c 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 3379d203678e3487f91fc8dc55a126b05c23e206..625195c3513bf5a71162d33e25b76066a09f3b84 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 1ddf921908269e57c7370c85b7252ea5dbde5b47..0ef79b530b974daaaed8ae9bc346ed86fb71a2bc 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 0423c94c73d6319e64f59b6cebf2c0adb64629f0..76967e8ea16086a1772118b76e503a32fe985ef6 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/core/src/main/java/hudson/ClassicPluginStrategy.java b/core/src/main/java/hudson/ClassicPluginStrategy.java index b295de6405b934874fdaaf632d5b9509dac9c29f..b90e6fcfda9e99415c00cd17932ee69c16407be9 100644 --- a/core/src/main/java/hudson/ClassicPluginStrategy.java +++ b/core/src/main/java/hudson/ClassicPluginStrategy.java @@ -66,6 +66,7 @@ import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.Vector; import java.util.jar.Attributes; import java.util.jar.JarFile; @@ -303,13 +304,19 @@ public class ClassicPluginStrategy implements PluginStrategy { // don't fix the dependency for yourself, or else we'll have a cycle String yourName = atts.getValue("Short-Name"); if (shortName.equals(yourName)) return; + if (BREAK_CYCLES.contains(yourName + '/' + shortName)) { + LOGGER.log(Level.FINE, "skipping implicit dependency {0} → {1}", new Object[] {yourName, shortName}); + return; + } // some earlier versions of maven-hpi-plugin apparently puts "null" as a literal in Hudson-Version. watch out for them. String jenkinsVersion = atts.getValue("Jenkins-Version"); if (jenkinsVersion==null) jenkinsVersion = atts.getValue("Hudson-Version"); - if (jenkinsVersion == null || jenkinsVersion.equals("null") || new VersionNumber(jenkinsVersion).compareTo(splitWhen) <= 0) - optionalDependencies.add(new PluginWrapper.Dependency(shortName+':'+requireVersion)); + if (jenkinsVersion == null || jenkinsVersion.equals("null") || new VersionNumber(jenkinsVersion).compareTo(splitWhen) <= 0) { + optionalDependencies.add(new PluginWrapper.Dependency(shortName + ':' + requireVersion)); + LOGGER.log(Level.FINE, "adding implicit dependency {0} → {1} because of {2}", new Object[] {yourName, shortName, jenkinsVersion}); + } } } @@ -330,6 +337,16 @@ public class ClassicPluginStrategy implements PluginStrategy { new DetachedPlugin("junit","1.577.*","1.0") ); + /** Implicit dependencies that are known to be unnecessary and which must be cut out to prevent a dependency cycle among bundled plugins. */ + private static final Set BREAK_CYCLES = new HashSet(Arrays.asList( + "script-security/matrix-auth", + "script-security/windows-slaves", + "script-security/antisamy-markup-formatter", + "script-security/matrix-project", + "credentials/matrix-auth", + "credentials/windows-slaves" + )); + /** * Computes the classloader that takes the class masking into account. * @@ -780,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); } } diff --git a/core/src/main/java/hudson/DNSMultiCast.java b/core/src/main/java/hudson/DNSMultiCast.java index 8d029b6ae3f4ba42ca5aa253cdea8ea9ee294b80..b1f7d0b5e0c0b9844659a2af23d7a6f6bc1f8fb6 100644 --- a/core/src/main/java/hudson/DNSMultiCast.java +++ b/core/src/main/java/hudson/DNSMultiCast.java @@ -66,7 +66,8 @@ public class DNSMultiCast implements Closeable { jmdns.registerService(ServiceInfo.create("_http._tcp.local.","Jenkins", jenkins_port,0,0,props)); } catch (IOException e) { - LOGGER.log(Level.WARNING,"Failed to advertise the service to DNS multi-cast",e); + LOGGER.log(Level.INFO, "Cannot advertise service to DNS multi-cast, skipping: {0}", e); + LOGGER.log(Level.FINE, null, e); } return null; } diff --git a/core/src/main/java/hudson/DependencyRunner.java b/core/src/main/java/hudson/DependencyRunner.java index bd4282f8c209bc8012d02ceb2ff16b913725c41b..acf035676910ad3ac77f6e4b3164ed7358fc0f39 100644 --- a/core/src/main/java/hudson/DependencyRunner.java +++ b/core/src/main/java/hudson/DependencyRunner.java @@ -35,7 +35,6 @@ import java.util.Set; import java.util.Collection; import java.util.logging.Logger; -import org.acegisecurity.Authentication; import org.acegisecurity.context.SecurityContext; import org.acegisecurity.context.SecurityContextHolder; diff --git a/core/src/main/java/hudson/DescriptorExtensionList.java b/core/src/main/java/hudson/DescriptorExtensionList.java index a3917b2e84b02cd1f9c997f966b9d485977040bc..513c557d44c7c11bcbd0c62c891d83f03997adeb 100644 --- a/core/src/main/java/hudson/DescriptorExtensionList.java +++ b/core/src/main/java/hudson/DescriptorExtensionList.java @@ -81,6 +81,7 @@ public class DescriptorExtensionList, D extends Descrip * @deprecated as of 1.416 * Use {@link #create(Jenkins, Class)} */ + @Deprecated public static ,D extends Descriptor> DescriptorExtensionList createDescriptorList(Hudson hudson, Class describableType) { return (DescriptorExtensionList)createDescriptorList((Jenkins)hudson,describableType); @@ -95,6 +96,7 @@ public class DescriptorExtensionList, D extends Descrip * @deprecated as of 1.416 * Use {@link #DescriptorExtensionList(Jenkins, Class)} */ + @Deprecated protected DescriptorExtensionList(Hudson hudson, Class describableType) { this((Jenkins)hudson,describableType); } @@ -109,6 +111,7 @@ public class DescriptorExtensionList, D extends Descrip * * @param fqcn * Fully qualified name of the descriptor, not the describable. + * @deprecated {@link Descriptor#getId} is supposed to be used for new code, not the descriptor class name. */ public D find(String fqcn) { return Descriptor.find(this,fqcn); diff --git a/core/src/main/java/hudson/ExtensionFinder.java b/core/src/main/java/hudson/ExtensionFinder.java index d4dc1ef31bc7ebe0b20ea152a53275044e94f25f..1a61b4d64a6dd01cc759d30f891bac4d705b6a60 100644 --- a/core/src/main/java/hudson/ExtensionFinder.java +++ b/core/src/main/java/hudson/ExtensionFinder.java @@ -85,6 +85,7 @@ public abstract class ExtensionFinder implements ExtensionPoint { * Use and implement {@link #find(Class,Hudson)} that allows us to put some metadata. */ @Restricted(NoExternalUse.class) + @Deprecated public Collection findExtensions(Class type, Hudson hudson) { return Collections.emptyList(); } @@ -244,7 +245,7 @@ public abstract class ExtensionFinder implements ExtensionPoint { */ private List> sezpozIndex; - private final Map annotations = new HashMap(); + private final Map annotations = new HashMap<>(); private final Sezpoz moduleFinder = new Sezpoz(); /** @@ -260,7 +261,7 @@ public abstract class ExtensionFinder implements ExtensionPoint { sezpozIndex = loadSezpozIndices(Jenkins.getInstance().getPluginManager().uberClassLoader); - List modules = new ArrayList(); + List modules = new ArrayList<>(); modules.add(new AbstractModule() { @Override protected void configure() { @@ -324,7 +325,7 @@ public abstract class ExtensionFinder implements ExtensionPoint { l.addAll(delta); sezpozIndex = l; - List modules = new ArrayList(); + List modules = new ArrayList<>(); modules.add(new SezpozModule(delta)); for (ExtensionComponent ec : moduleFinder.refresh().find(Module.class)) { modules.add(ec.getInstance()); @@ -337,7 +338,7 @@ public abstract class ExtensionFinder implements ExtensionPoint { return new ExtensionComponentSet() { @Override public Collection> find(Class type) { - List> result = new ArrayList>(); + List> result = new ArrayList<>(); _find(type, result, child); return result; } @@ -351,14 +352,11 @@ public abstract class ExtensionFinder implements ExtensionPoint { private Object instantiate(IndexItem item) { try { return item.instance(); - } catch (LinkageError e) { + } catch (LinkageError | Exception e) { // sometimes the instantiation fails in an indirect classloading failure, // which results in a LinkageError LOGGER.log(isOptional(item.annotation()) ? Level.FINE : Level.WARNING, "Failed to load "+item.className(), e); - } catch (Exception e) { - LOGGER.log(isOptional(item.annotation()) ? Level.FINE : Level.WARNING, - "Failed to load "+item.className(), e); } return null; } @@ -375,7 +373,7 @@ public abstract class ExtensionFinder implements ExtensionPoint { public Collection> find(Class type, Hudson jenkins) { // the find method contract requires us to traverse all known components - List> result = new ArrayList>(); + List> result = new ArrayList<>(); for (Injector i=container; i!=null; i=i.getParent()) { _find(type, result, i); } @@ -389,7 +387,7 @@ public abstract class ExtensionFinder implements ExtensionPoint { Object o = e.getValue().getProvider().get(); if (o!=null) { GuiceExtensionAnnotation gea = a!=null ? extensionAnnotations.get(a.annotationType()) : null; - result.add(new ExtensionComponent(type.cast(o),gea!=null?gea.getOrdinal(a):0)); + result.add(new ExtensionComponent<>(type.cast(o), gea != null ? gea.getOrdinal(a) : 0)); } } } @@ -443,7 +441,7 @@ public abstract class ExtensionFinder implements ExtensionPoint { } }; } - }; + } private static final Logger LOGGER = Logger.getLogger(GuiceFinder.class.getName()); @@ -532,14 +530,11 @@ public abstract class ExtensionFinder implements ExtensionPoint { } }).in(scope); } - } catch (LinkageError e) { + } catch (Exception|LinkageError e) { // sometimes the instantiation fails in an indirect classloading failure, // which results in a LinkageError LOGGER.log(optional ? Level.FINE : Level.WARNING, "Failed to load "+item.className(), e); - } catch (Exception e) { - LOGGER.log(optional ? Level.FINE : Level.WARNING, - "Failed to load "+item.className(), e); } } } @@ -621,7 +616,7 @@ public abstract class ExtensionFinder implements ExtensionPoint { * Finds all the matching {@link IndexItem}s that match the given type and instantiate them. */ private Collection> _find(Class type, List> indices) { - List> result = new ArrayList>(); + List> result = new ArrayList<>(); for (IndexItem item : indices) { try { @@ -641,14 +636,12 @@ public abstract class ExtensionFinder implements ExtensionPoint { if(type.isAssignableFrom(extType)) { Object instance = item.instance(); if(instance!=null) - result.add(new ExtensionComponent(type.cast(instance),item.annotation())); + result.add(new ExtensionComponent<>(type.cast(instance),item.annotation())); } - } catch (LinkageError e) { + } catch (LinkageError|Exception e) { // sometimes the instantiation fails in an indirect classloading failure, // which results in a LinkageError LOGGER.log(logLevel(item), "Failed to load "+item.className(), e); - } catch (Exception e) { - LOGGER.log(logLevel(item), "Failed to load "+item.className(), e); } } @@ -678,9 +671,7 @@ public abstract class ExtensionFinder implements ExtensionPoint { // according to http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6459208 // this appears to be the only way to force a class initialization Class.forName(extType.getName(),true,extType.getClassLoader()); - } catch (Exception e) { - LOGGER.log(logLevel(item), "Failed to scout "+item.className(), e); - } catch (LinkageError e) { + } catch (Exception | LinkageError e) { LOGGER.log(logLevel(item), "Failed to scout "+item.className(), e); } } diff --git a/core/src/main/java/hudson/ExtensionList.java b/core/src/main/java/hudson/ExtensionList.java index 7861de26c2a5b39bc006b922b92476d36cef46c0..46447fbcdabaffddfb0716b0cbbb94a73569f073 100644 --- a/core/src/main/java/hudson/ExtensionList.java +++ b/core/src/main/java/hudson/ExtensionList.java @@ -73,6 +73,7 @@ public class ExtensionList extends AbstractList { * @deprecated as of 1.417 * Use {@link #jenkins} */ + @Deprecated public final Hudson hudson; public final @CheckForNull Jenkins jenkins; public final Class extensionType; @@ -83,6 +84,8 @@ public class ExtensionList extends AbstractList { @CopyOnWrite private volatile List> extensions; + private final List listeners = new CopyOnWriteArrayList(); + /** * Place to store manually registered instances with the per-Hudson scope. * {@link CopyOnWriteArrayList} is used here to support concurrent iterations and mutation. @@ -93,6 +96,7 @@ public class ExtensionList extends AbstractList { * @deprecated as of 1.416 * Use {@link #ExtensionList(Jenkins, Class)} */ + @Deprecated protected ExtensionList(Hudson hudson, Class extensionType) { this((Jenkins)hudson,extensionType); } @@ -105,6 +109,7 @@ public class ExtensionList extends AbstractList { * @deprecated as of 1.416 * Use {@link #ExtensionList(Jenkins, Class, CopyOnWriteArrayList)} */ + @Deprecated protected ExtensionList(Hudson hudson, Class extensionType, CopyOnWriteArrayList> legacyStore) { this((Jenkins)hudson,extensionType,legacyStore); } @@ -126,11 +131,19 @@ public class ExtensionList extends AbstractList { } } + /** + * Add a listener to the extension list. + * @param listener The listener. + */ + public void addListener(@Nonnull ExtensionListListener listener) { + listeners.add(listener); + } + /** * Looks for the extension instance of the given type (subclasses excluded), * or return null. */ - public U get(Class type) { + public @CheckForNull U get(Class type) { for (T ext : this) if(ext.getClass()==type) return type.cast(ext); @@ -180,7 +193,17 @@ public class ExtensionList extends AbstractList { } @Override - public synchronized boolean remove(Object o) { + public boolean remove(Object o) { + try { + return removeSync(o); + } finally { + if(extensions!=null) { + fireOnChangeListeners(); + } + } + } + + private synchronized boolean removeSync(Object o) { boolean removed = removeComponent(legacyInstances, o); if(extensions!=null) { List> r = new ArrayList>(extensions); @@ -214,7 +237,18 @@ public class ExtensionList extends AbstractList { * Prefer automatic registration. */ @Override - public synchronized boolean add(T t) { + @Deprecated + public boolean add(T t) { + try { + return addSync(t); + } finally { + if(extensions!=null) { + fireOnChangeListeners(); + } + } + } + + private synchronized boolean addSync(T t) { legacyInstances.add(new ExtensionComponent(t)); // if we've already filled extensions, add it if(extensions!=null) { @@ -270,6 +304,7 @@ public class ExtensionList extends AbstractList { * Do not call from anywhere else. */ public void refresh(ExtensionComponentSet delta) { + boolean fireOnChangeListeners = false; synchronized (getLoadLock()) { if (extensions==null) return; // not yet loaded. when we load it, we'll load everything visible by then, so no work needed @@ -279,6 +314,20 @@ public class ExtensionList extends AbstractList { List> l = Lists.newArrayList(extensions); l.addAll(found); extensions = sort(l); + fireOnChangeListeners = true; + } + } + if (fireOnChangeListeners) { + fireOnChangeListeners(); + } + } + + private void fireOnChangeListeners() { + for (ExtensionListListener listener : listeners) { + try { + listener.onChange(); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error firing ExtensionListListener.onChange().", e); } } } @@ -325,6 +374,7 @@ public class ExtensionList extends AbstractList { * @deprecated as of 1.416 * Use {@link #create(Jenkins, Class)} */ + @Deprecated public static ExtensionList create(Hudson hudson, Class type) { return create((Jenkins)hudson,type); } diff --git a/core/src/main/java/hudson/ExtensionListListener.java b/core/src/main/java/hudson/ExtensionListListener.java new file mode 100644 index 0000000000000000000000000000000000000000..f5c8528add3995535060b3d39bd9bea75d447124 --- /dev/null +++ b/core/src/main/java/hudson/ExtensionListListener.java @@ -0,0 +1,42 @@ +/* + * 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; + +/** + * {@link ExtensionList} listener. + * + * @author tom.fennelly@gmail.com + * @since 1.614 + */ +public abstract class ExtensionListListener { + + /** + * {@link ExtensionList} contents has changed. + *

+ * This would be called when an entry gets added to or removed from the list for any reason e.g. + * when a dynamically loaded plugin introduces a new {@link ExtensionPoint} implementation + * that adds an entry to the {@link ExtensionList} being listened to. + */ + public abstract void onChange(); +} diff --git a/core/src/main/java/hudson/ExtensionListView.java b/core/src/main/java/hudson/ExtensionListView.java index 95ea80068c636ffc393785fb27f53ce7e4517961..59b81ffd95869297d20ea67694b923652235812d 100644 --- a/core/src/main/java/hudson/ExtensionListView.java +++ b/core/src/main/java/hudson/ExtensionListView.java @@ -24,7 +24,6 @@ package hudson; import jenkins.model.Jenkins; -import hudson.tasks.UserNameResolver; import hudson.util.CopyOnWriteList; import java.util.AbstractList; diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index 1fe2de55c802bc06dd0223cc6bdadaa1db87e929..9690c39cd0d03cef537a76aa399c7ed2bced97b1 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -33,7 +33,6 @@ import hudson.model.AbstractProject; import hudson.model.Computer; import hudson.model.Item; import hudson.model.TaskListener; -import hudson.org.apache.tools.tar.TarInputStream; import hudson.os.PosixAPI; import hudson.os.PosixException; import hudson.remoting.Callable; @@ -70,7 +69,6 @@ import org.apache.commons.io.input.CountingInputStream; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.types.FileSet; -import org.apache.tools.tar.TarEntry; import org.apache.tools.zip.ZipEntry; import org.apache.tools.zip.ZipFile; import org.kohsuke.stapler.Stapler; @@ -92,7 +90,6 @@ import java.io.OutputStreamWriter; import java.io.RandomAccessFile; import java.io.Serializable; import java.io.Writer; -import java.lang.reflect.Field; import java.net.HttpURLConnection; import java.net.URI; import java.net.URL; @@ -120,6 +117,8 @@ import static hudson.Util.*; import javax.annotation.Nonnull; import javax.annotation.Nullable; import jenkins.security.MasterToSlaveCallable; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; import org.jenkinsci.remoting.RoleChecker; import org.jenkinsci.remoting.RoleSensitive; @@ -175,7 +174,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. * @@ -367,6 +366,7 @@ public final class FilePath implements Serializable { * * @deprecated as of 1.315. Use {@link #zip(OutputStream)} that has more consistent name. */ + @Deprecated public void createZipArchive(OutputStream os) throws IOException, InterruptedException { zip(os); } @@ -411,6 +411,7 @@ public final class FilePath implements Serializable { * @deprecated as of 1.315 * Use {@link #zip(OutputStream,String)} that has more consistent name. */ + @Deprecated public void createZipArchive(OutputStream os, final String glob) throws IOException, InterruptedException { archive(ArchiverFactory.ZIP,os,glob); } @@ -2266,12 +2267,15 @@ public final class FilePath implements Serializable { /** * Reads from a tar stream and stores obtained files to the base dir. + * @since TODO supports large files > 10 GB, migration to commons-compress */ private void readFromTar(String name, File baseDir, InputStream in) throws IOException { - TarInputStream t = new TarInputStream(in); + TarArchiveInputStream t = new TarArchiveInputStream(in); + + // TarInputStream t = new TarInputStream(in); try { - TarEntry te; - while ((te = t.getNextEntry()) != null) { + TarArchiveEntry te; + while ((te = t.getNextTarEntry()) != null) { File f = new File(baseDir,te.getName()); if(te.isDirectory()) { mkdirs(f); @@ -2280,8 +2284,7 @@ public final class FilePath implements Serializable { if (parent != null) mkdirs(parent); writing(f); - byte linkFlag = (Byte) LINKFLAG_FIELD.get(te); - if (linkFlag==TarEntry.LF_SYMLINK) { + if (te.isSymbolicLink()) { new FilePath(f).symlinkTo(te.getLinkName(), TaskListener.NULL); } else { IOUtils.copy(t,f); @@ -2298,8 +2301,6 @@ public final class FilePath implements Serializable { } catch (InterruptedException e) { Thread.currentThread().interrupt(); // process this later throw new IOException("Failed to extract "+name,e); - } catch (IllegalAccessException e) { - throw new IOException("Failed to extract "+name,e); } finally { t.close(); } @@ -2337,12 +2338,20 @@ public final class FilePath implements Serializable { * @see #validateFileMask(FilePath, String) * @deprecated use {@link #validateAntFileMask(String, int)} instead */ + @Deprecated public String validateAntFileMask(final String fileMasks) throws IOException, InterruptedException { return validateAntFileMask(fileMasks, Integer.MAX_VALUE); } /** - * Default bound for {@link #validateAntFileMask(String, int)}. + * Same as {@link #validateFileMask(String, int, boolean)} with caseSensitive set to true + */ + public String validateAntFileMask(final String fileMasks, final int bound) throws IOException, InterruptedException { + return validateAntFileMask(fileMasks, bound, true); + } + + /** + * Default bound for {@link #validateAntFileMask(String, int, boolean)}. * @since 1.592 */ public static int VALIDATE_ANT_FILE_MASK_BOUND = Integer.getInteger(FilePath.class.getName() + ".VALIDATE_ANT_FILE_MASK_BOUND", 10000); @@ -2360,7 +2369,7 @@ public final class FilePath implements Serializable { * @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 */ - public String validateAntFileMask(final String fileMasks, final int bound) throws IOException, InterruptedException { + public String validateAntFileMask(final String fileMasks, final int bound, final boolean caseSensitive) throws IOException, InterruptedException { return act(new MasterToSlaveFileCallable() { private static final long serialVersionUID = 1; public String invoke(File dir, VirtualChannel channel) throws IOException, InterruptedException { @@ -2371,15 +2380,21 @@ public final class FilePath implements Serializable { while(tokens.hasMoreTokens()) { final String fileMask = tokens.nextToken().trim(); - if(hasMatch(dir,fileMask)) + if(hasMatch(dir,fileMask,caseSensitive)) continue; // no error on this portion + + // JENKINS-5253 - if we can get some match in case insensitive mode + // and user requested case sensitive match, notify the user + if (caseSensitive && hasMatch(dir, fileMask, false)) { + return Messages.FilePath_validateAntFileMask_matchWithCaseInsensitive(fileMask); + } // in 1.172 we introduced an incompatible change to stop using ' ' as the separator // so see if we can match by using ' ' as the separator if(fileMask.contains(" ")) { boolean matched = true; for (String token : Util.tokenize(fileMask)) - matched &= hasMatch(dir,token); + matched &= hasMatch(dir,token,caseSensitive); if(matched) return Messages.FilePath_validateAntFileMask_whitespaceSeprator(); } @@ -2395,7 +2410,7 @@ public final class FilePath implements Serializable { if(idx==-1) break; f=f.substring(idx+1); - if(hasMatch(dir,f)) + if(hasMatch(dir,f,caseSensitive)) return Messages.FilePath_validateAntFileMask_doesntMatchAndSuggest(fileMask,f); } } @@ -2403,6 +2418,7 @@ public final class FilePath implements Serializable { {// check the (2) above next as this is more expensive. // Try prepending "**/" to see if that results in a match FileSet fs = Util.createFileSet(reading(dir),"**/"+fileMask); + fs.setCaseSensitive(caseSensitive); DirectoryScanner ds = fs.getDirectoryScanner(new Project()); if(ds.getIncludedFilesCount()!=0) { // try shorter name first so that the suggestion results in least amount of changes @@ -2422,7 +2438,7 @@ public final class FilePath implements Serializable { prefix+=f.substring(0,idx)+'/'; f=f.substring(idx+1); - if(hasMatch(dir,prefix+fileMask)) + if(hasMatch(dir,prefix+fileMask,caseSensitive)) return Messages.FilePath_validateAntFileMask_doesntMatchAndSuggest(fileMask, prefix+fileMask); } } @@ -2434,7 +2450,7 @@ public final class FilePath implements Serializable { String pattern = fileMask; while(true) { - if(hasMatch(dir,pattern)) { + if(hasMatch(dir,pattern,caseSensitive)) { // found a match if(previous==null) return Messages.FilePath_validateAntFileMask_portionMatchAndSuggest(fileMask,pattern); @@ -2460,7 +2476,7 @@ public final class FilePath implements Serializable { return null; // no error } - private boolean hasMatch(File dir, String pattern) throws InterruptedException { + private boolean hasMatch(File dir, String pattern, boolean bCaseSensitive) throws InterruptedException { class Cancel extends RuntimeException {} DirectoryScanner ds = bound == Integer.MAX_VALUE ? new DirectoryScanner() : new DirectoryScanner() { int ticks; @@ -2478,6 +2494,7 @@ public final class FilePath implements Serializable { }; ds.setBasedir(reading(dir)); ds.setIncludes(new String[] {pattern}); + ds.setCaseSensitive(bCaseSensitive); try { ds.scan(); } catch (Cancel c) { @@ -2504,18 +2521,32 @@ public final class FilePath implements Serializable { } /** - * Shortcut for {@link #validateFileMask(String)} in case the left-hand side can be null. + * Short for {@code validateFileMask(path, value, true)} */ public static FormValidation validateFileMask(@CheckForNull FilePath path, String value) throws IOException { + return FilePath.validateFileMask(path, value, true); + } + + /** + * Shortcut for {@link #validateFileMask(String,true,boolean)} as the left-hand side can be null. + */ + public static FormValidation validateFileMask(@CheckForNull FilePath path, String value, boolean caseSensitive) throws IOException { if(path==null) return FormValidation.ok(); - return path.validateFileMask(value); + return path.validateFileMask(value, true, caseSensitive); } /** - * Short for {@code validateFileMask(value,true)} + * Short for {@code validateFileMask(value, true, true)} */ public FormValidation validateFileMask(String value) throws IOException { - return validateFileMask(value,true); + return validateFileMask(value, true, true); + } + + /** + * Short for {@code validateFileMask(value, errorIfNotExist, true)} + */ + public FormValidation validateFileMask(String value, boolean errorIfNotExist) throws IOException { + return validateFileMask(value, errorIfNotExist, true); } /** @@ -2524,7 +2555,7 @@ public final class FilePath implements Serializable { * or admin permission if no such ancestor is found. * @since 1.294 */ - public FormValidation validateFileMask(String value, boolean errorIfNotExist) throws IOException { + public FormValidation validateFileMask(String value, boolean errorIfNotExist, boolean caseSensitive) throws IOException { checkPermissionForValidate(); value = fixEmpty(value); @@ -2535,7 +2566,7 @@ public final class FilePath implements Serializable { if(!exists()) // no workspace. can't check return FormValidation.ok(); - String msg = validateAntFileMask(value, VALIDATE_ANT_FILE_MASK_BOUND); + String msg = validateAntFileMask(value, VALIDATE_ANT_FILE_MASK_BOUND, caseSensitive); if(errorIfNotExist) return FormValidation.error(msg); else return FormValidation.warning(msg); } catch (InterruptedException e) { @@ -2722,20 +2753,6 @@ public final class FilePath implements Serializable { } }; - private static final Field LINKFLAG_FIELD = getTarEntryLinkFlagField(); - - private static Field getTarEntryLinkFlagField() { - try { - Field f = TarEntry.class.getDeclaredField("linkFlag"); - f.setAccessible(true); - return f; - } catch (SecurityException e) { - throw new AssertionError(e); - } catch (NoSuchFieldException e) { - throw new AssertionError(e); - } - } - /** * Gets the {@link FilePath} representation of the "~" directory * (User's home directory in the Unix sense) of the given channel. diff --git a/core/src/main/java/hudson/FileSystemProvisioner.java b/core/src/main/java/hudson/FileSystemProvisioner.java index 58680eb88847035b1d00790d2c453e5edb82537e..bbb98f5e9d0c873ca4bc5af33b1d2b0b34048e58 100644 --- a/core/src/main/java/hudson/FileSystemProvisioner.java +++ b/core/src/main/java/hudson/FileSystemProvisioner.java @@ -204,6 +204,7 @@ public abstract class FileSystemProvisioner implements ExtensionPoint, Describab /** * @deprecated as of 1.350 */ + @Deprecated public WorkspaceSnapshot snapshot(AbstractBuild build, FilePath ws, TaskListener listener) throws IOException, InterruptedException { return snapshot(build, ws, "**/*", listener); } @@ -237,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 2cb0506fa9da19b11cea287563d6a6c4343e7b9c..4827366d36f41f3c7845aa71571eef7480d61f09 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 f331d7f1cb7b70f19335d1e35ff9639fa0400801..9f74f42b20647bba4d770e2dcec9ddffbdd9008f 100644 --- a/core/src/main/java/hudson/Functions.java +++ b/core/src/main/java/hudson/Functions.java @@ -28,6 +28,7 @@ package hudson; import hudson.cli.CLICommand; import hudson.console.ConsoleAnnotationDescriptor; import hudson.console.ConsoleAnnotatorFactory; +import hudson.init.InitMilestone; import hudson.model.AbstractProject; import hudson.model.Action; import hudson.model.Describable; @@ -74,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; @@ -151,6 +153,7 @@ import com.google.common.base.Predicate; import com.google.common.base.Predicates; import hudson.util.RunList; import java.util.concurrent.atomic.AtomicLong; +import javax.annotation.CheckForNull; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -201,7 +204,25 @@ public class Functions { public static String rfc822Date(Calendar cal) { return Util.RFC822_DATETIME_FORMATTER.format(cal.getTime()); } - + + /** + * During Jenkins start-up, before {@link InitMilestone#PLUGINS_STARTED} the extensions lists will be empty + * and they are not guaranteed to be fully populated until after {@link InitMilestone#EXTENSIONS_AUGMENTED}. + * If you attempt to access the extensions list from a UI thread while the extensions are being loaded you will + * hit a big honking great monitor lock that will block until the effective extension list has been determined + * (as if a plugin fails to start, all of the failed plugin's extensions and any dependent plugins' extensions + * will have to be evicted from the list of extensions. In practical terms this only affects the + * "Jenkins is loading" screen, but as that screen uses the generic layouts we provide this utility method + * so that the generic layouts can avoid iterating extension lists while Jenkins is starting up. + * + * @return {@code true} if the extensions lists have been populated. + * @since 1.607 + */ + public static boolean isExtensionsAvailable() { + final Jenkins jenkins = Jenkins.getInstance(); + return jenkins != null && jenkins.getInitLevel().compareTo(InitMilestone.EXTENSIONS_AUGMENTED) >= 0; + } + public static void initPageVariables(JellyContext context) { StaplerRequest currentRequest = Stapler.getCurrentRequest(); String rootURL = currentRequest.getContextPath(); @@ -419,6 +440,7 @@ public class Functions { * JEXL now supports the real ternary operator "x?y:z", so this work around * is no longer necessary. */ + @Deprecated public static Object ifThenElse(boolean cond, Object thenValue, Object elseValue) { return cond ? thenValue : elseValue; } @@ -438,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; @@ -820,6 +851,10 @@ public class Functions { return JobPropertyDescriptor.getPropertyDescriptors(clazz); } + public static List getJobPropertyDescriptors(Job job) { + return DescriptorVisibilityFilter.apply(job, JobPropertyDescriptor.getPropertyDescriptors(job.getClass())); + } + public static List> getBuildWrapperDescriptors(AbstractProject project) { return BuildWrappers.getFor(project); } @@ -1364,7 +1399,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 */ @@ -1372,7 +1407,17 @@ public class Functions { return value!=null ? value : defaultValue; } - public static String printThrowable(Throwable t) { + /** + * Gets info about the specified {@link Throwable}. + * @param t Input {@link Throwable} + * @return If {@link Throwable} is not null, a summary info with the + * stacktrace will be returned. Otherwise, the method returns a default + * "No exception details" string. + */ + public static String printThrowable(@CheckForNull Throwable t) { + if (t == null) { + return Messages.Functions_NoExceptionDetails(); + } StringWriter sw = new StringWriter(); t.printStackTrace(new PrintWriter(sw)); return sw.toString(); @@ -1554,6 +1599,7 @@ public class Functions { * @deprecated * Use {@link #calcCheckUrl} */ + @Deprecated public String getCheckUrl(String userDefined, Object descriptor, String field) { if(userDefined!=null || field==null) return userDefined; if (descriptor instanceof Descriptor) { @@ -1804,6 +1850,7 @@ public class Functions { * @deprecated as of 1.451 * Use {@link #getAvatar} */ + @Deprecated public String getUserAvatar(User user, String avatarSize) { return getAvatar(user,avatarSize); } @@ -1868,9 +1915,10 @@ public class Functions { TcpSlaveAgentListener tal = j.tcpSlaveAgentListener; if (tal !=null) { - rsp.setIntHeader("X-Hudson-CLI-Port", tal.getPort()); - rsp.setIntHeader("X-Jenkins-CLI-Port", tal.getPort()); - rsp.setIntHeader("X-Jenkins-CLI2-Port", tal.getPort()); + int p = TcpSlaveAgentListener.CLI_PORT !=null ? TcpSlaveAgentListener.CLI_PORT : tal.getPort(); + rsp.setIntHeader("X-Hudson-CLI-Port", p); + rsp.setIntHeader("X-Jenkins-CLI-Port", p); + rsp.setIntHeader("X-Jenkins-CLI2-Port", p); rsp.setHeader("X-Jenkins-CLI-Host", TcpSlaveAgentListener.CLI_HOST_NAME); } } diff --git a/core/src/main/java/hudson/Launcher.java b/core/src/main/java/hudson/Launcher.java index be003dfb648a76a3463bdae92151d9f812e37e0f..5be9397699f83c37d694fb9caceb8527df5caa27 100644 --- a/core/src/main/java/hudson/Launcher.java +++ b/core/src/main/java/hudson/Launcher.java @@ -29,7 +29,6 @@ import hudson.util.QuotedStringTokenizer; import jenkins.model.Jenkins; import hudson.model.TaskListener; import hudson.model.Node; -import hudson.remoting.Callable; import hudson.remoting.Channel; import hudson.remoting.Pipe; import hudson.remoting.RemoteInputStream; @@ -133,6 +132,7 @@ public abstract class Launcher { * figure out the current {@link Computer} from within a build, use * {@link Computer#currentComputer()} */ + @Deprecated public Computer getComputer() { for( Computer c : Jenkins.getInstance().getComputers() ) if(c.getChannel()==channel) @@ -412,6 +412,7 @@ public abstract class Launcher { * @deprecated as of 1.311 * Use {@link #launch()} and its associated builder pattern */ + @Deprecated public final Proc launch(String cmd, Map env, OutputStream out, FilePath workDir) throws IOException { return launch(cmd,Util.mapToEnv(env),out,workDir); } @@ -420,6 +421,7 @@ public abstract class Launcher { * @deprecated as of 1.311 * Use {@link #launch()} and its associated builder pattern */ + @Deprecated public final Proc launch(String[] cmd, Map env, OutputStream out, FilePath workDir) throws IOException { return launch(cmd, Util.mapToEnv(env), out, workDir); } @@ -428,6 +430,7 @@ public abstract class Launcher { * @deprecated as of 1.311 * Use {@link #launch()} and its associated builder pattern */ + @Deprecated public final Proc launch(String[] cmd, Map env, InputStream in, OutputStream out) throws IOException { return launch(cmd, Util.mapToEnv(env), in, out); } @@ -449,6 +452,7 @@ public abstract class Launcher { * @deprecated as of 1.311 * Use {@link #launch()} and its associated builder pattern */ + @Deprecated public final Proc launch(String[] cmd, boolean[] mask, Map env, OutputStream out, FilePath workDir) throws IOException { return launch(cmd, mask, Util.mapToEnv(env), out, workDir); } @@ -470,6 +474,7 @@ public abstract class Launcher { * @deprecated as of 1.311 * Use {@link #launch()} and its associated builder pattern */ + @Deprecated public final Proc launch(String[] cmd, boolean[] mask, Map env, InputStream in, OutputStream out) throws IOException { return launch(cmd, mask, Util.mapToEnv(env), in, out); } @@ -478,6 +483,7 @@ public abstract class Launcher { * @deprecated as of 1.311 * Use {@link #launch()} and its associated builder pattern */ + @Deprecated public final Proc launch(String cmd,String[] env,OutputStream out, FilePath workDir) throws IOException { return launch(Util.tokenize(cmd),env,out,workDir); } @@ -486,6 +492,7 @@ public abstract class Launcher { * @deprecated as of 1.311 * Use {@link #launch()} and its associated builder pattern */ + @Deprecated public final Proc launch(String[] cmd, String[] env, OutputStream out, FilePath workDir) throws IOException { return launch(cmd, env, null, out, workDir); } @@ -494,6 +501,7 @@ public abstract class Launcher { * @deprecated as of 1.311 * Use {@link #launch()} and its associated builder pattern */ + @Deprecated public final Proc launch(String[] cmd, String[] env, InputStream in, OutputStream out) throws IOException { return launch(cmd, env, in, out, null); } @@ -515,6 +523,7 @@ public abstract class Launcher { * @deprecated as of 1.311 * Use {@link #launch()} and its associated builder pattern */ + @Deprecated public final Proc launch(String[] cmd, boolean[] mask, String[] env, OutputStream out, FilePath workDir) throws IOException { return launch(cmd, mask, env, null, out, workDir); } @@ -536,6 +545,7 @@ public abstract class Launcher { * @deprecated as of 1.311 * Use {@link #launch()} and its associated builder pattern */ + @Deprecated public final Proc launch(String[] cmd, boolean[] mask, String[] env, InputStream in, OutputStream out) throws IOException { return launch(cmd, mask, env, in, out, null); } @@ -554,6 +564,7 @@ public abstract class Launcher { * @deprecated as of 1.311 * Use {@link #launch()} and its associated builder pattern */ + @Deprecated public Proc launch(String[] cmd, String[] env, InputStream in, OutputStream out, FilePath workDir) throws IOException { return launch(launch().cmds(cmd).envs(env).stdin(in).stdout(out).pwd(workDir)); } @@ -576,6 +587,7 @@ public abstract class Launcher { * @deprecated as of 1.311 * Use {@link #launch()} and its associated builder pattern */ + @Deprecated public Proc launch(String[] cmd, boolean[] mask, String[] env, InputStream in, OutputStream out, FilePath workDir) throws IOException { return launch(launch().cmds(cmd).masks(mask).envs(env).stdin(in).stdout(out).pwd(workDir)); } diff --git a/core/src/main/java/hudson/LauncherDecorator.java b/core/src/main/java/hudson/LauncherDecorator.java index 3bd5f7d0212b56bb87be7ebe56d1e5bda08c96c7..86f69fe496a2e3f6cfabe3cb8ddbe15bcc3fe0f0 100644 --- a/core/src/main/java/hudson/LauncherDecorator.java +++ b/core/src/main/java/hudson/LauncherDecorator.java @@ -1,6 +1,5 @@ package hudson; -import jenkins.model.Jenkins; import hudson.model.Node; import hudson.model.Executor; import hudson.tasks.BuildWrapper; diff --git a/core/src/main/java/hudson/MarkupText.java b/core/src/main/java/hudson/MarkupText.java index 4a56b1eb60faf98c04c5e18429630f4f2b401b04..5240cd3bdf62f6109f8362804576ead3c9147f54 100644 --- a/core/src/main/java/hudson/MarkupText.java +++ b/core/src/main/java/hudson/MarkupText.java @@ -283,6 +283,7 @@ public class MarkupText extends AbstractMarkupText { * Use {@link #toString(boolean)} to be explicit about the escape mode. */ @Override + @Deprecated public String toString() { return toString(false); } diff --git a/core/src/main/java/hudson/Plugin.java b/core/src/main/java/hudson/Plugin.java index 1e11d23bcd848cc1625542e564cbc7833228fa05..75af4fda013ef329000e81e1bed297d63dc6ab6a 100644 --- a/core/src/main/java/hudson/Plugin.java +++ b/core/src/main/java/hudson/Plugin.java @@ -40,15 +40,18 @@ import java.io.File; import net.sf.json.JSONObject; import com.thoughtworks.xstream.XStream; +import hudson.init.Initializer; +import hudson.init.Terminator; import java.net.URI; import java.net.URISyntaxException; +import jenkins.model.GlobalConfiguration; import org.kohsuke.stapler.HttpResponses; /** * Base class of Hudson plugin. * *

- * A plugin may derive from this class, or it may directly define extension + * A plugin may {@linkplain #Plugin derive from this class}, or it may directly define extension * points annotated with {@link hudson.Extension}. For a list of extension * points, see * https://wiki.jenkins-ci.org/display/JENKINS/Extension+points. @@ -78,6 +81,22 @@ import org.kohsuke.stapler.HttpResponses; */ public abstract class Plugin implements Saveable { + /** + * You do not need to create custom subtypes: + *

+ * Note that every plugin gets a {@link DummyImpl} by default, + * which will still route the URL space, serve {@link #getWrapper}, and so on. + * @deprecated Use more modern APIs rather than subclassing. + */ + @Deprecated + protected Plugin() {} + /** * Set by the {@link PluginManager}, before the {@link #start()} method is called. * This points to the {@link PluginWrapper} that wraps @@ -164,6 +183,7 @@ public abstract class Plugin implements Saveable { * @since 1.233 * @deprecated as of 1.305 override {@link #configure(StaplerRequest,JSONObject)} instead */ + @Deprecated public void configure(JSONObject formData) throws IOException, ServletException, FormException { } diff --git a/core/src/main/java/hudson/PluginManager.java b/core/src/main/java/hudson/PluginManager.java index 41605eed99865a7a0d5f94d134256e80c1f9398e..d7eb14f7b6dd2000c3b5a9d12bf407bf712a4beb 100644 --- a/core/src/main/java/hudson/PluginManager.java +++ b/core/src/main/java/hudson/PluginManager.java @@ -51,6 +51,8 @@ import jenkins.RestartRequiredException; import jenkins.YesNoMaybe; import jenkins.model.Jenkins; import jenkins.util.io.OnMaster; +import jenkins.util.xml.RestrictiveEntityResolver; + import net.sf.json.JSONArray; import net.sf.json.JSONObject; import org.apache.commons.fileupload.FileItem; @@ -69,6 +71,7 @@ import org.kohsuke.stapler.HttpRedirect; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponses; import org.kohsuke.stapler.QueryParameter; +import org.kohsuke.stapler.StaplerOverridable; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.export.Exported; @@ -109,12 +112,15 @@ import java.util.jar.Manifest; import java.util.logging.Level; import java.util.logging.Logger; import org.xml.sax.Attributes; +import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import static hudson.init.InitMilestone.*; import hudson.model.DownloadService; import hudson.util.FormValidation; + +import static java.util.logging.Level.SEVERE; import static java.util.logging.Level.WARNING; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -125,7 +131,7 @@ import org.kohsuke.accmod.restrictions.NoExternalUse; * @author Kohsuke Kawaguchi */ @ExportedBean -public abstract class PluginManager extends AbstractModelObject implements OnMaster { +public abstract class PluginManager extends AbstractModelObject implements OnMaster, StaplerOverridable { /** * All discovered plugins. */ @@ -148,6 +154,7 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas * {@link PluginManager} can now live longer than {@link jenkins.model.Jenkins} instance, so * use {@code Hudson.getInstance().servletContext} instead. */ + @Deprecated public final ServletContext context; /** @@ -211,6 +218,16 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas return new Api(this); } + /** + * Find all registered overrides (intended to allow overriding/adding views) + * @return List of extensions + * @since 1.627 + */ + @Override + public Collection getOverrides() { + return PluginManagerStaplerOverride.all(); + } + /** * Called immediately after the construction. * This is a separate method so that code executed from here will see a valid value in @@ -505,9 +522,33 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas } } + // Redo who depends on who. + resolveDependantPlugins(); + LOGGER.info("Plugin " + p.getShortName()+":"+p.getVersion() + " dynamically installed"); } + @Restricted(NoExternalUse.class) + public synchronized void resolveDependantPlugins() { + for (PluginWrapper plugin : plugins) { + Set dependants = new HashSet<>(); + for (PluginWrapper possibleDependant : plugins) { + // The plugin could have just been deleted. If so, it doesn't + // count as a dependant. + if (possibleDependant.isDeleted()) { + continue; + } + List dependencies = possibleDependant.getDependencies(); + for (Dependency dependency : dependencies) { + if (dependency.shortName.equals(plugin.getShortName())) { + dependants.add(possibleDependant.getShortName()); + } + } + } + plugin.setDependants(dependants); + } + } + /** * If the war file has any "/WEB-INF/plugins/[*.jpi | *.hpi]", extract them into the plugin directory. * @@ -764,6 +805,7 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas */ public void doInstall(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { boolean dynamicLoad = req.getParameter("dynamicLoad")!=null; + final List> deployJobs = new ArrayList<>(); Enumeration en = req.getParameterNames(); while (en.hasMoreElements()) { @@ -796,9 +838,36 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas if (p == null) { throw new Failure("No such plugin: " + n); } - p.deploy(dynamicLoad); + + deployJobs.add(p.deploy(dynamicLoad)); } } + + // Fire a one-off thread to wait for the plugins to be deployed and then + // refresh the dependant plugins list. + new Thread() { + @Override + public void run() { + INSTALLING: while (true) { + for (Future deployJob : deployJobs) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + LOGGER.log(SEVERE, "Unexpected error while waiting for some plugins to install. Plugin Manager state may be invalid. Please restart Jenkins ASAP.", e); + } + if (!deployJob.isCancelled() && !deployJob.isDone()) { + // One of the plugins is not installing/canceled, so + // go back to sleep and try again in a while. + continue INSTALLING; + } + } + // All the plugins are installed. It's now safe to refresh. + resolveDependantPlugins(); + break; + } + } + }.start(); + rsp.sendRedirect("../updateCenter/"); } @@ -806,6 +875,7 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas /** * Bare-minimum configuration mechanism to change the update center. */ + @RequirePOST public HttpResponse doSiteConfigure(@QueryParameter String site) throws IOException { Jenkins hudson = Jenkins.getInstance(); hudson.checkPermission(CONFIGURE_UPDATECENTER); @@ -821,6 +891,7 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas } + @RequirePOST public HttpResponse doProxyConfigure(StaplerRequest req) throws IOException, ServletException { Jenkins jenkins = Jenkins.getInstance(); jenkins.checkPermission(CONFIGURE_UPDATECENTER); @@ -839,6 +910,7 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas /** * Uploads a plugin. */ + @RequirePOST public HttpResponse doUploadPlugin(StaplerRequest req) throws IOException, ServletException { try { Jenkins.getInstance().checkPermission(UPLOAD_PLUGINS); @@ -1045,6 +1117,12 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas requestedPlugins.put(shortName, requested); } } + + @Override public InputSource resolveEntity(String publicId, String systemId) throws IOException, + SAXException { + return RestrictiveEntityResolver.INSTANCE.resolveEntity(publicId, systemId); + } + }); } catch (SAXException x) { throw new IOException("Failed to parse XML",x); diff --git a/core/src/main/java/hudson/PluginManagerStaplerOverride.java b/core/src/main/java/hudson/PluginManagerStaplerOverride.java new file mode 100644 index 0000000000000000000000000000000000000000..3103ba181835d9ba31bab32fb6581f9aee82b9a9 --- /dev/null +++ b/core/src/main/java/hudson/PluginManagerStaplerOverride.java @@ -0,0 +1,26 @@ +package hudson; + + +import javax.annotation.Nonnull; + +/** + * Extension point for selectively overriding parts of the {@link PluginManager} views + * Anything extending this and registered with an @Extension can replace existing views and define new views. + * + * It is also possible to add/modify API calls coming via Stapler, but this requires caution. + * + * In both cases, this is simply done by defining a resource or method that matches the existing one + * + * @author Sam Van Oort + * @since 1.627 + */ +public abstract class PluginManagerStaplerOverride implements ExtensionPoint { + + /** + * Return all implementations of this extension point + * @return All implementations of this extension point + */ + public static @Nonnull ExtensionList all() { + return ExtensionList.lookup(PluginManagerStaplerOverride.class); + } +} diff --git a/core/src/main/java/hudson/PluginWrapper.java b/core/src/main/java/hudson/PluginWrapper.java index aa683e630f7af7ca0306d86ad3474c2269584f1b..60eabf68cf5005593f278f2718336e7ab5ed8cc0 100644 --- a/core/src/main/java/hudson/PluginWrapper.java +++ b/core/src/main/java/hudson/PluginWrapper.java @@ -24,6 +24,7 @@ */ package hudson; +import com.google.common.collect.ImmutableSet; import hudson.PluginManager.PluginInstanceStore; import hudson.model.Api; import hudson.model.ModelObject; @@ -40,7 +41,10 @@ import java.io.OutputStream; import java.io.Closeable; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.jar.Manifest; import java.util.logging.Logger; import static java.util.logging.Level.WARNING; @@ -57,13 +61,14 @@ import java.util.Enumeration; import java.util.jar.JarFile; import java.util.logging.Level; import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; /** * Represents a Jenkins plug-in and associated control information * 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. * *

@@ -150,6 +155,54 @@ public class PluginWrapper implements Comparable, ModelObject { */ /*package*/ boolean isBundled; + /** + * List of plugins that depend on this plugin. + */ + private Set dependants = Collections.emptySet(); + + /** + * The core can depend on a plugin if it is bundled. Sometimes it's the only thing that + * depends on the plugin e.g. UI support library bundle plugin. + */ + private static Set CORE_ONLY_DEPENDANT = ImmutableSet.copyOf(Arrays.asList("jenkins-core")); + + /** + * Set the list of components that depend on this plugin. + * @param dependants The list of components that depend on this plugin. + */ + public void setDependants(@Nonnull Set dependants) { + this.dependants = dependants; + } + + /** + * Get the list of components that depend on this plugin. + * @return The list of components that depend on this plugin. + */ + public @Nonnull Set getDependants() { + if (isBundled && dependants.isEmpty()) { + return CORE_ONLY_DEPENDANT; + } else { + return dependants; + } + } + + /** + * Does this plugin have anything that depends on it. + * @return {@code true} if something (Jenkins core, or another plugin) depends on this + * plugin, otherwise {@code false}. + */ + public boolean hasDependants() { + return (isBundled || !dependants.isEmpty()); + } + + /** + * Does this plugin depend on any other plugins. + * @return {@code true} if this plugin depends on other plugins, otherwise {@code false}. + */ + public boolean hasDependencies() { + return (dependencies != null && !dependencies.isEmpty()); + } + @ExportedBean public static final class Dependency { @Exported @@ -632,8 +685,14 @@ public class PluginWrapper implements Comparable, ModelObject { @RequirePOST public HttpResponse doDoUninstall() throws IOException { - Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); + Jenkins jenkins = Jenkins.getActiveInstance(); + + jenkins.checkPermission(Jenkins.ADMINISTER); archive.delete(); + + // Redo who depends on who. + jenkins.getPluginManager().resolveDependantPlugins(); + return HttpResponses.redirectViaContextPath("/pluginManager/installed"); // send back to plugin manager } diff --git a/core/src/main/java/hudson/Proc.java b/core/src/main/java/hudson/Proc.java index 5114cbd2c445a9e490efe2477f7d396932296ad3..598fbca374efd2694ab661b9364bec81141cbd76 100644 --- a/core/src/main/java/hudson/Proc.java +++ b/core/src/main/java/hudson/Proc.java @@ -431,6 +431,7 @@ public abstract class Proc { * * @deprecated as of 1.399. Replaced by {@link Launcher.RemoteLauncher.ProcImpl} */ + @Deprecated public static final class RemoteProc extends Proc { private final Future process; diff --git a/core/src/main/java/hudson/ProxyConfiguration.java b/core/src/main/java/hudson/ProxyConfiguration.java index 0e36a4cd9d946d9bfa1f0e97a55bca3852deedf9..9b5199092502586e20b2609e271a6f02f8184063 100644 --- a/core/src/main/java/hudson/ProxyConfiguration.java +++ b/core/src/main/java/hudson/ProxyConfiguration.java @@ -165,6 +165,7 @@ public final class ProxyConfiguration extends AbstractDescribableImpl properties) { return replaceMacro(s,new VariableResolver.ByMap(properties)); } - + /** * Replaces the occurrence of '$key' by resolver.get('key'). * @@ -143,7 +151,7 @@ public class Util { if (s == null) { return null; } - + int idx=0; while(true) { Matcher m = VARIABLE.matcher(s); @@ -370,6 +378,30 @@ public class Util { } } + /** + * A mostly accurate check of whether a path is a relative path or not. This is designed to take a path against + * an unknown operating system so may give invalid results. + * + * @param path the path. + * @return {@code true} if the path looks relative. + * @since 1.606 + */ + public static boolean isRelativePath(String path) { + if (path.startsWith("/")) + return false; + if (path.startsWith("\\\\") && path.length() > 3 && path.indexOf('\\', 3) != -1) + return false; // a UNC path which is the most absolute you can get on windows + if (path.length() >= 3 && ':' == path.charAt(1)) { + // never mind that the drive mappings can be changed between sessions, we just want to + // know if the 3rd character is a `\` (or a '/' is acceptable too) + char p = path.charAt(0); + if (('A' <= p && p <= 'Z') || ('a' <= p && p <= 'z')) { + return path.charAt(2) != '\\' && path.charAt(2) != '/'; + } + } + return true; + } + /** * Creates a new temporary directory. */ @@ -624,7 +656,7 @@ public class Util { * Converts a string into 128-bit AES key. * @since 1.308 */ - @Nonnull + @Nonnull public static SecretKey toAes128Key(@Nonnull String s) { try { // turn secretKey into 256 bit hash @@ -743,13 +775,14 @@ public class Util { /** * Combines number and unit, with a plural suffix if needed. - * - * @deprecated - * Use individual localization methods instead. + * + * @deprecated + * Use individual localization methods instead. * See {@link Messages#Util_year(Object)} for an example. * Deprecated since 2009-06-24, remove method after 2009-12-24. */ @Nonnull + @Deprecated public static String combine(long n, @Nonnull String suffix) { String s = Long.toString(n)+' '+suffix; if(n!=1) @@ -780,7 +813,7 @@ public class Util { * {@link #rawEncode(String)} should generally be used instead, though be careful to pass only * a single path component to that method (it will encode /, but this method does not). */ - @Nonnull + @Nonnull public static String encode(@Nonnull String s) { try { boolean escaped = false; @@ -888,7 +921,7 @@ public class Util { /** * Escapes HTML unsafe characters like <, & to the respective character entities. */ - @Nonnull + @Nonnull public static String escape(@Nonnull String text) { if (text==null) return null; StringBuilder buf = new StringBuilder(text.length()+64); @@ -1112,7 +1145,7 @@ public class Util { * @param symlinkPath * Where to create a symlink in (relative to {@code baseDir}) */ - public static void createSymlink(@Nonnull File baseDir, @Nonnull String targetPath, + public static void createSymlink(@Nonnull File baseDir, @Nonnull String targetPath, @Nonnull String symlinkPath, @Nonnull TaskListener listener) throws InterruptedException { try { if (createSymlinkJava7(baseDir, targetPath, symlinkPath)) { @@ -1245,6 +1278,7 @@ public class Util { * @deprecated as of 1.456 * Use {@link #resolveSymlink(File)} */ + @Deprecated public static String resolveSymlink(File link, TaskListener listener) throws InterruptedException, IOException { return resolveSymlink(link); } @@ -1346,7 +1380,7 @@ public class Util { * @deprecated since 2008-05-13. This method is broken (see ISSUE#1666). It should probably * be removed but I'm not sure if it is considered part of the public API * that needs to be maintained for backwards compatibility. - * Use {@link #encode(String)} instead. + * Use {@link #encode(String)} instead. */ @Deprecated public static String encodeRFC2396(String url) { @@ -1367,7 +1401,7 @@ public class Util { s = ""+s+""; return s; } - + /** * Returns the parsed string if parsed successful; otherwise returns the default number. * If the string is null, empty or a ParseException is thrown then the defaultNumber @@ -1389,16 +1423,36 @@ public class Util { } /** - * Checks if the public method defined on the base type with the given arguments - * are overridden in the given derived type. + * Checks if the method defined on the base type with the given arguments + * is overridden in the given derived type. */ public static boolean isOverridden(@Nonnull Class base, @Nonnull Class derived, @Nonnull String methodName, @Nonnull Class... types) { + return !getMethod(base, methodName, types).equals(getMethod(derived, methodName, types)); + } + + private static Method getMethod(@Nonnull Class clazz, @Nonnull String methodName, @Nonnull Class... types) { + Method res = null; try { - return !base.getMethod(methodName, types).equals( - derived.getMethod(methodName,types)); + res = clazz.getDeclaredMethod(methodName, types); + // private, static or final methods can not be overridden + if (res != null && (Modifier.isPrivate(res.getModifiers()) || Modifier.isFinal(res.getModifiers()) + || Modifier.isStatic(res.getModifiers()))) { + res = null; + } } catch (NoSuchMethodException e) { + // Method not found in clazz, let's search in superclasses + Class superclass = clazz.getSuperclass(); + if (superclass != null) { + res = getMethod(superclass, methodName, types); + } + } catch (SecurityException e) { throw new AssertionError(e); } + if (res == null) { + throw new IllegalArgumentException( + String.format("Method %s not found in %s (or it is private, final or static)", methodName, clazz.getName())); + } + return res; } /** diff --git a/core/src/main/java/hudson/WebAppMain.java b/core/src/main/java/hudson/WebAppMain.java index 11d438d5ab0496010403ef6e046d9684c8ca0a66..d3375be646ad1a264c6a857178b826c25572b9e8 100644 --- a/core/src/main/java/hudson/WebAppMain.java +++ b/core/src/main/java/hudson/WebAppMain.java @@ -396,8 +396,10 @@ public class WebAppMain implements ServletContextListener { if(instance!=null) instance.cleanUp(); Thread t = initThread; - if (t!=null) + if (t != null && t.isAlive()) { + LOGGER.log(Level.INFO, "Shutting down a Jenkins instance that was still starting up", new Throwable("reason")); t.interrupt(); + } // Logger is in the system classloader, so if we don't do this // the whole web app will never be undepoyed. diff --git a/core/src/main/java/hudson/cli/BuildCommand.java b/core/src/main/java/hudson/cli/BuildCommand.java index 39df01901ad1fe0a916afd00b704bed6cbf7c17f..5a018aeeb70d50b41e4ee94f3175c603f2779b44 100644 --- a/core/src/main/java/hudson/cli/BuildCommand.java +++ b/core/src/main/java/hudson/cli/BuildCommand.java @@ -35,7 +35,6 @@ import hudson.model.ParameterDefinition; import hudson.Extension; import hudson.AbortException; import hudson.model.Item; -import hudson.model.Result; import hudson.model.TaskListener; import hudson.model.User; import hudson.model.queue.QueueTaskFuture; @@ -52,7 +51,6 @@ import java.util.ArrayList; import java.util.Map.Entry; import java.io.FileNotFoundException; import java.io.PrintStream; -import javax.annotation.Nonnull; import jenkins.model.Jenkins; diff --git a/core/src/main/java/hudson/cli/CLICommand.java b/core/src/main/java/hudson/cli/CLICommand.java index 2c68b0f6ff7ae094250e8dc89c14c81a8fad3280..a40a8b5bac1175fb1dfe2a6ade5a26f37d319deb 100644 --- a/core/src/main/java/hudson/cli/CLICommand.java +++ b/core/src/main/java/hudson/cli/CLICommand.java @@ -37,6 +37,7 @@ import hudson.remoting.ChannelProperty; import hudson.security.CliAuthenticator; import hudson.security.SecurityRealm; import jenkins.security.MasterToSlaveCallable; +import org.acegisecurity.AccessDeniedException; import org.acegisecurity.Authentication; import org.acegisecurity.BadCredentialsException; import org.acegisecurity.context.SecurityContext; @@ -239,6 +240,9 @@ public abstract class CLICommand implements ExtensionPoint, Cloneable { stderr.println(e.getMessage()); printUsage(stderr, p); return -1; + } catch (AccessDeniedException e) { + stderr.println(e.getMessage()); + return -1; } catch (AbortException e) { // signals an error without stack trace stderr.println(e.getMessage()); @@ -251,6 +255,10 @@ public abstract class CLICommand implements ExtensionPoint, Cloneable { stderr.println("Bad Credentials. Search the server log for "+id+" for more details."); return -1; } catch (Exception e) { + final String errorMsg = String.format("Unexpected exception occurred while performing %s command!", + getName()); + stderr.println(errorMsg); + LOGGER.log(Level.WARNING, errorMsg, e); e.printStackTrace(stderr); return -1; } finally { diff --git a/core/src/main/java/hudson/cli/CliProtocol.java b/core/src/main/java/hudson/cli/CliProtocol.java index 1d4f25627e077f237fa41dc731605309e7c72b59..eecb4c5faf9da881203b3668cbfd9fe23f330182 100644 --- a/core/src/main/java/hudson/cli/CliProtocol.java +++ b/core/src/main/java/hudson/cli/CliProtocol.java @@ -48,6 +48,7 @@ public class CliProtocol extends AgentProtocol { * @deprecated as of 1.559 * Use {@link #Handler(NioChannelHub, Socket)} */ + @Deprecated public Handler(Socket socket) { this(null,socket); } diff --git a/core/src/main/java/hudson/cli/CliProtocol2.java b/core/src/main/java/hudson/cli/CliProtocol2.java index 644914a089bdaa2bb2368f8d2c9bf940b5987cc0..0f2757df786b7dc72c0e8d4e59528aa79df4e6ad 100644 --- a/core/src/main/java/hudson/cli/CliProtocol2.java +++ b/core/src/main/java/hudson/cli/CliProtocol2.java @@ -37,6 +37,7 @@ public class CliProtocol2 extends CliProtocol { * @deprecated as of 1.559 * Use {@link #Handler2(NioChannelHub, Socket)} */ + @Deprecated public Handler2(Socket socket) { super(socket); } diff --git a/core/src/main/java/hudson/cli/CliTransportAuthenticator.java b/core/src/main/java/hudson/cli/CliTransportAuthenticator.java index 0db90cce10c8a57cb7bb9b56b4d63060cf625afd..f561a50eddf21c362f130fdf1c445f8003ceaa62 100644 --- a/core/src/main/java/hudson/cli/CliTransportAuthenticator.java +++ b/core/src/main/java/hudson/cli/CliTransportAuthenticator.java @@ -4,7 +4,6 @@ import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.remoting.Channel; import hudson.security.SecurityRealm; -import jenkins.model.Jenkins; /** * Perform {@link SecurityRealm} independent authentication. diff --git a/core/src/main/java/hudson/cli/CloneableCLICommand.java b/core/src/main/java/hudson/cli/CloneableCLICommand.java index 7fb3b96dd35a3841c491e4138f2cfc61c79c798c..f6a4c60b02c12a17b77481735f1d3b421adfe800 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/cli/CommandDuringBuild.java b/core/src/main/java/hudson/cli/CommandDuringBuild.java index dfa65f487ae5de60b985039fb204575a8d3b18c0..3834238a41fafb0b9f951e30880bca5144709ccc 100644 --- a/core/src/main/java/hudson/cli/CommandDuringBuild.java +++ b/core/src/main/java/hudson/cli/CommandDuringBuild.java @@ -27,7 +27,6 @@ package hudson.cli; import jenkins.model.Jenkins; import hudson.model.Job; import hudson.model.Run; -import hudson.remoting.Callable; import jenkins.security.MasterToSlaveCallable; import org.kohsuke.args4j.CmdLineException; diff --git a/core/src/main/java/hudson/cli/DeleteJobCommand.java b/core/src/main/java/hudson/cli/DeleteJobCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..361d889bccdd376eae9a0e4cc8db0215bcb74b6f --- /dev/null +++ b/core/src/main/java/hudson/cli/DeleteJobCommand.java @@ -0,0 +1,101 @@ +/* + * The MIT License + * + * Copyright (c) 2015 Red Hat, 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.cli; + +import hudson.Extension; +import hudson.model.AbstractItem; +import jenkins.model.Jenkins; +import org.kohsuke.args4j.Argument; + +import java.util.List; +import java.util.HashSet; +import java.util.logging.Logger; + +/** + * @author pjanouse + * @since TODO + */ +@Extension +public class DeleteJobCommand extends CLICommand { + + @Argument(usage="Name of the job(s) to delete", required=true, multiValued=true) + private List jobs; + + private static final Logger LOGGER = Logger.getLogger(DeleteJobCommand.class.getName()); + + @Override + public String getShortDescription() { + + return Messages.DeleteJobCommand_ShortDescription(); + } + + @Override + protected int run() throws Exception { + + boolean errorOccurred = false; + final Jenkins jenkins = Jenkins.getInstance(); + + if (jenkins == null) { + stderr.println("The Jenkins instance has not been started, or was already shut down!"); + return -1; + } + + final HashSet hs = new HashSet(); + hs.addAll(jobs); + + for (String job_s: hs) { + AbstractItem job = null; + + try { + job = (AbstractItem) jenkins.getItemByFullName(job_s); + + if(job == null) { + stderr.format("No such job '%s'\n", job_s); + errorOccurred = true; + continue; + } + + try { + job.checkPermission(AbstractItem.DELETE); + } catch (Exception e) { + stderr.println(e.getMessage()); + errorOccurred = true; + continue; + } + + job.delete(); + } catch (Exception e) { + final String errorMsg = String.format("Unexpected exception occurred during deletion of job '%s': %s", + job == null ? "(null)" : job.getFullName(), + e.getMessage()); + stderr.println(errorMsg); + LOGGER.warning(errorMsg); + errorOccurred = true; + //noinspection UnnecessaryContinue + continue; + } + } + return errorOccurred ? -1 : 0; + } +} diff --git a/core/src/main/java/hudson/cli/DeleteNodeCommand.java b/core/src/main/java/hudson/cli/DeleteNodeCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..4d48e2b78f14cb5e618321d50858ee395c080e11 --- /dev/null +++ b/core/src/main/java/hudson/cli/DeleteNodeCommand.java @@ -0,0 +1,99 @@ +/* + * The MIT License + * + * Copyright (c) 2015 Red Hat, 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.cli; + +import hudson.Extension; +import hudson.model.Node; +import org.acegisecurity.AccessDeniedException; +import jenkins.model.Jenkins; +import org.kohsuke.args4j.Argument; + +import java.util.HashSet; +import java.util.List; +import java.util.logging.Logger; + +/** + * @author pjanouse + * @since TODO + */ +@Extension +public class DeleteNodeCommand extends CLICommand { + + @Argument(usage="Nodes name to delete", required=true, multiValued=true) + private List nodes; + + private static final Logger LOGGER = Logger.getLogger(DeleteNodeCommand.class.getName()); + + @Override + public String getShortDescription() { + + return Messages.DeleteNodeCommand_ShortDescription(); + } + + @Override + protected int run() throws Exception { + + boolean errorOccurred = false; + final Jenkins jenkins = Jenkins.getInstance(); + + if (jenkins == null) { + stderr.println("The Jenkins instance has not been started, or was already shut down!"); + return -1; + } + + final HashSet hs = new HashSet(); + hs.addAll(nodes); + + for (String node_s : hs) { + Node node = null; + + try { + node = jenkins.getNode(node_s); + + if(node == null) { + stderr.format("No such node '%s'\n", node_s); + errorOccurred = true; + continue; + } + + 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(), + e.getMessage()); + stderr.println(errorMsg); + LOGGER.warning(errorMsg); + errorOccurred = true; + //noinspection UnnecessaryContinue + continue; + } + } + return errorOccurred ? -1 : 0; + } +} diff --git a/core/src/main/java/hudson/cli/DeleteViewCommand.java b/core/src/main/java/hudson/cli/DeleteViewCommand.java index 73414701139bab47cc931edb63df4b12e4e7b4c7..4c86edeb70221ed239d4d973371430ce792cccbe 100644 --- a/core/src/main/java/hudson/cli/DeleteViewCommand.java +++ b/core/src/main/java/hudson/cli/DeleteViewCommand.java @@ -1,7 +1,7 @@ /* * The MIT License * - * Copyright (c) 2013 Red Hat, Inc. + * Copyright (c) 2013-5 Red Hat, 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 @@ -24,20 +24,27 @@ package hudson.cli; import hudson.Extension; +import hudson.cli.handlers.ViewOptionHandler; import hudson.model.ViewGroup; import hudson.model.View; import org.kohsuke.args4j.Argument; +import java.util.HashSet; +import java.util.List; +import java.util.logging.Logger; + /** - * @author ogondza + * @author ogondza, pjanouse * @since 1.538 */ @Extension public class DeleteViewCommand extends CLICommand { - @Argument(usage="Name of the view to delete", required=true) - private View view; + @Argument(usage="View names to delete", required=true, multiValued=true) + private List views; + + private static final Logger LOGGER = Logger.getLogger(DeleteViewCommand.class.getName()); @Override public String getShortDescription() { @@ -48,20 +55,54 @@ public class DeleteViewCommand extends CLICommand { @Override protected int run() throws Exception { - view.checkPermission(View.DELETE); + boolean errorOccurred = false; - final ViewGroup group = view.getOwner(); - if (!group.canDelete(view)) { + // Remove duplicates + final HashSet hs = new HashSet(); + hs.addAll(views); - stderr.format("%s does not allow to delete '%s' view\n", - group.getDisplayName(), - view.getViewName() - ); - return -1; - } + ViewOptionHandler voh = new ViewOptionHandler(null, null, null); - group.deleteView(view);; + for(String view_s : hs) { + View view = null; - return 0; + try { + try { + view = voh.getView(view_s); + if (view == null) { + stderr.println("user is missing the View/Read permission"); + errorOccurred = true; + continue; + } + view.checkPermission(View.DELETE); + } catch (Exception e) { + stderr.println(e.getMessage()); + errorOccurred = true; + continue; + } + + ViewGroup group = view.getOwner(); + if (!group.canDelete(view)) { + stderr.format("%s does not allow to delete '%s' view\n", + group.getDisplayName(), + view.getViewName() + ); + errorOccurred = true; + continue; + } + + group.deleteView(view); + } catch (Exception e) { + final String errorMsg = String.format("Unexpected exception occurred during deletion of view '%s': %s", + view == null ? "(null)" : view.getViewName(), + e.getMessage()); + stderr.println(errorMsg); + LOGGER.warning(errorMsg); + errorOccurred = true; + //noinspection UnnecessaryContinue + continue; + } + } + return errorOccurred ? -1 : 0; } } diff --git a/core/src/main/java/hudson/cli/GroovyCommand.java b/core/src/main/java/hudson/cli/GroovyCommand.java index 7866e2f7228d6fde0ea480631c52676da97702fc..a77f41fd92057bf0c9561759646c3abe8e080881 100644 --- a/core/src/main/java/hudson/cli/GroovyCommand.java +++ b/core/src/main/java/hudson/cli/GroovyCommand.java @@ -30,23 +30,15 @@ import hudson.model.AbstractProject; import jenkins.model.Jenkins; import hudson.model.Item; import hudson.model.Run; -import hudson.remoting.Callable; -import hudson.AbortException; import hudson.Extension; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.CmdLineException; import org.apache.commons.io.IOUtils; -import org.apache.commons.io.FileUtils; import java.io.IOException; -import java.io.Serializable; -import java.io.File; -import java.io.InputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; -import java.net.URL; -import java.net.MalformedURLException; /** * Executes the specified groovy script. diff --git a/core/src/main/java/hudson/cli/OnlineNodeCommand.java b/core/src/main/java/hudson/cli/OnlineNodeCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..2ed90c746165a26ffacb448327b6b440b72374a5 --- /dev/null +++ b/core/src/main/java/hudson/cli/OnlineNodeCommand.java @@ -0,0 +1,85 @@ +/* + * The MIT License + * + * Copyright 2015 Red Hat, 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.cli; + +import hudson.Extension; +import hudson.model.Computer; +import jenkins.model.Jenkins; + +import org.acegisecurity.AccessDeniedException; +import org.kohsuke.args4j.Argument; + +import java.util.logging.Logger; + +/** + * @author pjanouse + * @since TODO + */ +@Extension +public class OnlineNodeCommand extends CLICommand { + + @Argument(metaVar="NAME", usage="Slave name, or empty string for master") + public String computerName; + + private static final Logger LOGGER = Logger.getLogger(OnlineNodeCommand.class.getName()); + + @Override + public String getShortDescription() { + + return Messages.OnlineNodeCommand_ShortDescription(); + } + + @Override + protected int run() throws Exception { + + boolean errorOccurred = false; + + final Jenkins jenkins = Jenkins.getInstance(); + + Computer computer = jenkins.getComputer(computerName); + + if (computer == null) { + stderr.println(hudson.model.Messages.Computer_NoSuchSlaveExists(computerName, null)); + errorOccurred = true; + } else { + try { + computer.cliOnline(); + } catch (AccessDeniedException e) { + stderr.println(e.getMessage()); + errorOccurred = true; + } catch (Exception e) { + final String errorMsg = String.format("Unexpected exception occurred during performing online operation on node '%s': %s", + computer == null ? "(null)" : computer.getName(), + e.getMessage()); + stderr.println(errorMsg); + LOGGER.warning(errorMsg); + errorOccurred = true; + } + } + + return errorOccurred ? 1 : 0; + } + +} diff --git a/core/src/main/java/hudson/cli/ReloadJobCommand.java b/core/src/main/java/hudson/cli/ReloadJobCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..a8905b79e0c17df9fa857fa226332bf201b04765 --- /dev/null +++ b/core/src/main/java/hudson/cli/ReloadJobCommand.java @@ -0,0 +1,117 @@ +/* + * The MIT License + * + * Copyright (c) 2015 Red Hat, 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.cli; + +import hudson.Extension; +import hudson.model.AbstractItem; +import hudson.model.AbstractProject; +import hudson.model.Item; + +import jenkins.model.Jenkins; +import org.kohsuke.args4j.Argument; + +import java.util.HashSet; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * @author pjanouse + * @since TODO + */ +@Extension +public class ReloadJobCommand extends CLICommand { + + @Argument(usage="Name of the job(s) to reload", required=true, multiValued=true) + private List jobs; + + private static final Logger LOGGER = Logger.getLogger(ReloadJobCommand.class.getName()); + + @Override + public String getShortDescription() { + + return Messages.ReloadJobCommand_ShortDescription(); + } + + @Override + protected int run() throws Exception { + + boolean errorOccurred = false; + final Jenkins jenkins = Jenkins.getInstance(); + + if (jenkins == null) { + stderr.println("The Jenkins instance has not been started, or was already shut down!"); + return -1; + } + + final HashSet hs = new HashSet(); + hs.addAll(jobs); + + for (String job_s: hs) { + AbstractItem job = null; + + try { + // TODO: JENKINS-30786 + Item item = jenkins.getItemByFullName(job_s); + if (item instanceof AbstractItem) { + job = (AbstractItem) item; + } else if (item != null) { + LOGGER.log(Level.WARNING, "Unsupported item type: {0}", item.getClass().getName()); + } + + if(job == null) { + // TODO: JENKINS-30785 + AbstractProject project = AbstractProject.findNearest(job_s); + if(project == null) { + stderr.format("No such job \u2018%s\u2019 exists.\n", job_s); + } else { + stderr.format("No such job \u2018%s\u2019 exists. Perhaps you meant \u2018%s\u2019?", job_s, project.getFullName()); + } + errorOccurred = true; + continue; + } + + try { + job.checkPermission(AbstractItem.CONFIGURE); + } catch (Exception e) { + stderr.println(e.getMessage()); + errorOccurred = true; + continue; + } + + job.doReload(); + } catch (Exception e) { + final String errorMsg = String.format("Unexpected exception occurred during reloading of job '%s': %s", + job == null ? "(null)" : job.getFullName(), + e.getMessage()); + stderr.println(errorMsg); + LOGGER.warning(errorMsg); + errorOccurred = true; + //noinspection UnnecessaryContinue + continue; + } + } + return errorOccurred ? 1 : 0; + } +} diff --git a/core/src/main/java/hudson/cli/SetBuildDescriptionCommand.java b/core/src/main/java/hudson/cli/SetBuildDescriptionCommand.java index 0aeedb4a37303b7875d1b5178181d79eccabc96c..c7767a796e7d81c48b989b629a89ca33b57dd607 100644 --- a/core/src/main/java/hudson/cli/SetBuildDescriptionCommand.java +++ b/core/src/main/java/hudson/cli/SetBuildDescriptionCommand.java @@ -3,9 +3,7 @@ package hudson.cli; import hudson.Extension; import hudson.model.AbstractProject; import hudson.model.Run; -import hudson.remoting.Callable; -import java.io.IOException; import java.io.Serializable; import org.apache.commons.io.IOUtils; diff --git a/core/src/main/java/hudson/cli/SetBuildResultCommand.java b/core/src/main/java/hudson/cli/SetBuildResultCommand.java index 7666d590a5f7147f33b08f7b15b4a08235e3800a..82756472c7b3ac09f7b6276e472512d4ad8df314 100644 --- a/core/src/main/java/hudson/cli/SetBuildResultCommand.java +++ b/core/src/main/java/hudson/cli/SetBuildResultCommand.java @@ -25,7 +25,6 @@ package hudson.cli; import hudson.Extension; -import hudson.model.Item; import hudson.model.Result; import hudson.model.Run; import org.kohsuke.args4j.Argument; diff --git a/core/src/main/java/hudson/cli/declarative/CLIRegisterer.java b/core/src/main/java/hudson/cli/declarative/CLIRegisterer.java index fe7ed1f690b8fa4aa486a2cc0ae9cd689fa91ac4..a96daf60f9ca8c510232bb3f045735376350e203 100644 --- a/core/src/main/java/hudson/cli/declarative/CLIRegisterer.java +++ b/core/src/main/java/hudson/cli/declarative/CLIRegisterer.java @@ -33,7 +33,6 @@ import hudson.model.Hudson; import jenkins.ExtensionComponentSet; import jenkins.ExtensionRefreshException; import jenkins.model.Jenkins; -import hudson.remoting.Channel; import hudson.security.CliAuthenticator; import org.acegisecurity.Authentication; import org.acegisecurity.context.SecurityContext; diff --git a/core/src/main/java/hudson/cli/declarative/MethodBinder.java b/core/src/main/java/hudson/cli/declarative/MethodBinder.java index 6b137727588a3bbee7a4befcaadb50f3e71a1a73..f9b8885e8ed306790feaaae77197ee2242d8b19a 100644 --- a/core/src/main/java/hudson/cli/declarative/MethodBinder.java +++ b/core/src/main/java/hudson/cli/declarative/MethodBinder.java @@ -30,10 +30,12 @@ import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; import org.kohsuke.args4j.Option; +import org.kohsuke.args4j.spi.FieldSetter; import org.kohsuke.args4j.spi.Setter; import org.kohsuke.args4j.spi.OptionHandler; import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; @@ -79,6 +81,16 @@ class MethodBinder { public boolean isMultiValued() { return false; } + + @Override + public FieldSetter asFieldSetter() { + return null; + } + + @Override + public AnnotatedElement asAnnotatedElement() { + return p; + } }; Option option = p.annotation(Option.class); if (option!=null) { @@ -148,5 +160,10 @@ class MethodBinder { public Class annotationType() { return base.annotationType(); } + + @Override + public boolean hidden() { + return base.hidden(); + } } } diff --git a/core/src/main/java/hudson/cli/handlers/ViewOptionHandler.java b/core/src/main/java/hudson/cli/handlers/ViewOptionHandler.java index 387621ae56b570e70731cbf7f6a6f6a98e755d41..77d086a1d1776141cc5932bb5a41cda0d902d0f5 100644 --- a/core/src/main/java/hudson/cli/handlers/ViewOptionHandler.java +++ b/core/src/main/java/hudson/cli/handlers/ViewOptionHandler.java @@ -38,6 +38,8 @@ import org.kohsuke.args4j.spi.OptionHandler; import org.kohsuke.args4j.spi.Parameters; import org.kohsuke.args4j.spi.Setter; +import javax.annotation.CheckForNull; + /** * Refers to {@link View} by its name. * @@ -73,10 +75,27 @@ public class ViewOptionHandler extends OptionHandler { return 1; } - private View getView(String name) throws CmdLineException { + /** + * + * Gets a view by its name + * Note: Personal user's views aren't supported now. + * + * @param name A view name + * @return The {@link View} instance. Null if {@link Jenkins#getInstance()} returns null + * sor user doesn't have a READ permission. + * @throws CmdLineException + * If view isn't found or an un-expected error occurred + * @since TODO + */ + @CheckForNull + public View getView(final String name) throws CmdLineException { - View view = null; ViewGroup group = Jenkins.getInstance(); + View view = null; + + if (group == null) + throw new CmdLineException(owner, + "The Jenkins instance has not been started, or was already shut down!"); final StringTokenizer tok = new StringTokenizer(name, "/"); while(tok.hasMoreTokens()) { @@ -84,18 +103,23 @@ public class ViewOptionHandler extends OptionHandler { String viewName = tok.nextToken(); view = group.getView(viewName); - if (view == null) throw new CmdLineException(owner, String.format( - "No view named %s inside view %s", - viewName, group.getDisplayName() - )); - - view.checkPermission(View.READ); + if (view == null) + throw new CmdLineException(owner, String.format( + "No view named %s inside view %s", + viewName, group.getDisplayName() + )); + + try { + view.checkPermission(View.READ); + } catch (Exception e) { + throw new CmdLineException(owner, e.getMessage()); + } if (view instanceof ViewGroup) { group = (ViewGroup) view; } else if (tok.hasMoreTokens()) { throw new CmdLineException( - owner, view.getViewName() + " view can not contain views" + owner, view.getViewName() + " view can not contain views" ); } } diff --git a/core/src/main/java/hudson/console/AnnotatedLargeText.java b/core/src/main/java/hudson/console/AnnotatedLargeText.java index 89e307bf22df8a46ad4e97dc0acc09bda283eedf..4e8c40658af523124c83815290ea0efaa8d2f43d 100644 --- a/core/src/main/java/hudson/console/AnnotatedLargeText.java +++ b/core/src/main/java/hudson/console/AnnotatedLargeText.java @@ -147,7 +147,7 @@ public class AnnotatedLargeText extends LargeText { /** * Strips annotations using a {@link PlainTextConsoleOutputStream}. - * @inheritDoc + * {@inheritDoc} */ @Override public long writeLogTo(long start, OutputStream out) throws IOException { @@ -156,7 +156,6 @@ public class AnnotatedLargeText extends LargeText { /** * Calls {@link LargeText#writeLogTo(long, OutputStream)} without stripping annotations as {@link #writeLogTo(long, OutputStream)} would. - * @inheritDoc * @since 1.577 */ public long writeRawLogTo(long start, OutputStream out) throws IOException { diff --git a/core/src/main/java/hudson/console/ConsoleAnnotationDescriptor.java b/core/src/main/java/hudson/console/ConsoleAnnotationDescriptor.java index b4e260b6af257a5f16fb62611253ce7c0ce7ec31..d5ac5081364fe5f7220d2435f65940aa2b436c2e 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 + * Even though this method is not marked 'abstract', this is the method that must be overridden + * by extensions. + */ + public OutputStream decorateLogger(Run build, OutputStream logger) throws IOException, InterruptedException { + // this implementation is backward compatibility thunk in case subtypes only override the + // old signature (AbstractBuild,OutputStream) + + if (build instanceof AbstractBuild) { + // maybe the plugin implements the old signature. + return decorateLogger((AbstractBuild) build, logger); + } else { + // this ConsoleLogFilter can only decorate AbstractBuild, so just pass through + return logger; + } + } + + /** + * Called to decorate logger for master/slave communication. + * + * @param computer + * Slave computer for which the logger is getting decorated. Useful to do + * contextual decoration. + * @since 1.632 + */ + public OutputStream decorateLogger(@Nonnull Computer computer, OutputStream logger) throws IOException, InterruptedException { + return logger; // by default no-op + } /** * All the registered {@link ConsoleLogFilter}s. diff --git a/core/src/main/java/hudson/console/PlainTextConsoleOutputStream.java b/core/src/main/java/hudson/console/PlainTextConsoleOutputStream.java index f1afa2fad5ad91447f5588d35edaede9defcab40..ee02d177d48c4fbd7d0aadc9e422b02aa3d02421 100644 --- a/core/src/main/java/hudson/console/PlainTextConsoleOutputStream.java +++ b/core/src/main/java/hudson/console/PlainTextConsoleOutputStream.java @@ -89,5 +89,5 @@ public class PlainTextConsoleOutputStream extends LineTransformationOutputStream } - private static final Logger LOGGER = Logger.getLogger(ConsoleAnnotationOutputStream.class.getName()); + private static final Logger LOGGER = Logger.getLogger(PlainTextConsoleOutputStream.class.getName()); } diff --git a/core/src/main/java/hudson/diagnosis/HudsonHomeDiskUsageMonitor.java b/core/src/main/java/hudson/diagnosis/HudsonHomeDiskUsageMonitor.java index bb4e8e50401e9292932cf948995d4bb21029ebcb..3b7c7d653f4440b34ddad1f5cad4de7bc5c2c2c5 100644 --- a/core/src/main/java/hudson/diagnosis/HudsonHomeDiskUsageMonitor.java +++ b/core/src/main/java/hudson/diagnosis/HudsonHomeDiskUsageMonitor.java @@ -24,7 +24,6 @@ package hudson.diagnosis; import hudson.model.AdministrativeMonitor; -import jenkins.model.Jenkins; import hudson.model.AbstractModelObject; import hudson.Extension; import hudson.ExtensionPoint; diff --git a/core/src/main/java/hudson/diagnosis/OldDataMonitor.java b/core/src/main/java/hudson/diagnosis/OldDataMonitor.java index f2e1b1eaa14c330bd89418f998bd69f3b7dc0e37..b955cd21783419bec1731a7a2a4d5bd47cfd0911 100644 --- a/core/src/main/java/hudson/diagnosis/OldDataMonitor.java +++ b/core/src/main/java/hudson/diagnosis/OldDataMonitor.java @@ -36,6 +36,7 @@ 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; @@ -46,10 +47,16 @@ 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.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.HttpRedirect; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponses; @@ -67,7 +74,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"); @@ -87,12 +94,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()); @@ -102,12 +105,20 @@ 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 { + 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); + } } } @@ -146,15 +157,18 @@ 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 && odm.data.replace(ref, vr, new VersionRange(vr, version, null))) { + break; + } else if (odm.data.putIfAbsent(ref, new VersionRange(null, version, null)) == null) { + break; + } } + } catch (IllegalArgumentException ex) { + LOGGER.log(Level.WARNING, "Bad parameter given to OldDataMonitor", ex); } } @@ -201,32 +215,49 @@ 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 && odm.data.replace(ref, vr, new VersionRange(vr, null, buf.toString()))) { + break; + } else if (odm.data.putIfAbsent(ref, new VersionRange(null, null, buf.toString())) == null) { + break; + } } } public static class VersionRange { private static VersionNumber currentVersion = Jenkins.getVersion(); - VersionNumber min, max; - boolean single = true; - public String extra; - - public VersionRange(String version, String extra) { - min = max = version != null ? new VersionNumber(version) : null; - this.extra = extra; - } - - public 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; } + final VersionNumber min; + final VersionNumber max; + final boolean single; + final public String extra; + + 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; } } @@ -245,15 +276,20 @@ public class OldDataMonitor extends AdministrativeMonitor { || (currentVersion.digit(0) == min.digit(0) && currentVersion.digit(1) - min.digit(1) >= threshold)); } + } /** * Sorted list of unique max-versions in the data set. For select list in jelly. */ - public synchronized Iterator getVersionList() { + @Restricted(NoExternalUse.class) + 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.max != null) { + set.add(vr.max); + } + } return set.iterator(); } @@ -279,7 +315,7 @@ 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; @@ -318,13 +354,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) { @@ -338,9 +369,7 @@ public class OldDataMonitor extends AdministrativeMonitor { } } - synchronized (this) { - data.keySet().removeAll(removed); - } + data.keySet().removeAll(removed); } public HttpResponse doIndex(StaplerResponse rsp) throws IOException { @@ -355,10 +384,12 @@ public class OldDataMonitor extends AdministrativeMonitor { private static SaveableReference referTo(Saveable s) { if (s instanceof Run) { - return new RunSaveableReference((Run) s); - } else { - return new SimpleSaveableReference(s); + Job parent = ((Run) s).getParent(); + if (Jenkins.getInstance().getItemByFullName(parent.getFullName()) == parent) { + return new RunSaveableReference((Run) s); + } } + return new SimpleSaveableReference(s); } private static final class SimpleSaveableReference implements SaveableReference { diff --git a/core/src/main/java/hudson/init/Terminator.java b/core/src/main/java/hudson/init/Terminator.java index 72a2c9025b6f4e1e1d2417bcb0f9e998c57aedb8..7cea40031c9052d93fe64291e72c0f38ac5ec6a4 100644 --- a/core/src/main/java/hudson/init/Terminator.java +++ b/core/src/main/java/hudson/init/Terminator.java @@ -1,7 +1,6 @@ package hudson.init; import org.jvnet.hudson.annotation_indexer.Indexed; -import org.jvnet.hudson.reactor.Task; import java.lang.annotation.Documented; import java.lang.annotation.Retention; diff --git a/core/src/main/java/hudson/init/impl/GroovyInitScript.java b/core/src/main/java/hudson/init/impl/GroovyInitScript.java index 621d52ce635f59c8d09bc4f198a3a24e4b90b88f..20cd1a481c006f82f2f69557f5a7fc1bcf72ccb0 100644 --- a/core/src/main/java/hudson/init/impl/GroovyInitScript.java +++ b/core/src/main/java/hudson/init/impl/GroovyInitScript.java @@ -27,7 +27,6 @@ import hudson.init.Initializer; import jenkins.model.Jenkins; import jenkins.util.groovy.GroovyHookScript; -import java.io.IOException; import static hudson.init.InitMilestone.*; @@ -39,6 +38,6 @@ import static hudson.init.InitMilestone.*; public class GroovyInitScript { @Initializer(after=JOB_LOADED) public static void init(Jenkins j) { - new GroovyHookScript("init").run(); + new GroovyHookScript("init", j.servletContext, j.getRootDir(), j.getPluginManager().uberClassLoader).run(); } } diff --git a/core/src/main/java/hudson/lifecycle/UnixLifecycle.java b/core/src/main/java/hudson/lifecycle/UnixLifecycle.java index 6a558594532ca65ad95372afecb3cd692c3ea835..0e489277e50ad2d9d486e1ca5ac2212d3673f04d 100644 --- a/core/src/main/java/hudson/lifecycle/UnixLifecycle.java +++ b/core/src/main/java/hudson/lifecycle/UnixLifecycle.java @@ -24,7 +24,6 @@ package hudson.lifecycle; import com.sun.akuma.JavaVMArguments; -import com.sun.akuma.Daemon; import com.sun.jna.Native; import com.sun.jna.StringArray; diff --git a/core/src/main/java/hudson/logging/LogRecorder.java b/core/src/main/java/hudson/logging/LogRecorder.java index 81c9486e3fa8fd0f6ce3d4b9c4ec111faaf5e06b..17ec36ee169ce16bfb67fdebc6ebcc6bd4b51fd5 100644 --- a/core/src/main/java/hudson/logging/LogRecorder.java +++ b/core/src/main/java/hudson/logging/LogRecorder.java @@ -33,7 +33,6 @@ import hudson.model.*; import hudson.util.HttpResponses; import jenkins.model.Jenkins; import hudson.model.listeners.SaveableListener; -import hudson.remoting.Callable; import hudson.remoting.Channel; import hudson.remoting.VirtualChannel; import hudson.slaves.ComputerListener; diff --git a/core/src/main/java/hudson/logging/LogRecorderManager.java b/core/src/main/java/hudson/logging/LogRecorderManager.java index d16ece6c2babdcfdf0fd9f95ddf25ce1098c0b06..e35a098d4bac0af2bc594e1d40f06c777d194ad4 100644 --- a/core/src/main/java/hudson/logging/LogRecorderManager.java +++ b/core/src/main/java/hudson/logging/LogRecorderManager.java @@ -40,6 +40,7 @@ import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpRedirect; +import org.kohsuke.stapler.interceptor.RequirePOST; import javax.servlet.ServletException; import java.io.File; @@ -106,6 +107,7 @@ public class LogRecorderManager extends AbstractModelObject implements ModelObje /** * Creates a new log recorder. */ + @RequirePOST public HttpResponse doNewLogRecorder(@QueryParameter String name) { Jenkins.checkGoodName(name); diff --git a/core/src/main/java/hudson/model/AbstractBuild.java b/core/src/main/java/hudson/model/AbstractBuild.java index d6dc13703f0345bbe310d37793e78450e07676b4..e9c4626706c6cb564cb4f2b6e260bf8ef541f709 100644 --- a/core/src/main/java/hudson/model/AbstractBuild.java +++ b/core/src/main/java/hudson/model/AbstractBuild.java @@ -30,8 +30,6 @@ import hudson.EnvVars; import hudson.FilePath; import hudson.Functions; import hudson.Launcher; -import hudson.console.AnnotatedLargeText; -import hudson.console.ExpandableDetailsNote; import hudson.console.ModelHyperlinkNote; import hudson.model.Fingerprint.BuildPtr; import hudson.model.Fingerprint.RangeSet; @@ -70,7 +68,6 @@ import javax.servlet.ServletException; import java.io.File; import java.io.IOException; import java.io.InterruptedIOException; -import java.io.StringWriter; import java.lang.ref.WeakReference; import java.util.AbstractSet; import java.util.ArrayList; @@ -413,6 +410,7 @@ public abstract class AbstractBuild

,R extends Abs * @deprecated as of 1.467 * Please use {@link hudson.model.Run.RunExecution} */ + @Deprecated public abstract class AbstractRunner extends AbstractBuildExecution { } @@ -691,6 +689,7 @@ public abstract class AbstractBuild

,R extends Abs * @deprecated as of 1.356 * Use {@link #performAllBuildSteps(BuildListener, Map, boolean)} */ + @Deprecated protected final void performAllBuildStep(BuildListener listener, Map buildSteps, boolean phase) throws InterruptedException, IOException { performAllBuildSteps(listener,buildSteps.values(),phase); } @@ -703,6 +702,7 @@ public abstract class AbstractBuild

,R extends Abs * @deprecated as of 1.356 * Use {@link #performAllBuildSteps(BuildListener, Iterable, boolean)} */ + @Deprecated protected final void performAllBuildStep(BuildListener listener, Iterable buildSteps, boolean phase) throws InterruptedException, IOException { performAllBuildSteps(listener,buildSteps,phase); } @@ -712,6 +712,8 @@ public abstract class AbstractBuild

,R extends Abs * * @param phase * true for the post build processing, and false for the final "run after finished" execution. + * + * @return false if any build step failed */ protected final boolean performAllBuildSteps(BuildListener listener, Iterable buildSteps, boolean phase) throws InterruptedException, IOException { boolean r = true; @@ -721,20 +723,39 @@ public abstract class AbstractBuild

,R extends Abs if (!perform(bs,listener)) { LOGGER.log(Level.FINE, "{0} : {1} failed", new Object[] {AbstractBuild.this, bs}); r = false; + if (phase) { + setResult(Result.FAILURE); + } } } catch (Exception e) { reportError(bs, e, listener, phase); + r = false; } catch (LinkageError e) { reportError(bs, e, listener, phase); + r = false; } } return r; } private void reportError(BuildStep bs, Throwable e, BuildListener listener, boolean phase) { - String msg = "Publisher " + bs.getClass().getName() + " aborted due to exception"; - e.printStackTrace(listener.error(msg)); - LOGGER.log(WARNING, msg, e); + 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, buildStep}); + listener.error("Step ‘" + buildStep + "’ failed: " + e.getMessage()); + } else { + String msg = "Step ‘" + buildStep + "’ aborted due to exception: "; + e.printStackTrace(listener.error(msg)); + LOGGER.log(WARNING, msg, e); + } + if (phase) { setResult(Result.FAILURE); } @@ -1051,6 +1072,7 @@ public abstract class AbstractBuild

,R extends Abs /** * @deprecated Use {@link #getAction(Class)} on {@link AbstractTestResultAction}. */ + @Deprecated public Action getTestResultAction() { try { return getAction(Jenkins.getInstance().getPluginManager().uberClassLoader.loadClass("hudson.tasks.test.AbstractTestResultAction").asSubclass(Action.class)); @@ -1062,6 +1084,7 @@ public abstract class AbstractBuild

,R extends Abs /** * @deprecated Use {@link #getAction(Class)} on {@link AggregatedTestResultAction}. */ + @Deprecated public Action getAggregatedTestResultAction() { try { return getAction(Jenkins.getInstance().getPluginManager().uberClassLoader.loadClass("hudson.tasks.test.AggregatedTestResultAction").asSubclass(Action.class)); @@ -1340,6 +1363,7 @@ public abstract class AbstractBuild

,R extends Abs * @deprecated as of 1.489 * Use {@link #doStop()} */ + @Deprecated public void doStop(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { doStop().generateResponse(req,rsp,this); } diff --git a/core/src/main/java/hudson/model/AbstractCIBase.java b/core/src/main/java/hudson/model/AbstractCIBase.java index cf9cec9bf27df85901cfcfd41bf502aacd9cecf4..cf487105c207d235765df804143e8b5e3796f1bd 100644 --- a/core/src/main/java/hudson/model/AbstractCIBase.java +++ b/core/src/main/java/hudson/model/AbstractCIBase.java @@ -34,7 +34,6 @@ import jenkins.model.Jenkins; import org.kohsuke.stapler.StaplerFallback; import org.kohsuke.stapler.StaplerProxy; -import java.io.IOException; import java.util.*; import java.util.concurrent.CopyOnWriteArraySet; import java.util.logging.Logger; @@ -48,8 +47,6 @@ public abstract class AbstractCIBase extends Node implements ItemGroup computers = getComputerMap(); - for (Map.Entry e : computers.entrySet()) { - if (e.getValue() == computer) { - computers.remove(e.getKey()); - computer.onRemoved(); - return; + /*package*/ void removeComputer(final Computer computer) { + Queue.withLock(new Runnable() { + @Override + public void run() { + Map computers = getComputerMap(); + for (Map.Entry e : computers.entrySet()) { + if (e.getValue() == computer) { + computers.remove(e.getKey()); + computer.onRemoved(); + return; + } + } } - } + }); } /*package*/ @CheckForNull Computer getComputer(Node n) { @@ -160,36 +163,46 @@ public abstract class AbstractCIBase extends Node implements ItemGroup computers = getComputerMap(); - synchronized(updateComputerLock) {// just so that we don't have two code updating computer list at the same time - Map byName = new HashMap(); - for (Computer c : computers.values()) { - Node node = c.getNode(); - if (node == null) - continue; // this computer is gone - byName.put(node.getNodeName(),c); - } + protected void updateComputerList(final boolean automaticSlaveLaunch) { + final Map computers = getComputerMap(); + final Set old = new HashSet(computers.size()); + Queue.withLock(new Runnable() { + @Override + public void run() { + Map byName = new HashMap(); + for (Computer c : computers.values()) { + old.add(c); + Node node = c.getNode(); + if (node == null) + continue; // this computer is gone + byName.put(node.getNodeName(),c); + } - final Set old = new HashSet(computers.values()); - Set used = new HashSet(); + Set used = new HashSet(old.size()); - updateComputer(this, byName, used, automaticSlaveLaunch); - for (Node s : getNodes()) { - long start = System.currentTimeMillis(); - updateComputer(s, byName, used, automaticSlaveLaunch); - if(LOG_STARTUP_PERFORMANCE) - LOGGER.info(String.format("Took %dms to update node %s", - System.currentTimeMillis()-start, s.getNodeName())); - } + updateComputer(AbstractCIBase.this, byName, used, automaticSlaveLaunch); + for (Node s : getNodes()) { + long start = System.currentTimeMillis(); + updateComputer(s, byName, used, automaticSlaveLaunch); + if(LOG_STARTUP_PERFORMANCE) + LOGGER.info(String.format("Took %dms to update node %s", + System.currentTimeMillis()-start, s.getNodeName())); + } - // find out what computers are removed, and kill off all executors. - // when all executors exit, it will be removed from the computers map. - // so don't remove too quickly - old.removeAll(used); - for (Computer c : old) { - killComputer(c); + // find out what computers are removed, and kill off all executors. + // when all executors exit, it will be removed from the computers map. + // so don't remove too quickly + old.removeAll(used); + // we need to start the process of reducing the executors on all computers as distinct + // from the killing action which should not excessively use the Queue lock. + for (Computer c : old) { + c.inflictMortalWound(); + } } + }); + for (Computer c : old) { + // when we get to here, the number of executors should be zero so this call should not need the Queue.lock + killComputer(c); } getQueue().scheduleMaintenance(); for (ComputerListener cl : ComputerListener.all()) diff --git a/core/src/main/java/hudson/model/AbstractDescribableImpl.java b/core/src/main/java/hudson/model/AbstractDescribableImpl.java index 5961a80834a13feb490f3d29fd3976860913dcda..07ed386a930885d755b29f9b68c1d184d1bc7a18 100644 --- a/core/src/main/java/hudson/model/AbstractDescribableImpl.java +++ b/core/src/main/java/hudson/model/AbstractDescribableImpl.java @@ -37,6 +37,7 @@ public abstract class AbstractDescribableImpl{@inheritDoc} */ + @Override public Descriptor getDescriptor() { return Jenkins.getInstance().getDescriptorOrDie(getClass()); } diff --git a/core/src/main/java/hudson/model/AbstractItem.java b/core/src/main/java/hudson/model/AbstractItem.java index 3524444feaf3fe4c837502244dd049509a48f14f..f0f300805ea6c25ed8718c1be0f147429414cc7c 100644 --- a/core/src/main/java/hudson/model/AbstractItem.java +++ b/core/src/main/java/hudson/model/AbstractItem.java @@ -30,7 +30,6 @@ import hudson.XmlFile; import hudson.Util; import hudson.Functions; import hudson.BulkChange; -import hudson.cli.declarative.CLIMethod; import hudson.cli.declarative.CLIResolver; import hudson.model.listeners.ItemListener; import hudson.model.listeners.SaveableListener; @@ -45,6 +44,8 @@ import jenkins.model.DirectlyModifiableTopLevelItemGroup; import jenkins.model.Jenkins; import jenkins.security.NotReallyRoleSensitiveCallable; import org.acegisecurity.Authentication; +import jenkins.util.xml.XMLUtils; + import org.apache.tools.ant.taskdefs.Copy; import org.apache.tools.ant.types.FileSet; import org.kohsuke.stapler.WebMethod; @@ -67,12 +68,11 @@ import org.kohsuke.stapler.HttpDeletable; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.stapler.interceptor.RequirePOST; +import org.xml.sax.SAXException; import javax.servlet.ServletException; import javax.xml.transform.Source; -import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; @@ -163,7 +163,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(); } @@ -215,6 +215,8 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet protected void renameTo(final String newName) throws IOException { // always synchronize from bigger objects first final ItemGroup parent = getParent(); + String oldName = this.name; + String oldFullName = getFullName(); synchronized (parent) { synchronized (this) { // sanity check @@ -247,9 +249,6 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet } }); - - String oldName = this.name; - String oldFullName = getFullName(); File oldRoot = this.getRootDir(); doSetName(newName); @@ -323,10 +322,9 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet } catch (AbstractMethodError _) { // ignore } - - ItemListener.fireLocationChange(this, oldFullName); } } + ItemListener.fireLocationChange(this, oldFullName); } @@ -539,7 +537,6 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet * since it predates {@code }. {@code /delete} goes to a Jelly page * which should now be unused by core but is left in case plugins are still using it. */ - @CLIMethod(name="delete-job") @RequirePOST public void doDoDelete( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException, InterruptedException { delete(); @@ -622,30 +619,30 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet * @deprecated as of 1.473 * Use {@link #updateByXml(Source)} */ + @Deprecated public void updateByXml(StreamSource source) throws IOException { updateByXml((Source)source); } /** - * Updates Job by its XML definition. + * Updates an Item by its XML definition. + * @param source source of the Item's new definition. + * The source should be either a StreamSource or a SAXSource, other + * sources may not be handled. * @since 1.473 */ public void updateByXml(Source source) throws IOException { checkPermission(CONFIGURE); XmlFile configXmlFile = getConfigFile(); - AtomicFileWriter out = new AtomicFileWriter(configXmlFile.getFile()); + final AtomicFileWriter out = new AtomicFileWriter(configXmlFile.getFile()); try { try { - // this allows us to use UTF-8 for storing data, - // plus it checks any well-formedness issue in the submitted - // data - Transformer t = TransformerFactory.newInstance() - .newTransformer(); - t.transform(source, - new StreamResult(out)); + XMLUtils.safeTransform(source, new StreamResult(out)); out.close(); } catch (TransformerException e) { throw new IOException("Failed to persist config.xml", e); + } catch (SAXException e) { + throw new IOException("Failed to persist config.xml", e); } // try to reflect the changes by reloading @@ -667,6 +664,7 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet // if everything went well, commit this new version out.commit(); SaveableListener.fireOnChange(this, getConfigFile()); + } finally { out.abort(); // don't leave anything behind } @@ -681,7 +679,6 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet * * @since 1.556 */ - @CLIMethod(name="reload-job") @RequirePOST public void doReload() throws IOException { checkPermission(CONFIGURE); @@ -701,8 +698,8 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet } - /* (non-Javadoc) - * @see hudson.model.AbstractModelObject#getSearchName() + /** + * {@inheritDoc} */ @Override public String getSearchName() { @@ -724,8 +721,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/java/hudson/model/AbstractModelObject.java b/core/src/main/java/hudson/model/AbstractModelObject.java index 301d6d09b3765a9b1ca449c1536d4706aacbe661..847d545222a99dfba2877d92fcfbf1579b12da23 100644 --- a/core/src/main/java/hudson/model/AbstractModelObject.java +++ b/core/src/main/java/hudson/model/AbstractModelObject.java @@ -81,6 +81,7 @@ public abstract class AbstractModelObject implements SearchableModelObject { * @deprecated * Use {@link RequirePOST} on your method. */ + @Deprecated protected final void requirePOST() throws ServletException { StaplerRequest req = Stapler.getCurrentRequest(); if (req==null) return; // invoked outside the context of servlet diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java index 4a8e3dd901087490ace0d33414d07520f081a2ca..d807695eb465516dc62d76ffd078e0db05817923 100644 --- a/core/src/main/java/hudson/model/AbstractProject.java +++ b/core/src/main/java/hudson/model/AbstractProject.java @@ -55,7 +55,6 @@ import hudson.model.queue.CauseOfBlockage; import hudson.model.queue.QueueTaskFuture; import hudson.model.queue.SubTask; import hudson.model.queue.SubTaskContributor; -import hudson.node_monitors.DiskSpaceMonitor; import hudson.scm.ChangeLogSet; import hudson.scm.ChangeLogSet.Entry; import hudson.scm.NullSCM; @@ -106,6 +105,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; @@ -266,7 +266,9 @@ public abstract class AbstractProject

,R extends A buildMixIn = createBuildMixIn(); builds = buildMixIn.getRunMap(); - if(Jenkins.getInstance()!=null && !Jenkins.getInstance().getNodes().isEmpty()) { + final Jenkins j = Jenkins.getInstance(); + final List nodes = j != null ? j.getNodes() : null; + if(nodes!=null && !nodes.isEmpty()) { // if a new job is configured with Hudson that already has slave nodes // make it roamable by default canRoam = true; @@ -323,7 +325,11 @@ public abstract class AbstractProject

,R extends A builds = buildMixIn.getRunMap(); triggers().setOwner(this); for (Trigger t : triggers()) { - t.start(this, Items.currentlyUpdatingByXml()); + 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) scm = new NullSCM(); // perhaps it was pointing to a plugin that no longer exists. @@ -351,7 +357,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"); } @@ -465,6 +471,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()); } @@ -505,6 +512,7 @@ public abstract class AbstractProject

,R extends A * If you are calling this method to serve a file from the workspace, doing a form validation, etc., then * use {@link #getSomeWorkspace()} */ + @Deprecated public final FilePath getWorkspace() { AbstractBuild b = getBuildForDeprecatedMethods(); return b != null ? b.getWorkspace() : null; @@ -586,6 +594,7 @@ public abstract class AbstractProject

,R extends A * @deprecated as of 1.319 * See {@link #getWorkspace()} for a migration strategy. */ + @Deprecated public FilePath getModuleRoot() { AbstractBuild b = getBuildForDeprecatedMethods(); return b != null ? b.getModuleRoot() : null; @@ -601,6 +610,7 @@ public abstract class AbstractProject

,R extends A * @deprecated as of 1.319 * See {@link #getWorkspace()} for a migration strategy. */ + @Deprecated public FilePath[] getModuleRoots() { AbstractBuild b = getBuildForDeprecatedMethods(); return b != null ? b.getModuleRoots() : null; @@ -797,6 +807,7 @@ public abstract class AbstractProject

,R extends A * @deprecated * Use {@link #scheduleBuild(Cause)}. Since 1.283 */ + @Deprecated public boolean scheduleBuild() { return getParameterizedJobMixIn().scheduleBuild(); } @@ -805,6 +816,7 @@ public abstract class AbstractProject

,R extends A * @deprecated * Use {@link #scheduleBuild(int, Cause)}. Since 1.283 */ + @Deprecated public boolean scheduleBuild(int quietPeriod) { return getParameterizedJobMixIn().scheduleBuild(quietPeriod); } @@ -1077,6 +1089,7 @@ public abstract class AbstractProject

,R extends A * or if the blockBuildWhenUpstreamBuilding option is true and an upstream * project is building, but derived classes can also check other conditions. */ + @Override public boolean isBuildBlocked() { return getCauseOfBlockage()!=null; } @@ -1087,23 +1100,12 @@ 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; - + @Deprecated + 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); } } @@ -1139,10 +1141,12 @@ public abstract class AbstractProject

,R extends A } } + @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) @@ -1226,6 +1230,7 @@ public abstract class AbstractProject

,R extends A * If you need to lock a workspace while you do some computation, see the source code of * {@link #pollSCMChanges(TaskListener)} for how to obtain a lock of a workspace through {@link WorkspaceList}. */ + @Deprecated public Resource getWorkspaceResource() { return new Resource(getFullDisplayName()+" workspace"); } @@ -1259,13 +1264,7 @@ public abstract class AbstractProject

,R extends A return true; // no SCM FilePath workspace = build.getWorkspace(); - try { - workspace.mkdirs(); - } catch (IOException e) { - // Can't create workspace dir - Is slave disk full ? - new DiskSpaceMonitor().markNodeOfflineIfDiskspaceIsTooLow(build.getBuiltOn().toComputer()); - throw e; - } + workspace.mkdirs(); boolean r = scm.checkout(build, launcher, workspace, listener, changelogFile); if (r) { @@ -1299,6 +1298,7 @@ public abstract class AbstractProject

,R extends A * @deprecated as of 1.346 * Use {@link #poll(TaskListener)} instead. */ + @Deprecated public boolean pollSCMChanges( TaskListener listener ) { return poll(listener).hasChanges(); } @@ -1460,7 +1460,8 @@ public abstract class AbstractProject

,R extends A Launcher launcher = ws.createLauncher(listener).decorateByEnv(getEnvironment(node,listener)); WorkspaceList.Lease lease = l.acquire(ws, !concurrentBuild); try { - listener.getLogger().println("Polling SCM changes on " + node.getSelfLabel().getName()); + String nodeName = node != null ? node.getSelfLabel().getName() : "[node_unavailable]"; + listener.getLogger().println("Polling SCM changes on " + nodeName); LOGGER.fine("Polling SCM changes of " + getName()); if (pollingBaseline==null) // see NOTE-NO-BASELINE above calcPollingBaseline(lb,launcher,listener); @@ -1756,6 +1757,7 @@ public abstract class AbstractProject

,R extends A * @deprecated as of 1.489 * Inject {@link TimeDuration}. */ + @Deprecated public int getDelay(StaplerRequest req) throws ServletException { String delay = req.getParameter("delay"); if (delay==null) return getQuietPeriod(); @@ -1872,6 +1874,7 @@ public abstract class AbstractProject

,R extends A * @deprecated * As of 1.261. Use {@link #buildDescribable(StaplerRequest, List)} instead. */ + @Deprecated protected final > List buildDescribable(StaplerRequest req, List> descriptors, String prefix) throws FormException, ServletException { return buildDescribable(req,descriptors); } @@ -1920,6 +1923,7 @@ public abstract class AbstractProject

,R extends A /** * Wipes out the workspace. */ + @RequirePOST public HttpResponse doDoWipeOutWorkspace() throws IOException, ServletException, InterruptedException { checkPermission(Functions.isWipeOutPermissionEnabled() ? WIPEOUT : BUILD); R b = getSomeBuildWithWorkspace(); @@ -2097,8 +2101,8 @@ public abstract class AbstractProject

,R extends A } } return FormValidation.okWithMarkup(Messages.AbstractProject_LabelLink( - j.getRootUrl(), l.getUrl(), l.getNodes().size() + l.getClouds().size() - )); + j.getRootUrl(), l.getUrl(), l.getNodes().size(), l.getClouds().size()) + ); } public FormValidation doCheckCustomWorkspace(@QueryParameter String customWorkspace){ @@ -2219,11 +2223,13 @@ public abstract class AbstractProject

,R extends A /** * @deprecated Just use {@link #CANCEL}. */ + @Deprecated 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(); /** @@ -2233,8 +2239,11 @@ public abstract class AbstractProject

,R extends A public static AbstractProject resolveForCLI( @Argument(required=true,metaVar="NAME",usage="Job name") String name) throws CmdLineException { AbstractProject item = Jenkins.getInstance().getItemByFullName(name, AbstractProject.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/java/hudson/model/AdministrativeMonitor.java b/core/src/main/java/hudson/model/AdministrativeMonitor.java index a8e555409214ac44570ffbd1384d8c53b887630d..0bdc8a97bc18b9cab09dbca8e559273e67cf2ae4 100644 --- a/core/src/main/java/hudson/model/AdministrativeMonitor.java +++ b/core/src/main/java/hudson/model/AdministrativeMonitor.java @@ -28,7 +28,6 @@ import hudson.ExtensionList; import hudson.Extension; import hudson.ExtensionPoint.LegacyInstancesAreScopedToHudson; import hudson.triggers.SCMTrigger; -import hudson.triggers.TimerTrigger; import java.util.Set; import java.io.IOException; diff --git a/core/src/main/java/hudson/model/AperiodicWork.java b/core/src/main/java/hudson/model/AperiodicWork.java index 56b0804da1ec2f949193a67c93d99e23db88ea70..fbd4f2c4f7a3da987d57e4f61168d453647ff667 100644 --- a/core/src/main/java/hudson/model/AperiodicWork.java +++ b/core/src/main/java/hudson/model/AperiodicWork.java @@ -27,11 +27,9 @@ import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.init.Initializer; import hudson.triggers.SafeTimerTask; -import jenkins.model.Jenkins; import jenkins.util.Timer; import java.util.Random; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; diff --git a/core/src/main/java/hudson/model/Api.java b/core/src/main/java/hudson/model/Api.java index c749f46d133336ef38979dae3a6a0c275a0184a8..258f48ffea95f243d6d47b2f831e356d51286f9f 100644 --- a/core/src/main/java/hudson/model/Api.java +++ b/core/src/main/java/hudson/model/Api.java @@ -24,6 +24,7 @@ package hudson.model; import hudson.ExtensionList; +import jenkins.util.xml.FilteredFunctionContext; import jenkins.model.Jenkins; import jenkins.security.SecureRequester; @@ -32,6 +33,7 @@ import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentFactory; import org.dom4j.Element; +import org.dom4j.XPath; import org.dom4j.io.SAXReader; import org.dom4j.io.XMLWriter; import org.kohsuke.stapler.QueryParameter; @@ -107,14 +109,16 @@ public class Api extends AbstractModelObject { p.writeTo(bean,pruner,Flavor.XML.createDataWriter(bean,sw)); // apply XPath + FilteredFunctionContext functionContext = new FilteredFunctionContext(); Object result; try { Document dom = new SAXReader().read(new StringReader(sw.toString())); - // apply exclusions if (excludes!=null) { for (String exclude : excludes) { - List list = (List)dom.selectNodes(exclude); + XPath xExclude = dom.createXPath(exclude); + xExclude.setFunctionContext(functionContext); + List list = (List)xExclude.selectNodes(dom); for (org.dom4j.Node n : list) { Element parent = n.getParent(); if(parent!=null) @@ -126,7 +130,9 @@ public class Api extends AbstractModelObject { if(xpath==null) { result = dom; } else { - List list = dom.selectNodes(xpath); + XPath comp = dom.createXPath(xpath); + comp.setFunctionContext(functionContext); + List list = comp.selectNodes(dom); if (wrapper!=null) { Element root = DocumentFactory.getInstance().createElement(wrapper); for (Object o : list) { @@ -202,7 +208,7 @@ public class Api extends AbstractModelObject { public void doJson(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { if (req.getParameter("jsonp") == null || permit(req)) { setHeaders(rsp); - rsp.serveExposedBean(req,bean, Flavor.JSON); + rsp.serveExposedBean(req,bean, req.getParameter("jsonp") == null ? Flavor.JSON : Flavor.JSONP); } else { rsp.sendError(HttpURLConnection.HTTP_FORBIDDEN, "jsonp forbidden; implement jenkins.security.SecureRequester"); } diff --git a/core/src/main/java/hudson/model/AsyncAperiodicWork.java b/core/src/main/java/hudson/model/AsyncAperiodicWork.java index f46dd33b61d835eec945fec60f76975809d9c3de..9111e5fd474d5536879c86180272737fe26aa67c 100644 --- a/core/src/main/java/hudson/model/AsyncAperiodicWork.java +++ b/core/src/main/java/hudson/model/AsyncAperiodicWork.java @@ -31,8 +31,6 @@ import java.io.IOException; import java.util.logging.Level; import jenkins.model.Jenkins; -import org.acegisecurity.context.SecurityContext; -import org.acegisecurity.context.SecurityContextHolder; /** * {@link AperiodicWork} that takes a long time to run. Similar to {@link AsyncPeriodicWork}, see {@link AsyncPeriodicWork} for diff --git a/core/src/main/java/hudson/model/Build.java b/core/src/main/java/hudson/model/Build.java index 99073f1b7332b5eccc737e2eea1edd55ed5f9a14..a5dbcfcf1f1958afc9cdccb54d4074d326d84470 100644 --- a/core/src/main/java/hudson/model/Build.java +++ b/core/src/main/java/hudson/model/Build.java @@ -119,6 +119,7 @@ public abstract class Build

,B extends Build> * proper execution object. */ @Restricted(NoExternalUse.class) + @Deprecated protected Runner createRunner() { return new BuildExecution(); } @@ -127,6 +128,7 @@ public abstract class Build

,B extends Build> * @deprecated as of 1.467 * Please use {@link BuildExecution} */ + @Deprecated protected class RunnerImpl extends BuildExecution { } @@ -189,8 +191,12 @@ public abstract class Build

,B extends Build> @Override public void cleanUp(@Nonnull BuildListener listener) throws Exception { // at this point it's too late to mark the build as a failure, so ignore return value. - performAllBuildSteps(listener, project.getPublishersList(), false); - performAllBuildSteps(listener, project.getProperties(), false); + try { + performAllBuildSteps(listener, project.getPublishersList(), false); + performAllBuildSteps(listener, project.getProperties(), false); + } catch (Exception x) { + x.printStackTrace(listener.error(Messages.Build_post_build_steps_failed())); + } super.cleanUp(listener); } diff --git a/core/src/main/java/hudson/model/BuildAuthorizationToken.java b/core/src/main/java/hudson/model/BuildAuthorizationToken.java index 7ab272afdad7f2638a8befa703561aa723a44e1f..8aa53eb429da444c1a435e99abc9cd72e35f21b1 100644 --- a/core/src/main/java/hudson/model/BuildAuthorizationToken.java +++ b/core/src/main/java/hudson/model/BuildAuthorizationToken.java @@ -45,6 +45,7 @@ import org.kohsuke.stapler.HttpResponses; * Use {@link ACL} and {@link Item#BUILD}. This code is only here * for the backward compatibility. */ +@Deprecated public final class BuildAuthorizationToken { private final String token; diff --git a/core/src/main/java/hudson/model/BuildStepListener.java b/core/src/main/java/hudson/model/BuildStepListener.java index a37cb8f67abfa6f37622d042ff09038207f4a6dd..e0ee3efe29ce12313b1ff81abfbc11c51d7d0905 100644 --- a/core/src/main/java/hudson/model/BuildStepListener.java +++ b/core/src/main/java/hudson/model/BuildStepListener.java @@ -3,7 +3,6 @@ package hudson.model; import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.tasks.BuildStep; -import jenkins.model.Jenkins; /** * Receives events that happen as a build executes {@link BuildStep}s. diff --git a/core/src/main/java/hudson/model/BuildVariableContributor.java b/core/src/main/java/hudson/model/BuildVariableContributor.java index 15baad759088c83ce5deb3cde44e56e7b4103e68..83046baa5440d2c5f7c489db65c040ce54da5009 100644 --- a/core/src/main/java/hudson/model/BuildVariableContributor.java +++ b/core/src/main/java/hudson/model/BuildVariableContributor.java @@ -27,7 +27,6 @@ import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.tasks.Builder; import hudson.tasks.Publisher; -import jenkins.model.Jenkins; import java.util.Map; diff --git a/core/src/main/java/hudson/model/BuildableItem.java b/core/src/main/java/hudson/model/BuildableItem.java index 17956d175b6f3d2cbdab7a7e07b8607eecfa0528..ef845e11750de8a31ae6ff4c2627ddc6594ceb3f 100644 --- a/core/src/main/java/hudson/model/BuildableItem.java +++ b/core/src/main/java/hudson/model/BuildableItem.java @@ -39,12 +39,14 @@ public interface BuildableItem extends Item, Task { * @deprecated * Use {@link #scheduleBuild(Cause)}. Since 1.283 */ + @Deprecated boolean scheduleBuild(); boolean scheduleBuild(Cause c); /** * @deprecated * Use {@link #scheduleBuild(int, Cause)}. Since 1.283 */ + @Deprecated boolean scheduleBuild(int quietPeriod); boolean scheduleBuild(int quietPeriod, Cause c); } diff --git a/core/src/main/java/hudson/model/Cause.java b/core/src/main/java/hudson/model/Cause.java index 37dbcee4ca753fdb5fa11f88eac7626fe77d5e9f..2ee6ba7982730ee1a563224c80e75cf8a6c1270b 100644 --- a/core/src/main/java/hudson/model/Cause.java +++ b/core/src/main/java/hudson/model/Cause.java @@ -124,6 +124,7 @@ public abstract class Cause { * Fall back implementation when no other type is available. * @deprecated since 2009-02-08 */ + @Deprecated public static class LegacyCodeCause extends Cause { private StackTraceElement [] stackTrace; public LegacyCodeCause() { @@ -162,6 +163,7 @@ public abstract class Cause { * @deprecated since 2009-02-28 */ // for backward bytecode compatibility + @Deprecated public UpstreamCause(AbstractBuild up) { this((Run)up); } @@ -361,6 +363,7 @@ public abstract class Cause { * @deprecated 1.428 * use {@link UserIdCause} */ + @Deprecated public static class UserCause extends Cause { private String authenticationName; public UserCause() { diff --git a/core/src/main/java/hudson/model/CauseAction.java b/core/src/main/java/hudson/model/CauseAction.java index afe715cef091f7832b987854a8d91cdadefe91ea..252c91c722cbba7ad0dc081bfadbf74c666862de 100644 --- a/core/src/main/java/hudson/model/CauseAction.java +++ b/core/src/main/java/hudson/model/CauseAction.java @@ -113,6 +113,7 @@ public class CauseAction implements FoldableAction, RunAction2 { * @deprecated as of 1.288 * but left here for backward compatibility. */ + @Deprecated public String getShortDescription() { if(causes.isEmpty()) return "N/A"; return causes.get(0).getShortDescription(); diff --git a/core/src/main/java/hudson/model/ChoiceParameterDefinition.java b/core/src/main/java/hudson/model/ChoiceParameterDefinition.java index c13137d62a7b2f833497b302cb66960d74c17936..0bd4b60ab3666bb55d7331ed29333304b352b18f 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 2d23453fad5293ef1a35ab79dc98938cb3ab20c8..4ce4a3b7a39db9ac05bf9c7b02023a7c29662e5a 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -2,7 +2,8 @@ * The MIT License * * Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, - * Red Hat, Inc., Seiji Sogabe, Stephen Connolly, Thomas J. Black, Tom Huybrechts, CloudBees, Inc. + * Red Hat, Inc., Seiji Sogabe, Stephen Connolly, Thomas J. Black, Tom Huybrechts, + * CloudBees, Inc., Christopher Simons * * 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,6 +28,7 @@ package hudson.model; import edu.umd.cs.findbugs.annotations.OverrideMustInvoke; import edu.umd.cs.findbugs.annotations.When; import hudson.EnvVars; +import hudson.Extension; import hudson.Launcher.ProcStarter; import hudson.Util; import hudson.cli.declarative.CLIMethod; @@ -45,6 +47,7 @@ import hudson.security.AccessControlled; import hudson.security.Permission; import hudson.security.PermissionGroup; import hudson.security.PermissionScope; +import hudson.slaves.AbstractCloudSlave; import hudson.slaves.ComputerLauncher; import hudson.slaves.ComputerListener; import hudson.slaves.NodeProperty; @@ -63,8 +66,14 @@ import hudson.util.NamingThreadFactory; import jenkins.model.Jenkins; import jenkins.util.ContextResettingExecutorService; import jenkins.security.MasterToSlaveCallable; +import jenkins.security.NotReallyRoleSensitiveCallable; + +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.DoNotUse; +import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.CmdLineException; +import org.kohsuke.stapler.Stapler; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.QueryParameter; @@ -77,7 +86,9 @@ import org.kohsuke.stapler.export.ExportedBean; import org.kohsuke.args4j.Option; 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; @@ -99,6 +110,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; @@ -164,12 +176,70 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces private volatile String cachedHostName; private volatile boolean hostNameCached; + /** + * @see #getEnvironment() + */ + private volatile EnvVars cachedEnvironment; + + private final WorkspaceList workspaceList = new WorkspaceList(); protected transient List transientActions; protected final Object statusChangeLock = new Object(); + /** + * Keeps track of stack traces to track the tremination requests for this computer. + * + * @since 1.607 + * @see Executor#resetWorkUnit(String) + */ + private transient final List terminatedBy = Collections.synchronizedList(new ArrayList + ()); + + /** + * This method captures the information of a request to terminate a computer instance. Method is public as + * it needs to be called from {@link AbstractCloudSlave} and {@link jenkins.model.Nodes}. In general you should + * not need to call this method directly, however if implementing a custom node type or a different path + * for removing nodes, it may make sense to call this method in order to capture the originating request. + * + * @since 1.607 + */ + public void recordTermination() { + StaplerRequest request = Stapler.getCurrentRequest(); + if (request != null) { + terminatedBy.add(new TerminationRequest( + String.format("Termination requested at %s by %s [id=%d] from HTTP request for %s", + new Date(), + Thread.currentThread(), + Thread.currentThread().getId(), + request.getRequestURL() + ) + )); + } else { + terminatedBy.add(new TerminationRequest( + String.format("Termination requested at %s by %s [id=%d]", + new Date(), + Thread.currentThread(), + Thread.currentThread().getId() + ) + )); + } + } + + /** + * Returns the list of captured termination requests for this Computer. This method is used by {@link Executor} + * to provide details on why a Computer was removed in-between work being scheduled against the {@link Executor} + * and the {@link Executor} starting to execute the task. + * + * @return the (possibly empty) list of termination requests. + * @see Executor#resetWorkUnit(String) + * @since 1.607 + */ + public List getTerminatedBy() { + return new ArrayList(terminatedBy); + } + public Computer(Node node) { setNode(node); } @@ -207,14 +277,25 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces /** * This is where the log from the remote agent goes. * The method also creates a log directory if required. - * @see #relocateOldLogs() + * @see #getLogDir(), #relocateOldLogs() */ - public File getLogFile() { + public @Nonnull File getLogFile() { + return new File(getLogDir(),"slave.log"); + } + + /** + * Directory where rotated slave logs are stored. + * + * The method also creates a log directory if required. + * + * @since 1.613 + */ + protected @Nonnull File getLogDir() { File dir = new File(Jenkins.getInstance().getRootDir(),"logs/slaves/"+nodeName); if (!dir.exists() && !dir.mkdirs()) { LOGGER.severe("Failed to create slave log directory " + dir.getAbsolutePath()); } - return new File(dir,"slave.log"); + return dir; } /** @@ -314,6 +395,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces /** * @deprecated since 2009-01-06. Use {@link #connect(boolean)} */ + @Deprecated public final void launch() { connect(true); } @@ -397,6 +479,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces * @since 1.320 */ public Future disconnect(OfflineCause cause) { + recordTermination(); offlineCause = cause; if (Util.isOverridden(Computer.class,getClass(),"disconnect")) return disconnect(); // legacy subtypes that extend disconnect(). @@ -411,7 +494,9 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces * @deprecated as of 1.320. * Use {@link #disconnect(OfflineCause)} and specify the cause. */ + @Deprecated public Future disconnect() { + recordTermination(); if (Util.isOverridden(Computer.class,getClass(),"disconnect",OfflineCause.class)) // if the subtype already derives disconnect(OfflineCause), delegate to it return disconnect(null); @@ -435,13 +520,12 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces @CLIMethod(name="offline-node") public void cliOffline(@Option(name="-m",usage="Record the note about why you are disconnecting this node") String cause) throws ExecutionException, InterruptedException { checkPermission(DISCONNECT); - setTemporarilyOffline(true,new ByCLI(cause)); + setTemporarilyOffline(true, new ByCLI(cause)); } - @CLIMethod(name="online-node") public void cliOnline() throws ExecutionException, InterruptedException { checkPermission(CONNECT); - setTemporarilyOffline(false,null); + setTemporarilyOffline(false, null); } /** @@ -464,6 +548,15 @@ 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). + * + * @since 1.624 + * @return + * null if the computer is disconnected and therefore we don't know whether it is Unix or not. + */ + public abstract @CheckForNull Boolean isUnix(); + /** * Returns the {@link Node} that this computer represents. * @@ -494,6 +587,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces /** * {@inheritDoc} */ + @Override public void taskAccepted(Executor executor, Queue.Task task) { // dummy implementation } @@ -501,6 +595,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces /** * {@inheritDoc} */ + @Override public void taskCompleted(Executor executor, Queue.Task task, long durationMS) { // dummy implementation } @@ -508,6 +603,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces /** * {@inheritDoc} */ + @Override public void taskCompletedWithProblems(Executor executor, Queue.Task task, long durationMS, Throwable problems) { // dummy implementation } @@ -573,6 +669,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces * accidentally call this method. */ @Exported + @Deprecated public boolean isTemporarilyOffline() { return temporarilyOffline; } @@ -581,6 +678,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces * @deprecated as of 1.320. * Use {@link #setTemporarilyOffline(boolean, OfflineCause)} */ + @Deprecated public void setTemporarilyOffline(boolean temporarilyOffline) { setTemporarilyOffline(temporarilyOffline,null); } @@ -600,7 +698,6 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces if (node != null) { node.setTemporaryOfflineCause(offlineCause); } - Jenkins.getInstance().getQueue().scheduleMaintenance(); synchronized (statusChangeLock) { statusChangeLock.notifyAll(); } @@ -691,6 +788,26 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces * @see #onRemoved() */ protected void kill() { + // On most code paths, this should already be zero, and thus this next call becomes a no-op... and more + // importantly it will not acquire a lock on the Queue... not that the lock is bad, more that the lock + // may delay unnecessarily + setNumExecutors(0); + } + + /** + * Called by {@link Jenkins#updateComputerList()} to notify {@link Computer} that it will be discarded. + * + *

+ * Note that at this point {@link #getNode()} returns null. + * + *

+ * Note that the Queue lock is already held when this method is called. + * + * @see #onRemoved() + */ + @Restricted(NoExternalUse.class) + @GuardedBy("hudson.model.Queue.lock") + /*package*/ void inflictMortalWound() { setNumExecutors(0); } @@ -801,6 +918,32 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces return new ArrayList(oneOffExecutors); } + /** + * Used to render the list of executors. + * @return a snapshot of the executor display information + * @since 1.607 + */ + @Restricted(NoExternalUse.class) + public List getDisplayExecutors() { + // The size may change while we are populating, but let's start with a reasonable guess to minimize resizing + List result = new ArrayList(executors.size()+oneOffExecutors.size()); + int index = 0; + for (Executor e: executors) { + if (e.isDisplayCell()) { + result.add(new DisplayExecutor(Integer.toString(index + 1), String.format("executors/%d", index), e)); + } + index++; + } + index = 0; + for (OneOffExecutor e: oneOffExecutors) { + if (e.isDisplayCell()) { + result.add(new DisplayExecutor("", String.format("oneOffExecutors/%d", index), e)); + } + index++; + } + return result; + } + /** * Returns true if all the executors of this computer are idle. */ @@ -860,18 +1003,30 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces /** * Called by {@link Executor} to kill excessive executors from this computer. */ - /*package*/ synchronized void removeExecutor(Executor e) { - executors.remove(e); - addNewExecutorIfNecessary(); - if(!isAlive()) - { - AbstractCIBase ciBase = Jenkins.getInstance(); - ciBase.removeComputer(this); + /*package*/ void removeExecutor(final Executor e) { + final Runnable task = new Runnable() { + @Override + public void run() { + synchronized (Computer.this) { + executors.remove(e); + addNewExecutorIfNecessary(); + if (!isAlive()) { + AbstractCIBase ciBase = Jenkins.getInstance(); + if (ciBase != null) { + 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)); } } /** - * Returns true if any of the executors are functioning. + * Returns true if any of the executors are {@linkplain Executor#isActive active}. * * Note that if an executor dies, we'll leave it in {@link #executors} until * the administrator yanks it out, so that we can see why it died. @@ -887,11 +1042,17 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces /** * Interrupt all {@link Executor}s. + * Called from {@link Jenkins#cleanUp}. */ public void interrupt() { - for (Executor e : executors) { - e.interrupt(); - } + Queue.withLock(new Runnable() { + @Override + public void run() { + for (Executor e : executors) { + e.interruptForShutdown(); + } + } + }); } public String getSearchUrl() { @@ -930,16 +1091,24 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces * @deprecated as of 1.292 * Use {@link #getEnvironment()} instead. */ + @Deprecated public Map getEnvVars() throws IOException, InterruptedException { return getEnvironment(); } /** - * Gets the environment variables of the JVM on this computer. + * Returns cached environment variables (copy to prevent modification) for the JVM on this computer. * If this is the master, it returns the system property of the master computer. */ public EnvVars getEnvironment() throws IOException, InterruptedException { - return EnvVars.getRemote(getChannel()); + EnvVars cachedEnvironment = this.cachedEnvironment; + if (cachedEnvironment != null) { + return new EnvVars(cachedEnvironment); + } + + cachedEnvironment = EnvVars.getRemote(getChannel()); + this.cachedEnvironment = cachedEnvironment; + return new EnvVars(cachedEnvironment); } /** @@ -1022,11 +1191,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(); @@ -1034,7 +1203,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); } } @@ -1058,27 +1230,38 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces } private static class ListPossibleNames extends MasterToSlaveCallable,IOException> { + /** + * In the normal case we would use {@link Computer} as the logger's name, however to + * do that we would have to send the {@link Computer} class over to the remote classloader + * and then it would need to be loaded, which pulls in {@link Jenkins} and loads that + * and then that fails to load as you are not supposed to do that. Another option + * would be to export the logger over remoting, with increased complexity as a result. + * Instead we just use a loger based on this class name and prevent any references to + * other classes from being transferred over remoting. + */ + 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()); } } @@ -1107,12 +1290,13 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces public void doRssAll( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { rss(req, rsp, " all builds", getBuilds()); } - public void doRssFailed( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { + + public void doRssFailed(StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { rss(req, rsp, " failed builds", getBuilds().failureOnly()); } private void rss(StaplerRequest req, StaplerResponse rsp, String suffix, RunList runs) throws IOException, ServletException { - RSS.forwardToRss(getDisplayName()+ suffix, getUrl(), - runs.newBuilds(), Run.FEED_ADAPTER, req, rsp ); + RSS.forwardToRss(getDisplayName() + suffix, getUrl(), + runs.newBuilds(), Run.FEED_ADAPTER, req, rsp); } @RequirePOST @@ -1190,7 +1374,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces _doScript(req, rsp, "_scriptText.jelly"); } - protected void _doScript( StaplerRequest req, StaplerResponse rsp, String view) throws IOException, ServletException { + protected void _doScript(StaplerRequest req, StaplerResponse rsp, String view) throws IOException, ServletException { Jenkins._doScript(req, rsp, req.getView(this, view), getChannel(), getACL()); } @@ -1201,13 +1385,19 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces public void doConfigSubmit( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException, FormException { checkPermission(CONFIGURE); - String name = Util.fixEmptyAndTrim(req.getSubmittedForm().getString("name")); - Jenkins.checkGoodName(name); + String proposedName = Util.fixEmptyAndTrim(req.getSubmittedForm().getString("name")); + Jenkins.checkGoodName(proposedName); Node node = getNode(); if (node == null) { throw new ServletException("No such node " + nodeName); } + + if ((!proposedName.equals(nodeName)) + && Jenkins.getActiveInstance().getNode(proposedName) != null) { + throw new FormException(Messages.ComputerSet_SlaveAlreadyExists(proposedName), "name"); + } + Node result = node.reconfigure(req, req.getSubmittedForm()); replaceBy(result); @@ -1246,21 +1436,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 NotReallyRoleSensitiveCallable() { + 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); - } + }); } /** @@ -1277,7 +1469,6 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces /** * Really deletes the slave. */ - @CLIMethod(name="delete-node") @RequirePOST public HttpResponse doDoDelete() throws IOException { checkPermission(DELETE); @@ -1314,7 +1505,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces * Handles incremental log. */ public void doProgressiveLog( StaplerRequest req, StaplerResponse rsp) throws IOException { - getLogText().doProgressText(req,rsp); + getLogText().doProgressText(req, rsp); } /** @@ -1387,8 +1578,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()}); @@ -1399,6 +1590,110 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces } } + /** + * A value class to provide a consistent snapshot view of the state of an executor to avoid race conditions + * during rendering of the executors list. + * + * @since 1.607 + */ + @Restricted(NoExternalUse.class) + public static class DisplayExecutor implements ModelObject { + + @Nonnull + private final String displayName; + @Nonnull + private final String url; + @Nonnull + private final Executor executor; + + public DisplayExecutor(@Nonnull String displayName, @Nonnull String url, @Nonnull Executor executor) { + this.displayName = displayName; + this.url = url; + this.executor = executor; + } + + @Override + @Nonnull + public String getDisplayName() { + return displayName; + } + + @Nonnull + public String getUrl() { + return url; + } + + @Nonnull + public Executor getExecutor() { + return executor; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("DisplayExecutor{"); + sb.append("displayName='").append(displayName).append('\''); + sb.append(", url='").append(url).append('\''); + sb.append(", executor=").append(executor); + sb.append('}'); + return sb.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + DisplayExecutor that = (DisplayExecutor) o; + + if (!executor.equals(that.executor)) { + return false; + } + + return true; + } + + @Extension(ordinal = Double.MAX_VALUE) + @Restricted(DoNotUse.class) + public static class InternalComputerListener extends ComputerListener { + @Override + public void onOnline(Computer c, TaskListener listener) throws IOException, InterruptedException { + c.cachedEnvironment = null; + } + } + + @Override + public int hashCode() { + return executor.hashCode(); + } + } + + /** + * Used to trace requests to terminate a computer. + * + * @since 1.607 + */ + public static class TerminationRequest extends RuntimeException { + private final long when; + public TerminationRequest(String message) { + super(message); + this.when = System.currentTimeMillis(); + } + + /** + * Returns the when the termination request was created. + * + * @return the difference, measured in milliseconds, between + * the time of the termination request and midnight, January 1, 1970 UTC. + */ + public long getWhen() { + return when; + } + } + public static final PermissionGroup PERMISSIONS = new PermissionGroup(Computer.class,Messages._Computer_Permissions_Title()); public static final Permission CONFIGURE = new Permission(PERMISSIONS,"Configure", Messages._Computer_ConfigurePermission_Description(), Permission.CONFIGURE, PermissionScope.COMPUTER); /** diff --git a/core/src/main/java/hudson/model/ComputerPanelBox.java b/core/src/main/java/hudson/model/ComputerPanelBox.java index f7def3d04f2321cd73a179015d06508c1c593aff..94ee1aaa3ca938aa8412999f65cbae7c2cbf7337 100644 --- a/core/src/main/java/hudson/model/ComputerPanelBox.java +++ b/core/src/main/java/hudson/model/ComputerPanelBox.java @@ -4,7 +4,6 @@ import hudson.ExtensionList; import hudson.ExtensionPoint; import java.util.ArrayList; import java.util.List; -import jenkins.model.Jenkins; /** * Adds box rendered in the computer side panel. diff --git a/core/src/main/java/hudson/model/ComputerPinger.java b/core/src/main/java/hudson/model/ComputerPinger.java index d924ab63b4fea091b3eeccd7033044f0addb2016..ecf81abceb7a430c81e1bfa61dccd8ce413652cd 100644 --- a/core/src/main/java/hudson/model/ComputerPinger.java +++ b/core/src/main/java/hudson/model/ComputerPinger.java @@ -3,7 +3,6 @@ package hudson.model; import hudson.Extension; import hudson.ExtensionList; import hudson.ExtensionPoint; -import jenkins.model.Jenkins; import java.io.IOException; import java.net.InetAddress; diff --git a/core/src/main/java/hudson/model/ComputerSet.java b/core/src/main/java/hudson/model/ComputerSet.java index 0502c64329059df41e606c956aa8227b3b564e6c..f887167058d74c427d43a886808218d9888b0b53 100644 --- a/core/src/main/java/hudson/model/ComputerSet.java +++ b/core/src/main/java/hudson/model/ComputerSet.java @@ -95,6 +95,7 @@ public final class ComputerSet extends AbstractModelObject implements Describabl * @deprecated as of 1.301 * Use {@link #getMonitors()}. */ + @Deprecated public static List get_monitors() { return monitors.toList(); } @@ -290,6 +291,7 @@ public final class ComputerSet extends AbstractModelObject implements Describabl JSONObject formData = req.getSubmittedForm(); formData.put("name", fixedName); + // TODO type is probably NodeDescriptor.id but confirm Node result = NodeDescriptor.all().find(type).newInstance(req, formData); app.addNode(result); @@ -378,11 +380,6 @@ public final class ComputerSet extends AbstractModelObject implements Describabl @Extension public static class DescriptorImpl 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/DependecyDeclarer.java b/core/src/main/java/hudson/model/DependecyDeclarer.java index 2693515053fb9df67402c24e32a3a0bf7fd27f05..5cd1fe640091f490fad89dd2ed6a88e98a25c161 100644 --- a/core/src/main/java/hudson/model/DependecyDeclarer.java +++ b/core/src/main/java/hudson/model/DependecyDeclarer.java @@ -30,4 +30,5 @@ import jenkins.model.DependencyDeclarer; * @deprecated Use {@link DependencyDeclarer} instead. * @since 1.160 */ +@Deprecated public interface DependecyDeclarer extends DependencyDeclarer {} diff --git a/core/src/main/java/hudson/model/Descriptor.java b/core/src/main/java/hudson/model/Descriptor.java index 2b5bcef0cf608b16b8759371d0929c48406e61be..2160d27b177c14139806b6aa44e43264c1e2e8c1 100644 --- a/core/src/main/java/hudson/model/Descriptor.java +++ b/core/src/main/java/hudson/model/Descriptor.java @@ -72,6 +72,7 @@ import java.lang.reflect.Type; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.beans.Introspector; +import java.util.IdentityHashMap; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; @@ -293,8 +294,15 @@ 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}. */ - public abstract String getDisplayName(); + @Nonnull + public String getDisplayName() { + return clazz.getSimpleName(); + } /** * Uniquely identifies this {@link Descriptor} among all the other {@link Descriptor}s. @@ -366,6 +374,7 @@ public abstract class Descriptor> implements Saveable { * @deprecated since 1.528 * Use {@link #getCheckMethod(String)} */ + @Deprecated public String getCheckUrl(String fieldName) { return getCheckMethod(fieldName).toCheckUrl(); } @@ -512,6 +521,7 @@ public abstract class Descriptor> implements Saveable { * Implement {@link #newInstance(StaplerRequest, JSONObject)} method instead. * Deprecated as of 1.145. */ + @Deprecated public T newInstance(StaplerRequest req) throws FormException { throw new UnsupportedOperationException(getClass()+" should implement newInstance(StaplerRequest,JSONObject)"); } @@ -550,7 +560,7 @@ public abstract class Descriptor> implements Saveable { * Signals a problem in the submitted form. * @since 1.145 */ - public T newInstance(StaplerRequest req, JSONObject formData) throws FormException { + public T newInstance(@CheckForNull StaplerRequest req, @Nonnull JSONObject formData) throws FormException { try { Method m = getClass().getMethod("newInstance", StaplerRequest.class); @@ -565,7 +575,20 @@ public abstract class Descriptor> implements Saveable { } // new behavior as of 1.206 - return verifyNewInstance(req.bindJSON(clazz,formData)); + BindInterceptor oldInterceptor = req.getBindInterceptor(); + try { + NewInstanceBindInterceptor interceptor; + if (oldInterceptor instanceof NewInstanceBindInterceptor) { + interceptor = (NewInstanceBindInterceptor) oldInterceptor; + } else { + interceptor = new NewInstanceBindInterceptor(oldInterceptor); + req.setBindInterceptor(interceptor); + } + interceptor.processed.put(formData, true); + return verifyNewInstance(req.bindJSON(clazz, formData)); + } finally { + req.setBindInterceptor(oldInterceptor); + } } } catch (NoSuchMethodException e) { throw new AssertionError(e); // impossible @@ -578,6 +601,78 @@ public abstract class Descriptor> implements Saveable { } } + /** + * Ensures that calls to {@link StaplerRequest#bindJSON(Class, JSONObject)} from {@link #newInstance(StaplerRequest, JSONObject)} recurse properly. + * {@code doConfigSubmit}-like methods will wind up calling {@code newInstance} directly + * or via {@link #newInstancesFromHeteroList(StaplerRequest, Object, Collection)}, + * which consult any custom {@code newInstance} overrides for top-level {@link Describable} objects. + * But for nested describable objects Stapler would know nothing about {@code newInstance} without this trick. + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + private static class NewInstanceBindInterceptor extends BindInterceptor { + + private final BindInterceptor oldInterceptor; + private final Map processed = new IdentityHashMap<>(); + + NewInstanceBindInterceptor(BindInterceptor oldInterceptor) { + LOGGER.log(Level.FINER, "new interceptor delegating to {0}", oldInterceptor); + this.oldInterceptor = oldInterceptor; + } + + private boolean isApplicable(Class type, JSONObject json) { + if (Modifier.isAbstract(type.getModifiers())) { + LOGGER.log(Level.FINER, "ignoring abstract {0} {1}", new Object[] {type.getName(), json}); + return false; + } + if (!Describable.class.isAssignableFrom(type)) { + LOGGER.log(Level.FINER, "ignoring non-Describable {0} {1}", new Object[] {type.getName(), json}); + return false; + } + if (Boolean.TRUE.equals(processed.put(json, true))) { + LOGGER.log(Level.FINER, "already processed {0} {1}", new Object[] {type.getName(), json}); + return false; + } + return true; + } + + @Override + public Object instantiate(Class actualType, JSONObject json) { + if (isApplicable(actualType, json)) { + LOGGER.log(Level.FINE, "switching to newInstance {0} {1}", new Object[] {actualType.getName(), json}); + try { + return Jenkins.getActiveInstance().getDescriptor(actualType).newInstance(Stapler.getCurrentRequest(), json); + } catch (Exception x) { + LOGGER.log(Level.WARNING, "falling back to default instantiation " + actualType.getName() + " " + json, x); + // If nested objects are not using newInstance, bindJSON will wind up throwing the same exception anyway, + // so logging above will result in a duplicated stack trace. + // However if they *are* then this is the only way to find errors in that newInstance. + // Normally oldInterceptor.instantiate will just return DEFAULT, not actually do anything, + // so we cannot try calling the default instantiation and then decide which problem to report. + } + } + return oldInterceptor.instantiate(actualType, json); + } + + @Override + public Object onConvert(Type targetType, Class targetTypeErasure, Object jsonSource) { + if (jsonSource instanceof JSONObject) { + JSONObject json = (JSONObject) jsonSource; + if (isApplicable(targetTypeErasure, json)) { + LOGGER.log(Level.FINE, "switching to newInstance {0} {1}", new Object[] {targetTypeErasure.getName(), json}); + try { + return Jenkins.getActiveInstance().getDescriptor(targetTypeErasure).newInstance(Stapler.getCurrentRequest(), json); + } catch (Exception x) { + LOGGER.log(Level.WARNING, "falling back to default instantiation " + targetTypeErasure.getName() + " " + json, x); + } + } + } else { + LOGGER.log(Level.FINER, "ignoring non-object {0}", jsonSource); + } + return oldInterceptor.onConvert(targetType, targetTypeErasure, jsonSource); + } + + } + /** * Look out for a typical error a plugin developer makes. * See http://hudson.361315.n4.nabble.com/Help-Hint-needed-Post-build-action-doesn-t-stay-activated-td2308833.html @@ -684,6 +779,7 @@ public abstract class Descriptor> implements Saveable { * @deprecated * As of 1.239, use {@link #configure(StaplerRequest, JSONObject)}. */ + @Deprecated public boolean configure( StaplerRequest req ) throws FormException { return true; } @@ -909,14 +1005,35 @@ public abstract class Descriptor> implements Saveable { if (formData!=null) { for (Object o : JSONArray.fromObject(formData)) { JSONObject jo = (JSONObject)o; - String kind = jo.optString("$class", null); - if (kind == null) { - // Legacy: Remove once plugins have been staged onto $class - kind = jo.getString("kind"); + Descriptor d = null; + // 'kind' and '$class' are mutually exclusive (see class-entry.jelly), but to be more lenient on the reader side, + // we check them both anyway. 'kind' (which maps to ID) is more unique than '$class', which can have multiple matching + // Descriptors, so we prefer 'kind' if it's present. + String kind = jo.optString("kind", null); + if (kind != null) { + // Only applies when Descriptor.getId is overridden. + // Note that kind is only supported here, + // *not* inside the StaplerRequest.bindJSON which is normally called by newInstance + // (since Descriptor.newInstance is not itself available to Stapler). + // If you merely override getId for some reason, but use @DataBoundConstructor on your Describable, + // there is no problem; but you can only rely on newInstance being called at top level. + d = findById(descriptors, kind); + } + if (d == null) { + kind = jo.optString("$class"); + if (kind != null) { // else we will fall through to the warning + // This is the normal case. + d = findByDescribableClassName(descriptors, kind); + if (d == null) { + // Deprecated system where stapler-class was the Descriptor class name (rather than Describable class name). + d = findByClassName(descriptors, kind); + } + } } - Descriptor d = find(descriptors, kind); if (d != null) { items.add(d.newInstance(req, jo)); + } else { + LOGGER.log(Level.WARNING, "Received unexpected form data element: {0}", jo); } } } @@ -925,22 +1042,58 @@ public abstract class Descriptor> implements Saveable { } /** - * Finds a descriptor from a collection by its class name. + * Finds a descriptor from a collection by its ID. + * @param id should match {@link #getId} + * @since 1.610 + */ + public static @CheckForNull T findById(Collection list, String id) { + for (T d : list) { + if(d.getId().equals(id)) + return d; + } + return null; + } + + /** + * Finds a descriptor from a collection by the class name of the {@link Descriptor}. + * This is useless as of the introduction of {@link #getId} and so only very old compatibility code needs it. */ - public static @CheckForNull T find(Collection list, String className) { + private static @CheckForNull T findByClassName(Collection list, String className) { for (T d : list) { if(d.getClass().getName().equals(className)) return d; } - // Since we introduced Descriptor.getId(), it is a preferred method of identifying descriptor by a string. - // To make that migration easier without breaking compatibility, let's also match up with the id. + return null; + } + + /** + * Finds a descriptor from a collection by the class name of the {@link Describable} it describes. + * @param className should match {@link Class#getName} of a {@link #clazz} + * @since 1.610 + */ + public static @CheckForNull T findByDescribableClassName(Collection list, String className) { for (T d : list) { - if(d.getId().equals(className)) + if(d.clazz.getName().equals(className)) return d; } return null; } + /** + * Finds a descriptor from a collection by its class name or ID. + * @deprecated choose between {@link #findById} or {@link #findByDescribableClassName} + */ + public static @CheckForNull T find(Collection list, String string) { + T d = findByClassName(list, string); + if (d != null) { + return d; + } + return findById(list, string); + } + + /** + * @deprecated choose between {@link #findById} or {@link #findByDescribableClassName} + */ public static @CheckForNull Descriptor find(String className) { return find(ExtensionList.lookup(Descriptor.class),className); } diff --git a/core/src/main/java/hudson/model/DescriptorVisibilityFilter.java b/core/src/main/java/hudson/model/DescriptorVisibilityFilter.java index 0a435c6fda0777b070e0b3b24814767bbd800fe1..bd5cbfd36ebd0649c0f115a50c60946a59e3eb2f 100644 --- a/core/src/main/java/hudson/model/DescriptorVisibilityFilter.java +++ b/core/src/main/java/hudson/model/DescriptorVisibilityFilter.java @@ -4,7 +4,6 @@ import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.scm.SCMDescriptor; import jenkins.ExtensionFilter; -import jenkins.model.Jenkins; import java.util.ArrayList; import java.util.List; diff --git a/core/src/main/java/hudson/model/DirectlyModifiableView.java b/core/src/main/java/hudson/model/DirectlyModifiableView.java index bdc651341b59219520c6ebe8baaa277aab34aa52..b799d2bd9e978d97b06b21f62aca9790deec7b90 100644 --- a/core/src/main/java/hudson/model/DirectlyModifiableView.java +++ b/core/src/main/java/hudson/model/DirectlyModifiableView.java @@ -23,7 +23,6 @@ */ package hudson.model; -import hudson.util.HttpResponses; import java.io.IOException; diff --git a/core/src/main/java/hudson/model/DirectoryBrowserSupport.java b/core/src/main/java/hudson/model/DirectoryBrowserSupport.java index cf803fcdc5f8e4648a7aaef5779818024eb15609..8be60142d09d60c29fabe4e57881e50b611bfcf8 100644 --- a/core/src/main/java/hudson/model/DirectoryBrowserSupport.java +++ b/core/src/main/java/hudson/model/DirectoryBrowserSupport.java @@ -47,6 +47,8 @@ import jenkins.util.VirtualFile; import org.apache.commons.io.IOUtils; import org.apache.tools.zip.ZipEntry; import org.apache.tools.zip.ZipOutputStream; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; @@ -75,6 +77,7 @@ public final class DirectoryBrowserSupport implements HttpResponse { * @deprecated as of 1.297 * Use {@link #DirectoryBrowserSupport(ModelObject, FilePath, String, String, boolean)} */ + @Deprecated public DirectoryBrowserSupport(ModelObject owner, String title) { this(owner, (VirtualFile) null, title, null, false); } @@ -147,6 +150,7 @@ public final class DirectoryBrowserSupport implements HttpResponse { * Instead of calling this method explicitly, just return the {@link DirectoryBrowserSupport} object * from the {@code doXYZ} method and let Stapler generate a response for you. */ + @Deprecated public void serveFile(StaplerRequest req, StaplerResponse rsp, FilePath root, String icon, boolean serveDirIndex) throws IOException, ServletException, InterruptedException { serveFile(req, rsp, root.toVirtualFile(), icon, serveDirIndex); } @@ -307,6 +311,17 @@ public final class DirectoryBrowserSupport implements HttpResponse { // pseudo file name to let the Stapler set text/plain rsp.serveFile(req, in, lastModified, -1, length, "plain.txt"); } else { + String csp = System.getProperty(DirectoryBrowserSupport.class.getName() + ".CSP"); + if (csp == null) { + // default value unless overridden with system property + csp = DEFAULT_CSP_VALUE; + } + if (!csp.trim().equals("")) { + // allow users to prevent sending this header by setting empty system property + for (String header : new String[]{"Content-Security-Policy", "X-WebKit-CSP", "X-Content-Security-Policy"}) { + rsp.setHeader(header, csp); + } + } rsp.serveFile(req, in, lastModified, -1, length, baseFile.getName() ); } } @@ -574,4 +589,7 @@ public final class DirectoryBrowserSupport implements HttpResponse { private static final Logger LOGGER = Logger.getLogger(DirectoryBrowserSupport.class.getName()); + + @Restricted(NoExternalUse.class) + public static final String DEFAULT_CSP_VALUE = "sandbox; default-src 'none'; img-src 'self'; style-src 'self';"; } diff --git a/core/src/main/java/hudson/model/DownloadService.java b/core/src/main/java/hudson/model/DownloadService.java index 707491dbc18939c70ec4f5d107e1b4f0c9625436..0bbf7a87542a48647cf243c06e5781f39fedd909 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; @@ -35,8 +38,12 @@ import static hudson.util.TimeUnit2.DAYS; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Field; import java.net.URL; import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; import java.util.logging.Logger; import jenkins.model.DownloadSettings; import jenkins.model.Jenkins; @@ -66,7 +73,7 @@ public class DownloadService extends PageDecorator { * Builds up an HTML fragment that starts all the download jobs. */ public String generateFragment() { - if (!DownloadSettings.get().isUseBrowser()) { + if (!DownloadSettings.usePostBack()) { return ""; } if (neverUpdate) return ""; @@ -170,6 +177,69 @@ public class DownloadService extends PageDecorator { } } + /** + * Loads JSON from a JSON-with-{@code postMessage} URL. + * @param src a URL to a JSON HTML file (typically including {@code id} and {@code version} query parameters) + * @return the embedded JSON text + * @throws IOException if either downloading or processing failed + */ + @Restricted(NoExternalUse.class) + public static String loadJSONHTML(URL src) throws IOException { + InputStream is = ProxyConfiguration.open(src).getInputStream(); + try { + String jsonp = IOUtils.toString(is, "UTF-8"); + String preamble = "window.parent.postMessage(JSON.stringify("; + int start = jsonp.indexOf(preamble); + int end = jsonp.lastIndexOf("),'*');"); + if (start >= 0 && end > start) { + return jsonp.substring(start + preamble.length(), end).trim(); + } else { + throw new IOException("Could not find JSON in " + src); + } + } finally { + is.close(); + } + } + + /** + * 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. * @@ -234,6 +304,24 @@ public class DownloadService extends PageDecorator { return Jenkins.getInstance().getUpdateCenter().getDefaultBaseUrl()+"updates/"+url; } + /** + * URLs to download from. + */ + public List getUrls() { + List updateSites = new ArrayList(); + for (UpdateSite site : Jenkins.getActiveInstance().getUpdateCenter().getSiteList()) { + String siteUrl = site.getUrl(); + int baseUrlEnd = siteUrl.indexOf("update-center.json"); + if (baseUrlEnd != -1) { + String siteBaseUrl = siteUrl.substring(0, baseUrlEnd); + updateSites.add(siteBaseUrl + "updates/" + url); + } else { + LOGGER.log(Level.WARNING, "Url {0} does not look like an update center:", siteUrl); + } + } + return updateSites; + } + /** * How often do we retrieve the new image? * @@ -283,9 +371,7 @@ public class DownloadService extends PageDecorator { * This is where the browser sends us the data. */ public void doPostBack(StaplerRequest req, StaplerResponse rsp) throws IOException { - if (!DownloadSettings.get().isUseBrowser()) { - throw new IOException("not allowed"); - } + DownloadSettings.checkPostBackAccess(); long dataTimestamp = System.currentTimeMillis(); due = dataTimestamp+getInterval(); // success or fail, don't try too often @@ -299,15 +385,6 @@ public class DownloadService extends PageDecorator { } private FormValidation load(String json, long dataTimestamp) throws IOException { - JSONObject o = JSONObject.fromObject(json); - - if (signatureCheck) { - FormValidation e = new JSONSignatureValidator("downloadable '"+id+"'").verifySignature(o); - if (e.kind!= Kind.OK) { - return e; - } - } - TextFile df = getDataFile(); df.write(json); df.file.setLastModified(dataTimestamp); @@ -317,7 +394,72 @@ public class DownloadService extends PageDecorator { @Restricted(NoExternalUse.class) public FormValidation updateNow() throws IOException { - return load(loadJSON(new URL(getUrl() + "?id=" + URLEncoder.encode(getId(), "UTF-8") + "&version=" + URLEncoder.encode(Jenkins.VERSION, "UTF-8"))), System.currentTimeMillis()); + List jsonList = new ArrayList<>(); + for (String site : getUrls()) { + String jsonString; + try { + jsonString = loadJSONHTML(new URL(site + ".html?id=" + URLEncoder.encode(getId(), "UTF-8") + "&version=" + URLEncoder.encode(Jenkins.VERSION, "UTF-8"))); + } catch (Exception e) { + LOGGER.log(Level.WARNING, "Could not load json from " + site, e ); + continue; + } + JSONObject o = JSONObject.fromObject(jsonString); + if (signatureCheck) { + FormValidation e = new JSONSignatureValidator("downloadable '"+id+"'").verifySignature(o); + if (e.kind!= Kind.OK) { + continue; + } + } + jsonList.add(o); + } + if (jsonList.size() == 0) { + return FormValidation.warning("None of the Update Sites passed the signature check"); + } + JSONObject reducedJson = reduce(jsonList); + return load(reducedJson.toString(), System.currentTimeMillis()); + } + + /** + * Function that takes multiple JSONObjects and returns a single one. + * @param jsonList to be processed + * @return a single JSONObject + */ + public JSONObject reduce(List jsonList) { + return jsonList.get(0); + } + + /** + * check if the list of update center entries has duplicates + * @param genericList list of entries coming from multiple update centers + * @param comparator the unique ID of an entry + * @param the generic class + * @return true if the list has duplicates, false otherwise + */ + public static boolean hasDuplicates (List genericList, String comparator) { + if (genericList.isEmpty()) { + return false; + } + Field field; + try { + field = genericList.get(0).getClass().getDeclaredField(comparator); + } catch (NoSuchFieldException e) { + LOGGER.warning("comparator: " + comparator + "does not exist for " + genericList.get(0).getClass() + ", " + e); + return false; + } + for (int i = 0; i < genericList.size(); i ++ ) { + T data1 = genericList.get(i); + for (int j = i + 1; j < genericList.size(); j ++ ) { + T data2 = genericList.get(j); + try { + if (field.get(data1).equals(field.get(data2))) { + return true; + } + } catch (IllegalAccessException e) { + LOGGER.warning("could not access field: " + comparator + ", " + e); + } + } + } + return false; } /** diff --git a/core/src/main/java/hudson/model/EnvironmentContributor.java b/core/src/main/java/hudson/model/EnvironmentContributor.java index d6d630bcb56c47eab192fed8f09a078255757301..77ea159b309b3efa7fcd55a81b811ffaf8e5f4b3 100644 --- a/core/src/main/java/hudson/model/EnvironmentContributor.java +++ b/core/src/main/java/hudson/model/EnvironmentContributor.java @@ -28,7 +28,6 @@ import hudson.Extension; import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.scm.SCM; -import jenkins.model.Jenkins; import java.io.IOException; import javax.annotation.Nonnull; diff --git a/core/src/main/java/hudson/model/Executor.java b/core/src/main/java/hudson/model/Executor.java index 574cfb748608382d4c1b4121baa6b3712482b75b..817166c60ef6e7e8db54252d58cb5532014d4315 100644 --- a/core/src/main/java/hudson/model/Executor.java +++ b/core/src/main/java/hudson/model/Executor.java @@ -46,34 +46,45 @@ import org.kohsuke.stapler.export.Exported; import org.kohsuke.stapler.export.ExportedBean; import org.kohsuke.stapler.interceptor.RequirePOST; +import javax.annotation.concurrent.GuardedBy; import javax.servlet.ServletException; import java.io.IOException; +import java.io.PrintWriter; +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; +import java.util.concurrent.locks.ReentrantReadWriteLock; 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; +import jenkins.model.queue.AsynchronousExecution; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; /** * Thread that executes builds. * Since 1.536, {@link Executor}s start threads on-demand. - * The entire logic should use {@link #isActive()} instead of {@link #isAlive()} - * in order to check if the {@link Executor} it ready to take tasks. + *

Callers should use {@link #isActive()} instead of {@link #isAlive()}. * @author Kohsuke Kawaguchi */ @ExportedBean public class Executor extends Thread implements ModelObject { protected final @Nonnull Computer owner; private final Queue queue; + private final ReadWriteLock lock = new ReentrantReadWriteLock(); + @GuardedBy("lock") private long startTime; /** * Used to track when a job was last executed. @@ -87,29 +98,41 @@ public class Executor extends Thread implements ModelObject { /** * {@link hudson.model.Queue.Executable} being executed right now, or null if the executor is idle. */ - private volatile Queue.Executable executable; + @GuardedBy("lock") + private Queue.Executable executable; + + /** + * Used to mark that the execution is continuing asynchronously even though {@link Executor} as {@link Thread} + * has finished. + */ + @GuardedBy("lock") + private AsynchronousExecution asynchronousExecution; /** * When {@link Queue} allocates a work for this executor, this field is set * and the executor is {@linkplain Thread#start() started}. */ - private volatile WorkUnit workUnit; + @GuardedBy("lock") + private WorkUnit workUnit; private Throwable causeOfDeath; private boolean induceDeath; - private volatile boolean started; + @GuardedBy("lock") + private boolean started; /** * When the executor is interrupted, we allow the code that interrupted the thread to override the * result code it prefers. */ + @GuardedBy("lock") private Result interruptStatus; /** * Cause of interruption. Access needs to be synchronized. */ + @GuardedBy("lock") private final List causes = new Vector(); public Executor(@Nonnull Computer owner, int n) { @@ -121,9 +144,39 @@ 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() { + interrupt(Result.ABORTED, true); + } /** * Interrupt the execution, * but instead of marking the build as aborted, mark it as specified result. @@ -131,13 +184,17 @@ public class Executor extends Thread implements ModelObject { * @since 1.417 */ public void interrupt(Result result) { + interrupt(result, false); + } + + private void interrupt(Result result, boolean forShutdown) { Authentication a = Jenkins.getAuthentication(); if (a == ACL.SYSTEM) - interrupt(result, new CauseOfInterruption[0]); + interrupt(result, forShutdown, new CauseOfInterruption[0]); else { // worth recording who did it // avoid using User.get() to avoid deadlock. - interrupt(result, new UserInterruption(a.getName())); + interrupt(result, forShutdown, new UserInterruption(a.getName())); } } @@ -145,31 +202,55 @@ public class Executor extends Thread implements ModelObject { * Interrupt the execution. Mark the cause and the status accordingly. */ public void interrupt(Result result, CauseOfInterruption... causes) { + interrupt(result, false, causes); + } + + private void interrupt(Result result, boolean forShutdown, CauseOfInterruption... causes) { if (LOGGER.isLoggable(FINE)) LOGGER.log(FINE, String.format("%s is interrupted(%s): %s", getDisplayName(), result, Util.join(Arrays.asList(causes),",")), new InterruptedException()); - synchronized (this) { + lock.writeLock().lock(); + try { if (!started) { // not yet started, so simply dispose this owner.removeExecutor(this); return; } - } - interruptStatus = result; - synchronized (this.causes) { + interruptStatus = result; + for (CauseOfInterruption c : causes) { if (!this.causes.contains(c)) this.causes.add(c); } + if (asynchronousExecution != null) { + asynchronousExecution.interrupt(forShutdown); + } else { + super.interrupt(); + } + } finally { + lock.writeLock().unlock(); } - super.interrupt(); } public Result abortResult() { - Result r = interruptStatus; - if (r==null) r = Result.ABORTED; // this is when we programmatically throw InterruptedException instead of calling the interrupt method. - return r; + // 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 = + Result.ABORTED; // this is when we programmatically throw InterruptedException instead of calling the interrupt method. + + return r; + } finally { + lock.writeLock().unlock(); + } } /** @@ -180,11 +261,14 @@ public class Executor extends Thread implements ModelObject { public void recordCauseOfInterruption(Run build, TaskListener listener) { List r; - // atomically get&clear causes, and minimize the lock. - synchronized (causes) { + // atomically get&clear causes. + lock.writeLock().lock(); + try { if (causes.isEmpty()) return; r = new ArrayList(causes); causes.clear(); + } finally { + lock.writeLock().unlock(); } build.addAction(new InterruptedBuildAction(r)); @@ -192,9 +276,64 @@ public class Executor extends Thread implements ModelObject { c.print(listener); } + /** + * There are some cases where an executor is started but the node is removed or goes off-line before we are ready + * to start executing the assigned work unit. This method is called to clear the assigned work unit so that + * the {@link Queue#maintain()} method can return the item to the buildable state. + * + * Note: once we create the {@link Executable} we cannot unwind the state and the build will have to end up being + * marked as a failure. + */ + private void resetWorkUnit(String reason) { + StringWriter writer = new StringWriter(); + PrintWriter pw = new PrintWriter(writer); + try { + pw.printf("%s grabbed %s from queue but %s %s. ", getName(), workUnit, owner.getDisplayName(), reason); + if (owner.getTerminatedBy().isEmpty()) { + pw.print("No termination trace available."); + } else { + pw.println("Termination trace follows:"); + for (Computer.TerminationRequest request: owner.getTerminatedBy()) { + request.printStackTrace(pw); + } + } + } finally { + pw.close(); + } + LOGGER.log(WARNING, writer.toString()); + lock.writeLock().lock(); + try { + if (executable != null) { + throw new IllegalStateException("Cannot reset the work unit after the executable has been created"); + } + workUnit = null; + } finally { + lock.writeLock().unlock(); + } + } + @Override public void run() { - startTime = System.currentTimeMillis(); + if (!owner.isOnline()) { + resetWorkUnit("went off-line before the task's worker thread started"); + owner.removeExecutor(this); + queue.scheduleMaintenance(); + return; + } + if (owner.getNode() == null) { + resetWorkUnit("was removed before the task's worker thread started"); + owner.removeExecutor(this); + queue.scheduleMaintenance(); + return; + } + final WorkUnit workUnit; + lock.writeLock().lock(); + try { + startTime = System.currentTimeMillis(); + workUnit = this.workUnit; + } finally { + lock.writeLock().unlock(); + } ACL.impersonate(ACL.SYSTEM); @@ -204,14 +343,45 @@ public class Executor extends Thread implements ModelObject { SubTask task; // transition from idle to building. // perform this state change as an atomic operation wrt other queue operations - synchronized (queue) { - workUnit.setExecutor(this); - queue.onStartExecuting(this); - if (LOGGER.isLoggable(FINE)) - LOGGER.log(FINE, getName()+" grabbed "+workUnit+" from queue"); - task = workUnit.work; - executable = task.createExecutable(); - workUnit.setExecutable(executable); + task = Queue.withLock(new java.util.concurrent.Callable() { + @Override + public SubTask call() throws Exception { + if (!owner.isOnline()) { + resetWorkUnit("went off-line before the task's worker thread was ready to execute"); + return null; + } + if (owner.getNode() == null) { + resetWorkUnit("was removed before the task's worker thread was ready to execute"); + return null; + } + // after this point we cannot unwind the assignment of the work unit, if the owner + // is removed or goes off-line then the build will just have to fail. + workUnit.setExecutor(Executor.this); + queue.onStartExecuting(Executor.this); + if (LOGGER.isLoggable(FINE)) + LOGGER.log(FINE, getName()+" grabbed "+workUnit+" from queue"); + SubTask task = workUnit.work; + Executable executable = task.createExecutable(); + lock.writeLock().lock(); + try { + Executor.this.executable = executable; + } finally { + lock.writeLock().unlock(); + } + workUnit.setExecutable(executable); + return task; + } + }); + Executable executable; + lock.readLock().lock(); + try { + if (this.workUnit == null) { + // we called resetWorkUnit, so bail. Outer finally will remove this and schedule queue maintenance + return; + } + executable = this.executable; + } finally { + lock.readLock().unlock(); } if (LOGGER.isLoggable(FINE)) LOGGER.log(FINE, getName()+" is going to execute "+executable); @@ -238,23 +408,26 @@ public class Executor extends Thread implements ModelObject { if (LOGGER.isLoggable(FINE)) LOGGER.log(FINE, getName()+" is now executing "+executable); queue.execute(executable, task); + } catch (AsynchronousExecution x) { + lock.writeLock().lock(); + try { + x.setExecutor(this); + this.asynchronousExecution = x; + } finally { + lock.writeLock().unlock(); + } } catch (Throwable e) { - // for some reason the executor died. this is really - // a bug in the code, but we don't want the executor to die, - // so just leave some info and go on to build other things - LOGGER.log(Level.SEVERE, "Executor threw an exception", e); - workUnit.context.abort(e); problems = e; } finally { - long time = System.currentTimeMillis()-startTime; - if (LOGGER.isLoggable(FINE)) - LOGGER.log(FINE, getName()+" completed "+executable+" in "+time+"ms"); + boolean needFinish1; + lock.readLock().lock(); try { - workUnit.context.synchronizeEnd(executable,problems,time); - } catch (InterruptedException e) { - workUnit.context.abort(e); + needFinish1 = asynchronousExecution == null; } finally { - workUnit.setExecutor(null); + lock.readLock().unlock(); + } + if (needFinish1) { + finish1(problems); } } } catch (InterruptedException e) { @@ -267,12 +440,52 @@ public class Executor extends Thread implements ModelObject { causeOfDeath = e; LOGGER.log(SEVERE, "Unexpected executor death", e); } finally { - if (causeOfDeath==null) - // let this thread die and be replaced by a fresh unstarted instance - owner.removeExecutor(this); + if (asynchronousExecution == null) { + finish2(); + } + } + } - queue.scheduleMaintenance(); + private void finish1(@CheckForNull Throwable problems) { + if (problems != null) { + // for some reason the executor died. this is really + // a bug in the code, but we don't want the executor to die, + // so just leave some info and go on to build other things + LOGGER.log(Level.SEVERE, "Executor threw an exception", problems); + workUnit.context.abort(problems); } + long time = System.currentTimeMillis() - startTime; + LOGGER.log(FINE, "{0} completed {1} in {2}ms", new Object[]{getName(), executable, time}); + try { + workUnit.context.synchronizeEnd(this, executable, problems, time); + } catch (InterruptedException e) { + workUnit.context.abort(e); + } finally { + workUnit.setExecutor(null); + } + } + + private void finish2() { + for (RuntimeException e1 : owner.getTerminatedBy()) { + LOGGER.log(Level.FINE, String.format("%s termination trace", getName()), e1); + } + if (causeOfDeath == null) {// let this thread die and be replaced by a fresh unstarted instance + owner.removeExecutor(this); + } + if (this instanceof OneOffExecutor) { + owner.remove((OneOffExecutor) this); + } + queue.scheduleMaintenance(); + } + + @Restricted(NoExternalUse.class) + public void completedAsynchronous(@CheckForNull Throwable error) { + try { + finish1(error); + } finally { + finish2(); + } + asynchronousExecution = null; } /** @@ -290,7 +503,22 @@ public class Executor extends Thread implements ModelObject { */ @Exported public @CheckForNull Queue.Executable getCurrentExecutable() { - return executable; + lock.readLock().lock(); + try { + return executable; + } finally { + 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); } /** @@ -302,7 +530,12 @@ public class Executor extends Thread implements ModelObject { */ @Exported public WorkUnit getCurrentWorkUnit() { - return workUnit; + lock.readLock().lock(); + try { + return workUnit; + } finally { + lock.readLock().unlock(); + } } /** @@ -311,13 +544,19 @@ public class Executor extends Thread implements ModelObject { * to that point yet. */ public FilePath getCurrentWorkspace() { - Executable e = executable; - if(e==null) return null; - if (e instanceof AbstractBuild) { - AbstractBuild ab = (AbstractBuild) e; - return ab.getWorkspace(); + lock.readLock().lock(); + try { + if (executable == null) { + return null; + } + if (executable instanceof AbstractBuild) { + AbstractBuild ab = (AbstractBuild) executable; + return ab.getWorkspace(); + } + return null; + } finally { + lock.readLock().unlock(); } - return null; } /** @@ -344,43 +583,92 @@ public class Executor extends Thread implements ModelObject { */ @Exported public boolean isIdle() { - return executable==null; + lock.readLock().lock(); + try { + return workUnit == null && executable == null; + } finally { + lock.readLock().unlock(); + } } /** * The opposite of {@link #isIdle()} — the executor is doing some work. */ public boolean isBusy() { - return executable!=null; + lock.readLock().lock(); + try { + return workUnit != null || executable != null; + } finally { + lock.readLock().unlock(); + } } /** * Check if executor is ready to accept tasks. * This method becomes the critical one since 1.536, which introduces the - * on-demand creation of executor threads. The entire logic should use - * this method instead of {@link #isAlive()}, because it provides wrong - * information for non-started threads. + * on-demand creation of executor threads. Callers should use + * this method instead of {@link #isAlive()}, which would be incorrect for + * non-started threads or running {@link AsynchronousExecution}. * @return True if the executor is available for tasks * @since 1.536 */ public boolean isActive() { - return !started || isAlive(); + lock.readLock().lock(); + try { + return !started || asynchronousExecution != null || isAlive(); + } finally { + lock.readLock().unlock(); + } + } + + /** + * If currently running in asynchronous mode, returns that handle. + * @since 1.607 + */ + public @CheckForNull AsynchronousExecution getAsynchronousExecution() { + lock.readLock().lock(); + try { + return asynchronousExecution; + } finally { + lock.readLock().unlock(); + } + } + + /** + * If this executor is running an {@link AsynchronousExecution} and that execution wants to hide the display + * cell for the executor (because there is another executor displaying the job progress and we don't want to + * confuse the user) then this method will return {@code false} to indicate to {@code executors.jelly} that + * the executor cell should be hidden. + * + * @return {@code true} iff the {@code executorCell.jelly} for this {@link Executor} should be displayed in + * {@code executors.jelly}. + * @since 1.607 + * @see AsynchronousExecution#displayCell() + */ + public boolean isDisplayCell() { + AsynchronousExecution asynchronousExecution = getAsynchronousExecution(); + return asynchronousExecution == null || asynchronousExecution.displayCell(); } /** * Returns true if this executor is waiting for a task to execute. */ public boolean isParking() { - return !started; + lock.readLock().lock(); + try { + return !started; + } finally { + lock.readLock().unlock(); + } } /** * If this thread dies unexpectedly, obtain the cause of the failure. * - * @return null if the death is expected death or the thread is {@link #isAlive() still alive}. + * @return null if the death is expected death or the thread {@link #isActive}. * @since 1.142 */ - public Throwable getCauseOfDeath() { + public @CheckForNull Throwable getCauseOfDeath() { return causeOfDeath; } @@ -392,13 +680,24 @@ public class Executor extends Thread implements ModelObject { */ @Exported public int getProgress() { - Queue.Executable e = executable; - if(e==null) return -1; - long d = Executables.getEstimatedDurationFor(e); - if(d<0) return -1; + long d; + lock.readLock().lock(); + try { + if (executable == null) { + return -1; + } + d = Executables.getEstimatedDurationFor(executable); + } finally { + lock.readLock().unlock(); + } + if (d <= 0) { + return -1; + } - int num = (int)(getElapsedTime()*100/d); - if(num>=100) num=99; + int num = (int) (getElapsedTime() * 100 / d); + if (num >= 100) { + num = 99; + } return num; } @@ -411,22 +710,35 @@ public class Executor extends Thread implements ModelObject { */ @Exported public boolean isLikelyStuck() { - Queue.Executable e = executable; - if(e==null) return false; + long d; + long elapsed; + lock.readLock().lock(); + try { + if (executable == null) { + return false; + } - long elapsed = getElapsedTime(); - long d = Executables.getEstimatedDurationFor(e); - if(d>=0) { + elapsed = getElapsedTime(); + d = Executables.getEstimatedDurationFor(executable); + } finally { + lock.readLock().unlock(); + } + if (d >= 0) { // if it's taking 10 times longer than ETA, consider it stuck - return d*10 < elapsed; + return d * 10 < elapsed; } else { // if no ETA is available, a build taking longer than a day is considered stuck - return TimeUnit2.MILLISECONDS.toHours(elapsed)>24; + return TimeUnit2.MILLISECONDS.toHours(elapsed) > 24; } } public long getElapsedTime() { - return System.currentTimeMillis() - startTime; + lock.readLock().lock(); + try { + return System.currentTimeMillis() - startTime; + } finally { + lock.readLock().unlock(); + } } /** @@ -435,7 +747,12 @@ public class Executor extends Thread implements ModelObject { * @since 1.440 */ public long getTimeSpentInQueue() { - return startTime - workUnit.context.item.buildableStartMilliseconds; + lock.readLock().lock(); + try { + return startTime - workUnit.context.item.buildableStartMilliseconds; + } finally { + lock.readLock().unlock(); + } } /** @@ -453,14 +770,25 @@ public class Executor extends Thread implements ModelObject { * until the build completes. */ public String getEstimatedRemainingTime() { - Queue.Executable e = executable; - if(e==null) return Messages.Executor_NotAvailable(); + long d; + lock.readLock().lock(); + try { + if (executable == null) { + return Messages.Executor_NotAvailable(); + } - long d = Executables.getEstimatedDurationFor(e); - if(d<0) return Messages.Executor_NotAvailable(); + d = Executables.getEstimatedDurationFor(executable); + } finally { + lock.readLock().unlock(); + } + if (d < 0) { + return Messages.Executor_NotAvailable(); + } - long eta = d-getElapsedTime(); - if(eta<=0) return Messages.Executor_NotAvailable(); + long eta = d - getElapsedTime(); + if (eta <= 0) { + return Messages.Executor_NotAvailable(); + } return Util.getTimeSpanString(eta); } @@ -470,14 +798,25 @@ public class Executor extends Thread implements ModelObject { * it as a number of milli-seconds. */ public long getEstimatedRemainingTimeMillis() { - Queue.Executable e = executable; - if(e==null) return -1; + long d; + lock.readLock().lock(); + try { + if (executable == null) { + return -1; + } - long d = Executables.getEstimatedDurationFor(e); - if(d<0) return -1; + d = Executables.getEstimatedDurationFor(executable); + } finally { + lock.readLock().unlock(); + } + if (d < 0) { + return -1; + } - long eta = d-getElapsedTime(); - if(eta<=0) return -1; + long eta = d - getElapsedTime(); + if (eta <= 0) { + return -1; + } return eta; } @@ -488,14 +827,19 @@ public class Executor extends Thread implements ModelObject { * @see #start(WorkUnit) */ @Override - public synchronized void start() { + public void start() { throw new UnsupportedOperationException(); } - /*protected*/ synchronized void start(WorkUnit task) { - this.workUnit = task; - super.start(); - started = true; + /*protected*/ void start(WorkUnit task) { + lock.writeLock().lock(); + try { + this.workUnit = task; + super.start(); + started = true; + } finally { + lock.writeLock().unlock(); + } } @@ -504,6 +848,7 @@ public class Executor extends Thread implements ModelObject { * Use {@link #doStop()}. */ @RequirePOST + @Deprecated public void doStop( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { doStop().generateResponse(req,rsp,this); } @@ -515,10 +860,14 @@ public class Executor extends Thread implements ModelObject { */ @RequirePOST public HttpResponse doStop() { - Queue.Executable e = executable; - if(e!=null) { - Tasks.getOwnerTaskOf(getParentOf(e)).checkAbortPermission(); - interrupt(); + lock.writeLock().lock(); // need write lock as interrupt will change the field + try { + if (executable != null) { + Tasks.getOwnerTaskOf(getParentOf(executable)).checkAbortPermission(); + interrupt(); + } + } finally { + lock.writeLock().unlock(); } return HttpResponses.forwardToPreviousPage(); } @@ -529,7 +878,7 @@ public class Executor extends Thread implements ModelObject { @RequirePOST public HttpResponse doYank() { Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); - if (isAlive()) + if (isActive()) throw new Failure("Can't yank a live executor"); owner.removeExecutor(this); return HttpResponses.redirectViaContextPath("/"); @@ -539,8 +888,12 @@ public class Executor extends Thread implements ModelObject { * Checks if the current user has a permission to stop this build. */ public boolean hasStopPermission() { - Queue.Executable e = executable; - return e!=null && Tasks.getOwnerTaskOf(getParentOf(e)).hasAbortPermission(); + lock.readLock().lock(); + try { + return executable != null && Tasks.getOwnerTaskOf(getParentOf(executable)).hasAbortPermission(); + } finally { + lock.readLock().unlock(); + } } public @Nonnull Computer getOwner() { @@ -551,11 +904,16 @@ public class Executor extends Thread implements ModelObject { * Returns when this executor started or should start being idle. */ public long getIdleStartMilliseconds() { - if (isIdle()) - return Math.max(creationTime, owner.getConnectTime()); - else { - return Math.max(startTime + Math.max(0, Executables.getEstimatedDurationFor(executable)), - System.currentTimeMillis() + 15000); + lock.readLock().lock(); + try { + if (isIdle()) + return Math.max(creationTime, owner.getConnectTime()); + else { + return Math.max(startTime + Math.max(0, Executables.getEstimatedDurationFor(executable)), + System.currentTimeMillis() + 15000); + } + } finally { + lock.readLock().unlock(); } } @@ -593,6 +951,33 @@ public class Executor extends Thread implements ModelObject { return IMPERSONATION.get(); } + /** + * Finds the executor currently running a given process. + * @param executable a possibly running executable + * @return the executor (possibly a {@link OneOffExecutor}) whose {@link Executor#getCurrentExecutable} matches that, + * or null if it could not be found (for example because the execution has already completed) + * @since 1.607 + */ + public static @CheckForNull Executor of(Executable executable) { + Jenkins jenkins = Jenkins.getInstance(); + if (jenkins == null) { + return null; + } + for (Computer computer : jenkins.getComputers()) { + for (Executor executor : computer.getExecutors()) { + if (executor.getCurrentExecutable() == executable) { + return executor; + } + } + for (Executor executor : computer.getOneOffExecutors()) { + if (executor.getCurrentExecutable() == executable) { + return executor; + } + } + } + return null; + } + /** * Returns the estimated duration for the executable. * Protects against {@link AbstractMethodError}s if the {@link Executable} implementation @@ -601,6 +986,7 @@ public class Executor extends Thread implements ModelObject { * @deprecated as of 1.388 * Use {@link Executables#getEstimatedDurationFor(Queue.Executable)} */ + @Deprecated public static long getEstimatedDurationFor(Executable e) { return Executables.getEstimatedDurationFor(e); } diff --git a/core/src/main/java/hudson/model/ExecutorListener.java b/core/src/main/java/hudson/model/ExecutorListener.java index 3c5e221f17f277d8bc2a9c53a3e587e36039f9cd..678a0ca702ad54314630fa972a5e663160deedc7 100644 --- a/core/src/main/java/hudson/model/ExecutorListener.java +++ b/core/src/main/java/hudson/model/ExecutorListener.java @@ -23,7 +23,6 @@ */ package hudson.model; -import hudson.slaves.SlaveComputer; /** * A listener for task related events from executors. diff --git a/core/src/main/java/hudson/model/Fingerprint.java b/core/src/main/java/hudson/model/Fingerprint.java index 22fac5bb8db1ffe4c0fc8daaa99474b5e0c755fa..6411cf08aa26155b8d1920e10abb9ef530ac4ad0 100644 --- a/core/src/main/java/hudson/model/Fingerprint.java +++ b/core/src/main/java/hudson/model/Fingerprint.java @@ -71,6 +71,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 +106,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 +154,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; } @@ -761,13 +787,16 @@ public class Fingerprint implements ModelObject, Saveable { private static final DateConverter DATE_CONVERTER = new DateConverter(); - private final Date timestamp; + /** + * Time when the fingerprint has been captured. + */ + private final @Nonnull Date timestamp; /** * Null if this fingerprint is for a file that's * apparently produced outside. */ - private final BuildPtr original; + private final @CheckForNull BuildPtr original; private final byte[] md5sum; @@ -785,12 +814,12 @@ public class Fingerprint implements ModelObject, Saveable { */ private transient volatile List transientFacets = null; - public Fingerprint(Run build, String fileName, byte[] md5sum) throws IOException { + public Fingerprint(@CheckForNull Run build, @Nonnull String fileName, @Nonnull byte[] md5sum) throws IOException { this(build==null ? null : new BuildPtr(build), fileName, md5sum); save(); } - Fingerprint(BuildPtr original, String fileName, byte[] md5sum) { + Fingerprint(@CheckForNull BuildPtr original, @Nonnull String fileName, @Nonnull byte[] md5sum) { this.original = original; this.md5sum = md5sum; this.fileName = fileName; @@ -806,14 +835,18 @@ 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; + public @CheckForNull BuildPtr getOriginal() { + if (original != null && original.hasPermissionToDiscoverBuild()) { + return original; + } + return null; } - public String getDisplayName() { + public @Nonnull String getDisplayName() { return fileName; } @@ -821,7 +854,7 @@ public class Fingerprint implements ModelObject, Saveable { * The file name (like "foo.jar" without path). */ @Exported - public String getFileName() { + public @Nonnull String getFileName() { return fileName; } @@ -829,7 +862,7 @@ public class Fingerprint implements ModelObject, Saveable { * Gets the MD5 hash string. */ @Exported(name="hash") - public String getHashString() { + public @Nonnull String getHashString() { return Util.toHexString(md5sum); } @@ -837,7 +870,7 @@ public class Fingerprint implements ModelObject, Saveable { * Gets the timestamp when this record is created. */ @Exported - public Date getTimestamp() { + public @Nonnull Date getTimestamp() { return timestamp; } @@ -847,7 +880,7 @@ public class Fingerprint implements ModelObject, Saveable { * @return * string like "3 minutes" "1 day" etc. */ - public String getTimestampString() { + public @Nonnull String getTimestampString() { long duration = System.currentTimeMillis()-timestamp.getTime(); return Util.getPastTimeString(duration); } @@ -857,8 +890,9 @@ public class Fingerprint implements ModelObject, Saveable { * *

* These builds of this job has used this file. + * @return may be empty but not null. */ - public RangeSet getRangeSet(String jobFullName) { + public @Nonnull RangeSet getRangeSet(String jobFullName) { RangeSet r = usages.get(jobFullName); if(r==null) r = new RangeSet(); return r; @@ -871,14 +905,14 @@ public class Fingerprint implements ModelObject, Saveable { /** * Gets the sorted list of job names where this jar is used. */ - public List getJobs() { + public @Nonnull List getJobs() { List r = new ArrayList(); r.addAll(usages.keySet()); Collections.sort(r); return r; } - public Hashtable getUsages() { + public @Nonnull Hashtable getUsages() { return usages; } @@ -897,34 +931,48 @@ public class Fingerprint implements ModelObject, Saveable { // this is for remote API @Exported(name="usage") - public List _getUsages() { + public @Nonnull 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; } + /** + * @deprecated Use {@link #addFor(hudson.model.Run)} + */ @Deprecated - public synchronized void add(AbstractBuild b) throws IOException { + public synchronized void add(@Nonnull AbstractBuild b) throws IOException { addFor((Run) b); } /** + * Adds a usage reference to the build. + * @param b {@link Run} to be referenced in {@link #usages} * @since 1.577 */ - public synchronized void addFor(Run b) throws IOException { + public synchronized void addFor(@Nonnull Run b) throws IOException { add(b.getParent().getFullName(), b.getNumber()); } /** * Records that a build of a job has used this file. */ - public synchronized void add(String jobFullName, int n) throws IOException { + public synchronized void add(@Nonnull String jobFullName, int n) throws IOException { addWithoutSaving(jobFullName, n); save(); } - void addWithoutSaving(String jobFullName, int n) { + void addWithoutSaving(@Nonnull String jobFullName, int n) { synchronized(usages) { // TODO why not synchronized (this) like some, though not all, other accesses? RangeSet r = usages.get(jobFullName); if(r==null) { @@ -968,6 +1016,8 @@ public class Fingerprint implements ModelObject, Saveable { * * @return true * if this record was modified. + * + * @throws IOException Save failure */ public synchronized boolean trim() throws IOException { boolean modified = false; @@ -1041,7 +1091,7 @@ public class Fingerprint implements ModelObject, Saveable { * * @since 1.421 */ - public Collection getFacets() { + public @Nonnull Collection getFacets() { if (transientFacets==null) { List transientFacets = new ArrayList(); for (TransientFingerprintFacetFactory fff : TransientFingerprintFacetFactory.all()) { @@ -1079,7 +1129,11 @@ public class Fingerprint implements ModelObject, Saveable { }; } - public Collection getSortedFacets() { + /** + * Sorts {@link FingerprintFacet}s by their timestamps. + * @return Sorted list of {@link FingerprintFacet}s + */ + public @Nonnull Collection getSortedFacets() { List r = new ArrayList(getFacets()); Collections.sort(r,new Comparator() { public int compare(FingerprintFacet o1, FingerprintFacet o2) { @@ -1095,8 +1149,11 @@ public class Fingerprint implements ModelObject, Saveable { /** * Finds a facet of the specific type (including subtypes.) + * @param Class of the {@link FingerprintFacet} + * @return First matching facet of the specified class + * @since 1.556 */ - public T getFacet(Class type) { + public @CheckForNull T getFacet(Class type) { for (FingerprintFacet f : getFacets()) { if (type.isInstance(f)) return type.cast(f); @@ -1107,7 +1164,7 @@ public class Fingerprint implements ModelObject, Saveable { /** * Returns the actions contributed from {@link #getFacets()} */ - public List getActions() { + public @Nonnull List getActions() { List r = new ArrayList(); for (FingerprintFacet ff : getFacets()) ff.createActions(r); @@ -1116,6 +1173,7 @@ public class Fingerprint implements ModelObject, Saveable { /** * Save the settings to a file. + * @throws IOException Save error */ public synchronized void save() throws IOException { if(BulkChange.contains(this)) return; @@ -1218,14 +1276,14 @@ public class Fingerprint implements ModelObject, Saveable { /** * The file we save our configuration. */ - private static XmlFile getConfigFile(File file) { + private static @Nonnull XmlFile getConfigFile(@Nonnull File file) { return new XmlFile(XSTREAM,file); } /** * Determines the file name from md5sum. */ - private static File getFingerprintFile(byte[] md5sum) { + private static @Nonnull File getFingerprintFile(@Nonnull byte[] md5sum) { assert md5sum.length==16; return new File( Jenkins.getInstance().getRootDir(), "fingerprints/"+ Util.toHexString(md5sum,0,1)+'/'+Util.toHexString(md5sum,1,1)+'/'+Util.toHexString(md5sum,2,md5sum.length-2)+".xml"); @@ -1233,11 +1291,13 @@ public class Fingerprint implements ModelObject, Saveable { /** * Loads a {@link Fingerprint} from a file in the image. + * @return Loaded {@link Fingerprint}. Null if the config file does not exist or + * malformed. */ - /*package*/ static @CheckForNull Fingerprint load(byte[] md5sum) throws IOException { + /*package*/ static @CheckForNull Fingerprint load(@Nonnull byte[] md5sum) throws IOException { return load(getFingerprintFile(md5sum)); } - /*package*/ static @CheckForNull Fingerprint load(File file) throws IOException { + /*package*/ static @CheckForNull Fingerprint load(@Nonnull File file) throws IOException { XmlFile configFile = getConfigFile(file); if(!configFile.exists()) return null; @@ -1292,6 +1352,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/java/hudson/model/FingerprintMap.java b/core/src/main/java/hudson/model/FingerprintMap.java index f7112efa3dd8248e99e0637c881a91d16f3b34aa..7760bd0ada91fcf10695fb59fa8d7ced5e6d238c 100644 --- a/core/src/main/java/hudson/model/FingerprintMap.java +++ b/core/src/main/java/hudson/model/FingerprintMap.java @@ -30,6 +30,8 @@ import jenkins.model.Jenkins; import java.io.File; import java.io.IOException; import java.util.Locale; +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; /** * Cache of {@link Fingerprint}s. @@ -56,16 +58,17 @@ public final class FingerprintMap extends KeyedDataStorage i /** * @deprecated as of 1.390 */ + @Deprecated public FreeStyleProject(Jenkins parent, String name) { super(parent, name); } diff --git a/core/src/main/java/hudson/model/FullDuplexHttpChannel.java b/core/src/main/java/hudson/model/FullDuplexHttpChannel.java index 6372b60ed21b917ec65346f035e188f8f5078e87..e96718890143765294d6319a62d6d1a3a429db31 100644 --- a/core/src/main/java/hudson/model/FullDuplexHttpChannel.java +++ b/core/src/main/java/hudson/model/FullDuplexHttpChannel.java @@ -39,7 +39,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.UUID; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.logging.Level; import java.util.logging.Logger; diff --git a/core/src/main/java/hudson/model/HealthReport.java b/core/src/main/java/hudson/model/HealthReport.java index bf8c776d77b3a98c900533e1ad242dc698b93afe..0217a211abc600c6fd0b3e4d3f944e6ebd259432 100644 --- a/core/src/main/java/hudson/model/HealthReport.java +++ b/core/src/main/java/hudson/model/HealthReport.java @@ -325,6 +325,7 @@ public class HealthReport implements Serializable, Comparable { /** * {@inheritDoc} */ + @Override public int compareTo(HealthReport o) { return (this.score < o.score ? -1 : (this.score == o.score ? 0 : 1)); } diff --git a/core/src/main/java/hudson/model/Hudson.java b/core/src/main/java/hudson/model/Hudson.java index c4b6cf4a61554a50b2f082d111feaf9d2ec9c78a..9792d38e1c60722e65095a9c85bccb09b0da450d 100644 --- a/core/src/main/java/hudson/model/Hudson.java +++ b/core/src/main/java/hudson/model/Hudson.java @@ -47,9 +47,7 @@ import java.io.File; import java.io.IOException; import java.text.NumberFormat; import java.text.ParseException; -import java.util.Collections; import java.util.List; -import java.util.Map; import static hudson.Util.fixEmpty; import javax.annotation.CheckForNull; @@ -60,12 +58,14 @@ public class Hudson extends Jenkins { * List of registered {@link hudson.model.listeners.ItemListener}s. * @deprecated as of 1.286 */ + @Deprecated private transient final CopyOnWriteList itemListeners = ExtensionListView.createCopyOnWriteList(ItemListener.class); /** * List of registered {@link hudson.slaves.ComputerListener}s. * @deprecated as of 1.286 */ + @Deprecated private transient final CopyOnWriteList computerListeners = ExtensionListView.createCopyOnWriteList(ComputerListener.class); /** @deprecated Here only for compatibility. Use {@link Jenkins#getInstance} instead. */ @@ -89,6 +89,7 @@ public class Hudson extends Jenkins { * @deprecated as of 1.286. * Use {@link ItemListener#all()}. */ + @Deprecated public CopyOnWriteList getJobListeners() { return itemListeners; } @@ -99,6 +100,7 @@ public class Hudson extends Jenkins { * @deprecated as of 1.286. * Use {@link ComputerListener#all()}. */ + @Deprecated public CopyOnWriteList getComputerListeners() { return computerListeners; } @@ -109,6 +111,7 @@ public class Hudson extends Jenkins { * @deprecated * Use {@link #getNode(String)}. Since 1.252. */ + @Deprecated public Slave getSlave(String name) { Node n = getNode(name); if (n instanceof Slave) @@ -120,8 +123,9 @@ public class Hudson extends Jenkins { * @deprecated * Use {@link #getNodes()}. Since 1.252. */ + @Deprecated public List getSlaves() { - return (List)slaves; + return (List)getNodes(); } /** @@ -130,6 +134,7 @@ public class Hudson extends Jenkins { * @deprecated * Use {@link #setNodes(List)}. Since 1.252. */ + @Deprecated public void setSlaves(List slaves) throws IOException { setNodes(slaves); } @@ -139,6 +144,7 @@ public class Hudson extends Jenkins { * Left only for the compatibility of URLs. * Should not be invoked for any other purpose. */ + @Deprecated public TopLevelItem getJob(String name) { return getItem(name); } @@ -147,6 +153,7 @@ public class Hudson extends Jenkins { * @deprecated * Used only for mapping jobs to URL in a case-insensitive fashion. */ + @Deprecated public TopLevelItem getJobCaseInsensitive(String name) { String match = Functions.toEmailSafeString(name); for(TopLevelItem item : getItems()) { @@ -161,6 +168,7 @@ public class Hudson extends Jenkins { * @deprecated as of 1.317 * Use {@link #doQuietDown()} instead. */ + @Deprecated public synchronized void doQuietDown(StaplerResponse rsp) throws IOException, ServletException { doQuietDown().generateResponse(null, rsp, this); } @@ -171,6 +179,7 @@ public class Hudson extends Jenkins { * @deprecated * As on 1.267, moved to "/log/rss..." */ + @Deprecated public void doLogRss( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { String qs = req.getQueryString(); rsp.sendRedirect2("./log/rss"+(qs==null?"":'?'+qs)); @@ -180,6 +189,7 @@ public class Hudson extends Jenkins { * @deprecated as of 1.294 * Define your own check method, instead of relying on this generic one. */ + @Deprecated public void doFieldCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { doFieldCheck( fixEmpty(req.getParameter("value")), @@ -201,6 +211,7 @@ public class Hudson extends Jenkins { * Either use client-side validation (e.g. class="required number") * or define your own check method, instead of relying on this generic one. */ + @Deprecated public FormValidation doFieldCheck(@QueryParameter(fixEmpty=true) String value, @QueryParameter(fixEmpty=true) String type, @QueryParameter(fixEmpty=true) String errorText, @@ -236,6 +247,7 @@ public class Hudson extends Jenkins { * @deprecated * Use {@link Functions#isWindows()}. */ + @Deprecated public static boolean isWindows() { return File.pathSeparatorChar==';'; } @@ -244,6 +256,7 @@ public class Hudson extends Jenkins { * @deprecated * Use {@link hudson.Platform#isDarwin()} */ + @Deprecated public static boolean isDarwin() { return Platform.isDarwin(); } @@ -252,6 +265,7 @@ public class Hudson extends Jenkins { * @deprecated since 2007-12-18. * Use {@link #checkPermission(hudson.security.Permission)} */ + @Deprecated public static boolean adminCheck() throws IOException { return adminCheck(Stapler.getCurrentRequest(), Stapler.getCurrentResponse()); } @@ -260,6 +274,7 @@ public class Hudson extends Jenkins { * @deprecated since 2007-12-18. * Use {@link #checkPermission(hudson.security.Permission)} */ + @Deprecated public static boolean adminCheck(StaplerRequest req,StaplerResponse rsp) throws IOException { if (isAdmin(req)) return true; @@ -285,6 +300,7 @@ public class Hudson extends Jenkins { * if appropriate), then identify a suitable {@link hudson.security.AccessControlled} object to check its permission * against. */ + @Deprecated public static boolean isAdmin() { return Jenkins.getInstance().getACL().hasPermission(ADMINISTER); } @@ -294,6 +310,7 @@ public class Hudson extends Jenkins { * Define a custom {@link hudson.security.Permission} and check against ACL. * See {@link #isAdmin()} for more instructions. */ + @Deprecated public static boolean isAdmin(StaplerRequest req) { return isAdmin(); } @@ -305,6 +322,7 @@ public class Hudson extends Jenkins { /** * @deprecated only here for backward comp */ + @Deprecated public static final class MasterComputer extends Jenkins.MasterComputer { // no op } @@ -312,6 +330,7 @@ public class Hudson extends Jenkins { /** * @deprecated only here for backward comp */ + @Deprecated public static class CloudList extends Jenkins.CloudList { public CloudList(Jenkins h) { super(h); diff --git a/core/src/main/java/hudson/model/Item.java b/core/src/main/java/hudson/model/Item.java index 726796fa8e673bb118386237d4bbcefcaeb15570..94ee4181de75c7394031c213f29b0acc61dc5376 100644 --- a/core/src/main/java/hudson/model/Item.java +++ b/core/src/main/java/hudson/model/Item.java @@ -176,6 +176,7 @@ public interface Item extends PersistenceRoot, SearchableModelObject, AccessCont * This method is only intended for the remote API clients who cannot resolve relative references * (even this won't work for the same reason, which should be fixed.) */ + @Deprecated String getAbsoluteUrl(); /** diff --git a/core/src/main/java/hudson/model/ItemGroup.java b/core/src/main/java/hudson/model/ItemGroup.java index ace90e16b4354ec2f98dd022e7dce4d9cced37f6..0de4fa477bd3fda285bd390f787c80fdbe961398 100644 --- a/core/src/main/java/hudson/model/ItemGroup.java +++ b/core/src/main/java/hudson/model/ItemGroup.java @@ -23,7 +23,6 @@ */ package hudson.model; -import hudson.model.listeners.ItemListener; import java.io.IOException; import java.util.Collection; import java.io.File; diff --git a/core/src/main/java/hudson/model/ItemGroupMixIn.java b/core/src/main/java/hudson/model/ItemGroupMixIn.java index 6a02420d953e5cac7cd25fe26a914a9007ce22d9..15c1283743be14a7edb01d469255a8016ae57c25 100644 --- a/core/src/main/java/hudson/model/ItemGroupMixIn.java +++ b/core/src/main/java/hudson/model/ItemGroupMixIn.java @@ -29,13 +29,17 @@ import hudson.model.listeners.ItemListener; import hudson.security.AccessControlled; 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 +48,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} @@ -103,11 +108,11 @@ public abstract class ItemGroupMixIn { // Try to retain the identity of an existing child object if we can. V item = (V) parent.getItem(subdir.getName()); if (item == null) { - XmlFile xmlFile = Items.getConfigFile( subdir ); + XmlFile xmlFile = Items.getConfigFile(subdir); if (xmlFile.exists()) { - item = (V) Items.load( parent, subdir ); - }else{ - Logger.getLogger( ItemGroupMixIn.class.getName() ).log( Level.WARNING, "could not find file " + xmlFile.getFile()); + item = (V) Items.load(parent, subdir); + } else { + Logger.getLogger(ItemGroupMixIn.class.getName()).log(Level.WARNING, "could not find file " + xmlFile.getFile()); continue; } } else { @@ -141,10 +146,14 @@ public abstract class ItemGroupMixIn { TopLevelItem result; String requestContentType = req.getContentType(); - if(requestContentType==null) + String mode = req.getParameter("mode"); + if (requestContentType == null + && !(mode != null && mode.equals("copy"))) throw new Failure("No Content-Type header set"); - boolean isXmlSubmission = requestContentType.startsWith("application/xml") || requestContentType.startsWith("text/xml"); + boolean isXmlSubmission = requestContentType != null + && (requestContentType.startsWith("application/xml") + || requestContentType.startsWith("text/xml")); String name = req.getParameter("name"); if(name==null) @@ -157,7 +166,6 @@ public abstract class ItemGroupMixIn { throw new Failure(Messages.Hudson_JobAlreadyExists(name)); } - String mode = req.getParameter("mode"); if(mode!=null && mode.equals("copy")) { String from = req.getParameter("from"); @@ -190,6 +198,8 @@ public abstract class ItemGroupMixIn { if (descriptor == null) { throw new Failure("No item type ‘" + mode + "’ is known"); } + descriptor.checkApplicableIn(parent); + acl.getACL().checkCreatePermission(parent, descriptor); // create empty job and redirect to the project config screen result = createProject(descriptor, name, true); @@ -214,6 +224,8 @@ public abstract class ItemGroupMixIn { public synchronized T copy(T src, String name) throws IOException { acl.checkPermission(Item.CREATE); src.checkPermission(Item.EXTENDED_READ); + src.getDescriptor().checkApplicableIn(parent); + acl.getACL().checkCreatePermission(parent, src.getDescriptor()); T result = (T)createProject(src.getDescriptor(),name,false); @@ -249,8 +261,9 @@ public abstract class ItemGroupMixIn { File configXml = Items.getConfigFile(getRootDirFor(name)).getFile(); final File dir = configXml.getParentFile(); dir.mkdirs(); + boolean success = false; try { - IOUtils.copy(xml,configXml); + XMLUtils.safeTransform((Source)new StreamSource(xml), new StreamResult(configXml)); // load it TopLevelItem result = Items.whileUpdatingByXml(new NotReallyRoleSensitiveCallable() { @@ -258,22 +271,41 @@ public abstract class ItemGroupMixIn { return (TopLevelItem) Items.load(parent, dir); } }); + + success = acl.getACL().hasCreatePermission(Jenkins.getAuthentication(), parent, result.getDescriptor()) + && result.getDescriptor().isApplicableIn(parent); + add(result); ItemListener.fireOnCreated(result); Jenkins.getInstance().rebuildDependencyGraphAsync(); return result; + } catch (TransformerException e) { + success = false; + throw new IOException("Failed to persist config.xml", e); + } catch (SAXException e) { + success = false; + 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); + success = false; + throw e; + } catch (RuntimeException e) { + success = false; throw e; + } finally { + if (!success) { + // if anything fails, delete the config file to avoid further confusion + Util.deleteRecursive(dir); + } } } public synchronized TopLevelItem createProject( TopLevelItemDescriptor type, String name, boolean notify ) throws IOException { acl.checkPermission(Item.CREATE); + type.checkApplicableIn(parent); + acl.getACL().checkCreatePermission(parent, type); Jenkins.getInstance().getProjectNamingStrategy().checkName(name); if(parent.getItem(name)!=null) diff --git a/core/src/main/java/hudson/model/Items.java b/core/src/main/java/hudson/model/Items.java index 0358e4471aeda42dc4f67f746638c9efffa0632f..8700c0554fb855e20cf0a9bc0c8bf53e693e8610 100644 --- a/core/src/main/java/hudson/model/Items.java +++ b/core/src/main/java/hudson/model/Items.java @@ -29,11 +29,14 @@ import hudson.Extension; import hudson.XmlFile; import hudson.model.listeners.ItemListener; import hudson.remoting.Callable; +import hudson.security.ACL; +import hudson.security.AccessControlled; import hudson.triggers.Trigger; import hudson.util.DescriptorList; import hudson.util.EditDistance; import hudson.util.XStream2; import jenkins.model.Jenkins; +import org.acegisecurity.Authentication; import org.apache.commons.lang.StringUtils; import java.io.File; @@ -46,6 +49,8 @@ import java.util.List; import java.util.Stack; import java.util.StringTokenizer; import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; + import jenkins.model.DirectlyModifiableTopLevelItemGroup; import org.apache.commons.io.FileUtils; @@ -61,6 +66,7 @@ public class Items { * @deprecated as of 1.286 * Use {@link #all()} for read access and {@link Extension} for registration. */ + @Deprecated public static final List LIST = (List)new DescriptorList(TopLevelItem.class); /** @@ -110,6 +116,42 @@ public class Items { return Jenkins.getInstance().getDescriptorList(TopLevelItem.class); } + /** + * Returns all the registered {@link TopLevelItemDescriptor}s that the current security principal is allowed to + * create within the specified item group. + * + * @since TODO + */ + public static List all(ItemGroup c) { + return all(Jenkins.getAuthentication(), c); + } + + /** + * Returns all the registered {@link TopLevelItemDescriptor}s that the specified security principal is allowed to + * create within the specified item group. + * + * @since TODO + */ + public static List all(Authentication a, ItemGroup c) { + List result = new ArrayList(); + ACL acl; + if (c instanceof AccessControlled) { + acl = ((AccessControlled) c).getACL(); + } else { + // fall back to root + acl = Jenkins.getInstance().getACL(); + } + for (TopLevelItemDescriptor d: all()) { + if (acl.hasCreatePermission(a, c, d) && d.isApplicableIn(c)) { + result.add(d); + } + } + return result; + } + + /** + * @deprecated Underspecified what the parameter is. {@link Descriptor#getId}? A {@link Describable} class name? + */ public static TopLevelItemDescriptor getDescriptor(String fqcn) { return Descriptor.find(all(), fqcn); } @@ -131,6 +173,7 @@ public class Items { * @deprecated as of 1.406 * Use {@link #fromNameList(ItemGroup, String, Class)} */ + @Deprecated public static List fromNameList(String list, Class type) { return fromNameList(null,list,type); } @@ -138,7 +181,7 @@ public class Items { /** * Does the opposite of {@link #toNameList(Collection)}. */ - public static List fromNameList(ItemGroup context, String list, Class type) { + public static List fromNameList(ItemGroup context, @Nonnull String list, @Nonnull Class type) { Jenkins hudson = Jenkins.getInstance(); List r = new ArrayList(); @@ -161,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, 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)"; + + @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) || name == null; + } /** * @deprecated since 2009-02-25 @@ -80,6 +91,7 @@ public final class JDK extends ToolInstallation implements NodeSpecific, En * @deprecated as of 1.304 * Use {@link #getHome()} */ + @Deprecated public String getJavaHome() { return getHome(); } @@ -108,6 +120,7 @@ public final class JDK extends ToolInstallation implements NodeSpecific, En /** * @deprecated as of 1.460. Use {@link #buildEnvVars(EnvVars)} */ + @Deprecated public void buildEnvVars(Map env) { String home = getHome(); if (home == null) { @@ -164,11 +177,8 @@ public final class JDK extends ToolInstallation implements NodeSpecific, En return Jenkins.getInstance().getJDKs().toArray(new JDK[0]); } - // this isn't really synchronized well since the list is Hudson.jdks :( - public @Override synchronized void setInstallations(JDK... jdks) { - List list = Jenkins.getInstance().getJDKs(); - list.clear(); - list.addAll(Arrays.asList(jdks)); + public @Override void setInstallations(JDK... jdks) { + Jenkins.getInstance().setJDKs(Arrays.asList(jdks)); } @Override diff --git a/core/src/main/java/hudson/model/Job.java b/core/src/main/java/hudson/model/Job.java index 2addad98b0c80bfdb91d297829ea9c7cc5162005..d60f144d554b66ffd75614a08c62af731ead43d2 100644 --- a/core/src/main/java/hudson/model/Job.java +++ b/core/src/main/java/hudson/model/Job.java @@ -26,6 +26,7 @@ package hudson.model; import com.google.common.base.Function; import com.google.common.collect.Collections2; import com.infradna.tool.bridge_method_injector.WithBridgeMethods; +import hudson.BulkChange; import hudson.EnvVars; import hudson.Extension; @@ -104,6 +105,7 @@ import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import static javax.servlet.http.HttpServletResponse.*; +import jenkins.model.BuildDiscarderProperty; import jenkins.model.ModelObjectWithChildren; import jenkins.model.RunIdMigrator; import jenkins.model.lazy.LazyBuildMixIn; @@ -147,6 +149,7 @@ public abstract class Job, RunT extends Run, RunT extends Run> properties = new CopyOnWriteList>(); @@ -424,15 +427,24 @@ public abstract class Job, RunT extends Run, RunT extends Run, RunT extends Run> getProperties() { - return Descriptor.toMap((Iterable) properties); + Map result = Descriptor.toMap((Iterable) properties); + if (logRotator != null) { + result.put(Jenkins.getActiveInstance().getDescriptorByType(BuildDiscarderProperty.DescriptorImpl.class), new BuildDiscarderProperty(logRotator)); + } + return result; } /** @@ -559,6 +576,13 @@ public abstract class Job, RunT extends Run T getProperty(Class clazz) { + if (clazz == BuildDiscarderProperty.class && logRotator != null) { + return clazz.cast(new BuildDiscarderProperty(logRotator)); + } + return _getProperty(clazz); + } + + private T _getProperty(Class clazz) { for (JobProperty p : properties) { if (clazz.isInstance(p)) return clazz.cast(p); @@ -744,6 +768,7 @@ public abstract class Job, RunT extends Run getBuildsByTimestamp(long start, long end) { return getBuilds().byTimestamp(start,end); } @@ -1182,10 +1207,7 @@ public abstract class Job, RunT extends Run, JobPropertyDescriptor> t = new DescribableList, JobPropertyDescriptor>(NOOP,getAllProperties()); JSONObject jsonProperties = json.optJSONObject("properties"); @@ -1207,7 +1229,8 @@ public abstract class Job, RunT extends Run, RunT extends Run - * {@link Plugin}s can extend this to define custom properties + * Plugins can extend this to define custom properties * for {@link Job}s. {@link JobProperty}s show up in the user * configuration screen, and they are persisted with the job object. * @@ -63,6 +65,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 @@ -96,6 +100,7 @@ public abstract class JobProperty> implements ReconfigurableD /** * {@inheritDoc} */ + @Override public JobPropertyDescriptor getDescriptor() { return (JobPropertyDescriptor) Jenkins.getInstance().getDescriptorOrDie(getClass()); } @@ -104,6 +109,7 @@ public abstract class JobProperty> implements ReconfigurableD * @deprecated * as of 1.341. Override {@link #getJobActions(Job)} instead. */ + @Deprecated public Action getJobAction(J job) { return null; } @@ -128,6 +134,7 @@ public abstract class JobProperty> implements ReconfigurableD * @see ProminentProjectAction * @see PermalinkProjectAction */ + @Nonnull public Collection getJobActions(J job) { // delegate to getJobAction (singular) for backward compatible behavior Action a = getJobAction(job); @@ -149,6 +156,7 @@ public abstract class JobProperty> implements ReconfigurableD *

* Invoked after {@link Publisher}s have run. */ + @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { return true; } @@ -165,6 +173,7 @@ public abstract class JobProperty> implements ReconfigurableD return getJobAction((J)project); } + @Nonnull public final Collection getProjectActions(AbstractProject project) { return getJobActions((J)project); } diff --git a/core/src/main/java/hudson/model/JobPropertyDescriptor.java b/core/src/main/java/hudson/model/JobPropertyDescriptor.java index a894370fb8eff2cc4fba6e49c8e14bffb0d0b6c3..2af8f74bc14fe5db129b5fbc678da7c089b9a7c3 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/hudson/model/Jobs.java b/core/src/main/java/hudson/model/Jobs.java index c124861603f9bcde0dea58ac0c59a82b88210f84..e6a13e68d72d30ae9d753ec615d2619bbd4a2bf0 100644 --- a/core/src/main/java/hudson/model/Jobs.java +++ b/core/src/main/java/hudson/model/Jobs.java @@ -34,6 +34,7 @@ import java.util.List; * @author Kohsuke Kawaguchi * @deprecated since 1.281 */ +@Deprecated public class Jobs { /** * List of all installed {@link JobPropertyDescriptor} types. @@ -47,6 +48,7 @@ public class Jobs { * Use {@link JobPropertyDescriptor#all()} for read access, * and {@link Extension} for registration. */ + @Deprecated public static final List PROPERTIES = (List) new DescriptorList>((Class)JobProperty.class); } diff --git a/core/src/main/java/hudson/model/Label.java b/core/src/main/java/hudson/model/Label.java index cdfcfb5e864ac9f6d94c6c787506d0af5a0c770f..ff32c1f9401c8b5ccf41fb3758aa2761ad4ffccd 100644 --- a/core/src/main/java/hudson/model/Label.java +++ b/core/src/main/java/hudson/model/Label.java @@ -39,6 +39,7 @@ import hudson.model.labels.LabelExpressionLexer; import hudson.model.labels.LabelExpressionParser; import hudson.model.labels.LabelOperatorPrecedence; import hudson.model.labels.LabelVisitor; +import hudson.model.queue.SubTask; import hudson.security.ACL; import hudson.slaves.NodeProvisioner; import hudson.slaves.Cloud; @@ -84,6 +85,7 @@ public abstract class Label extends Actionable implements Comparable

Life-cycle

*

- * {@link Plugin}s that contribute this extension point + * Plugins that contribute this extension point * should implement a new decorator and put {@link Extension} on the class. * *

Associated Views

@@ -79,6 +78,7 @@ public abstract class PageDecorator extends Descriptor implements * @deprecated as of 1.425 * Use the default constructor that's less error prone */ + @Deprecated protected PageDecorator(Class yourClass) { super(yourClass); } @@ -95,14 +95,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. * @@ -119,6 +111,7 @@ public abstract class PageDecorator extends Descriptor implements * @deprecated as of 1.286 * Use {@link #all()} for read access, and use {@link Extension} for registration. */ + @Deprecated public static final List ALL = (List)new DescriptorList(PageDecorator.class); /** diff --git a/core/src/main/java/hudson/model/PaneStatusProperties.java b/core/src/main/java/hudson/model/PaneStatusProperties.java index 9f8be772279f2623ae959beec3488e606bc77959..8ee6cd3539badac69b2eeccb4378cbb3cb0f718e 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/ParameterDefinition.java b/core/src/main/java/hudson/model/ParameterDefinition.java index a62c4902c00998ec7788bb57ea5622b740b942b5..20250924d909dd408ed556da1dc8552d42a3a15e 100644 --- a/core/src/main/java/hudson/model/ParameterDefinition.java +++ b/core/src/main/java/hudson/model/ParameterDefinition.java @@ -155,6 +155,7 @@ public abstract class ParameterDefinition implements /** * {@inheritDoc} */ + @Override public ParameterDescriptor getDescriptor() { return (ParameterDescriptor) Jenkins.getInstance().getDescriptorOrDie(getClass()); } @@ -232,6 +233,7 @@ public abstract class ParameterDefinition implements * @deprecated as of 1.286 * Use {@link #all()} for read access, and {@link Extension} for registration. */ + @Deprecated public static final DescriptorList LIST = new DescriptorList(ParameterDefinition.class); public abstract static class ParameterDescriptor extends diff --git a/core/src/main/java/hudson/model/ParameterValue.java b/core/src/main/java/hudson/model/ParameterValue.java index 8bafa5aa766f9ceebb802664c96da70bf689540a..d3b39f614a3678c5e2c8a1cd8dd79e76180382c4 100644 --- a/core/src/main/java/hudson/model/ParameterValue.java +++ b/core/src/main/java/hudson/model/ParameterValue.java @@ -127,6 +127,7 @@ public abstract class ParameterValue implements Serializable { * @deprecated as of 1.344 * Use {@link #buildEnvironment(Run, EnvVars)} instead. */ + @Deprecated public void buildEnvVars(AbstractBuild build, Map env) { if (env instanceof EnvVars) { if (Util.isOverridden(ParameterValue.class, getClass(), "buildEnvironment", Run.class, EnvVars.class)) { @@ -222,6 +223,7 @@ public abstract class ParameterValue implements Serializable { * instead copy them in {@link ParameterDefinition#createValue(StaplerRequest, JSONObject)} * into {@link ParameterValue}. */ + @Deprecated public ParameterDefinition getDefinition() { throw new UnsupportedOperationException(); } diff --git a/core/src/main/java/hudson/model/ParametersAction.java b/core/src/main/java/hudson/model/ParametersAction.java index 85ed085c80859cc4c24a2b74e8ec944e2771e28d..202703036d95f297fbd75030ba21220ddc924dde 100644 --- a/core/src/main/java/hudson/model/ParametersAction.java +++ b/core/src/main/java/hudson/model/ParametersAction.java @@ -64,6 +64,7 @@ public class ParametersAction implements Action, Iterable, Queue /** * @deprecated since 1.283; kept to avoid warnings loading old build data, but now transient. */ + @Deprecated private transient AbstractBuild build; public ParametersAction(List parameters) { diff --git a/core/src/main/java/hudson/model/ParametersDefinitionProperty.java b/core/src/main/java/hudson/model/ParametersDefinitionProperty.java index 13a6156b5c88a26d7ea23dd2f9a064f4fe0dd92d..65c948c419896550e040004e0c5731b571f4c0b1 100644 --- a/core/src/main/java/hudson/model/ParametersDefinitionProperty.java +++ b/core/src/main/java/hudson/model/ParametersDefinitionProperty.java @@ -35,15 +35,18 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; 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 +63,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; } @@ -103,6 +107,7 @@ public class ParametersDefinitionProperty extends JobProperty> }; } + @Nonnull @Override public Collection getJobActions(Job job) { return Collections.singleton(this); @@ -203,33 +208,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/java/hudson/model/PeriodicWork.java b/core/src/main/java/hudson/model/PeriodicWork.java index d66ef11d48ac685f8620204aa7afcd6f04b15f5e..95de4fb3042d34eecf530154468943b661608f07 100644 --- a/core/src/main/java/hudson/model/PeriodicWork.java +++ b/core/src/main/java/hudson/model/PeriodicWork.java @@ -25,11 +25,9 @@ package hudson.model; import hudson.init.Initializer; import hudson.triggers.SafeTimerTask; -import hudson.triggers.Trigger; import hudson.ExtensionPoint; import hudson.Extension; import hudson.ExtensionList; -import jenkins.model.Jenkins; import jenkins.util.Timer; import java.util.concurrent.TimeUnit; @@ -60,6 +58,7 @@ public abstract class PeriodicWork extends SafeTimerTask implements ExtensionPoi /** @deprecated Use your own logger, or send messages to the logger in {@link AsyncPeriodicWork#execute}. */ @SuppressWarnings("NonConstantLogger") + @Deprecated protected final Logger logger = Logger.getLogger(getClass().getName()); /** diff --git a/core/src/main/java/hudson/model/PermalinkProjectAction.java b/core/src/main/java/hudson/model/PermalinkProjectAction.java index 60e38d3cd2d4c4d07ea89095b7b71fd30c84e9c8..38e561a982124036add7700fb23d0e070f7a94ee 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/java/hudson/model/Project.java b/core/src/main/java/hudson/model/Project.java index 894bb612d7e88a49e0f2f84aafcf1900a538496f..1b5fe372546c69766da6985bbb3c553dacd770d8 100644 --- a/core/src/main/java/hudson/model/Project.java +++ b/core/src/main/java/hudson/model/Project.java @@ -130,6 +130,7 @@ public abstract class Project

,B extends Build> * We will be soon removing the restriction that only one instance of publisher is allowed per type. * Use {@link #getPublishersList()} instead. */ + @Deprecated public Map,Publisher> getPublishers() { return getPublishersList().toMap(); } @@ -177,6 +178,7 @@ public abstract class Project

,B extends Build> * @deprecated as of 1.290 * Use {@code getPublishersList().add(x)} */ + @Deprecated public void addPublisher(Publisher buildStep) throws IOException { getPublishersList().add(buildStep); } @@ -187,6 +189,7 @@ public abstract class Project

,B extends Build> * @deprecated as of 1.290 * Use {@code getPublishersList().remove(x)} */ + @Deprecated public void removePublisher(Descriptor descriptor) throws IOException { getPublishersList().remove(descriptor); } diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java index 737e3fb0705dfc54591efdebab61c449dc08c30a..daeb98f4588191237c2c66ece03cdf1a848d4099 100644 --- a/core/src/main/java/hudson/model/Queue.java +++ b/core/src/main/java/hudson/model/Queue.java @@ -64,7 +64,8 @@ import hudson.model.queue.CauseOfBlockage.BecauseNodeIsOffline; import hudson.model.queue.CauseOfBlockage.BecauseLabelIsOffline; import hudson.model.queue.CauseOfBlockage.BecauseNodeIsBusy; import hudson.model.queue.WorkUnitContext; -import hudson.security.ACL; +import hudson.security.AccessControlled; +import hudson.security.Permission; import jenkins.security.QueueItemAuthenticatorProvider; import jenkins.util.Timer; import hudson.triggers.SafeTimerTask; @@ -88,6 +89,7 @@ import java.util.GregorianCalendar; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; @@ -95,9 +97,10 @@ import java.util.Set; import java.util.TreeSet; import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; import java.util.logging.Level; import java.util.logging.Logger; @@ -109,6 +112,9 @@ import jenkins.security.QueueItemAuthenticator; 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.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponses; import org.kohsuke.stapler.export.Exported; @@ -120,6 +126,8 @@ import org.kohsuke.accmod.restrictions.DoNotUse; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter; import javax.annotation.CheckForNull; +import javax.annotation.Nonnegative; +import jenkins.model.queue.AsynchronousExecution; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.interceptor.RequirePOST; @@ -139,9 +147,20 @@ import org.kohsuke.stapler.interceptor.RequirePOST; * | | * | v * +--> buildables ---> pending ---> left + * ^ | + * | | + * +---(rarely)---+ * * *

+ * Note: In the normal case of events pending items only move to left. However they can move back + * if the node they are assigned to execute on disappears before their {@link Executor} thread + * starts, where the node is removed before the {@link Executable} has been instantiated it + * is safe to move the pending item back to buildable. Once the {@link Executable} has been + * instantiated the only option is to let the {@link Executable} bomb out as soon as it starts + * to try an execute on the node that no longer exists. + * + *

* In addition, at any stage, an item can be removed from the queue (for example, when the user * cancels a job in the queue.) See the corresponding field for their exact meanings. * @@ -152,13 +171,6 @@ import org.kohsuke.stapler.interceptor.RequirePOST; @ExportedBean public class Queue extends ResourceController implements Saveable { - /** - * Defines the refresh period for of the internal cache ({@link #itemsView}). - * Data should be defined in milliseconds, default value - 1000; - * @since 1.577 - */ - private static int CACHE_REFRESH_PERIOD = Integer.getInteger(Queue.class.getName() + ".cacheRefreshPeriod", 1000); - /** * Items that are waiting for its quiet period to pass. * @@ -190,47 +202,14 @@ public class Queue extends ResourceController implements Saveable { */ private final ItemList pendings = new ItemList(); - /** - * Items that left queue would stay here for a while to enable tracking via {@link Item#id}. - * - * This map is forgetful, since we can't remember everything that executed in the past. - */ - private final Cache leftItems = CacheBuilder.newBuilder().expireAfterWrite(5*60, TimeUnit.SECONDS).build(); - - private final CachedItemList itemsView = new CachedItemList(); + private transient volatile Snapshot snapshot = new Snapshot(waitingList, blockedProjects, buildables, pendings); /** - * Maintains a copy of {@link Queue#getItems()} + * Items that left queue would stay here for a while to enable tracking via {@link Item#getId()}. * - * @see Queue#getApproximateItemsQuickly() + * This map is forgetful, since we can't remember everything that executed in the past. */ - private class CachedItemList { - /** - * The current cached value. - */ - @CopyOnWrite - private volatile List itemsView = Collections.emptyList(); - /** - * When does the cache info expire? - */ - private final AtomicLong expires = new AtomicLong(); - - List get() { - long t = System.currentTimeMillis(); - long d = expires.get(); - if (t>d) {// need to refresh the cache - long next = t+CACHE_REFRESH_PERIOD; - if (expires.compareAndSet(d,next)) { - // avoid concurrent cache update via CAS. - // if the getItems() lock is contended, - // some threads will end up serving stale data, - // but that's OK. - itemsView = ImmutableList.copyOf(getItems()); - } - } - return itemsView; - } - } + private final Cache leftItems = CacheBuilder.newBuilder().expireAfterWrite(5*60, TimeUnit.SECONDS).build(); /** * Data structure created for each idle {@link Executor}. @@ -318,6 +297,10 @@ public class Queue extends ResourceController implements Saveable { } }); + private transient final ReentrantLock lock = new ReentrantLock(); + + private transient final Condition condition = lock.newCondition(); + public Queue(@Nonnull LoadBalancer loadBalancer) { this.loadBalancer = loadBalancer.sanitize(); // if all the executors are busy doing something, then the queue won't be maintained in @@ -342,11 +325,20 @@ public class Queue extends ResourceController implements Saveable { this.sorter = sorter; } + /** + * Simple queue state persistence object. + */ + static class State { + public long counter; + public List items = new ArrayList(); + } + /** * Loads the queue contents that was {@link #save() saved}. */ - public synchronized void load() { - try { + public void load() { + lock.lock(); + try { try { // first try the old format File queueFile = getQueueFile(); if (queueFile.exists()) { @@ -366,18 +358,36 @@ public class Queue extends ResourceController implements Saveable { } else { queueFile = getXMLQueueFile(); if (queueFile.exists()) { - List list = (List) new XmlFile(XSTREAM, queueFile).read(); - int maxId = 0; - for (Object o : list) { + Object unmarshaledObj = new XmlFile(XSTREAM, queueFile).read(); + List items; + + if (unmarshaledObj instanceof State) { + State state = (State) unmarshaledObj; + items = state.items; + WaitingItem.COUNTER.set(state.counter); + } else { + // backward compatibility - it's an old List queue.xml + items = (List) unmarshaledObj; + long maxId = 0; + for (Object o : items) { + if (o instanceof Item) { + maxId = Math.max(maxId, ((Item)o).id); + } + } + WaitingItem.COUNTER.set(maxId); + } + + for (Object o : items) { if (o instanceof Task) { // backward compatibility schedule((Task)o, 0); } else if (o instanceof Item) { Item item = (Item)o; - if(item.task==null) + + if (item.task == null) { continue; // botched persistence. throw this one away + } - maxId = Math.max(maxId, item.id); if (item instanceof WaitingItem) { item.enter(this); } else if (item instanceof BlockedItem) { @@ -387,9 +397,8 @@ public class Queue extends ResourceController implements Saveable { } else { throw new IllegalStateException("Unknown item type! " + item); } - } // this conveniently ignores null + } } - WaitingItem.COUNTER.set(maxId); // I just had an incident where all the executors are dead at AbstractProject._getRuns() // because runs is null. Debugger revealed that this is caused by a MatrixConfiguration @@ -404,42 +413,58 @@ public class Queue extends ResourceController implements Saveable { } } catch (IOException e) { LOGGER.log(Level.WARNING, "Failed to load the queue file " + getXMLQueueFile(), e); + } finally { updateSnapshot(); } } finally { + lock.unlock(); } } /** * Persists the queue contents to the disk. */ - public synchronized void save() { + public void save() { if(BulkChange.contains(this)) return; - // write out the tasks on the queue - ArrayList items = new ArrayList(); - for (Item item: getItems()) { - if(item.task instanceof TransientTask) continue; - items.add(item); - } - + XmlFile queueFile = new XmlFile(XSTREAM, getXMLQueueFile()); + lock.lock(); try { - XmlFile queueFile = new XmlFile(XSTREAM, getXMLQueueFile()); - queueFile.write(items); - SaveableListener.fireOnChange(this, queueFile); - } catch (IOException e) { - LOGGER.log(Level.WARNING, "Failed to write out the queue file " + getXMLQueueFile(), e); + // write out the queue state we want to save + State state = new State(); + state.counter = WaitingItem.COUNTER.longValue(); + + // write out the tasks on the queue + for (Item item: getItems()) { + if(item.task instanceof TransientTask) continue; + state.items.add(item); + } + + try { + queueFile.write(state); + } catch (IOException e) { + LOGGER.log(Level.WARNING, "Failed to write out the queue file " + getXMLQueueFile(), e); + } + } finally { + lock.unlock(); } + SaveableListener.fireOnChange(this, queueFile); } /** * Wipes out all the items currently in the queue, as if all of them are cancelled at once. */ @CLIMethod(name="clear-queue") - public synchronized void clear() { + public void clear() { Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); - for (WaitingItem i : new ArrayList(waitingList)) // copy the list as we'll modify it in the loop - i.cancel(this); - blockedProjects.cancelAll(); - pendings.cancelAll(); - buildables.cancelAll(); + lock.lock(); + try { try { + for (WaitingItem i : new ArrayList( + waitingList)) // copy the list as we'll modify it in the loop + i.cancel(this); + blockedProjects.cancelAll(); + pendings.cancelAll(); + buildables.cancelAll(); + } finally { updateSnapshot(); } } finally { + lock.unlock(); + } scheduleMaintenance(); } @@ -455,6 +480,7 @@ public class Queue extends ResourceController implements Saveable { * @deprecated as of 1.311 * Use {@link #schedule(AbstractProject)} */ + @Deprecated public boolean add(AbstractProject p) { return schedule(p)!=null; } @@ -477,6 +503,7 @@ public class Queue extends ResourceController implements Saveable { * @deprecated as of 1.311 * Use {@link #schedule(Task, int)} */ + @Deprecated public boolean add(AbstractProject p, int quietPeriod) { return schedule(p, quietPeriod)!=null; } @@ -485,7 +512,8 @@ public class Queue extends ResourceController implements Saveable { * @deprecated as of 1.521 * Use {@link #schedule2(Task, int, List)} */ - public synchronized WaitingItem schedule(Task p, int quietPeriod, List actions) { + @Deprecated + public WaitingItem schedule(Task p, int quietPeriod, List actions) { return schedule2(p, quietPeriod, actions).getCreateItem(); } @@ -508,9 +536,9 @@ public class Queue extends ResourceController implements Saveable { * is that such {@link Item} only captures the state of the item at a particular moment, * and by the time you inspect the object, some of its information can be already stale. * - * That said, one can still look at {@link Queue.Item#future}, {@link Queue.Item#id}, etc. + * That said, one can still look at {@link Queue.Item#future}, {@link Queue.Item#getId()}, etc. */ - public synchronized @Nonnull ScheduleResult schedule2(Task p, int quietPeriod, List actions) { + public @Nonnull ScheduleResult schedule2(Task p, int quietPeriod, List actions) { // remove nulls actions = new ArrayList(actions); for (Iterator itr = actions.iterator(); itr.hasNext();) { @@ -518,11 +546,16 @@ public class Queue extends ResourceController implements Saveable { if (a==null) itr.remove(); } - for(QueueDecisionHandler h : QueueDecisionHandler.all()) - if (!h.shouldSchedule(p, actions)) - return ScheduleResult.refused(); // veto + lock.lock(); + try { try { + for (QueueDecisionHandler h : QueueDecisionHandler.all()) + if (!h.shouldSchedule(p, actions)) + return ScheduleResult.refused(); // veto - return scheduleInternal(p, quietPeriod, actions); + return scheduleInternal(p, quietPeriod, actions); + } finally { updateSnapshot(); } } finally { + lock.unlock(); + } } /** @@ -536,73 +569,70 @@ public class Queue extends ResourceController implements Saveable { * is that such {@link Item} only captures the state of the item at a particular moment, * and by the time you inspect the object, some of its information can be already stale. * - * That said, one can still look at {@link WaitingItem#future}, {@link WaitingItem#id}, etc. - */ - private synchronized @Nonnull ScheduleResult scheduleInternal(Task p, int quietPeriod, List actions) { - Calendar due = new GregorianCalendar(); - due.add(Calendar.SECOND, quietPeriod); - - // Do we already have this task in the queue? Because if so, we won't schedule a new one. - List duplicatesInQueue = new ArrayList(); - for(Item item : getItems(p)) { - boolean shouldScheduleItem = false; - for (QueueAction action: item.getActions(QueueAction.class)) { - shouldScheduleItem |= action.shouldSchedule(actions); - } - for (QueueAction action: Util.filter(actions,QueueAction.class)) { - shouldScheduleItem |= action.shouldSchedule((new ArrayList(item.getAllActions()))); - } - if(!shouldScheduleItem) { - duplicatesInQueue.add(item); - } - } - if (duplicatesInQueue.isEmpty()) { - LOGGER.log(Level.FINE, "{0} added to queue", p); - - // put the item in the queue - WaitingItem added = new WaitingItem(due,p,actions); - added.enter(this); - scheduleMaintenance(); // let an executor know that a new item is in the queue. - return ScheduleResult.created(added); - } + * That said, one can still look at {@link WaitingItem#future}, {@link WaitingItem#getId()}, etc. + */ + private @Nonnull ScheduleResult scheduleInternal(Task p, int quietPeriod, List actions) { + lock.lock(); + try { try { + Calendar due = new GregorianCalendar(); + due.add(Calendar.SECOND, quietPeriod); + + // Do we already have this task in the queue? Because if so, we won't schedule a new one. + List duplicatesInQueue = new ArrayList(); + for (Item item : liveGetItems(p)) { + boolean shouldScheduleItem = false; + for (QueueAction action : item.getActions(QueueAction.class)) { + shouldScheduleItem |= action.shouldSchedule(actions); + } + for (QueueAction action : Util.filter(actions, QueueAction.class)) { + shouldScheduleItem |= action.shouldSchedule((new ArrayList(item.getAllActions()))); + } + if (!shouldScheduleItem) { + duplicatesInQueue.add(item); + } + } + if (duplicatesInQueue.isEmpty()) { + LOGGER.log(Level.FINE, "{0} added to queue", p); + + // put the item in the queue + WaitingItem added = new WaitingItem(due, p, actions); + added.enter(this); + scheduleMaintenance(); // let an executor know that a new item is in the queue. + return ScheduleResult.created(added); + } - LOGGER.log(Level.FINE, "{0} is already in the queue", p); + LOGGER.log(Level.FINE, "{0} is already in the queue", p); - // but let the actions affect the existing stuff. - for(Item item : duplicatesInQueue) { - for(FoldableAction a : Util.filter(actions,FoldableAction.class)) { - a.foldIntoExisting(item, p, actions); + // but let the actions affect the existing stuff. + for (Item item : duplicatesInQueue) { + for (FoldableAction a : Util.filter(actions, FoldableAction.class)) { + a.foldIntoExisting(item, p, actions); + } } - } - boolean queueUpdated = false; - for(WaitingItem wi : Util.filter(duplicatesInQueue,WaitingItem.class)) { - if(quietPeriod<=0) { - // the user really wants to build now, and they mean NOW. - // so let's pull in the timestamp if we can. + boolean queueUpdated = false; + for (WaitingItem wi : Util.filter(duplicatesInQueue, WaitingItem.class)) { + // make sure to always use the shorter of the available due times if (wi.timestamp.before(due)) continue; - } else { - // otherwise we do the normal quiet period implementation - if (wi.timestamp.after(due)) - continue; - // quiet period timer reset. start the period over again - } - // waitingList is sorted, so when we change a timestamp we need to maintain order - wi.leave(this); - wi.timestamp = due; - wi.enter(this); - queueUpdated=true; - } + // waitingList is sorted, so when we change a timestamp we need to maintain order + wi.leave(this); + wi.timestamp = due; + wi.enter(this); + queueUpdated = true; + } - if (queueUpdated) scheduleMaintenance(); + if (queueUpdated) scheduleMaintenance(); - // REVISIT: when there are multiple existing items in the queue that matches the incoming one, - // whether the new one should affect all existing ones or not is debatable. I for myself - // thought this would only affect one, so the code was bit of surprise, but I'm keeping the current - // behaviour. - return ScheduleResult.existing(duplicatesInQueue.get(0)); + // REVISIT: when there are multiple existing items in the queue that matches the incoming one, + // whether the new one should affect all existing ones or not is debatable. I for myself + // thought this would only affect one, so the code was bit of surprise, but I'm keeping the current + // behaviour. + return ScheduleResult.existing(duplicatesInQueue.get(0)); + } finally { updateSnapshot(); } } finally { + lock.unlock(); + } } @@ -610,11 +640,12 @@ public class Queue extends ResourceController implements Saveable { * @deprecated as of 1.311 * Use {@link #schedule(Task, int)} */ - public synchronized boolean add(Task p, int quietPeriod) { + @Deprecated + public boolean add(Task p, int quietPeriod) { return schedule(p, quietPeriod)!=null; } - public synchronized @CheckForNull WaitingItem schedule(Task p, int quietPeriod) { + public @CheckForNull WaitingItem schedule(Task p, int quietPeriod) { return schedule(p, quietPeriod, new Action[0]); } @@ -622,21 +653,22 @@ public class Queue extends ResourceController implements Saveable { * @deprecated as of 1.311 * Use {@link #schedule(Task, int, Action...)} */ - public synchronized boolean add(Task p, int quietPeriod, Action... actions) { + @Deprecated + public boolean add(Task p, int quietPeriod, Action... actions) { return schedule(p, quietPeriod, actions)!=null; } /** * Convenience wrapper method around {@link #schedule(Task, int, List)} */ - public synchronized @CheckForNull WaitingItem schedule(Task p, int quietPeriod, Action... actions) { + public @CheckForNull WaitingItem schedule(Task p, int quietPeriod, Action... actions) { return schedule2(p, quietPeriod, actions).getCreateItem(); } /** * Convenience wrapper method around {@link #schedule2(Task, int, List)} */ - public synchronized @Nonnull ScheduleResult schedule2(Task p, int quietPeriod, Action... actions) { + public @Nonnull ScheduleResult schedule2(Task p, int quietPeriod, Action... actions) { return schedule2(p, quietPeriod, Arrays.asList(actions)); } @@ -646,27 +678,41 @@ public class Queue extends ResourceController implements Saveable { * @return true if the project was indeed in the queue and was removed. * false if this was no-op. */ - public synchronized boolean cancel(Task p) { - LOGGER.log(Level.FINE, "Cancelling {0}", p); - for (WaitingItem item : waitingList) { - if (item.task.equals(p)) { - return item.cancel(this); + public boolean cancel(Task p) { + lock.lock(); + try { try { + LOGGER.log(Level.FINE, "Cancelling {0}", p); + for (WaitingItem item : waitingList) { + if (item.task.equals(p)) { + return item.cancel(this); + } } + // use bitwise-OR to make sure that both branches get evaluated all the time + return blockedProjects.cancel(p) != null | buildables.cancel(p) != null; + } finally { updateSnapshot(); } } finally { + lock.unlock(); } - // use bitwise-OR to make sure that both branches get evaluated all the time - return blockedProjects.cancel(p)!=null | buildables.cancel(p)!=null; } - public synchronized boolean cancel(Item item) { + private void updateSnapshot() { + snapshot = new Snapshot(waitingList, blockedProjects, buildables, pendings); + } + + public boolean cancel(Item item) { LOGGER.log(Level.FINE, "Cancelling {0} item#{1}", new Object[] {item.task, item.id}); - return item.cancel(this); + lock.lock(); + try { try { + return item.cancel(this); + } finally { updateSnapshot(); } } finally { + lock.unlock(); + } } /** * Called from {@code queue.jelly} and {@code entries.jelly}. */ @RequirePOST - public HttpResponse doCancelItem(@QueryParameter int id) throws IOException, ServletException { + public HttpResponse doCancelItem(@QueryParameter long id) throws IOException, ServletException { Item item = getItem(id); if (item != null) { cancel(item); @@ -674,11 +720,13 @@ public class Queue extends ResourceController implements Saveable { return HttpResponses.forwardToPreviousPage(); } - public synchronized boolean isEmpty() { - return waitingList.isEmpty() && blockedProjects.isEmpty() && buildables.isEmpty() && pendings.isEmpty(); + public boolean isEmpty() { + Snapshot snapshot = this.snapshot; + return snapshot.waitingList.isEmpty() && snapshot.blockedProjects.isEmpty() && snapshot.buildables.isEmpty() + && snapshot.pendings.isEmpty(); } - private synchronized WaitingItem peek() { + private WaitingItem peek() { return waitingList.iterator().next(); } @@ -689,16 +737,72 @@ public class Queue extends ResourceController implements Saveable { * at the end. */ @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; + public Item[] getItems() { + Snapshot s = this.snapshot; + List r = new ArrayList(); + + for(WaitingItem p : s.waitingList) { + r = checkPermissionsAndAddToList(r, p); + } + for (BlockedItem p : s.blockedProjects){ + r = checkPermissionsAndAddToList(r, p); + } + for (BuildableItem p : reverse(s.buildables)) { + r = checkPermissionsAndAddToList(r, p); + } + for (BuildableItem p : reverse(s.pendings)) { + r= checkPermissionsAndAddToList(r, p); + } + Item[] items = new Item[r.size()]; + r.toArray(items); + return items; + } + + private List checkPermissionsAndAddToList(List r, Item t) { + if (t.task instanceof hudson.security.AccessControlled) { + if (((hudson.security.AccessControlled)t.task).hasPermission(hudson.model.Item.READ) + || ((hudson.security.AccessControlled) t.task).hasPermission(hudson.security.Permission.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 StubItem[] getDiscoverableItems() { + Snapshot s = this.snapshot; + List r = new ArrayList(); + + for(WaitingItem p : s.waitingList) { + r = filterDiscoverableItemListBasedOnPermissions(r, p); + } + for (BlockedItem p : s.blockedProjects){ + r = filterDiscoverableItemListBasedOnPermissions(r, p); + } + for (BuildableItem p : reverse(s.buildables)) { + r = filterDiscoverableItemListBasedOnPermissions(r, p); + } + for (BuildableItem p : reverse(s.pendings)) { + 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; } @@ -718,35 +822,51 @@ public class Queue extends ResourceController implements Saveable { * This method is primarily added to make UI threads run faster. * * @since 1.483 + * @deprecated Use {@link #getItems()} directly. As of 1.607 the approximation is no longer needed. */ + @Deprecated public List getApproximateItemsQuickly() { - return itemsView.get(); + return Arrays.asList(getItems()); } - public synchronized Item getItem(int id) { - for (Item item: waitingList) if (item.id == id) return item; - for (Item item: blockedProjects) if (item.id == id) return item; - for (Item item: buildables) if (item.id == id) return item; - for (Item item: pendings) if (item.id == id) return item; - + public Item getItem(long id) { + Snapshot snapshot = this.snapshot; + for (Item item : snapshot.blockedProjects) { + if (item.id == id) + return item; + } + for (Item item : snapshot.buildables) { + if (item.id == id) + return item; + } + for (Item item : snapshot.pendings) { + if (item.id == id) + return item; + } + for (Item item : snapshot.waitingList) { + if (item.id == id) { + return item; + } + } return leftItems.getIfPresent(id); } /** * Gets all the {@link BuildableItem}s that are waiting for an executor in the given {@link Computer}. */ - public synchronized List getBuildableItems(Computer c) { + public List getBuildableItems(Computer c) { + Snapshot snapshot = this.snapshot; List result = new ArrayList(); - _getBuildableItems(c, buildables, result); - _getBuildableItems(c, pendings, result); + _getBuildableItems(c, snapshot.buildables, result); + _getBuildableItems(c, snapshot.pendings, result); return result; } - private void _getBuildableItems(Computer c, ItemList col, List result) { + private void _getBuildableItems(Computer c, List col, List result) { Node node = c.getNode(); if (node == null) // Deleted computers cannot take build items... return; - for (BuildableItem p : col.values()) { + for (BuildableItem p : col) { if (node.canTake(p) == null) result.add(p); } @@ -755,19 +875,27 @@ public class Queue extends ResourceController implements Saveable { /** * Gets the snapshot of all {@link BuildableItem}s. */ - public synchronized List getBuildableItems() { - ArrayList r = new ArrayList(buildables.values()); - r.addAll(pendings.values()); + public List getBuildableItems() { + Snapshot snapshot = this.snapshot; + ArrayList r = new ArrayList(snapshot.buildables); + r.addAll(snapshot.pendings); return r; } /** * Gets the snapshot of all {@link BuildableItem}s. */ - public synchronized List getPendingItems() { - return new ArrayList(pendings.values()); + public List getPendingItems() { + return new ArrayList(snapshot.pendings); } + /** + * Gets the snapshot of all {@link BlockedItem}s. + */ + protected List getBlockedItems() { + return new ArrayList(snapshot.blockedProjects); + } + /** * Returns the snapshot of all {@link LeftItem}s. * @@ -791,11 +919,12 @@ public class Queue extends ResourceController implements Saveable { * * @since 1.402 */ - public synchronized List getUnblockedItems() { - List queuedNotBlocked = new ArrayList(); - queuedNotBlocked.addAll(waitingList); - queuedNotBlocked.addAll(buildables); - queuedNotBlocked.addAll(pendings); + public List getUnblockedItems() { + Snapshot snapshot = this.snapshot; + List queuedNotBlocked = new ArrayList(); + queuedNotBlocked.addAll(snapshot.waitingList); + queuedNotBlocked.addAll(snapshot.buildables); + queuedNotBlocked.addAll(snapshot.pendings); // but not 'blockedProjects' return queuedNotBlocked; } @@ -805,7 +934,7 @@ public class Queue extends ResourceController implements Saveable { * * @since 1.402 */ - public synchronized Set getUnblockedTasks() { + public Set getUnblockedTasks() { List items = getUnblockedItems(); Set unblockedTasks = new HashSet(items.size()); for (Queue.Item t : items) @@ -816,8 +945,9 @@ public class Queue extends ResourceController implements Saveable { /** * Is the given task currently pending execution? */ - public synchronized boolean isPending(Task t) { - for (BuildableItem i : pendings) + public boolean isPending(Task t) { + Snapshot snapshot = this.snapshot; + for (BuildableItem i : snapshot.pendings) if (i.task.equals(t)) return true; return false; @@ -825,16 +955,45 @@ public class Queue extends ResourceController implements Saveable { /** * How many {@link BuildableItem}s are assigned for the given label? + * @param l Label to be checked. If null, any label will be accepted. + * If you want to count {@link BuildableItem}s without assigned labels, + * use {@link #strictCountBuildableItemsFor(hudson.model.Label)}. + * @return Number of {@link BuildableItem}s for the specified label. */ - public synchronized int countBuildableItemsFor(Label l) { + public @Nonnegative int countBuildableItemsFor(@CheckForNull Label l) { + Snapshot snapshot = this.snapshot; int r = 0; - for (BuildableItem bi : buildables.values()) + for (BuildableItem bi : snapshot.buildables) for (SubTask st : bi.task.getSubTasks()) - if (null==l || bi.getAssignedLabelFor(st)==l) + if (null == l || bi.getAssignedLabelFor(st) == l) r++; - for (BuildableItem bi : pendings.values()) + for (BuildableItem bi : snapshot.pendings) for (SubTask st : bi.task.getSubTasks()) - if (null==l || bi.getAssignedLabelFor(st)==l) + if (null == l || bi.getAssignedLabelFor(st) == l) + r++; + return r; + } + + /** + * How many {@link BuildableItem}s are assigned for the given label? + *

+ * The implementation is quite similar to {@link #countBuildableItemsFor(hudson.model.Label)}, + * but it has another behavior for null parameters. + * @param l Label to be checked. If null, only jobs without assigned labels + * will be taken into the account. + * @return Number of {@link BuildableItem}s for the specified label. + * @since 1.615 + */ + public @Nonnegative int strictCountBuildableItemsFor(@CheckForNull Label l) { + Snapshot _snapshot = this.snapshot; + int r = 0; + for (BuildableItem bi : _snapshot.buildables) + for (SubTask st : bi.task.getSubTasks()) + if (bi.getAssignedLabelFor(st) == l) + r++; + for (BuildableItem bi : _snapshot.pendings) + for (SubTask st : bi.task.getSubTasks()) + if (bi.getAssignedLabelFor(st) == l) r++; return r; } @@ -842,7 +1001,7 @@ public class Queue extends ResourceController implements Saveable { /** * Counts all the {@link BuildableItem}s currently in the queue. */ - public synchronized int countBuildableItems() { + public int countBuildableItems() { return countBuildableItemsFor(null); } @@ -851,18 +1010,21 @@ public class Queue extends ResourceController implements Saveable { * * @return null if the project is not in the queue. */ - public synchronized Item getItem(Task t) { - BlockedItem bp = blockedProjects.get(t); - if (bp!=null) - return bp; - BuildableItem bi = buildables.get(t); - if(bi!=null) - return bi; - bi = pendings.get(t); - if(bi!=null) - return bi; - - for (Item item : waitingList) { + public Item getItem(Task t) { + Snapshot snapshot = this.snapshot; + for (Item item : snapshot.blockedProjects) { + if (item.task.equals(t)) + return item; + } + for (Item item : snapshot.buildables) { + if (item.task.equals(t)) + return item; + } + for (Item item : snapshot.pendings) { + if (item.task.equals(t)) + return item; + } + for (Item item : snapshot.waitingList) { if (item.task.equals(t)) { return item; } @@ -874,36 +1036,75 @@ public class Queue extends ResourceController implements Saveable { * Gets the information about the queue item for the given project. * * @return null if the project is not in the queue. + * @since 1.607 */ - public synchronized List getItems(Task t) { - List result =new ArrayList(); - result.addAll(blockedProjects.getAll(t)); - result.addAll(buildables.getAll(t)); - result.addAll(pendings.getAll(t)); - for (Item item : waitingList) { - if (item.task.equals(t)) { - result.add(item); + private List liveGetItems(Task t) { + lock.lock(); + try { + List result = new ArrayList(); + result.addAll(blockedProjects.getAll(t)); + result.addAll(buildables.getAll(t)); + result.addAll(pendings.getAll(t)); + for (Item item : waitingList) { + if (item.task.equals(t)) { + result.add(item); + } } + return result; + } finally { + lock.unlock(); } - return result; } /** - * Left for backward compatibility. + * Gets the information about the queue item for the given project. * - * @see #getItem(Task) - public synchronized Item getItem(AbstractProject p) { - return getItem((Task) p); - } + * @return null if the project is not in the queue. */ + public List getItems(Task t) { + Snapshot snapshot = this.snapshot; + List result = new ArrayList(); + for (Item item : snapshot.blockedProjects) { + if (item.task.equals(t)) { + result.add(item); + } + } + for (Item item : snapshot.buildables) { + if (item.task.equals(t)) { + result.add(item); + } + } + for (Item item : snapshot.pendings) { + if (item.task.equals(t)) { + result.add(item); + } + } + for (Item item : snapshot.waitingList) { + if (item.task.equals(t)) { + result.add(item); + } + } + return result; + } /** * Returns true if this queue contains the said project. */ - public synchronized boolean contains(Task t) { - if (blockedProjects.containsKey(t) || buildables.containsKey(t) || pendings.containsKey(t)) - return true; - for (Item item : waitingList) { + public boolean contains(Task t) { + final Snapshot snapshot = this.snapshot; + for (Item item : snapshot.blockedProjects) { + if (item.task.equals(t)) + return true; + } + for (Item item : snapshot.buildables) { + if (item.task.equals(t)) + return true; + } + for (Item item : snapshot.pendings) { + if (item.task.equals(t)) + return true; + } + for (Item item : snapshot.waitingList) { if (item.task.equals(t)) { return true; } @@ -916,12 +1117,17 @@ public class Queue extends ResourceController implements Saveable { * * This moves the task from the pending state to the "left the queue" state. */ - /*package*/ synchronized void onStartExecuting(Executor exec) throws InterruptedException { - final WorkUnit wu = exec.getCurrentWorkUnit(); - pendings.remove(wu.context.item); + /*package*/ void onStartExecuting(Executor exec) throws InterruptedException { + lock.lock(); + try { try { + final WorkUnit wu = exec.getCurrentWorkUnit(); + pendings.remove(wu.context.item); - LeftItem li = new LeftItem(wu.context); - li.enter(this); + LeftItem li = new LeftItem(wu.context); + li.enter(this); + } finally { updateSnapshot(); } } finally { + lock.unlock(); + } } /** @@ -985,7 +1191,7 @@ 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 + * Some operations require the {@link Queue} lock held. Use one of these methods rather * than locking directly on Queue in order to allow for future refactoring. * * @param callable the operation to perform. @@ -1025,14 +1231,102 @@ public class Queue extends ResourceController implements Saveable { } } + /** + * Invokes the supplied {@link Runnable} if the {@link Queue} lock was obtained without blocking. + * + * @param runnable the operation to perform. + * @return {@code true} if the lock was available and the operation was performed. + * @since 1.618 + */ + 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.618 + */ + 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.618 + */ + 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.618 + */ + 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(); + } + + @Override + protected void _signalAll() { + condition.signalAll(); + } + /** * 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. * @since 1.592 */ - protected synchronized void _withLock(Runnable runnable) { - runnable.run(); + protected void _withLock(Runnable runnable) { + lock.lock(); + try { + runnable.run(); + } finally { + lock.unlock(); + } + } + + /** + * Invokes the supplied {@link Runnable} if the {@link Queue} lock was obtained without blocking. + * + * @param runnable the operation to perform. + * @return {@code true} if the lock was available and the operation was performed. + * @since 1.618 + */ + protected boolean _tryWithLock(Runnable runnable) { + if (lock.tryLock()) { + try { + runnable.run(); + } finally { + lock.unlock(); + } + return true; + } else { + return false; + } } /** @@ -1046,8 +1340,13 @@ public class Queue extends ResourceController implements Saveable { * @throws T the exception of the callable * @since 1.592 */ - protected synchronized V _withLock(hudson.remoting.Callable callable) throws T { - return callable.call(); + protected V _withLock(hudson.remoting.Callable callable) throws T { + lock.lock(); + try { + return callable.call(); + } finally { + lock.unlock(); + } } /** @@ -1060,8 +1359,13 @@ public class Queue extends ResourceController implements Saveable { * @throws Exception if the callable throws an exception. * @since 1.592 */ - protected synchronized V _withLock(java.util.concurrent.Callable callable) throws Exception { - return callable.call(); + protected V _withLock(java.util.concurrent.Callable callable) throws Exception { + lock.lock(); + try { + return callable.call(); + } finally { + lock.unlock(); + } } /** @@ -1076,98 +1380,193 @@ public class Queue extends ResourceController implements Saveable { * the scheduling (such as new node becoming online, # of executors change, a task completes execution, etc.), * and it also gets invoked periodically (see {@link Queue.MaintainTask}.) */ - public synchronized void maintain() { - LOGGER.log(Level.FINE, "Queue maintenance started {0}", this); - - // The executors that are currently waiting for a job to run. - Map parked = new HashMap(); - - {// update parked - for (Computer c : Jenkins.getInstance().getComputers()) { - for (Executor e : c.getExecutors()) { - if (e.isParking()) { - parked.put(e,new JobOffer(e)); + public void maintain() { + lock.lock(); + try { try { + + LOGGER.log(Level.FINE, "Queue maintenance started {0}", this); + + // The executors that are currently waiting for a job to run. + Map parked = new HashMap(); + + {// update parked (and identify any pending items whose executor has disappeared) + 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. + 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(); + if (workUnit != null) { + lostPendings.remove(workUnit.context.item); + } } } + // pending -> buildable + for (BuildableItem p: lostPendings) { + LOGGER.log(Level.INFO, + "BuildableItem {0}: pending -> buildable as the assigned executor disappeared", + p.task.getFullDisplayName()); + p.isPending = false; + pendings.remove(p); + makeBuildable(p); + } } - } + final QueueSorter s = sorter; - {// blocked -> buildable - for (BlockedItem p : new ArrayList(blockedProjects.values())) {// copy as we'll mutate the list - if (!isBuildBlocked(p) && allowNewBuildableTask(p.task)) { - // ready to be executed - Runnable r = makeBuildable(new BuildableItem(p)); - if (r != null) { - p.leave(this); - r.run(); + {// blocked -> buildable + // copy as we'll mutate the list and we want to process in a potentially different order + 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) { + String taskDisplayName = p.task.getFullDisplayName(); + LOGGER.log(Level.FINEST, "Current blocked item: {0}", taskDisplayName); + if (!isBuildBlocked(p) && allowNewBuildableTask(p.task)) { + LOGGER.log(Level.FINEST, + "BlockedItem {0}: blocked -> buildable as the build is not blocked and new tasks are allowed", + taskDisplayName); + + // 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(); + } } } } - } - // waitingList -> buildable/blocked - while (!waitingList.isEmpty()) { - WaitingItem top = peek(); + // waitingList -> buildable/blocked + while (!waitingList.isEmpty()) { + WaitingItem top = peek(); - if (top.timestamp.compareTo(new GregorianCalendar())>0) - break; // finished moving all ready items from queue + if (top.timestamp.compareTo(new GregorianCalendar()) > 0) { + LOGGER.log(Level.FINEST, "Finished moving all ready items from queue."); + break; // finished moving all ready items from queue + } - top.leave(this); - Task p = top.task; - if (!isBuildBlocked(top) && allowNewBuildableTask(p)) { - // ready to be executed immediately - Runnable r = makeBuildable(new BuildableItem(top)); - if (r != null) { - r.run(); + top.leave(this); + Task p = top.task; + 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.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); + new BlockedItem(top).enter(this); + } } else { + // this can't be built now because another build is in progress + // set this project aside. new BlockedItem(top).enter(this); } - } else { - // this can't be built now because another build is in progress - // set this project aside. - new BlockedItem(top).enter(this); } - } - final QueueSorter s = sorter; - if (s != null) - s.sortBuildableItems(buildables); + if (s != null) + s.sortBuildableItems(buildables); + + // Ensure that identification of blocked tasks is using the live state: JENKINS-27708 & JENKINS-27871 + updateSnapshot(); + + // allocate buildable jobs to executors + for (BuildableItem p : new ArrayList( + buildables)) {// copy as we'll mutate the list in the loop + // one last check to make sure this build is not blocked. + if (isBuildBlocked(p)) { + 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; + } - // allocate buildable jobs to executors - for (BuildableItem p : new ArrayList(buildables)) {// copy as we'll mutate the list in the loop - // one last check to make sure this build is not blocked. - if (isBuildBlocked(p)) { - p.leave(this); - new BlockedItem(p).enter(this); - LOGGER.log(Level.FINE, "Catching that {0} is blocked in the last minute", p); - continue; - } + String taskDisplayName = p.task.getFullDisplayName(); - List candidates = new ArrayList(parked.size()); - for (JobOffer j : parked.values()) - if (j.canTake(p)) - candidates.add(j); - - MappingWorksheet ws = new MappingWorksheet(p, candidates); - Mapping m = loadBalancer.map(p.task, ws); - if (m == null) { - // if we couldn't find the executor that fits, - // just leave it in the buildables list and - // check if we can execute other projects - LOGGER.log(Level.FINER, "Failed to map {0} to executors. candidates={1} parked={2}", new Object[]{p, candidates, parked.values()}); - continue; - } + 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}", taskDisplayName); + r.run(); + updateSnapshot(); + } + } else { - // found a matching executor. use it. - WorkUnitContext wuc = new WorkUnitContext(p); - m.execute(wuc); + List candidates = new ArrayList(parked.size()); + for (JobOffer j : parked.values()) { + if (j.canTake(p)) { + LOGGER.log(Level.FINEST, + "{0} is a potential candidate for task {1}", + new Object[]{j.executor.getDisplayName(), taskDisplayName}); + candidates.add(j); + } + } - p.leave(this); - if (!wuc.getWorkUnits().isEmpty()) - makePending(p); - else - LOGGER.log(Level.FINE, "BuildableItem {0} with empty work units!?", p); + MappingWorksheet ws = new MappingWorksheet(p, candidates); + Mapping m = loadBalancer.map(p.task, ws); + if (m == null) { + // if we couldn't find the executor that fits, + // just leave it in the buildables list and + // check if we can execute other projects + LOGGER.log(Level.FINER, "Failed to map {0} to executors. candidates={1} parked={2}", + new Object[]{p, candidates, parked.values()}); + continue; + } + + // found a matching executor. use it. + WorkUnitContext wuc = new WorkUnitContext(p); + 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.FINEST, "BuildableItem {0} marked as pending.", taskDisplayName); + makePending(p); + } + else + 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 + // job execution. You probably would need 100's of jobs starting execution every iteration + // of maintain() before this could even start to become an issue and likely the calculation + // of isBuildBlocked(p) will become a bottleneck before updateSnapshot() will. Additionally + // since the snapshot itself only ever has at most one reference originating outside of the stack + // it should remain in the eden space and thus be cheap to GC. + // See https://issues.jenkins-ci.org/browse/JENKINS-27708?focusedCommentId=225819&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-225819 + // or https://issues.jenkins-ci.org/browse/JENKINS-27708?focusedCommentId=225906&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-225906 + // for alternative fixes of this issue. + updateSnapshot(); + } + } + } finally { updateSnapshot(); } } finally { + lock.unlock(); } } @@ -1178,9 +1577,42 @@ 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.FINEST, "Converting flyweight task: {0} into a BuildableRunnable", taskDisplayName); + if(runnable != null){ + return runnable; + } + + //this is to solve JENKINS-30084: the task has to be buildable to force the provisioning of nodes. + //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.", 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.FINEST, "Task {0} is blocked by shutdown.", taskDisplayName); + return null; + } else { + // regular heavyweight task + return new BuildableRunnable(p); + } + } + + /** + * This method checks if the flyweight task can be run on any of the available executors + * @param p - the flyweight task to be scheduled + * @return a Runnable if there is an executor that can take the task, null otherwise + */ + @CheckForNull + private Runnable makeFlyWeightTaskBuildable(final BuildableItem p){ + //we double check if this is a flyweight task + if (p.task instanceof FlyweightTask) { Jenkins h = Jenkins.getInstance(); - Map hashSource = new HashMap(h.getNodes().size()); + Map hashSource = new HashMap(h.getNodes().size()); // Even if master is configured with zero executors, we may need to run a flyweight task like MatrixProject on it. hashSource.put(h, Math.max(h.getNumExecutors() * 100, 1)); @@ -1195,9 +1627,17 @@ public class Queue extends ResourceController implements Saveable { Label lbl = p.getAssignedLabel(); for (Node n : hash.list(p.task.getFullDisplayName())) { final Computer c = n.toComputer(); - if (c==null || c.isOffline()) continue; - if (lbl!=null && !lbl.contains(n)) continue; - if (n.canTake(p) != null) continue; + if (c == null || c.isOffline()) { + continue; + } + if (lbl!=null && !lbl.contains(n)) { + continue; + } + if (n.canTake(p) != null) { + continue; + } + + 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)); @@ -1205,19 +1645,10 @@ public class Queue extends ResourceController implements Saveable { } }; } - } - // if the execution get here, it means we couldn't schedule it anywhere. - return null; - } else { // regular heavyweight task - return new Runnable() { - @Override public void run() { - p.enter(Queue.this); - } - }; } + return null; } - private static Hash NODE_HASH = new Hash() { public String hash(Node node) { return node.getNodeName(); @@ -1231,6 +1662,7 @@ public class Queue extends ResourceController implements Saveable { } /** @deprecated Use {@link #isBlockedByShutdown} instead. */ + @Deprecated public static boolean ifBlockedByHudsonShutdown(Task task) { return isBlockedByShutdown(task); } @@ -1289,6 +1721,10 @@ public class Queue extends ResourceController implements Saveable { * compatibility with future changes to this interface. * *

+ * Plugins are encouraged to implement {@link AccessControlled} otherwise + * the tasks will be hidden from display in the queue. + * + *

* For historical reasons, {@link Task} object by itself * also represents the "primary" sub-task (and as implied by this * design, a {@link Task} must have at least one sub-task.) @@ -1308,6 +1744,7 @@ public class Queue extends ResourceController implements Saveable { * @deprecated as of 1.330 * Use {@link CauseOfBlockage#getShortDescription()} instead. */ + @Deprecated String getWhyBlocked(); /** @@ -1339,6 +1776,9 @@ public class Queue extends ResourceController implements Saveable { /** * Checks the permission to see if the current user can abort this executable. * Returns normally from this method if it's OK. + *

+ * NOTE: If you have implemented {@link AccessControlled} this should just be + * {@code checkPermission(hudson.model.Item.CANCEL);} * * @throws AccessDeniedException if the permission is not granted. */ @@ -1348,6 +1788,12 @@ public class Queue extends ResourceController implements Saveable { * Works just like {@link #checkAbortPermission()} except it indicates the status by a return value, * instead of exception. * Also used by default for {@link hudson.model.Queue.Item#hasCancelPermission}. + *

+ * NOTE: If you have implemented {@link AccessControlled} this should just be + * {@code return hasPermission(hudson.model.Item.CANCEL);} + * + * @return false + * if the user doesn't have the permission. */ boolean hasAbortPermission(); @@ -1449,9 +1895,10 @@ public class Queue extends ResourceController implements Saveable { @Nonnull SubTask getParent(); /** - * Called by {@link Executor} to perform the task + * Called by {@link Executor} to perform the task. + * @throws AsynchronousExecution if you would like to continue without consuming a thread */ - void run(); + @Override void run() throws AsynchronousExecution; /** * Estimate of how long will it take to execute this executable. @@ -1476,12 +1923,32 @@ public class Queue extends ResourceController implements Saveable { */ @ExportedBean(defaultVisibility = 999) public static abstract class Item extends Actionable { + + private final long id; + /** - * VM-wide unique ID that tracks the {@link Task} as it moves through different stages - * in the queue (each represented by different subtypes of {@link Item}. + * Unique ID (per master) that tracks the {@link Task} as it moves through different stages + * in the queue (each represented by different subtypes of {@link Item} and into any subsequent + * {@link Run} instance (see {@link Run#getQueueId()}). + * @return + * @since 1.601 */ @Exported - public final int id; + public long getId() { + return id; + } + + @AdaptField(was=int.class, name="id") + @Deprecated + public int getIdLegacy() { + if (id > Integer.MAX_VALUE) { + throw new IllegalStateException("Sorry, you need to update any Plugins attempting to " + + "assign 'Queue.Item.id' to an int value. 'Queue.Item.id' is now a long value and " + + "has incremented to a value greater than Integer.MAX_VALUE (2^31 - 1)."); + } + return (int) id; + } + /** * Project to be built. @@ -1536,7 +2003,7 @@ public class Queue extends ResourceController implements Saveable { /** * Can be used to wait for the completion (either normal, abnormal, or cancellation) of the {@link Task}. *

- * Just like {@link #id}, the same object tracks various stages of the queue. + * Just like {@link #getId()}, the same object tracks various stages of the queue. */ @WithBridgeMethods(Future.class) public QueueTaskFuture getFuture() { return future; } @@ -1558,13 +2025,16 @@ public class Queue extends ResourceController implements Saveable { } /** - * Test if the specified {@link SubTask} needs to be run on a node with a particular label, and - * return that {@link Label}. Otherwise null, indicating it can run on anywhere. - * + * Test if the specified {@link SubTask} needs to be run on a node with a particular label. *

- * This code takes {@link LabelAssignmentAction} into account, then falls back to {@link SubTask#getAssignedLabel()} + * This method takes {@link LabelAssignmentAction} into account, the first + * non-null assignment will be returned. + * Otherwise falls back to {@link SubTask#getAssignedLabel()} + * @param st {@link SubTask} to be checked. + * @return Required {@link Label}. Otherwise null, indicating it can run on anywhere. + */ - public Label getAssignedLabelFor(SubTask st) { + public @CheckForNull Label getAssignedLabelFor(@Nonnull SubTask st) { for (LabelAssignmentAction laa : getActions(LabelAssignmentAction.class)) { Label l = laa.getAssignedLabel(st); if (l!=null) return l; @@ -1595,7 +2065,7 @@ public class Queue extends ResourceController implements Saveable { return s.toString(); } - protected Item(Task task, List actions, int id, FutureImpl future) { + protected Item(Task task, List actions, long id, FutureImpl future) { this.task = task; this.id = id; this.future = future; @@ -1603,7 +2073,7 @@ public class Queue extends ResourceController implements Saveable { for (Action action: actions) addAction(action); } - protected Item(Task task, List actions, int id, FutureImpl future, long inQueueSince) { + protected Item(Task task, List actions, long id, FutureImpl future, long inQueueSince) { this.task = task; this.id = id; this.future = future; @@ -1746,6 +2216,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. * Lets the action cooperate in queue management. @@ -1796,7 +2302,7 @@ public class Queue extends ResourceController implements Saveable { * {@link Item} in the {@link Queue#waitingList} stage. */ public static final class WaitingItem extends Item implements Comparable { - private static final AtomicInteger COUNTER = new AtomicInteger(0); + private static final AtomicLong COUNTER = new AtomicLong(0); /** * This item can be run after this time. @@ -1809,11 +2315,21 @@ public class Queue extends ResourceController implements Saveable { this.timestamp = timestamp; } + static int getCurrentCounterValue() { + return COUNTER.intValue(); + } + public int compareTo(WaitingItem that) { int r = this.timestamp.getTime().compareTo(that.timestamp.getTime()); if (r != 0) return r; - return this.id - that.id; + if (this.getId() < that.getId()) { + return -1; + } else if (this.getId() == that.getId()) { + return 0; + } else { + return 1; + } } public CauseOfBlockage getCauseOfBlockage() { @@ -2081,7 +2597,7 @@ public class Queue extends ResourceController implements Saveable { @Override void enter(Queue q) { - q.leftItems.put(id,this); + q.leftItems.put(getId(),this); for (QueueListener ql : QueueListener.all()) { try { ql.onLeft(this); @@ -2265,6 +2781,80 @@ public class Queue extends ResourceController implements Saveable { } } + private static class Snapshot { + private final Set waitingList; + private final List blockedProjects; + private final List buildables; + private final List pendings; + + public Snapshot(Set waitingList, List blockedProjects, List buildables, + List pendings) { + this.waitingList = new LinkedHashSet(waitingList); + this.blockedProjects = new ArrayList(blockedProjects); + this.buildables = new ArrayList(buildables); + 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 class BuildableRunnable implements Runnable { + private final BuildableItem buildableItem; + + private BuildableRunnable(BuildableItem p) { + this.buildableItem = p; + } + + @Override + public void run() { + //the flyweighttask enters the buildables queue and will ask Jenkins to provision a node + buildableItem.enter(Queue.this); + } + } + + 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() { return Jenkins.getInstance().getQueue(); diff --git a/core/src/main/java/hudson/model/Resource.java b/core/src/main/java/hudson/model/Resource.java index e92287f8145c379c009b77462ffc51d7da9aa63a..caef6428bc5006669e0a63b23cdc758085b5d65a 100644 --- a/core/src/main/java/hudson/model/Resource.java +++ b/core/src/main/java/hudson/model/Resource.java @@ -25,7 +25,6 @@ package hudson.model; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; -import javax.annotation.Nullable; /** * Represents things that {@link hudson.model.Queue.Executable} uses while running. diff --git a/core/src/main/java/hudson/model/ResourceController.java b/core/src/main/java/hudson/model/ResourceController.java index d1239f3eec5147ff76d3ebc0d11f8277ecb59bd4..b47f62f72099ce699ff236eee965f7c6db1f0af6 100644 --- a/core/src/main/java/hudson/model/ResourceController.java +++ b/core/src/main/java/hudson/model/ResourceController.java @@ -1,18 +1,18 @@ /* * 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 @@ -29,6 +29,7 @@ import java.util.Set; import java.util.Collection; import java.util.AbstractCollection; import java.util.Iterator; +import java.util.concurrent.Callable; import java.util.concurrent.CopyOnWriteArraySet; import javax.annotation.Nonnull; @@ -61,7 +62,7 @@ public class ResourceController { /** * Union of all {@link Resource}s that are currently in use. - * Updated as a task starts/completes executing. + * Updated as a task starts/completes executing. */ private ResourceList inUse = ResourceList.EMPTY; @@ -74,25 +75,37 @@ public class ResourceController { * @throws InterruptedException * the thread can be interrupted while waiting for the available resources. */ - public void execute(@Nonnull Runnable task, ResourceActivity activity ) throws InterruptedException { - ResourceList resources = activity.getResourceList(); - synchronized(this) { - while(inUse.isCollidingWith(resources)) - wait(); - - // we have a go - inProgress.add(activity); - inUse = ResourceList.union(inUse,resources); - } + public void execute(@Nonnull Runnable task, final ResourceActivity activity ) throws InterruptedException { + final ResourceList resources = activity.getResourceList(); + _withLock(new Runnable() { + @Override + public void run() { + while(inUse.isCollidingWith(resources)) + try { + // TODO revalidate the resource list after re-acquiring lock, for now we just let the build fail + _await(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + // we have a go + inProgress.add(activity); + inUse = ResourceList.union(inUse,resources); + } + }); try { task.run(); } finally { - synchronized(this) { - inProgress.remove(activity); - inUse = ResourceList.union(resourceView); - notifyAll(); - } + // TODO if AsynchronousExecution, do that later + _withLock(new Runnable() { + @Override + public void run() { + inProgress.remove(activity); + inUse = ResourceList.union(resourceView); + _signalAll(); + } + }); } } @@ -105,8 +118,17 @@ public class ResourceController { * another activity might acquire resources before the caller * gets to call {@link #execute(Runnable, ResourceActivity)}. */ - public synchronized boolean canRun(ResourceList resources) { - return !inUse.isCollidingWith(resources); + public boolean canRun(final ResourceList resources) { + try { + return _withLock(new Callable() { + @Override + public Boolean call() { + return !inUse.isCollidingWith(resources); + } + }); + } catch (Exception e) { + throw new IllegalStateException("Inner callable does not throw exception"); + } } /** @@ -117,8 +139,17 @@ public class ResourceController { * If more than one such resource exists, one is chosen and returned. * This method is used for reporting what's causing the blockage. */ - public synchronized Resource getMissingResource(ResourceList resources) { - return resources.getConflict(inUse); + public Resource getMissingResource(final ResourceList resources) { + try { + return _withLock(new Callable() { + @Override + public Resource call() { + return resources.getConflict(inUse); + } + }); + } catch (Exception e) { + throw new IllegalStateException("Inner callable does not throw exception"); + } } /** @@ -133,5 +164,25 @@ public class ResourceController { return a; return null; } + + protected void _await() throws InterruptedException { + wait(); + } + + protected void _signalAll() { + notifyAll(); + } + + protected void _withLock(Runnable runnable) { + synchronized (this) { + runnable.run(); + } + } + + protected V _withLock(java.util.concurrent.Callable callable) throws Exception { + synchronized (this) { + return callable.call(); + } + } } diff --git a/core/src/main/java/hudson/model/RestartListener.java b/core/src/main/java/hudson/model/RestartListener.java index 524dcfc20eb0552510cdb21ecbf146ba8a3b2c68..062ad1a8787e23d77fc7e47874ba11785e7f70f1 100644 --- a/core/src/main/java/hudson/model/RestartListener.java +++ b/core/src/main/java/hudson/model/RestartListener.java @@ -6,6 +6,7 @@ import hudson.ExtensionPoint; import jenkins.model.Jenkins; import java.io.IOException; +import jenkins.model.queue.AsynchronousExecution; /** * Extension point that allows plugins to veto the restart. @@ -46,12 +47,39 @@ public abstract class RestartListener implements ExtensionPoint { /** * Default logic. Wait for all the executors to become idle. + * @see AsynchronousExecution#blocksRestart */ @Extension public static class Default extends RestartListener { @Override public boolean isReadyToRestart() throws IOException, InterruptedException { - return new ComputerSet().getBusyExecutors() == 0; + for (Computer c : Jenkins.getInstance().getComputers()) { + if (c.isOnline()) { + for (Executor e : c.getExecutors()) { + if (blocksRestart(e)) { + return false; + } + } + for (Executor e : c.getOneOffExecutors()) { + if (blocksRestart(e)) { + return false; + } + } + } + } + return true; + } + private static boolean blocksRestart(Executor e) { + if (e.isBusy()) { + AsynchronousExecution execution = e.getAsynchronousExecution(); + if (execution != null) { + return execution.blocksRestart(); + } else { + return true; + } + } else { + return false; + } } } } diff --git a/core/src/main/java/hudson/model/Result.java b/core/src/main/java/hudson/model/Result.java index b17a98a4cf5b11d45b5ea56ac6d83ed2b4e1c656..02e71f3ff3ff89e8d81adc832eaa72054053e432 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); } diff --git a/core/src/main/java/hudson/model/Run.java b/core/src/main/java/hudson/model/Run.java index 8686716dce1352db3c2e07fb04a7b1ca41225f23..c4f64ccade01e20f12bf0274cc113b79229cc510 100644 --- a/core/src/main/java/hudson/model/Run.java +++ b/core/src/main/java/hudson/model/Run.java @@ -39,15 +39,12 @@ 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; import hudson.model.listeners.SaveableListener; -import hudson.model.queue.SubTask; +import hudson.model.queue.Executables; import hudson.search.SearchIndexBuilder; import hudson.security.ACL; import hudson.security.AccessControlled; @@ -55,7 +52,6 @@ import hudson.security.Permission; import hudson.security.PermissionGroup; import hudson.security.PermissionScope; import hudson.tasks.BuildWrapper; -import hudson.util.FlushProofOutputStream; import hudson.util.FormApply; import hudson.util.LogTaskListener; import hudson.util.ProcessTree; @@ -72,7 +68,6 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.io.Reader; import java.io.StringWriter; -import java.io.Writer; import java.nio.charset.Charset; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -108,7 +103,6 @@ import jenkins.model.PeepholePermalink; import jenkins.model.RunAction2; import jenkins.model.StandardArtifactManager; import jenkins.model.lazy.BuildReference; -import jenkins.model.lazy.LazyBuildMixIn; import jenkins.util.VirtualFile; import jenkins.util.io.OnMaster; import net.sf.json.JSONObject; @@ -138,6 +132,12 @@ import org.kohsuke.stapler.interceptor.RequirePOST; public abstract class Run ,RunT extends Run> extends Actionable implements ExtensionPoint, Comparable, AccessControlled, PersistenceRoot, DescriptorByNameOwner, OnMaster { + /** + * The original {@link Queue.Item#getId()} has not yet been mapped onto the {@link Run} instance. + * @since 1.601 + */ + public static final long QUEUE_ID_UNKNOWN = -1; + protected transient final @Nonnull JobT project; /** @@ -149,6 +149,11 @@ public abstract class Run ,RunT extends Run,RunT extends Run + * Mapped from the {@link Queue.Item#getId()}. + * @param queueId The queue item ID. + */ + @Restricted(NoExternalUse.class) + public void setQueueId(long queueId) { + this.queueId = queueId; + } + /** * Returns the build result. * @@ -480,25 +507,11 @@ public abstract class Run ,RunT extends Run,RunT extends Run,RunT extends Run,RunT extends Run,RunT extends Run,RunT extends Run,RunT extends Run,RunT extends Run,RunT extends Run,RunT extends Run,RunT extends Run getLog(int maxLines) throws IOException { int lineCount = 0; List logLines = new LinkedList(); + if (maxLines == 0) { + return logLines; + } BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(getLogFile()),getCharset())); try { for (String line = reader.readLine(); line != null; line = reader.readLine()) { @@ -2068,19 +2081,13 @@ public abstract class Run ,RunT extends Run,RunT extends Run,RunT extends Run getEnvVars() { LOGGER.log(WARNING, "deprecated call to Run.getEnvVars\n\tat {0}", new Throwable().getStackTrace()[1]); try { @@ -2191,6 +2200,7 @@ public abstract class Run ,RunT extends Run> extends AbstractLazyLoadRunMap * @deprecated as of 1.485 * Use {@link #RunMap(File, Constructor)}. */ + @Deprecated public RunMap() { super(null); // will be set later } @@ -152,6 +152,7 @@ public final class RunMap> extends AbstractLazyLoadRunMap * @deprecated as of 1.485 * Use {@link ReverseComparator} */ + @Deprecated public static final Comparator COMPARATOR = new Comparator() { public int compare(Comparable o1, Comparable o2) { return -o1.compareTo(o2); @@ -184,9 +185,11 @@ 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()); } - proposeNewNumber(r.getNumber()); rootDir.mkdirs(); return super._put(r); } @@ -227,6 +230,8 @@ public final class RunMap> extends AbstractLazyLoadRunMap LOGGER.log(Level.WARNING, "could not load " + d, e); } catch (InstantiationError e) { LOGGER.log(Level.WARNING, "could not load " + d, e); + } catch (Exception e) { + LOGGER.log(Level.WARNING, "could not load " + d, e); } } return null; @@ -245,6 +250,7 @@ public final class RunMap> extends AbstractLazyLoadRunMap * @deprecated as of 1.485 * Use {@link #RunMap(File, Constructor)} */ + @Deprecated public void load(Job job, Constructor cons) { this.cons = cons; initBaseDir(job.getBuildDir()); diff --git a/core/src/main/java/hudson/model/RunParameterDefinition.java b/core/src/main/java/hudson/model/RunParameterDefinition.java index a1ad6879e240d57bd5663afc26289fba330313c3..07195499d6688d8e509aebcb25c99a8a9f84a1ae 100644 --- a/core/src/main/java/hudson/model/RunParameterDefinition.java +++ b/core/src/main/java/hudson/model/RunParameterDefinition.java @@ -74,6 +74,7 @@ public class RunParameterDefinition extends SimpleParameterDefinition { /** * @deprecated as of 1.517 */ + @Deprecated public RunParameterDefinition(String name, String projectName, String description) { // delegate to updated constructor with additional RunParameterFilter parameter defaulted to ALL. this(name, projectName, description, RunParameterFilter.ALL); diff --git a/core/src/main/java/hudson/model/SCMedItem.java b/core/src/main/java/hudson/model/SCMedItem.java index ef4ae60d94527b3cc5dd285ac72dc92d9d96433e..142e4f51535d2b09580ae7ea2e9b27cb1bf8ad71 100644 --- a/core/src/main/java/hudson/model/SCMedItem.java +++ b/core/src/main/java/hudson/model/SCMedItem.java @@ -30,6 +30,7 @@ import jenkins.triggers.SCMTriggerItem; /** * @deprecated Implement {@link SCMTriggerItem} instead. */ +@Deprecated public interface SCMedItem extends BuildableItem { /** * Gets the {@link SCM} for this item. @@ -55,6 +56,7 @@ public interface SCMedItem extends BuildableItem { * @deprecated as of 1.346 * Use {@link #poll(TaskListener)} instead. */ + @Deprecated boolean pollSCMChanges( TaskListener listener ); /** diff --git a/core/src/main/java/hudson/model/Saveable.java b/core/src/main/java/hudson/model/Saveable.java index a27d35e27dd235b0341280545bf5838ccb8893a6..79e361cc26ae7b501905b5fe3293b048c868940f 100644 --- a/core/src/main/java/hudson/model/Saveable.java +++ b/core/src/main/java/hudson/model/Saveable.java @@ -24,7 +24,6 @@ package hudson.model; import hudson.BulkChange; -import hudson.model.listeners.SaveableListener; import java.io.IOException; /** diff --git a/core/src/main/java/hudson/model/Slave.java b/core/src/main/java/hudson/model/Slave.java index 92ac16518d1b07f29ca8d8a86d13c86aa7f67f79..d9dcf85a77c475f51d104d4eb9f5a781c78f1e88 100644 --- a/core/src/main/java/hudson/model/Slave.java +++ b/core/src/main/java/hudson/model/Slave.java @@ -1,19 +1,19 @@ /* * The MIT License - * + * * Copyright (c) 2004-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi, * Erik Ramfelt, Martin Eigenbrodt, Stephen Connolly, Tom Huybrechts - * + * * 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 @@ -24,6 +24,7 @@ */ package hudson.model; +import com.google.common.collect.ImmutableSet; import hudson.FilePath; import hudson.Launcher; import hudson.Util; @@ -51,8 +52,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; @@ -63,6 +66,7 @@ import jenkins.security.MasterToSlaveCallable; import jenkins.slaves.WorkspaceLocator; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; @@ -92,8 +96,12 @@ public abstract class Slave extends Node implements Serializable { private final String description; /** - * Absolute path to the root of the workspace - * from the view point of this node, such as "/hudson" + * Path to the root of the workspace from the view point of this node, such as "/hudson", this need not + * be absolute provided that the launcher establishes a consistent working directory, such as "./.jenkins-slave" + * when used with an SSH launcher. + * + * NOTE: if the administrator is using a relative path they are responsible for ensuring that the launcher used + * provides a consistent working directory */ protected final String remoteFS; @@ -121,14 +129,15 @@ public abstract class Slave extends Node implements Serializable { * Whitespace-separated labels. */ 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}. */ private transient volatile Set

- * This is useful for a workflow/company specific job type that wants to eliminate + * This is useful for a workflow/company specific item type that wants to eliminate * options that the user would see. * * @since 1.294 @@ -61,6 +62,29 @@ public abstract class TopLevelItemDescriptor extends Descriptor { return true; } + /** + * {@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 1.607 + */ + public boolean isApplicableIn(ItemGroup parent) { + return true; + } + + /** + * Checks if this top level item is applicable within the specified item group. + *

+ * This is just a convenience function. + * @since 1.607 + */ + public final void checkApplicableIn(ItemGroup parent) { + if (!isApplicableIn(parent)) { + throw new AccessDeniedException( + Messages.TopLevelItemDescriptor_NotApplicableIn(getDisplayName(), parent.getFullDisplayName())); + } + } + /** * Tests if the given instance belongs to this descriptor, in the sense * that this descriptor can produce items like the given one. @@ -79,16 +103,19 @@ public abstract class TopLevelItemDescriptor extends Descriptor { * {@inheritDoc} * *

- * Used as the caption when the user chooses what job type to create. - * The descriptor implementation also needs to have newJobDetail.jelly + * Used as the caption when the user chooses what item type to create. + * The descriptor implementation also needs to have newInstanceDetail.jelly * script, which will be used to render the text below the caption - * that explains the job type. + * that explains the item type. */ - public abstract String getDisplayName(); + @Override + public String getDisplayName() { + return super.getDisplayName(); + } /** * @deprecated since 2007-01-19. - * This is not a valid operation for {@link Job}s. + * This is not a valid operation for {@link Item}s. */ @Deprecated public TopLevelItem newInstance(StaplerRequest req) throws FormException { @@ -101,6 +128,7 @@ public abstract class TopLevelItemDescriptor extends Descriptor { * @deprecated as of 1.390 * Use {@link #newInstance(ItemGroup, String)} */ + @Deprecated public TopLevelItem newInstance(String name) { return newInstance(Jenkins.getInstance(), name); } diff --git a/core/src/main/java/hudson/model/TransientBuildActionFactory.java b/core/src/main/java/hudson/model/TransientBuildActionFactory.java index 314590f0ecc092e9d7e9283f441dd7074d22b2d0..dfac20cb07808ac000edb1a8807f616c3c77b59b 100644 --- a/core/src/main/java/hudson/model/TransientBuildActionFactory.java +++ b/core/src/main/java/hudson/model/TransientBuildActionFactory.java @@ -3,7 +3,6 @@ package hudson.model; import hudson.Extension; import hudson.ExtensionList; import hudson.ExtensionPoint; -import jenkins.model.Jenkins; import java.util.Collection; import java.util.Collections; import jenkins.model.TransientActionFactory; @@ -37,6 +36,7 @@ public abstract class TransientBuildActionFactory implements ExtensionPoint { * @deprecated as of 1.461 * Override and call {@link #createFor(Run)} instead. */ + @Deprecated public Collection createFor(AbstractBuild target) { return Collections.emptyList(); } @@ -47,4 +47,4 @@ public abstract class TransientBuildActionFactory implements ExtensionPoint { public static ExtensionList all() { return ExtensionList.lookup(TransientBuildActionFactory.class); } -} \ No newline at end of file +} diff --git a/core/src/main/java/hudson/model/TransientComputerActionFactory.java b/core/src/main/java/hudson/model/TransientComputerActionFactory.java index 37fc369e95f51612f2939dd69b21ca0bc237a4e1..3a77db8c5260e77310a790ace88eb8af6c5d5351 100644 --- a/core/src/main/java/hudson/model/TransientComputerActionFactory.java +++ b/core/src/main/java/hudson/model/TransientComputerActionFactory.java @@ -25,7 +25,6 @@ package hudson.model; import hudson.ExtensionList; import hudson.ExtensionPoint; -import jenkins.model.Jenkins; import java.util.ArrayList; import java.util.Collection; diff --git a/core/src/main/java/hudson/model/TransientProjectActionFactory.java b/core/src/main/java/hudson/model/TransientProjectActionFactory.java index 35acbaebb9a7b5cda30ac662a1d3d4888da8566b..23fd0a138c78d1e357f45aa09fd425c5fe7f62c9 100644 --- a/core/src/main/java/hudson/model/TransientProjectActionFactory.java +++ b/core/src/main/java/hudson/model/TransientProjectActionFactory.java @@ -27,7 +27,6 @@ import hudson.Extension; import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.tasks.BuildStep; -import jenkins.model.Jenkins; import java.util.Collection; import jenkins.model.TransientActionFactory; diff --git a/core/src/main/java/hudson/model/TransientViewActionFactory.java b/core/src/main/java/hudson/model/TransientViewActionFactory.java index 43633bac2d84154343dcea184e6ea2cce2d2d10e..edf9a1c85afce7fccad49c6feda2b6595db3245c 100644 --- a/core/src/main/java/hudson/model/TransientViewActionFactory.java +++ b/core/src/main/java/hudson/model/TransientViewActionFactory.java @@ -2,7 +2,6 @@ package hudson.model; import hudson.ExtensionList; import hudson.ExtensionPoint; -import jenkins.model.Jenkins; import java.util.ArrayList; import java.util.List; diff --git a/core/src/main/java/hudson/model/UpdateCenter.java b/core/src/main/java/hudson/model/UpdateCenter.java index f5aecb59ef7bded5c64baf60cb3b28cfca41031f..b5fde8aac6c0bcbf1394fa344932489a1a982132 100644 --- a/core/src/main/java/hudson/model/UpdateCenter.java +++ b/core/src/main/java/hudson/model/UpdateCenter.java @@ -54,6 +54,7 @@ import jenkins.model.Jenkins; import jenkins.util.io.OnMaster; import org.acegisecurity.Authentication; import org.acegisecurity.context.SecurityContext; +import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.input.CountingInputStream; import org.apache.commons.io.output.NullOutputStream; import org.jvnet.localizer.Localizable; @@ -61,9 +62,11 @@ import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; +import javax.annotation.Nonnull; import javax.net.ssl.SSLHandshakeException; import javax.servlet.ServletException; import java.io.File; +import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -71,6 +74,10 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.net.UnknownHostException; +import java.security.DigestInputStream; +import java.security.DigestOutputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -320,6 +327,7 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas * TODO: revisit tool update mechanism, as that should be de-centralized, too. In the mean time, * please try not to use this method, and instead ping us to get this part completed. */ + @Deprecated public String getDefaultBaseUrl() { return config.getUpdateCenterUrl(); } @@ -747,6 +755,15 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas * @see DownloadJob */ public File download(DownloadJob job, URL src) throws IOException { + MessageDigest sha1 = null; + try { + sha1 = MessageDigest.getInstance("SHA-1"); + } catch (NoSuchAlgorithmException ignored) { + // Irrelevant as the Java spec says SHA-1 must exist. Still, if this fails + // the DownloadJob will just have computedSha1 = null and that is expected + // to be handled by caller + } + CountingInputStream in = null; OutputStream out = null; URLConnection con = null; @@ -760,8 +777,14 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas File dst = job.getDestination(); File tmp = new File(dst.getPath()+".tmp"); out = new FileOutputStream(tmp); + if (sha1 != null) { + out = new DigestOutputStream(out, sha1); + } LOGGER.info("Downloading "+job.getName()); + Thread t = Thread.currentThread(); + String oldName = t.getName(); + t.setName(oldName + ": " + src); try { while((len=in.read(buf))>=0) { out.write(buf,0,len); @@ -769,6 +792,9 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas } } catch (IOException e) { throw new IOException("Failed to load "+src+" to "+tmp,e); + } finally { + IOUtils.closeQuietly(out); + t.setName(oldName); } if (total!=-1 && total!=tmp.length()) { @@ -778,6 +804,10 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas throw new IOException("Inconsistent file length: expected "+total+" but only got "+tmp.length()); } + if (sha1 != null) { + byte[] digest = sha1.digest(); + job.computedSHA1 = Base64.encodeBase64String(digest); + } return tmp; } catch (IOException e) { // assist troubleshooting in case of e.g. "too many redirects" by printing actual URL @@ -837,6 +867,7 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas * is now a part of the update-center.json file. See * http://jenkins-ci.org/update-center.json as an example. */ + @Deprecated public String getConnectionCheckUrl() { return "http://www.google.com"; } @@ -851,6 +882,7 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas * @return * Absolute URL that ends with '/'. */ + @Deprecated public String getUpdateCenterUrl() { return UPDATE_CENTER_URL; } @@ -862,6 +894,7 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas * update-center.json is now signed, so we don't have to further make sure that * we aren't downloading from anywhere unsecure. */ + @Deprecated public String getPluginRepositoryBaseUrl() { return "http://jenkins-ci.org/"; } @@ -915,6 +948,7 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas * @deprecated as of 1.326 * Use {@link #submit()} instead. */ + @Deprecated public void schedule() { submit(); } @@ -1094,6 +1128,17 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas */ protected abstract void onSuccess(); + /** + * During download, an attempt is made to compute the SHA-1 checksum of the file. + * + * @since TODO + */ + @CheckForNull + protected String getComputedSHA1() { + return computedSHA1; + } + + private String computedSHA1; private Authentication authentication; @@ -1245,6 +1290,26 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas } } + /** + * If expectedSHA1 is non-null, ensure that actualSha1 is the same value, otherwise throw. + * + * Utility method for InstallationJob and HudsonUpgradeJob. + * + * @throws IOException when checksums don't match, or actual checksum was null. + */ + private void verifyChecksums(String expectedSHA1, String actualSha1, File downloadedFile) throws IOException { + if (expectedSHA1 != null) { + if (actualSha1 == null) { + // refuse to install if SHA-1 could not be computed + throw new IOException("Failed to compute SHA-1 of downloaded file, refusing installation"); + } + if (!expectedSHA1.equals(actualSha1)) { + throw new IOException("Downloaded file " + downloadedFile.getAbsolutePath() + " does not match expected SHA-1, expected '" + expectedSHA1 + "', actual '" + actualSha1 + "'"); + // keep 'downloadedFile' around for investigating what's going on + } + } + } + /** * Represents the state of the installation activity of one plugin. */ @@ -1265,6 +1330,7 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas /** * @deprecated as of 1.442 */ + @Deprecated public InstallationJob(Plugin plugin, UpdateSite site, Authentication auth) { this(plugin,site,auth,false); } @@ -1336,18 +1402,24 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas */ @Override protected void replace(File dst, File src) throws IOException { - File bak = Util.changeExtension(dst,".bak"); - + + verifyChecksums(plugin.getSha1(), getComputedSHA1(), src); + + File bak = Util.changeExtension(dst, ".bak"); bak.delete(); + final File legacy = getLegacyDestination(); - if(legacy.exists()){ - legacy.renameTo(bak); - }else{ - dst.renameTo(bak); + if (legacy.exists()) { + if (!legacy.renameTo(bak)) { + legacy.delete(); + } } - legacy.delete(); - dst.delete(); // any failure up to here is no big deal - + if (dst.exists()) { + if (!dst.renameTo(bak)) { + dst.delete(); + } + } + if(!src.renameTo(dst)) { throw new IOException("Failed to rename "+src+" to "+dst); } @@ -1465,6 +1537,8 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas @Override protected void replace(File dst, File src) throws IOException { + String expectedSHA1 = site.getData().core.getSha1(); + verifyChecksums(expectedSHA1, getComputedSHA1(), src); Lifecycle.get().rewriteHudsonWar(src); } } @@ -1560,6 +1634,7 @@ public class UpdateCenter extends AbstractModelObject implements Saveable, OnMas * @deprecated as of 1.333 * Use {@link UpdateSite#neverUpdate} */ + @Deprecated public static boolean neverUpdate = Boolean.getBoolean(UpdateCenter.class.getName()+".never"); public static final XStream2 XSTREAM = new XStream2(); diff --git a/core/src/main/java/hudson/model/UpdateSite.java b/core/src/main/java/hudson/model/UpdateSite.java index 77b5926c4b7d38ba3b7a7775aed46fe6c2fd510c..061091bb671936f32f0395bbc91e776321b67b3a 100644 --- a/core/src/main/java/hudson/model/UpdateSite.java +++ b/core/src/main/java/hudson/model/UpdateSite.java @@ -27,6 +27,7 @@ package hudson.model; import hudson.PluginManager; import hudson.PluginWrapper; +import hudson.Util; import hudson.lifecycle.Lifecycle; import hudson.model.UpdateCenter.UpdateCenterJob; import hudson.util.FormValidation; @@ -126,6 +127,8 @@ public class UpdateSite { */ private final String url; + + public UpdateSite(String id, String url) { this.id = id; this.url = url; @@ -174,9 +177,7 @@ public class UpdateSite { * This is the endpoint that receives the update center data file from the browser. */ public FormValidation doPostBack(StaplerRequest req) throws IOException, GeneralSecurityException { - if (!DownloadSettings.get().isUseBrowser()) { - throw new IOException("not allowed"); - } + DownloadSettings.checkPostBackAccess(); return updateData(IOUtils.toString(req.getInputStream(),"UTF-8"), true); } @@ -408,6 +409,7 @@ public class UpdateSite { * @deprecated * Exposed only for UI. */ + @Deprecated public String getDownloadUrl() { /* HACKISH: @@ -509,6 +511,11 @@ public class UpdateSite { @Exported public final String url; + + // non-private, non-final for test + @Restricted(NoExternalUse.class) + /* final */ String sha1; + public Entry(String sourceId, JSONObject o) { this(sourceId, o, null); } @@ -517,6 +524,11 @@ public class UpdateSite { this.sourceId = sourceId; this.name = o.getString("name"); this.version = o.getString("version"); + + // Trim this to prevent issues when the other end used Base64.encodeBase64String that added newlines + // to the end in old commons-codec. Not the case on updates.jenkins-ci.org, but let's be safe. + this.sha1 = Util.fixEmptyAndTrim(o.optString("sha1")); + String url = o.getString("url"); if (!URI.create(url).isAbsolute()) { if (baseURL == null) { @@ -527,6 +539,16 @@ public class UpdateSite { this.url = url; } + /** + * The base64 encoded binary SHA-1 checksum of the file. + * Can be null if not provided by the update site. + * @since TODO + */ + // TODO @Exported assuming we want this in the API + public String getSha1() { + return sha1; + } + /** * Checks if the specified "current version" is older than the version of this entry. * @@ -770,6 +792,7 @@ public class UpdateSite { * @deprecated as of 1.326 * Use {@link #deploy()}. */ + @Deprecated public void install() { deploy(); } diff --git a/core/src/main/java/hudson/model/UsageStatistics.java b/core/src/main/java/hudson/model/UsageStatistics.java index 805403216b0aad6aaea35fe30e37972772a20a47..b6d2af2496dcb659c99e0283118d1f3262950e50 100644 --- a/core/src/main/java/hudson/model/UsageStatistics.java +++ b/core/src/main/java/hudson/model/UsageStatistics.java @@ -31,6 +31,7 @@ import hudson.node_monitors.ArchitectureMonitor.DescriptorImpl; import hudson.util.IOUtils; import hudson.util.Secret; import static hudson.util.TimeUnit2.DAYS; +import static hudson.init.InitMilestone.COMPLETED; import jenkins.model.Jenkins; import net.sf.json.JSONObject; @@ -95,9 +96,12 @@ public class UsageStatistics extends PageDecorator { * Returns true if it's time for us to check for new version. */ public boolean isDue() { - // user opted out. no data collection. - if(!Jenkins.getInstance().isUsageStatisticsCollected() || DISABLED) return false; - + final Jenkins j = Jenkins.getInstance(); + // user opted out or Jenkins not fully initialized. no data collection. + if (j == null || j.isUsageStatisticsCollected() || DISABLED || COMPLETED.compareTo(j.getInitLevel()) > 0) { + return false; + } + long now = System.currentTimeMillis(); if(now - lastAttempt > DAY) { lastAttempt = now; @@ -197,10 +201,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/model/User.java b/core/src/main/java/hudson/model/User.java index c4190ee4af4386ccfe7656ed819118c30c2cf2de..e2a09768f4737aa4c42c0c43677c3b80eb61965f 100644 --- a/core/src/main/java/hudson/model/User.java +++ b/core/src/main/java/hudson/model/User.java @@ -35,6 +35,7 @@ import hudson.security.Permission; import hudson.security.SecurityRealm; import hudson.security.UserMayOrMayNotExistException; import hudson.util.FormApply; +import hudson.util.FormValidation; import hudson.util.RunList; import hudson.util.XStream2; import jenkins.model.IdStrategy; @@ -109,7 +110,18 @@ import javax.annotation.Nullable; */ @ExportedBean public class User extends AbstractModelObject implements AccessControlled, DescriptorByNameOwner, Saveable, Comparable, ModelObjectWithContextMenu { - + + /** + * The username of the 'unknown' user used to avoid null user references. + */ + private static final String UKNOWN_USERNAME = "unknown"; + + /** + * These usernames should not be used by real users logging into Jenkins. Therefore, we prevent + * users with these names from being saved. + */ + private static final String[] ILLEGAL_PERSISTED_USERNAMES = new String[]{ACL.ANONYMOUS_USERNAME, + ACL.SYSTEM_USERNAME, UKNOWN_USERNAME}; private transient final String id; private volatile String fullName; @@ -231,6 +243,15 @@ public class User extends AbstractModelObject implements AccessControlled, Descr return description; } + + /** + * Sets the description of the user. + * @since 1.609 + */ + public void setDescription(String description) { + this.description = description; + } + /** * Gets the user properties configured for this user. */ @@ -292,7 +313,8 @@ public class User extends AbstractModelObject implements AccessControlled, Descr // backend can't load information about other users. so use the stored information if available } catch (UsernameNotFoundException e) { // if the user no longer exists in the backend, we need to refuse impersonating this user - throw e; + if (!ALLOW_NON_EXISTENT_USER_TO_LOGIN) + throw e; } catch (DataAccessException e) { // seems like it's in the same boat as UserMayOrMayNotExistException } @@ -320,7 +342,7 @@ public class User extends AbstractModelObject implements AccessControlled, Descr * This is used to avoid null {@link User} instance. */ public static @Nonnull User getUnknown() { - return get("unknown"); + return get(UKNOWN_USERNAME); } /** @@ -335,6 +357,7 @@ public class User extends AbstractModelObject implements AccessControlled, Descr * {@code create} is false. * @deprecated use {@link User#get(String, boolean, java.util.Map)} */ + @Deprecated public static @Nullable User get(String idOrFullName, boolean create) { return get(idOrFullName, create, Collections.emptyMap()); } @@ -464,8 +487,18 @@ public class User extends AbstractModelObject implements AccessControlled, Descr * @since 1.172 */ public static @CheckForNull User current() { - Authentication a = Jenkins.getAuthentication(); - if(a instanceof AnonymousAuthenticationToken) + return get(Jenkins.getAuthentication()); + } + + /** + * Gets the {@link User} object representing the supplied {@link Authentication} or + * {@code null} if the supplied {@link Authentication} is either anonymous or {@code null} + * @param a the supplied {@link Authentication} . + * @return a {@link User} object for the supplied {@link Authentication} or {@code null} + * @since 1.609 + */ + public static @CheckForNull User get(@CheckForNull Authentication a) { + if(a == null || a instanceof AnonymousAuthenticationToken) return null; // Since we already know this is a name, we can just call getOrCreate with the name directly. @@ -642,10 +675,35 @@ public class User extends AbstractModelObject implements AccessControlled, Descr return new File(Jenkins.getInstance().getRootDir(), "users"); } + /** + * Is the ID allowed? Some are prohibited for security reasons. See SECURITY-166. + *

+ * Note that this is only enforced when saving. These users are often created + * via the constructor (and even listed on /asynchPeople), but our goal is to + * prevent anyone from logging in as these users. Therefore, we prevent + * saving a User with one of these ids. + * + * @return true if the username or fullname is valid + * @since 1.600 + */ + public static boolean isIdOrFullnameAllowed(String id) { + for (String invalidId : ILLEGAL_PERSISTED_USERNAMES) { + if (id.equalsIgnoreCase(invalidId)) + return false; + } + return true; + } + /** * Save the settings to a file. */ - public synchronized void save() throws IOException { + public synchronized void save() throws IOException, FormValidation { + if (! isIdOrFullnameAllowed(id)) { + throw FormValidation.error(Messages.User_IllegalUsername(id)); + } + if (! isIdOrFullnameAllowed(fullName)) { + throw FormValidation.error(Messages.User_IllegalFullname(fullName)); + } if(BulkChange.contains(this)) return; getConfigFile().write(this); SaveableListener.fireOnChange(this, getConfigFile()); @@ -939,5 +997,15 @@ public class User extends AbstractModelObject implements AccessControlled, Descr } } + /** + * Jenkins now refuses to let the user login if he/she doesn't exist in {@link SecurityRealm}, + * which was necessary to make sure users removed from the backend will get removed from the frontend. + *

+ * Unfortunately this infringed some legitimate use cases of creating Jenkins-local users for + * automation purposes. This escape hatch switch can be enabled to resurrect that behaviour. + * + * JENKINS-22346. + */ + public static boolean ALLOW_NON_EXISTENT_USER_TO_LOGIN = Boolean.getBoolean(User.class.getName()+".allowNonExistentUserToLogin"); } diff --git a/core/src/main/java/hudson/model/UserProperties.java b/core/src/main/java/hudson/model/UserProperties.java index 5561fe7caac492b82158b6c462459bc118aa52a9..2c936dfbbfa29389ee99f5617717b9c8df2b5990 100644 --- a/core/src/main/java/hudson/model/UserProperties.java +++ b/core/src/main/java/hudson/model/UserProperties.java @@ -33,10 +33,12 @@ import java.util.List; * @author Kohsuke Kawaguchi * @deprecated as of 1.286 */ +@Deprecated public class UserProperties { /** * @deprecated as of 1.286 * Use {@link UserProperty#all()} for read access and {@link Extension} for auto-registration. */ + @Deprecated public static final List LIST = (List)new DescriptorList(UserProperty.class); } diff --git a/core/src/main/java/hudson/model/UserProperty.java b/core/src/main/java/hudson/model/UserProperty.java index 3400bb27eea1d43b5ca35921de91283b4c59fa9b..0f0958d95cb22680b32ab6af3c40b52f7d185ef6 100644 --- a/core/src/main/java/hudson/model/UserProperty.java +++ b/core/src/main/java/hudson/model/UserProperty.java @@ -24,7 +24,6 @@ package hudson.model; import hudson.ExtensionPoint; -import hudson.Plugin; import hudson.DescriptorExtensionList; import hudson.model.Descriptor.FormException; import jenkins.model.Jenkins; @@ -37,7 +36,7 @@ import org.kohsuke.stapler.export.ExportedBean; * Extensible property of {@link User}. * *

- * {@link Plugin}s can extend this to define custom properties + * Plugins can extend this to define custom properties * for {@link User}s. {@link UserProperty}s show up in the user * configuration screen, and they are persisted with the user object. * diff --git a/core/src/main/java/hudson/model/View.java b/core/src/main/java/hudson/model/View.java index d03727af6cf4a31a9743576756e479947c3776d1..0cfa562922d242ff2ac3c0deeaf3533f6dd937b4 100644 --- a/core/src/main/java/hudson/model/View.java +++ b/core/src/main/java/hudson/model/View.java @@ -35,7 +35,6 @@ import hudson.Indenter; import hudson.Util; import hudson.model.Descriptor.FormException; import hudson.model.labels.LabelAtomPropertyDescriptor; -import hudson.model.listeners.ItemListener; import hudson.scm.ChangeLogSet; import hudson.scm.ChangeLogSet.Entry; import hudson.search.CollectionSearchIndex; @@ -58,6 +57,8 @@ import hudson.widgets.Widget; import jenkins.model.Jenkins; import jenkins.model.ModelObjectWithChildren; import jenkins.util.ProgressiveRendering; +import jenkins.util.xml.XMLUtils; + import net.sf.json.JSON; import net.sf.json.JSONArray; import net.sf.json.JSONObject; @@ -75,9 +76,7 @@ import org.kohsuke.stapler.interceptor.RequirePOST; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import javax.xml.transform.Source; -import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import java.io.BufferedInputStream; @@ -106,6 +105,7 @@ import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; import static jenkins.model.Jenkins.*; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.xml.sax.SAXException; /** * Encapsulates the rendering of the list of {@link TopLevelItem}s @@ -480,6 +480,11 @@ public abstract class View extends AbstractModelObject implements AccessControll return filterQueue(Arrays.asList(Jenkins.getInstance().getQueue().getItems())); } + /** + * @deprecated Use {@link #getQueueItems()}. As of 1.607 the approximation is no longer needed. + * @return The items in the queue. + */ + @Deprecated public List getApproximateQueueItemsQuickly() { return filterQueue(Jenkins.getInstance().getQueue().getApproximateItemsQuickly()); } @@ -654,6 +659,7 @@ public abstract class View extends AbstractModelObject implements AccessControll * Does this {@link View} has any associated user information recorded? * @deprecated Potentially very expensive call; do not use from Jelly views. */ + @Deprecated public boolean hasPeople() { return People.isApplicable(getItems()); } @@ -737,6 +743,7 @@ public abstract class View extends AbstractModelObject implements AccessControll /** * @deprecated Potentially very expensive call; do not use from Jelly views. */ + @Deprecated public static boolean isApplicable(Collection items) { for (Item item : items) { for (Job job : item.getAllJobs()) { @@ -1063,7 +1070,10 @@ public abstract class View extends AbstractModelObject implements AccessControll } /** - * Updates Job by its XML definition. + * Updates the View with the new XML definition. + * @param source source of the Item's new definition. + * The source should be either a StreamSource or SAXSource, other sources + * may not be handled. */ public void updateByXml(Source source) throws IOException { checkPermission(CONFIGURE); @@ -1072,13 +1082,12 @@ public abstract class View extends AbstractModelObject implements AccessControll // this allows us to use UTF-8 for storing data, // plus it checks any well-formedness issue in the submitted // data - Transformer t = TransformerFactory.newInstance() - .newTransformer(); - t.transform(source, - new StreamResult(out)); + XMLUtils.safeTransform(source, new StreamResult(out)); out.close(); } catch (TransformerException e) { throw new IOException("Failed to persist configuration.xml", e); + } catch (SAXException e) { + throw new IOException("Failed to persist configuration.xml", e); } // try to reflect the changes by reloading @@ -1113,6 +1122,7 @@ public abstract class View extends AbstractModelObject implements AccessControll * @deprecated as of 1.286 * Use {@link #all()} for read access, and use {@link Extension} for registration. */ + @Deprecated public static final DescriptorList LIST = new DescriptorList(View.class); /** @@ -1152,18 +1162,22 @@ public abstract class View extends AbstractModelObject implements AccessControll public static View create(StaplerRequest req, StaplerResponse rsp, ViewGroup owner) throws FormException, IOException, ServletException { + String mode = req.getParameter("mode"); + String requestContentType = req.getContentType(); - if(requestContentType==null) + if (requestContentType == null + && !(mode != null && mode.equals("copy"))) throw new Failure("No Content-Type header set"); - boolean isXmlSubmission = requestContentType.startsWith("application/xml") || requestContentType.startsWith("text/xml"); + boolean isXmlSubmission = requestContentType != null + && (requestContentType.startsWith("application/xml") + || requestContentType.startsWith("text/xml")); String name = req.getParameter("name"); checkGoodName(name); if(owner.getView(name)!=null) throw new Failure(Messages.Hudson_ViewAlreadyExists(name)); - String mode = req.getParameter("mode"); if (mode==null || mode.length()==0) { if(isXmlSubmission) { View v = createViewFromXML(name, req.getInputStream()); diff --git a/core/src/main/java/hudson/model/ViewDescriptor.java b/core/src/main/java/hudson/model/ViewDescriptor.java index b8e6344365e7e69562cf57bfeb30ea05e93557dd..2f304fa90f29899cfb47c6048b66933249346b72 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/model/ViewGroupMixIn.java b/core/src/main/java/hudson/model/ViewGroupMixIn.java index 3134ae06d26e53c9c46ff21d75b1b40d65971be7..e390005edbb57e186f8afadd96b02616ef6935dd 100644 --- a/core/src/main/java/hudson/model/ViewGroupMixIn.java +++ b/core/src/main/java/hudson/model/ViewGroupMixIn.java @@ -32,7 +32,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Iterator; import java.util.List; /** diff --git a/core/src/main/java/hudson/model/ViewJob.java b/core/src/main/java/hudson/model/ViewJob.java index c86abb33e74314ebe4d43bb0dc778d2be4f8429c..92e36999e2150c50ae301b9ef4f8e23744237cf3 100644 --- a/core/src/main/java/hudson/model/ViewJob.java +++ b/core/src/main/java/hudson/model/ViewJob.java @@ -79,6 +79,7 @@ public abstract class ViewJob, RunT extends Run< /** * @deprecated as of 1.390 */ + @Deprecated protected ViewJob(Jenkins parent, String name) { super(parent,name); } diff --git a/core/src/main/java/hudson/model/WorkspaceCleanupThread.java b/core/src/main/java/hudson/model/WorkspaceCleanupThread.java index 1ccf248c51ee43fbd759025d49e0ef0d32796f9b..9e83e143e5a361b265986746cd8d87968a1596df 100644 --- a/core/src/main/java/hudson/model/WorkspaceCleanupThread.java +++ b/core/src/main/java/hudson/model/WorkspaceCleanupThread.java @@ -49,7 +49,7 @@ public class WorkspaceCleanupThread extends AsyncPeriodicWork { } @Override public long getRecurrencePeriod() { - return DAY; + return recurrencePeriodHours * HOUR; } public static void invoke() { @@ -99,7 +99,7 @@ public class WorkspaceCleanupThread extends AsyncPeriodicWork { } } - private boolean shouldBeDeleted(@Nonnull TopLevelItem item, FilePath dir, Node n) throws IOException, InterruptedException { + private boolean shouldBeDeleted(@Nonnull TopLevelItem item, FilePath dir, @Nonnull Node n) throws IOException, InterruptedException { // TODO: the use of remoting is not optimal. // One remoting can execute "exists", "lastModified", and "delete" all at once. // (Could even invert master loop so that one FileCallable takes care of all known items.) @@ -110,7 +110,7 @@ public class WorkspaceCleanupThread extends AsyncPeriodicWork { // if younger than a month, keep it long now = new Date().getTime(); - if(dir.lastModified() + 30 * DAY > now) { + if(dir.lastModified() + retainForDays * DAY > now) { LOGGER.log(Level.FINE, "Directory {0} is only {1} old, so not deleting", new Object[] {dir, Util.getTimeSpanString(now-dir.lastModified())}); return false; } @@ -128,7 +128,7 @@ public class WorkspaceCleanupThread extends AsyncPeriodicWork { return false; } - if(!p.getScm().processWorkspaceBeforeDeletion(p,dir,n)) { + if(!p.getScm().processWorkspaceBeforeDeletion((Job) p,dir,n)) { LOGGER.log(Level.FINE, "Directory deletion of {0} is vetoed by SCM", dir); return false; } @@ -143,5 +143,15 @@ public class WorkspaceCleanupThread extends AsyncPeriodicWork { /** * Can be used to disable workspace clean up. */ - public static final boolean disabled = Boolean.getBoolean(WorkspaceCleanupThread.class.getName()+".disabled"); + public static boolean disabled = Boolean.getBoolean(WorkspaceCleanupThread.class.getName()+".disabled"); + + /** + * How often the clean up should run. This is final as Jenkins will not reflect changes anyway. + */ + public static final int recurrencePeriodHours = Integer.getInteger(WorkspaceCleanupThread.class.getName()+".recurrencePeriodHours", 24); + + /** + * Number of days workspaces should be retained. + */ + public static int retainForDays = Integer.getInteger(WorkspaceCleanupThread.class.getName()+".retainForDays", 30); } diff --git a/core/src/main/java/hudson/model/WorkspaceListener.java b/core/src/main/java/hudson/model/WorkspaceListener.java index 9635a42192407ac8262dd64c12671446205aa5be..94d37d41441833998e655823bbc00fd0ce7d772e 100644 --- a/core/src/main/java/hudson/model/WorkspaceListener.java +++ b/core/src/main/java/hudson/model/WorkspaceListener.java @@ -3,7 +3,6 @@ package hudson.model; import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.FilePath; -import jenkins.model.Jenkins; public abstract class WorkspaceListener implements ExtensionPoint { diff --git a/core/src/main/java/hudson/model/labels/LabelAssignmentAction.java b/core/src/main/java/hudson/model/labels/LabelAssignmentAction.java index 57c2de13c336c540e8dda8bc434692c594e057b8..c91284aef3014bc67c8c6f83fa0c3efde54e89c5 100644 --- a/core/src/main/java/hudson/model/labels/LabelAssignmentAction.java +++ b/core/src/main/java/hudson/model/labels/LabelAssignmentAction.java @@ -7,6 +7,7 @@ import hudson.model.Queue; import hudson.model.Queue.QueueDecisionHandler; import hudson.model.Queue.Task; import hudson.model.queue.SubTask; +import javax.annotation.Nonnull; /** * {@link Action} that can be submitted to {@link Queue} that controls where @@ -35,5 +36,5 @@ public interface LabelAssignmentAction extends Action { * null to let other {@link LabelAssignmentAction}s take control, eventually to {@code SubTask#getAssignedLabel()}. * If non-null value is returned, that label will be authoritative. */ - Label getAssignedLabel(SubTask task); + Label getAssignedLabel(@Nonnull SubTask task); } diff --git a/core/src/main/java/hudson/model/labels/LabelAtom.java b/core/src/main/java/hudson/model/labels/LabelAtom.java index a420b112d2808fbb3aa642c20264e5499f7a459a..91c1f3bd7707fba23c0fa8cd6edb438c77cf236e 100644 --- a/core/src/main/java/hudson/model/labels/LabelAtom.java +++ b/core/src/main/java/hudson/model/labels/LabelAtom.java @@ -116,7 +116,7 @@ public class LabelAtom extends Label implements Saveable { } /** - * @since TODO + * @since 1.580 */ public String getDescription() { return description; diff --git a/core/src/main/java/hudson/model/listeners/ItemListener.java b/core/src/main/java/hudson/model/listeners/ItemListener.java index 4f3d235f515d0fb8c7ebdfdf8c85265104338b3f..7ff530c43816ae47cc64058932cb256b8ed26ebc 100644 --- a/core/src/main/java/hudson/model/listeners/ItemListener.java +++ b/core/src/main/java/hudson/model/listeners/ItemListener.java @@ -148,6 +148,7 @@ public class ItemListener implements ExtensionPoint { * @deprecated as of 1.286 * put {@link Extension} on your class to have it auto-registered. */ + @Deprecated public void register() { all().add(this); } diff --git a/core/src/main/java/hudson/model/listeners/RunListener.java b/core/src/main/java/hudson/model/listeners/RunListener.java index 329292ded00dd1bf8477a7329d129b44ca520f5f..e65347bc0299648ce1ddb29bbb54aa94feed3e7b 100644 --- a/core/src/main/java/hudson/model/listeners/RunListener.java +++ b/core/src/main/java/hudson/model/listeners/RunListener.java @@ -171,6 +171,7 @@ public abstract class RunListener implements ExtensionPoint { * @deprecated as of 1.281 * Put {@link Extension} on your class to get it auto-registered. */ + @Deprecated public void register() { all().add(this); } @@ -187,6 +188,7 @@ public abstract class RunListener implements ExtensionPoint { * @deprecated as of 1.281 * Use {@link #all()} for read access, and use {@link Extension} for registration. */ + @Deprecated public static final CopyOnWriteList LISTENERS = ExtensionListView.createCopyOnWriteList(RunListener.class); /** diff --git a/core/src/main/java/hudson/model/listeners/SCMPollListener.java b/core/src/main/java/hudson/model/listeners/SCMPollListener.java index 7b7b94ba4034124554fae662b39c4461b3dc1d10..55dd8d558930c0ace3445c18f84a2658d4743bf7 100644 --- a/core/src/main/java/hudson/model/listeners/SCMPollListener.java +++ b/core/src/main/java/hudson/model/listeners/SCMPollListener.java @@ -26,7 +26,6 @@ package hudson.model.listeners; import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.scm.PollingResult; -import jenkins.model.Jenkins; import hudson.model.AbstractProject; import hudson.model.TaskListener; diff --git a/core/src/main/java/hudson/model/listeners/SaveableListener.java b/core/src/main/java/hudson/model/listeners/SaveableListener.java index f0ad8d57205014fa7556ae1796041420c5e47bd3..37fed04f69f156d3e2c25dd85665fc93028cdf80 100644 --- a/core/src/main/java/hudson/model/listeners/SaveableListener.java +++ b/core/src/main/java/hudson/model/listeners/SaveableListener.java @@ -60,6 +60,7 @@ public abstract class SaveableListener implements ExtensionPoint { * @deprecated as of 1.281 * Put {@link Extension} on your class to get it auto-registered. */ + @Deprecated public void register() { all().add(this); } diff --git a/core/src/main/java/hudson/model/queue/AbstractQueueTask.java b/core/src/main/java/hudson/model/queue/AbstractQueueTask.java index d3586384f0dca4aec809a0377a6a8d05afc6fdf7..7a1bae3f7a71b68ee5e6940d5c21827d179964ee 100644 --- a/core/src/main/java/hudson/model/queue/AbstractQueueTask.java +++ b/core/src/main/java/hudson/model/queue/AbstractQueueTask.java @@ -27,6 +27,7 @@ package hudson.model.queue; import hudson.model.Queue; import hudson.model.Queue.Task; import hudson.security.ACL; +import hudson.security.AccessControlled; import org.acegisecurity.Authentication; import javax.annotation.Nonnull; @@ -37,6 +38,10 @@ import java.util.Collections; * Abstract base class for {@link hudson.model.Queue.Task} to protect plugins * from new additions to the interface. * + *

+ * Plugins are encouraged to implement {@link AccessControlled} otherwise + * the tasks will be hidden from display in the queue. + * * @author Kohsuke Kawaguchi * @since 1.360 */ diff --git a/core/src/main/java/hudson/model/queue/AbstractSubTask.java b/core/src/main/java/hudson/model/queue/AbstractSubTask.java index a031d9ef81f8beaa71dab99f9fa9600ceeaec09a..90110b751741e95297f60003bbc2141adc19379c 100644 --- a/core/src/main/java/hudson/model/queue/AbstractSubTask.java +++ b/core/src/main/java/hudson/model/queue/AbstractSubTask.java @@ -51,6 +51,6 @@ public abstract class AbstractSubTask implements SubTask { } public ResourceList getResourceList() { - return new ResourceList(); + return ResourceList.EMPTY; } } diff --git a/core/src/main/java/hudson/model/queue/Executables.java b/core/src/main/java/hudson/model/queue/Executables.java index a8a524bc8e7d31246c80a7c4390b6c109d7683bb..39bd48ea36a57e92499b54452d4f3eaf3c9566d0 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; } } diff --git a/core/src/main/java/hudson/model/queue/LoadPredictor.java b/core/src/main/java/hudson/model/queue/LoadPredictor.java index 868bf927604fd7409867ff01a009fb6b017703fe..2fc4bf8d657c6aaaf0bd6e587d6fa6f6dcb1b6fd 100644 --- a/core/src/main/java/hudson/model/queue/LoadPredictor.java +++ b/core/src/main/java/hudson/model/queue/LoadPredictor.java @@ -28,7 +28,6 @@ import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.model.Computer; import hudson.model.Executor; -import jenkins.model.Jenkins; import java.util.ArrayList; import java.util.Collections; @@ -73,6 +72,7 @@ public abstract class LoadPredictor implements ExtensionPoint { * @deprecated as of 1.380 * Use {@link #predict(MappingWorksheet, Computer, long, long)} */ + @Deprecated public Iterable predict(Computer computer, long start, long end) { return Collections.emptyList(); } diff --git a/core/src/main/java/hudson/model/queue/MappingWorksheet.java b/core/src/main/java/hudson/model/queue/MappingWorksheet.java index 0e21fa31ad72268b5c0e0ad6d8ae431fc7b16a5d..4ef5af3c8c9fb4f15a52c18e8edb17ee649f5446 100644 --- a/core/src/main/java/hudson/model/queue/MappingWorksheet.java +++ b/core/src/main/java/hudson/model/queue/MappingWorksheet.java @@ -25,7 +25,6 @@ package hudson.model.queue; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; -import hudson.model.AbstractProject; import hudson.model.Computer; import hudson.model.Executor; import hudson.model.Label; diff --git a/core/src/main/java/hudson/model/queue/QueueListener.java b/core/src/main/java/hudson/model/queue/QueueListener.java index 527a9485b4dc0a82616ad9a3723bfae740fa5ac3..50fbf35e274f8b3f9a059a4042debaa33209acd8 100644 --- a/core/src/main/java/hudson/model/queue/QueueListener.java +++ b/core/src/main/java/hudson/model/queue/QueueListener.java @@ -2,14 +2,12 @@ package hudson.model.queue; import hudson.ExtensionList; import hudson.ExtensionPoint; -import hudson.model.Computer; import hudson.model.Queue; import hudson.model.Queue.BlockedItem; import hudson.model.Queue.BuildableItem; import hudson.model.Queue.Item; import hudson.model.Queue.LeftItem; import hudson.model.Queue.WaitingItem; -import jenkins.model.Jenkins; import java.util.concurrent.Executor; diff --git a/core/src/main/java/hudson/model/queue/QueueSorter.java b/core/src/main/java/hudson/model/queue/QueueSorter.java index fafd9b0c1cc3b59baeefb819f16ececeb0081b28..251f8d72b80723959d266df1d7130326a0c80cf2 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.618 + */ + 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.618 + */ + 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)}. diff --git a/core/src/main/java/hudson/model/queue/QueueTaskDispatcher.java b/core/src/main/java/hudson/model/queue/QueueTaskDispatcher.java index fe8681975c7f7b855606c242f2134f13f9c2c193..cd5c5d5b0cc9a743d41b71e4e360c1ba72a06cce 100644 --- a/core/src/main/java/hudson/model/queue/QueueTaskDispatcher.java +++ b/core/src/main/java/hudson/model/queue/QueueTaskDispatcher.java @@ -27,9 +27,7 @@ package hudson.model.queue; import hudson.Extension; import hudson.ExtensionList; import hudson.ExtensionPoint; -import hudson.model.Queue.Item; import hudson.slaves.Cloud; -import jenkins.model.Jenkins; import hudson.model.Node; import hudson.model.Queue; import hudson.model.Queue.BuildableItem; @@ -68,6 +66,7 @@ public abstract class QueueTaskDispatcher implements ExtensionPoint { * @deprecated since 1.413 * Use {@link #canTake(Node, Queue.BuildableItem)} */ + @Deprecated public @CheckForNull CauseOfBlockage canTake(Node node, Task task) { return null; } diff --git a/core/src/main/java/hudson/model/queue/ScheduleResult.java b/core/src/main/java/hudson/model/queue/ScheduleResult.java index 95ebf0394ac4ad07784630bc881ff40dcf7d6142..0ba9b08944fba2d6797e54441321430476c4acbd 100644 --- a/core/src/main/java/hudson/model/queue/ScheduleResult.java +++ b/core/src/main/java/hudson/model/queue/ScheduleResult.java @@ -1,9 +1,7 @@ package hudson.model.queue; -import hudson.model.Action; import hudson.model.Queue; import hudson.model.Queue.Item; -import hudson.model.Queue.Task; import hudson.model.Queue.WaitingItem; import javax.annotation.CheckForNull; diff --git a/core/src/main/java/hudson/model/queue/SubTaskContributor.java b/core/src/main/java/hudson/model/queue/SubTaskContributor.java index b61a19ea3384cf2241188386eb92cc3a9e7282ab..313b863601c4d918f55cee0ef2591364c056b51b 100644 --- a/core/src/main/java/hudson/model/queue/SubTaskContributor.java +++ b/core/src/main/java/hudson/model/queue/SubTaskContributor.java @@ -27,7 +27,6 @@ import hudson.Extension; import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.model.AbstractProject; -import jenkins.model.Jenkins; import java.util.Collection; import java.util.Collections; diff --git a/core/src/main/java/hudson/model/queue/WorkUnit.java b/core/src/main/java/hudson/model/queue/WorkUnit.java index 385dc28fe9e641c37fb61780ecb5b9750a5a6e19..58c4ba31ca7641313aec28fa274daf78d1f98797 100644 --- a/core/src/main/java/hudson/model/queue/WorkUnit.java +++ b/core/src/main/java/hudson/model/queue/WorkUnit.java @@ -28,6 +28,7 @@ import hudson.model.Queue; import hudson.model.Queue.Executable; import hudson.model.Queue.Task; import javax.annotation.CheckForNull; +import hudson.model.Run; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.export.ExportedBean; @@ -85,6 +86,9 @@ public final class WorkUnit { @Restricted(NoExternalUse.class) public void setExecutable(Executable executable) { this.executable = executable; + if (executable instanceof Run) { + ((Run) executable).setQueueId(context.item.getId()); + } } /** diff --git a/core/src/main/java/hudson/model/queue/WorkUnitContext.java b/core/src/main/java/hudson/model/queue/WorkUnitContext.java index 3ae936f6d9d6891ff19687b04b631d02ecbb4388..503a1774917d53666c0840ddc311b58a13a2b6ff 100644 --- a/core/src/main/java/hudson/model/queue/WorkUnitContext.java +++ b/core/src/main/java/hudson/model/queue/WorkUnitContext.java @@ -76,6 +76,7 @@ public final class WorkUnitContext { protected void onCriteriaMet() { // on behalf of the member Executors, // the one that executes the main thing will send notifications + // Unclear if this will work with AsynchronousExecution; it *seems* this is only called from synchronize which is only called from synchronizeStart which is only called from an executor thread. Executor e = Executor.currentExecutor(); if (e.getCurrentWorkUnit().isMainWork()) { e.getOwner().taskAccepted(e,task); @@ -121,6 +122,11 @@ public final class WorkUnitContext { } } + @Deprecated + public void synchronizeEnd(Queue.Executable executable, Throwable problems, long duration) throws InterruptedException { + synchronizeEnd(Executor.currentExecutor(), executable, problems, duration); + } + /** * All the {@link Executor}s that jointly execute a {@link Task} call this method to synchronize on the end of the task. * @@ -128,11 +134,10 @@ public final class WorkUnitContext { * If any of the member thread is interrupted while waiting for other threads to join, all * the member threads will report {@link InterruptedException}. */ - public void synchronizeEnd(Queue.Executable executable, Throwable problems, long duration) throws InterruptedException { + public void synchronizeEnd(Executor e, Queue.Executable executable, Throwable problems, long duration) throws InterruptedException { endLatch.synchronize(); // the main thread will send a notification - Executor e = Executor.currentExecutor(); WorkUnit wu = e.getCurrentWorkUnit(); if (wu.isMainWork()) { if (problems == null) { diff --git a/core/src/main/java/hudson/node_monitors/AbstractAsyncNodeMonitorDescriptor.java b/core/src/main/java/hudson/node_monitors/AbstractAsyncNodeMonitorDescriptor.java index 7a0a0237fd88f80a1d10e71e356c8f633d21d350..054c6e08d77f50555a8faff5913c0132d233d851 100644 --- a/core/src/main/java/hudson/node_monitors/AbstractAsyncNodeMonitorDescriptor.java +++ b/core/src/main/java/hudson/node_monitors/AbstractAsyncNodeMonitorDescriptor.java @@ -12,7 +12,6 @@ import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.logging.Logger; diff --git a/core/src/main/java/hudson/node_monitors/AbstractNodeMonitorDescriptor.java b/core/src/main/java/hudson/node_monitors/AbstractNodeMonitorDescriptor.java index 21c0f95dd38a5a88c232bc42d402a185d6801bae..c79d4ea918e63392e2e08c056278955079db9e05 100644 --- a/core/src/main/java/hudson/node_monitors/AbstractNodeMonitorDescriptor.java +++ b/core/src/main/java/hudson/node_monitors/AbstractNodeMonitorDescriptor.java @@ -26,7 +26,6 @@ package hudson.node_monitors; import hudson.Util; import hudson.model.Computer; import hudson.model.Descriptor; -import hudson.model.Run; import jenkins.model.Jenkins; import hudson.model.ComputerSet; import hudson.model.AdministrativeMonitor; @@ -58,6 +57,7 @@ public abstract class AbstractNodeMonitorDescriptor extends Descriptor extends Descriptor extends Descriptor clazz) { this(clazz,HOUR); } @@ -82,6 +84,7 @@ public abstract class AbstractNodeMonitorDescriptor extends Descriptor clazz, long interval) { super(clazz); @@ -166,12 +169,7 @@ public abstract class AbstractNodeMonitorDescriptor extends Descriptor extends Descriptor extends Descriptor inProgressStarted + getMonitoringTimeOut() + 1000) { + if (!inProgress.isAlive()) { + LOGGER.log(Level.WARNING, "Previous {0} monitoring activity died without cleaning up after itself", + getDisplayName()); + inProgress = null; + } else if (System.currentTimeMillis() > inProgressStarted + getMonitoringTimeOut() + 1000) { // maybe it got stuck? LOGGER.log(Level.WARNING, "Previous {0} monitoring activity still in progress. Interrupting", getDisplayName()); diff --git a/core/src/main/java/hudson/node_monitors/DiskSpaceMonitorDescriptor.java b/core/src/main/java/hudson/node_monitors/DiskSpaceMonitorDescriptor.java index 4bd1c939c622c890ae81d59977b82225e2db6f9d..3fb829710001a9e9d138057be74882ab62cefef1 100644 --- a/core/src/main/java/hudson/node_monitors/DiskSpaceMonitorDescriptor.java +++ b/core/src/main/java/hudson/node_monitors/DiskSpaceMonitorDescriptor.java @@ -27,7 +27,6 @@ import hudson.Functions; import jenkins.MasterToSlaveFileCallable; import hudson.remoting.VirtualChannel; import hudson.Util; -import hudson.slaves.OfflineCause; import hudson.node_monitors.DiskSpaceMonitorDescriptor.DiskSpace; import java.io.File; @@ -37,6 +36,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 +82,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/java/hudson/node_monitors/NodeMonitor.java b/core/src/main/java/hudson/node_monitors/NodeMonitor.java index b608eb4ab9d8fb3c0a8ce34f8b2e19436b8cabb3..9429af2c1b548a307c930775809365d06ccef54c 100644 --- a/core/src/main/java/hudson/node_monitors/NodeMonitor.java +++ b/core/src/main/java/hudson/node_monitors/NodeMonitor.java @@ -139,6 +139,7 @@ public abstract class NodeMonitor implements ExtensionPoint, Describable LIST = new DescriptorList(NodeMonitor.class); /** diff --git a/core/src/main/java/hudson/node_monitors/NodeMonitorUpdater.java b/core/src/main/java/hudson/node_monitors/NodeMonitorUpdater.java index f46d9a2141b72bf1b8965434e55a9142514ac66f..9f3b5f19ff4a678c6ead27abab19da59c39f0529 100644 --- a/core/src/main/java/hudson/node_monitors/NodeMonitorUpdater.java +++ b/core/src/main/java/hudson/node_monitors/NodeMonitorUpdater.java @@ -4,11 +4,12 @@ import hudson.Extension; import hudson.model.Computer; import hudson.model.TaskListener; import hudson.slaves.ComputerListener; +import hudson.util.Futures; import jenkins.model.Jenkins; import java.io.IOException; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; import jenkins.util.Timer; @@ -20,7 +21,16 @@ import jenkins.util.Timer; @Extension public class NodeMonitorUpdater extends ComputerListener { - private final AtomicInteger id = new AtomicInteger(); + private static final Runnable MONITOR_UPDATER = new Runnable() { + @Override + public void run() { + for (NodeMonitor nm : Jenkins.getInstance().getComputer().getMonitors()) { + nm.triggerUpdate(); + } + } + }; + + private Future future = Futures.precomputed(null); /** * Triggers the update with 5 seconds quiet period, to avoid triggering data check too often @@ -28,18 +38,9 @@ public class NodeMonitorUpdater extends ComputerListener { */ @Override public void onOnline(Computer c, TaskListener listener) throws IOException, InterruptedException { - Timer.get().schedule(new Runnable() { - final int _id = id.incrementAndGet(); - - public void run() { - if (id.get() != _id) - return; - - for (NodeMonitor nm : Jenkins.getInstance().getComputer().getMonitors()) { - nm.triggerUpdate(); - } - } - }, 5, TimeUnit.SECONDS); + synchronized(this) { + future.cancel(false); + future = Timer.get().schedule(MONITOR_UPDATER, 5, TimeUnit.SECONDS); + } } - } diff --git a/core/src/main/java/hudson/node_monitors/ResponseTimeMonitor.java b/core/src/main/java/hudson/node_monitors/ResponseTimeMonitor.java index 69da2e6bcddc404dbdd75d506c91eed55c3e2576..af1c3a79e46c26b9de103cfd0a16a02419c22d66 100644 --- a/core/src/main/java/hudson/node_monitors/ResponseTimeMonitor.java +++ b/core/src/main/java/hudson/node_monitors/ResponseTimeMonitor.java @@ -25,7 +25,6 @@ package hudson.node_monitors; import hudson.Util; import hudson.Extension; -import hudson.slaves.OfflineCause; import hudson.model.Computer; import hudson.remoting.Callable; import jenkins.security.MasterToSlaveCallable; @@ -188,7 +187,7 @@ public class ResponseTimeMonitor extends NodeMonitor { } /** - * HTML rendering of the data + * String rendering of the data */ @Override public String toString() { @@ -200,7 +199,7 @@ public class ResponseTimeMonitor extends NodeMonitor { // return buf.toString(); int fc = failureCount(); if(fc>0) - return Util.wrapToErrorSpan(Messages.ResponseTimeMonitor_TimeOut(fc)); + return Messages.ResponseTimeMonitor_TimeOut(fc); return getAverage()+"ms"; } diff --git a/core/src/main/java/hudson/org/apache/tools/tar/TarInputStream.java b/core/src/main/java/hudson/org/apache/tools/tar/TarInputStream.java index f2d10c1c39960b09cb7ee9fd89505ba8fc9cb79a..d7d8a5b54da3e24bd7f83ea3f1d1f1306d63d77c 100644 --- a/core/src/main/java/hudson/org/apache/tools/tar/TarInputStream.java +++ b/core/src/main/java/hudson/org/apache/tools/tar/TarInputStream.java @@ -37,8 +37,9 @@ import java.io.ByteArrayOutputStream; * methods are provided to position at each successive entry in * the archive, and the read each entry as a normal input stream * using read(). - * + * @deprecated Use {@link org.apache.commons.compress.archivers.tar.TarArchiveInputStream} instead */ +@Deprecated public class TarInputStream extends FilterInputStream { // CheckStyle:VisibilityModifier OFF - bc diff --git a/core/src/main/java/hudson/org/apache/tools/tar/TarOutputStream.java b/core/src/main/java/hudson/org/apache/tools/tar/TarOutputStream.java index f23e44262847de611c21231223966e8f78d1c5b7..48f4876bd45c3cfee3fb0bd9a7d102df85162d19 100644 --- a/core/src/main/java/hudson/org/apache/tools/tar/TarOutputStream.java +++ b/core/src/main/java/hudson/org/apache/tools/tar/TarOutputStream.java @@ -35,8 +35,11 @@ import java.io.IOException; * The TarOutputStream writes a UNIX tar archive as an OutputStream. * Methods are provided to put entries, and then write their contents * by writing to this stream using write(). + * + * @deprecated Use {@link org.apache.commons.compress.archivers.tar.TarArchiveOutputStream} instead * */ +@Deprecated public class TarOutputStream extends FilterOutputStream { /** Fail if a long file name is required in the archive. */ public static final int LONGFILE_ERROR = 0; diff --git a/core/src/main/java/hudson/os/PosixAPI.java b/core/src/main/java/hudson/os/PosixAPI.java index 2e69069c1c2e4a94e7dfbb782be4e12d9112cbc4..f54f29331e8a1f3c7dfc4169e8c9089dac13f1b0 100644 --- a/core/src/main/java/hudson/os/PosixAPI.java +++ b/core/src/main/java/hudson/os/PosixAPI.java @@ -22,6 +22,7 @@ public class PosixAPI { /** * Load the JNR implementation of the POSIX APIs for the current platform. * Runtime exceptions will be of type {@link PosixException}. + * {@link IllegalStateException} will be thrown for methods not implemented on this platform. * @return some implementation (even on Windows or unsupported Unix) * @since 1.518 */ diff --git a/core/src/main/java/hudson/os/SU.java b/core/src/main/java/hudson/os/SU.java index 6a2b8abfa204be7534b9ae376e46a6db2c15ef9a..5998d366c0b753b5c85e382fee17cc7fcbead9c1 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/os/solaris/ZFSInstaller.java b/core/src/main/java/hudson/os/solaris/ZFSInstaller.java index 17a3bb48ac264566530a1d7e462ec4e049911b40..94ff9638d85123b81a87a36918243f134b5dd440 100644 --- a/core/src/main/java/hudson/os/solaris/ZFSInstaller.java +++ b/core/src/main/java/hudson/os/solaris/ZFSInstaller.java @@ -32,7 +32,6 @@ import hudson.os.SU; import hudson.model.AdministrativeMonitor; import jenkins.model.Jenkins; import hudson.model.TaskListener; -import hudson.remoting.Callable; import hudson.util.ForkOutputStream; import hudson.util.HudsonIsRestarting; import hudson.util.StreamTaskListener; diff --git a/core/src/main/java/hudson/os/solaris/ZFSProvisioner.java b/core/src/main/java/hudson/os/solaris/ZFSProvisioner.java index 649a4880f23df88ab1636f57af39b10004d76ba8..a2ba279f3b0c6bb58d3638ca38c77c51a0a47e23 100644 --- a/core/src/main/java/hudson/os/solaris/ZFSProvisioner.java +++ b/core/src/main/java/hudson/os/solaris/ZFSProvisioner.java @@ -102,6 +102,7 @@ public class ZFSProvisioner extends FileSystemProvisioner implements Serializabl /** * @deprecated as of 1.350 */ + @Deprecated public WorkspaceSnapshot snapshot(AbstractBuild build, FilePath ws, TaskListener listener) throws IOException, InterruptedException { throw new UnsupportedOperationException(); } diff --git a/core/src/main/java/hudson/scheduler/CronTab.java b/core/src/main/java/hudson/scheduler/CronTab.java index 9a86ec1400db87d76620377be6d1a0084f34610c..d289dc32efd0aeeb809e6663d9fcf6fb9b82ca5c 100644 --- a/core/src/main/java/hudson/scheduler/CronTab.java +++ b/core/src/main/java/hudson/scheduler/CronTab.java @@ -27,6 +27,7 @@ import antlr.ANTLRException; import java.io.StringReader; import java.util.Calendar; +import java.util.TimeZone; import java.util.GregorianCalendar; import java.util.Locale; import java.util.regex.Matcher; @@ -58,6 +59,11 @@ public final class CronTab { */ private String spec; + /** + * Optional timezone string for calendar + */ + private @CheckForNull String specTimezone; + public CronTab(String format) throws ANTLRException { this(format,null); } @@ -70,6 +76,7 @@ public final class CronTab { * @deprecated as of 1.448 * Use {@link #CronTab(String, int, Hash)} */ + @Deprecated public CronTab(String format, int line) throws ANTLRException { set(format, line, null); } @@ -80,15 +87,33 @@ public final class CronTab { * of not spreading it out at all. */ public CronTab(String format, int line, Hash hash) throws ANTLRException { - set(format, line, hash); + this(format, line, hash, null); + } + + /** + * @param timezone + * Used to schedule cron in a different timezone. Null to use the default system + * timezone + * @since 1.615 + */ + public CronTab(String format, int line, Hash hash, @CheckForNull String timezone) throws ANTLRException { + set(format, line, hash, timezone); } private void set(String format, int line, Hash hash) throws ANTLRException { + set(format, line, hash, null); + } + + /** + * @since 1.615 + */ + private void set(String format, int line, Hash hash, String timezone) throws ANTLRException { CrontabLexer lexer = new CrontabLexer(new StringReader(format)); lexer.setLine(line); CrontabParser parser = new CrontabParser(lexer); parser.setHash(hash); spec = format; + specTimezone = timezone; parser.startRule(this); if((dayOfWeek&(1<<7))!=0) { @@ -102,15 +127,24 @@ public final class CronTab { * Returns true if the given calendar matches */ boolean check(Calendar cal) { - if(!checkBits(bits[0],cal.get(MINUTE))) + + Calendar checkCal = cal; + + if(specTimezone != null && !specTimezone.isEmpty()) { + Calendar tzCal = Calendar.getInstance(TimeZone.getTimeZone(specTimezone)); + tzCal.setTime(cal.getTime()); + checkCal = tzCal; + } + + if(!checkBits(bits[0],checkCal.get(MINUTE))) return false; - if(!checkBits(bits[1],cal.get(HOUR_OF_DAY))) + if(!checkBits(bits[1],checkCal.get(HOUR_OF_DAY))) return false; - if(!checkBits(bits[2],cal.get(DAY_OF_MONTH))) + if(!checkBits(bits[2],checkCal.get(DAY_OF_MONTH))) return false; - if(!checkBits(bits[3],cal.get(MONTH)+1)) + if(!checkBits(bits[3],checkCal.get(MONTH)+1)) return false; - if(!checkBits(dayOfWeek,cal.get(Calendar.DAY_OF_WEEK)-1)) + if(!checkBits(dayOfWeek,checkCal.get(Calendar.DAY_OF_WEEK)-1)) return false; return true; diff --git a/core/src/main/java/hudson/scheduler/CronTabList.java b/core/src/main/java/hudson/scheduler/CronTabList.java index da3d0065f7e5217b27fdd6a9fd9304ed095d896b..3243dda38e113fa50573e516230b9be82555c7c0 100644 --- a/core/src/main/java/hudson/scheduler/CronTabList.java +++ b/core/src/main/java/hudson/scheduler/CronTabList.java @@ -25,12 +25,18 @@ package hudson.scheduler; import antlr.ANTLRException; import java.util.Calendar; +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; +import java.util.logging.Level; +import java.util.logging.Logger; + /** * {@link CronTab} list (logically OR-ed). * @@ -40,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); } /** @@ -71,24 +77,53 @@ public final class CronTabList { return null; } - public static CronTabList create(String format) throws ANTLRException { + /** + * Checks if given timezone string is supported by TimeZone and returns + * the same string if valid, null otherwise + * @since 1.615 + */ + public static @CheckForNull String getValidTimezone(String timezone) { + String[] validIDs = TimeZone.getAvailableIDs(); + for (String str : validIDs) { + if (str != null && str.equals(timezone)) { + return timezone; + } + } + return null; + } + + 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; + for (String line : format.split("\\r?\\n")) { lineNumber++; line = line.trim(); + + if(lineNumber == 1 && line.startsWith("TZ=")) { + timezone = getValidTimezone(line.replace("TZ=","")); + if(timezone != null) { + LOGGER.log(Level.CONFIG, "cron with timezone {0}", timezone); + } else { + LOGGER.log(Level.CONFIG, "invalid timezone {0}", line); + } + continue; + } + if(line.length()==0 || line.startsWith("#")) continue; // ignorable line try { - r.add(new CronTab(line,lineNumber,hash)); + r.add(new CronTab(line,lineNumber,hash,timezone)); } catch (ANTLRException e) { throw new ANTLRException(Messages.CronTabList_InvalidInput(line,e.toString()),e); } } + return new CronTabList(r); } @@ -115,5 +150,6 @@ public final class CronTabList { } return nearest; } - + + private static final Logger LOGGER = Logger.getLogger(CronTabList.class.getName()); } diff --git a/core/src/main/java/hudson/scm/ChangeLogAnnotator.java b/core/src/main/java/hudson/scm/ChangeLogAnnotator.java index 67173edb3bf77689cdd32aa175a28d1b6689f743..d393995f931764a2b81ea21ce3ea99127c192904 100644 --- a/core/src/main/java/hudson/scm/ChangeLogAnnotator.java +++ b/core/src/main/java/hudson/scm/ChangeLogAnnotator.java @@ -34,7 +34,6 @@ import hudson.model.Run; import hudson.scm.ChangeLogSet.Entry; import hudson.util.CopyOnWriteList; import java.util.logging.Logger; -import jenkins.model.Jenkins; /** * Performs mark up on changelog messages to be displayed. @@ -98,6 +97,7 @@ public abstract class ChangeLogAnnotator implements ExtensionPoint { * @deprecated as of 1.286 * Prefer automatic registration via {@link Extension} */ + @Deprecated public final void register() { all().add(this); } @@ -115,6 +115,7 @@ public abstract class ChangeLogAnnotator implements ExtensionPoint { * @deprecated as of 1.286 * Use {@link #all()} for read access, and {@link Extension} for registration. */ + @Deprecated public static final CopyOnWriteList annotators = ExtensionListView.createCopyOnWriteList(ChangeLogAnnotator.class); /** diff --git a/core/src/main/java/hudson/scm/PollingResult.java b/core/src/main/java/hudson/scm/PollingResult.java index a5ec21fb4079b51b9bb17357a92f945a003baeac..39b3a0caba817158fc398b612127250641c05e7b 100644 --- a/core/src/main/java/hudson/scm/PollingResult.java +++ b/core/src/main/java/hudson/scm/PollingResult.java @@ -7,7 +7,6 @@ import hudson.FilePath; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.io.Serializable; /** diff --git a/core/src/main/java/hudson/scm/RepositoryBrowsers.java b/core/src/main/java/hudson/scm/RepositoryBrowsers.java index 3c5dd86c0edc5648dac0d4b29bcdf0c93e47caab..c7d8ab90daaed28b6eedcb6884e21154d54326fb 100644 --- a/core/src/main/java/hudson/scm/RepositoryBrowsers.java +++ b/core/src/main/java/hudson/scm/RepositoryBrowsers.java @@ -46,6 +46,7 @@ public class RepositoryBrowsers { * @deprecated as of 1.286. * Use {@link RepositoryBrowser#all()} for read access and {@link Extension} for registration. */ + @Deprecated public static final List>> LIST = new DescriptorList>((Class)RepositoryBrowser.class); /** @@ -65,6 +66,7 @@ public class RepositoryBrowsers { * @deprecated since 2008-06-19. * Use {@link #createInstance(Class, StaplerRequest, JSONObject, String)}. */ + @Deprecated public static T createInstance(Class type, StaplerRequest req, String fieldName) throws FormException { List>> list = filter(type); diff --git a/core/src/main/java/hudson/scm/SCM.java b/core/src/main/java/hudson/scm/SCM.java index 297ec0e2e14f663f5384783b252aff642551a57f..e7597933d093dba6072f6e823752097dc0acf173 100644 --- a/core/src/main/java/hudson/scm/SCM.java +++ b/core/src/main/java/hudson/scm/SCM.java @@ -268,6 +268,7 @@ public abstract class SCM implements Describable, ExtensionPoint { * * Call {@link #poll(AbstractProject, Launcher, FilePath, TaskListener, SCMRevisionState)} for use instead. */ + @Deprecated public boolean pollChanges(AbstractProject project, Launcher launcher, FilePath workspace, TaskListener listener) throws IOException, InterruptedException { // up until 1.336, this method was abstract, so everyone should have overridden this method // without calling super.pollChanges. So the compatibility implementation is purely for @@ -578,6 +579,7 @@ public abstract class SCM implements Describable, ExtensionPoint { * @deprecated since 1.382 * Use/override {@link #getModuleRoot(FilePath, AbstractBuild)} instead. */ + @Deprecated public FilePath getModuleRoot(FilePath workspace) { if (Util.isOverridden(SCM.class,getClass(),"getModuleRoot", FilePath.class,AbstractBuild.class)) // if the subtype already implements newer getModuleRoot(FilePath,AbstractBuild), call that. @@ -632,6 +634,7 @@ public abstract class SCM implements Describable, ExtensionPoint { * @deprecated as of 1.382. * Use/derive from {@link #getModuleRoots(FilePath, AbstractBuild)} instead. */ + @Deprecated public FilePath[] getModuleRoots(FilePath workspace) { if (Util.isOverridden(SCM.class,getClass(),"getModuleRoots", FilePath.class, AbstractBuild.class)) // if the subtype already derives newer getModuleRoots(FilePath,AbstractBuild), delegate to it diff --git a/core/src/main/java/hudson/scm/SCMS.java b/core/src/main/java/hudson/scm/SCMS.java index 351d1b6a4782566ae668cd9818ed9215cacfa844..e79af364de0155313afcd770524439d8356cb410 100644 --- a/core/src/main/java/hudson/scm/SCMS.java +++ b/core/src/main/java/hudson/scm/SCMS.java @@ -45,6 +45,7 @@ public class SCMS { * @deprecated as of 1.286 * Use {@link SCM#all()} for read access and {@link Extension} for registration. */ + @Deprecated public static final List> SCMS = (List)new DescriptorList(SCM.class); /** @@ -67,6 +68,7 @@ public class SCMS { * @deprecated as of 1.294 * Use {@link #parseSCM(StaplerRequest, AbstractProject)} and pass in the caller's project type. */ + @Deprecated public static SCM parseSCM(StaplerRequest req) throws FormException, ServletException { return parseSCM(req,null); } diff --git a/core/src/main/java/hudson/search/Search.java b/core/src/main/java/hudson/search/Search.java index f6f5d1051a154015702df42241899b96aea78152..c817a26dbd171ce5c9508bb16bb9e71ec13c9e41 100644 --- a/core/src/main/java/hudson/search/Search.java +++ b/core/src/main/java/hudson/search/Search.java @@ -76,7 +76,7 @@ public class Search { SuggestedItem target = find(index, query, smo); if(target!=null) { // found - rsp.sendRedirect2(a.getUrl()+target.getUrl()); + rsp.sendRedirect2(req.getContextPath()+target.getUrl()); return; } } diff --git a/core/src/main/java/hudson/search/SearchFactory.java b/core/src/main/java/hudson/search/SearchFactory.java index 850672ffe9fc8ba61609a5ec8c865284f4217903..0e1290addb6a21eb0c4116e3c45ae4620230d427 100644 --- a/core/src/main/java/hudson/search/SearchFactory.java +++ b/core/src/main/java/hudson/search/SearchFactory.java @@ -3,7 +3,6 @@ package hudson.search; import hudson.Extension; import hudson.ExtensionList; import hudson.ExtensionPoint; -import jenkins.model.Jenkins; /** * Creates a {@link Search} instance for a {@link SearchableModelObject}. diff --git a/core/src/main/java/hudson/search/SuggestedItem.java b/core/src/main/java/hudson/search/SuggestedItem.java index 1dbcad9c3d0abfd10354cea6c29bd90779b8137b..31e5956ce4ed707cdd737a7412e0e5b5282744c9 100644 --- a/core/src/main/java/hudson/search/SuggestedItem.java +++ b/core/src/main/java/hudson/search/SuggestedItem.java @@ -81,7 +81,7 @@ public class SuggestedItem { private static SuggestedItem build(SearchableModelObject searchContext, Item top) { ItemGroup parent = top.getParent(); - if (parent instanceof Item && parent != searchContext) { + if (parent instanceof Item) { Item parentItem = (Item)parent; return new SuggestedItem(build(searchContext, parentItem), top); } diff --git a/core/src/main/java/hudson/security/ACL.java b/core/src/main/java/hudson/security/ACL.java index 2a1b230f5fcd2625965b320f2d1ea9499ae73152..e4736cbe9e2ce54a14c551c8f45c30cb745a4fa6 100644 --- a/core/src/main/java/hudson/security/ACL.java +++ b/core/src/main/java/hudson/security/ACL.java @@ -24,7 +24,11 @@ package hudson.security; import javax.annotation.Nonnull; + +import hudson.model.Item; import hudson.remoting.Callable; +import hudson.model.ItemGroup; +import hudson.model.TopLevelItemDescriptor; import jenkins.security.NonSerializableSecurityContext; import jenkins.model.Jenkins; import jenkins.security.NotReallyRoleSensitiveCallable; @@ -35,6 +39,8 @@ import org.acegisecurity.context.SecurityContextHolder; import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; import org.acegisecurity.acls.sid.PrincipalSid; import org.acegisecurity.acls.sid.Sid; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; /** * Gate-keeper that controls access to Hudson's model objects. @@ -76,6 +82,42 @@ public abstract class ACL { */ public abstract boolean hasPermission(@Nonnull Authentication a, @Nonnull Permission permission); + /** + * Checks if the current security principal has the permission to create top level items within the specified + * item group. + *

+ * This is just a convenience function. + * @param c the container of the item. + * @param d the descriptor of the item to be created. + * @throws AccessDeniedException + * if the user doesn't have the permission. + * @since TODO + */ + public final void checkCreatePermission(@Nonnull ItemGroup c, + @Nonnull TopLevelItemDescriptor d) { + Authentication a = Jenkins.getAuthentication(); + if (!hasCreatePermission(a, c, d)) { + throw new AccessDeniedException(Messages.AccessDeniedException2_MissingPermission(a.getName(), + Item.CREATE.group.title+"/"+Item.CREATE.name + Item.CREATE + "/" + d.getDisplayName())); + } + } + /** + * Checks if the given principal has the permission to create top level items within the specified item group. + *

+ * Note that {@link #SYSTEM} can be passed in as the authentication parameter, + * in which case you should probably just assume it can create anything anywhere. + * @param a the principal. + * @param c the container of the item. + * @param d the descriptor of the item to be created. + * @return false + * if the user doesn't have the permission. + * @since TODO + */ + public boolean hasCreatePermission(@Nonnull Authentication a, @Nonnull ItemGroup c, + @Nonnull TopLevelItemDescriptor d) { + return true; + } + // // Sid constants // @@ -85,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() { @@ -95,23 +137,34 @@ public abstract class ACL { } }; + /** + * The username for the anonymous user + */ + @Restricted(NoExternalUse.class) + public static final String ANONYMOUS_USERNAME = "anonymous"; /** * {@link Sid} that represents the anonymous unauthenticated users. *

* {@link HudsonFilter} sets this up, so this sid remains the same * regardless of the current {@link SecurityRealm} in use. */ - public static final Sid ANONYMOUS = new PrincipalSid("anonymous"); + public static final Sid ANONYMOUS = new PrincipalSid(ANONYMOUS_USERNAME); protected static final Sid[] AUTOMATIC_SIDS = new Sid[]{EVERYONE,ANONYMOUS}; + /** + * The username for the system user + */ + @Restricted(NoExternalUse.class) + public static final String SYSTEM_USERNAME = "SYSTEM"; + /** * {@link Sid} that represents the Hudson itself. *

* This is used when Hudson is performing computation for itself, instead * of acting on behalf of an user, such as doing builds. */ - public static final Authentication SYSTEM = new UsernamePasswordAuthenticationToken("SYSTEM","SYSTEM"); + public static final Authentication SYSTEM = new UsernamePasswordAuthenticationToken(SYSTEM_USERNAME,"SYSTEM"); /** * Changes the {@link Authentication} associated with the current thread diff --git a/core/src/main/java/hudson/security/AuthorizationStrategy.java b/core/src/main/java/hudson/security/AuthorizationStrategy.java index 22d21d72fc15a9cd551704dc8adc9c3f7b296f5e..f544e8ad300ad4ebe01dbe6f7ca9206e944e5a7f 100644 --- a/core/src/main/java/hudson/security/AuthorizationStrategy.java +++ b/core/src/main/java/hudson/security/AuthorizationStrategy.java @@ -194,6 +194,7 @@ public abstract class AuthorizationStrategy extends AbstractDescribableImpl LIST = new DescriptorList(AuthorizationStrategy.class); /** diff --git a/core/src/main/java/hudson/security/BasicAuthenticationFilter.java b/core/src/main/java/hudson/security/BasicAuthenticationFilter.java index 8d18afff06274a2f6e1be20ea75f85b0a7f2de1d..c31876a6d1ac0df3588e0a7e4b25d8fc27ff22b0 100644 --- a/core/src/main/java/hudson/security/BasicAuthenticationFilter.java +++ b/core/src/main/java/hudson/security/BasicAuthenticationFilter.java @@ -28,8 +28,6 @@ import jenkins.model.Jenkins; import hudson.util.Scrambler; import jenkins.security.ApiTokenProperty; import org.acegisecurity.context.SecurityContextHolder; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; import javax.servlet.Filter; import javax.servlet.FilterChain; diff --git a/core/src/main/java/hudson/security/DeferredCreationLdapAuthoritiesPopulator.java b/core/src/main/java/hudson/security/DeferredCreationLdapAuthoritiesPopulator.java index 34276f279ae943062683f128b4ccaf715bcfa63c..f6ae9ca44d2518006708c6435d903eb6fdc3639a 100644 --- a/core/src/main/java/hudson/security/DeferredCreationLdapAuthoritiesPopulator.java +++ b/core/src/main/java/hudson/security/DeferredCreationLdapAuthoritiesPopulator.java @@ -44,6 +44,7 @@ import hudson.security.SecurityRealm.SecurityComponents; * {@link SecurityComponents} are now created after {@link SecurityRealm} is created, so * the initialization order issue that this code was trying to address no longer exists. */ +@Deprecated public class DeferredCreationLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator { /** diff --git a/core/src/main/java/hudson/security/FullControlOnceLoggedInAuthorizationStrategy.java b/core/src/main/java/hudson/security/FullControlOnceLoggedInAuthorizationStrategy.java index c9808c43712e6a9f159affbc5af0a69d5687aa9b..8b2239f2f4b9e1d766d703181d80348282c9901c 100644 --- a/core/src/main/java/hudson/security/FullControlOnceLoggedInAuthorizationStrategy.java +++ b/core/src/main/java/hudson/security/FullControlOnceLoggedInAuthorizationStrategy.java @@ -23,17 +23,17 @@ */ package hudson.security; +import hudson.Extension; import hudson.model.Descriptor; import jenkins.model.Jenkins; -import hudson.Extension; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.kohsuke.stapler.DataBoundConstructor; +import javax.inject.Inject; import java.util.Collections; import java.util.List; -import net.sf.json.JSONObject; - -import org.kohsuke.stapler.StaplerRequest; - /** * {@link AuthorizationStrategy} that grants full-control to authenticated user * (other than anonymous users.) @@ -41,6 +41,10 @@ import org.kohsuke.stapler.StaplerRequest; * @author Kohsuke Kawaguchi */ public class FullControlOnceLoggedInAuthorizationStrategy extends AuthorizationStrategy { + @DataBoundConstructor + public FullControlOnceLoggedInAuthorizationStrategy() { + } + @Override public ACL getRootACL() { return THE_ACL; @@ -58,15 +62,21 @@ public class FullControlOnceLoggedInAuthorizationStrategy extends AuthorizationS THE_ACL.add(ACL.ANONYMOUS,Permission.READ,true); } + /** + * @deprecated as of 1.643 + * Inject descriptor via {@link Inject}. + */ + @Restricted(NoExternalUse.class) + public static Descriptor DESCRIPTOR; + @Extension - public static final Descriptor DESCRIPTOR = new Descriptor() { - public String getDisplayName() { - return Messages.FullControlOnceLoggedInAuthorizationStrategy_DisplayName(); + public static class DescriptorImpl extends Descriptor { + public DescriptorImpl() { + DESCRIPTOR = this; } - @Override - public AuthorizationStrategy newInstance(StaplerRequest req, JSONObject formData) throws FormException { - return new FullControlOnceLoggedInAuthorizationStrategy(); + public String getDisplayName() { + return Messages.FullControlOnceLoggedInAuthorizationStrategy_DisplayName(); } - }; + } } diff --git a/core/src/main/java/hudson/security/HudsonAuthenticationEntryPoint.java b/core/src/main/java/hudson/security/HudsonAuthenticationEntryPoint.java index 30f386eb1fa086e1183a7092aa96fdcc81b033cf..b590dce40842558b814c84d65a179261b08374f7 100644 --- a/core/src/main/java/hudson/security/HudsonAuthenticationEntryPoint.java +++ b/core/src/main/java/hudson/security/HudsonAuthenticationEntryPoint.java @@ -24,8 +24,6 @@ package hudson.security; import hudson.Functions; -import jenkins.model.Jenkins; -import hudson.TcpSlaveAgentListener; import com.google.common.base.Strings; import org.acegisecurity.AuthenticationException; diff --git a/core/src/main/java/hudson/security/HudsonFilter.java b/core/src/main/java/hudson/security/HudsonFilter.java index 40c7e7c69de6c68f255925ae4c3e45d0bd1343a1..3a1868344a71babec7d6ab4a09e9e6dcb225f2af 100644 --- a/core/src/main/java/hudson/security/HudsonFilter.java +++ b/core/src/main/java/hudson/security/HudsonFilter.java @@ -36,6 +36,7 @@ import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; import org.acegisecurity.AuthenticationManager; import org.acegisecurity.ui.rememberme.RememberMeServices; @@ -73,6 +74,7 @@ public class HudsonFilter implements Filter { * This proxy always delegate to {@code Hudson.getInstance().getSecurityRealm().getSecurityComponents().manager}, * so use that instead. */ + @Deprecated public static final AuthenticationManagerProxy AUTHENTICATION_MANAGER = new AuthenticationManagerProxy(); /** @@ -83,6 +85,7 @@ public class HudsonFilter implements Filter { * This proxy always delegate to {@code Hudson.getInstance().getSecurityRealm().getSecurityComponents().userDetails}, * so use that instead. */ + @Deprecated public static final UserDetailsServiceProxy USER_DETAILS_SERVICE_PROXY = new UserDetailsServiceProxy(); /** @@ -93,6 +96,7 @@ public class HudsonFilter implements Filter { * This proxy always delegate to {@code Hudson.getInstance().getSecurityRealm().getSecurityComponents().rememberMe}, * so use that instead. */ + @Deprecated public static final RememberMeServicesProxy REMEMBER_ME_SERVICES_PROXY = new RememberMeServicesProxy(); public void init(FilterConfig filterConfig) throws ServletException { @@ -153,7 +157,10 @@ public class HudsonFilter implements Filter { public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { LOGGER.entering(HudsonFilter.class.getName(), "doFilter"); - + + // this is not the best place to do it, but doing it here makes the patch smaller. + ((HttpServletResponse)response).setHeader("X-Content-Type-Options", "nosniff"); + // to deal with concurrency, we need to capture the object. Filter f = filter; diff --git a/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java b/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java index 642ebac84b2009e9228beebe1748881c40875819..ffaf8311d7849a2f2389468647eb8f0dce09e7af 100644 --- a/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java +++ b/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java @@ -337,6 +337,14 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea if(si.email==null || !si.email.contains("@")) si.errorMessage = Messages.HudsonPrivateSecurityRealm_CreateAccount_InvalidEmailAddress(); + if (! User.isIdOrFullnameAllowed(si.username)) { + si.errorMessage = hudson.model.Messages.User_IllegalUsername(si.username); + } + + if (! User.isIdOrFullnameAllowed(si.fullname)) { + si.errorMessage = hudson.model.Messages.User_IllegalFullname(si.fullname); + } + if(si.errorMessage!=null) { // failed. ask the user to try again. req.setAttribute("data",si); @@ -459,6 +467,7 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea * Field kept here to load old (pre 1.283) user records, * but now marked transient so field is no longer saved. */ + @Deprecated private transient String password; private Details(String passwordHash) { @@ -532,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 @@ -559,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/hudson/security/InvalidatableUserDetails.java b/core/src/main/java/hudson/security/InvalidatableUserDetails.java index 8c3e2551d4fa89c8f22c91cba608bb88739fe36a..8f59170c01bf87fb9ad8b25ba3942108f51aa53d 100644 --- a/core/src/main/java/hudson/security/InvalidatableUserDetails.java +++ b/core/src/main/java/hudson/security/InvalidatableUserDetails.java @@ -54,6 +54,7 @@ import jenkins.security.NonSerializableSecurityContext; * Starting 1.285, Hudson stops persisting {@link Authentication} altogether * (see {@link NonSerializableSecurityContext}), so there's no need to use this mechanism. */ +@Deprecated public interface InvalidatableUserDetails extends UserDetails { boolean isInvalid(); } diff --git a/core/src/main/java/hudson/security/LegacyAuthorizationStrategy.java b/core/src/main/java/hudson/security/LegacyAuthorizationStrategy.java index f9a50993f1734de6f11407804b8562a1f890a969..f850df6a886d277eacbe8c892c60da2f9ba692eb 100644 --- a/core/src/main/java/hudson/security/LegacyAuthorizationStrategy.java +++ b/core/src/main/java/hudson/security/LegacyAuthorizationStrategy.java @@ -23,12 +23,11 @@ */ package hudson.security; +import hudson.Extension; import hudson.model.Descriptor; import jenkins.model.Jenkins; -import hudson.Extension; import org.acegisecurity.acls.sid.GrantedAuthoritySid; -import org.kohsuke.stapler.StaplerRequest; -import net.sf.json.JSONObject; +import org.kohsuke.stapler.DataBoundConstructor; import java.util.Collection; import java.util.Collections; @@ -43,6 +42,10 @@ public final class LegacyAuthorizationStrategy extends AuthorizationStrategy { add(new GrantedAuthoritySid("admin"), Jenkins.ADMINISTER,true); }}; + @DataBoundConstructor + public LegacyAuthorizationStrategy() { + } + public ACL getRootACL() { return LEGACY_ACL; } @@ -56,9 +59,5 @@ public final class LegacyAuthorizationStrategy extends AuthorizationStrategy { public String getDisplayName() { return Messages.LegacyAuthorizationStrategy_DisplayName(); } - - public LegacyAuthorizationStrategy newInstance(StaplerRequest req, JSONObject formData) throws FormException { - return new LegacyAuthorizationStrategy(); - } } } diff --git a/core/src/main/java/hudson/security/Permission.java b/core/src/main/java/hudson/security/Permission.java index 7c758072da9f433e291a7c9003d41e78ed8935ca..2bfdeb0bc9bffb6ff506f9999c58d3fce6bc9c58 100644 --- a/core/src/main/java/hudson/security/Permission.java +++ b/core/src/main/java/hudson/security/Permission.java @@ -173,6 +173,7 @@ public final class Permission { * @deprecated as of 1.421 * Use {@link #Permission(PermissionGroup, String, Localizable, Permission, boolean, PermissionScope[])} */ + @Deprecated public Permission(@Nonnull PermissionGroup group, @Nonnull String name, @CheckForNull Localizable description, @CheckForNull Permission impliedBy, boolean enable) { this(group,name,description,impliedBy,enable,new PermissionScope[]{PermissionScope.JENKINS}); } @@ -181,6 +182,7 @@ public final class Permission { * @deprecated as of 1.421 * Use {@link #Permission(PermissionGroup, String, Localizable, Permission, PermissionScope)} */ + @Deprecated public Permission(@Nonnull PermissionGroup group, @Nonnull String name, @CheckForNull Localizable description, @CheckForNull Permission impliedBy) { this(group, name, description, impliedBy, PermissionScope.JENKINS); } @@ -189,6 +191,7 @@ public final class Permission { * @deprecated since 1.257. * Use {@link #Permission(PermissionGroup, String, Localizable, Permission)} */ + @Deprecated public Permission(@Nonnull PermissionGroup group, @Nonnull String name, @CheckForNull Permission impliedBy) { this(group,name,null,impliedBy); } @@ -293,6 +296,7 @@ public final class Permission { * @deprecated since 2009-01-23. * Access {@link jenkins.model.Jenkins#PERMISSIONS} instead. */ + @Deprecated public static final PermissionGroup HUDSON_PERMISSIONS = new PermissionGroup(Hudson.class, hudson.model.Messages._Hudson_Permissions_Title()); /** * {@link Permission} that represents the God-like access. Equivalent of Unix root. @@ -303,6 +307,7 @@ public final class Permission { * @deprecated since 2009-01-23. * Access {@link jenkins.model.Jenkins#ADMINISTER} instead. */ + @Deprecated public static final Permission HUDSON_ADMINISTER = new Permission(HUDSON_PERMISSIONS,"Administer", hudson.model.Messages._Hudson_AdministerPermission_Description(),null); // @@ -322,6 +327,7 @@ public final class Permission { * @deprecated since 2009-01-23. * Use {@link jenkins.model.Jenkins#ADMINISTER}. */ + @Deprecated public static final Permission FULL_CONTROL = new Permission(GROUP, "FullControl",null, HUDSON_ADMINISTER); /** diff --git a/core/src/main/java/hudson/security/PermissionAdder.java b/core/src/main/java/hudson/security/PermissionAdder.java index 9c6186e667eca5486ed1944be4ee74f5e3da19f4..1e963fa0702ce7be4ea14619937c111e7d67725a 100644 --- a/core/src/main/java/hudson/security/PermissionAdder.java +++ b/core/src/main/java/hudson/security/PermissionAdder.java @@ -26,7 +26,6 @@ package hudson.security; import hudson.ExtensionPoint; import hudson.model.User; -import jenkins.model.Jenkins; /** * Service which can add permissions for a given user to the configured authorization strategy. diff --git a/core/src/main/java/hudson/security/SecurityRealm.java b/core/src/main/java/hudson/security/SecurityRealm.java index 4e4e8484a4a517888a499864b949bf8be7345770..577f7f60f55f9614f8fe56d51aebf6a0225d727a 100644 --- a/core/src/main/java/hudson/security/SecurityRealm.java +++ b/core/src/main/java/hudson/security/SecurityRealm.java @@ -202,6 +202,7 @@ public abstract class SecurityRealm extends AbstractDescribableImplconfig.jelly and never with * global.jelly. */ + @Override public Descriptor getDescriptor() { return super.getDescriptor(); } @@ -357,7 +358,7 @@ public abstract class SecurityRealm extends AbstractDescribableImpl LIST = new DescriptorList(SecurityRealm.class); /** diff --git a/core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java b/core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java index 6ff8da82274aaf441221e2ded8f6cb9046a45987..6ae4d1c42626f5c8dc58b2201122751b644c4e43 100644 --- a/core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java +++ b/core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java @@ -1,18 +1,18 @@ /* * 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 @@ -35,8 +35,11 @@ import org.acegisecurity.userdetails.UserDetailsService; import org.apache.commons.codec.binary.Base64; import org.springframework.util.Assert; +import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Date; /** @@ -128,8 +131,41 @@ public class TokenBasedRememberMeServices2 extends TokenBasedRememberMeServices } } - /** + @Override + protected Cookie makeValidCookie(String tokenValueBase64, HttpServletRequest request, long maxAge) { + Cookie cookie = super.makeValidCookie(tokenValueBase64, request, maxAge); + // if we can mark the cookie HTTP only, do so to protect this cookie even in case of XSS vulnerability. + if (SET_HTTP_ONLY!=null) { + try { + SET_HTTP_ONLY.invoke(cookie,true); + } catch (IllegalAccessException e) { + // ignore + } catch (InvocationTargetException e) { + // ignore + } + } + + // if the user is running Jenkins over HTTPS, we also want to prevent the cookie from leaking in HTTP. + // whether the login is done over HTTPS or not would be a good enough approximation of whether Jenkins runs in + // HTTPS or not, so use that. + if (request.isSecure()) + cookie.setSecure(true); + return cookie; + } + + /** * Used to compute the token signature securely. */ private static final HMACConfidentialKey MAC = new HMACConfidentialKey(TokenBasedRememberMeServices.class,"mac"); + + private static final Method SET_HTTP_ONLY; + + static { + Method m = null; + try { + m = Cookie.class.getMethod("setHttpOnly", boolean.class); + } catch (NoSuchMethodException x) { // 3.0+ + } + SET_HTTP_ONLY = m; + } } diff --git a/core/src/main/java/hudson/security/csrf/CrumbExclusion.java b/core/src/main/java/hudson/security/csrf/CrumbExclusion.java index 688e2a9822db91a2b58167d25ffea9c73e2fd3ed..8b48ec4dca24cbda6ffde4adc389b7f919a63cb5 100644 --- a/core/src/main/java/hudson/security/csrf/CrumbExclusion.java +++ b/core/src/main/java/hudson/security/csrf/CrumbExclusion.java @@ -7,7 +7,6 @@ package hudson.security.csrf; import hudson.ExtensionList; import hudson.ExtensionPoint; -import jenkins.model.Jenkins; import javax.servlet.FilterChain; import javax.servlet.ServletException; diff --git a/core/src/main/java/hudson/security/csrf/CrumbFilter.java b/core/src/main/java/hudson/security/csrf/CrumbFilter.java index 788eaa50caf30d37e3bb46671568b3af04380cbf..8e0fe64cb6a0dee09eaa392956395aa993159513 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; @@ -80,8 +81,8 @@ public class CrumbFilter implements Filter { LOGGER.log(Level.WARNING, "Found invalid crumb {0}. Will check remaining parameters for a valid one...", crumb); } } - // Multipart requests need to be handled by each handler. - if (valid || isMultipart(httpRequest)) { + + if (valid) { chain.doFilter(request, response); } else { LOGGER.log(Level.WARNING, "No valid crumb was included in request for {0}. Returning {1}.", new Object[] {httpRequest.getRequestURI(), HttpServletResponse.SC_FORBIDDEN}); @@ -97,28 +98,13 @@ 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.isMultiPartForm(request.getContentType()); } /** * {@inheritDoc} */ + @Override public void destroy() { } diff --git a/core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java b/core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java index f23699b7581d128896d1e2d861e28c2b286a0781..b801866fa671688bc5f1bd75247987929f6c927a 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(); } diff --git a/core/src/main/java/hudson/slaves/AbstractCloudSlave.java b/core/src/main/java/hudson/slaves/AbstractCloudSlave.java index 9b96e4af117263c21a899a86d4b97966b59a0909..cc7967d8efd319ef6ab7ba46b7629eb048dcd528 100644 --- a/core/src/main/java/hudson/slaves/AbstractCloudSlave.java +++ b/core/src/main/java/hudson/slaves/AbstractCloudSlave.java @@ -23,6 +23,7 @@ */ package hudson.slaves; +import hudson.model.Computer; import hudson.model.Descriptor.FormException; import jenkins.model.Jenkins; import hudson.model.Slave; @@ -57,6 +58,10 @@ public abstract class AbstractCloudSlave extends Slave { * Releases and removes this slave. */ public void terminate() throws InterruptedException, IOException { + final Computer computer = toComputer(); + if (computer != null) { + computer.recordTermination(); + } try { // TODO: send the output to somewhere real _terminate(new StreamTaskListener(System.out, Charset.defaultCharset())); diff --git a/core/src/main/java/hudson/slaves/Channels.java b/core/src/main/java/hudson/slaves/Channels.java index 1f2878a57c1ee1e8d32ea45a1c11419d52d5c55e..873cdbe4e3bb8a1754338d02b1506474dea85cdb 100644 --- a/core/src/main/java/hudson/slaves/Channels.java +++ b/core/src/main/java/hudson/slaves/Channels.java @@ -62,6 +62,7 @@ public class Channels { * @deprecated since 2009-04-13. * Use {@link #forProcess(String, ExecutorService, InputStream, OutputStream, OutputStream, Proc)} */ + @Deprecated public static Channel forProcess(String name, ExecutorService execService, InputStream in, OutputStream out, Proc proc) throws IOException { return forProcess(name,execService,in,out,null,proc); } diff --git a/core/src/main/java/hudson/slaves/Cloud.java b/core/src/main/java/hudson/slaves/Cloud.java index ef7469f33fc2bdb8d01c752630f87be30d218d69..c3e3679474c1585382b4c117a6efcdecd33a2165 100644 --- a/core/src/main/java/hudson/slaves/Cloud.java +++ b/core/src/main/java/hudson/slaves/Cloud.java @@ -165,6 +165,7 @@ public abstract class Cloud extends AbstractModelObject implements ExtensionPoin * @deprecated as of 1.286 * Use {@link #all()} for read access, and {@link Extension} for registration. */ + @Deprecated public static final DescriptorList ALL = new DescriptorList(Cloud.class); /** diff --git a/core/src/main/java/hudson/slaves/CloudProvisioningListener.java b/core/src/main/java/hudson/slaves/CloudProvisioningListener.java index 0041ebfefcb631dd3c7a04732d23823db52b8b6d..7789824d5f9ae777de5822cab951d9bb094c7a70 100644 --- a/core/src/main/java/hudson/slaves/CloudProvisioningListener.java +++ b/core/src/main/java/hudson/slaves/CloudProvisioningListener.java @@ -5,8 +5,6 @@ import hudson.ExtensionPoint; import hudson.model.Label; import hudson.model.Node; import hudson.model.queue.CauseOfBlockage; -import jenkins.model.Jenkins; -import org.jvnet.localizer.Localizable; import java.util.Collection; diff --git a/core/src/main/java/hudson/slaves/CloudRetentionStrategy.java b/core/src/main/java/hudson/slaves/CloudRetentionStrategy.java index 25fddc96b6b210ea9ccd7d99a4ce531d9664e8be..054a13b6ac5e9a77732da7d025ef0e2c2fdb8b05 100644 --- a/core/src/main/java/hudson/slaves/CloudRetentionStrategy.java +++ b/core/src/main/java/hudson/slaves/CloudRetentionStrategy.java @@ -23,11 +23,8 @@ */ package hudson.slaves; -import hudson.model.Computer; -import hudson.model.Node; -import hudson.model.Queue; -import jenkins.model.Jenkins; +import javax.annotation.concurrent.GuardedBy; import java.io.IOException; import java.util.logging.Logger; @@ -50,30 +47,20 @@ public class CloudRetentionStrategy extends RetentionStrategy MINUTES.toMillis(idleMinutes)) { - Queue.withLock(new Runnable() { - @Override - public void run() { - // re-check idle now that we are within the Queue lock - if (c.isIdle()) { - final long idleMilliseconds = System.currentTimeMillis() - c.getIdleStartMilliseconds(); - if (idleMilliseconds > MINUTES.toMillis(idleMinutes)) { - LOGGER.log(Level.INFO, "Disconnecting {0}", c.getName()); - try { - computerNode.terminate(); - } catch (InterruptedException e) { - LOGGER.log(WARNING, "Failed to terminate " + c.getName(), e); - } catch (IOException e) { - LOGGER.log(WARNING, "Failed to terminate " + c.getName(), e); - } - } - } - } - }); + LOGGER.log(Level.INFO, "Disconnecting {0}", c.getName()); + try { + computerNode.terminate(); + } catch (InterruptedException e) { + LOGGER.log(WARNING, "Failed to terminate " + c.getName(), e); + } catch (IOException e) { + LOGGER.log(WARNING, "Failed to terminate " + c.getName(), e); + } } } return 1; diff --git a/core/src/main/java/hudson/slaves/CloudSlaveRetentionStrategy.java b/core/src/main/java/hudson/slaves/CloudSlaveRetentionStrategy.java index 0c965508a390b0a9c6b5487415fd4e8470d0b077..ac9a404d47ae5dd63884bb61812bdaafb68c7db6 100644 --- a/core/src/main/java/hudson/slaves/CloudSlaveRetentionStrategy.java +++ b/core/src/main/java/hudson/slaves/CloudSlaveRetentionStrategy.java @@ -5,6 +5,7 @@ import hudson.model.Node; import hudson.util.TimeUnit2; import jenkins.model.Jenkins; +import javax.annotation.concurrent.GuardedBy; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; @@ -22,6 +23,7 @@ import java.util.logging.Logger; public class CloudSlaveRetentionStrategy extends RetentionStrategy { @Override + @GuardedBy("hudson.model.Queue.lock") public long check(T c) { if (!c.isConnecting() && c.isAcceptingTasks()) { if (isIdleForTooLong(c)) { diff --git a/core/src/main/java/hudson/slaves/CommandLauncher.java b/core/src/main/java/hudson/slaves/CommandLauncher.java index 8d08f9b39c3a97ee010b4ce470773cf9e7132878..66cfaaf05636a18ae4e6ad53f0a9cc56d9442ae6 100644 --- a/core/src/main/java/hudson/slaves/CommandLauncher.java +++ b/core/src/main/java/hudson/slaves/CommandLauncher.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Stephen Connolly - * + * * 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 @@ -41,6 +41,7 @@ import java.util.Date; import java.util.logging.Level; import java.util.logging.Logger; +import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; @@ -57,7 +58,7 @@ public class CommandLauncher extends ComputerLauncher { * "ssh myslave java -jar /path/to/hudson-remoting.jar" */ private final String agentCommand; - + /** * Optional environment variables to add to the current environment. Can be null. */ @@ -67,7 +68,7 @@ public class CommandLauncher extends ComputerLauncher { public CommandLauncher(String command) { this(command, null); } - + public CommandLauncher(String command, EnvVars env) { this.agentCommand = command; this.env = env; @@ -90,10 +91,10 @@ public class CommandLauncher extends ComputerLauncher { Process _proc = null; try { Slave node = computer.getNode(); - if (node == null) { + if (node == null) { throw new AbortException("Cannot launch commands on deleted nodes"); } - + listener.getLogger().println(hudson.model.Messages.Slave_Launching(getTimestamp())); if(getCommand().trim().length()==0) { listener.getLogger().println(Messages.CommandLauncher_NoLaunchCommand()); @@ -103,8 +104,8 @@ public class CommandLauncher extends ComputerLauncher { ProcessBuilder pb = new ProcessBuilder(Util.tokenize(getCommand())); final EnvVars cookie = _cookie = EnvVars.createCookie(); - pb.environment().putAll(cookie); - pb.environment().put("WORKSPACE", node.getRemoteFS()); //path for local slave log + pb.environment().putAll(cookie); + pb.environment().put("WORKSPACE", StringUtils.defaultString(computer.getAbsoluteRemoteFs(), node.getRemoteFS())); //path for local slave log {// system defined variables String rootUrl = Jenkins.getInstance().getRootUrl(); @@ -118,7 +119,7 @@ public class CommandLauncher extends ComputerLauncher { if (env != null) { pb.environment().putAll(env); } - + final Process proc = _proc = pb.start(); // capture error information from stderr. this will terminate itself @@ -129,14 +130,7 @@ public class CommandLauncher extends ComputerLauncher { computer.setChannel(proc.getInputStream(), proc.getOutputStream(), listener.getLogger(), new Channel.Listener() { @Override public void onClosed(Channel channel, IOException cause) { - try { - int exitCode = proc.exitValue(); - if (exitCode!=0) { - listener.error("Process terminated with exit code "+exitCode); - } - } catch (IllegalThreadStateException e) { - // hasn't terminated yet - } + reportProcessTerminated(proc, listener); try { ProcessTree.get().killAll(proc, cookie); @@ -166,12 +160,23 @@ public class CommandLauncher extends ComputerLauncher { LOGGER.log(Level.SEVERE, msg, e); e.printStackTrace(listener.error(msg)); - if(_proc!=null) + if(_proc!=null) { + reportProcessTerminated(_proc, listener); try { ProcessTree.get().killAll(_proc, _cookie); } catch (InterruptedException x) { x.printStackTrace(listener.error(Messages.ComputerLauncher_abortedLaunch())); } + } + } + } + + private static void reportProcessTerminated(Process proc, TaskListener listener) { + try { + int exitCode = proc.exitValue(); + listener.error("Process terminated with exit code " + exitCode); + } catch (IllegalThreadStateException e) { + // hasn't terminated yet } } diff --git a/core/src/main/java/hudson/slaves/ComputerLauncher.java b/core/src/main/java/hudson/slaves/ComputerLauncher.java index 56b78c76969cf27f04e85e9537300f529840e427..18c44d7b6024c9cc9c92d6b7fb2a1351da65f44b 100644 --- a/core/src/main/java/hudson/slaves/ComputerLauncher.java +++ b/core/src/main/java/hudson/slaves/ComputerLauncher.java @@ -93,6 +93,7 @@ public abstract class ComputerLauncher extends AbstractDescribableImpl LIST = new DescriptorList(ComputerLauncher.class); /** diff --git a/core/src/main/java/hudson/slaves/ComputerListener.java b/core/src/main/java/hudson/slaves/ComputerListener.java index 5af844859ed4a9d61935d71c31c5ce4f159f477e..01c0cfab6e97f863032cf5e6d0d2b14cd7b08325 100644 --- a/core/src/main/java/hudson/slaves/ComputerListener.java +++ b/core/src/main/java/hudson/slaves/ComputerListener.java @@ -31,10 +31,7 @@ import hudson.FilePath; import hudson.model.Computer; import hudson.model.Node; import hudson.model.TaskListener; -import org.jenkinsci.remoting.CallableDecorator; import hudson.remoting.Channel; -import hudson.remoting.ChannelBuilder; -import jenkins.model.Jenkins; import java.io.IOException; @@ -132,6 +129,7 @@ public abstract class ComputerListener implements ExtensionPoint { * @deprecated as of 1.292 * Use {@link #onOnline(Computer, TaskListener)} */ + @Deprecated public void onOnline(Computer c) {} /** @@ -214,6 +212,7 @@ public abstract class ComputerListener implements ExtensionPoint { * @deprecated as of 1.286 * put {@link Extension} on your class to have it auto-registered. */ + @Deprecated public final void register() { all().add(this); } diff --git a/core/src/main/java/hudson/slaves/ComputerRetentionWork.java b/core/src/main/java/hudson/slaves/ComputerRetentionWork.java index b676a62f0bd3eea1fc8ecb8c70b622c87e95cfc4..7dbfb0de9649ce0a101632caabab4e40fef1aa78 100644 --- a/core/src/main/java/hudson/slaves/ComputerRetentionWork.java +++ b/core/src/main/java/hudson/slaves/ComputerRetentionWork.java @@ -1,18 +1,18 @@ /* * The MIT License - * + * * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Stephen Connolly - * + * * 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 @@ -27,6 +27,7 @@ import java.util.Map; import java.util.WeakHashMap; import hudson.model.Computer; +import hudson.model.Queue; import jenkins.model.Jenkins; import hudson.model.Node; import hudson.model.PeriodicWork; @@ -54,18 +55,24 @@ public class ComputerRetentionWork extends PeriodicWork { * {@inheritDoc} */ @SuppressWarnings("unchecked") + @Override protected void doRun() { final long startRun = System.currentTimeMillis(); - for (Computer c : Jenkins.getInstance().getComputers()) { - Node n = c.getNode(); - if (n!=null && n.isHoldOffLaunchUntilSave()) - continue; - if (!nextCheck.containsKey(c) || startRun > nextCheck.get(c)) { - // at the moment I don't trust strategies to wait more than 60 minutes - // strategies need to wait at least one minute - final long waitInMins = Math.max(1, Math.min(60, c.getRetentionStrategy().check(c))); - nextCheck.put(c, startRun + waitInMins*1000*60 /*MINS->MILLIS*/); - } + for (final Computer c : Jenkins.getInstance().getComputers()) { + Queue.withLock(new Runnable() { + @Override + public void run() { + Node n = c.getNode(); + if (n!=null && n.isHoldOffLaunchUntilSave()) + return; + if (!nextCheck.containsKey(c) || startRun > nextCheck.get(c)) { + // at the moment I don't trust strategies to wait more than 60 minutes + // strategies need to wait at least one minute + final long waitInMins = Math.max(1, Math.min(60, c.getRetentionStrategy().check(c))); + nextCheck.put(c, startRun + waitInMins*1000*60 /*MINS->MILLIS*/); + } + } + }); } } } diff --git a/core/src/main/java/hudson/slaves/DumbSlave.java b/core/src/main/java/hudson/slaves/DumbSlave.java index 6e9444791b1b0d8c1c12bc5123a61986466bded3..618cb976db09507e10e2e4ade5720b828ebf9899 100644 --- a/core/src/main/java/hudson/slaves/DumbSlave.java +++ b/core/src/main/java/hudson/slaves/DumbSlave.java @@ -44,6 +44,7 @@ public final class DumbSlave extends Slave { * @deprecated as of 1.286. * Use {@link #DumbSlave(String, String, String, String, Node.Mode, String, ComputerLauncher, RetentionStrategy, List)} */ + @Deprecated public DumbSlave(String name, String nodeDescription, String remoteFS, String numExecutors, Mode mode, String labelString, ComputerLauncher launcher, RetentionStrategy retentionStrategy) throws FormException, IOException { this(name, nodeDescription, remoteFS, numExecutors, mode, labelString, launcher, retentionStrategy, new ArrayList()); } diff --git a/core/src/main/java/hudson/slaves/NodeDescriptor.java b/core/src/main/java/hudson/slaves/NodeDescriptor.java index 38cac339661446cc5aaf1ed6c31e1b656493660b..d75d3a15291eef24bfbc228c36c804a79a4f9093 100644 --- a/core/src/main/java/hudson/slaves/NodeDescriptor.java +++ b/core/src/main/java/hudson/slaves/NodeDescriptor.java @@ -120,6 +120,7 @@ public abstract class NodeDescriptor extends Descriptor { * @deprecated as of 1.286 * Use {@link #all()} for read access, and {@link Extension} for registration. */ + @Deprecated public static final DescriptorList ALL = new DescriptorList(Node.class); public static List allInstantiable() { diff --git a/core/src/main/java/hudson/slaves/NodeProperty.java b/core/src/main/java/hudson/slaves/NodeProperty.java index 68c50230c4df6f553d3f089dbb63c7adbd41d476..b87a57fe8874394d41d990bbbed7f72db5a8d95a 100644 --- a/core/src/main/java/hudson/slaves/NodeProperty.java +++ b/core/src/main/java/hudson/slaves/NodeProperty.java @@ -39,7 +39,6 @@ import hudson.model.BuildListener; import hudson.model.Environment; import jenkins.model.Jenkins; import hudson.model.Node; -import hudson.model.Queue; import hudson.model.Queue.Task; import net.sf.json.JSONObject; import org.kohsuke.stapler.StaplerRequest; @@ -97,6 +96,7 @@ public abstract class NodeProperty implements ReconfigurableDesc * @deprecated as of 1.413 * Use {@link #canTake(Queue.BuildableItem)} */ + @Deprecated public CauseOfBlockage canTake(Task task) { return null; } diff --git a/core/src/main/java/hudson/slaves/NodeProvisioner.java b/core/src/main/java/hudson/slaves/NodeProvisioner.java index 25018f190f175c7f3f04f5a44a87e2e3a72b4507..3f5ea3642b8eb8c874d2b8e6fb43f5f9e2306875 100644 --- a/core/src/main/java/hudson/slaves/NodeProvisioner.java +++ b/core/src/main/java/hudson/slaves/NodeProvisioner.java @@ -30,9 +30,9 @@ import jenkins.model.Jenkins; import static hudson.model.LoadStatistics.DECAY; import hudson.model.MultiStageTimeSeries.TimeScale; import hudson.Extension; -import net.jcip.annotations.GuardedBy; import javax.annotation.Nonnull; +import javax.annotation.concurrent.GuardedBy; import java.awt.Color; import java.util.Arrays; import java.util.concurrent.Future; @@ -42,6 +42,9 @@ 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; import java.util.logging.Level; import java.io.IOException; @@ -120,8 +123,13 @@ public class NodeProvisioner { */ private final Label label; - @GuardedBy("self") - private final List pendingLaunches = new ArrayList(); + private final AtomicReference> pendingLaunches + = new AtomicReference>(new ArrayList()); + + private final Lock provisioningLock = new ReentrantLock(); + + @GuardedBy("provisioningLock") + private StrategyState provisioningState = null; private transient volatile long lastSuggestedReview; @@ -148,9 +156,7 @@ public class NodeProvisioner { * @since 1.401 */ public List getPendingLaunches() { - synchronized (pendingLaunches) { - return new ArrayList(pendingLaunches); - } + return new ArrayList(pendingLaunches.get()); } /** @@ -173,81 +179,138 @@ public class NodeProvisioner { /** * Periodically invoked to keep track of the load. * Launches additional nodes if necessary. + * + * Note: This method will obtain a lock on {@link #provisioningLock} first (to ensure that one and only one + * instance of this provisioner is running at a time) and then a lock on {@link Queue#lock} */ - private synchronized void update() { - Jenkins jenkins = Jenkins.getInstance(); - lastSuggestedReview = System.currentTimeMillis(); + private void update() { + provisioningLock.lock(); + try { + lastSuggestedReview = System.currentTimeMillis(); - // clean up the cancelled launch activity, then count the # of executors that we are about to bring up. - int plannedCapacitySnapshot = 0; - List completedLaunches = new ArrayList(); + // We need to get the lock on Queue for two reasons: + // 1. We will potentially adding a lot of nodes and we don't want to fight with Queue#maintain to acquire + // the Queue#lock in order to add each node. Much better is to hold the Queue#lock until all nodes + // that were provisioned since last we checked have been added. + // 2. We want to know the idle executors count, which can only be measured if you hold the Queue#lock + // Strictly speaking we don't need an accurate measure for this, but as we had to get the Queue#lock + // anyway, we might as well get an accurate measure. + // + // We do not need the Queue#lock to get the count of items in the queue as that is a lock-free call + // Since adding a node should not (in principle) confuse Queue#maintain (it is only removal of nodes + // that causes issues in Queue#maintain) we should be able to remove the need for Queue#lock + // + // TODO once Nodes#addNode is made lock free, we should be able to remove the requirement for Queue#lock + Queue.withLock(new Runnable() { + @Override + public void run() { + Jenkins jenkins = Jenkins.getInstance(); + // clean up the cancelled launch activity, then count the # of executors that we are about to + // bring up. + + int plannedCapacitySnapshot = 0; + + List snapPendingLaunches = new ArrayList(pendingLaunches.get()); + for (Iterator itr = snapPendingLaunches.iterator(); itr.hasNext(); ) { + PlannedNode f = itr.next(); + if (f.future.isDone()) { + 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 { + 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 { + plannedCapacitySnapshot += f.numExecutors; + } + } - synchronized (pendingLaunches) { - for (Iterator itr = pendingLaunches.iterator(); itr.hasNext(); ) { - PlannedNode f = itr.next(); - if (f.future.isDone()) { - completedLaunches.add(f); - itr.remove(); - } else { - plannedCapacitySnapshot += f.numExecutors; - } - } - } + float plannedCapacity = plannedCapacitySnapshot; + plannedCapacitiesEMA.update(plannedCapacity); - for (PlannedNode f : completedLaunches) { - try { - Node node = f.future.get(); - for (CloudProvisioningListener cl : CloudProvisioningListener.all()) { - cl.onComplete(f, node); - } + final LoadStatistics.LoadStatisticsSnapshot snapshot = stat.computeSnapshot(); - 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); - } - } + int availableSnapshot = snapshot.getAvailableExecutors(); + int queueLengthSnapshot = snapshot.getQueueLength(); - f.spent(); - } + if (queueLengthSnapshot <= availableSnapshot) { + LOGGER.log(Level.FINER, + "Queue length {0} is less than the available capacity {1}. No provisioning strategy required", + new Object[]{queueLengthSnapshot, availableSnapshot}); + provisioningState = null; + } else { + provisioningState = new StrategyState(snapshot, label, plannedCapacitySnapshot);; + } + } + }); - float plannedCapacity = plannedCapacitySnapshot; - plannedCapacitiesEMA.update(plannedCapacity); - - int idleSnapshot = stat.computeIdleExecutors(); - int queueLengthSnapshot = stat.computeQueueLength(); - - if (queueLengthSnapshot <= idleSnapshot) { - LOGGER.log(Level.FINE, - "Queue length {0} is less than the idle capacity {1}. No provisioning strategy required", - new Object[]{queueLengthSnapshot, idleSnapshot}); - } else { - StrategyState state = - new StrategyState(queueLengthSnapshot, label, idleSnapshot, stat.computeTotalExecutors(), - plannedCapacitySnapshot); - List strategies = Jenkins.getInstance().getExtensionList(Strategy.class); - for (Strategy strategy : strategies.isEmpty() - ? Arrays.asList(new StandardStrategyImpl()) - : strategies) { - LOGGER.log(Level.FINER, "Consulting {0} provisioning strategy with state {1}", - new Object[]{strategy, state}); - if (StrategyDecision.PROVISIONING_COMPLETED == strategy.apply(state)) { - LOGGER.log(Level.FINER, "Provisioning strategy {0} declared provisioning complete", - strategy); - break; + if (provisioningState != null) { + List strategies = Jenkins.getInstance().getExtensionList(Strategy.class); + for (Strategy strategy : strategies.isEmpty() + ? Arrays.asList(new StandardStrategyImpl()) + : strategies) { + LOGGER.log(Level.FINER, "Consulting {0} provisioning strategy with state {1}", + new Object[]{strategy, provisioningState}); + if (StrategyDecision.PROVISIONING_COMPLETED == strategy.apply(provisioningState)) { + LOGGER.log(Level.FINER, "Provisioning strategy {0} declared provisioning complete", + strategy); + break; + } } } + } finally { + provisioningLock.unlock(); } } @@ -283,7 +346,7 @@ public class NodeProvisioner { * Called by {@link NodeProvisioner#update()} to apply this strategy against the specified state. * Any provisioning activities should be recorded by calling * {@link hudson.slaves.NodeProvisioner.StrategyState#recordPendingLaunches(java.util.Collection)} - * This method will be called by a thread that is holding a lock on {@link hudson.slaves.NodeProvisioner} + * This method will be called by a thread that is holding {@link hudson.slaves.NodeProvisioner#provisioningLock} * @param state the current state. * @return the decision. */ @@ -303,23 +366,14 @@ public class NodeProvisioner { * The label under consideration. */ private final Label label; - /** - * The number of items in the queue requiring this {@link #label}. - */ - private final int queueLengthSnapshot; /** * The planned capacity for this {@link #label}. */ private final int plannedCapacitySnapshot; /** - * The number of idle executors for this {@link #label} + * The current statistics snapshot for this {@link #label}. */ - private final int idleSnapshot; - /** - * The total number of executors for this {@link #label} - */ - private final int totalSnapshot; - private final List pendingLaunches; + private final LoadStatistics.LoadStatisticsSnapshot snapshot; /** * The additional planned capacity for this {@link #label} and provisioned by previous strategies during the * current updating of the {@link NodeProvisioner}. @@ -329,20 +383,13 @@ public class NodeProvisioner { /** * Should only be instantiated by {@link NodeProvisioner#update()} - * @param queueLengthSnapshot the queue length. * @param label the label. - * @param idleSnapshot the idle executor count. - * @param totalSnapshot the totoal executor count. * @param plannedCapacitySnapshot the planned executor count. */ - private StrategyState(int queueLengthSnapshot, Label label, int idleSnapshot, int totalSnapshot, - int plannedCapacitySnapshot) { - this.queueLengthSnapshot = queueLengthSnapshot; + private StrategyState(LoadStatistics.LoadStatisticsSnapshot snapshot, Label label, int plannedCapacitySnapshot) { + this.snapshot = snapshot; this.label = label; - this.idleSnapshot = idleSnapshot; - this.totalSnapshot = totalSnapshot; this.plannedCapacitySnapshot = plannedCapacitySnapshot; - pendingLaunches = NodeProvisioner.this.pendingLaunches; } /** @@ -352,11 +399,21 @@ public class NodeProvisioner { return label; } + /** + * The current snapshot of the load statistics for this {@link #getLabel()}. + * @since 1.607 + */ + public LoadStatistics.LoadStatisticsSnapshot getSnapshot() { + return snapshot; + } + /** * The number of items in the queue requiring this {@link #getLabel()}. + * @deprecated use {@link #getSnapshot()}, {@link LoadStatistics.LoadStatisticsSnapshot#getQueueLength()} */ + @Deprecated public int getQueueLengthSnapshot() { - return queueLengthSnapshot; + return snapshot.getQueueLength(); } /** @@ -368,16 +425,20 @@ public class NodeProvisioner { /** * The number of idle executors for this {@link #getLabel()} + * @deprecated use {@link #getSnapshot()}, {@link LoadStatistics.LoadStatisticsSnapshot#getAvailableExecutors()} */ + @Deprecated public int getIdleSnapshot() { - return idleSnapshot; + return snapshot.getAvailableExecutors(); } /** * The total number of executors for this {@link #getLabel()} + * @deprecated use {@link #getSnapshot()}, {@link LoadStatistics.LoadStatisticsSnapshot#getOnlineExecutors()} */ + @Deprecated public int getTotalSnapshot() { - return totalSnapshot; + return snapshot.getOnlineExecutors(); } /** @@ -404,16 +465,68 @@ public class NodeProvisioner { /** * The time series average number of idle executors for this {@link #getLabel()} + * @deprecated use {@link #getAvailableExecutorsLatest()} */ + @Deprecated public float getIdleLatest() { - return stat.getLatestIdleExecutors(TIME_SCALE); + return getAvailableExecutorsLatest(); } /** * The time series average total number of executors for this {@link #getLabel()} + * @deprecated use {@link #getOnlineExecutorsLatest()} */ + @Deprecated public float getTotalLatest() { - return stat.totalExecutors.getLatest(TIME_SCALE); + return getOnlineExecutorsLatest(); + } + + /** + * The time series average number of defined executors for this {@link #getLabel()} + * @since 1.607 + */ + public float getDefinedExecutorsLatest() { + return stat.definedExecutors.getLatest(TIME_SCALE); + } + + /** + * The time series average number of online executors for this {@link #getLabel()} + * @since 1.607 + */ + public float getOnlineExecutorsLatest() { + return stat.onlineExecutors.getLatest(TIME_SCALE); + } + + /** + * The time series average number of connecting executors for this {@link #getLabel()} + * @since 1.607 + */ + public float getConnectingExecutorsLatest() { + return stat.connectingExecutors.getLatest(TIME_SCALE); + } + + /** + * The time series average number of busy executors for this {@link #getLabel()} + * @since 1.607 + */ + public float getBusyExecutorsLatest() { + return stat.busyExecutors.getLatest(TIME_SCALE); + } + + /** + * The time series average number of idle executors for this {@link #getLabel()} + * @since 1.607 + */ + public float getIdleExecutorsLatest() { + return stat.idleExecutors.getLatest(TIME_SCALE); + } + + /** + * The time series average number of available executors for this {@link #getLabel()} + * @since 1.607 + */ + public float getAvailableExecutorsLatest() { + return stat.availableExecutors.getLatest(TIME_SCALE); } /** @@ -443,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 } @@ -451,12 +564,17 @@ public class NodeProvisioner { additionalPlannedCapacity += f.numExecutors; } } - synchronized (pendingLaunches) { - pendingLaunches.addAll(plannedNodes); - } - if (additionalPlannedCapacity > 0) { - synchronized (this) { - 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; } } } @@ -468,10 +586,8 @@ public class NodeProvisioner { public String toString() { final StringBuilder sb = new StringBuilder("StrategyState{"); sb.append("label=").append(label); - sb.append(", queueLengthSnapshot=").append(queueLengthSnapshot); + sb.append(", snapshot=").append(snapshot); sb.append(", plannedCapacitySnapshot=").append(plannedCapacitySnapshot); - sb.append(", idleSnapshot=").append(idleSnapshot); - sb.append(", totalSnapshot=").append(totalSnapshot); sb.append(", additionalPlannedCapacity=").append(additionalPlannedCapacity); sb.append('}'); return sb.toString(); @@ -522,21 +638,24 @@ public class NodeProvisioner { estimate won't create a starvation. */ - boolean needSomeWhenNoneAtAll = (state.getIdleSnapshot() == 0) - && (state.getTotalSnapshot() + state.getPlannedCapacitySnapshot() + state.getAdditionalPlannedCapacity() == 0) - && (state.getQueueLengthSnapshot() > 0); - float idle = Math.max(state.getIdleLatest(), state.getIdleSnapshot()); - if (idle < MARGIN || needSomeWhenNoneAtAll) { + final LoadStatistics.LoadStatisticsSnapshot snapshot = state.getSnapshot(); + boolean needSomeWhenNoneAtAll = (snapshot.getAvailableExecutors() + snapshot.getConnectingExecutors() == 0) + && (snapshot.getOnlineExecutors() + state.getPlannedCapacitySnapshot() + state.getAdditionalPlannedCapacity() == 0) + && (snapshot.getQueueLength() > 0); + float available = Math.max(snapshot.getAvailableExecutors(), state.getAvailableExecutorsLatest()); + if (available < MARGIN || needSomeWhenNoneAtAll) { // make sure the system is fully utilized before attempting any new launch. // this is the amount of work left to be done - float qlen = Math.min(state.getQueueLengthLatest(), state.getQueueLengthSnapshot()); + float qlen = Math.min(state.getQueueLengthLatest(), snapshot.getQueueLength()); + + float connectingCapacity = Math.min(state.getConnectingExecutorsLatest(), snapshot.getConnectingExecutors()); // ... and this is the additional executors we've already provisioned. float plannedCapacity = Math.max(state.getPlannedCapacityLatest(), state.getPlannedCapacitySnapshot()) + state.getAdditionalPlannedCapacity(); - float excessWorkload = qlen - plannedCapacity; + float excessWorkload = qlen - plannedCapacity - connectingCapacity; if (needSomeWhenNoneAtAll && excessWorkload < 1) { // in this specific exceptional case we should just provision right now // the exponential smoothing will delay the build unnecessarily @@ -545,12 +664,12 @@ public class NodeProvisioner { float m = calcThresholdMargin(state.getTotalSnapshot()); if (excessWorkload > 1 - m) {// and there's more work to do... LOGGER.log(Level.FINE, "Excess workload {0,number,#.###} detected. " - + "(planned capacity={1,number,#.###}," - + "Qlen={2,number,#.###},idle={3,number,#.###}&{4,number,integer}," - + "total={5,number,integer},m={6,number,#.###})", + + "(planned capacity={1,number,#.###},connecting capacity={7,number,#.###}," + + "Qlen={2,number,#.###},available={3,number,#.###}&{4,number,integer}," + + "online={5,number,integer},m={6,number,#.###})", new Object[]{ - excessWorkload, plannedCapacity, qlen, idle, state.getIdleSnapshot(), - state.getTotalSnapshot(), m + excessWorkload, plannedCapacity, qlen, available, snapshot.getAvailableExecutors(), + snapshot.getOnlineExecutors(), m , snapshot.getConnectingExecutors() }); CLOUD: @@ -571,11 +690,10 @@ public class NodeProvisioner { int workloadToProvision = (int) Math.round(Math.floor(excessWorkload + m)); - for (CloudProvisioningListener cl : CloudProvisioningListener.all()) - // consider displaying reasons in a future cloud ux - { + for (CloudProvisioningListener cl : CloudProvisioningListener.all()) { if (cl.canProvision(c, state.getLabel(), workloadToProvision) != null) { - break CLOUD; + // consider displaying reasons in a future cloud ux + continue CLOUD; } } diff --git a/core/src/main/java/hudson/slaves/OfflineCause.java b/core/src/main/java/hudson/slaves/OfflineCause.java index e603135f53741a6cf913f653282f8247ebc429c1..7f7704d712162073f05e9ef300f155391d30323a 100644 --- a/core/src/main/java/hudson/slaves/OfflineCause.java +++ b/core/src/main/java/hudson/slaves/OfflineCause.java @@ -29,11 +29,13 @@ import hudson.Functions; import hudson.model.Computer; import hudson.model.User; -import org.acegisecurity.Authentication; import org.jvnet.localizer.Localizable; import org.kohsuke.stapler.export.ExportedBean; import org.kohsuke.stapler.export.Exported; +import javax.annotation.Nonnull; +import java.util.Date; + /** * Represents a cause that puts a {@linkplain Computer#isOffline() computer offline}. * @@ -41,13 +43,34 @@ import org.kohsuke.stapler.export.Exported; *

* {@link OfflineCause} must have cause.jelly that renders a cause * into HTML. This is used to tell users why the node is put offline. - * This view should render a block element like DIV. + * This view should render a block element like DIV. * * @author Kohsuke Kawaguchi * @since 1.320 */ @ExportedBean public abstract class OfflineCause { + protected final long timestamp = System.currentTimeMillis(); + + /** + * Timestamp in which the event happened. + * + * @since 1.612 + */ + @Exported + public long getTimestamp() { + return timestamp; + } + + /** + * Same as {@link #getTimestamp()} but in a different type. + * + * @since 1.612 + */ + public final @Nonnull Date getTime() { + return new Date(timestamp); + } + /** * {@link OfflineCause} that renders a static text, * but without any further UI. @@ -132,4 +155,14 @@ public abstract class OfflineCause { this.message = message; } } + + /** + * Caused by idle period. + * @since 1.644 + */ + public static class IdleOfflineCause extends SimpleOfflineCause { + public IdleOfflineCause () { + super(hudson.slaves.Messages._RetentionStrategy_Demand_OfflineIdle()); + } + } } diff --git a/core/src/main/java/hudson/slaves/RetentionStrategy.java b/core/src/main/java/hudson/slaves/RetentionStrategy.java index 25a9eb68dd3ee4aef2e231f5da746d916271b8d2..6fb8f7c8eb837d2116a253c7cd7f89a5ae331815 100644 --- a/core/src/main/java/hudson/slaves/RetentionStrategy.java +++ b/core/src/main/java/hudson/slaves/RetentionStrategy.java @@ -28,13 +28,14 @@ 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; import jenkins.model.Jenkins; import org.kohsuke.stapler.DataBoundConstructor; +import javax.annotation.concurrent.GuardedBy; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; @@ -54,6 +55,7 @@ public abstract class RetentionStrategy extends AbstractDesc * @return The number of minutes after which the strategy would like to be checked again. The strategy may be * rechecked earlier or later that this! */ + @GuardedBy("hudson.model.Queue.lock") public abstract long check(T c); /** @@ -91,8 +93,13 @@ public abstract class RetentionStrategy extends AbstractDesc * * @since 1.275 */ - public void start(T c) { - check(c); + public void start(final T c) { + Queue.withLock(new Runnable() { + @Override + public void run() { + check(c); + } + }); } /** @@ -107,12 +114,14 @@ public abstract class RetentionStrategy extends AbstractDesc * @deprecated as of 1.286 * Use {@link #all()} for read access, and {@link Extension} for registration. */ + @Deprecated public static final DescriptorList> LIST = new DescriptorList>((Class)RetentionStrategy.class); /** * Dummy instance that doesn't do any attempt to retention. */ public static final RetentionStrategy NOOP = new RetentionStrategy() { + @GuardedBy("hudson.model.Queue.lock") public long check(Computer c) { return 60; } @@ -129,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> {} }; /** @@ -152,6 +157,7 @@ public abstract class RetentionStrategy extends AbstractDesc public Always() { } + @GuardedBy("hudson.model.Queue.lock") public long check(SlaveComputer c) { if (c.isOffline() && !c.isConnecting() && c.isLaunchSupported()) c.tryReconnect(); @@ -208,7 +214,8 @@ public abstract class RetentionStrategy extends AbstractDesc } @Override - public synchronized long check(final SlaveComputer c) { + @GuardedBy("hudson.model.Queue.lock") + public long check(final SlaveComputer c) { if (c.isOffline() && c.isLaunchSupported()) { final HashMap availableComputers = new HashMap(); for (Computer o : Jenkins.getInstance().getComputers()) { @@ -257,21 +264,13 @@ public abstract class RetentionStrategy extends AbstractDesc } else if (c.isIdle()) { final long idleMilliseconds = System.currentTimeMillis() - c.getIdleStartMilliseconds(); if (idleMilliseconds > idleDelay * 1000 * 60 /*MINS->MILLIS*/) { - Queue.withLock(new Runnable() { - @Override - public void run() { - // re-check idle now that we are within the Queue lock - if (c.isIdle()) { - final long idleMilliseconds = System.currentTimeMillis() - c.getIdleStartMilliseconds(); - if (idleMilliseconds > idleDelay * 1000 * 60 /*MINS->MILLIS*/) { - // we've been idle for long enough - logger.log(Level.INFO, "Disconnecting computer {0} as it has been idle for {1}", - new Object[]{c.getName(), Util.getTimeSpanString(idleMilliseconds)}); - c.disconnect(OfflineCause.create(Messages._RetentionStrategy_Demand_OfflineIdle())); - } - } - } - }); + // we've been idle for long enough + logger.log(Level.INFO, "Disconnecting computer {0} as it has been idle for {1}", + new Object[]{c.getName(), Util.getTimeSpanString(idleMilliseconds)}); + c.disconnect(new OfflineCause.IdleOfflineCause()); + } else { + // no point revisiting until we can be confident we will be idle + return TimeUnit.MILLISECONDS.toMinutes(TimeUnit.MINUTES.toMillis(idleDelay) - idleMilliseconds); } } return 1; diff --git a/core/src/main/java/hudson/slaves/SimpleScheduledRetentionStrategy.java b/core/src/main/java/hudson/slaves/SimpleScheduledRetentionStrategy.java index a63fdc94fcb2037bf2bcb96cb528de16684dfde0..5a1e804b7992b6a9f22b10962ef24b4d53e6d285 100644 --- a/core/src/main/java/hudson/slaves/SimpleScheduledRetentionStrategy.java +++ b/core/src/main/java/hudson/slaves/SimpleScheduledRetentionStrategy.java @@ -34,6 +34,7 @@ import hudson.util.FormValidation; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; +import javax.annotation.concurrent.GuardedBy; import java.io.InvalidObjectException; import java.io.ObjectStreamException; import java.util.Calendar; @@ -163,6 +164,7 @@ public class SimpleScheduledRetentionStrategy extends RetentionStrategy * This is normally the same as {@link Slave#getLauncher()} but - * can be different. See {@link #grabLauncher(Node)}. + * can be different. See {@link #grabLauncher(Node)}. */ private ComputerLauncher launcher; @@ -132,13 +133,29 @@ public class SlaveComputer extends Computer { private Object constructed = new Object(); + private transient volatile String absoluteRemoteFs; + public SlaveComputer(Slave slave) { super(slave); this.log = new ReopenableRotatingFileOutputStream(getLogFile(),10); - this.taskListener = new StreamTaskListener(log); + this.taskListener = new StreamTaskListener(decorate(this.log)); assert slave.getNumExecutors()!=0 : "Computer created with 0 executors"; } + /** + * Uses {@link ConsoleLogFilter} to decorate logger. + */ + private OutputStream decorate(OutputStream os) { + for (ConsoleLogFilter f : ConsoleLogFilter.all()) { + try { + os = f.decorateLogger(this,os); + } catch (IOException|InterruptedException e) { + LOGGER.log(Level.WARNING, "Failed to filter log with "+f, e); + } + } + return os; + } + /** * {@inheritDoc} */ @@ -170,12 +187,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; } @@ -249,6 +261,9 @@ public class SlaveComputer extends Computer { } catch (InterruptedException e) { e.printStackTrace(taskListener.error(Messages.ComputerLauncher_abortedLaunch())); throw e; + } catch (Exception e) { + e.printStackTrace(taskListener.error(Messages.ComputerLauncher_unexpectedError())); + throw e; } } finally { if (channel==null) { @@ -274,7 +289,7 @@ public class SlaveComputer extends Computer { if (launcher instanceof ExecutorListener) { ((ExecutorListener)launcher).taskAccepted(executor, task); } - + //getNode() can return null at indeterminate times when nodes go offline Slave node = getNode(); if (node != null && node.getRetentionStrategy() instanceof ExecutorListener) { @@ -410,6 +425,19 @@ public class SlaveComputer extends Computer { return channel.call(new LoadingTime(true)); } + /** + * Returns the remote FS root absolute path or {@code null} if the slave is off-line. The absolute path may change + * between connections if the connection method does not provide a consistent working directory and the node's + * remote FS is specified as a relative path. + * + * @return the remote FS root absolute path or {@code null} if the slave is off-line. + * @since 1.606 + */ + @CheckForNull + public String getAbsoluteRemoteFs() { + return channel == null ? null : absoluteRemoteFs; + } + static class LoadingCount extends MasterToSlaveCallable { private final boolean resource; LoadingCount(boolean resource) { @@ -440,7 +468,7 @@ public class SlaveComputer extends Computer { /** * Sets up the connection through an existing channel. - * + * @param channel the channel to use; warning: callers are expected to have called {@link ChannelConfigurator} already * @since 1.444 */ public void setChannel(Channel channel, OutputStream launchLog, Channel.Listener listener) throws IOException, InterruptedException { @@ -463,7 +491,15 @@ public class SlaveComputer extends Computer { taskListener.getLogger().println("Connection terminated"); } closeChannel(); - launcher.afterDisconnect(SlaveComputer.this, taskListener); + try { + launcher.afterDisconnect(SlaveComputer.this, taskListener); + } catch (Throwable t) { + LogRecord lr = new LogRecord(Level.SEVERE, + "Launcher {0}'s afterDisconnect method propagated an exception when {1}'s connection was closed: {2}"); + lr.setThrown(t); + lr.setParameters(new Object[]{launcher, SlaveComputer.this.getName(), t.getMessage()}); + logger.log(lr); + } } }); if(listener!=null) @@ -481,11 +517,16 @@ public class SlaveComputer extends Computer { if (node == null) { // Node has been disabled/removed during the connection throw new IOException("Node "+nodeName+" has been deleted during the channel setup"); } - - String remoteFs = node.getRemoteFS(); - if(_isUnix && !remoteFs.contains("/") && remoteFs.contains("\\")) - log.println("WARNING: "+remoteFs+" looks suspiciously like Windows path. Maybe you meant "+remoteFs.replace('\\','/')+"?"); - FilePath root = new FilePath(channel,remoteFs); + + String remoteFS = node.getRemoteFS(); + if (Util.isRelativePath(remoteFS)) { + remoteFS = channel.call(new AbsolutePath(remoteFS)); + log.println("NOTE: Relative remote path resolved to: "+remoteFS); + } + if(_isUnix && !remoteFS.contains("/") && remoteFS.contains("\\")) + log.println("WARNING: "+remoteFS + +" looks suspiciously like Windows path. Maybe you meant "+remoteFS.replace('\\','/')+"?"); + FilePath root = new FilePath(channel,remoteFS); // reference counting problem is known to happen, such as JENKINS-9017, and so as a preventive measure // we pin the base classloader so that it'll never get GCed. When this classloader gets released, @@ -519,6 +560,7 @@ public class SlaveComputer extends Computer { isUnix = _isUnix; numRetryAttempt = 0; this.channel = channel; + this.absoluteRemoteFs = remoteFS; defaultCharset = Charset.forName(defaultCharsetName); synchronized (statusChangeLock) { @@ -608,6 +650,7 @@ public class SlaveComputer extends Computer { * This URL binding is no longer used and moved up directly under to {@link jenkins.model.Jenkins}, * but it's left here for now just in case some old JNLP slave agents request it. */ + @Deprecated public Slave.JnlpJar getJnlpJars(String fileName) { return new Slave.JnlpJar(fileName); } @@ -622,6 +665,12 @@ public class SlaveComputer extends Computer { super.kill(); closeChannel(); IOUtils.closeQuietly(log); + + try { + Util.deleteRecursive(getLogDir()); + } catch (IOException ex) { + logger.log(Level.WARNING, "Unable to delete slave logs", ex); + } } public RetentionStrategy getRetentionStrategy() { @@ -634,9 +683,13 @@ public class SlaveComputer extends Computer { */ private void closeChannel() { // TODO: race condition between this and the setChannel method. - Channel c = channel; - channel = null; - isUnix = null; + Channel c; + synchronized (channelLock) { + c = channel; + channel = null; + absoluteRemoteFs = null; + isUnix = null; + } if (c != null) { try { c.close(); @@ -649,7 +702,7 @@ public class SlaveComputer extends Computer { } @Override - protected void setNode(Node node) { + protected void setNode(final Node node) { super.setNode(node); launcher = grabLauncher(node); @@ -657,10 +710,16 @@ public class SlaveComputer extends Computer { // "constructed==null" test is an ugly hack to avoid launching before the object is fully // constructed. if(constructed!=null) { - if (node instanceof Slave) - ((Slave)node).getRetentionStrategy().check(this); - else + if (node instanceof Slave) { + Queue.withLock(new Runnable() { + @Override + public void run() { + ((Slave)node).getRetentionStrategy().check(SlaveComputer.this); + } + }); + } else { connect(false); + } } } @@ -708,6 +767,21 @@ public class SlaveComputer extends Computer { } } + private static final class AbsolutePath extends MasterToSlaveCallable { + + private static final long serialVersionUID = 1L; + + private final String relativePath; + + private AbsolutePath(String relativePath) { + this.relativePath = relativePath; + } + + public String call() throws IOException { + return new File(relativePath).getAbsolutePath(); + } + } + private static final class DetectDefaultCharset extends MasterToSlaveCallable { public String call() throws IOException { return Charset.defaultCharset().name(); @@ -744,7 +818,7 @@ public class SlaveComputer extends Computer { } Channel.current().setProperty("slave",Boolean.TRUE); // indicate that this side of the channel is the slave side. - + return null; } private static final long serialVersionUID = 1L; @@ -784,4 +858,6 @@ public class SlaveComputer extends Computer { return new ArrayList(SLAVE_LOG_HANDLER.getView()); } } + + private static final Logger LOGGER = Logger.getLogger(SlaveComputer.class.getName()); } diff --git a/core/src/main/java/hudson/slaves/WorkspaceList.java b/core/src/main/java/hudson/slaves/WorkspaceList.java index 5e335f23e26c1f60c808126ecc404f8ac4e381fa..a344b45aacb87a3fd56bf540b2d27588677fb60b 100644 --- a/core/src/main/java/hudson/slaves/WorkspaceList.java +++ b/core/src/main/java/hudson/slaves/WorkspaceList.java @@ -26,10 +26,12 @@ package hudson.slaves; import hudson.FilePath; import hudson.Functions; import hudson.model.Computer; +import java.io.Closeable; import java.util.Date; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.Nonnull; @@ -104,7 +106,7 @@ public final class WorkspaceList { /** * Represents a leased workspace that needs to be returned later. */ - public static abstract class Lease { + public static abstract class Lease implements /*Auto*/Closeable { public final @Nonnull FilePath path; protected Lease(@Nonnull FilePath path) { @@ -117,6 +119,14 @@ public final class WorkspaceList { */ public abstract void release(); + /** + * By default, calls {@link #release}, but should be idempotent. + * @since 1.600 + */ + @Override public void close() { + release(); + } + /** * Creates a dummy {@link Lease} object that does no-op in the release. */ @@ -261,9 +271,15 @@ public final class WorkspaceList { */ private Lease lease(@Nonnull FilePath p) { return new Lease(p) { + final AtomicBoolean released = new AtomicBoolean(); public void release() { _release(path); } + @Override public void close() { + if (released.compareAndSet(false, true)) { + release(); + } + } }; } diff --git a/core/src/main/java/hudson/tasks/ArtifactArchiver.java b/core/src/main/java/hudson/tasks/ArtifactArchiver.java index f681642b5053594439abfbea1e694a1b27f6ff23..297300b525759e8e58fc8ebebe195230e90fd4c6 100644 --- a/core/src/main/java/hudson/tasks/ArtifactArchiver.java +++ b/core/src/main/java/hudson/tasks/ArtifactArchiver.java @@ -97,9 +97,16 @@ public class ArtifactArchiver extends Recorder implements SimpleBuildStep { */ @Nonnull private Boolean defaultExcludes = true; + + /** + * Indicate whether include and exclude patterns should be considered as case sensitive + */ + @Nonnull + private Boolean caseSensitive = true; @DataBoundConstructor public ArtifactArchiver(String artifacts) { this.artifacts = artifacts.trim(); + allowEmptyArchive = false; } @Deprecated @@ -135,6 +142,9 @@ public class ArtifactArchiver extends Recorder implements SimpleBuildStep { if (defaultExcludes == null){ defaultExcludes = true; } + if (caseSensitive == null) { + caseSensitive = true; + } return this; } @@ -187,6 +197,14 @@ public class ArtifactArchiver extends Recorder implements SimpleBuildStep { @DataBoundSetter public final void setDefaultExcludes(boolean defaultExcludes) { this.defaultExcludes = defaultExcludes; } + + public boolean isCaseSensitive() { + return caseSensitive; + } + + @DataBoundSetter public final void setCaseSensitive(boolean caseSensitive) { + this.caseSensitive = caseSensitive; + } private void listenerWarnOrError(TaskListener listener, String message) { if (allowEmptyArchive) { @@ -213,7 +231,7 @@ public class ArtifactArchiver extends Recorder implements SimpleBuildStep { try { String artifacts = build.getEnvironment(listener).expand(this.artifacts); - Map files = ws.act(new ListFiles(artifacts, excludes, defaultExcludes)); + Map files = ws.act(new ListFiles(artifacts, excludes, defaultExcludes, caseSensitive)); if (!files.isEmpty()) { build.pickArtifactManager().archive(ws, launcher, BuildListenerAdapter.wrap(listener), files); if (fingerprint) { @@ -227,7 +245,7 @@ public class ArtifactArchiver extends Recorder implements SimpleBuildStep { listenerWarnOrError(listener, Messages.ArtifactArchiver_NoMatchFound(artifacts)); String msg = null; try { - msg = ws.validateAntFileMask(artifacts, FilePath.VALIDATE_ANT_FILE_MASK_BOUND); + msg = ws.validateAntFileMask(artifacts, FilePath.VALIDATE_ANT_FILE_MASK_BOUND, caseSensitive); } catch (Exception e) { listenerWarnOrError(listener, e.getMessage()); } @@ -252,17 +270,21 @@ public class ArtifactArchiver extends Recorder implements SimpleBuildStep { private static final long serialVersionUID = 1; private final String includes, excludes; private final boolean defaultExcludes; + private final boolean caseSensitive; - ListFiles(String includes, String excludes, boolean defaultExcludes) { + ListFiles(String includes, String excludes, boolean defaultExcludes, boolean caseSensitive) { this.includes = includes; this.excludes = excludes; this.defaultExcludes = defaultExcludes; + this.caseSensitive = caseSensitive; } + @Override public Map invoke(File basedir, VirtualChannel channel) throws IOException, InterruptedException { Map r = new HashMap(); FileSet fileSet = Util.createFileSet(basedir, includes, excludes); fileSet.setDefaultexcludes(defaultExcludes); + fileSet.setCaseSensitive(caseSensitive); for (String f : fileSet.getDirectoryScanner().getIncludedFiles()) { f = f.replace(File.separatorChar, '/'); @@ -281,6 +303,7 @@ public class ArtifactArchiver extends Recorder implements SimpleBuildStep { * Some plugin depends on this, so this field is left here and points to the last created instance. * Use {@link jenkins.model.Jenkins#getDescriptorByType(Class)} instead. */ + @Deprecated public static volatile DescriptorImpl DESCRIPTOR; @Extension @@ -294,13 +317,19 @@ public class ArtifactArchiver extends Recorder implements SimpleBuildStep { } /** - * Performs on-the-fly validation on the file mask wildcard. + * Performs on-the-fly validation of the file mask wildcard, when the artifacts + * textbox or the caseSensitive checkbox are modified */ - public FormValidation doCheckArtifacts(@AncestorInPath AbstractProject project, @QueryParameter String value) throws IOException { + public FormValidation doCheckArtifacts(@AncestorInPath AbstractProject project, + @QueryParameter String value, + @QueryParameter(value = "caseSensitive") String caseSensitive) + throws IOException { if (project == null) { return FormValidation.ok(); } - return FilePath.validateFileMask(project.getSomeWorkspace(),value); + // defensive approach to remain case sensitive in doubtful situations + boolean bCaseSensitive = caseSensitive == null || !"false".equals(caseSensitive); + return FilePath.validateFileMask(project.getSomeWorkspace(), value, bCaseSensitive); } @Override diff --git a/core/src/main/java/hudson/tasks/BuildStep.java b/core/src/main/java/hudson/tasks/BuildStep.java index 699015f7f49ebc2b6ec034ecd2a5bd596ea1de93..e006adb8dd4f608fe165862cecf0e8dfc4d27db3 100644 --- a/core/src/main/java/hudson/tasks/BuildStep.java +++ b/core/src/main/java/hudson/tasks/BuildStep.java @@ -46,10 +46,11 @@ import java.util.List; import java.util.AbstractList; import java.util.Iterator; import java.util.WeakHashMap; -import jenkins.model.Jenkins; import jenkins.security.QueueItemAuthenticator; import org.acegisecurity.Authentication; +import javax.annotation.Nonnull; + /** * One step of the whole build process. * @@ -131,6 +132,7 @@ public interface BuildStep { * @deprecated as of 1.341. * Use {@link #getProjectActions(AbstractProject)} instead. */ + @Deprecated Action getProjectAction(AbstractProject project); /** @@ -154,6 +156,7 @@ public interface BuildStep { * @return * can be empty but never null. */ + @Nonnull Collection getProjectActions(AbstractProject project); @@ -230,6 +233,7 @@ public interface BuildStep { * Use {@link Builder#all()} for read access, and use * {@link Extension} for registration. */ + @Deprecated List> BUILDERS = new DescriptorList(Builder.class); /** @@ -246,6 +250,7 @@ public interface BuildStep { * Use {@link Publisher#all()} for read access, and use * {@link Extension} for registration. */ + @Deprecated PublisherList PUBLISHERS = new PublisherList(); /** diff --git a/core/src/main/java/hudson/tasks/BuildStepCompatibilityLayer.java b/core/src/main/java/hudson/tasks/BuildStepCompatibilityLayer.java index 11c39c21b63c8f25cba84bcb9a114849a708e144..24e2093c106e837b3e04825ef5120d0b2ef9afd2 100644 --- a/core/src/main/java/hudson/tasks/BuildStepCompatibilityLayer.java +++ b/core/src/main/java/hudson/tasks/BuildStepCompatibilityLayer.java @@ -41,6 +41,8 @@ import hudson.model.Run; import hudson.model.TaskListener; import jenkins.tasks.SimpleBuildStep; +import javax.annotation.Nonnull; + /** * Provides compatibility with {@link BuildStep} before 1.150 * so that old plugin binaries can continue to function with new Hudson. @@ -49,6 +51,7 @@ import jenkins.tasks.SimpleBuildStep; * @since 1.150 * @deprecated since 1.150 */ +@Deprecated public abstract class BuildStepCompatibilityLayer implements BuildStep { // // new definitions >= 1.150 @@ -61,9 +64,10 @@ public abstract class BuildStepCompatibilityLayer implements BuildStep { } /** - * @inheritDoc + * {@inheritDoc} * @return Delegates to {@link SimpleBuildStep#perform(Run, FilePath, Launcher, TaskListener)} if possible, always returning true or throwing an error. */ + @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { if (this instanceof SimpleBuildStep) { // delegate to the overloaded version defined in SimpleBuildStep @@ -88,6 +92,7 @@ public abstract class BuildStepCompatibilityLayer implements BuildStep { return null; } + @Nonnull public Collection getProjectActions(AbstractProject project) { // delegate to getJobAction (singular) for backward compatible behavior Action a = getProjectAction(project); @@ -103,6 +108,7 @@ public abstract class BuildStepCompatibilityLayer implements BuildStep { * @deprecated * Use {@link #prebuild(AbstractBuild, BuildListener)} instead. */ + @Deprecated public boolean prebuild(Build build, BuildListener listener) { return true; } @@ -111,6 +117,7 @@ public abstract class BuildStepCompatibilityLayer implements BuildStep { * @deprecated * Use {@link #perform(AbstractBuild, Launcher, BuildListener)} instead. */ + @Deprecated public boolean perform(Build build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { throw new UnsupportedOperationException(); } @@ -119,6 +126,7 @@ public abstract class BuildStepCompatibilityLayer implements BuildStep { * @deprecated * Use {@link #getProjectAction(AbstractProject)} instead. */ + @Deprecated public Action getProjectAction(Project project) { return null; } diff --git a/core/src/main/java/hudson/tasks/BuildTrigger.java b/core/src/main/java/hudson/tasks/BuildTrigger.java index ee121ca195d8ac663810fc097f97049e1e82cc2d..75b1b68a01100b8864636e84fb7494400ceb83ed 100644 --- a/core/src/main/java/hudson/tasks/BuildTrigger.java +++ b/core/src/main/java/hudson/tasks/BuildTrigger.java @@ -144,6 +144,7 @@ public class BuildTrigger extends Recorder implements DependencyDeclarer { * @deprecated as of 1.406 * Use {@link #getChildProjects(ItemGroup)} */ + @Deprecated public List getChildProjects() { return getChildProjects(Jenkins.getInstance()); } @@ -172,6 +173,7 @@ public class BuildTrigger extends Recorder implements DependencyDeclarer { * @deprecated as of 1.406 * Use {@link #hasSame(AbstractProject, Collection)} */ + @Deprecated public boolean hasSame(Collection projects) { return hasSame(null,projects); } diff --git a/core/src/main/java/hudson/tasks/BuildWrapper.java b/core/src/main/java/hudson/tasks/BuildWrapper.java index 8b103e3bfdf8816a31182c4bca7bbcff75b785d5..3c2ac9c8492a836fa14302bc18d4a53f09331828 100644 --- a/core/src/main/java/hudson/tasks/BuildWrapper.java +++ b/core/src/main/java/hudson/tasks/BuildWrapper.java @@ -252,6 +252,7 @@ public abstract class BuildWrapper extends AbstractDescribableImpl * @deprecated * Use {@link #getProjectActions(AbstractProject)} instead. */ + @Deprecated public Action getProjectAction(AbstractProject job) { return null; } diff --git a/core/src/main/java/hudson/tasks/BuildWrappers.java b/core/src/main/java/hudson/tasks/BuildWrappers.java index 7778a1f11cfc4cb4b7c0d51c5aca7e72f9f54d05..874caedc30fe4a5c0413dd6204de995d6d465098 100644 --- a/core/src/main/java/hudson/tasks/BuildWrappers.java +++ b/core/src/main/java/hudson/tasks/BuildWrappers.java @@ -44,7 +44,8 @@ public class BuildWrappers { * as of 1.281. Use {@link Extension} for registration, and use {@link BuildWrapper#all()} * for listing them. */ - public static final List> WRAPPERS = new DescriptorList(BuildWrapper.class); + @Deprecated + public static final List> WRAPPERS = new DescriptorList<>(BuildWrapper.class); /** * List up all {@link BuildWrapperDescriptor}s that are applicable for the given project. @@ -54,7 +55,7 @@ public class BuildWrappers { * with {@link BuildWrapper} implementations before 1.150. */ public static List> getFor(AbstractProject project) { - List> result = new ArrayList>(); + List> result = new ArrayList<>(); Descriptor pd = Jenkins.getInstance().getDescriptor((Class)project.getClass()); for (Descriptor w : BuildWrapper.all()) { diff --git a/core/src/main/java/hudson/tasks/CommandInterpreter.java b/core/src/main/java/hudson/tasks/CommandInterpreter.java index bfab1c639d7583331f65255379e41f1685985eeb..982ecadb3f46c12edd6e3ebaf43c6b0eedf0a6b8 100644 --- a/core/src/main/java/hudson/tasks/CommandInterpreter.java +++ b/core/src/main/java/hudson/tasks/CommandInterpreter.java @@ -25,14 +25,12 @@ package hudson.tasks; import hudson.FilePath; import hudson.Launcher; -import hudson.Launcher.ProcStarter; import hudson.Proc; import hudson.Util; import hudson.EnvVars; import hudson.model.AbstractBuild; import hudson.model.BuildListener; import hudson.model.Node; -import hudson.model.Result; import hudson.model.TaskListener; import hudson.remoting.ChannelClosedException; diff --git a/core/src/main/java/hudson/tasks/LogRotator.java b/core/src/main/java/hudson/tasks/LogRotator.java index bc7a2d97383ef8139299c26a845079e01550c1aa..36efff2145ceb9cfcf3561c45de4008ab5601e14 100644 --- a/core/src/main/java/hudson/tasks/LogRotator.java +++ b/core/src/main/java/hudson/tasks/LogRotator.java @@ -94,6 +94,7 @@ public class LogRotator extends BuildDiscarder { * @deprecated since 1.350. * Use {@link #LogRotator(int, int, int, int)} */ + @Deprecated public LogRotator(int daysToKeep, int numToKeep) { this(daysToKeep, numToKeep, -1, -1); } @@ -187,6 +188,10 @@ public class LogRotator extends BuildDiscarder { LOGGER.log(FINER, "{0} is not to be removed or purged of artifacts because it’s the last stable build", r); return true; } + if (r.isBuilding()) { + LOGGER.log(FINER, "{0} is not to be removed or purged of artifacts because it’s still building", r); + return true; + } return false; } diff --git a/core/src/main/java/hudson/tasks/Maven.java b/core/src/main/java/hudson/tasks/Maven.java index 44016c6d3d290740cf02d9f731c3f4b08b646338..51f41aa2208eef6ea84653b27a39647cb1d13f27 100644 --- a/core/src/main/java/hudson/tasks/Maven.java +++ b/core/src/main/java/hudson/tasks/Maven.java @@ -322,6 +322,10 @@ public class Maven extends Builder { wrapUpArguments(args,normalizedTarget,build,launcher,listener); buildEnvVars(env, mi); + + if (!launcher.isUnix()) { + args = args.toWindowsCommand(); + } try { MavenConsoleAnnotator mca = new MavenConsoleAnnotator(listener.getLogger(),build.getCharset()); @@ -381,6 +385,7 @@ public class Maven extends Builder { * For compatibility, this field retains the last created {@link DescriptorImpl}. * TODO: fix sonar plugin that depends on this. That's the only plugin that depends on this field. */ + @Deprecated public static DescriptorImpl DESCRIPTOR; @Extension @@ -455,13 +460,14 @@ public class Maven extends Builder { /** * @deprecated since 2009-02-25. */ - @Deprecated // kept for backward compatiblity - use getHome() + @Deprecated // kept for backward compatibility - use getHome() private transient String mavenHome; /** * @deprecated as of 1.308. * Use {@link #Maven.MavenInstallation(String, String, List)} */ + @Deprecated public MavenInstallation(String name, String home) { super(name, home); } @@ -476,6 +482,7 @@ public class Maven extends Builder { * * @deprecated as of 1.308. Use {@link #getHome()}. */ + @Deprecated public String getMavenHome() { return getHome(); } @@ -578,12 +585,20 @@ public class Maven extends Builder { } private File getExeFile(String execName) { - if(File.separatorChar=='\\') - execName += ".bat"; - String m2Home = Util.replaceMacro(getHome(),EnvVars.masterEnvVars); - return new File(m2Home, "bin/" + execName); + if(Functions.isWindows()) { + File exeFile = new File(m2Home, "bin/" + execName + ".bat"); + + // since Maven 3.3 .bat files are replaced with .cmd + if (!exeFile.exists()) { + return new File(m2Home, "bin/" + execName + ".cmd"); + } + + return exeFile; + } else { + return new File(m2Home, "bin/" + execName); + } } /** diff --git a/core/src/main/java/hudson/tasks/Shell.java b/core/src/main/java/hudson/tasks/Shell.java index 661f75e312073e31060c25e8c683857131662831..45d9c7d84cefe1d1214c9f6dfdc5dab1750d5b08 100644 --- a/core/src/main/java/hudson/tasks/Shell.java +++ b/core/src/main/java/hudson/tasks/Shell.java @@ -125,6 +125,7 @@ public class Shell extends CommandInterpreter { * @deprecated 1.403 * Use {@link #getShellOrDefault(hudson.remoting.VirtualChannel) }. */ + @Deprecated public String getShellOrDefault() { if(shell==null) return Functions.isWindows() ?"sh":"/bin/sh"; diff --git a/core/src/main/java/hudson/tasks/UserNameResolver.java b/core/src/main/java/hudson/tasks/UserNameResolver.java index 71594caa0c97d6f70f740002653947d7ad8a608a..5aa7af3768737af85d837bc70f75e7c0cc89a17f 100644 --- a/core/src/main/java/hudson/tasks/UserNameResolver.java +++ b/core/src/main/java/hudson/tasks/UserNameResolver.java @@ -27,7 +27,6 @@ import hudson.Extension; import hudson.ExtensionList; import hudson.ExtensionListView; import hudson.ExtensionPoint; -import jenkins.model.Jenkins; import hudson.model.User; import java.util.List; @@ -92,5 +91,6 @@ public abstract class UserNameResolver implements ExtensionPoint { * @deprecated since 2009-02-24. * Use {@link #all()} for read access, and use {@link Extension} for registration. */ + @Deprecated public static final List LIST = ExtensionListView.createList(UserNameResolver.class); } diff --git a/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java b/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java index 938325f6681de75c893be2ceb6169f5596773a44..2aa3579823fc42159b7dc9bc1598a7c913fef9d0 100644 --- a/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java +++ b/core/src/main/java/hudson/tools/DownloadFromUrlInstaller.java @@ -4,11 +4,13 @@ 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; import java.util.Arrays; import java.util.Collections; +import java.util.LinkedList; import java.util.List; import java.net.URL; @@ -64,6 +66,10 @@ 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; @@ -121,10 +127,94 @@ public abstract class DownloadFromUrlInstaller extends ToolInstaller { Downloadable.all().add(createDownloadable()); } - protected Downloadable createDownloadable() { + /** + * function that creates a {@link Downloadable}. + * @return a downloadable object + */ + public Downloadable createDownloadable() { + if (this instanceof DownloadFromUrlInstaller.DescriptorImpl) { + final DownloadFromUrlInstaller.DescriptorImpl delegate = (DownloadFromUrlInstaller.DescriptorImpl)this; + return new Downloadable(getId()) { + public JSONObject reduce(List jsonList) { + if (isDefualtSchema(jsonList)) { + return delegate.reduce(jsonList); + } else { + //if it's not default schema fall back to the super class implementation + return super.reduce(jsonList); + } + } + }; + } return new Downloadable(getId()); } + /** + * this function checks is the update center tool has the default schema + * @param jsonList the list of Update centers json files + * @return true if the schema is the default one (id, name, url), false otherwise + */ + private boolean isDefualtSchema(List jsonList) { + JSONObject jsonToolInstallerList = jsonList.get(0); + ToolInstallerList toolInstallerList = (ToolInstallerList) JSONObject.toBean(jsonToolInstallerList, ToolInstallerList.class); + + if (toolInstallerList != null) { + ToolInstallerEntry[] entryList = toolInstallerList.list; + ToolInstallerEntry sampleEntry = entryList[0]; + if (sampleEntry != null) { + if (sampleEntry.id != null && sampleEntry.name != null && sampleEntry.url != null) { + return true; + } + } + } + return false; + } + + private JSONObject reduce(List jsonList) { + List reducedToolEntries = new LinkedList<>(); + //collect all tool installers objects from the multiple json objects + for (JSONObject jsonToolList : jsonList) { + ToolInstallerList toolInstallerList = (ToolInstallerList) JSONObject.toBean(jsonToolList, ToolInstallerList.class); + reducedToolEntries.addAll(Arrays.asList(toolInstallerList.list)); + } + + while (Downloadable.hasDuplicates(reducedToolEntries, "id")) { + List tmpToolInstallerEntries = new LinkedList<>(); + //we need to skip the processed entries + boolean processed[] = new boolean[reducedToolEntries.size()]; + for (int i = 0; i < reducedToolEntries.size(); i++) { + if (processed[i] == true) { + continue; + } + ToolInstallerEntry data1 = reducedToolEntries.get(i); + boolean hasDuplicate = false; + for (int j = i + 1; j < reducedToolEntries.size(); j ++) { + ToolInstallerEntry data2 = reducedToolEntries.get(j); + //if we found a duplicate we choose the first one + if (data1.id.equals(data2.id)) { + hasDuplicate = true; + processed[j] = true; + tmpToolInstallerEntries.add(data1); + //after the first duplicate has been found we break the loop since the duplicates are + //processed two by two + break; + } + } + //if no duplicate has been found we just insert the entry in the tmp list + if (!hasDuplicate) { + tmpToolInstallerEntries.add(data1); + } + } + reducedToolEntries = tmpToolInstallerEntries; + } + + ToolInstallerList toolInstallerList = new ToolInstallerList(); + toolInstallerList.list = new ToolInstallerEntry[reducedToolEntries.size()]; + reducedToolEntries.toArray(toolInstallerList.list); + JSONObject reducedToolEntriesJsonList = JSONObject.fromObject(toolInstallerList); + //return the list with no duplicates + return reducedToolEntriesJsonList; + } + /** * This ID needs to be unique, and needs to match the ID token in the JSON update file. *

@@ -175,4 +265,17 @@ public abstract class DownloadFromUrlInstaller extends ToolInstaller { */ public String url; } + + /** + * Convenient abstract class to implement a NodeSpecificInstallable based on an existing Installable + * @since 1.626 + */ + public abstract class NodeSpecificInstallable extends Installable implements NodeSpecific { + + public NodeSpecificInstallable(Installable inst) { + this.id = inst.id; + this.name = inst.name; + this.url = inst.url; + } + } } diff --git a/core/src/main/java/hudson/tools/JDKInstaller.java b/core/src/main/java/hudson/tools/JDKInstaller.java index 2cddb4d69c3ffc48d13550c5229a99628e89eeb3..d270769de16312021772b42cc3c679f2a293a0fe 100644 --- a/core/src/main/java/hudson/tools/JDKInstaller.java +++ b/core/src/main/java/hudson/tools/JDKInstaller.java @@ -32,9 +32,9 @@ import hudson.ProxyConfiguration; import hudson.Util; import hudson.model.DownloadService.Downloadable; import hudson.model.JDK; +import hudson.model.Job; import hudson.model.Node; import hudson.model.TaskListener; -import hudson.remoting.Callable; import hudson.util.ArgumentListBuilder; import hudson.util.FormValidation; import hudson.util.HttpResponses; @@ -42,6 +42,7 @@ import hudson.util.Secret; import jenkins.model.Jenkins; import jenkins.security.MasterToSlaveCallable; import net.sf.json.JSONObject; +import net.sf.json.JsonConfig; import org.apache.commons.httpclient.Cookie; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpMethodBase; @@ -70,6 +71,7 @@ import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.logging.Logger; @@ -171,6 +173,7 @@ public class JDKInstaller extends ToolInstaller { PrintStream out = log.getLogger(); out.println("Installing "+ jdkBundle); + FilePath parent = new FilePath(launcher.getChannel(), expectedLocation).getParent(); switch (p) { case LINUX: case SOLARIS: @@ -240,7 +243,7 @@ public class JDKInstaller extends ToolInstaller { // Prevent a trailing slash from escaping quotes expectedLocation = expectedLocation.substring(0, expectedLocation.length() - 1); } - String logFile = new FilePath(launcher.getChannel(), expectedLocation).getParent().createTempFile("install", "log").getRemote(); + String logFile = parent.createTempFile("install", "log").getRemote(); ArgumentListBuilder args = new ArgumentListBuilder(); @@ -281,6 +284,61 @@ public class JDKInstaller extends ToolInstaller { fs.delete(logFile); break; + + case OSX: + // Mount the DMG distribution bundle + FilePath dmg = parent.createTempDir("jdk", "dmg"); + exit = launcher.launch() + .cmds("hdiutil", "attach", "-puppetstrings", "-mountpoint", dmg.getRemote(), jdkBundle) + .stdout(log) + .join(); + if (exit != 0) + throw new AbortException(Messages.JDKInstaller_FailedToInstallJDK(exit)); + + // expand the installation PKG + FilePath[] list = dmg.list("*.pkg"); + if (list.length != 1) { + log.getLogger().println("JDK dmg bundle does not contain expected pkg installer"); + throw new AbortException(Messages.JDKInstaller_FailedToInstallJDK(exit)); + } + String installer = list[0].getRemote(); + + FilePath pkg = parent.createTempDir("jdk", "pkg"); + pkg.deleteRecursive(); // pkgutil fails if target directory exists + exit = launcher.launch() + .cmds("pkgutil", "--expand", installer, pkg.getRemote()) + .stdout(log) + .join(); + if (exit != 0) + throw new AbortException(Messages.JDKInstaller_FailedToInstallJDK(exit)); + + exit = launcher.launch() + .cmds("umount", dmg.getRemote()) + .stdout(log) + .join(); + if (exit != 0) + throw new AbortException(Messages.JDKInstaller_FailedToInstallJDK(exit)); + + // We only want the actual JDK sub-package, which "Payload" is actually a tar.gz archive + list = pkg.list("jdk*.pkg/Payload"); + if (list.length != 1) { + log.getLogger().println("JDK pkg installer does not contain expected JDK Payload archive"); + throw new AbortException(Messages.JDKInstaller_FailedToInstallJDK(exit)); + } + String payload = list[0].getRemote(); + exit = launcher.launch() + .pwd(parent).cmds("tar", "xzf", payload) + .stdout(log) + .join(); + if (exit != 0) + throw new AbortException(Messages.JDKInstaller_FailedToInstallJDK(exit)); + + parent.child("Contents/Home").moveAllChildrenTo(new FilePath(launcher.getChannel(), expectedLocation)); + parent.child("Contents").deleteRecursive(); + + pkg.deleteRecursive(); + dmg.deleteRecursive(); + break; } } @@ -457,7 +515,7 @@ public class JDKInstaller extends ToolInstaller { m = post; } else { - log.getLogger().println("Downloading " + m.getResponseContentLength() + "bytes"); + log.getLogger().println("Downloading " + m.getResponseContentLength() + " bytes"); // download to a temporary file and rename it in to handle concurrency and failure correctly, File tmp = new File(cache.getPath()+".tmp"); @@ -502,7 +560,7 @@ public class JDKInstaller extends ToolInstaller { * Supported platform. */ public enum Platform { - LINUX("jdk.sh"), SOLARIS("jdk.sh"), WINDOWS("jdk.exe"); + LINUX("jdk.sh"), SOLARIS("jdk.sh"), WINDOWS("jdk.exe"), OSX("jdk.dmg"); /** * Choose the file name suitable for the downloaded JDK bundle. @@ -529,6 +587,7 @@ public class JDKInstaller extends ToolInstaller { if(arch.contains("linux")) return LINUX; if(arch.contains("windows")) return WINDOWS; if(arch.contains("sun") || arch.contains("solaris")) return SOLARIS; + if(arch.contains("mac")) return OSX; throw new DetectionFailedException("Unknown CPU name: "+arch); } @@ -613,8 +672,8 @@ public class JDKInstaller extends ToolInstaller { } public static final class JDKFamilyList { - public int version; public JDKFamily[] data = new JDKFamily[0]; + public int version; public boolean isEmpty() { for (JDKFamily f : data) { @@ -641,6 +700,18 @@ public class JDKInstaller extends ToolInstaller { } public static final class JDKRelease { + /** + * the list of {@Link JDKFile}s + */ + public JDKFile[] files; + /** + * the license path + */ + public String licpath; + /** + * the license title + */ + public String lictitle; /** * This maps to the former product code, like "jdk-6u13-oth-JPR" */ @@ -649,7 +720,6 @@ public class JDKInstaller extends ToolInstaller { * This is human readable. */ public String title; - public JDKFile[] files; /** * We used to use IDs like "jdk-6u13-oth-JPR@CDS-CDS_Developer", but Oracle switched to just "jdk-6u13-oth-JPR". @@ -661,9 +731,9 @@ public class JDKInstaller extends ToolInstaller { } public static final class JDKFile { + public String filepath; public String name; public String title; - public String filepath; } @Override @@ -746,6 +816,123 @@ public class JDKInstaller extends ToolInstaller { if(d==null) return new JDKFamilyList(); return (JDKFamilyList)JSONObject.toBean(d,JDKFamilyList.class); } + + /** + * @{inheritDoc} + */ + @Override + public JSONObject reduce (List jsonObjectList) { + List reducedFamilies = new LinkedList<>(); + int version = 0; + JsonConfig jsonConfig = new JsonConfig(); + jsonConfig.registerPropertyExclusion(JDKFamilyList.class, "empty"); + jsonConfig.setRootClass(JDKFamilyList.class); + //collect all JDKFamily objects from the multiple json objects + for (JSONObject jsonJdkFamilyList : jsonObjectList) { + JDKFamilyList jdkFamilyList = (JDKFamilyList)JSONObject.toBean(jsonJdkFamilyList, jsonConfig); + if (version == 0) { + //we set as version the version of the first update center + version = jdkFamilyList.version; + } + JDKFamily[] jdkFamilies = jdkFamilyList.data; + reducedFamilies.addAll(Arrays.asList(jdkFamilies)); + } + //we iterate on the list and reduce it until there are no more duplicates + //this could be made recursive + while (hasDuplicates(reducedFamilies, "name")) { + //create a temporary list to store the tmp result + List tmpReducedFamilies = new LinkedList<>(); + //we need to skip the processed families + boolean processed [] = new boolean[reducedFamilies.size()]; + for (int i = 0; i < reducedFamilies.size(); i ++ ) { + if (processed [i] == true) { + continue; + } + JDKFamily data1 = reducedFamilies.get(i); + boolean hasDuplicate = false; + for (int j = i + 1; j < reducedFamilies.size(); j ++ ) { + JDKFamily data2 = reducedFamilies.get(j); + //if we found a duplicate we need to merge the families + if (data1.name.equals(data2.name)) { + hasDuplicate = true; + processed [j] = true; + JDKFamily reducedData = reduceData(data1.name, new LinkedList(Arrays.asList(data1.releases)), new LinkedList(Arrays.asList(data2.releases))); + tmpReducedFamilies.add(reducedData); + //after the first duplicate has been found we break the loop since the duplicates are + //processed two by two + break; + } + } + //if no duplicate has been found we just insert the whole family in the tmp list + if (!hasDuplicate) { + tmpReducedFamilies.add(data1); + } + } + reducedFamilies = tmpReducedFamilies; + } + JDKFamilyList jdkFamilyList = new JDKFamilyList(); + jdkFamilyList.version = version; + jdkFamilyList.data = new JDKFamily[reducedFamilies.size()]; + reducedFamilies.toArray(jdkFamilyList.data); + JSONObject reducedJdkFamilyList = JSONObject.fromObject(jdkFamilyList, jsonConfig); + //return the list with no duplicates + return reducedJdkFamilyList; + } + + private JDKFamily reduceData(String name, List releases1, List releases2) { + LinkedList reducedReleases = new LinkedList<>(); + for (Iterator iterator = releases1.iterator(); iterator.hasNext(); ) { + JDKRelease release1 = iterator.next(); + boolean hasDuplicate = false; + for (Iterator iterator2 = releases2.iterator(); iterator2.hasNext(); ) { + JDKRelease release2 = iterator2.next(); + if (release1.name.equals(release2.name)) { + hasDuplicate = true; + JDKRelease reducedRelease = reduceReleases(release1, new LinkedList(Arrays.asList(release1.files)), new LinkedList(Arrays.asList(release2.files))); + iterator2.remove(); + reducedReleases.add(reducedRelease); + //we assume that in one release list there are no duplicates so we stop at the first one + break; + } + } + if (!hasDuplicate) { + reducedReleases.add(release1); + } + } + reducedReleases.addAll(releases2); + JDKFamily reducedFamily = new JDKFamily(); + reducedFamily.name = name; + reducedFamily.releases = new JDKRelease[reducedReleases.size()]; + reducedReleases.toArray(reducedFamily.releases); + return reducedFamily; + } + + private JDKRelease reduceReleases(JDKRelease release, List files1, List files2) { + LinkedList reducedFiles = new LinkedList<>(); + for (Iterator iterator1 = files1.iterator(); iterator1.hasNext(); ) { + JDKFile file1 = iterator1.next(); + for (Iterator iterator2 = files2.iterator(); iterator2.hasNext(); ) { + JDKFile file2 = iterator2.next(); + if (file1.name.equals(file2.name)) { + iterator2.remove(); + //we assume the in one file list there are no duplicates so we break after we find the + //first match + break; + } + } + } + reducedFiles.addAll(files1); + reducedFiles.addAll(files2); + + JDKRelease jdkRelease = new JDKRelease(); + jdkRelease.files = new JDKFile[reducedFiles.size()]; + reducedFiles.toArray(jdkRelease.files); + jdkRelease.name = release.name; + jdkRelease.licpath = release.licpath; + jdkRelease.lictitle = release.lictitle; + jdkRelease.title = release.title; + return jdkRelease; + } } private static final Logger LOGGER = Logger.getLogger(JDKInstaller.class.getName()); diff --git a/core/src/main/java/hudson/tools/ToolInstallation.java b/core/src/main/java/hudson/tools/ToolInstallation.java index 0ba5dd730c871b21732708586b6616654463cbeb..a14fed1c1bf257ef7ad13cab3861d486f321418c 100644 --- a/core/src/main/java/hudson/tools/ToolInstallation.java +++ b/core/src/main/java/hudson/tools/ToolInstallation.java @@ -90,6 +90,7 @@ public abstract class ToolInstallation extends AbstractDescribableImpl, Exten public ToolInstallerDescriptor getDescriptor() { return (ToolInstallerDescriptor) Jenkins.getInstance().getDescriptorOrDie(getClass()); } + + @Restricted(NoExternalUse.class) + public static final class ToolInstallerList { + /** + * the list of {@link ToolInstallerEntry} + */ + public ToolInstallerEntry [] list; + } + + @Restricted(NoExternalUse.class) + public static final class ToolInstallerEntry { + /** + * the id of the of the release entry + */ + public String id; + /** + * the name of the release entry + */ + public String name; + /** + * the url of the release + */ + public String url; + + /** + * public default constructor needed by the JSON parser + */ + public ToolInstallerEntry() { + + } + + /** + * The constructor + * @param id the id of the release + * @param name the name of the release + * @param url the URL of thr release + */ + public ToolInstallerEntry (String id, String name, String url) { + this.id = id; + this.name = name; + this.url = url; + } + } } diff --git a/core/src/main/java/hudson/tools/ToolLocationNodeProperty.java b/core/src/main/java/hudson/tools/ToolLocationNodeProperty.java index 55526dfb19c01b0667759326513fdf693abc372c..cd5157ed46ee357b7c33c7253e9dc112d61b4a6f 100644 --- a/core/src/main/java/hudson/tools/ToolLocationNodeProperty.java +++ b/core/src/main/java/hudson/tools/ToolLocationNodeProperty.java @@ -90,6 +90,7 @@ public class ToolLocationNodeProperty extends NodeProperty { * @deprecated since 2009-04-09. * Use {@link ToolInstallation#translateFor(Node,TaskListener)} */ + @Deprecated public static String getToolHome(Node node, ToolInstallation installation, TaskListener log) throws IOException, InterruptedException { String result = null; @@ -167,6 +168,7 @@ public class ToolLocationNodeProperty extends NodeProperty { return home; } + @SuppressWarnings("deprecation") // TODO this was mistakenly made to be the ToolDescriptor class name, rather than .id as you would expect; now baked into serial form public ToolDescriptor getType() { if (descriptor == null) { descriptor = (ToolDescriptor) Descriptor.find(type); diff --git a/core/src/main/java/hudson/tools/ToolLocationTranslator.java b/core/src/main/java/hudson/tools/ToolLocationTranslator.java index 09350475077fc6265a3158b30ccc54a33f730079..47194ef37f57b90220408fa9045ab7d945189531 100644 --- a/core/src/main/java/hudson/tools/ToolLocationTranslator.java +++ b/core/src/main/java/hudson/tools/ToolLocationTranslator.java @@ -26,7 +26,6 @@ package hudson.tools; import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.slaves.NodeSpecific; -import jenkins.model.Jenkins; import hudson.model.Node; import hudson.model.TaskListener; diff --git a/core/src/main/java/hudson/triggers/SCMTrigger.java b/core/src/main/java/hudson/triggers/SCMTrigger.java index 6289c759a58647b71dd2427202124174bdb04295..6f772064a59f1f6ffa397a22a87f93c4269cf890 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,8 +134,7 @@ public class SCMTrigger extends Trigger { * @since 1.375 */ public void run(Action[] additionalActions) { - if (Jenkins.getInstance().isQuietingDown()) { - LOGGER.log(INFO, "Skipping polling for {0} since Jenkins is in quiet mode", job.getFullName()); + if (job == null) { return; } @@ -157,6 +162,10 @@ public class SCMTrigger extends Trigger { @Override public Collection getProjectActions() { + if (job == null) { + return Collections.emptyList(); + } + return Collections.singleton(new SCMAction()); } @@ -462,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 { @@ -519,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; @@ -537,6 +544,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 { @@ -605,6 +616,7 @@ public class SCMTrigger extends Trigger { * @deprecated * Use {@link #SCMTrigger.SCMTriggerCause(String)}. */ + @Deprecated public SCMTriggerCause() { this(""); } diff --git a/core/src/main/java/hudson/triggers/SafeTimerTask.java b/core/src/main/java/hudson/triggers/SafeTimerTask.java index e47dfc61e62b52872beaede1f3a03317cf5f5bfe..08a6e16dcd3f66609fe83154f8ce13507bf37760 100644 --- a/core/src/main/java/hudson/triggers/SafeTimerTask.java +++ b/core/src/main/java/hudson/triggers/SafeTimerTask.java @@ -29,7 +29,6 @@ import hudson.security.ACL; import java.util.TimerTask; import java.util.logging.Level; import java.util.logging.Logger; -import jenkins.util.Timer; import org.acegisecurity.context.SecurityContext; import org.acegisecurity.context.SecurityContextHolder; diff --git a/core/src/main/java/hudson/triggers/TimerTrigger.java b/core/src/main/java/hudson/triggers/TimerTrigger.java index 0466c8a4c31404b2b3babf6d112a0829b98c3481..c2a3ee4574cb07e9c460c79b5ade86d9f5f6c6bd 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 @@ -33,11 +34,16 @@ import hudson.scheduler.CronTabList; import hudson.scheduler.Hash; import hudson.util.FormValidation; import java.text.DateFormat; +import java.util.ArrayList; import java.util.Calendar; +import java.util.Collection; + 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. * @@ -46,12 +52,16 @@ 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); } @Override public void run() { + if (job == null) { + return; + } + job.scheduleBuild(0, new TimerTriggerCause()); } @@ -76,22 +86,32 @@ public class TimerTrigger extends Trigger { public FormValidation doCheckSpec(@QueryParameter String value, @AncestorInPath Item item) { try { CronTabList ctl = CronTabList.create(fixNull(value), item != null ? Hash.from(item.getFullName()) : null); - String msg = ctl.checkSanity(); - if(msg!=null) return FormValidation.warning(msg); - Calendar prev = ctl.previous(); - Calendar next = ctl.next(); - if (prev != null && next != null) { - DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL); - return FormValidation.ok(Messages.TimerTrigger_would_last_have_run_at_would_next_run_at(fmt.format(prev.getTime()), fmt.format(next.getTime()))); - } else { - return FormValidation.warning(Messages.TimerTrigger_no_schedules_so_will_never_run()); - } + Collection validations = new ArrayList<>(); + updateValidationsForSanity(validations, ctl); + updateValidationsForNextRun(validations, ctl); + return FormValidation.aggregate(validations); } catch (ANTLRException e) { if (value.trim().indexOf('\n')==-1 && value.contains("**")) return FormValidation.error(Messages.TimerTrigger_MissingWhitespace()); return FormValidation.error(e.getMessage()); } } + + private void updateValidationsForSanity(Collection validations, CronTabList ctl) { + String msg = ctl.checkSanity(); + if(msg!=null) validations.add(FormValidation.warning(msg)); + } + + private void updateValidationsForNextRun(Collection validations, CronTabList ctl) { + Calendar prev = ctl.previous(); + Calendar next = ctl.next(); + if (prev != null && next != null) { + DateFormat fmt = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL); + validations.add(FormValidation.ok(Messages.TimerTrigger_would_last_have_run_at_would_next_run_at(fmt.format(prev.getTime()), fmt.format(next.getTime())))); + } else { + validations.add(FormValidation.warning(Messages.TimerTrigger_no_schedules_so_will_never_run())); + } + } } public static class TimerTriggerCause extends Cause { diff --git a/core/src/main/java/hudson/triggers/Trigger.java b/core/src/main/java/hudson/triggers/Trigger.java index 32b4d9b5bc36689cd365f13908925b481d1e67b6..65350e48ca78eb41b0c59619640440bd295e466b 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 @@ -57,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; @@ -99,6 +102,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() {} @@ -120,6 +125,7 @@ public abstract class Trigger implements Describable> * @deprecated as of 1.341 * Use {@link #getProjectActions()} instead. */ + @Deprecated public Action getProjectAction() { return null; } @@ -146,6 +152,7 @@ public abstract class Trigger implements Describable> protected final String spec; protected transient CronTabList tabs; + @CheckForNull protected transient J job; /** @@ -153,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); } @@ -303,7 +310,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; diff --git a/core/src/main/java/hudson/triggers/Triggers.java b/core/src/main/java/hudson/triggers/Triggers.java index 746ced5028cb8cace1dee03e9c1108ef848077b3..04c04d8546b10f38c9ead2c99d7193e67ba86dc8 100644 --- a/core/src/main/java/hudson/triggers/Triggers.java +++ b/core/src/main/java/hudson/triggers/Triggers.java @@ -36,12 +36,14 @@ import java.util.List; * @deprecated as of 1.286 * See each member for how to migrate your code. */ +@Deprecated public class Triggers { /** * All registered {@link TriggerDescriptor} implementations. * @deprecated as of 1.286 * Use {@link Trigger#all()} for read access, and {@link Extension} for registration. */ + @Deprecated public static final List TRIGGERS = (List)new DescriptorList>((Class)Trigger.class); // Descriptor.toList( // SCMTrigger.DESCRIPTOR, @@ -54,6 +56,7 @@ public class Triggers { * @deprecated as of 1.286 * Use {@link Trigger#for_(Item)}. */ + @Deprecated public static List getApplicableTriggers(Item i) { return Trigger.for_(i); } diff --git a/core/src/main/java/hudson/util/AlternativeUiTextProvider.java b/core/src/main/java/hudson/util/AlternativeUiTextProvider.java index 9b4aa3b458530478e5f7e0c7445aafe070d495d0..45605bb7626df713495a30d34d9b91210166b789 100644 --- a/core/src/main/java/hudson/util/AlternativeUiTextProvider.java +++ b/core/src/main/java/hudson/util/AlternativeUiTextProvider.java @@ -27,7 +27,6 @@ import hudson.Extension; import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.model.AbstractProject; -import jenkins.model.Jenkins; /** * Provides the alternative text to be rendered in the UI. diff --git a/core/src/main/java/hudson/util/ArgumentListBuilder.java b/core/src/main/java/hudson/util/ArgumentListBuilder.java index d89744a413ca08db2c6154856bb80963c4524e49..e9edd17b1eaa2f42ea06e705c3c07c8918df4877 100644 --- a/core/src/main/java/hudson/util/ArgumentListBuilder.java +++ b/core/src/main/java/hudson/util/ArgumentListBuilder.java @@ -24,7 +24,6 @@ */ package hudson.util; -import hudson.FilePath; import hudson.Launcher; import hudson.Util; diff --git a/core/src/main/java/hudson/util/BootFailure.java b/core/src/main/java/hudson/util/BootFailure.java index 8ad6bedc29ff2fa369dc7c1597fcab0dcf47f49e..eefb4da81978f361b000dfc72f848cab77d4a089 100644 --- a/core/src/main/java/hudson/util/BootFailure.java +++ b/core/src/main/java/hudson/util/BootFailure.java @@ -40,7 +40,10 @@ public abstract class BootFailure extends ErrorObject { LOGGER.log(Level.SEVERE, "Failed to initialize Jenkins",this); WebApp.get(context).setApp(this); - new GroovyHookScript("boot-failure") + if (home == null) { + return; + } + new GroovyHookScript("boot-failure", context, home, BootFailure.class.getClassLoader()) .bind("exception",this) .bind("home",home) .bind("servletContext", context) diff --git a/core/src/main/java/hudson/util/ByteBuffer.java b/core/src/main/java/hudson/util/ByteBuffer.java index ee1f16f47ed3e4ef607573f14e2596d4f87b785b..8281ce25c6cda17c87859b07892bfaf00cca3c16 100644 --- a/core/src/main/java/hudson/util/ByteBuffer.java +++ b/core/src/main/java/hudson/util/ByteBuffer.java @@ -37,6 +37,7 @@ import java.io.InputStream; * @author Kohsuke Kawaguchi * @deprecated since 2008-05-28. Moved to stapler */ +@Deprecated public class ByteBuffer extends OutputStream { private byte[] buf = new byte[8192]; /** diff --git a/core/src/main/java/hudson/util/CharSpool.java b/core/src/main/java/hudson/util/CharSpool.java index 45d28ddb783432f8a76a4149fe3e2f2d269ab09f..c27a74cb6fa45d2f562df04b96b97cd3c63047aa 100644 --- a/core/src/main/java/hudson/util/CharSpool.java +++ b/core/src/main/java/hudson/util/CharSpool.java @@ -34,6 +34,7 @@ import java.util.List; * @author Kohsuke Kawaguchi * @deprecated since 2008-05-28. moved to stapler */ +@Deprecated public final class CharSpool extends Writer { private List buf; diff --git a/core/src/main/java/hudson/util/ChartUtil.java b/core/src/main/java/hudson/util/ChartUtil.java index 3d6903ea08453560b2fbc2e46654dd7accb71a25..1fcd8d72156ae3b3a9bbd4084b614ce208cddebf 100644 --- a/core/src/main/java/hudson/util/ChartUtil.java +++ b/core/src/main/java/hudson/util/ChartUtil.java @@ -100,6 +100,7 @@ public class ChartUtil { * @deprecated * Use {@code awtProblemCause!=null} instead. As of 1.267. */ + @Deprecated public static boolean awtProblem = false; /** @@ -112,11 +113,12 @@ public class ChartUtil { * * @param defaultSize * The size of the picture to be generated. These values can be overridden - * by the query paramter 'width' and 'height' in the request. + * by the query parameter 'width' and 'height' in the request. * @deprecated as of 1.320 * Bind {@link Graph} to the URL space. See {@code hudson.tasks.junit.History} as an example (note that doing so involves * a bit of URL structure change.) */ + @Deprecated public static void generateGraph(StaplerRequest req, StaplerResponse rsp, JFreeChart chart, Area defaultSize) throws IOException { generateGraph(req,rsp,chart,defaultSize.width, defaultSize.height); } @@ -127,11 +129,12 @@ public class ChartUtil { * @param defaultW * @param defaultH * The size of the picture to be generated. These values can be overridden - * by the query paramter 'width' and 'height' in the request. + * by the query parameter 'width' and 'height' in the request. * @deprecated as of 1.320 * Bind {@link Graph} to the URL space. See {@code hudson.tasks.junit.History} as an example (note that doing so involves * a bit of URL structure change.) */ + @Deprecated public static void generateGraph(StaplerRequest req, StaplerResponse rsp, final JFreeChart chart, int defaultW, int defaultH) throws IOException { new Graph(-1,defaultW,defaultH) { protected JFreeChart createGraph() { @@ -147,6 +150,7 @@ public class ChartUtil { * Bind {@link Graph} to the URL space. See {@code hudson.tasks.junit.History} as an example (note that doing so involves * a bit of URL structure change.) */ + @Deprecated public static void generateClickableMap(StaplerRequest req, StaplerResponse rsp, JFreeChart chart, Area defaultSize) throws IOException { generateClickableMap(req,rsp,chart,defaultSize.width,defaultSize.height); } @@ -158,6 +162,7 @@ public class ChartUtil { * Bind {@link Graph} to the URL space. See {@code hudson.tasks.junit.History} as an example (note that doing so involves * a bit of URL structure change.) */ + @Deprecated public static void generateClickableMap(StaplerRequest req, StaplerResponse rsp, final JFreeChart chart, int defaultW, int defaultH) throws IOException { new Graph(-1,defaultW,defaultH) { protected JFreeChart createGraph() { diff --git a/core/src/main/java/hudson/util/ComboBoxModel.java b/core/src/main/java/hudson/util/ComboBoxModel.java index 48351bc16b5acacc1fc729dafc6516e5f5b8a6d5..f39f9bc555319eb6aed33a0f3c965e23dab4f700 100644 --- a/core/src/main/java/hudson/util/ComboBoxModel.java +++ b/core/src/main/java/hudson/util/ComboBoxModel.java @@ -33,7 +33,6 @@ import javax.servlet.ServletException; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import static java.util.Arrays.asList; diff --git a/core/src/main/java/hudson/util/ConsistentHash.java b/core/src/main/java/hudson/util/ConsistentHash.java index 83bdb3f53d27ae8283606a93698ebb0400f2d8c4..cd67228ce0b003b864996f3e939b83022a23d6ae 100644 --- a/core/src/main/java/hudson/util/ConsistentHash.java +++ b/core/src/main/java/hudson/util/ConsistentHash.java @@ -64,6 +64,7 @@ public class ConsistentHash { * All the items in the hash, to their replication factors. */ private final Map items = new HashMap(); + private int numPoints; private final int defaultReplication; private final Hash hash; @@ -100,8 +101,13 @@ public class ConsistentHash { private final Object[] owner; // really T[] private Table() { + int r=0; + for (Point[] v : items.values()) + r+=v.length; + numPoints = r; + // merge all points from all nodes and sort them into a single array - Point[] allPoints = new Point[countAllPoints()]; + Point[] allPoints = new Point[numPoints]; int p=0; for (Point[] v : items.values()) { System.arraycopy(v,0,allPoints,p,v.length); @@ -186,18 +192,18 @@ public class ConsistentHash { String hash(T t); } - static final Hash DEFAULT_HASH = new Hash() { + static final Hash DEFAULT_HASH = new Hash() { public String hash(Object o) { return o.toString(); } }; public ConsistentHash() { - this(DEFAULT_HASH); + this((Hash) DEFAULT_HASH); } public ConsistentHash(int defaultReplication) { - this(DEFAULT_HASH,defaultReplication); + this((Hash) DEFAULT_HASH,defaultReplication); } public ConsistentHash(Hash hash) { @@ -211,23 +217,20 @@ public class ConsistentHash { } public int countAllPoints() { - int r=0; - for (Point[] v : items.values()) - r+=v.length; - return r; + return numPoints; } /** * Adds a new node with the default number of replica. */ - public void add(T node) { + public synchronized void add(T node) { add(node,defaultReplication); } /** * Calls {@link #add(Object)} with all the arguments. */ - public void addAll(T... nodes) { + public synchronized void addAll(T... nodes) { for (T node : nodes) addInternal(node,defaultReplication); refreshTable(); @@ -236,7 +239,7 @@ public class ConsistentHash { /** * Calls {@link #add(Object)} with all the arguments. */ - public void addAll(Collection nodes) { + public synchronized void addAll(Collection nodes) { for (T node : nodes) addInternal(node,defaultReplication); refreshTable(); @@ -245,7 +248,7 @@ public class ConsistentHash { /** * Calls {@link #add(Object,int)} with all the arguments. */ - public void addAll(Map nodes) { + public synchronized void addAll(Map nodes) { for (Map.Entry node : nodes.entrySet()) addInternal(node.getKey(),node.getValue()); refreshTable(); @@ -254,23 +257,20 @@ public class ConsistentHash { /** * Removes the node entirely. This is the same as {@code add(node,0)} */ - public void remove(T node) { + public synchronized void remove(T node) { add(node, 0); } /** * Adds a new node with the given number of replica. - * - *

- * This is the only function that manipulates {@link #items}. */ public synchronized void add(T node, int replica) { addInternal(node, replica); refreshTable(); } - private void addInternal(T node, int replica) { - if(replica==0) { + private synchronized void addInternal(T node, int replica) { + if (replica==0) { items.remove(node); } else { Point[] points = new Point[replica]; @@ -281,11 +281,10 @@ public class ConsistentHash { } } - private void refreshTable() { + private synchronized void refreshTable() { table = new Table(); } - /** * Compresses a string into an integer with MD5. */ diff --git a/core/src/main/java/hudson/util/CopyOnWriteList.java b/core/src/main/java/hudson/util/CopyOnWriteList.java index 179d2d08250ae155ded9d3514230ace799b47dce..43e189ba19a5a15f70c31b102cc8e2229067504e 100644 --- a/core/src/main/java/hudson/util/CopyOnWriteList.java +++ b/core/src/main/java/hudson/util/CopyOnWriteList.java @@ -39,6 +39,8 @@ import java.util.Iterator; import java.util.List; import java.util.Arrays; +import jenkins.util.xstream.CriticalXStreamException; + /** * {@link List}-like implementation that has copy-on-write semantics. @@ -194,6 +196,8 @@ public class CopyOnWriteList implements Iterable { try { Object item = readItem(reader, context, items); items.add(item); + } catch (CriticalXStreamException e) { + throw e; } catch (XStreamException e) { RobustReflectionConverter.addErrorInContext(context, e); } catch (LinkageError e) { diff --git a/core/src/main/java/hudson/util/CyclicGraphDetector.java b/core/src/main/java/hudson/util/CyclicGraphDetector.java index 74f7fdeb48afc155a1aa7ecfd22ffc087cb25c50..7e0bf2029db3de6b84bf54c2148aa68d2333582f 100644 --- a/core/src/main/java/hudson/util/CyclicGraphDetector.java +++ b/core/src/main/java/hudson/util/CyclicGraphDetector.java @@ -3,9 +3,7 @@ package hudson.util; import hudson.Util; import java.util.ArrayList; -import java.util.Collection; import java.util.HashSet; -import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.Stack; diff --git a/core/src/main/java/hudson/util/DescribableList.java b/core/src/main/java/hudson/util/DescribableList.java index 027ce70d41d705e948bc3e5c9d7555f4ee3ad129..66c60e443598739c4d88a2e977817f9c72342146 100644 --- a/core/src/main/java/hudson/util/DescribableList.java +++ b/core/src/main/java/hudson/util/DescribableList.java @@ -46,6 +46,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Persisted list of {@link Describable}s with some operations specific @@ -69,6 +71,7 @@ public class DescribableList, D extends Descriptor> * @deprecated since 2008-08-15. * Use {@link #DescribableList(Saveable)} */ + @Deprecated public DescribableList(Owner owner) { setOwner(owner); } @@ -86,6 +89,7 @@ public class DescribableList, D extends Descriptor> * @deprecated since 2008-08-15. * Use {@link #setOwner(Saveable)} */ + @Deprecated public void setOwner(Owner owner) { this.owner = owner; } @@ -187,6 +191,7 @@ public class DescribableList, D extends Descriptor> * @deprecated as of 1.271 * Use {@link #rebuild(StaplerRequest, JSONObject, List)} instead. */ + @Deprecated public void rebuild(StaplerRequest req, JSONObject json, List> descriptors, String prefix) throws FormException, IOException { rebuild(req,json,descriptors); } @@ -210,7 +215,11 @@ public class DescribableList, D extends Descriptor> for (Object o : this) { if (o instanceof DependencyDeclarer) { DependencyDeclarer dd = (DependencyDeclarer) o; - dd.buildDependencyGraph(owner,graph); + try { + dd.buildDependencyGraph(owner,graph); + } catch (RuntimeException e) { + LOGGER.log(Level.SEVERE, "Failed to build dependency graph for " + owner,e); + } } } } @@ -233,6 +242,7 @@ public class DescribableList, D extends Descriptor> * @deprecated since 2008-08-15. * Just implement {@link Saveable}. */ + @Deprecated public interface Owner extends Saveable { } @@ -277,4 +287,6 @@ public class DescribableList, D extends Descriptor> } } } + + private final static Logger LOGGER = Logger.getLogger(DescribableList.class.getName()); } diff --git a/core/src/main/java/hudson/util/DescriptorList.java b/core/src/main/java/hudson/util/DescriptorList.java index 3f90c68c777495df7dd1a6a13024f14ac85a477d..f7f716860fc02ce19d7e4f2578cf5a331f4f5d6d 100644 --- a/core/src/main/java/hudson/util/DescriptorList.java +++ b/core/src/main/java/hudson/util/DescriptorList.java @@ -78,6 +78,7 @@ public final class DescriptorList> extends AbstractList * @deprecated * As of 1.286. Use {@link #DescriptorList(Class)} instead. */ + @Deprecated public DescriptorList(Descriptor... descriptors) { this.type = null; this.legacy = new CopyOnWriteArrayList>(descriptors); @@ -114,6 +115,7 @@ public final class DescriptorList> extends AbstractList * instead of registering a descriptor manually. */ @Override + @Deprecated public boolean add(Descriptor d) { return store().add(d); } @@ -126,6 +128,7 @@ public final class DescriptorList> extends AbstractList * instead of registering a descriptor manually. */ @Override + @Deprecated public void add(int index, Descriptor element) { add(element); // order is ignored } @@ -196,6 +199,7 @@ public final class DescriptorList> extends AbstractList /** * Finds the descriptor that has the matching fully-qualified class name. + * @deprecated Underspecified what the parameter is. {@link Descriptor#getId}? A {@link Describable} class name? */ public Descriptor find(String fqcn) { return Descriptor.find(this,fqcn); diff --git a/core/src/main/java/hudson/util/DoubleLaunchChecker.java b/core/src/main/java/hudson/util/DoubleLaunchChecker.java index 340465023394189bdee0a4e801a98583d7cd394e..801b9fe5c657b9a9173d50186e9d8df7f43dea38 100644 --- a/core/src/main/java/hudson/util/DoubleLaunchChecker.java +++ b/core/src/main/java/hudson/util/DoubleLaunchChecker.java @@ -28,7 +28,6 @@ import jenkins.model.Jenkins; import hudson.triggers.SafeTimerTask; import jenkins.util.Timer; import org.apache.commons.io.FileUtils; -import org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; @@ -51,7 +50,7 @@ import java.lang.reflect.Method; * to forestall the problem of running multiple instances of Hudson that point to the same data directory. * *

- * 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/FormFieldValidator.java b/core/src/main/java/hudson/util/FormFieldValidator.java index d344dd43d5b9c1dc8bd02ab0f0a89bb56bdae8d7..2fc8874a9683153985d8c99dd110b5a14c261e80 100644 --- a/core/src/main/java/hudson/util/FormFieldValidator.java +++ b/core/src/main/java/hudson/util/FormFieldValidator.java @@ -61,6 +61,7 @@ import org.kohsuke.stapler.Stapler; * @deprecated as of 1.294 * Use {@link FormValidation} as a return value in your check method. */ +@Deprecated public abstract class FormFieldValidator { public static final Permission CHECK = Jenkins.ADMINISTER; @@ -92,6 +93,7 @@ public abstract class FormFieldValidator { * Use {@link #FormFieldValidator(Permission)} and remove {@link StaplerRequest} and {@link StaplerResponse} * from your "doCheck..." method parameter */ + @Deprecated protected FormFieldValidator(StaplerRequest request, StaplerResponse response, Permission permission) { this(request,response, Jenkins.getInstance(),permission); } @@ -109,6 +111,7 @@ public abstract class FormFieldValidator { * Use {@link #FormFieldValidator(AccessControlled,Permission)} and remove {@link StaplerRequest} and {@link StaplerResponse} * from your "doCheck..." method parameter */ + @Deprecated protected FormFieldValidator(StaplerRequest request, StaplerResponse response, AccessControlled subject, Permission permission) { this.request = request; this.response = response; @@ -239,6 +242,7 @@ public abstract class FormFieldValidator { * @deprecated as of 1.294 * Use {@link FormValidation.URLCheck} */ + @Deprecated public static abstract class URLCheck extends FormFieldValidator { public URLCheck(StaplerRequest request, StaplerResponse response) { @@ -346,8 +350,9 @@ public abstract class FormFieldValidator { * Checks the file mask (specified in the 'value' query parameter) against * the current workspace. * @since 1.90. - * @deprecated as of 1.294. Use {@link FilePath#validateFileMask(String, boolean)} + * @deprecated as of 1.294. Use {@link FilePath#validateFileMask(String, boolean, boolean)} */ + @Deprecated public static class WorkspaceFileMask extends FormFieldValidator { private final boolean errorIfNotExist; @@ -401,6 +406,7 @@ public abstract class FormFieldValidator { * @deprecated as of 1.294. Use {@link FilePath#validateRelativeDirectory(String, boolean)} * (see javadoc plugin for the example) */ + @Deprecated public static class WorkspaceDirectory extends WorkspaceFilePath { public WorkspaceDirectory(StaplerRequest request, StaplerResponse response, boolean errorIfNotExist) { super(request, response, errorIfNotExist, false); @@ -417,6 +423,7 @@ public abstract class FormFieldValidator { * @since 1.160 * @deprecated as of 1.294. Use {@link FilePath#validateRelativePath(String, boolean, boolean)} */ + @Deprecated public static class WorkspaceFilePath extends FormFieldValidator { private final boolean errorIfNotExist; private final boolean expectingFile; @@ -500,6 +507,7 @@ public abstract class FormFieldValidator { * @since 1.124 * @deprecated as of 1.294. Use {@link FormValidation#validateExecutable(String)} */ + @Deprecated public static class Executable extends FormFieldValidator { public Executable(StaplerRequest request, StaplerResponse response) { @@ -586,6 +594,7 @@ public abstract class FormFieldValidator { * @deprecated as of 1.305 * Use {@link FormValidation#validateBase64(String, boolean, boolean, String)} instead. */ + @Deprecated public static class Base64 extends FormFieldValidator { private final boolean allowWhitespace; private final boolean allowEmpty; @@ -632,6 +641,7 @@ public abstract class FormFieldValidator { * @deprecated as of 1.294 * Use {@link FormValidation#validateNonNegativeInteger(String)} */ + @Deprecated public static class NonNegativeInteger extends FormFieldValidator { public NonNegativeInteger() { super(null); diff --git a/core/src/main/java/hudson/util/FormValidation.java b/core/src/main/java/hudson/util/FormValidation.java index 12b6c069d2575098ade68359b4e0a6e4b1bb3a5c..4c52f19b6d909f07ccc703c5de43a2d490ea1460 100644 --- a/core/src/main/java/hudson/util/FormValidation.java +++ b/core/src/main/java/hudson/util/FormValidation.java @@ -199,7 +199,7 @@ public abstract class FormValidation extends IOException implements HttpResponse " " + Messages.FormValidation_Error_Details() + "

"
-            + Functions.printThrowable(e) +
+            + Util.escape(Functions.printThrowable(e)) +
             "
",kind ); } @@ -216,7 +216,7 @@ public abstract class FormValidation extends IOException implements HttpResponse * Aggregate multiple validations into one. * * @return Validation of the least successful kind aggregating all child messages. - * @since TODO + * @since 1.590 */ public static @Nonnull FormValidation aggregate(@Nonnull Collection validations) { if (validations == null || validations.isEmpty()) return FormValidation.ok(); diff --git a/core/src/main/java/hudson/util/Graph.java b/core/src/main/java/hudson/util/Graph.java index 8009286eac4f2647e6835ef8fa0a73833a2feeb4..bef25b2d9e06bece21efe418c82a0bacccde552d 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. */ diff --git a/core/src/main/java/hudson/util/IOUtils.java b/core/src/main/java/hudson/util/IOUtils.java index e88013c701f4c8182775747d1bc7ad3984c07e57..b8edc312426a650da8a380f22f98d673209e6ecc 100644 --- a/core/src/main/java/hudson/util/IOUtils.java +++ b/core/src/main/java/hudson/util/IOUtils.java @@ -149,31 +149,37 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#DIR_SEPARATOR_UNIX} */ + @Deprecated public static final char DIR_SEPARATOR_UNIX = org.apache.commons.io.IOUtils.DIR_SEPARATOR_UNIX; /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#DIR_SEPARATOR_WINDOWS} */ + @Deprecated public static final char DIR_SEPARATOR_WINDOWS = org.apache.commons.io.IOUtils.DIR_SEPARATOR_WINDOWS; /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#DIR_SEPARATOR} */ + @Deprecated public static final char DIR_SEPARATOR = org.apache.commons.io.IOUtils.DIR_SEPARATOR; /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#LINE_SEPARATOR_UNIX} */ + @Deprecated public static final String LINE_SEPARATOR_UNIX = org.apache.commons.io.IOUtils.LINE_SEPARATOR_UNIX; /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#LINE_SEPARATOR_WINDOWS} */ + @Deprecated public static final String LINE_SEPARATOR_WINDOWS = org.apache.commons.io.IOUtils.LINE_SEPARATOR_WINDOWS; /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#LINE_SEPARATOR} */ + @Deprecated public static final String LINE_SEPARATOR; static { @@ -187,6 +193,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#closeQuietly(java.io.Reader)} */ + @Deprecated public static void closeQuietly(Reader input) { org.apache.commons.io.IOUtils.closeQuietly(input); } @@ -194,6 +201,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#closeQuietly(java.io.Writer)} */ + @Deprecated public static void closeQuietly(Writer output) { org.apache.commons.io.IOUtils.closeQuietly(output); } @@ -201,6 +209,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#closeQuietly(java.io.InputStream)} */ + @Deprecated public static void closeQuietly(InputStream input) { org.apache.commons.io.IOUtils.closeQuietly(input); } @@ -208,6 +217,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#closeQuietly(java.io.OutputStream)} */ + @Deprecated public static void closeQuietly(OutputStream output) { org.apache.commons.io.IOUtils.closeQuietly(output); } @@ -215,6 +225,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#toByteArray(java.io.InputStream)} */ + @Deprecated public static byte[] toByteArray(InputStream input) throws IOException { return org.apache.commons.io.IOUtils.toByteArray(input); } @@ -222,6 +233,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#toByteArray(java.io.Reader)} */ + @Deprecated public static byte[] toByteArray(Reader input) throws IOException { return org.apache.commons.io.IOUtils.toByteArray(input); } @@ -229,6 +241,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#toByteArray(java.io.Reader, String)} */ + @Deprecated public static byte[] toByteArray(Reader input, String encoding) throws IOException { return org.apache.commons.io.IOUtils.toByteArray(input, encoding); } @@ -236,6 +249,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#toByteArray(String)} */ + @Deprecated public static byte[] toByteArray(String input) throws IOException { return org.apache.commons.io.IOUtils.toByteArray(input); } @@ -243,6 +257,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#toCharArray(java.io.InputStream)} */ + @Deprecated public static char[] toCharArray(InputStream is) throws IOException { return org.apache.commons.io.IOUtils.toCharArray(is); } @@ -250,6 +265,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#toCharArray(java.io.InputStream, String)} */ + @Deprecated public static char[] toCharArray(InputStream is, String encoding) throws IOException { return org.apache.commons.io.IOUtils.toCharArray(is, encoding); } @@ -257,6 +273,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#toCharArray(java.io.Reader)} */ + @Deprecated public static char[] toCharArray(Reader input) throws IOException { return org.apache.commons.io.IOUtils.toCharArray(input); } @@ -264,6 +281,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#toString(java.io.InputStream)} */ + @Deprecated public static String toString(InputStream input) throws IOException { return org.apache.commons.io.IOUtils.toString(input); } @@ -271,6 +289,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#toString(java.io.InputStream, String)} */ + @Deprecated public static String toString(InputStream input, String encoding) throws IOException { return org.apache.commons.io.IOUtils.toString(input, encoding); } @@ -278,6 +297,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#toString(java.io.Reader)} */ + @Deprecated public static String toString(Reader input) throws IOException { return org.apache.commons.io.IOUtils.toString(input); } @@ -285,6 +305,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#toString(byte[])} */ + @Deprecated public static String toString(byte[] input) throws IOException { return org.apache.commons.io.IOUtils.toString(input); } @@ -292,6 +313,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#toString(byte[], String)} */ + @Deprecated public static String toString(byte[] input, String encoding) throws IOException { return org.apache.commons.io.IOUtils.toString(input, encoding); } @@ -299,6 +321,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#readLines(java.io.InputStream)} */ + @Deprecated public static List readLines(InputStream input) throws IOException { return org.apache.commons.io.IOUtils.readLines(input); } @@ -306,6 +329,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#readLines(java.io.InputStream, String)} */ + @Deprecated public static List readLines(InputStream input, String encoding) throws IOException { return org.apache.commons.io.IOUtils.readLines(input, encoding); } @@ -313,6 +337,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#readLines(java.io.Reader)} */ + @Deprecated public static List readLines(Reader input) throws IOException { return org.apache.commons.io.IOUtils.readLines(input); } @@ -320,6 +345,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#lineIterator(java.io.Reader)} */ + @Deprecated public static LineIterator lineIterator(Reader reader) { return org.apache.commons.io.IOUtils.lineIterator(reader); } @@ -327,6 +353,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#lineIterator(java.io.InputStream, String)} */ + @Deprecated public static LineIterator lineIterator(InputStream input, String encoding) throws IOException { return org.apache.commons.io.IOUtils.lineIterator(input, encoding); } @@ -334,6 +361,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#toInputStream(String)} */ + @Deprecated public static InputStream toInputStream(String input) { return org.apache.commons.io.IOUtils.toInputStream(input); } @@ -341,6 +369,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#toInputStream(String, String)} */ + @Deprecated public static InputStream toInputStream(String input, String encoding) throws IOException { return org.apache.commons.io.IOUtils.toInputStream(input, encoding); } @@ -348,6 +377,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#write(byte[], java.io.OutputStream)} */ + @Deprecated public static void write(byte[] data, OutputStream output) throws IOException { org.apache.commons.io.IOUtils.write(data, output); } @@ -355,6 +385,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#write(byte[], java.io.Writer)} */ + @Deprecated public static void write(byte[] data, Writer output) throws IOException { org.apache.commons.io.IOUtils.write(data, output); } @@ -362,6 +393,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#write(byte[], java.io.Writer, String)} */ + @Deprecated public static void write(byte[] data, Writer output, String encoding) throws IOException { org.apache.commons.io.IOUtils.write(data, output, encoding); } @@ -369,6 +401,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#write(char[], java.io.OutputStream)} */ + @Deprecated public static void write(char[] data, Writer output) throws IOException { org.apache.commons.io.IOUtils.write(data, output); } @@ -376,6 +409,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#write(char[], java.io.OutputStream)} */ + @Deprecated public static void write(char[] data, OutputStream output) throws IOException { org.apache.commons.io.IOUtils.write(data, output); } @@ -383,6 +417,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#write(char[], java.io.OutputStream, String)} */ + @Deprecated public static void write(char[] data, OutputStream output, String encoding) throws IOException { org.apache.commons.io.IOUtils.write(data, output, encoding); } @@ -390,6 +425,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#write(char[], java.io.Writer)} */ + @Deprecated public static void write(String data, Writer output) throws IOException { org.apache.commons.io.IOUtils.write(data, output); } @@ -397,6 +433,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#write(String, java.io.OutputStream)} */ + @Deprecated public static void write(String data, OutputStream output) throws IOException { org.apache.commons.io.IOUtils.write(data, output); } @@ -404,6 +441,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#write(String, java.io.OutputStream, String)} */ + @Deprecated public static void write(String data, OutputStream output, String encoding) throws IOException { org.apache.commons.io.IOUtils.write(data, output, encoding); } @@ -411,6 +449,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#write(StringBuffer, java.io.Writer)} */ + @Deprecated public static void write(StringBuffer data, Writer output) throws IOException { org.apache.commons.io.IOUtils.write(data, output); } @@ -418,6 +457,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#write(StringBuffer, java.io.OutputStream)} */ + @Deprecated public static void write(StringBuffer data, OutputStream output) throws IOException { org.apache.commons.io.IOUtils.write(data, output); } @@ -425,6 +465,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#write(StringBuffer, java.io.OutputStream, String)} */ + @Deprecated public static void write(StringBuffer data, OutputStream output, String encoding) throws IOException { org.apache.commons.io.IOUtils.write(data, output, encoding); } @@ -432,6 +473,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#writeLines(java.util.Collection, String, java.io.OutputStream)} */ + @Deprecated public static void writeLines(Collection lines, String lineEnding, OutputStream output) throws IOException { org.apache.commons.io.IOUtils.writeLines(lines, lineEnding, output); } @@ -439,6 +481,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#writeLines(java.util.Collection, String, java.io.OutputStream, String)} */ + @Deprecated public static void writeLines(Collection lines, String lineEnding, OutputStream output, String encoding) throws IOException { org.apache.commons.io.IOUtils.writeLines(lines, lineEnding, output, encoding); } @@ -446,6 +489,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#writeLines(java.util.Collection, String, java.io.Writer)} */ + @Deprecated public static void writeLines(Collection lines, String lineEnding, Writer writer) throws IOException { org.apache.commons.io.IOUtils.writeLines(lines, lineEnding, writer); } @@ -453,6 +497,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#copy(java.io.InputStream, java.io.OutputStream)} */ + @Deprecated public static int copy(InputStream input, OutputStream output) throws IOException { return org.apache.commons.io.IOUtils.copy(input, output); } @@ -460,6 +505,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#copyLarge(java.io.InputStream, java.io.OutputStream)} */ + @Deprecated public static long copyLarge(InputStream input, OutputStream output) throws IOException { return org.apache.commons.io.IOUtils.copyLarge(input, output); } @@ -467,6 +513,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#copy(java.io.InputStream, java.io.Writer)} */ + @Deprecated public static void copy(InputStream input, Writer output) throws IOException { org.apache.commons.io.IOUtils.copy(input, output); } @@ -474,6 +521,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#copy(java.io.InputStream, java.io.Writer, String)} */ + @Deprecated public static void copy(InputStream input, Writer output, String encoding) throws IOException { org.apache.commons.io.IOUtils.copy(input, output, encoding); } @@ -481,6 +529,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#copy(java.io.Reader, java.io.Writer)} */ + @Deprecated public static int copy(Reader input, Writer output) throws IOException { return org.apache.commons.io.IOUtils.copy(input, output); } @@ -488,6 +537,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#copyLarge(java.io.Reader, java.io.Writer)} */ + @Deprecated public static long copyLarge(Reader input, Writer output) throws IOException { return org.apache.commons.io.IOUtils.copyLarge(input, output); } @@ -495,6 +545,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#copy(java.io.Reader, java.io.OutputStream)} */ + @Deprecated public static void copy(Reader input, OutputStream output) throws IOException { org.apache.commons.io.IOUtils.copy(input, output); } @@ -502,6 +553,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#copy(java.io.Reader, java.io.OutputStream, String)} */ + @Deprecated public static void copy(Reader input, OutputStream output, String encoding) throws IOException { org.apache.commons.io.IOUtils.copy(input, output, encoding); } @@ -509,6 +561,7 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#contentEquals(java.io.InputStream, java.io.InputStream)} */ + @Deprecated public static boolean contentEquals(InputStream input1, InputStream input2) throws IOException { return org.apache.commons.io.IOUtils.contentEquals(input1, input2); } @@ -516,9 +569,10 @@ public class IOUtils { /** * @deprecated Use instead {@link org.apache.commons.io.IOUtils#contentEquals(java.io.Reader, java.io.Reader)} */ + @Deprecated public static boolean contentEquals(Reader input1, Reader input2) throws IOException { return org.apache.commons.io.IOUtils.contentEquals(input1, input2); } private static final byte[] SKIP_BUFFER = new byte[8192]; -} \ No newline at end of file +} diff --git a/core/src/main/java/hudson/util/KeyedDataStorage.java b/core/src/main/java/hudson/util/KeyedDataStorage.java index bae5c79d6617ba93e68b4f243c1ca9348a4c5bb0..49a220b1b245db200a356c90f7bb0c41ea7ed986 100644 --- a/core/src/main/java/hudson/util/KeyedDataStorage.java +++ b/core/src/main/java/hudson/util/KeyedDataStorage.java @@ -31,6 +31,8 @@ import java.lang.ref.SoftReference; import java.text.MessageFormat; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; /** * Convenient base class for implementing data storage. @@ -69,10 +71,10 @@ public abstract class KeyedDataStorage { * but do so without having a single lock. */ private static class Loading { - private T value; + private @CheckForNull T value; private boolean set; - public synchronized void set(T value) { + public synchronized void set(@CheckForNull T value) { this.set = true; this.value = value; notifyAll(); @@ -82,7 +84,7 @@ public abstract class KeyedDataStorage { * Blocks until the value is {@link #set(Object)} by another thread * and returns the value. */ - public synchronized T get() { + public synchronized @CheckForNull T get() { try { while(!set) wait(); @@ -100,26 +102,31 @@ public abstract class KeyedDataStorage { * {@link #create(String,Object) create} it and return it. * * @return - * Never null. + * Item with the specified {@code key}. * @param createParams * Additional parameters needed to create a new data object. Can be null. + * @throws IOException Loading error */ - public T getOrCreate(String key, P createParams) throws IOException { + public @Nonnull T getOrCreate(String key, P createParams) throws IOException { return get(key,true,createParams); } /** * Finds the data object that matches the given key if available, or null * if not found. + * @return Item with the specified {@code key} + * @throws IOException Loading error */ - public T get(String key) throws IOException { + public @CheckForNull T get(String key) throws IOException { return get(key,false,null); } /** * Implementation of get/getOrCreate. + * @return Item with the specified {@code key} + * @throws IOException Loading error */ - protected T get(String key, boolean createIfNotExist, P createParams) throws IOException { + protected @CheckForNull T get(@Nonnull String key, boolean createIfNotExist, P createParams) throws IOException { while(true) { totalQuery.incrementAndGet(); Object value = core.get(key); @@ -155,7 +162,7 @@ public abstract class KeyedDataStorage { if(t==null && createIfNotExist) { t = create(key,createParams); // create the new data if(t==null) - throw new IllegalStateException(); // bug in the derived classes + throw new IllegalStateException("Bug in the derived class"); // bug in the derived classes } } catch(IOException e) { loadFailure.incrementAndGet(); @@ -192,7 +199,7 @@ public abstract class KeyedDataStorage { * if load operation fails. This exception will be * propagated to the caller. */ - protected abstract T load(String key) throws IOException; + protected abstract @CheckForNull T load(String key) throws IOException; /** * Creates a new data object. @@ -206,13 +213,13 @@ public abstract class KeyedDataStorage { * this method returns a properly initialized "valid" object. * * @return - * never null. If construction fails, abort with an exception. + * Created item. If construction fails, abort with an exception. * @throws IOException * if the method fails to create a new data object, it can throw * {@link IOException} (or any other exception) and that will be * propagated to the caller. */ - protected abstract T create(String key, P createParams) throws IOException; + protected abstract @Nonnull T create(@Nonnull String key, @Nonnull P createParams) throws IOException; public void resetPerformanceStats() { totalQuery.set(0); diff --git a/core/src/main/java/hudson/util/LineEndNormalizingWriter.java b/core/src/main/java/hudson/util/LineEndNormalizingWriter.java index e2f26e75f860a4ab4901226f21a72eb2e31bbf15..2a0edee1d031c5124e8cb7f6d3b416f59b45137a 100644 --- a/core/src/main/java/hudson/util/LineEndNormalizingWriter.java +++ b/core/src/main/java/hudson/util/LineEndNormalizingWriter.java @@ -39,6 +39,7 @@ import java.io.IOException; * @author Kohsuke Kawaguchi * @deprecated since 2008-05-28. moved to stapler */ +@Deprecated public class LineEndNormalizingWriter extends FilterWriter { private boolean seenCR; diff --git a/core/src/main/java/hudson/util/LineEndingConversion.java b/core/src/main/java/hudson/util/LineEndingConversion.java index 744ff4a4eaf8abeb28172ca7cec9bdd710b02e92..fbc64965015022113bfa6eb74855119d3a062bed 100644 --- a/core/src/main/java/hudson/util/LineEndingConversion.java +++ b/core/src/main/java/hudson/util/LineEndingConversion.java @@ -3,7 +3,7 @@ package hudson.util; /** * Converts line endings of a string. * - * @since TODO + * @since 1.582 * @author David Ruhmann */ public class LineEndingConversion { diff --git a/core/src/main/java/hudson/util/ListBoxModel.java b/core/src/main/java/hudson/util/ListBoxModel.java index 6fb0e53ff3f898b03bff56b491bc6baafa64113f..c880739b2cf10ed892a5a6167828da24049884c7 100644 --- a/core/src/main/java/hudson/util/ListBoxModel.java +++ b/core/src/main/java/hudson/util/ListBoxModel.java @@ -176,6 +176,7 @@ public class ListBoxModel extends ArrayList implements Http * Exposed for stapler. Not meant for programatic consumption. */ @Exported + @Deprecated public Option[] values() { return toArray(new Option[size()]); } diff --git a/core/src/main/java/hudson/util/MaskingClassLoader.java b/core/src/main/java/hudson/util/MaskingClassLoader.java index 2a25910de5aee8bda6634b4d6303cd52e237aa4c..c51e1f187bcb5588843b8b0451d872073fa39ef1 100644 --- a/core/src/main/java/hudson/util/MaskingClassLoader.java +++ b/core/src/main/java/hudson/util/MaskingClassLoader.java @@ -23,10 +23,14 @@ */ 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.Enumeration; +import java.util.Collections; /** * {@link ClassLoader} that masks a specified set of classes @@ -41,7 +45,9 @@ public class MaskingClassLoader extends ClassLoader { /** * Prefix of the packages that should be hidden. */ - private List masks; + private final List masksClasses = new ArrayList(); + + private final List masksResources = new ArrayList(); public MaskingClassLoader(ClassLoader parent, String... masks) { this(parent, Arrays.asList(masks)); @@ -49,12 +55,19 @@ public class MaskingClassLoader extends ClassLoader { public MaskingClassLoader(ClassLoader parent, Collection masks) { super(parent); - this.masks = new ArrayList(masks); + this.masksClasses.addAll(masks); + + /** + * The name of a resource is a '/'-separated path name + */ + for (String mask : masks) { + masksResources.add(mask.replace(".","/")); + } } @Override protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - for (String mask : masks) { + for (String mask : masksClasses) { if(name.startsWith(mask)) throw new ClassNotFoundException(); } @@ -62,7 +75,32 @@ public class MaskingClassLoader extends ClassLoader { return super.loadClass(name, resolve); } + @Override + public synchronized URL getResource(String name) { + if (isMasked(name)) return null; + + return super.getResource(name); + } + + @Override + public Enumeration getResources(String name) throws IOException { + if (isMasked(name)) return Collections.emptyEnumeration(); + + return super.getResources(name); + } + public synchronized void add(String prefix) { - masks.add(prefix); + masksClasses.add(prefix); + if(prefix !=null){ + masksResources.add(prefix.replace(".","/")); + } + } + + private boolean isMasked(String name) { + for (String mask : masksResources) { + if(name.startsWith(mask)) + return true; + } + return false; } } diff --git a/core/src/main/java/hudson/util/MultipartFormDataParser.java b/core/src/main/java/hudson/util/MultipartFormDataParser.java index ee579b839055ee11ec7ea15f5cb21edcfbe40a07..5c1184cd2e996aadd1c6f790fbd83768c632a0ca 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; @@ -71,4 +72,30 @@ public class MultipartFormDataParser { for (FileItem item : byName.values()) item.delete(); } + + /** + * 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; + } + + 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/main/java/hudson/util/NamingThreadFactory.java b/core/src/main/java/hudson/util/NamingThreadFactory.java index e55b7dd4a5c9f05129e6b2a93fecca62e3f00c0b..a1994a0433b04174e68ee0f7bbc86dbe84e31443 100644 --- a/core/src/main/java/hudson/util/NamingThreadFactory.java +++ b/core/src/main/java/hudson/util/NamingThreadFactory.java @@ -24,7 +24,6 @@ package hudson.util; -import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; diff --git a/core/src/main/java/hudson/util/NoClientBindProtocolSocketFactory.java b/core/src/main/java/hudson/util/NoClientBindProtocolSocketFactory.java index d23660b4e4aa90f7babe1f88a925da4e52dd0bd3..18a3e3e76173b60abd175993ab108c51888746b7 100644 --- a/core/src/main/java/hudson/util/NoClientBindProtocolSocketFactory.java +++ b/core/src/main/java/hudson/util/NoClientBindProtocolSocketFactory.java @@ -31,9 +31,7 @@ import java.net.UnknownHostException; import org.apache.commons.httpclient.ConnectTimeoutException; import org.apache.commons.httpclient.params.HttpConnectionParams; -import org.apache.commons.httpclient.protocol.ControllerThreadSocketFactory; import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; -import org.apache.commons.httpclient.protocol.ReflectionSocketFactory; /** * A SecureProtocolSocketFactory that creates sockets without binding to a specific interface. diff --git a/core/src/main/java/hudson/util/NoTempDir.java b/core/src/main/java/hudson/util/NoTempDir.java index b45aff8d4feacd48f6a1ddece06fc991b0a33dc5..10cfceb5ac04e446d2bb0c45c1836a8b2130a341 100644 --- a/core/src/main/java/hudson/util/NoTempDir.java +++ b/core/src/main/java/hudson/util/NoTempDir.java @@ -23,7 +23,6 @@ */ package hudson.util; -import hudson.Functions; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; diff --git a/core/src/main/java/hudson/util/PluginServletFilter.java b/core/src/main/java/hudson/util/PluginServletFilter.java index dfc8bdf03e38f670f9bbeec4273627959ea531a5..41d83899a593d46d65d8d9dd63e651cb45283212 100644 --- a/core/src/main/java/hudson/util/PluginServletFilter.java +++ b/core/src/main/java/hudson/util/PluginServletFilter.java @@ -27,6 +27,7 @@ import hudson.ExtensionPoint; import hudson.security.SecurityRealm; import jenkins.model.Jenkins; +import javax.annotation.CheckForNull; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; @@ -71,8 +72,11 @@ public class PluginServletFilter implements Filter, ExtensionPoint { /** * Lookup the instance from servlet context. + * + * @param c the ServletContext most of the time taken from a Jenkins instance + * @return get the current PluginServletFilter if it is already available */ - private static PluginServletFilter getInstance(ServletContext c) { + private static @CheckForNull PluginServletFilter getInstance(ServletContext c) { return (PluginServletFilter)c.getAttribute(KEY); } @@ -90,12 +94,17 @@ public class PluginServletFilter implements Filter, ExtensionPoint { public static void addFilter(Filter filter) throws ServletException { Jenkins j = Jenkins.getInstance(); - if (j==null) { + + PluginServletFilter container = null; + if(j != null) { + container = getInstance(j.servletContext); + } + // https://marvelution.atlassian.net/browse/JJI-188 + if (j==null || container == null) { // report who is doing legacy registration LOGGER.log(Level.WARNING, "Filter instance is registered too early: "+filter, new Exception()); LEGACY.add(filter); } else { - PluginServletFilter container = getInstance(j.servletContext); filter.init(container.config); container.list.add(filter); } @@ -103,7 +112,7 @@ public class PluginServletFilter implements Filter, ExtensionPoint { public static void removeFilter(Filter filter) throws ServletException { Jenkins j = Jenkins.getInstance(); - if (j==null) { + if (j==null || getInstance(j.servletContext) == null) { LEGACY.remove(filter); } else { getInstance(j.servletContext).list.remove(filter); diff --git a/core/src/main/java/hudson/util/ProcessKiller.java b/core/src/main/java/hudson/util/ProcessKiller.java index 81cb4b91a959e6e8205218105789661cdd377fee..1aeb8f7815ed65631348b730244b880f21ba9b80 100644 --- a/core/src/main/java/hudson/util/ProcessKiller.java +++ b/core/src/main/java/hudson/util/ProcessKiller.java @@ -26,8 +26,6 @@ package hudson.util; import hudson.ExtensionList; import hudson.ExtensionPoint; -import jenkins.model.Jenkins; -import hudson.util.ProcessTree.OSProcess; import java.io.IOException; import java.io.Serializable; diff --git a/core/src/main/java/hudson/util/ProcessKillingVeto.java b/core/src/main/java/hudson/util/ProcessKillingVeto.java new file mode 100644 index 0000000000000000000000000000000000000000..a410a610fd6ea1263f905b01714f9389eb13f04f --- /dev/null +++ b/core/src/main/java/hudson/util/ProcessKillingVeto.java @@ -0,0 +1,92 @@ +/* + * The MIT License + * + * Copyright (c) 2015, Daniel Weber + * + * 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 hudson.ExtensionPoint; +import hudson.util.ProcessTreeRemoting.IOSProcess; + +import java.util.Collections; +import java.util.List; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; + +import jenkins.model.Jenkins; + +/** + * Allows extensions to veto killing processes. If at least one extension vetoes + * the killing of a process, it will not be killed. This can be useful to keep + * daemon processes alive. An example is mspdbsrv.exe used by Microsoft + * compilers. + * + * See JENKINS-9104 + * + * @since TODO + * + * @author Daniel Weber + */ +public abstract class ProcessKillingVeto implements ExtensionPoint { + + /** + * Describes the cause for a process killing veto. + */ + public static class VetoCause { + private final String message; + + /** + * @param message A string describing the reason for the veto + */ + public VetoCause(@Nonnull String message) { + this.message = message; + } + + /** + * @return A string describing the reason for the veto. + */ + public @Nonnull String getMessage() { + return message; + } + } + + /** + * @return All ProcessKillingVeto extensions currently registered. An empty + * list if Jenkins is not available, never null. + */ + public static List all() { + Jenkins jenkins = Jenkins.getInstance(); + if (jenkins == null) + return Collections.emptyList(); + return jenkins.getExtensionList(ProcessKillingVeto.class); + } + + /** + * Ask the extension whether it vetoes killing of the given process + * + * @param p The process that is about to be killed + * @return a {@link VetoCause} if the process should not be killed, + * null else. + */ + @CheckForNull + public abstract VetoCause vetoProcessKilling(@Nonnull IOSProcess p); +} diff --git a/core/src/main/java/hudson/util/ProcessTree.java b/core/src/main/java/hudson/util/ProcessTree.java index 00d64f5d75f7e5392f8c92cfab45bf9fb11a400a..dd5a3d756b4d5b80417788a1c330ba9c84e4a289 100644 --- a/core/src/main/java/hudson/util/ProcessTree.java +++ b/core/src/main/java/hudson/util/ProcessTree.java @@ -32,6 +32,7 @@ import hudson.Util; import hudson.remoting.Channel; import hudson.remoting.VirtualChannel; import hudson.slaves.SlaveComputer; +import hudson.util.ProcessKillingVeto.VetoCause; import hudson.util.ProcessTree.OSProcess; import hudson.util.ProcessTreeRemoting.IOSProcess; import hudson.util.ProcessTreeRemoting.IProcessTree; @@ -56,6 +57,7 @@ import java.util.SortedMap; import java.util.logging.Level; import java.util.logging.Logger; +import javax.annotation.CheckForNull; import static com.sun.jna.Pointer.NULL; import static hudson.util.jna.GNUCLibrary.LIBC; import static java.util.logging.Level.FINE; @@ -227,6 +229,22 @@ public abstract class ProcessTree implements Iterable, IProcessTree, */ public abstract void killRecursively() throws InterruptedException; + /** + * @return The first non-null {@link VetoCause} provided by a process killing veto extension for this OSProcess. + * null if no one objects killing the process. + */ + protected @CheckForNull VetoCause getVeto() { + for (ProcessKillingVeto vetoExtension : ProcessKillingVeto.all()) { + VetoCause cause = vetoExtension.vetoProcessKilling(this); + if (cause != null) { + if (LOGGER.isLoggable(FINEST)) + LOGGER.finest("Killing of pid " + getPid() + " vetoed by " + vetoExtension.getClass().getName() + ": " + cause.getMessage()); + return cause; + } + } + return null; + } + /** * Gets the command-line arguments of this process. * @@ -363,6 +381,8 @@ public abstract class ProcessTree implements Iterable, IProcessTree, } public void kill() throws InterruptedException { + if (getVeto() != null) + return; proc.destroy(); killByKiller(); } @@ -398,12 +418,18 @@ public abstract class ProcessTree implements Iterable, IProcessTree, } public void killRecursively() throws InterruptedException { + if (getVeto() != null) + return; + LOGGER.finer("Killing recursively "+getPid()); p.killRecursively(); killByKiller(); } public void kill() throws InterruptedException { + if (getVeto() != null) + return; + LOGGER.finer("Killing "+getPid()); p.kill(); killByKiller(); @@ -537,6 +563,8 @@ public abstract class ProcessTree implements Iterable, IProcessTree, * Tries to kill this process. */ public void kill() throws InterruptedException { + if (getVeto() != null) + return; try { int pid = getPid(); LOGGER.fine("Killing pid="+pid); @@ -557,6 +585,7 @@ public abstract class ProcessTree implements Iterable, IProcessTree, } public void killRecursively() throws InterruptedException { + // We kill individual processes of a tree, so handling vetoes inside #kill() is enough for UnixProcess es LOGGER.fine("Recursively killing pid="+getPid()); for (OSProcess p : getChildren()) p.killRecursively(); diff --git a/core/src/main/java/hudson/util/ProcessTreeKiller.java b/core/src/main/java/hudson/util/ProcessTreeKiller.java index 600b765bad40d6e70b867a4df34f3b33176ff497..def30b10b4cf176d7d4344f74ed81e528ebf807c 100644 --- a/core/src/main/java/hudson/util/ProcessTreeKiller.java +++ b/core/src/main/java/hudson/util/ProcessTreeKiller.java @@ -35,12 +35,14 @@ import java.util.Map; * @since 1.201 * @deprecated as of 1.315. Use {@link ProcessTree}. */ +@Deprecated public final class ProcessTreeKiller { /** * Short for {@code kill(proc,null)} * * @deprecated Use {@link OSProcess#killRecursively()} */ + @Deprecated public void kill(Process proc) throws InterruptedException { kill(proc,null); } @@ -73,6 +75,7 @@ public final class ProcessTreeKiller { * If non-null, search-and-destroy will be performed. * @deprecated Use {@link ProcessTree#killAll(Map)} and {@link OSProcess#killRecursively()} */ + @Deprecated public void kill(Process proc, Map modelEnvVars) throws InterruptedException { ProcessTree pt = ProcessTree.get(); if(proc!=null) @@ -85,6 +88,7 @@ public final class ProcessTreeKiller { * Short for {@code kill(null,modelEnvVars)} * @deprecated Use {@link ProcessTree#killAll(Map)} */ + @Deprecated public void kill(Map modelEnvVars) throws InterruptedException { kill(null,modelEnvVars); } @@ -95,6 +99,7 @@ public final class ProcessTreeKiller { * * @deprecated Use {@link EnvVars#createCookie()} */ + @Deprecated public static EnvVars createCookie() { return EnvVars.createCookie(); } diff --git a/core/src/main/java/hudson/util/QuotedStringTokenizer.java b/core/src/main/java/hudson/util/QuotedStringTokenizer.java index 248f1ac95402496b3874f8aa350e588cf8bdcf02..e33b15ccab968c6b7ee980010ef2de8dda94ee8a 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/ReflectionUtils.java b/core/src/main/java/hudson/util/ReflectionUtils.java index fb914acf531a6035917dda85117b34afc7e91c37..f491b59d8758bffb2f0aba72a306d42bb3283b92 100644 --- a/core/src/main/java/hudson/util/ReflectionUtils.java +++ b/core/src/main/java/hudson/util/ReflectionUtils.java @@ -28,6 +28,7 @@ import org.kohsuke.stapler.ClassDescriptor; import java.beans.PropertyDescriptor; import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -122,7 +123,7 @@ public class ReflectionUtils extends org.springframework.util.ReflectionUtils { } } - public static final class Parameter { + public static final class Parameter implements AnnotatedElement { private final MethodInfo parent; private final int index; @@ -180,6 +181,26 @@ public class ReflectionUtils extends org.springframework.util.ReflectionUtils { return names[index]; return null; } + + @Override + public boolean isAnnotationPresent(Class type) { + return annotation(type)!=null; + } + + @Override + public T getAnnotation(Class type) { + return annotation(type); + } + + @Override + public Annotation[] getAnnotations() { + return annotations(); + } + + @Override + public Annotation[] getDeclaredAnnotations() { + return annotations(); + } } /** diff --git a/core/src/main/java/hudson/util/RemotingDiagnostics.java b/core/src/main/java/hudson/util/RemotingDiagnostics.java index ba383e2081551bf455f0e3eec60c8d90a0b1cf68..8a2a51aa28608fc251652dbd90ef4f7715a26b16 100644 --- a/core/src/main/java/hudson/util/RemotingDiagnostics.java +++ b/core/src/main/java/hudson/util/RemotingDiagnostics.java @@ -34,15 +34,18 @@ import hudson.remoting.Future; import hudson.remoting.VirtualChannel; import hudson.security.AccessControlled; import jenkins.security.MasterToSlaveCallable; + import org.codehaus.groovy.control.CompilerConfiguration; import org.codehaus.groovy.control.customizers.ImportCustomizer; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.WebMethod; +import javax.annotation.Nonnull; import javax.management.JMException; import javax.management.MBeanServer; import javax.management.ObjectName; + import java.io.File; import java.io.IOException; import java.io.PrintWriter; @@ -104,7 +107,7 @@ public final class RemotingDiagnostics { /** * Executes Groovy script remotely. */ - public static String executeGroovy(String script, VirtualChannel channel) throws IOException, InterruptedException { + public static String executeGroovy(String script, @Nonnull VirtualChannel channel) throws IOException, InterruptedException { return channel.call(new Script(script)); } diff --git a/core/src/main/java/hudson/util/RobustCollectionConverter.java b/core/src/main/java/hudson/util/RobustCollectionConverter.java index 78dc2b2f2fdf3f85fcde05cea9271628969f4e57..d0903ff82b5c9cdc9e15d933bf51202a8ee2962b 100644 --- a/core/src/main/java/hudson/util/RobustCollectionConverter.java +++ b/core/src/main/java/hudson/util/RobustCollectionConverter.java @@ -36,6 +36,8 @@ import java.util.Collection; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; +import jenkins.util.xstream.CriticalXStreamException; + /** * {@link CollectionConverter} that ignores {@link XStreamException}. @@ -82,6 +84,8 @@ public class RobustCollectionConverter extends CollectionConverter { try { Object item = readItem(reader, context, collection); collection.add(item); + } catch (CriticalXStreamException e) { + throw e; } catch (XStreamException e) { RobustReflectionConverter.addErrorInContext(context, e); } catch (LinkageError e) { diff --git a/core/src/main/java/hudson/util/RobustMapConverter.java b/core/src/main/java/hudson/util/RobustMapConverter.java index 6a52bfb0162070778f3d92386ff3c07f4fde8824..48bdf94c79200449ed2edf16c42fe8e9aed58962 100644 --- a/core/src/main/java/hudson/util/RobustMapConverter.java +++ b/core/src/main/java/hudson/util/RobustMapConverter.java @@ -30,6 +30,7 @@ import com.thoughtworks.xstream.converters.collections.MapConverter; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.mapper.Mapper; import java.util.Map; +import jenkins.util.xstream.CriticalXStreamException; /** * Loads a {@link Map} while tolerating read errors on its keys and values. @@ -55,6 +56,8 @@ final class RobustMapConverter extends MapConverter { reader.moveDown(); try { return readItem(reader, context, map); + } catch (CriticalXStreamException x) { + throw x; } catch (XStreamException x) { RobustReflectionConverter.addErrorInContext(context, x); return ERROR; diff --git a/core/src/main/java/hudson/util/RobustReflectionConverter.java b/core/src/main/java/hudson/util/RobustReflectionConverter.java index 18909ba74f52d144e05b3ecd1938ca812a3f36ce..7270ee4e10484664f16f11c40d9464e73069721e 100644 --- a/core/src/main/java/hudson/util/RobustReflectionConverter.java +++ b/core/src/main/java/hudson/util/RobustReflectionConverter.java @@ -54,6 +54,7 @@ import java.util.Set; import static java.util.logging.Level.FINE; import java.util.logging.Logger; import javax.annotation.Nonnull; +import jenkins.util.xstream.CriticalXStreamException; /** * Custom {@link ReflectionConverter} that handle errors more gracefully. @@ -307,9 +308,11 @@ public class RobustReflectionConverter implements Converter { implicitCollectionsForCurrentObject = writeValueToImplicitCollection(context, value, implicitCollectionsForCurrentObject, result, fieldName); } } + } catch (CriticalXStreamException e) { + throw e; } catch (XStreamException e) { if (critical) { - throw e; + throw new CriticalXStreamException(e); } addErrorInContext(context, e); } catch (LinkageError e) { diff --git a/core/src/main/java/hudson/util/RunList.java b/core/src/main/java/hudson/util/RunList.java index 3b2c49ec43daf13188a2bf2e9dd20ab7d03b871e..f77232afcc687571c89eac3c398823a9a0c2acde 100644 --- a/core/src/main/java/hudson/util/RunList.java +++ b/core/src/main/java/hudson/util/RunList.java @@ -102,6 +102,7 @@ public class RunList extends AbstractList { * {@link RunList}, despite its name, should be really used as {@link Iterable}, not as {@link List}. */ @Override + @Deprecated public int size() { if (size==null) { int sz=0; @@ -119,6 +120,7 @@ public class RunList extends AbstractList { * {@link RunList}, despite its name, should be really used as {@link Iterable}, not as {@link List}. */ @Override + @Deprecated public R get(int index) { return Iterators.get(iterator(),index); } diff --git a/core/src/main/java/hudson/util/Secret.java b/core/src/main/java/hudson/util/Secret.java index 90144ed6afd81dae2b5dd38ff49583655a048dab..80be75b8ffa93d38cd099ab0d79773a374c2cb0d 100644 --- a/core/src/main/java/hudson/util/Secret.java +++ b/core/src/main/java/hudson/util/Secret.java @@ -73,6 +73,7 @@ public final class Secret implements Serializable { * Or if you really know what you are doing, use the {@link #getPlainText()} method. */ @Override + @Deprecated public String toString() { return value; } @@ -103,6 +104,7 @@ public final class Secret implements Serializable { * This is no longer the key we use to encrypt new information, but we still need this * to be able to decrypt what's already persisted. */ + @Deprecated /*package*/ static SecretKey getLegacyKey() throws GeneralSecurityException { String secret = SECRET; if(secret==null) return Jenkins.getInstance().getSecretKeyAsAES128(); diff --git a/core/src/main/java/hudson/util/SecretRewriter.java b/core/src/main/java/hudson/util/SecretRewriter.java index 37dc9fb2ede19377bdd3c3ddc6232d33734e2786..0ee05dc869371d895914d4c8403f09a755be5b6f 100644 --- a/core/src/main/java/hudson/util/SecretRewriter.java +++ b/core/src/main/java/hudson/util/SecretRewriter.java @@ -13,6 +13,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; +import java.nio.file.LinkOption; import java.security.GeneralSecurityException; import java.security.InvalidKeyException; import java.util.HashSet; @@ -145,7 +146,7 @@ public class SecretRewriter { private int rewriteRecursive(File dir, String relative, TaskListener listener) throws InvalidKeyException { String canonical; try { - canonical = dir.getCanonicalPath(); + canonical = dir.toPath().toRealPath(new LinkOption[0]).toString(); } catch (IOException e) { canonical = dir.getAbsolutePath(); // } diff --git a/core/src/main/java/hudson/util/SequentialExecutionQueue.java b/core/src/main/java/hudson/util/SequentialExecutionQueue.java index 31f10e049d9a672c5bbb5a747ac884e2e1863df3..a1cfa3ccba97beff3fbb220db77674ca2f65557a 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); diff --git a/core/src/main/java/hudson/util/StreamTaskListener.java b/core/src/main/java/hudson/util/StreamTaskListener.java index dd2f3b9d4b7703a55261a7f17575eb557dacce4f..4d6aea568d74bce91f31172e5150c0a866ebb2b6 100644 --- a/core/src/main/java/hudson/util/StreamTaskListener.java +++ b/core/src/main/java/hudson/util/StreamTaskListener.java @@ -65,6 +65,7 @@ public class StreamTaskListener extends AbstractTaskListener implements Serializ * the charset and output stream separately, so that this class can handle encoding correctly, * or use {@link #fromStdout()} or {@link #fromStderr()}. */ + @Deprecated public StreamTaskListener(PrintStream out) { this(out,null); } @@ -105,6 +106,7 @@ public class StreamTaskListener extends AbstractTaskListener implements Serializ * @deprecated as of 1.349 * Use {@link #NULL} */ + @Deprecated public StreamTaskListener() throws IOException { this(new NullStream()); } diff --git a/core/src/main/java/hudson/util/WriterOutputStream.java b/core/src/main/java/hudson/util/WriterOutputStream.java index 469b015db6969c10407cce5a0cd9632eeb7d2763..a73bbfa45f9ccb34ee8fbac8e47f9f6fbe7cb2a9 100644 --- a/core/src/main/java/hudson/util/WriterOutputStream.java +++ b/core/src/main/java/hudson/util/WriterOutputStream.java @@ -41,6 +41,7 @@ import java.nio.*; * @deprecated since 2008-05-28. * Use the one in stapler. */ +@Deprecated public class WriterOutputStream extends OutputStream { private final Writer writer; private final CharsetDecoder decoder; diff --git a/core/src/main/java/hudson/util/io/TarArchiver.java b/core/src/main/java/hudson/util/io/TarArchiver.java index 7e7a3dd4f0ec1a14981f98fc64a2cfdfbb40a87d..3411310fdbc4f8b9f943b9b730f13d6de5ac6ce7 100644 --- a/core/src/main/java/hudson/util/io/TarArchiver.java +++ b/core/src/main/java/hudson/util/io/TarArchiver.java @@ -25,18 +25,16 @@ package hudson.util.io; import hudson.Functions; -import hudson.org.apache.tools.tar.TarOutputStream; import hudson.os.PosixException; import hudson.util.FileVisitor; import hudson.util.IOUtils; -import org.apache.tools.tar.TarEntry; -import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; -import java.lang.reflect.Field; +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import static org.apache.tools.tar.TarConstants.LF_SYMLINK; @@ -47,24 +45,17 @@ import static org.apache.tools.tar.TarConstants.LF_SYMLINK; */ final class TarArchiver extends Archiver { private final byte[] buf = new byte[8192]; - private final TarOutputStream tar; + private final TarArchiveOutputStream tar; TarArchiver(OutputStream out) { - tar = new TarOutputStream(new BufferedOutputStream(out) { - // TarOutputStream uses TarBuffer internally, - // which flushes the stream for each block. this creates unnecessary - // data stream fragmentation, and flush request to a remote, which slows things down. - @Override - public void flush() throws IOException { - // so don't do anything in flush - } - }); - tar.setLongFileMode(TarOutputStream.LONGFILE_GNU); + tar = new TarArchiveOutputStream(out); + tar.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_STAR); + tar.setLongFileMode(TarArchiveOutputStream.LONGFILE_GNU); } @Override public void visitSymlink(File link, String target, String relativePath) throws IOException { - TarEntry e = new TarEntry(relativePath, LF_SYMLINK); + TarArchiveEntry e = new TarArchiveEntry(relativePath, LF_SYMLINK); try { int mode = IOUtils.mode(link); if (mode != -1) { @@ -73,16 +64,11 @@ final class TarArchiver extends Archiver { } catch (PosixException x) { // ignore } + + e.setLinkName(target); - try { - StringBuffer linkName = (StringBuffer) LINKNAME_FIELD.get(e); - linkName.setLength(0); - linkName.append(target); - } catch (IllegalAccessException x) { - throw new IOException("Failed to set linkName", x); - } - - tar.putNextEntry(e); + tar.putArchiveEntry(e); + tar.closeArchiveEntry(); entriesWritten++; } @@ -97,14 +83,14 @@ final class TarArchiver extends Archiver { if(file.isDirectory()) relativePath+='/'; - TarEntry te = new TarEntry(relativePath); + TarArchiveEntry te = new TarArchiveEntry(relativePath); int mode = IOUtils.mode(file); if (mode!=-1) te.setMode(mode); te.setModTime(file.lastModified()); if(!file.isDirectory()) te.setSize(file.length()); - tar.putNextEntry(te); + tar.putArchiveEntry(te); if (!file.isDirectory()) { FileInputStream in = new FileInputStream(file); @@ -117,25 +103,11 @@ final class TarArchiver extends Archiver { } } - tar.closeEntry(); + tar.closeArchiveEntry(); entriesWritten++; } public void close() throws IOException { tar.close(); } - - private static final Field LINKNAME_FIELD = getTarEntryLinkNameField(); - - private static Field getTarEntryLinkNameField() { - try { - Field f = TarEntry.class.getDeclaredField("linkName"); - f.setAccessible(true); - return f; - } catch (SecurityException e) { - throw new AssertionError(e); - } catch (NoSuchFieldException e) { - throw new AssertionError(e); - } - } } diff --git a/core/src/main/java/hudson/util/jna/DotNet.java b/core/src/main/java/hudson/util/jna/DotNet.java index 4011767b1941026670e09fd0b5ea5861c804559f..4d820149ca0afb78100f23e5fed90166d1017dab 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/hudson/util/jna/GNUCLibrary.java b/core/src/main/java/hudson/util/jna/GNUCLibrary.java index 28cdfabb5f6544c49dbe0dbf4d1223ad61581aeb..d555c8c4d18e1fa0ecc4a65c0ebb4b3870499a2d 100644 --- a/core/src/main/java/hudson/util/jna/GNUCLibrary.java +++ b/core/src/main/java/hudson/util/jna/GNUCLibrary.java @@ -30,7 +30,6 @@ import com.sun.jna.Native; import com.sun.jna.Memory; import com.sun.jna.NativeLong; import com.sun.jna.ptr.IntByReference; -import hudson.os.PosixAPI; import jnr.posix.POSIX; import org.jvnet.libpam.impl.CLibrary.passwd; diff --git a/core/src/main/java/hudson/util/spring/BeanBuilder.java b/core/src/main/java/hudson/util/spring/BeanBuilder.java index 5e4c51131bb19ef0967d67c9fc9db0d47fcccd0a..e1d1cba514ba6b29446ab3274cc1292113662045 100644 --- a/core/src/main/java/hudson/util/spring/BeanBuilder.java +++ b/core/src/main/java/hudson/util/spring/BeanBuilder.java @@ -327,7 +327,7 @@ public class BeanBuilder extends GroovyObjectSupport { public void loadBeans(Resource[] resources) throws IOException { Closure beans = new Closure(this){ @Override - public Object call(Object[] args) { + public Object call(Object... args) { return beans((Closure)args[0]); } }; diff --git a/core/src/main/java/hudson/util/xstream/ImmutableListConverter.java b/core/src/main/java/hudson/util/xstream/ImmutableListConverter.java index 18fd97ec98ada93a66984ac3ed62b68eceac8ed6..3734c472454fa4e4c8fab16d57104c02914c7196 100644 --- a/core/src/main/java/hudson/util/xstream/ImmutableListConverter.java +++ b/core/src/main/java/hudson/util/xstream/ImmutableListConverter.java @@ -39,6 +39,8 @@ import hudson.util.RobustReflectionConverter; import java.util.ArrayList; import java.util.List; +import jenkins.util.xstream.CriticalXStreamException; + /** * {@link ImmutableList} should convert like a list, instead of via serialization. * @@ -76,6 +78,8 @@ public class ImmutableListConverter extends CollectionConverter { try { Object item = readItem(reader, context, items); items.add(item); + } catch (CriticalXStreamException e) { + throw e; } catch (XStreamException e) { RobustReflectionConverter.addErrorInContext(context, e); } catch (LinkageError e) { diff --git a/core/src/main/java/hudson/util/xstream/MapperDelegate.java b/core/src/main/java/hudson/util/xstream/MapperDelegate.java index 143368717685c79b0f588badbf2275e492165771..f7eb78b5516e266aab9ede1a5731dd93e2e3abf2 100644 --- a/core/src/main/java/hudson/util/xstream/MapperDelegate.java +++ b/core/src/main/java/hudson/util/xstream/MapperDelegate.java @@ -90,6 +90,7 @@ public class MapperDelegate extends MapperWrapper { /** * @deprecated since 1.3, use {@link #getConverterFromItemType(String, Class, Class)} */ + @Deprecated public SingleValueConverter getConverterFromItemType(String fieldName, Class type) { return delegate.getConverterFromItemType(fieldName, type); } @@ -97,6 +98,7 @@ public class MapperDelegate extends MapperWrapper { /** * @deprecated since 1.3, use {@link #getConverterFromItemType(String, Class, Class)} */ + @Deprecated public SingleValueConverter getConverterFromItemType(Class type) { return delegate.getConverterFromItemType(type); } @@ -104,6 +106,7 @@ public class MapperDelegate extends MapperWrapper { /** * @deprecated since 1.3, use {@link #getConverterFromAttribute(Class, String, Class)} */ + @Deprecated public SingleValueConverter getConverterFromAttribute(String name) { return delegate.getConverterFromAttribute(name); } @@ -123,6 +126,7 @@ public class MapperDelegate extends MapperWrapper { /** * @deprecated since 1.3, use combination of {@link #serializedMember(Class, String)} and {@link #getConverterFromItemType(String, Class, Class)} */ + @Deprecated public String aliasForAttribute(Class definedIn, String fieldName) { return delegate.aliasForAttribute(definedIn, fieldName); } @@ -130,6 +134,7 @@ public class MapperDelegate extends MapperWrapper { /** * @deprecated since 1.3, use combination of {@link #realMember(Class, String)} and {@link #getConverterFromItemType(String, Class, Class)} */ + @Deprecated public String attributeForAlias(Class definedIn, String alias) { return delegate.attributeForAlias(definedIn, alias); } @@ -137,6 +142,7 @@ public class MapperDelegate extends MapperWrapper { /** * @deprecated since 1.3.1, use {@link #getConverterFromAttribute(Class, String, Class)} */ + @Deprecated public SingleValueConverter getConverterFromAttribute(Class type, String attribute) { return delegate.getConverterFromAttribute(type, attribute); } diff --git a/core/src/main/java/hudson/views/BuildButtonColumn.java b/core/src/main/java/hudson/views/BuildButtonColumn.java index c43b877b651ad93035d26ec50f32bcbe4f7679fa..83f314597994a184cbf8104f63f07c4168922d1a 100644 --- a/core/src/main/java/hudson/views/BuildButtonColumn.java +++ b/core/src/main/java/hudson/views/BuildButtonColumn.java @@ -31,7 +31,7 @@ public class BuildButtonColumn extends ListViewColumn { public BuildButtonColumn() { } - @Extension + @Extension(ordinal=DEFAULT_COLUMNS_ORDINAL_ACTIONS_START-1) public static class DescriptorImpl extends ListViewColumnDescriptor { @Override public String getDisplayName() { diff --git a/core/src/main/java/hudson/views/GlobalDefaultViewConfiguration.java b/core/src/main/java/hudson/views/GlobalDefaultViewConfiguration.java index 65e020a06c8d69e79aaee674b3c143e17daf51c3..934920b3e82e9dd09affbaf8c662ea8dc4144cef 100644 --- a/core/src/main/java/hudson/views/GlobalDefaultViewConfiguration.java +++ b/core/src/main/java/hudson/views/GlobalDefaultViewConfiguration.java @@ -24,9 +24,6 @@ package hudson.views; import hudson.Extension; -import hudson.markup.MarkupFormatter; -import hudson.security.AuthorizationStrategy; -import hudson.security.SecurityRealm; import jenkins.model.GlobalConfiguration; import jenkins.model.Jenkins; import net.sf.json.JSONObject; diff --git a/core/src/main/java/hudson/views/JobColumn.java b/core/src/main/java/hudson/views/JobColumn.java index 5c09560abdb996fabea30a828553cc628714c802..d34b49415ad3d65a127c7ce3a7e57b476ad68f7d 100644 --- a/core/src/main/java/hudson/views/JobColumn.java +++ b/core/src/main/java/hudson/views/JobColumn.java @@ -35,7 +35,8 @@ public class JobColumn extends ListViewColumn { public JobColumn() { } - @Extension + // put this in the middle of icons and properties + @Extension(ordinal=DEFAULT_COLUMNS_ORDINAL_ICON_END+1) public static class DescriptorImpl extends ListViewColumnDescriptor { @Override public String getDisplayName() { diff --git a/core/src/main/java/hudson/views/LastDurationColumn.java b/core/src/main/java/hudson/views/LastDurationColumn.java index 873d051ae0031262de94c94977fe361c1bdf9f5d..7379d7b6a321251ab6e4164531cf06d7af3f913c 100644 --- a/core/src/main/java/hudson/views/LastDurationColumn.java +++ b/core/src/main/java/hudson/views/LastDurationColumn.java @@ -31,7 +31,7 @@ public class LastDurationColumn extends ListViewColumn { public LastDurationColumn() { } - @Extension + @Extension(ordinal=DEFAULT_COLUMNS_ORDINAL_PROPERTIES_START-4) public static class DescriptorImpl extends ListViewColumnDescriptor { @Override public String getDisplayName() { diff --git a/core/src/main/java/hudson/views/LastFailureColumn.java b/core/src/main/java/hudson/views/LastFailureColumn.java index b16fd4839949a37c83de2d3c6197d06b447623f8..28276df9e130e167e8c663242c1695f493488848 100644 --- a/core/src/main/java/hudson/views/LastFailureColumn.java +++ b/core/src/main/java/hudson/views/LastFailureColumn.java @@ -31,7 +31,7 @@ public class LastFailureColumn extends ListViewColumn { public LastFailureColumn() { } - @Extension + @Extension(ordinal=DEFAULT_COLUMNS_ORDINAL_PROPERTIES_START-2) public static class DescriptorImpl extends ListViewColumnDescriptor { @Override public String getDisplayName() { diff --git a/core/src/main/java/hudson/views/LastStableColumn.java b/core/src/main/java/hudson/views/LastStableColumn.java index e2fd9fbbe2885e5535e30ce5ce5ac40e204d8f30..408c70b726a5d3acb544c81bf0657647a8042d8e 100644 --- a/core/src/main/java/hudson/views/LastStableColumn.java +++ b/core/src/main/java/hudson/views/LastStableColumn.java @@ -31,7 +31,7 @@ public class LastStableColumn extends ListViewColumn { public LastStableColumn() { } - @Extension + @Extension(ordinal=DEFAULT_COLUMNS_ORDINAL_PROPERTIES_START-3) public static class DescriptorImpl extends ListViewColumnDescriptor { @Override public String getDisplayName() { diff --git a/core/src/main/java/hudson/views/LastSuccessColumn.java b/core/src/main/java/hudson/views/LastSuccessColumn.java index e87d72735ee95319e82d365c5fd3a51d86dbb122..c0232075e564c2c8241250bdb1cbb2af9d87a630 100644 --- a/core/src/main/java/hudson/views/LastSuccessColumn.java +++ b/core/src/main/java/hudson/views/LastSuccessColumn.java @@ -31,7 +31,7 @@ public class LastSuccessColumn extends ListViewColumn { public LastSuccessColumn() { } - @Extension + @Extension(ordinal=DEFAULT_COLUMNS_ORDINAL_PROPERTIES_START-1) public static class DescriptorImpl extends ListViewColumnDescriptor { @Override public String getDisplayName() { diff --git a/core/src/main/java/hudson/views/ListViewColumn.java b/core/src/main/java/hudson/views/ListViewColumn.java index 2e6c4b98804fe27425a88ffd0de70af3cd012395..4fd010d8616e03f53d064c9f5da2ae5a5ebee258 100644 --- a/core/src/main/java/hudson/views/ListViewColumn.java +++ b/core/src/main/java/hudson/views/ListViewColumn.java @@ -38,7 +38,6 @@ import hudson.util.DescriptorList; import org.kohsuke.stapler.export.Exported; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -94,6 +93,7 @@ public abstract class ListViewColumn implements ExtensionPoint, Describable LIST = new DescriptorList(ListViewColumn.class); /** @@ -104,6 +104,7 @@ public abstract class ListViewColumn implements ExtensionPoint, Describable r = new ArrayList(); - DescriptorExtensionList> all = ListViewColumn.all(); - ArrayList> left = new ArrayList>(all); - - for (Class d: DEFAULT_COLUMNS) { - Descriptor des = all.find(d); - if (des != null) { - try { - r.add(des.newInstance(null, null)); - left.remove(des); - } catch (FormException e) { - LOGGER.log(Level.WARNING, "Failed to instantiate "+des.clazz,e); - } - } - } - for (Descriptor d : left) + + for (Descriptor d : ListViewColumn.all()) try { if (d instanceof ListViewColumnDescriptor) { ListViewColumnDescriptor ld = (ListViewColumnDescriptor) d; @@ -155,18 +143,22 @@ public abstract class ListViewColumn implements ExtensionPoint, Describable> DEFAULT_COLUMNS = Arrays.asList( - StatusColumn.class, - WeatherColumn.class, - JobColumn.class, - LastSuccessColumn.class, - LastFailureColumn.class, - LastDurationColumn.class, - BuildButtonColumn.class - ); - private static final Logger LOGGER = Logger.getLogger(ListViewColumn.class.getName()); + + /* + Standard ordinal positions for built-in ListViewColumns. + + There are icons at the very left that are generally used to show status, + then item name that comes in at the very end of that icon set. + + Then the section of "properties" that show various properties of the item in text. + + Finally, the section of action icons at the end. + */ + public static final double DEFAULT_COLUMNS_ORDINAL_ICON_START = 60; + public static final double DEFAULT_COLUMNS_ORDINAL_ICON_END = 50; + public static final double DEFAULT_COLUMNS_ORDINAL_PROPERTIES_START = 40; + public static final double DEFAULT_COLUMNS_ORDINAL_PROPERTIES_END = 30; + public static final double DEFAULT_COLUMNS_ORDINAL_ACTIONS_START = 20; + public static final double DEFAULT_COLUMNS_ORDINAL_ACTIONS_END = 10; } diff --git a/core/src/main/java/hudson/views/StatusColumn.java b/core/src/main/java/hudson/views/StatusColumn.java index 9d67ae1536a1b5adaca493594387716d394619ba..47f82643d2c87e6767494a20b548b2b6e54ce164 100644 --- a/core/src/main/java/hudson/views/StatusColumn.java +++ b/core/src/main/java/hudson/views/StatusColumn.java @@ -37,7 +37,7 @@ public class StatusColumn extends ListViewColumn { public StatusColumn() { } - @Extension + @Extension(ordinal=DEFAULT_COLUMNS_ORDINAL_ICON_START-1) public static class DescriptorImpl extends ListViewColumnDescriptor { @Override public String getDisplayName() { diff --git a/core/src/main/java/hudson/views/WeatherColumn.java b/core/src/main/java/hudson/views/WeatherColumn.java index a0832686cde476f7347f1e7def514f2384bad7bf..1e8436a08af391300457616d2397521674d4dc0c 100644 --- a/core/src/main/java/hudson/views/WeatherColumn.java +++ b/core/src/main/java/hudson/views/WeatherColumn.java @@ -32,7 +32,7 @@ public class WeatherColumn extends ListViewColumn { public WeatherColumn() { } - @Extension + @Extension(ordinal=DEFAULT_COLUMNS_ORDINAL_ICON_START-2) public static class DescriptorImpl extends ListViewColumnDescriptor { @Override public String getDisplayName() { diff --git a/core/src/main/java/hudson/widgets/BuildHistoryWidget.java b/core/src/main/java/hudson/widgets/BuildHistoryWidget.java index ec80e138a828514b26faf083d32148e7b4611a38..4b963d7d6741af41436180a38feecbd0554b80d2 100644 --- a/core/src/main/java/hudson/widgets/BuildHistoryWidget.java +++ b/core/src/main/java/hudson/widgets/BuildHistoryWidget.java @@ -26,7 +26,10 @@ package hudson.widgets; 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; import java.util.LinkedList; import java.util.List; @@ -60,11 +63,25 @@ public class BuildHistoryWidget extends HistoryWidget { */ public List getQueuedItems() { LinkedList list = new LinkedList(); - for (Item item : Jenkins.getInstance().getQueue().getApproximateItemsQuickly()) { + for (Item item : Jenkins.getInstance().getQueue().getItems()) { if (item.task == owner) { list.addFirst(item); } } return list; } + + @Override + public HistoryPageFilter getHistoryPageFilter() { + 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/HistoryWidget.java b/core/src/main/java/hudson/widgets/HistoryWidget.java index a2ec051839581c236dd5a277984713ae21f5a8c2..0059680ef5723885784a852dd3d7ce25fcafc038 100644 --- a/core/src/main/java/hudson/widgets/HistoryWidget.java +++ b/core/src/main/java/hudson/widgets/HistoryWidget.java @@ -26,22 +26,23 @@ package hudson.widgets; import hudson.Functions; import hudson.model.ModelObject; import hudson.model.Run; -import hudson.util.Iterators; +import jenkins.widgets.HistoryPageEntry; +import jenkins.widgets.HistoryPageFilter; +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; +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. * @@ -73,6 +74,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 +88,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 +114,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 +128,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; + } + + /** + * Get a {@link jenkins.widgets.HistoryPageFilter} for rendering a page of queue items. + */ + public HistoryPageFilter getHistoryPageFilter() { + 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 +201,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; - } + } 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))); + 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; + baseList = items; - rsp.setHeader("n",nn); - firstTransientBuildKey = nn; // all builds >= nn should be marked transient + rsp.setHeader("n",nn); + firstTransientBuildKey = nn; // all builds >= nn should be marked transient + } - req.getView(this,"ajaxBuildHistory.jelly").forward(req,rsp); + HistoryPageFilter page = getHistoryPageFilter(); + 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 +261,20 @@ public class HistoryWidget extends Widget { boolean isBuilding(T record); String getNextKey(String key); } + + 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; + } + try { + return new Long(paramVal); + } catch (NumberFormatException nfe) { + return null; + } + } } diff --git a/core/src/main/java/jenkins/AgentProtocol.java b/core/src/main/java/jenkins/AgentProtocol.java index 6a9adaff3ca35a9b5937794eb9a29fd78ef5c746..667f881cde13b604c043ddeb8b08c9ee3f82181d 100644 --- a/core/src/main/java/jenkins/AgentProtocol.java +++ b/core/src/main/java/jenkins/AgentProtocol.java @@ -4,8 +4,6 @@ import hudson.Extension; import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.TcpSlaveAgentListener; -import hudson.model.AperiodicWork; -import jenkins.model.Jenkins; import java.io.IOException; import java.net.Socket; @@ -40,7 +38,7 @@ public abstract class AgentProtocol implements ExtensionPoint { public abstract void handle(Socket socket) throws IOException, InterruptedException; /** - * Returns all the registered {@link AperiodicWork}s. + * Returns all the registered {@link AgentProtocol}s. */ public static ExtensionList all() { return ExtensionList.lookup(AgentProtocol.class); diff --git a/core/src/main/java/jenkins/ExtensionFilter.java b/core/src/main/java/jenkins/ExtensionFilter.java index 6b20d805e25f87b62a4901f3b34ccb9b292c4561..1f3ec5c8865f0bc0873f8c50f8315950f4a813e1 100644 --- a/core/src/main/java/jenkins/ExtensionFilter.java +++ b/core/src/main/java/jenkins/ExtensionFilter.java @@ -31,7 +31,6 @@ import hudson.model.AdministrativeMonitor; import hudson.model.Describable; import hudson.model.Descriptor; import hudson.model.DescriptorVisibilityFilter; -import jenkins.model.Jenkins; /** * Filters out {@link ExtensionComponent}s discovered by {@link ExtensionFinder}s, diff --git a/core/src/main/java/jenkins/management/AsynchronousAdministrativeMonitor.java b/core/src/main/java/jenkins/management/AsynchronousAdministrativeMonitor.java index f5a0da69a27b4b6bb20c68a21a3851468bd3d981..50d4e6cbebd205c6c30b58cc16d6ea41e586f0f5 100644 --- a/core/src/main/java/jenkins/management/AsynchronousAdministrativeMonitor.java +++ b/core/src/main/java/jenkins/management/AsynchronousAdministrativeMonitor.java @@ -8,7 +8,6 @@ import hudson.security.ACL; import hudson.util.StreamTaskListener; import jenkins.model.Jenkins; import jenkins.security.RekeySecretAdminMonitor; -import org.apache.commons.io.output.NullOutputStream; import java.io.File; import java.io.IOException; @@ -115,10 +114,10 @@ public abstract class AsynchronousAdministrativeMonitor extends AdministrativeMo } } } - + /** - * Runs the monitor and encapsulates all errors within. - * @since TODO: define a version + * Runs the monitor and encapsulates all errors within. + * @since 1.590 */ private void doRun(@Nonnull TaskListener listener) { try { diff --git a/core/src/main/java/jenkins/management/NodesLink.java b/core/src/main/java/jenkins/management/NodesLink.java index 5bff1b525308a8de6e623cef1440cccc4b54f9a2..11ea4698570997af6e601eb5c38e7e799630ca7d 100644 --- a/core/src/main/java/jenkins/management/NodesLink.java +++ b/core/src/main/java/jenkins/management/NodesLink.java @@ -27,7 +27,6 @@ package jenkins.management; import hudson.Extension; import hudson.model.ManagementLink; import jenkins.management.Messages; -import jenkins.model.Jenkins; /** * @author Nicolas De Loof diff --git a/core/src/main/java/jenkins/model/ArtifactManager.java b/core/src/main/java/jenkins/model/ArtifactManager.java index bb5fde97e2fe250e1f99396bea55b1b9241f95fb..eeca67143c5d3debbfaec7bcf9f053d4963acea7 100644 --- a/core/src/main/java/jenkins/model/ArtifactManager.java +++ b/core/src/main/java/jenkins/model/ArtifactManager.java @@ -26,7 +26,6 @@ package jenkins.model; import hudson.FilePath; import hudson.Launcher; -import hudson.model.AbstractBuild; import hudson.model.BuildListener; import hudson.model.Run; import hudson.model.TaskListener; diff --git a/test/src/main/java/org/jvnet/hudson/test/ExtractChangeLogSet.java b/core/src/main/java/jenkins/model/BlockedBecauseOfBuildInProgress.java similarity index 53% rename from test/src/main/java/org/jvnet/hudson/test/ExtractChangeLogSet.java rename to core/src/main/java/jenkins/model/BlockedBecauseOfBuildInProgress.java index 5e36aaeb243eb866c002c0d62f1f72f8eb4c564f..f55537c2ca5662407995935d4690457f36687aa3 100644 --- a/test/src/main/java/org/jvnet/hudson/test/ExtractChangeLogSet.java +++ b/core/src/main/java/jenkins/model/BlockedBecauseOfBuildInProgress.java @@ -1,7 +1,7 @@ /* * The MIT License * - * Copyright (c) 2004-2009, Sun Microsystems, Inc. + * 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 @@ -21,37 +21,35 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.jvnet.hudson.test; -import hudson.model.AbstractBuild; -import hudson.scm.ChangeLogSet; - -import java.util.List; -import java.util.Collections; -import java.util.Iterator; +package jenkins.model; +import hudson.model.Executor; +import hudson.model.Job; +import hudson.model.Run; +import hudson.model.queue.CauseOfBlockage; /** - * @author Andrew Bayer + * 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 1.624 */ -public class ExtractChangeLogSet extends ChangeLogSet { - private List changeLogs = null; +public class BlockedBecauseOfBuildInProgress extends CauseOfBlockage { + + private final Run build; - public ExtractChangeLogSet(AbstractBuild build, List changeLogs) { - super(build); - for (ExtractChangeLogParser.ExtractChangeLogEntry entry : changeLogs) { - entry.setParent(this); - } - this.changeLogs = Collections.unmodifiableList(changeLogs); + public BlockedBecauseOfBuildInProgress(Run build) { + this.build = build; } - @Override - public boolean isEmptySet() { - return changeLogs.isEmpty(); - } - - public Iterator iterator() { - return changeLogs.iterator(); + @Override public String getShortDescription() { + Executor e = build.getExecutor(); + String eta = ""; + if (e != null) { + eta = Messages.BlockedBecauseOfBuildInProgress_ETA(e.getEstimatedRemainingTime()); + } + int lbn = build.getNumber(); + return Messages.BlockedBecauseOfBuildInProgress_shortDescription(lbn, eta); } } diff --git a/core/src/main/java/jenkins/model/BuildDiscarder.java b/core/src/main/java/jenkins/model/BuildDiscarder.java index 72e6552aa9da40251d2557c301b0927bf2b97abf..8e4c3abadc57c506a42e8957f59151223106fdf2 100644 --- a/core/src/main/java/jenkins/model/BuildDiscarder.java +++ b/core/src/main/java/jenkins/model/BuildDiscarder.java @@ -9,7 +9,6 @@ import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.mapper.Mapper; import hudson.ExtensionPoint; import hudson.model.AbstractDescribableImpl; -import hudson.model.AbstractProject; import hudson.model.Job; import hudson.model.Run; import hudson.tasks.LogRotator; diff --git a/test/src/main/java/org/jvnet/hudson/test/SleepBuilder.java b/core/src/main/java/jenkins/model/BuildDiscarderProperty.java similarity index 50% rename from test/src/main/java/org/jvnet/hudson/test/SleepBuilder.java rename to core/src/main/java/jenkins/model/BuildDiscarderProperty.java index 9d2176aedecc8c1995b0f44d1274360b26236edb..9c9be1d31228ca1d2074ffcbb5a80d6349ff3c3a 100644 --- a/test/src/main/java/org/jvnet/hudson/test/SleepBuilder.java +++ b/core/src/main/java/jenkins/model/BuildDiscarderProperty.java @@ -1,18 +1,18 @@ /* * The MIT License - * - * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * + * 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 @@ -21,41 +21,59 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -package org.jvnet.hudson.test; -import hudson.Launcher; +package jenkins.model; + import hudson.Extension; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; import hudson.model.Descriptor; -import hudson.tasks.Builder; +import hudson.model.DescriptorVisibilityFilter; +import hudson.model.Items; +import hudson.model.Job; import org.kohsuke.stapler.DataBoundConstructor; -import java.io.IOException; - /** - * {@link Builder} that just sleeps for the specified amount of milli-seconds. - * - * @author Kohsuke Kawaguchi + * Defines a {@link BuildDiscarder}. + * @since 1.637 */ -public class SleepBuilder extends Builder { - public final long time; +public class BuildDiscarderProperty extends OptionalJobProperty> { + + private final BuildDiscarder strategy; @DataBoundConstructor - public SleepBuilder(long time) { - this.time = time; + public BuildDiscarderProperty(BuildDiscarder strategy) { + this.strategy = strategy; } - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - listener.getLogger().println("Sleeping "+time+"ms"); - Thread.sleep(time); - return true; + public BuildDiscarder getStrategy() { + return strategy; } @Extension - public static final class DescriptorImpl extends Descriptor { + public static class DescriptorImpl extends OptionalJobPropertyDescriptor { + + @Override public String getDisplayName() { - return "Sleep"; + return Messages.BuildDiscarderProperty_displayName(); + } + + static { + Items.XSTREAM2.addCompatibilityAlias("org.jenkinsci.plugins.workflow.job.properties.BuildDiscarderProperty", BuildDiscarderProperty.class); + } + + } + + @Extension + public static class ConditionallyHidden extends DescriptorVisibilityFilter { + + @SuppressWarnings("rawtypes") + @Override + public boolean filter(Object context, Descriptor descriptor) { + if (descriptor instanceof DescriptorImpl && context instanceof Job) { + return ((Job) context).supportsLogRotator(); + } + return true; } + } + } diff --git a/core/src/main/java/jenkins/model/CauseOfInterruption.java b/core/src/main/java/jenkins/model/CauseOfInterruption.java index d733ffe33eabcb6480b679ecde34a0beaebad5c2..90da391dbcb43cfba9f73864fd6c1eea93d33d04 100644 --- a/core/src/main/java/jenkins/model/CauseOfInterruption.java +++ b/core/src/main/java/jenkins/model/CauseOfInterruption.java @@ -25,7 +25,6 @@ package jenkins.model; import hudson.console.ModelHyperlinkNote; import hudson.model.Executor; -import hudson.model.Result; import hudson.model.TaskListener; import hudson.model.User; import org.kohsuke.stapler.export.Exported; @@ -70,7 +69,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 +111,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/java/jenkins/model/DependencyDeclarer.java b/core/src/main/java/jenkins/model/DependencyDeclarer.java index a6cb2c52c61ee54787d5101ade9927a44caf61a7..5d53d472685b7e546e74db064a477f66c5e2fbe4 100644 --- a/core/src/main/java/jenkins/model/DependencyDeclarer.java +++ b/core/src/main/java/jenkins/model/DependencyDeclarer.java @@ -29,7 +29,6 @@ import hudson.tasks.BuildWrapper; import hudson.tasks.Builder; import hudson.tasks.Publisher; import hudson.triggers.Trigger; -import hudson.util.DescribableList; /** * Marker interface for project-associated objects that can participate diff --git a/core/src/main/java/jenkins/model/DirectlyModifiableTopLevelItemGroup.java b/core/src/main/java/jenkins/model/DirectlyModifiableTopLevelItemGroup.java index f08d3f3faf0249883baaa70c51631a240e700460..1d80e5d7b068460c2590cd9f9cc89cc7c2bfb653 100644 --- a/core/src/main/java/jenkins/model/DirectlyModifiableTopLevelItemGroup.java +++ b/core/src/main/java/jenkins/model/DirectlyModifiableTopLevelItemGroup.java @@ -24,9 +24,7 @@ package jenkins.model; -import hudson.model.Item; import hudson.model.TopLevelItem; -import hudson.model.listeners.ItemListener; import java.io.IOException; /** diff --git a/core/src/main/java/jenkins/model/DownloadSettings.java b/core/src/main/java/jenkins/model/DownloadSettings.java index 0cf410c28b662aea2ff5bb44e8a961c92dd630b1..e16898ab86dc83dc6816f31c744f860c91376e8c 100644 --- a/core/src/main/java/jenkins/model/DownloadSettings.java +++ b/core/src/main/java/jenkins/model/DownloadSettings.java @@ -25,6 +25,8 @@ package jenkins.model; import hudson.Extension; +import hudson.Main; +import hudson.model.AdministrativeMonitor; import hudson.model.AsyncPeriodicWork; import hudson.model.DownloadService; import hudson.model.TaskListener; @@ -32,6 +34,7 @@ import hudson.model.UpdateSite; import hudson.util.FormValidation; import java.io.IOException; import net.sf.json.JSONObject; +import org.acegisecurity.AccessDeniedException; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.HttpResponse; @@ -49,7 +52,7 @@ import org.kohsuke.stapler.StaplerRequest; return Jenkins.getInstance().getInjector().getInstance(DownloadSettings.class); } - private boolean useBrowser = true; // historical default, not necessarily recommended + private boolean useBrowser = false; public DownloadSettings() { load(); @@ -69,6 +72,21 @@ import org.kohsuke.stapler.StaplerRequest; save(); } + @Override public GlobalConfigurationCategory getCategory() { + return GlobalConfigurationCategory.get(GlobalConfigurationCategory.Security.class); + } + + public static boolean usePostBack() { + return get().isUseBrowser() && Jenkins.getInstance().hasPermission(Jenkins.ADMINISTER); + } + + public static void checkPostBackAccess() throws AccessDeniedException { + if (!get().isUseBrowser()) { + throw new AccessDeniedException("browser-based download disabled"); + } + Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER); + } + @Extension public static final class DailyCheck extends AsyncPeriodicWork { public DailyCheck() { @@ -79,10 +97,24 @@ import org.kohsuke.stapler.StaplerRequest; return DAY; } + @Override public long getInitialDelay() { + return Main.isUnitTest ? DAY : 0; + } + @Override protected void execute(TaskListener listener) throws IOException, InterruptedException { if (get().isUseBrowser()) { return; } + boolean due = false; + for (UpdateSite site : Jenkins.getInstance().getUpdateCenter().getSites()) { + if (site.isDue()) { + due = true; + break; + } + } + if (!due) { + return; + } HttpResponse rsp = Jenkins.getInstance().getPluginManager().doCheckUpdatesServer(); if (rsp instanceof FormValidation) { listener.error(((FormValidation) rsp).renderHtml()); @@ -91,4 +123,12 @@ import org.kohsuke.stapler.StaplerRequest; } + @Extension public static final class Warning extends AdministrativeMonitor { + + @Override public boolean isActivated() { + return DownloadSettings.get().isUseBrowser(); + } + + } + } diff --git a/core/src/main/java/jenkins/model/FingerprintFacet.java b/core/src/main/java/jenkins/model/FingerprintFacet.java index 9af1843b17bc718a0beddfeb8c17e960efd2bb98..83dd8af79b2a8fcb84e613cdea280db5db27215e 100644 --- a/core/src/main/java/jenkins/model/FingerprintFacet.java +++ b/core/src/main/java/jenkins/model/FingerprintFacet.java @@ -30,6 +30,7 @@ import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; import java.util.List; +import javax.annotation.Nonnull; /** * Plugin-specific additions to fingerprint information. @@ -65,9 +66,9 @@ public abstract class FingerprintFacet implements ExtensionPoint { * @param fingerprint * {@link Fingerprint} object to which this facet is going to be added to. * @param timestamp - * Timestamp when the use happened. + * Timestamp when the use happened (when the facet has been created). */ - protected FingerprintFacet(Fingerprint fingerprint, long timestamp) { + protected FingerprintFacet(@Nonnull Fingerprint fingerprint, long timestamp) { assert fingerprint!=null; this.fingerprint = fingerprint; this.timestamp = timestamp; @@ -79,18 +80,20 @@ public abstract class FingerprintFacet implements ExtensionPoint { * @return * always non-null. */ - public Fingerprint getFingerprint() { + public @Nonnull Fingerprint getFingerprint() { return fingerprint; } /** * Create action objects to be contributed to the owner {@link Fingerprint}. - * + * By default, creates no actions. *

* {@link Fingerprint} calls this method for every {@link FingerprintFacet} that * it owns when the rendering is requested. + * @param result Output list */ public void createActions(List result) { + // Create no actions by default } /** diff --git a/core/src/main/java/jenkins/model/GlobalConfiguration.java b/core/src/main/java/jenkins/model/GlobalConfiguration.java index 92eabc4ea7b7f52638204f01a4ae268f39d0cfe8..15cc69f831c343f51187b8503e179ab03e630180 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 imp /** * {@inheritDoc} */ + @Override @Nonnull public String keyFor(@Nonnull String id) { return id.toLowerCase(Locale.ENGLISH); @@ -288,6 +289,7 @@ public abstract class IdStrategy extends AbstractDescribableImpl imp /** * {@inheritDoc} */ + @Override @Nonnull public String keyFor(@Nonnull String id) { return id; @@ -348,6 +350,7 @@ public abstract class IdStrategy extends AbstractDescribableImpl imp /** * {@inheritDoc} */ + @Override @Nonnull public String keyFor(@Nonnull String id) { int index = id.lastIndexOf('@'); // The @ can be used in local-part if quoted correctly diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index 34cbe9b7588d16b688ef917991f373b0ad16bab2..7fcf37c7ca3bad4991ec1e9649c1064075e1fd00 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; @@ -146,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; @@ -252,7 +252,6 @@ import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import java.io.File; -import java.io.FileFilter; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; @@ -316,7 +315,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve public transient final Lookup lookup = new Lookup(); /** - * We update this field to the current version of Hudson whenever we save {@code config.xml}. + * We update this field to the current version of Jenkins whenever we save {@code config.xml}. * This can be used to detect when an upgrade happens from one version to next. * *

@@ -351,7 +350,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve /** * Controls how the * authorization - * is handled in Hudson. + * is handled in Jenkins. *

* This ultimately controls who has access to what. * @@ -362,7 +361,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve /** * Controls a part of the * authentication - * handling in Hudson. + * handling in Jenkins. *

* Intuitively, this corresponds to the user database. * @@ -432,7 +431,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve private transient volatile boolean isQuietingDown; private transient volatile boolean terminating; - private List jdks = new ArrayList(); + private volatile List jdks = new ArrayList(); private transient volatile DependencyGraph dependencyGraph; private final transient AtomicBoolean dependencyGraphDirty = new AtomicBoolean(); @@ -466,7 +465,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve }; /** - * {@link Computer}s in this Hudson system. Read-only. + * {@link Computer}s in this Jenkins system. Read-only. */ protected transient final Map computers = new CopyOnWriteMap.Hash(); @@ -498,17 +497,18 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } /** - * Set of installed cluster nodes. - *

- * We use this field with copy-on-write semantics. - * This field has mutable list (to keep the serialization look clean), - * but it shall never be modified. Only new completely populated slave - * list can be set here. - *

- * The field name should be really {@code nodes}, but again the backward compatibility - * prevents us from renaming. + * Legacy store of the set of installed cluster nodes. + * @deprecated in favour of {@link Nodes} + */ + @Deprecated + protected transient volatile NodeList slaves; + + /** + * The holder of the set of installed cluster nodes. + * + * @since 1.607 */ - protected volatile NodeList slaves; + private transient final Nodes nodes = new Nodes(this); /** * Quiet period. @@ -551,6 +551,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; @@ -564,7 +566,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * TCP slave agent port. * 0 for random, -1 to disable. */ - private int slaveAgentPort =0; + private int slaveAgentPort = Integer.getInteger(Jenkins.class.getName()+".slaveAgentPort",0); /** * Whitespace-separated labels assigned to the master as a {@link Node}. @@ -614,6 +616,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * slaves and free-roaming jobs in the queue. */ @Restricted(NoExternalUse.class) + @Deprecated public transient final NodeProvisioner overallNodeProvisioner = unlabeledNodeProvisioner; @@ -643,7 +646,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve public transient final List administrativeMonitors = getExtensionList(AdministrativeMonitor.class); /** - * Widgets on Hudson. + * Widgets on Jenkins. */ private transient final List widgets = getExtensionList(Widget.class); @@ -819,16 +822,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 { @@ -868,6 +862,9 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve System.currentTimeMillis()-itemListenerStart,l.getClass().getName())); } + // All plugins are loaded. Now we can figure out who depends on who. + resolveDependantPlugins(); + if (LOG_STARTUP_PERFORMANCE) LOGGER.info(String.format("Took %dms for complete Jenkins startup", System.currentTimeMillis()-start)); @@ -876,11 +873,35 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } } + private void resolveDependantPlugins() throws InterruptedException, ReactorException, IOException { + TaskGraphBuilder graphBuilder = new TaskGraphBuilder(); + + graphBuilder.add("Resolving Dependant Plugins Graph", new Executable() { + @Override + public void run(Reactor reactor) throws Exception { + pluginManager.resolveDependantPlugins(); + } + }); + + executeReactor(null, graphBuilder); + } + + /** + * Maintains backwards compatibility. Invoked by XStream when this object is de-serialized. + */ + @SuppressWarnings({"unused"}) + private Object readResolve() { + if (jdks == null) { + jdks = new ArrayList<>(); + } + return this; + } + /** * Executes a reactor. * * @param is - * If non-null, this can be consulted for ignoring some tasks. Only used during the initialization of Hudson. + * If non-null, this can be consulted for ignoring some tasks. Only used during the initialization of Jenkins. */ private void executeReactor(final InitStrategy is, TaskBuilder... builders) throws IOException, InterruptedException, ReactorException { Reactor reactor = new Reactor(builders) { @@ -944,17 +965,32 @@ 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) - tcpSlaveAgentListener = new TcpSlaveAgentListener(slaveAgentPort); - } else { - if(tcpSlaveAgentListener.configuredPort!=slaveAgentPort) { + private void launchTcpSlaveAgentListener() throws IOException { + synchronized(tcpSlaveAgentListenerLock) { + // shutdown previous agent if the port has changed + if (tcpSlaveAgentListener != null && tcpSlaveAgentListener.configuredPort != slaveAgentPort) { tcpSlaveAgentListener.shutdown(); tcpSlaveAgentListener = null; - if(slaveAgentPort!=-1) + } + 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); + } } } } @@ -1004,6 +1040,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * Does this {@link View} has any associated user information recorded? * @deprecated Potentially very expensive call; do not use from Jelly views. */ + @Deprecated public boolean hasPeople() { return View.People.isApplicable(items.values()); } @@ -1021,6 +1058,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * Due to the past security advisory, this value should not be used any more to protect sensitive information. * See {@link ConfidentialStore} and {@link ConfidentialKey} for how to store secrets. */ + @Deprecated public String getSecretKey() { return secretKey; } @@ -1031,6 +1069,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * @deprecated * See {@link #getSecretKey()}. */ + @Deprecated public SecretKey getSecretKeyAsAES128() { return Util.toAes128Key(secretKey); } @@ -1113,6 +1152,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * @deprecated * UI method. Not meant to be used programatically. */ + @Deprecated public ComputerSet getComputer() { return new ComputerSet(); } @@ -1185,7 +1225,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } /** - * Gets the {@link Descriptor} instance in the current Hudson by its type. + * Gets the {@link Descriptor} instance in the current Jenkins by its type. */ public T getDescriptorByType(Class type) { for( Descriptor d : getExtensionList(Descriptor.class) ) @@ -1214,7 +1254,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve return null; } - protected void updateComputerList() throws IOException { + protected void updateComputerList() { updateComputerList(AUTOMATIC_SLAVE_LAUNCH); } @@ -1342,7 +1382,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * *

* To register an {@link Action}, implement {@link RootAction} extension point, or write code like - * {@code Hudson.getInstance().getActions().add(...)}. + * {@code Jenkins.getInstance().getActions().add(...)}. * * @return * Live list where the changes can be made. Can be empty but never null. @@ -1480,7 +1520,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } /** - * Returns the primary {@link View} that renders the top-page of Hudson. + * Returns the primary {@link View} that renders the top-page of Jenkins. */ @Exported public View getPrimaryView() { @@ -1516,7 +1556,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * *

* This method continues to return true until the system configuration is saved, at which point - * {@link #version} will be overwritten and Hudson forgets the upgrade history. + * {@link #version} will be overwritten and Jenkins forgets the upgrade history. * *

* To handle SNAPSHOTS correctly, pass in "1.N.*" to test if it's upgrading from the version @@ -1635,11 +1675,20 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } public List getJDKs() { - if(jdks==null) - jdks = new ArrayList(); return jdks; } + /** + * Replaces all JDK installations with those from the given collection. + * + * Use {@link hudson.model.JDK.DescriptorImpl#setInstallations(JDK...)} to + * set JDK installations from external code. + */ + @Restricted(NoExternalUse.class) + public void setJDKs(Collection jdks) { + this.jdks = new ArrayList(jdks); + } + /** * Gets the JDK installation of the given name, or returns null. */ @@ -1660,10 +1709,10 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve /** - * Gets the slave node of the give name, hooked under this Hudson. + * Gets the slave node of the give name, hooked under this Jenkins. */ public @CheckForNull Node getNode(String name) { - return slaves.getNode(name); + return nodes.getNode(name); } /** @@ -1682,38 +1731,49 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * represents the master. */ public List getNodes() { - return slaves; + return nodes.getNodes(); } /** - * Adds one more {@link Node} to Hudson. + * Get the {@link Nodes} object that handles maintaining individual {@link Node}s. + * @return The Nodes object. */ - public synchronized void addNode(Node n) throws IOException { - if(n==null) throw new IllegalArgumentException(); - ArrayList nl = new ArrayList(this.slaves); - if(!nl.contains(n)) // defensive check - nl.add(n); - setNodes(nl); + @Restricted(NoExternalUse.class) + public Nodes getNodesObject() { + // TODO replace this with something better when we properly expose Nodes. + return nodes; } /** - * Removes a {@link Node} from Hudson. + * Adds one more {@link Node} to Jenkins. */ - public synchronized void removeNode(@Nonnull Node n) throws IOException { - Computer c = n.toComputer(); - if (c!=null) - c.disconnect(OfflineCause.create(Messages._Hudson_NodeBeingRemoved())); + public void addNode(Node n) throws IOException { + nodes.addNode(n); + } - ArrayList nl = new ArrayList(this.slaves); - nl.remove(n); - setNodes(nl); + /** + * Removes a {@link Node} from Jenkins. + */ + public void removeNode(@Nonnull Node n) throws IOException { + nodes.removeNode(n); } - public void setNodes(final List nodes) throws IOException { - Jenkins.this.slaves = new NodeList(nodes); - updateComputerList(); - trimLabels(); - save(); + /** + * 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 + */ + public boolean updateNode(Node n) throws IOException { + return nodes.updateNode(n); + } + + public void setNodes(final List n) throws IOException { + nodes.setNodes(n); } public DescribableList, NodePropertyDescriptor> getNodeProperties() { @@ -1730,7 +1790,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * This should be called when the assumptions behind label cache computation changes, * but we also call this periodically to self-heal any data out-of-sync issue. */ - private void trimLabels() { + /*package*/ void trimLabels() { for (Iterator

* Unlike {@link #getRootUrl()}, which uses the manually configured value, @@ -2082,8 +2138,8 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } /** - * If true, all the POST requests to Hudson would have to have crumb in it to protect - * Hudson from CSRF vulnerabilities. + * If true, all the POST requests to Jenkins would have to have crumb in it to protect + * Jenkins from CSRF vulnerabilities. */ @Exported public boolean isUseCrumbs() { @@ -2091,8 +2147,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } /** - * Returns the constant that captures the three basic security modes - * in Hudson. + * Returns the constant that captures the three basic security modes in Jenkins. */ public SecurityMode getSecurity() { // fix the variable so that this code works under concurrent modification to securityRealm. @@ -2289,7 +2344,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } /** - * Returns true if Hudson is quieting down. + * Returns true if Jenkins is quieting down. *

* No further jobs will be executed unless it * can be finished while other current pending builds @@ -2319,8 +2374,11 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } public void setNumExecutors(int n) throws IOException { - this.numExecutors = n; - save(); + if (this.numExecutors != n) { + this.numExecutors = n; + updateComputerList(); + save(); + } } @@ -2407,7 +2465,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve return getItem(pathName,context!=null?context.getParent():null); } - public final T getItem(String pathName, ItemGroup context, Class type) { + public final T getItem(String pathName, ItemGroup context, @Nonnull Class type) { Item r = getItem(pathName, context); if (type.isInstance(r)) return type.cast(r); @@ -2516,7 +2574,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve /** * Called by {@link Job#renameTo(String)} to update relevant data structure. - * assumed to be synchronized on Hudson by the caller. + * assumed to be synchronized on Jenkins by the caller. */ public void onRenamed(TopLevelItem job, String oldName, String newName) throws IOException { items.remove(oldName); @@ -2625,12 +2683,8 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve final Set loadedNames = Collections.synchronizedSet(new HashSet()); TaskGraphBuilder g = new TaskGraphBuilder(); - Handle loadHudson = g.requires(EXTENSIONS_AUGMENTED).attains(JOB_LOADED).add("Loading global config", new Executable() { + Handle loadJenkins = g.requires(EXTENSIONS_AUGMENTED).attains(JOB_LOADED).add("Loading global config", new Executable() { public void run(Reactor session) throws Exception { - // JENKINS-8043: some slaves (eg. swarm slaves) are not saved into the config file - // and will get overwritten when reloading. Make a backup copy now, and re-add them later - NodeList oldSlaves = slaves; - XmlFile cfg = getConfigFile(); if (cfg.exists()) { // reset some data that may not exist in the disk file @@ -2643,28 +2697,19 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } // if we are loading old data that doesn't have this field - if (slaves == null) slaves = new NodeList(); + if (slaves != null && !slaves.isEmpty() && nodes.isLegacy()) { + nodes.setNodes(slaves); + slaves = null; + } else { + nodes.load(); + } clouds.setOwner(Jenkins.this); - - // JENKINS-8043: re-add the slaves which were not saved into the config file - // and are now missing, but still connected. - if (oldSlaves != null) { - ArrayList newSlaves = new ArrayList(slaves); - for (Node n: oldSlaves) { - if (n instanceof EphemeralNode) { - if(!newSlaves.contains(n)) { - newSlaves.add(n); - } - } - } - setNodes(newSlaves); - } } }); for (final File subdir : subdirs) { - g.requires(loadHudson).attains(JOB_LOADED).notFatal().add("Loading job "+subdir.getName(),new Executable() { + g.requires(loadJenkins).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 @@ -2697,14 +2742,14 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve rebuildDependencyGraph(); {// recompute label objects - populates the labels mapping. - for (Node slave : slaves) + for (Node slave : nodes.getNodes()) // Note that not all labels are visible until the slaves have connected. slave.getAssignedLabels(); getAssignedLabels(); } // initialize views by inserting the default view if necessary - // this is both for clean Hudson and for backward compatibility. + // this is both for clean Jenkins and for backward compatibility. if(views.size()==0 || primaryView==null) { View v = new AllView(Messages.Hudson_ViewName()); setViewOwner(v); @@ -2785,13 +2830,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) @@ -2870,8 +2921,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve systemMessage = Util.nullify(req.getParameter("system_message")); - jdks.clear(); - jdks.addAll(req.bindJSONToList(JDK.class,json.get("jdks"))); + setJDKs(req.bindJSONToList(JDK.class, json.get("jdks"))); boolean result = true; for (Descriptor d : Functions.getSortedDescriptorsForGlobalConfigUnclassified()) @@ -3320,7 +3370,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } /** - * Perform a restart of Hudson, if we can. + * Perform a restart of Jenkins, if we can. * * This first replaces "app" to {@link HudsonIsRestarting} */ @@ -3339,7 +3389,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } /** - * Queues up a restart of Hudson for when there are no builds running, if we can. + * Queues up a restart of Jenkins for when there are no builds running, if we can. * * This first replaces "app" to {@link HudsonIsRestarting} * @@ -3361,7 +3411,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve */ public void restart() throws RestartNotSupportedException { final Lifecycle lifecycle = Lifecycle.get(); - lifecycle.verifyRestartable(); // verify that Hudson is restartable + lifecycle.verifyRestartable(); // verify that Jenkins is restartable servletContext.setAttribute("app", new HudsonIsRestarting()); new Thread("restart thread") { @@ -3378,9 +3428,9 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve listener.onRestart(); lifecycle.restart(); } catch (InterruptedException e) { - LOGGER.log(Level.WARNING, "Failed to restart Hudson",e); + LOGGER.log(Level.WARNING, "Failed to restart Jenkins",e); } catch (IOException e) { - LOGGER.log(Level.WARNING, "Failed to restart Hudson",e); + LOGGER.log(Level.WARNING, "Failed to restart Jenkins",e); } } }.start(); @@ -3392,7 +3442,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve */ public void safeRestart() throws RestartNotSupportedException { final Lifecycle lifecycle = Lifecycle.get(); - lifecycle.verifyRestartable(); // verify that Hudson is restartable + lifecycle.verifyRestartable(); // verify that Jenkins is restartable // Quiet down so that we won't launch new builds. isQuietingDown = true; @@ -3492,17 +3542,14 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve LOGGER.severe(String.format("Shutting down VM as requested by %s from %s", exitUser, exitAddr)); // Wait 'til we have no active executors. - while (isQuietingDown - && (overallLoad.computeTotalExecutors() > overallLoad.computeIdleExecutors())) { - Thread.sleep(5000); - } + doQuietDown(true, 0); // Make sure isQuietingDown is still true. if (isQuietingDown) { cleanUp(); System.exit(0); } - } catch (InterruptedException e) { - LOGGER.log(Level.WARNING, "Failed to shutdown Hudson",e); + } catch (Exception e) { + LOGGER.log(Level.WARNING, "Failed to shut down Jenkins", e); } } }.start(); @@ -3552,6 +3599,11 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve if (!"POST".equals(req.getMethod())) { throw HttpResponses.error(HttpURLConnection.HTTP_BAD_METHOD, "requires POST"); } + + if (channel == null) { + throw HttpResponses.error(HttpURLConnection.HTTP_NOT_FOUND, "Node is offline"); + } + try { req.setAttribute("output", RemotingDiagnostics.executeGroovy(text, channel)); @@ -3627,7 +3679,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(); @@ -3687,6 +3739,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * Checks if a top-level view with the given name exists. * @deprecated 1.512 */ + @Deprecated public FormValidation doViewExistsCheck(@QueryParameter String value) { checkPermission(View.CREATE); @@ -3824,26 +3877,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; @@ -3997,6 +4048,11 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve return true; } + @Override + public Boolean isUnix() { + return !Functions.isWindows(); + } + /** * Report an error. */ @@ -4051,6 +4107,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * @deprecated as of 1.558 * Use {@link FilePath#localChannel} */ + @Deprecated public static final LocalChannel localChannel = FilePath.localChannel; } @@ -4063,7 +4120,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } /** - * Live view of recent {@link LogRecord}s produced by Hudson. + * Live view of recent {@link LogRecord}s produced by Jenkins. */ public static List logRecords = Collections.emptyList(); // initialized to dummy value to avoid NPE @@ -4119,20 +4176,20 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } /** - * Version number of this Hudson. + * Version number of this Jenkins. */ public static String VERSION="?"; /** * Parses {@link #VERSION} into {@link VersionNumber}, or null if it's not parseable as a version number - * (such as when Hudson is run with "mvn hudson-dev:run") + * (such as when Jenkins is run with "mvn hudson-dev:run") */ public static VersionNumber getVersion() { try { return new VersionNumber(VERSION); } catch (NumberFormatException e) { try { - // for non-released version of Hudson, this looks like "1.345 (private-foobar), so try to approximate. + // for non-released version of Jenkins, this looks like "1.345 (private-foobar), so try to approximate. int idx = VERSION.indexOf(' '); if (idx>0) return new VersionNumber(VERSION.substring(0,idx)); @@ -4173,7 +4230,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve /** * Prefix to resources alongside view scripts. - * Strings like "/resources/VERSION", which avoids Hudson to pick up + * Strings like "/resources/VERSION", which avoids Jenkins to pick up * stale cache when the user upgrades to a different version. *

* Value computed in {@link WebAppMain}. @@ -4185,6 +4242,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve /** * @deprecated No longer used. */ + @Deprecated public static boolean FLYWEIGHT_SUPPORT = true; /** @@ -4196,6 +4254,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve * This flag will have no effect. */ @Restricted(NoExternalUse.class) + @Deprecated public static boolean CONCURRENT_BUILD = true; /** @@ -4215,6 +4274,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 diff --git a/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java b/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java index c10e51d526b6b01c1ec289330af30be2e05b90f0..f626750deb8553cbc8046e8c2bdba821b26466ac 100644 --- a/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java +++ b/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java @@ -20,6 +20,8 @@ import java.util.logging.Level; import java.util.logging.Logger; import static hudson.Util.fixNull; +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; /** * Stores the location of Jenkins (e-mail address and the HTTP URL.) @@ -30,8 +32,9 @@ import static hudson.Util.fixNull; @Extension public class JenkinsLocationConfiguration extends GlobalConfiguration { /** - * @deprecated + * @deprecated replaced by {@link #jenkinsUrl} */ + @Deprecated private transient String hudsonUrl; private String adminAddress; private String jenkinsUrl; @@ -39,7 +42,7 @@ public class JenkinsLocationConfiguration extends GlobalConfiguration { // just to suppress warnings private transient String charset,useSsl; - public static JenkinsLocationConfiguration get() { + public static @CheckForNull JenkinsLocationConfiguration get() { return GlobalConfiguration.all().get(JenkinsLocationConfiguration.class); } @@ -72,28 +75,37 @@ public class JenkinsLocationConfiguration extends GlobalConfiguration { updateSecureSessionFlag(); } - public String getAdminAddress() { + /** + * Gets the service administrator e-mail address. + * @return Admin address or "address not configured" stub + */ + public @Nonnull String getAdminAddress() { String v = adminAddress; if(v==null) v = Messages.Mailer_Address_Not_Configured(); return v; } - public void setAdminAddress(String adminAddress) { - if(adminAddress.startsWith("\"") && adminAddress.endsWith("\"")) { - // some users apparently quote the whole thing. Don't konw why + /** + * Sets the e-mail address of Jenkins administrator. + * @param adminAddress Admin address. Use null to reset the value to default. + */ + 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 know why // anyone does this, but it's a machine's job to forgive human mistake - adminAddress = adminAddress.substring(1,adminAddress.length()-1); + address = address.substring(1,address.length()-1); } - this.adminAddress = adminAddress; + this.adminAddress = address; save(); } - public String getUrl() { + public @CheckForNull String getUrl() { return jenkinsUrl; } - public void setUrl(String hudsonUrl) { - String url = Util.nullify(hudsonUrl); + public void setUrl(@CheckForNull String jenkinsUrl) { + String url = Util.nullify(jenkinsUrl); if(url!=null && !url.endsWith("/")) url += '/'; this.jenkinsUrl = url; diff --git a/core/src/main/java/jenkins/model/Nodes.java b/core/src/main/java/jenkins/model/Nodes.java new file mode 100644 index 0000000000000000000000000000000000000000..f11affc06becdc4a14dd5b1eec6a6a4cf98b6a9a --- /dev/null +++ b/core/src/main/java/jenkins/model/Nodes.java @@ -0,0 +1,332 @@ +/* + * The MIT License + * + * Copyright (c) 2015, CloudBees, Inc., Stephen Connolly + * + * 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.BulkChange; +import hudson.Util; +import hudson.XmlFile; +import hudson.model.Computer; +import hudson.model.Node; +import hudson.model.Queue; +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; + +import javax.annotation.CheckForNull; +import javax.annotation.Nonnull; +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentSkipListMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Manages all the nodes for Jenkins. + * + * @since 1.607 + */ +@Restricted(NoExternalUse.class) // for now, we may make it public later +public class Nodes implements Saveable { + + /** + * The {@link Jenkins} instance that we are tracking nodes for. + */ + @Nonnull + private final Jenkins jenkins; + + /** + * The map of nodes. + */ + private final ConcurrentMap nodes = new ConcurrentSkipListMap(); + + /** + * Constructor, intended to be called only from {@link Jenkins}. + * + * @param jenkins A reference to the {@link Jenkins} that this instance is tracking nodes for, beware not to + * let this reference escape from a partially constructed {@link Nodes} as when we are passed the + * reference the {@link Jenkins} instance has not completed instantiation. + */ + /*package*/ Nodes(@Nonnull Jenkins jenkins) { + this.jenkins = jenkins; + } + + /** + * Returns the list of nodes. + * + * @return the list of nodes. + */ + @Nonnull + public List getNodes() { + return new ArrayList(nodes.values()); + } + + /** + * Sets the list of nodes. + * + * @param nodes the new list of nodes. + * @throws IOException if the new list of nodes could not be persisted. + */ + public void setNodes(final @Nonnull Collection nodes) throws IOException { + Queue.withLock(new Runnable() { + @Override + public void run() { + Set toRemove = new HashSet(Nodes.this.nodes.keySet()); + for (Node n : nodes) { + final String name = n.getNodeName(); + toRemove.remove(name); + Nodes.this.nodes.put(name, n); + } + Nodes.this.nodes.keySet().removeAll(toRemove); // directory clean up will be handled by save + jenkins.updateComputerList(); + jenkins.trimLabels(); + } + }); + save(); + } + + /** + * Adds a node. If a node of the same name already exists then that node will be replaced. + * + * @param node the new node. + * @throws IOException if the list of nodes could not be persisted. + */ + public void addNode(final @Nonnull Node node) throws IOException { + if (node != nodes.get(node.getNodeName())) { + // TODO we should not need to lock the queue for adding nodes but until we have a way to update the + // computer list for just the new node + Queue.withLock(new Runnable() { + @Override + public void run() { + nodes.put(node.getNodeName(), node); + jenkins.updateComputerList(); + jenkins.trimLabels(); + } + }); + // TODO there is a theoretical race whereby the node instance is updated/removed after lock release + persistNode(node); + } + } + + /** + * Actually persists a node on disk. + * + * @param node the node to be persisted. + * @throws IOException if the node could not be persisted. + */ + private void persistNode(final @Nonnull Node node) throws IOException { + // no need for a full save() so we just do the minimum + if (node instanceof EphemeralNode) { + Util.deleteRecursive(new File(getNodesDir(), node.getNodeName())); + } else { + XmlFile xmlFile = new XmlFile(Jenkins.XSTREAM, + new File(new File(getNodesDir(), node.getNodeName()), "config.xml")); + xmlFile.write(node); + SaveableListener.fireOnChange(this, xmlFile); + } + jenkins.getQueue().scheduleMaintenance(); + } + + /** + * 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. + * @since 1.634 + */ + public boolean updateNode(final @Nonnull Node node) throws IOException { + boolean exists; + try { + exists = Queue.withLock(new Callable() { + @Override + public Boolean call() throws Exception { + if (node == nodes.get(node.getNodeName())) { + jenkins.trimLabels(); + return true; + } + 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; + } + if (exists) { + // TODO there is a theoretical race whereby the node instance is updated/removed after lock release + persistNode(node); + return true; + } + return false; + } + + /** + * Removes a node. 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 instance to remove. + * @throws IOException if the list of nodes could not be persisted. + */ + public void removeNode(final @Nonnull Node node) throws IOException { + if (node == nodes.get(node.getNodeName())) { + Queue.withLock(new Runnable() { + @Override + public void run() { + Computer c = node.toComputer(); + if (c != null) { + c.recordTermination(); + c.disconnect(OfflineCause.create(hudson.model.Messages._Hudson_NodeBeingRemoved())); + } + if (node == nodes.remove(node.getNodeName())) { + jenkins.updateComputerList(); + jenkins.trimLabels(); + } + } + }); + // no need for a full save() so we just do the minimum + Util.deleteRecursive(new File(getNodesDir(), node.getNodeName())); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void save() throws IOException { + if (BulkChange.contains(this)) { + return; + } + final File nodesDir = getNodesDir(); + final Set existing = new HashSet(); + for (Node n : nodes.values()) { + if (n instanceof EphemeralNode) { + continue; + } + existing.add(n.getNodeName()); + XmlFile xmlFile = new XmlFile(Jenkins.XSTREAM, new File(new File(nodesDir, n.getNodeName()), "config.xml")); + xmlFile.write(n); + SaveableListener.fireOnChange(this, xmlFile); + } + for (File forDeletion : nodesDir.listFiles(new FileFilter() { + @Override + public boolean accept(File pathname) { + return pathname.isDirectory() && !existing.contains(pathname.getName()); + } + })) { + Util.deleteRecursive(forDeletion); + } + } + + /** + * Returns the named node. + * + * @param name the {@link Node#getNodeName()} of the node to retrieve. + * @return the {@link Node} or {@code null} if the node could not be found. + */ + @CheckForNull + public Node getNode(String name) { + return name == null ? null : nodes.get(name); + } + + /** + * Loads the nodes from disk. + * + * @throws IOException if the nodes could not be deserialized. + */ + public void load() throws IOException { + final File nodesDir = getNodesDir(); + final File[] subdirs = nodesDir.listFiles(new FileFilter() { + public boolean accept(File child) { + return child.isDirectory(); + } + }); + final Map newNodes = new TreeMap(); + if (subdirs != null) { + for (File subdir : subdirs) { + try { + XmlFile xmlFile = new XmlFile(Jenkins.XSTREAM, new File(subdir, "config.xml")); + if (xmlFile.exists()) { + Node node = (Node) xmlFile.read(); + newNodes.put(node.getNodeName(), node); + } + } catch (IOException e) { + Logger.getLogger(Nodes.class.getName()).log(Level.WARNING, "could not load " + subdir, e); + } + } + } + Queue.withLock(new Runnable() { + @Override + public void run() { + for (Iterator> i = nodes.entrySet().iterator(); i.hasNext(); ) { + if (!(i.next().getValue() instanceof EphemeralNode)) { + i.remove(); + } + } + nodes.putAll(newNodes); + jenkins.updateComputerList(); + jenkins.trimLabels(); + } + }); + } + + /** + * Returns the directory that the nodes are stored in. + * + * @return the directory that the nodes are stored in. + * @throws IOException + */ + private File getNodesDir() throws IOException { + final File nodesDir = new File(jenkins.getRootDir(), "nodes"); + if (!nodesDir.isDirectory() && !nodesDir.mkdirs()) { + throw new IOException(String.format("Could not mkdirs %s", nodesDir)); + } + return nodesDir; + } + + /** + * Returns {@code true} if and only if the list of nodes is stored in the legacy location. + * + * @return {@code true} if and only if the list of nodes is stored in the legacy location. + */ + public boolean isLegacy() { + return !new File(jenkins.getRootDir(), "nodes").isDirectory(); + } +} diff --git a/test/src/main/java/org/jvnet/hudson/test/FailureBuilder.java b/core/src/main/java/jenkins/model/OptionalJobProperty.java similarity index 53% rename from test/src/main/java/org/jvnet/hudson/test/FailureBuilder.java rename to core/src/main/java/jenkins/model/OptionalJobProperty.java index 7caa45305c7a89cf242159c2d1158e937b9ccd50..996ea3a8a482c27ba0f1f19d297189035f180feb 100644 --- a/test/src/main/java/org/jvnet/hudson/test/FailureBuilder.java +++ b/core/src/main/java/jenkins/model/OptionalJobProperty.java @@ -1,18 +1,18 @@ /* * The MIT License - * - * Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi - * + * + * 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 @@ -21,32 +21,41 @@ * 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.Descriptor; -import hudson.model.Result; -import hudson.tasks.Builder; +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; /** - * Mock {@link Builder} that always cause a build to fail. - * - * @author Kohsuke Kawaguchi + * 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 1.637 */ -public class FailureBuilder extends MockBuilder { - public FailureBuilder() { - super(Result.FAILURE); +public abstract class OptionalJobProperty> extends JobProperty { + + @Override + public OptionalJobPropertyDescriptor getDescriptor() { + return (OptionalJobPropertyDescriptor) super.getDescriptor(); } - @Extension - public static final class DescriptorImpl extends Descriptor { - public String getDisplayName() { - return "Always fail"; + public static abstract class OptionalJobPropertyDescriptor extends JobPropertyDescriptor { + + protected OptionalJobPropertyDescriptor(Class> clazz) { + super(clazz); } - public FailureBuilder newInstance(StaplerRequest req, JSONObject data) { - return new FailureBuilder(); + + 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/java/jenkins/model/ParameterizedJobMixIn.java b/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java index 1fff85ec128f8fe7df87d938c62f8e21a5216224..07d1e61e6bb21b53e980bd09b17232ff2350f3fa 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; @@ -94,17 +95,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; + } + + /** + * 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 1.621 + */ + 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)); } - private @CheckForNull QueueTaskFuture scheduleBuild2(int quietPeriod, List actions) { + @CheckForNull Queue.Item scheduleBuild2(int quietPeriod, List actions) { if (!asJob().isBuildable()) return null; @@ -112,8 +135,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() { @@ -240,13 +262,39 @@ 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 is it worthwhile to define a 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() ? Messages.ParameterizedJobMixIn_build_with_parameters() : AlternativeUiTextProvider.get(BUILD_NOW_TEXT, asJob(), Messages.ParameterizedJobMixIn_build_now()); + } + + /** + * 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 1.621 + */ + 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; } /** @@ -265,6 +313,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/model/RunIdMigrator.java b/core/src/main/java/jenkins/model/RunIdMigrator.java index 7d375c79a5f6b8362e159b7617f1a3016d3aef3e..94d378633a228cbecd5b21b2576a3a1d1ed216e9 100644 --- a/core/src/main/java/jenkins/model/RunIdMigrator.java +++ b/core/src/main/java/jenkins/model/RunIdMigrator.java @@ -28,12 +28,14 @@ import hudson.Extension; import hudson.Util; import hudson.model.Job; import hudson.model.RootAction; -import hudson.model.Run; import hudson.util.AtomicFileWriter; import hudson.util.StreamTaskListener; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.net.URISyntaxException; import java.net.URL; import java.text.DateFormat; @@ -198,22 +200,21 @@ public final class RunIdMigrator { File kid = it.next(); String name = kid.getName(); try { - String link = Util.resolveSymlink(kid); - if (link == null && name.matches("\\d+") && kid.isFile()) { // legacy Windows format - link = FileUtils.readFileToString(kid); - } else if (link == null) { + Integer.parseInt(name); + } catch (NumberFormatException x) { + LOGGER.log(FINE, "ignoring nonnumeric entry {0}", name); + continue; + } + try { + if (Util.isSymlink(kid)) { + LOGGER.log(FINE, "deleting build number symlink {0} → {1}", new Object[] {name, Util.resolveSymlink(kid)}); + } else if (kid.isDirectory()) { + LOGGER.log(FINE, "ignoring build directory {0}", name); continue; + } else { + LOGGER.log(WARNING, "need to delete anomalous file entry {0}", name); } - try { - Integer.parseInt(name); - if (kid.delete()) { - LOGGER.log(FINE, "deleted build number symlink {0} → {1}", new Object[] {name, link}); - } else { - LOGGER.log(WARNING, "could not delete build number symlink {0} → {1}", new Object[] {name, link}); - } - } catch (NumberFormatException x) { - LOGGER.log(FINE, "skipping other symlink {0} → {1}", new Object[] {name, link}); - } + Util.deleteFile(kid); it.remove(); } catch (Exception x) { LOGGER.log(WARNING, "failed to process " + kid, x); @@ -259,10 +260,7 @@ public final class RunIdMigrator { String nl = m.group(2); xml = m.replaceFirst(" " + name + "" + nl + " " + timestamp + "" + nl); File newKid = new File(dir, Integer.toString(number)); - if (!kid.renameTo(newKid)) { - LOGGER.log(WARNING, "failed to rename {0} to {1}", new Object[] {name, number}); - continue; - } + move(kid, newKid); FileUtils.writeStringToFile(new File(newKid, "build.xml"), xml, Charsets.UTF_8); LOGGER.log(FINE, "fully processed {0} → {1}", new Object[] {name, number}); idToNumber.put(name, number); @@ -272,6 +270,42 @@ public final class RunIdMigrator { } } + /** + * Tries to move/rename a file from one path to another. + * Uses {@link java.nio.file.Files#move} when available. + * Does not use {@link java.nio.file.StandardCopyOption#REPLACE_EXISTING} or any other options. + * TODO candidate for moving to {@link Util} + */ + static void move(File src, File dest) throws IOException { + Class pathC; + try { + pathC = Class.forName("java.nio.file.Path"); + } catch (ClassNotFoundException x) { + // Java 6, do our best + if (dest.exists()) { + throw new IOException(dest + " already exists"); + } + if (src.renameTo(dest)) { + return; + } + throw new IOException("could not move " + src + " to " + dest); + } + try { + Method toPath = File.class.getMethod("toPath"); + Class copyOptionAC = Class.forName("[Ljava.nio.file.CopyOption;"); + Class.forName("java.nio.file.Files").getMethod("move", pathC, pathC, copyOptionAC).invoke(null, toPath.invoke(src), toPath.invoke(dest), Array.newInstance(copyOptionAC.getComponentType(), 0)); + } catch (InvocationTargetException x) { + Throwable cause = x.getCause(); + if (cause instanceof IOException) { + throw (IOException) cause; + } else { + throw new IOException(cause); + } + } catch (Exception x) { + throw new IOException(x); + } + } + /** * Look up a historical run by ID. * @param id a nonnumeric ID which may be a valid {@link Run#getId} @@ -315,6 +349,12 @@ public final class RunIdMigrator { return; } 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; @@ -326,7 +366,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); } } diff --git a/core/src/main/java/jenkins/model/TransientActionFactory.java b/core/src/main/java/jenkins/model/TransientActionFactory.java index 5ae8a430959d3b41ef03ab0f03828379b206bea1..f0871920eaf6f6fc98c271999eb1b3bade581a5b 100644 --- a/core/src/main/java/jenkins/model/TransientActionFactory.java +++ b/core/src/main/java/jenkins/model/TransientActionFactory.java @@ -24,6 +24,7 @@ package jenkins.model; +import hudson.ExtensionPoint; import hudson.model.Action; import hudson.model.Actionable; import hudson.model.TopLevelItem; @@ -37,7 +38,7 @@ import javax.annotation.Nonnull; * @see Actionable#getAllActions * @since 1.548 */ -public abstract class TransientActionFactory { +public abstract class TransientActionFactory implements ExtensionPoint { /** * The type of object this factory cares about. diff --git a/core/src/main/java/jenkins/model/TransientFingerprintFacetFactory.java b/core/src/main/java/jenkins/model/TransientFingerprintFacetFactory.java index 96cf7ebec4af2886c97685ba5e2a58e417de13ca..5e7826cbdde3a9bcaf475da1b239909bc100857f 100644 --- a/core/src/main/java/jenkins/model/TransientFingerprintFacetFactory.java +++ b/core/src/main/java/jenkins/model/TransientFingerprintFacetFactory.java @@ -27,7 +27,6 @@ import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.model.Fingerprint; -import java.util.Collection; import java.util.List; /** diff --git a/core/src/main/java/jenkins/model/UnlabeledLoadStatistics.java b/core/src/main/java/jenkins/model/UnlabeledLoadStatistics.java index 7809356ecb565e342dffdcb889f3d05c79cc50f9..cf4abda2819725bc3d2eb55df949fd478633c227 100644 --- a/core/src/main/java/jenkins/model/UnlabeledLoadStatistics.java +++ b/core/src/main/java/jenkins/model/UnlabeledLoadStatistics.java @@ -28,7 +28,12 @@ import hudson.model.LoadStatistics; import hudson.model.Node; import hudson.model.Node.Mode; import hudson.model.OverallLoadStatistics; +import hudson.model.Queue; import hudson.model.Queue.Task; +import hudson.model.queue.SubTask; +import hudson.util.Iterators; + +import java.util.Iterator; /** * {@link LoadStatistics} that track the "free roam" jobs (whose {@link Task#getAssignedLabel()} is null) @@ -41,6 +46,8 @@ import hudson.model.Queue.Task; */ public class UnlabeledLoadStatistics extends LoadStatistics { + private final Iterable nodes = new UnlabeledNodesIterable(); + UnlabeledLoadStatistics() { super(0, 0); } @@ -71,6 +78,48 @@ public class UnlabeledLoadStatistics extends LoadStatistics { @Override public int computeQueueLength() { - return Jenkins.getInstance().getQueue().countBuildableItemsFor(null); + final Jenkins j = Jenkins.getInstance(); + if (j == null) { // Consider queue as empty when Jenkins is inactive + return 0; + } + return j.getQueue().strictCountBuildableItemsFor(null); + } + + @Override + protected Iterable getNodes() { + return nodes; + } + + @Override + protected boolean matches(Queue.Item item, SubTask subTask) { + return item.getAssignedLabelFor(subTask) == null; + } + + private static class UnlabeledNodesIterable implements Iterable { + + @Override + public Iterator iterator() { + return new UnlabeledNodesIterator(); + } + } + + private static class UnlabeledNodesIterator extends Iterators.FilterIterator { + + protected UnlabeledNodesIterator() { + super(Jenkins.getActiveInstance().getNodes().iterator()); + } + + @Override + protected boolean filter(Node n) { + return n != null && n.getMode() == Mode.NORMAL; + } + + public void remove() { + // why does Iterators.FilterIterator do the stupid thing and allow remove? + // (remove should remove the object last returned by next(), but it won't if hasNext() is called + // the way Iterators.FilterIterator is written... it should just return a read-only + // view... which is what we do! + throw new UnsupportedOperationException("remove"); + } } } diff --git a/core/src/main/java/jenkins/model/lazy/AbstractLazyLoadRunMap.java b/core/src/main/java/jenkins/model/lazy/AbstractLazyLoadRunMap.java index 1fd3b58391a6874f913d503a951b79d062124140..25ac5f4dfcb35687bc5674a6ed6a269d315fc3a3 100644 --- a/core/src/main/java/jenkins/model/lazy/AbstractLazyLoadRunMap.java +++ b/core/src/main/java/jenkins/model/lazy/AbstractLazyLoadRunMap.java @@ -118,7 +118,7 @@ public abstract class AbstractLazyLoadRunMap extends AbstractMap i private final TreeMap> byNumber; private Index() { - byNumber = new TreeMap>(COMPARATOR); + byNumber = new TreeMap>(Collections.reverseOrder()); } private Index(Index rhs) { @@ -203,7 +203,7 @@ public abstract class AbstractLazyLoadRunMap extends AbstractMap i } public Comparator comparator() { - return COMPARATOR; + return Collections.reverseOrder(); } @Override @@ -353,7 +353,19 @@ public abstract class AbstractLazyLoadRunMap extends AbstractMap i if (v!=null) return v; // already in memory // otherwise fall through to load } - return load(n, null); + synchronized (this) { + if (index.byNumber.containsKey(n)) { // JENKINS-22767: recheck inside lock + BuildReference ref = index.byNumber.get(n); + if (ref == null) { + return null; + } + R v = unwrap(ref); + if (v != null) { + return v; + } + } + return load(n, null); + } } protected final synchronized void proposeNewNumber(int number) throws IllegalStateException { @@ -443,7 +455,8 @@ public abstract class AbstractLazyLoadRunMap extends AbstractMap i * * @return null if the data failed to load. */ - protected R load(int n, Index editInPlace) { + private R load(int n, Index editInPlace) { + assert Thread.holdsLock(this); assert dir != null; R v = load(new File(dir, String.valueOf(n)), editInPlace); if (v==null && editInPlace!=null) { @@ -460,7 +473,8 @@ public abstract class AbstractLazyLoadRunMap extends AbstractMap i * If non-null, update this data structure. * Otherwise do a copy-on-write of {@link #index} */ - protected synchronized R load(File dataDir, Index editInPlace) { + private R load(File dataDir, Index editInPlace) { + assert Thread.holdsLock(this); try { R r = retrieve(dataDir); if (r==null) return null; @@ -548,12 +562,6 @@ public abstract class AbstractLazyLoadRunMap extends AbstractMap i return o==this; } - private static final Comparator COMPARATOR = new Comparator() { - @Override public int compare(Integer o1, Integer o2) { - return o2 - o1; - } - }; - public enum Direction { ASC, DESC, EXACT } diff --git a/core/src/main/java/jenkins/model/lazy/LazyBuildMixIn.java b/core/src/main/java/jenkins/model/lazy/LazyBuildMixIn.java index 99c48f820b1357a39f3636603852eb09a04577e1..b206035c386d30fce003f96b06820dbbfb0ede45 100644 --- a/core/src/main/java/jenkins/model/lazy/LazyBuildMixIn.java +++ b/core/src/main/java/jenkins/model/lazy/LazyBuildMixIn.java @@ -25,7 +25,6 @@ package jenkins.model.lazy; import hudson.Extension; -import hudson.model.AbstractItem; import hudson.model.Item; import hudson.model.ItemGroup; import hudson.model.Job; @@ -33,7 +32,6 @@ import hudson.model.Queue; import hudson.model.Run; import hudson.model.RunMap; import hudson.model.listeners.ItemListener; -import hudson.model.queue.SubTask; import hudson.widgets.BuildHistoryWidget; import hudson.widgets.HistoryWidget; import java.io.File; diff --git a/core/src/main/java/jenkins/model/queue/AsynchronousExecution.java b/core/src/main/java/jenkins/model/queue/AsynchronousExecution.java new file mode 100644 index 0000000000000000000000000000000000000000..d53fc768c3421d09470e7fb938c69b8d63ad94f6 --- /dev/null +++ b/core/src/main/java/jenkins/model/queue/AsynchronousExecution.java @@ -0,0 +1,127 @@ +/* + * 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 jenkins.model.queue; + +import hudson.model.Executor; +import hudson.model.OneOffExecutor; +import hudson.model.Queue.FlyweightTask; +import hudson.model.Resource; +import hudson.model.ResourceActivity; +import hudson.model.ResourceController; +import hudson.model.ResourceList; +import javax.annotation.CheckForNull; +import javax.annotation.concurrent.GuardedBy; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + +/** + * Special means of indicating that an executable will proceed in the background without consuming a native thread ({@link Executor}). + * May be thrown from {@link Executable#run} after doing any preparatory work synchronously. + *

{@link Executor#isActive} will remain true (even though {@link Executor#isAlive} is not) until {@link #completed} is called. + * The thrower will need to hold on to a reference to this instance as a handle to call {@link #completed}. + *

The execution may not extend into another Jenkins session; if you wish to model a long-running execution, you must schedule a new task after restart. + * This class is not serializable anyway. + *

Mainly intended for use with {@link OneOffExecutor} (from a {@link FlyweightTask}), of which there could be many, + * but could also be used with a heavyweight executor even though the number of executors is bounded by node configuration. + *

{@link ResourceController}/{@link ResourceActivity}/{@link ResourceList}/{@link Resource} are not currently supported. + * Nor are {@link hudson.model.Queue.Task#getSubTasks} other than the primary task. + * @since 1.607 + */ +public abstract class AsynchronousExecution extends RuntimeException { + + @GuardedBy("this") + private Executor executor; + + /** + * Initially null, and usually stays null. + * If {@link #completed} is called before {@link #setExecutor}, then either {@link #NULL} for success, or the error. + */ + @GuardedBy("this") + private @CheckForNull Throwable result; + + /** Constructor for subclasses. */ + protected AsynchronousExecution() {} + + /** + * Called in lieu of {@link Thread#interrupt} by {@link Executor#interrupt()} and its overloads. + * As with the standard Java method, you are requested to cease work as soon as possible, but there is no enforcement of this. + * You might also want to call {@link Executor#recordCauseOfInterruption} on {@link #getExecutor}. + * @param forShutdown if true, this interruption is because Jenkins is shutting down (and thus {@link Computer#interrupt} was called from {@link Jenkins#cleanUp}); otherwise, a normal interrupt such as by {@link Executor#doStop()} + */ + public abstract void interrupt(boolean forShutdown); + + /** + * Allows an executable to indicate whether it is currently doing something which should prevent Jenkins from being shut down safely. + * You may return false if it is fine for an administrator to exit/restart Jenkins despite this executable still being running. + * (If so, {@link #interrupt} will be passed {@code forShutdown=true}.) + * @return traditionally always true + * @see hudson.model.RestartListener.Default#isReadyToRestart + */ + public abstract boolean blocksRestart(); + + /** + * Allows an executable to control whether or not to display {@code executorCell.jelly}. + * + *

+ * If this method returns false, the asynchronous execution becomes invisible from UI. + * + * @return traditionally always true + */ + public abstract boolean displayCell(); + + /** + * Obtains the associated executor. + */ + public synchronized final Executor getExecutor() { + return executor; + } + + @Restricted(NoExternalUse.class) + public synchronized final void setExecutor(Executor executor) { + assert this.executor==null; + + this.executor = executor; + if (result!=null) { + executor.completedAsynchronous( result!=NULL ? result : null ); + result = null; + } + } + + /** + * To be called when the task is actually complete. + * @param error normally null (preferable to handle errors yourself), but may be specified to simulate an exception from {@link Executable#run}, as per {@link ExecutorListener#taskCompletedWithProblems} + */ + public synchronized final void completed(@CheckForNull Throwable error) { + if (executor!=null) { + executor.completedAsynchronous(error); + } else { + result = error == null ? NULL : error; + } + } + + /** @see #result */ + private static final Throwable NULL = new Throwable("NULL"); + +} diff --git a/core/src/main/java/jenkins/mvn/FilePathGlobalSettingsProvider.java b/core/src/main/java/jenkins/mvn/FilePathGlobalSettingsProvider.java index 4e5b9ed3229d0d56e92ca1f400290c3b361738cd..39690a04725dce102185039a7a75b02a3e8035e1 100644 --- a/core/src/main/java/jenkins/mvn/FilePathGlobalSettingsProvider.java +++ b/core/src/main/java/jenkins/mvn/FilePathGlobalSettingsProvider.java @@ -9,7 +9,6 @@ import hudson.model.TaskListener; import hudson.util.IOUtils; import java.io.File; -import java.io.IOException; import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.DataBoundConstructor; diff --git a/core/src/main/java/jenkins/mvn/GlobalSettingsProvider.java b/core/src/main/java/jenkins/mvn/GlobalSettingsProvider.java index 6438cfad1e688b59e98d531a7c7b32b7ad9b3f75..aa7285eed9695978639586c8b476e3f0b93d0baa 100644 --- a/core/src/main/java/jenkins/mvn/GlobalSettingsProvider.java +++ b/core/src/main/java/jenkins/mvn/GlobalSettingsProvider.java @@ -51,11 +51,7 @@ public abstract class GlobalSettingsProvider extends AbstractDescribableImpl build, TaskListener listener) { FilePath settingsPath = null; if (settings != null) { - try { - settingsPath = settings.supplySettings(build, listener); - } catch (Exception e) { - listener.getLogger().print("failed to get the path to the alternate global settings.xml"); - } + settingsPath = settings.supplySettings(build, listener); } return settingsPath; } diff --git a/core/src/main/java/jenkins/security/ApiTokenFilter.java b/core/src/main/java/jenkins/security/ApiTokenFilter.java index 3d5985d6bafedb210bfcdbba8f592b281b44dbb4..f7b63c2062828af0f273dab45cc95174c34606a0 100644 --- a/core/src/main/java/jenkins/security/ApiTokenFilter.java +++ b/core/src/main/java/jenkins/security/ApiTokenFilter.java @@ -16,6 +16,7 @@ import java.util.List; * @deprecated as of 1.576 * Use {@link BasicHeaderProcessor} */ +@Deprecated public class ApiTokenFilter extends BasicHeaderProcessor { @Override protected List all() { diff --git a/core/src/main/java/jenkins/security/ApiTokenProperty.java b/core/src/main/java/jenkins/security/ApiTokenProperty.java index caa9ed8853c6d97eb38f7da5d3f2dee8555e4603..8aef388cbd64d5554f1b4e7af6475e5c7574f2d7 100644 --- a/core/src/main/java/jenkins/security/ApiTokenProperty.java +++ b/core/src/main/java/jenkins/security/ApiTokenProperty.java @@ -29,6 +29,7 @@ import hudson.model.Descriptor.FormException; import hudson.model.User; import hudson.model.UserProperty; import hudson.model.UserPropertyDescriptor; +import hudson.security.ACL; import hudson.util.HttpResponses; import hudson.util.Secret; import jenkins.model.Jenkins; @@ -41,6 +42,10 @@ import org.kohsuke.stapler.StaplerResponse; import java.io.IOException; import java.security.SecureRandom; +import javax.annotation.Nonnull; +import org.apache.commons.lang.StringUtils; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; /** * Remembers the API token for this user, that can be used like a password to login. @@ -53,6 +58,16 @@ import java.security.SecureRandom; public class ApiTokenProperty extends UserProperty { private volatile Secret apiToken; + /** + * If enabled, shows API tokens to users with {@link Jenkins#ADMINISTER) permissions. + * Disabled by default due to the security reasons. + * If enabled, it restores the original Jenkins behavior (SECURITY-200). + * @since TODO + */ + private static final boolean SHOW_TOKEN_TO_ADMINS = + Boolean.getBoolean(ApiTokenProperty.class.getName() + ".showTokenToAdmins"); + + @DataBoundConstructor public ApiTokenProperty() { _changeApiToken(); @@ -66,7 +81,24 @@ public class ApiTokenProperty extends UserProperty { apiToken = Secret.fromString(seed); } + /** + * Gets the API token. + * The method performs security checks. Only the current user and SYSTEM may see it. + * Users with {@link Jenkins#ADMINISTER} may be allowed to do it using {@link #SHOW_TOKEN_TO_ADMINS}. + * + * @return API Token. Never null, but may be {@link Messages#ApiTokenProperty_ChangeToken_TokenIsHidden()} + * if the user has no appropriate permissions. + * @since TODO: the method performs security checks + */ + @Nonnull public String getApiToken() { + return hasPermissionToSeeToken() ? getApiTokenInsecure() + : Messages.ApiTokenProperty_ChangeToken_TokenIsHidden(); + } + + @Nonnull + @Restricted(NoExternalUse.class) + /*package*/ String getApiTokenInsecure() { String p = apiToken.getPlainText(); if (p.equals(Util.getDigestOf(Jenkins.getInstance().getSecretKey()+":"+user.getId()))) { // if the current token is the initial value created by pre SECURITY-49 Jenkins, we can't use that. @@ -77,13 +109,40 @@ public class ApiTokenProperty extends UserProperty { } public boolean matchesPassword(String password) { - return getApiToken().equals(password); + return getApiTokenInsecure().equals(password); + } + + private boolean hasPermissionToSeeToken() { + final Jenkins jenkins = Jenkins.getInstance(); + if (jenkins == null) { + return false; // Should not happen - we don't display UIs in this stage + } + + // Administrators can do whatever they want + if (SHOW_TOKEN_TO_ADMINS && jenkins.hasPermission(Jenkins.ADMINISTER)) { + return true; + } + + + final User current = User.current(); + if (current == null) { // Anonymous + return false; + } + + // SYSTEM user is always eligible to see tokens + if (Jenkins.getAuthentication() == ACL.SYSTEM) { + return true; + } + + //TODO: replace by IdStrategy in newer Jenkins versions + //return User.idStrategy().equals(user.getId(), current.getId()); + return StringUtils.equals(user.getId(), current.getId()); } public void changeApiToken() throws IOException { + user.checkPermission(Jenkins.ADMINISTER); _changeApiToken(); - if (user!=null) - user.save(); + user.save(); } private void _changeApiToken() { @@ -124,7 +183,9 @@ public class ApiTokenProperty extends UserProperty { p.changeApiToken(); } rsp.setHeader("script","document.getElementById('apiToken').value='"+p.getApiToken()+"'"); - return HttpResponses.html(Messages.ApiTokenProperty_ChangeToken_Success()); + return HttpResponses.html(p.hasPermissionToSeeToken() + ? Messages.ApiTokenProperty_ChangeToken_Success() + : Messages.ApiTokenProperty_ChangeToken_SuccessHidden()); } } diff --git a/core/src/main/java/jenkins/security/BasicHeaderAuthenticator.java b/core/src/main/java/jenkins/security/BasicHeaderAuthenticator.java index bd6a9bd7e8b4a5c408c689be27f063ff5a29bfd8..ade67de48a51a28443255c1c31b7c82fae483099 100644 --- a/core/src/main/java/jenkins/security/BasicHeaderAuthenticator.java +++ b/core/src/main/java/jenkins/security/BasicHeaderAuthenticator.java @@ -2,7 +2,6 @@ package jenkins.security; import hudson.ExtensionList; import hudson.ExtensionPoint; -import jenkins.model.Jenkins; import org.acegisecurity.Authentication; import javax.servlet.ServletException; diff --git a/core/src/main/java/jenkins/security/BasicHeaderProcessor.java b/core/src/main/java/jenkins/security/BasicHeaderProcessor.java index 6bec1a2e4a2a660565113aaf7d54b77dc13f333a..1469fa841eacca4bf5cd6d01a21def7d85bad7c3 100644 --- a/core/src/main/java/jenkins/security/BasicHeaderProcessor.java +++ b/core/src/main/java/jenkins/security/BasicHeaderProcessor.java @@ -158,5 +158,5 @@ public class BasicHeaderProcessor implements Filter { public void destroy() { } - private static final Logger LOGGER = Logger.getLogger(ApiTokenFilter.class.getName()); + private static final Logger LOGGER = Logger.getLogger(BasicHeaderProcessor.class.getName()); } diff --git a/core/src/main/java/jenkins/security/ConfidentialKey.java b/core/src/main/java/jenkins/security/ConfidentialKey.java index a0167f478d680e5fe1b8931170cb8ca044384fea..a9ac452768dce7218e539bdcf13890670b84d63b 100644 --- a/core/src/main/java/jenkins/security/ConfidentialKey.java +++ b/core/src/main/java/jenkins/security/ConfidentialKey.java @@ -3,7 +3,6 @@ package jenkins.security; import hudson.scm.SCM; import hudson.tasks.Builder; import hudson.util.Secret; -import jenkins.slaves.JnlpSlaveAgentProtocol; import javax.annotation.CheckForNull; import java.io.IOException; diff --git a/core/src/main/java/jenkins/security/ConfidentialStore.java b/core/src/main/java/jenkins/security/ConfidentialStore.java index 9b3efdbec6956319f2b2f0eb26eea771789d6d47..1c747b32c87d76e2c34607dcbdf493e255cbf628 100644 --- a/core/src/main/java/jenkins/security/ConfidentialStore.java +++ b/core/src/main/java/jenkins/security/ConfidentialStore.java @@ -2,7 +2,6 @@ package jenkins.security; import hudson.Extension; import hudson.Lookup; -import hudson.init.InitMilestone; import hudson.util.Secret; import hudson.util.Service; import jenkins.model.Jenkins; @@ -11,7 +10,6 @@ import org.kohsuke.MetaInfServices; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import java.io.IOException; -import java.security.SecureRandom; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; diff --git a/core/src/main/java/jenkins/security/LastGrantedAuthoritiesProperty.java b/core/src/main/java/jenkins/security/LastGrantedAuthoritiesProperty.java index 8fc7042d0c708f9fd6f3229497285c99d9b8ea14..3f5924cabd64910de6e8ae2a3033c4dabe75ac55 100644 --- a/core/src/main/java/jenkins/security/LastGrantedAuthoritiesProperty.java +++ b/core/src/main/java/jenkins/security/LastGrantedAuthoritiesProperty.java @@ -148,15 +148,11 @@ public class LastGrantedAuthoritiesProperty extends UserProperty { @Extension public static final class DescriptorImpl extends UserPropertyDescriptor { - public String getDisplayName() { - return null; // not visible - } - @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/java/jenkins/security/MasterToSlaveCallable.java b/core/src/main/java/jenkins/security/MasterToSlaveCallable.java index 8be5b98305c1eed129da241c454a76ce49b3ce4e..29837e973ad5656ebb30b8f4b31771007126ae1c 100644 --- a/core/src/main/java/jenkins/security/MasterToSlaveCallable.java +++ b/core/src/main/java/jenkins/security/MasterToSlaveCallable.java @@ -1,10 +1,8 @@ package jenkins.security; import hudson.remoting.Callable; -import org.jenkinsci.remoting.Role; import org.jenkinsci.remoting.RoleChecker; -import java.util.Collection; /** * Convenient {@link Callable} meant to be run on slave. diff --git a/core/src/main/java/jenkins/security/NonSerializableSecurityContext.java b/core/src/main/java/jenkins/security/NonSerializableSecurityContext.java index 5a22491327f47c0e42be8cfd9ff84047f9857eab..a37fd0ed40fa8484348301e2a135994c00cf2b31 100644 --- a/core/src/main/java/jenkins/security/NonSerializableSecurityContext.java +++ b/core/src/main/java/jenkins/security/NonSerializableSecurityContext.java @@ -28,7 +28,7 @@ import javax.servlet.http.HttpSession; * {@link Authentication} often contains {@link UserDetails} implemented by a plugin, * but when it's persisted as a part of {@link HttpSession}, such instance will never * de-serialize correctly because the container isn't aware of additional classloading - * in Hudson. + * in Jenkins. * *

* Jenkins doesn't work with a clustering anyway, and so it's better to just not persist diff --git a/core/src/main/java/jenkins/security/QueueItemAuthenticatorConfiguration.java b/core/src/main/java/jenkins/security/QueueItemAuthenticatorConfiguration.java index 05e00097c9bd3841171ed5c9572206ef1bc31569..9bc8ef0017109efa79588218dbd411e0fa7c1ebf 100644 --- a/core/src/main/java/jenkins/security/QueueItemAuthenticatorConfiguration.java +++ b/core/src/main/java/jenkins/security/QueueItemAuthenticatorConfiguration.java @@ -2,14 +2,11 @@ package jenkins.security; import edu.umd.cs.findbugs.annotations.NonNull; import hudson.Extension; -import hudson.model.AbstractProject; -import hudson.security.ACL; import hudson.util.DescribableList; import jenkins.model.GlobalConfiguration; import jenkins.model.GlobalConfigurationCategory; import jenkins.model.Jenkins; import net.sf.json.JSONObject; -import org.acegisecurity.Authentication; import org.kohsuke.stapler.StaplerRequest; import java.io.IOException; diff --git a/core/src/main/java/jenkins/security/RSAConfidentialKey.java b/core/src/main/java/jenkins/security/RSAConfidentialKey.java new file mode 100644 index 0000000000000000000000000000000000000000..c8a065f10b5ea17a2d9ec2a93f63daf55ad2350d --- /dev/null +++ b/core/src/main/java/jenkins/security/RSAConfidentialKey.java @@ -0,0 +1,111 @@ +/* + * 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 jenkins.security; + +import org.apache.commons.codec.binary.Base64; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.SecureRandom; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.RSAPublicKeySpec; + +/** + * RSA public/private key pair as {@link ConfidentialKey}. + * + *

+ * As per the design principle of {@link ConfidentialKey}, not exposing {@link PrivateKey} directly. + * Define subtypes for different use cases. + * + * @author Kohsuke Kawaguchi + */ +public abstract class RSAConfidentialKey extends ConfidentialKey { + private RSAPrivateKey priv; + private RSAPublicKey pub; + + public RSAConfidentialKey(String id) { + super(id); + } + + public RSAConfidentialKey(Class owner, String shortName) { + this(owner.getName() + '.' + shortName); + } + + /** + * Obtains the private key (lazily.) + *

+ * This method is not publicly exposed as per the design principle of {@link ConfidentialKey}. + * Instead of exposing private key, define methods that use them in specific way, such as + * {@link RSADigitalSignatureConfidentialKey}. + * + * @throws Error + * If key cannot be loaded for some reasons, we fail. + */ + protected synchronized RSAPrivateKey getPrivateKey() { + try { + if (priv == null) { + byte[] payload = load(); + if (payload == null) { + KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA"); + gen.initialize(2048, new SecureRandom()); // going beyond 2048 requires crypto extension + KeyPair keys = gen.generateKeyPair(); + priv = (RSAPrivateKey) keys.getPrivate(); + pub = (RSAPublicKey) keys.getPublic(); + store(priv.getEncoded()); + } else { + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + priv = (RSAPrivateKey) keyFactory.generatePrivate(new PKCS8EncodedKeySpec(payload)); + + RSAPrivateCrtKey pks = (RSAPrivateCrtKey) priv; + pub = (RSAPublicKey) keyFactory.generatePublic( + new RSAPublicKeySpec(pks.getModulus(), pks.getPublicExponent())); + } + } + return priv; + } catch (IOException e) { + throw new Error("Failed to load the key: " + getId(), e); + } catch (GeneralSecurityException e) { + throw new Error("Failed to load the key: " + getId(), e); + } + } + + public RSAPublicKey getPublicKey() { + getPrivateKey(); + return pub; + } + + /** + * Gets base64-encoded public key. + */ + public String getEncodedPublicKey() { + return new String(Base64.encodeBase64(getPublicKey().getEncoded())); + } +} diff --git a/core/src/main/java/jenkins/security/RSADigitalSignatureConfidentialKey.java b/core/src/main/java/jenkins/security/RSADigitalSignatureConfidentialKey.java new file mode 100644 index 0000000000000000000000000000000000000000..5ff1b55bdc8d93d7d4340ef0cc8421d41390d7a4 --- /dev/null +++ b/core/src/main/java/jenkins/security/RSADigitalSignatureConfidentialKey.java @@ -0,0 +1,63 @@ +/* + * 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 jenkins.security; + +import java.io.UnsupportedEncodingException; +import java.security.GeneralSecurityException; +import java.security.Signature; +import java.security.interfaces.RSAPrivateKey; + +/** + * RSA digital signature as {@link ConfidentialKey} to prevent accidental leak of private key. + * + * @author Kohsuke Kawaguchi + */ +public class RSADigitalSignatureConfidentialKey extends RSAConfidentialKey { + public RSADigitalSignatureConfidentialKey(String id) { + super(id); + } + + public RSADigitalSignatureConfidentialKey(Class owner, String shortName) { + super(owner, shortName); + } + + /** + * Sign a message and base64 encode the signature. + */ + public String sign(String msg) { + try { + RSAPrivateKey key = getPrivateKey(); + Signature sig = Signature.getInstance(SIGNING_ALGORITHM + "with" + key.getAlgorithm()); + sig.initSign(key); + sig.update(msg.getBytes("UTF-8")); + return hudson.remoting.Base64.encode(sig.sign()); + } catch (GeneralSecurityException e) { + throw new SecurityException(e); + } catch (UnsupportedEncodingException e) { + throw new AssertionError(e); // UTF-8 is mandatory + } + } + + static final String SIGNING_ALGORITHM = "SHA256"; +} diff --git a/core/src/main/java/jenkins/security/SecurityListener.java b/core/src/main/java/jenkins/security/SecurityListener.java index e7e03a62603c1cb604c03a95d5a0e6789f1d1a3d..7cec8c0eea4afa72f446c03d781d80592c0a5443 100644 --- a/core/src/main/java/jenkins/security/SecurityListener.java +++ b/core/src/main/java/jenkins/security/SecurityListener.java @@ -33,7 +33,6 @@ import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.Nonnull; -import jenkins.model.Jenkins; import org.acegisecurity.GrantedAuthority; import org.acegisecurity.userdetails.UserDetails; @@ -80,12 +79,6 @@ public abstract class SecurityListener implements ExtensionPoint { */ protected abstract void loggedOut(@Nonnull String username); - // TODO event for authenticated via SSH key in CLI (SshCliAuthenticator) - // TODO event for authenticated via API token (ApiTokenFilter) - // TODO event for permission denied exception thrown (mainly ACL.checkPermission), and/or caught at top level (ExceptionTranslationFilter.handleException) - // TODO event for new user signed up (e.g. in HudsonPrivateSecurityRealm) - // TODO event for CAPTCHA failure - /** @since 1.569 */ public static void fireAuthenticated(@Nonnull UserDetails details) { if (LOGGER.isLoggable(Level.FINE)) { diff --git a/core/src/main/java/jenkins/security/SlaveToMasterCallable.java b/core/src/main/java/jenkins/security/SlaveToMasterCallable.java index 61265cbdea54544055eaa09eaa91136258c73c8a..2a3a35a42b21df6712be665a65dc7a82e236a27c 100644 --- a/core/src/main/java/jenkins/security/SlaveToMasterCallable.java +++ b/core/src/main/java/jenkins/security/SlaveToMasterCallable.java @@ -1,10 +1,8 @@ package jenkins.security; import hudson.remoting.Callable; -import org.jenkinsci.remoting.Role; import org.jenkinsci.remoting.RoleChecker; -import java.util.Collection; /** * Convenient {@link Callable} that are meant to run on the master (sent by slave/CLI/etc). diff --git a/core/src/main/java/jenkins/security/s2m/FilePathRuleConfig.java b/core/src/main/java/jenkins/security/s2m/FilePathRuleConfig.java index 76289186bd2e512acd5932d520a317457f9ddead..122d7e687d640cd5f257cbd8f76517630fa27b30 100644 --- a/core/src/main/java/jenkins/security/s2m/FilePathRuleConfig.java +++ b/core/src/main/java/jenkins/security/s2m/FilePathRuleConfig.java @@ -40,7 +40,7 @@ class FilePathRuleConfig extends ConfigDirectory if (line.isEmpty()) return null; line = line.replace("","/builds/"); - line = line.replace("","[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9]"); + line = line.replace("","(?:[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]_[0-9][0-9]-[0-9][0-9]-[0-9][0-9]|[0-9]+)"); line = line.replace("","/jobs/.+"); line = line.replace("","\\Q"+Jenkins.getInstance().getRootDir().getPath()+"\\E"); diff --git a/core/src/main/java/jenkins/security/s2m/MasterKillSwitchConfiguration.java b/core/src/main/java/jenkins/security/s2m/MasterKillSwitchConfiguration.java index d83d436f4bf09570711f8c3132fb44139c692295..69bb8e34bc1f71b455047939d3ffe2cbd928e2a4 100644 --- a/core/src/main/java/jenkins/security/s2m/MasterKillSwitchConfiguration.java +++ b/core/src/main/java/jenkins/security/s2m/MasterKillSwitchConfiguration.java @@ -1,14 +1,13 @@ package jenkins.security.s2m; import hudson.Extension; +import javax.inject.Inject; import jenkins.model.GlobalConfiguration; import jenkins.model.GlobalConfigurationCategory; import jenkins.model.Jenkins; import net.sf.json.JSONObject; import org.kohsuke.stapler.StaplerRequest; -import javax.inject.Inject; - /** * Exposes {@link AdminWhitelistRule#masterKillSwitch} to the admin. * @@ -47,9 +46,7 @@ public class MasterKillSwitchConfiguration extends GlobalConfiguration { * Unless this option is relevant, we don't let users choose this. */ public boolean isRelevant() { - return jenkins.getComputers().length>1 // if there's no slave, there's no point - && jenkins.isUseSecurity() // if security is off, likewise this is pointless - ; + return jenkins.hasPermission(Jenkins.RUN_SCRIPTS) && jenkins.isUseSecurity(); } } diff --git a/core/src/main/java/jenkins/slaves/DefaultJnlpSlaveReceiver.java b/core/src/main/java/jenkins/slaves/DefaultJnlpSlaveReceiver.java index 1011db9334d714104c7ce79b97ce25f850a7e059..db08fa3c92d946e926c6a640adb7893c90cec72a 100644 --- a/core/src/main/java/jenkins/slaves/DefaultJnlpSlaveReceiver.java +++ b/core/src/main/java/jenkins/slaves/DefaultJnlpSlaveReceiver.java @@ -14,13 +14,15 @@ import java.util.Properties; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.logging.Level; import java.util.logging.Logger; /** * Match the name against the slave name and route the incoming JNLP agent as {@link Slave}. * * @author Kohsuke Kawaguchi - * @since 1.561 + * @since 1.561 + * @since 1.614 handle() returns true on handshake error as it required in JnlpAgentReceiver. */ @Extension public class DefaultJnlpSlaveReceiver extends JnlpAgentReceiver { @@ -28,12 +30,12 @@ public class DefaultJnlpSlaveReceiver extends JnlpAgentReceiver { public boolean handle(String nodeName, JnlpSlaveHandshake handshake) throws IOException, InterruptedException { SlaveComputer computer = (SlaveComputer) Jenkins.getInstance().getComputer(nodeName); - if(computer==null) { + if (computer==null) { return false; } Channel ch = computer.getChannel(); - if(ch !=null) { + if (ch !=null) { String c = handshake.getRequestProperty("Cookie"); if (c!=null && c.equals(ch.getProperty(COOKIE_NAME))) { // we think we are currently connected, but this request proves that it's from the party @@ -48,10 +50,15 @@ public class DefaultJnlpSlaveReceiver extends JnlpAgentReceiver { } } else { handshake.error(nodeName + " is already connected to this master. Rejecting this connection."); - return false; + return true; } } + if (!matchesSecret(nodeName,handshake)) { + handshake.error(nodeName + " can't be connected since the slave's secret does not match the handshake secret."); + return true; + } + Properties response = new Properties(); String cookie = generateCookie(); response.put("Cookie",cookie); @@ -66,6 +73,31 @@ public class DefaultJnlpSlaveReceiver extends JnlpAgentReceiver { return true; } + + /** + * Called after the client has connected to check if the slave secret matches the handshake secret + * + * @param nodeName + * Name of the incoming JNLP agent. All {@link JnlpAgentReceiver} shares a single namespace + * of names. The implementation needs to be able to tell which name belongs to them. + * + * @param handshake + * Encapsulation of the interaction with the incoming JNLP agent. + * + * @return + * true if the slave secret matches the handshake secret, false otherwise. + */ + private boolean matchesSecret(String nodeName, JnlpSlaveHandshake handshake){ + SlaveComputer computer = (SlaveComputer) Jenkins.getInstance().getComputer(nodeName); + String handshakeSecret = handshake.getRequestProperty("Secret-Key"); + // Verify that the slave secret matches the handshake secret. + if (!computer.getJnlpMac().equals(handshakeSecret)) { + LOGGER.log(Level.WARNING, "An attempt was made to connect as {0} from {1} with an incorrect secret", new Object[]{nodeName, handshake.getSocket()!=null?handshake.getSocket().getRemoteSocketAddress():null}); + return false; + } else { + return true; + } + } private String generateCookie() { byte[] cookie = new byte[32]; diff --git a/core/src/main/java/jenkins/slaves/JnlpAgentReceiver.java b/core/src/main/java/jenkins/slaves/JnlpAgentReceiver.java index 914447332f66447e1ec8657d0956df1a8c81c33d..b9ab82e4a3e717427b3ba5e0178da6a620cee7f8 100644 --- a/core/src/main/java/jenkins/slaves/JnlpAgentReceiver.java +++ b/core/src/main/java/jenkins/slaves/JnlpAgentReceiver.java @@ -3,7 +3,6 @@ package jenkins.slaves; import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.model.Slave; -import jenkins.model.Jenkins; import java.io.IOException; import java.util.Properties; diff --git a/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol.java b/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol.java index d82a42e51a74d265ed981d86058194e19f596f52..b82826fd579cd4ec2e44b4f46262a65038a7ecd7 100644 --- a/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol.java +++ b/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol.java @@ -9,6 +9,7 @@ import hudson.remoting.Engine; import hudson.slaves.SlaveComputer; import jenkins.AgentProtocol; import jenkins.model.Jenkins; +import jenkins.security.ChannelConfigurator; import jenkins.security.HMACConfidentialKey; import org.jenkinsci.remoting.nio.NioChannelHub; @@ -72,6 +73,7 @@ public class JnlpSlaveAgentProtocol extends AgentProtocol { * @deprecated as of 1.559 * Use {@link #Handler(NioChannelHub, Socket)} */ + @Deprecated public Handler(Socket socket) throws IOException { this(null,socket); } @@ -117,12 +119,16 @@ public class JnlpSlaveAgentProtocol extends AgentProtocol { try { ChannelBuilder cb = createChannelBuilder(nodeName); + for (ChannelConfigurator cc : ChannelConfigurator.all()) { + cc.onChannelBuilding(cb, computer); + } + computer.setChannel(cb.withHeaderStream(log).build(socket), log, new Listener() { @Override public void onClosed(Channel channel, IOException cause) { if(cause!=null) - LOGGER.log(Level.WARNING, Thread.currentThread().getName()+" for + " + nodeName + " terminated",cause); + LOGGER.log(Level.WARNING, Thread.currentThread().getName() + " for " + nodeName + " terminated", cause); try { socket.close(); } catch (IOException e) { diff --git a/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol2.java b/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol2.java index 30993bc08b1e50127fd11109a22be7913490875c..658cfedf0bf8910ad1a8143cea6956b2a19ab816 100644 --- a/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol2.java +++ b/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol2.java @@ -6,7 +6,6 @@ import org.jenkinsci.remoting.nio.NioChannelHub; import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.Socket; -import java.util.Properties; /** * {@link JnlpSlaveAgentProtocol} Version 2. @@ -36,6 +35,7 @@ public class JnlpSlaveAgentProtocol2 extends JnlpSlaveAgentProtocol { * @deprecated as of 1.559 * Use {@link #Handler2(NioChannelHub, Socket)} */ + @Deprecated public Handler2(Socket socket) throws IOException { super(socket); } @@ -58,7 +58,7 @@ public class JnlpSlaveAgentProtocol2 extends JnlpSlaveAgentProtocol { return; } - error("Unrecognized name: "+nodeName); + error("JNLP2-connect: rejected connection for node: " + nodeName); } } } diff --git a/core/src/main/java/jenkins/slaves/WorkspaceLocator.java b/core/src/main/java/jenkins/slaves/WorkspaceLocator.java index ff40093b6cbc7a1fc83ebd3b0c1727b64a6a4e69..7c7cb382587073ce35716b56726cbeea226c6aea 100644 --- a/core/src/main/java/jenkins/slaves/WorkspaceLocator.java +++ b/core/src/main/java/jenkins/slaves/WorkspaceLocator.java @@ -5,7 +5,6 @@ import hudson.ExtensionPoint; import hudson.FilePath; import hudson.model.Node; import hudson.model.TopLevelItem; -import jenkins.model.Jenkins; /** * Allow extensions to override workspace locations diff --git a/core/src/main/java/jenkins/slaves/restarter/SlaveRestarter.java b/core/src/main/java/jenkins/slaves/restarter/SlaveRestarter.java index e0c7c2f9124d81a47ab432b324b74e1ebcdecb8a..84e88202c9c53525db977847bd0fd768a7ecc5a4 100644 --- a/core/src/main/java/jenkins/slaves/restarter/SlaveRestarter.java +++ b/core/src/main/java/jenkins/slaves/restarter/SlaveRestarter.java @@ -2,7 +2,6 @@ package jenkins.slaves.restarter; import hudson.ExtensionList; import hudson.ExtensionPoint; -import jenkins.model.Jenkins; import java.io.Serializable; import java.util.logging.Logger; @@ -11,7 +10,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/java/jenkins/slaves/restarter/WinswSlaveRestarter.java b/core/src/main/java/jenkins/slaves/restarter/WinswSlaveRestarter.java index 35c606cdcd3d4c47f08cfd9130dc11047b207da9..f9bd660a2133e260abdfc64d70fbed318ebb6d44 100644 --- a/core/src/main/java/jenkins/slaves/restarter/WinswSlaveRestarter.java +++ b/core/src/main/java/jenkins/slaves/restarter/WinswSlaveRestarter.java @@ -51,7 +51,9 @@ public class WinswSlaveRestarter extends SlaveRestarter { // so it's possible that we end up in the situation where jenkins-slave.exe doesn't support // this command. If that is the case, there's nothing we can do about it. int r = exec("restart!"); - throw new IOException("Restart failure. '"+exe+" restart' completed with "+r+" but I'm still alive"); + throw new IOException("Restart failure. '"+exe+" restart' completed with "+r+" but I'm still alive! " + + "See https://wiki.jenkins-ci.org/display/JENKINS/Distributed+builds#Distributedbuilds-Windowsslaveserviceupgrades" + + " for a possible explanation and solution"); } private static final Logger LOGGER = Logger.getLogger(WinswSlaveRestarter.class.getName()); diff --git a/core/src/main/java/jenkins/slaves/systemInfo/SlaveSystemInfo.java b/core/src/main/java/jenkins/slaves/systemInfo/SlaveSystemInfo.java index 6b39684f7552c2e4ed73ff491e043eb2e8f95cf0..16a5352d09aad470496420168cc9d4e267a1b79e 100644 --- a/core/src/main/java/jenkins/slaves/systemInfo/SlaveSystemInfo.java +++ b/core/src/main/java/jenkins/slaves/systemInfo/SlaveSystemInfo.java @@ -3,7 +3,6 @@ package jenkins.slaves.systemInfo; import hudson.ExtensionList; import hudson.ExtensionPoint; import hudson.model.Computer; -import jenkins.model.Jenkins; /** * Extension point that contributes to the system information page of {@link Computer}. diff --git a/core/src/main/java/jenkins/tasks/SimpleBuildStep.java b/core/src/main/java/jenkins/tasks/SimpleBuildStep.java index 50b2fb8ca79951c9efd3af3f260276af890c5009..c99b15b71770242324b9d4224a8596d80898d1b0 100644 --- a/core/src/main/java/jenkins/tasks/SimpleBuildStep.java +++ b/core/src/main/java/jenkins/tasks/SimpleBuildStep.java @@ -28,19 +28,13 @@ import hudson.AbortException; import hudson.Extension; import hudson.FilePath; import hudson.Launcher; -import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.Action; -import hudson.model.BuildListener; -import hudson.model.Computer; -import hudson.model.Executor; import hudson.model.InvisibleAction; import hudson.model.Job; import hudson.model.Run; import hudson.model.TaskListener; import hudson.tasks.BuildStep; -import hudson.tasks.BuildStepDescriptor; -import hudson.tasks.BuildStepMonitor; import hudson.tasks.Builder; import hudson.tasks.Publisher; import java.io.IOException; @@ -81,18 +75,22 @@ public interface SimpleBuildStep extends BuildStep { * @throws InterruptedException if the step is interrupted * @throws IOException if something goes wrong; use {@link AbortException} for a polite error */ - void perform(@Nonnull Run run, @Nonnull FilePath workspace, @Nonnull Launcher launcher, @Nonnull TaskListener listener) throws InterruptedException, IOException; + void perform(@Nonnull Run run, @Nonnull FilePath workspace, @Nonnull Launcher launcher, + @Nonnull TaskListener listener) throws InterruptedException, IOException; /** - * Marker for explicitly added build actions (as {@link Run#addAction}) which should imply a transient project action ({@link Job#getActions}) when present on the {@link Job#getLastSuccessfulBuild}. - * This can serve as a substitute for {@link BuildStep#getProjectActions} which does not assume that the project can enumerate the steps it would run before they are actually run. + * Marker for explicitly added build actions (as {@link Run#addAction}) which should imply a transient project + * action ({@link Job#getActions}) when present on the {@link Job#getLastSuccessfulBuild}. + * This can serve as a substitute for {@link BuildStep#getProjectActions} which does not assume that the project + * can enumerate the steps it would run before they are actually run. * (Use {@link InvisibleAction} as a base class if you do not need to show anything in the build itself.) */ interface LastBuildAction extends Action { /** * Optionally add some actions to the project owning this build. - * @return zero or more transient actions; if you need to know the {@link Job}, implement {@link RunAction2} and use {@link Run#getParent} + * @return zero or more transient actions; + * if you need to know the {@link Job}, implement {@link RunAction2} and use {@link Run#getParent} */ Collection getProjectActions(); @@ -100,14 +98,18 @@ public interface SimpleBuildStep extends BuildStep { @SuppressWarnings("rawtypes") @Restricted(DoNotUse.class) - @Extension public static final class LastBuildActionFactory extends TransientActionFactory { + @Extension + public static final class LastBuildActionFactory extends TransientActionFactory { - @Override public Class type() { + @Override + public Class type() { return Job.class; } - @Override public Collection createFor(Job j) { - List actions = new LinkedList(); + @Nonnull + @Override + public Collection createFor(@Nonnull Job j) { + List actions = new LinkedList<>(); Run r = j.getLastSuccessfulBuild(); if (r != null) { for (LastBuildAction a : r.getActions(LastBuildAction.class)) { @@ -115,7 +117,8 @@ public interface SimpleBuildStep extends BuildStep { } } // TODO should there be an option to check lastCompletedBuild even if it failed? - // Not useful for, say, TestResultAction, since if you have a build that fails before recording test results, the job would then have no TestResultProjectAction. + // Not useful for, say, TestResultAction, since if you have a build that fails before recording test + // results, the job would then have no TestResultProjectAction. return actions; } diff --git a/core/src/main/java/jenkins/tasks/SimpleBuildWrapper.java b/core/src/main/java/jenkins/tasks/SimpleBuildWrapper.java index d23a202f95b65af936f3b4f5e8ad6e34815327f5..df9ba97c96a097bacd2c1a7ea93ee6bd6ed06acc 100644 --- a/core/src/main/java/jenkins/tasks/SimpleBuildWrapper.java +++ b/core/src/main/java/jenkins/tasks/SimpleBuildWrapper.java @@ -28,11 +28,11 @@ import hudson.AbortException; import hudson.EnvVars; import hudson.FilePath; import hudson.Launcher; +import hudson.console.ConsoleLogFilter; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.Action; import hudson.model.BuildListener; -import hudson.model.Computer; import hudson.model.Run; import hudson.model.TaskListener; import hudson.tasks.BuildWrapper; @@ -177,34 +177,51 @@ public abstract class SimpleBuildWrapper extends BuildWrapper { } } + /** + * Allows this wrapper to decorate log output. + * @param build as is passed to {@link #setUp(Context, Run, FilePath, Launcher, TaskListener, EnvVars)} + * @return a filter which ignores its {@code build} parameter and is {@link Serializable}; or null (the default) + * @since 1.608 + */ + public @CheckForNull ConsoleLogFilter createLoggerDecorator(@Nonnull Run build) { + return null; + } + @Override public final OutputStream decorateLogger(AbstractBuild build, OutputStream logger) throws IOException, InterruptedException, Run.RunnerAbortedException { - // Doubtful this can be supported. - // Decorating a TaskListener would be more reasonable. - // But for an AbstractBuild this is called early in Run.execute, before setUp. - // And for other kinds of builds, it is unclear what this would even mean. - return logger; + ConsoleLogFilter filter = createLoggerDecorator(build); + return filter != null ? filter.decorateLogger(build, logger) : logger; } - @Override public final Launcher decorateLauncher(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException, Run.RunnerAbortedException { + /** + * May be overridden but this will only take effect when used as a {@link BuildWrapper} on an {@link AbstractProject}. + *

{@inheritDoc} + * @since 1.608 + */ + @Override public Launcher decorateLauncher(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException, Run.RunnerAbortedException { + return super.decorateLauncher(build, launcher, listener); // TODO reasonable to decorate Launcher within a dynamic scope, but this signature does not mix well with Context pattern. // Called from AbstractBuildExecution.createLauncher; how do we track what is decorating what? // Would have to keep something like a LaunchedDecorator, not an actual Launcher, in Context. // And createLauncher is called before even preCheckout, so much too early for the Context to have been prepared. // Could perhaps create a proxy Launcher whose launch method checks some field in the Context remembered for the build. - return launcher; } /** - * May not do anything. - * {@inheritDoc} + * May be overridden but this will only take effect when used as a {@link BuildWrapper} on an {@link AbstractProject}. + *

{@inheritDoc} + * @since 1.608 */ - @Override public final void makeBuildVariables(AbstractBuild build, Map variables) {} + @Override public void makeBuildVariables(AbstractBuild build, Map variables) { + super.makeBuildVariables(build, variables); + } /** - * May not do anything. - * {@inheritDoc} + * May be overridden but this will only take effect when used as a {@link BuildWrapper} on an {@link AbstractProject}. + *

{@inheritDoc} + * @since 1.608 */ - @Override public final void makeSensitiveBuildVariables(AbstractBuild build, Set sensitiveVariables) { + @Override public void makeSensitiveBuildVariables(AbstractBuild build, Set sensitiveVariables) { + super.makeSensitiveBuildVariables(build, sensitiveVariables); // TODO determine if there is a meaningful way to generalize this; perhaps as a new [Run]Action recording sensitiveVariables? // Complicated by the fact that in principle someone could call getSensitiveBuildVariables *before* the wrapper starts and actually sets those variables, // though in practice the likely use cases would come later, and perhaps it is acceptable to omit the names of variables which are yet to be set. diff --git a/core/src/main/java/jenkins/triggers/ReverseBuildTrigger.java b/core/src/main/java/jenkins/triggers/ReverseBuildTrigger.java index be6078eb51b9ec516243cfacebe462e9b2adc1d3..530533dac663a8523af4dc2387df4c7dae58a4c6 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; @@ -71,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}, @@ -83,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; } @@ -103,7 +107,7 @@ public final class ReverseBuildTrigger extends Trigger implements Dependenc private boolean shouldTrigger(Run upstreamBuild, TaskListener listener) { Jenkins jenkins = Jenkins.getInstance(); - if (jenkins == null) { + if (jenkins == null || job == null) { return false; } // This checks Item.READ also on parent folders; note we are checking as the upstream auth currently: @@ -143,7 +147,7 @@ public final class ReverseBuildTrigger extends Trigger implements Dependenc } } - @Override public void start(Job project, boolean newInstance) { + @Override public void start(@Nonnull Job project, boolean newInstance) { super.start(project, newInstance); SecurityContext orig = ACL.impersonate(ACL.SYSTEM); try { @@ -154,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); @@ -221,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)) { @@ -237,11 +241,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 +257,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; diff --git a/core/src/main/java/jenkins/util/AntClassLoader.java b/core/src/main/java/jenkins/util/AntClassLoader.java index 6416a57ddc2c7f8a4c07a1b291c07b4629f0e46d..16c7c374742507b66dcf8852ef89c28cfd6b33a0 100644 --- a/core/src/main/java/jenkins/util/AntClassLoader.java +++ b/core/src/main/java/jenkins/util/AntClassLoader.java @@ -582,6 +582,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @deprecated since 1.6.x. * Use Class.forName with initialize=true instead. */ + @Deprecated public static void initializeClass(Class theClass) { // ***HACK*** We ask the VM to create an instance // by voluntarily providing illegal arguments to force diff --git a/core/src/main/java/jenkins/util/AtmostOneTaskExecutor.java b/core/src/main/java/jenkins/util/AtmostOneTaskExecutor.java index b6369a81a15e1faa6af3666bbd7f9a14a2254bf8..a030ecdf4ea13c9c7a74dc868330951630be52c7 100644 --- a/core/src/main/java/jenkins/util/AtmostOneTaskExecutor.java +++ b/core/src/main/java/jenkins/util/AtmostOneTaskExecutor.java @@ -2,6 +2,8 @@ package jenkins.util; import com.google.common.util.concurrent.SettableFuture; import hudson.remoting.AtmostOneThreadExecutor; +import hudson.util.DaemonThreadFactory; +import hudson.util.NamingThreadFactory; import java.util.concurrent.Callable; import java.util.concurrent.Executor; @@ -63,7 +65,12 @@ public class AtmostOneTaskExecutor { } public AtmostOneTaskExecutor(Callable task) { - this(new AtmostOneThreadExecutor(),task); + this(new AtmostOneThreadExecutor(new NamingThreadFactory( + new DaemonThreadFactory(), + String.format("AtmostOneTaskExecutor[%s]", task) + )), + task + ); } public synchronized Future submit() { diff --git a/core/src/main/java/jenkins/util/JSONSignatureValidator.java b/core/src/main/java/jenkins/util/JSONSignatureValidator.java index b36f4e399f8f1a1f2d2be0c0e1c1acdac620a03b..76d422cd90743110d7279db0ecb926efc6d10acc 100644 --- a/core/src/main/java/jenkins/util/JSONSignatureValidator.java +++ b/core/src/main/java/jenkins/util/JSONSignatureValidator.java @@ -135,6 +135,9 @@ public class JSONSignatureValidator { // which isn't useful at all Set anchors = new HashSet(); // CertificateUtil.getDefaultRootCAs(); Jenkins j = Jenkins.getInstance(); + if (j == null) { + return anchors; + } for (String cert : (Set) j.servletContext.getResourcePaths("/WEB-INF/update-center-rootCAs")) { if (cert.endsWith("/") || cert.endsWith(".txt")) { continue; // skip directories also any text files that are meant to be documentation diff --git a/core/src/main/java/jenkins/util/ProgressiveRendering.java b/core/src/main/java/jenkins/util/ProgressiveRendering.java index 11cd35c0e28207fb55d52220b2b76a0047d2c82c..103081a29df4ebccaf65dae4ffa483c3c67cbb03 100644 --- a/core/src/main/java/jenkins/util/ProgressiveRendering.java +++ b/core/src/main/java/jenkins/util/ProgressiveRendering.java @@ -25,7 +25,6 @@ package jenkins.util; import edu.umd.cs.findbugs.annotations.SuppressWarnings; -import hudson.model.AbstractItem; import java.lang.reflect.Field; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; diff --git a/core/src/main/java/jenkins/util/VirtualFile.java b/core/src/main/java/jenkins/util/VirtualFile.java index 3ccd3f09c69a2caad4878ee31f47059eea4de0a0..f6f592cd5ff2afbd8aa1913062ea26a63fcbbf18 100644 --- a/core/src/main/java/jenkins/util/VirtualFile.java +++ b/core/src/main/java/jenkins/util/VirtualFile.java @@ -33,12 +33,17 @@ import hudson.util.DirScanner; import hudson.util.FileVisitor; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.net.URI; +import java.nio.file.InvalidPathException; +import java.nio.file.LinkOption; import java.util.ArrayList; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.annotation.Nonnull; import jenkins.MasterToSlaveFileCallable; @@ -158,7 +163,7 @@ public abstract class VirtualFile implements Comparable, Serializab /** * Does case-insensitive comparison. - * @inheritDoc + * {@inheritDoc} */ @Override public final int compareTo(VirtualFile o) { return getName().compareToIgnoreCase(o.getName()); @@ -166,7 +171,7 @@ public abstract class VirtualFile implements Comparable, Serializab /** * Compares according to {@link #toURI}. - * @inheritDoc + * {@inheritDoc} */ @Override public final boolean equals(Object obj) { return obj instanceof VirtualFile && toURI().equals(((VirtualFile) obj).toURI()); @@ -174,7 +179,7 @@ public abstract class VirtualFile implements Comparable, Serializab /** * Hashes according to {@link #toURI}. - * @inheritDoc + * {@inheritDoc} */ @Override public final int hashCode() { return toURI().hashCode(); @@ -182,7 +187,7 @@ public abstract class VirtualFile implements Comparable, Serializab /** * Displays {@link #toURI}. - * @inheritDoc + * {@inheritDoc} */ @Override public final String toString() { return toURI().toString(); @@ -209,12 +214,14 @@ public abstract class VirtualFile implements Comparable, Serializab * @return a wrapper */ public static VirtualFile forFile(final File f) { - return new FileVF(f); + return new FileVF(f, f); } private static final class FileVF extends VirtualFile { private final File f; - FileVF(File f) { + private final File root; + FileVF(File f, File root) { this.f = f; + this.root = root; } @Override public String getName() { return f.getName(); @@ -223,46 +230,88 @@ public abstract class VirtualFile implements Comparable, Serializab return f.toURI(); } @Override public VirtualFile getParent() { - return forFile(f.getParentFile()); + return new FileVF(f.getParentFile(), root); } @Override public boolean isDirectory() throws IOException { + if (isIllegalSymlink()) { + return false; + } return f.isDirectory(); } @Override public boolean isFile() throws IOException { + if (isIllegalSymlink()) { + return false; + } return f.isFile(); } @Override public boolean exists() throws IOException { + if (isIllegalSymlink()) { + return false; + } return f.exists(); } @Override public VirtualFile[] list() throws IOException { + if (isIllegalSymlink()) { + return new VirtualFile[0]; + } File[] kids = f.listFiles(); if (kids == null) { return new VirtualFile[0]; } VirtualFile[] vfs = new VirtualFile[kids.length]; for (int i = 0; i < kids.length; i++) { - vfs[i] = forFile(kids[i]); + vfs[i] = new FileVF(kids[i], root); } return vfs; } @Override public String[] list(String glob) throws IOException { + if (isIllegalSymlink()) { + return new String[0]; + } return new Scanner(glob).invoke(f, null); } @Override public VirtualFile child(String name) { - return forFile(new File(f, name)); + return new FileVF(new File(f, name), root); } @Override public long length() throws IOException { + if (isIllegalSymlink()) { + return 0; + } return f.length(); } @Override public long lastModified() throws IOException { + if (isIllegalSymlink()) { + return 0; + } return f.lastModified(); } @Override public boolean canRead() throws IOException { + if (isIllegalSymlink()) { + return false; + } return f.canRead(); } @Override public InputStream open() throws IOException { + if (isIllegalSymlink()) { + throw new FileNotFoundException(f.getPath()); + } return new FileInputStream(f); } + private boolean isIllegalSymlink() { // TODO JENKINS-26838 + try { + String myPath = f.toPath().toRealPath(new LinkOption[0]).toString(); + String rootPath = root.toPath().toRealPath(new LinkOption[0]).toString(); + if (!myPath.equals(rootPath) && !myPath.startsWith(rootPath + File.separatorChar)) { + return true; + } + } catch (IOException x) { + Logger.getLogger(VirtualFile.class.getName()).log(Level.FINE, "could not determine symlink status of " + f, x); + } catch (InvalidPathException x2) { + // if this cannot be converted to a path, it cannot be an illegal symlink, as it cannot exist + Logger.getLogger(VirtualFile.class.getName()).log(Level.FINE, "Could not convert " + f + " to path", x2); + } + return false; + } } /** diff --git a/core/src/main/java/jenkins/util/groovy/GroovyHookScript.java b/core/src/main/java/jenkins/util/groovy/GroovyHookScript.java index 8a946534fd0858e58bd637b8e89d3853287bb774..168f3d00a198a77f5e2e28735e83b42910b556ec 100644 --- a/core/src/main/java/jenkins/util/groovy/GroovyHookScript.java +++ b/core/src/main/java/jenkins/util/groovy/GroovyHookScript.java @@ -3,8 +3,6 @@ package jenkins.util.groovy; import groovy.lang.Binding; import groovy.lang.GroovyCodeSource; import groovy.lang.GroovyShell; -import jenkins.model.Jenkins; - import java.io.File; import java.io.FileFilter; import java.io.IOException; @@ -12,9 +10,11 @@ import java.net.URL; import java.util.Arrays; import java.util.Set; import java.util.TreeSet; -import java.util.logging.Logger; - import static java.util.logging.Level.WARNING; +import java.util.logging.Logger; +import javax.annotation.Nonnull; +import javax.servlet.ServletContext; +import jenkins.model.Jenkins; /** * A collection of Groovy scripts that are executed as various hooks. @@ -40,9 +40,24 @@ import static java.util.logging.Level.WARNING; public class GroovyHookScript { private final String hook; private final Binding bindings = new Binding(); + private final ServletContext servletContext; + private final File home; + private final ClassLoader loader; + @Deprecated public GroovyHookScript(String hook) { + this(hook, Jenkins.getActiveInstance()); + } + + private GroovyHookScript(String hook, Jenkins j) { + this(hook, j.servletContext, j.getRootDir(), j.getPluginManager().uberClassLoader); + } + + public GroovyHookScript(String hook, @Nonnull ServletContext servletContext, @Nonnull File home, @Nonnull ClassLoader loader) { this.hook = hook; + this.servletContext = servletContext; + this.home = home; + this.loader = loader; } public GroovyHookScript bind(String name, Object o) { @@ -55,23 +70,22 @@ public class GroovyHookScript { } public void run() { - Jenkins j = Jenkins.getInstance(); final String hookGroovy = hook+".groovy"; final String hookGroovyD = hook+".groovy.d"; try { - URL bundled = j.servletContext.getResource("/WEB-INF/"+ hookGroovy); + URL bundled = servletContext.getResource("/WEB-INF/"+ hookGroovy); execute(bundled); } catch (IOException e) { LOGGER.log(WARNING, "Failed to execute /WEB-INF/"+hookGroovy,e); } - Set resources = j.servletContext.getResourcePaths("/WEB-INF/"+ hookGroovyD +"/"); + Set resources = servletContext.getResourcePaths("/WEB-INF/"+ hookGroovyD +"/"); if (resources!=null) { // sort to execute them in a deterministic order for (String res : new TreeSet(resources)) { try { - URL bundled = j.servletContext.getResource(res); + URL bundled = servletContext.getResource(res); execute(bundled); } catch (IOException e) { LOGGER.log(WARNING, "Failed to execute " + res, e); @@ -79,10 +93,10 @@ public class GroovyHookScript { } } - File script = new File(j.getRootDir(), hookGroovy); + File script = new File(home, hookGroovy); execute(script); - File scriptD = new File(j.getRootDir(), hookGroovyD); + File scriptD = new File(home, hookGroovyD); if (scriptD.isDirectory()) { File[] scripts = scriptD.listFiles(new FileFilter() { public boolean accept(File f) { @@ -129,7 +143,7 @@ public class GroovyHookScript { * Can be used to customize the environment in which the script runs. */ protected GroovyShell createShell() { - return new GroovyShell(Jenkins.getInstance().getPluginManager().uberClassLoader, bindings); + return new GroovyShell(loader, bindings); } private static final Logger LOGGER = Logger.getLogger(GroovyHookScript.class.getName()); diff --git a/core/src/main/java/jenkins/util/xml/FilteredFunctionContext.java b/core/src/main/java/jenkins/util/xml/FilteredFunctionContext.java new file mode 100644 index 0000000000000000000000000000000000000000..81048283deeef91736121a825aacaaade8599254 --- /dev/null +++ b/core/src/main/java/jenkins/util/xml/FilteredFunctionContext.java @@ -0,0 +1,77 @@ + +/* + * The MIT License + * + * Copyright (c) 2015, CloudBees, Inc. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package jenkins.util.xml; + +import org.jaxen.Function; +import org.jaxen.FunctionContext; +import org.jaxen.UnresolvableException; +import org.jaxen.XPathFunctionContext; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; + +/** + * {@link org.jaxen.FunctionContext} that removes some {@link org.dom4j.XPath} + * function names that are deemed bad as user input. + * + * @author Robert Sandell <rsandell@cloudbees.com>. + * @see org.jaxen.FunctionContext + * @see org.dom4j.XPath + * @see hudson.model.Api + */ +@Restricted(NoExternalUse.class) +public class FilteredFunctionContext implements FunctionContext { + + /** + * Default set of "bad" function names. + */ + private static final Set DEFAULT_ILLEGAL_FUNCTIONS = Collections.unmodifiableSet(new HashSet( + Arrays.asList("document") + )); + private final FunctionContext base; + private final Set illegalFunctions; + + public FilteredFunctionContext(Set illegalFunctions) { + this.illegalFunctions = illegalFunctions; + base = XPathFunctionContext.getInstance(); + } + + public FilteredFunctionContext() { + this(DEFAULT_ILLEGAL_FUNCTIONS); + } + + @Override + public Function getFunction(String namespaceURI, String prefix, String localName) throws UnresolvableException { + if (localName != null && illegalFunctions.contains(localName.toLowerCase(Locale.ENGLISH))) { + throw new UnresolvableException("Illegal function: " + localName); + } + return base.getFunction(namespaceURI, prefix, localName); + } +} diff --git a/core/src/main/java/jenkins/util/xml/RestrictiveEntityResolver.java b/core/src/main/java/jenkins/util/xml/RestrictiveEntityResolver.java new file mode 100644 index 0000000000000000000000000000000000000000..1cf37c9bd5393cad4ac06b5726df6fc6bb6ffd1a --- /dev/null +++ b/core/src/main/java/jenkins/util/xml/RestrictiveEntityResolver.java @@ -0,0 +1,32 @@ +package jenkins.util.xml; + +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import java.io.IOException; + +/** + * An EntityResolver that will fail to resolve any entities. + * Useful in preventing External XML Entity injection attacks. + */ +@Restricted(NoExternalUse.class) +public final class RestrictiveEntityResolver implements EntityResolver { + + public final static RestrictiveEntityResolver INSTANCE = new RestrictiveEntityResolver(); + + private RestrictiveEntityResolver() { + // prevent multiple instantiation. + super(); + } + + /** + * Throws a SAXException if this tried to resolve any entity. + */ + @Override + public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException { + throw new SAXException("Refusing to resolve entity with publicId(" + publicId + ") and systemId (" + systemId + ")"); + } +} diff --git a/core/src/main/java/jenkins/util/xml/XMLUtils.java b/core/src/main/java/jenkins/util/xml/XMLUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..84e6f6151bf6feba4b8589cb3ee4a8bea4d4120d --- /dev/null +++ b/core/src/main/java/jenkins/util/xml/XMLUtils.java @@ -0,0 +1,99 @@ +package jenkins.util.xml; + +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.Logger; +import javax.annotation.Nonnull; +import javax.xml.XMLConstants; +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.sax.SAXTransformerFactory; + +/** + * Utilities useful when working with various XML types. + */ +@Restricted(NoExternalUse.class) +public final class XMLUtils { + + private final static Logger LOGGER = LogManager.getLogManager().getLogger(XMLUtils.class.getName()); + private final static String DISABLED_PROPERTY_NAME = XMLUtils.class.getName() + ".disableXXEPrevention"; + + /** + * Transform the source to the output in a manner that is protected against XXE attacks. + * If the transform can not be completed safely then an IOException is thrown. + * Note - to turn off safety set the system property disableXXEPrevention to true. + * @param source The XML input to transform. - This should be a StreamSource or a + * SAXSource in order to be able to prevent XXE attacks. + * @param out The Result of transforming the source. + */ + public static void safeTransform(@Nonnull Source source, @Nonnull Result out) throws TransformerException, + SAXException { + + InputSource src = SAXSource.sourceToInputSource(source); + if (src != null) { + SAXTransformerFactory stFactory = (SAXTransformerFactory) TransformerFactory.newInstance(); + stFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + + XMLReader xmlReader = XMLReaderFactory.createXMLReader(); + try { + xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", false); + } + catch (SAXException ignored) { /* ignored */ } + try { + xmlReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + } + catch (SAXException ignored) { /* ignored */ } + // defend against XXE + // the above features should strip out entities - however the feature may not be supported depending + // on the xml implementation used and this is out of our control. + // So add a fallback plan if all else fails. + xmlReader.setEntityResolver(RestrictiveEntityResolver.INSTANCE); + SAXSource saxSource = new SAXSource(xmlReader, src); + _transform(saxSource, out); + } + else { + // for some reason we could not convert source + // this applies to DOMSource and StAXSource - and possibly 3rd party implementations... + // a DOMSource can already be compromised as it is parsed by the time it gets to us. + if (Boolean.getBoolean(DISABLED_PROPERTY_NAME)) { + LOGGER.log(Level.WARNING, "XML external entity (XXE) prevention has been disabled by the system " + + "property {0}=true Your system may be vulnerable to XXE attacks.", DISABLED_PROPERTY_NAME); + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.log(Level.FINE, "Caller stack trace: ", new Exception("XXE Prevention caller history")); + } + _transform(source, out); + } + else { + throw new TransformerException("Could not convert source of type " + source.getClass() + " and " + + "XXEPrevention is enabled."); + } + } + } + + /** + * potentially unsafe XML transformation. + * @param source The XML input to transform. + * @param out The Result of transforming the source. + */ + private static void _transform(Source source, Result out) throws TransformerException { + TransformerFactory factory = TransformerFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + + // this allows us to use UTF-8 for storing data, + // plus it checks any well-formedness issue in the submitted data. + Transformer t = factory.newTransformer(); + t.transform(source, out); + } + +} diff --git a/core/src/main/java/jenkins/util/xstream/CriticalXStreamException.java b/core/src/main/java/jenkins/util/xstream/CriticalXStreamException.java new file mode 100644 index 0000000000000000000000000000000000000000..4c098ff1e409e5bb11bbdf103dfed183e5a33844 --- /dev/null +++ b/core/src/main/java/jenkins/util/xstream/CriticalXStreamException.java @@ -0,0 +1,41 @@ +/* + * The MIT License + * + * Copyright (c) 2015 IKEDA Yasuyuki + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package jenkins.util.xstream; + +import com.thoughtworks.xstream.XStreamException; +import com.thoughtworks.xstream.converters.ConversionException; + +/** + * Wraps {@link XStreamException} to indicate it is critical for Jenkins. + * + * @since 1.625 + */ +public class CriticalXStreamException extends ConversionException { + private static final long serialVersionUID = 1L; + + public CriticalXStreamException(XStreamException cause) { + super(cause); + } +} diff --git a/core/src/main/java/jenkins/util/xstream/XStreamDOM.java b/core/src/main/java/jenkins/util/xstream/XStreamDOM.java index c5aad8c95c15d7fb62f4725954400deee707db40..4fa5e4d04c9b35d836507a3c809225b94f538d27 100644 --- a/core/src/main/java/jenkins/util/xstream/XStreamDOM.java +++ b/core/src/main/java/jenkins/util/xstream/XStreamDOM.java @@ -38,14 +38,10 @@ import com.thoughtworks.xstream.io.xml.XmlFriendlyReplacer; import com.thoughtworks.xstream.io.xml.XppDriver; import hudson.Util; import hudson.util.VariableResolver; -import hudson.util.XStream2; -import org.apache.commons.io.IOUtils; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; -import java.io.StringReader; -import java.io.StringWriter; import java.io.Writer; import java.util.ArrayList; import java.util.HashMap; diff --git a/core/src/main/java/jenkins/widgets/HistoryPageEntry.java b/core/src/main/java/jenkins/widgets/HistoryPageEntry.java new file mode 100644 index 0000000000000000000000000000000000000000..b3aeaecedb8221aea3af1be4be4c2bacbb29344b --- /dev/null +++ b/core/src/main/java/jenkins/widgets/HistoryPageEntry.java @@ -0,0 +1,70 @@ +/* + * 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 jenkins.widgets; + +import hudson.model.Queue; +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 { + + 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; + return (Long.MIN_VALUE + run.getNumber()); + } else if (entry instanceof Number) { + // Used for testing purposes because of JENKINS-30899 and JENKINS-30909 + return (Long.MIN_VALUE + ((Number) entry).longValue()); + } else { + return Run.QUEUE_ID_UNKNOWN; + } + } +} diff --git a/core/src/main/java/jenkins/widgets/HistoryPageFilter.java b/core/src/main/java/jenkins/widgets/HistoryPageFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..6101916958d7d2dd73299c60b7bab0f8098c0ea8 --- /dev/null +++ b/core/src/main/java/jenkins/widgets/HistoryPageFilter.java @@ -0,0 +1,326 @@ +/* + * 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 jenkins.widgets; + +import hudson.model.Job; +import hudson.model.Queue; +import hudson.model.Run; +import hudson.widgets.HistoryWidget; + +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 String searchString; + + // 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) { + this.searchString = searchString; + } + + /** + * 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) { + HistoryPageEntry entry = new HistoryPageEntry(item); + queueItems.add(entry); + updateNewestOldest(entry.getEntryId()); + } + + private void addRun(Run run) { + HistoryPageEntry entry = new HistoryPageEntry(run); + runs.add(entry); + updateNewestOldest(entry.getEntryId()); + } + + private void updateNewestOldest(long entryId) { + newestOnPage = Math.max(newestOnPage, entryId); + oldestOnPage = Math.min(oldestOnPage, entryId); + } + + 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 (searchString != null && !fitsSearchParams(item)) { + return false; + } + addQueueItem(item); + return true; + } else if (entry instanceof Run) { + Run run = (Run) entry; + if (searchString != null && !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())); + } + + private boolean fitsSearchParams(@Nonnull Queue.Item item) { + if (fitsSearchString(item.getDisplayName())) { + return true; + } else if (fitsSearchString(item.getId())) { + return true; + } + // Non of the fuzzy matches "liked" the search term. + return false; + } + + private boolean fitsSearchParams(@Nonnull Run run) { + if (searchString == null) { + return true; + } + + if (fitsSearchString(run.getDisplayName())) { + return true; + } else if (fitsSearchString(run.getDescription())) { + return true; + } else if (fitsSearchString(run.getNumber())) { + return true; + } else if (fitsSearchString(run.getQueueId())) { + return true; + } else if (fitsSearchString(run.getResult())) { + return true; + } + + // Non of the fuzzy matches "liked" the search term. + return false; + } + + private boolean fitsSearchString(Object data) { + if (searchString == null) { + return true; + } + + if (data != null) { + if (data instanceof Number) { + return data.toString().equals(searchString); + } else { + return data.toString().toLowerCase().contains(searchString); + } + } + + return false; + } +} diff --git a/core/src/main/resources/hudson/Messages.properties b/core/src/main/resources/hudson/Messages.properties index 2613298aff908330ce3b1b751a5832ef8c414d60..85c7803bfb3167d58b0a48d13b0250191d134f24 100644 --- a/core/src/main/resources/hudson/Messages.properties +++ b/core/src/main/resources/hudson/Messages.properties @@ -28,6 +28,7 @@ FilePath.validateAntFileMask.doesntMatchAndSuggest=\ FilePath.validateAntFileMask.portionMatchAndSuggest=\u2018{0}\u2019 doesn\u2019t match anything, although \u2018{1}\u2019 exists FilePath.validateAntFileMask.portionMatchButPreviousNotMatchAndSuggest=\u2018{0}\u2019 doesn\u2019t match anything: \u2018{1}\u2019 exists but not \u2018{2}\u2019 FilePath.validateAntFileMask.doesntMatchAnything=\u2018{0}\u2019 doesn\u2019t match anything +FilePath.validateAntFileMask.matchWithCaseInsensitive=\u2018{0}\u2019 doesn\u2019t match anything because it is treated case sensitively. You can deactivate case sensitivity to get matches FilePath.validateAntFileMask.doesntMatchAnythingAndSuggest=\u2018{0}\u2019 doesn\u2019t match anything: even \u2018{1}\u2019 doesn\u2019t exist FilePath.validateRelativePath.wildcardNotAllowed=Wildcard is not allowed here @@ -67,4 +68,6 @@ AboutJenkins.Description=See the version and license information. ProxyConfiguration.TestUrlRequired=Test URL is required. ProxyConfiguration.FailedToConnectViaProxy=Failed to connect to {0}. ProxyConfiguration.FailedToConnect=Failed to connect to {0} (code {1}). -ProxyConfiguration.Success=Success \ No newline at end of file +ProxyConfiguration.Success=Success + +Functions.NoExceptionDetails=No Exception details \ No newline at end of file diff --git a/core/src/main/resources/hudson/Messages_bg.properties b/core/src/main/resources/hudson/Messages_bg.properties new file mode 100644 index 0000000000000000000000000000000000000000..3f7b19a557b53a0b7ae4cf26b17f7043ce57ff8b --- /dev/null +++ b/core/src/main/resources/hudson/Messages_bg.properties @@ -0,0 +1,108 @@ +# The MIT License +# +# Bulgarian translation copyright 2015 Alexander Shopov . +# +# 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. + +FilePath.did_not_manage_to_validate_may_be_too_sl=\ + \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430\u0442\u0430 \u043d\u0430 \u201e{0}\u201c \u043d\u0435 \u0435 \u0437\u0430\u0432\u044a\u0440\u0448\u0438\u043b\u0430, \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440\u044a\u0442 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0435 \u043f\u0440\u0435\u043a\u0430\u043b\u0435\u043d\u043e \u0431\u0430\u0432\u0435\u043d. +FilePath.validateAntFileMask.whitespaceSeprator=\ + \u041f\u0440\u0430\u0437\u043d\u0438\u0442\u0435 \u0437\u043d\u0430\u0446\u0438 \u0432\u0435\u0447\u0435 \u043d\u0435 \u0441\u0435 \u043f\u043e\u043b\u0437\u0432\u0430\u0442 \u0437\u0430 \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u0438. \u041f\u043e\u043b\u0437\u0432\u0430\u0439\u0442\u0435 \u0437\u0430\u043f\u0435\u0442\u0430\u044f \u2014 \u201e,\u201c. +FilePath.validateAntFileMask.doesntMatchAndSuggest=\ + \u201e{0}\u201c \u043d\u0435 \u0441\u044a\u0432\u043f\u0430\u0434\u0430 \u0441 \u043d\u0438\u0449\u043e, \u043d\u043e \u201e{1}\u201c \u0441\u044a\u0432\u043f\u0430\u0434\u0430. \u0422\u043e\u0432\u0430 \u043b\u0438 \u0438\u043c\u0430\u0445\u0442\u0435 \u043f\u0440\u0435\u0434\u0432\u0438\u0434? +FilePath.validateAntFileMask.portionMatchAndSuggest=\ + \u201e{0}\u201c \u043d\u0435 \u0441\u044a\u0432\u043f\u0430\u0434\u0430 \u0441 \u043d\u0438\u0449\u043e, \u043d\u043e \u201e{1}\u201c \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430. +FilePath.validateAntFileMask.portionMatchButPreviousNotMatchAndSuggest=\ + \u201e{0}\u201c \u043d\u0435 \u0441\u044a\u0432\u043f\u0430\u0434\u0430 \u0441 \u043d\u0438\u0449\u043e: \u201e{1}\u201c \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430, \u043d\u043e \u043d\u0435 \u0438 \u201e{1}\u201c. +FilePath.validateAntFileMask.doesntMatchAnything=\ + \u201e{0}\u201c \u043d\u0435 \u0441\u044a\u0432\u043f\u0430\u0434\u0430 \u0441 \u043d\u0438\u0449\u043e. +FilePath.validateAntFileMask.matchWithCaseInsensitive=\ + \u201e{0}\u201c \u043d\u0435 \u0441\u044a\u0432\u043f\u0430\u0434\u0430 \u0441 \u043d\u0438\u0449\u043e, \u0437\u0430\u0449\u043e\u0442\u043e \u043f\u0440\u0430\u0432\u0438 \u0440\u0430\u0437\u043b\u0438\u043a\u0430 \u043c\u0435\u0436\u0434\u0443 \u0433\u043b\u0430\u0432\u043d\u0438 \u0438 \u043c\u0430\u043b\u043a\u0438 \u0431\u0443\u043a\u0432\u0438.\ + \u041c\u043e\u0436\u0435 \u0434\u0430 \u0438\u0437\u043a\u043b\u044e\u0447\u0438\u0442\u0435 \u0440\u0430\u0437\u043b\u0438\u0447\u0430\u0432\u0430\u043d\u0435\u0442\u043e, \u0437\u0430 \u0434\u0430 \u0438\u043c\u0430 \u0441\u044a\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044f. +FilePath.validateAntFileMask.doesntMatchAnythingAndSuggest=\ + \u201e{0}\u201c \u043d\u0435 \u0441\u044a\u0432\u043f\u0430\u0434\u0430 \u0441 \u043d\u0438\u0449\u043e, \u0434\u043e\u0440\u0438 \u0438 \u201e{1}\u201c \u043d\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430. + +FilePath.validateRelativePath.wildcardNotAllowed=\ + \u0417\u043d\u0430\u043a\u044a\u0442 \u201e*\u201c \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0441\u0435 \u043f\u043e\u043b\u0437\u0432\u0430 +FilePath.validateRelativePath.notFile=\ + \u201e{0}\u201c \u043d\u0435 \u0435 \u0444\u0430\u0439\u043b +FilePath.validateRelativePath.notDirectory=\ + \u201e{0}\u201c \u043d\u0435 \u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f +FilePath.validateRelativePath.noSuchFile=\ + \u041b\u0438\u043f\u0441\u0432\u0430 \u0444\u0430\u0439\u043b \u201e{0}\u201c +FilePath.validateRelativePath.noSuchDirectory=\ + \u041b\u0438\u043f\u0441\u0432\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u201e{0}\u201c + +PluginManager.PluginDoesntSupportDynamicLoad.RestartRequired=\ + \u041f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430\u0442\u0430 \u201e{0}\u201c \u043d\u0435 \u043f\u043e\u0434\u0434\u044a\u0440\u0436\u0430 \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u043d\u043e \u0437\u0430\u0440\u0435\u0436\u0434\u0430\u043d\u0435. \u041f\u0440\u043e\u043c\u044f\u043d\u0430\u0442\u0430 \u043d\u0430\u043b\u0430\u0433\u0430\ + \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 Jenkins. +PluginManager.PluginIsAlreadyInstalled.RestartRequired=\ + \u041f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430\u0442\u0430 \u201e{0}\u201c \u0432\u0435\u0447\u0435 \u0435 \u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0430. \u041f\u0440\u043e\u043c\u044f\u043d\u0430\u0442\u0430 \u043d\u0430\u043b\u0430\u0433\u0430 \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 Jenkins +Util.millisecond=\ + {0} {0,choice,0#\u043c\u0438\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u0438|1#\u043c\u0438\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u0430|1<\u043c\u0438\u043b\u0438\u0441\u0435\u043a\u0443\u043d\u0434\u0438} +Util.second=\ + {0} {0,choice,0#\u0441\u0435\u043a\u0443\u043d\u0434\u0438|1#\u0441\u0435\u043a\u0443\u043d\u0434\u0430|1\u0441\u0435\u043a\u0443\u043d\u0434\u0438} +Util.minute=\ + {0} {0,choice,0#\u043c\u0438\u043d\u0443\u0442\u0438|1#\u043c\u0438\u043d\u0443\u0442\u0430|1<\u043c\u0438\u043d\u0443\u0442\u0438} +Util.hour =\ + {0} {0,choice,0#\u0447\u0430\u0441\u0430|1#\u0447\u0430\u0441|1<\u0447\u0430\u0441\u0430} +Util.day =\ + {0} {0,choice,0#\u0434\u043d\u0438|1#\u0434\u0435\u043d|1<\u0434\u043d\u0438} +Util.month =\ + {0} {0,choice,0#\u043c\u0435\u0441\u0435\u0446\u0430|1#\u043c\u0435\u0441\u0435\u0446|1<\u043c\u0435\u0441\u0435\u0446\u0430} +Util.year =\ + {0} {0,choice,0#\u0433\u043e\u0434\u0438\u043d\u0438|1#\u0433\u043e\u0434\u0438\u043d\u0430|1<\u0433\u043e\u0434\u0438\u043d\u0438} + +# ideally it should be "{0} ago" but this saves more space +# another implication of this is that where we use this, +# we often want to add "ago" there +Util.pastTime=\ + {0} +FilePath.TildaDoesntWork=\ + \u201e~\u201c \u0441\u0435 \u043f\u043e\u0434\u0434\u044a\u0440\u0436\u0430 \u0441\u0430\u043c\u043e \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u0438\u0442\u0435 \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0442\u043e\u0440\u0438 \u043d\u0430 Unix \u0438 \u043d\u0438\u043a\u044a\u0434\u0435 \u0434\u0440\u0443\u0433\u0430\u0434\u0435. + +PluginManager.DisplayName=\ + \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0438 +PluginManager.PortNotANumber=\ + \u0421\u0442\u043e\u0439\u043d\u043e\u0441\u0442\u0442\u0430 \u0437\u0430 \u043f\u043e\u0440\u0442\u0430 \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0435 \u0447\u0438\u0441\u043b\u043e +PluginManager.PortNotInRange=\ + \u0421\u0442\u043e\u0439\u043d\u043e\u0441\u0442\u0442\u0430 \u0437\u0430 \u043f\u043e\u0440\u0442\u0430 \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0435 \u0432 \u0438\u043d\u0442\u0435\u0440\u0432\u0430\u043b\u0430 [{0}; {1}] +PluginManager.UploadPluginsPermission.Description=\ + \u041f\u0440\u0430\u0432\u043e\u0442\u043e \u0437\u0430 \u043a\u0430\u0447\u0432\u0430\u043d\u0435 \u043d\u0430 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0438 \u0434\u0430\u0432\u0430 \u0432\u044a\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442 \u043d\u0430 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f \u0434\u0430 \u043a\u0430\u0447\u0438\ + \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u043d\u0430 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430. +PluginManager.ConfigureUpdateCenterPermission.Description=\ + \u041f\u0440\u0430\u0432\u043e\u0442\u043e \u0437\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u0432\u0430\u043d\u0435 \u0434\u0430\u0432\u0430 \u0432\u044a\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442 \u043d\u0430 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f \u0434\u0430 \u043f\u0440\u043e\u043c\u0435\u043d\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u0442\u0435\ + \u043d\u0430 \u0441\u0430\u0439\u0442\u043e\u0432\u0435\u0442\u0435 \u0438 \u0441\u044a\u0440\u0432\u044a\u0440\u0430-\u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a. + +AboutJenkins.DisplayName=\ + \u041e\u0442\u043d\u043e\u0441\u043d\u043e Jenkins +AboutJenkins.Description=\ + \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0437\u0430 \u0432\u0435\u0440\u0441\u0438\u044f\u0442\u0430 \u0438 \u043b\u0438\u0446\u0435\u043d\u0437\u0430. + +ProxyConfiguration.TestUrlRequired=\ + \u0418\u0437\u0438\u0441\u043a\u0432\u0430 \u0441\u0435 \u0430\u0434\u0440\u0435\u0441 \u0437\u0430 \u043f\u0440\u043e\u0431\u0430. +ProxyConfiguration.FailedToConnectViaProxy=\ + \u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435 \u043a\u044a\u043c \u201e{0}\u201c. +ProxyConfiguration.FailedToConnect=\ + \u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u0430 \u0432\u0440\u044a\u0437\u043a\u0430 \u043a\u044a\u043c \u201e{0}\u201c (\u043a\u043e\u0434: {1}). +ProxyConfiguration.Success=\ + \u0423\u0441\u043f\u0435\u0445 + +Functions.NoExceptionDetails=\ + \u041d\u044f\u043c\u0430 \u0434\u043e\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u043d\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0437\u0430 \u0438\u0437\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435\u0442\u043e. diff --git a/core/src/main/resources/hudson/Messages_pl.properties b/core/src/main/resources/hudson/Messages_pl.properties new file mode 100644 index 0000000000000000000000000000000000000000..3c92922c2734aac9fb37ad5351a22815333fca97 --- /dev/null +++ b/core/src/main/resources/hudson/Messages_pl.properties @@ -0,0 +1,26 @@ +# The MIT License +# +# Copyright (c) 2016, Damian Szczepanik +# +# 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. + +PluginManager.DisplayName=Menad\u017Cer wtyczek +PluginManager.PluginIsAlreadyInstalled.RestartRequired=Wtyczka {0} by\u0142a ju\u017C zainstalowana. Jenkins musi zosta\u0107 ponownie uruchomiony, aby zaktualizowa\u0107 wtyczk\u0119. +AboutJenkins.DisplayName=Informacje o Jenkinsie +AboutJenkins.Description=Sprawd\u017A wersj\u0119 i licencj\u0119 diff --git a/core/src/main/resources/hudson/Messages_pt_BR.properties b/core/src/main/resources/hudson/Messages_pt_BR.properties index 21b4e0b23fafd8e39a1cb69b77b04b15f814a711..eb8bfb29f7bfe41f4692043b0c50b1d7ecab3260 100644 --- a/core/src/main/resources/hudson/Messages_pt_BR.properties +++ b/core/src/main/resources/hudson/Messages_pt_BR.properties @@ -25,17 +25,20 @@ FilePath.validateAntFileMask.whitespaceSeprator=\ FilePath.validateAntFileMask.doesntMatchAndSuggest=\ ''{0}'' n\u00e3o corresponde a nada, mas ''{1}'' sim. Talvez seja isto que voc\u00ea quis dizer? FilePath.validateRelativePath.noSuchDirectory=Diret\u00f3rio n\u00e3o encontrado: ''{0}'' -FilePath.TildaDoesntWork= ''~'' s\u00f3 \u00e9 suportado apenas pelo shell do Unix +# TODO pick one: +#FilePath.TildaDoesntWork= ''~'' s\u00f3 \u00e9 suportado apenas pelo shell do Unix +#FilePath.TildaDoesntWork=\u2018~\u2019 \u00e9 suportado somente em shell Unix. FilePath.validateAntFileMask.portionMatchAndSuggest=''{0}'' n\u00e3o foi encontrado, mas ''{1}'' existe FilePath.validateAntFileMask.doesntMatchAnything= ''{0}'' n\u00e3o foi encontrada nenhuma correspond\u00eancia -FilePath.validateAntFileMask.doesntMatchAnythingAndSuggest=''{0}'' n\u00e3o foi encontrada nenhuma correspond\u00eancia: mesmo ''{1}'' n\u00e3o existe FilePath.validateRelativePath.wildcardNotAllowed=Curinga n\u00e3o \u00e9 permitido aqui FilePath.validateRelativePath.notFile= ''{0}'' n\u00e3o \u00e9 um arquivo FilePath.validateRelativePath.notDirectory= ''{0}'' n\u00e3o \u00e9 um diret\u00f3rio FilePath.validateRelativePath.noSuchFile=''{0}'' arquivo n\u00e3o encontrado FilePath.validateAntFileMask.portionMatchButPreviousNotMatchAndSuggest= ''{0}'' n\u00e3o encontrado: ''{1}'' existe, mas n\u00e3o ''{2}'' -FilePath.validateAntFileMask.doesntMatchAnythingAndSuggest= ''{0}'' n\u00e3o localizado: mesmo ''{1}'' n\u00e3o existe +# TODO pick one: +#FilePath.validateAntFileMask.doesntMatchAnythingAndSuggest=''{0}'' n\u00e3o foi encontrada nenhuma correspond\u00eancia: mesmo ''{1}'' n\u00e3o existe +#FilePath.validateAntFileMask.doesntMatchAnythingAndSuggest=''{0}'' n\u00e3o localizado: mesmo ''{1}'' n\u00e3o existe PluginManager.PluginDoesntSupportDynamicLoad.RestartRequired={0} plugin n\u00e3o suporta hot deploy. O Jenkins precisa ser reiniciado para efetivar a atualiza\u00e7\u00e3o @@ -53,7 +56,6 @@ Util.year ={0} {0,choice,0#anos|1#ano|1 0) { + return elementsBySelector[0]; + } else { + return undefined; + } + } + + /** + * Wait for document onload. + */ + Element.observe(window, "load", function() { + var pluginsTable = select('#plugins'); + var pluginTRs = selectAll('.plugin', pluginsTable); + + if (!pluginTRs) { + return; + } + + var pluginI18n = select('.plugins.i18n'); + function i18n(messageId) { + return pluginI18n.getAttribute('data-' + messageId); + } + + // Create a map of the plugin rows, making it easy to index them. + var plugins = {}; + for (var i = 0; i < pluginTRs.length; i++) { + var pluginTR = pluginTRs[i]; + var pluginId = pluginTR.getAttribute('data-plugin-id'); + + plugins[pluginId] = pluginTR; + } + + function getPluginTR(pluginId) { + return plugins[pluginId]; + } + function getPluginName(pluginId) { + var pluginTR = getPluginTR(pluginId); + if (pluginTR) { + return pluginTR.getAttribute('data-plugin-name'); + } else { + return pluginId; + } + } + + function processSpanSet(spans) { + var ids = []; + for (var i = 0; i < spans.length; i++) { + var span = spans[i]; + var pluginId = span.getAttribute('data-plugin-id'); + var pluginName = getPluginName(pluginId); + + span.update(pluginName); + ids.push(pluginId); + } + return ids; + } + + function markAllDependantsDisabled(pluginTR) { + var jenkinsPluginMetadata = pluginTR.jenkinsPluginMetadata; + var dependantIds = jenkinsPluginMetadata.dependantIds; + + if (dependantIds) { + // If the only dependant is jenkins-core (it's a bundle plugin), then lets + // treat it like all its dependants are disabled. We're really only interested in + // dependant plugins in this case. + // Note: This does not cover "implied" dependencies ala detached plugins. See https://goo.gl/lQHrUh + if (dependantIds.length === 1 && dependantIds[0] === 'jenkins-core') { + pluginTR.addClassName('all-dependants-disabled'); + return; + } + + for (var i = 0; i < dependantIds.length; i++) { + var dependantId = dependantIds[i]; + + if (dependantId === 'jenkins-core') { + // Jenkins core is always enabled. So, make sure it's not possible to disable/uninstall + // any plugins that it "depends" on. (we sill have bundled plugins) + pluginTR.removeClassName('all-dependants-disabled'); + return; + } + + // The dependant is a plugin.... + var dependantPluginTr = getPluginTR(dependantId); + if (dependantPluginTr && dependantPluginTr.jenkinsPluginMetadata.enableInput.checked) { + // One of the plugins that depend on this plugin, is marked as enabled. + pluginTR.removeClassName('all-dependants-disabled'); + return; + } + } + } + + pluginTR.addClassName('all-dependants-disabled'); + } + + function markHasDisabledDependencies(pluginTR) { + var jenkinsPluginMetadata = pluginTR.jenkinsPluginMetadata; + var dependencyIds = jenkinsPluginMetadata.dependencyIds; + + if (dependencyIds) { + for (var i = 0; i < dependencyIds.length; i++) { + var dependencyPluginTr = getPluginTR(dependencyIds[i]); + if (dependencyPluginTr && !dependencyPluginTr.jenkinsPluginMetadata.enableInput.checked) { + // One of the plugins that this plugin depend on, is marked as disabled. + pluginTR.addClassName('has-disabled-dependency'); + return; + } + } + } + + pluginTR.removeClassName('has-disabled-dependency'); + } + + function setEnableWidgetStates() { + for (var i = 0; i < pluginTRs.length; i++) { + markAllDependantsDisabled(pluginTRs[i]); + markHasDisabledDependencies(pluginTRs[i]); + } + } + + function addDependencyInfoRow(pluginTR, infoTR) { + infoTR.addClassName('plugin-dependency-info'); + pluginTR.insert({ + after: infoTR + }); + } + function removeDependencyInfoRow(pluginTR) { + var nextRows = pluginTR.nextSiblings(); + if (nextRows && nextRows.length > 0) { + var nextRow = nextRows[0]; + if (nextRow.hasClassName('plugin-dependency-info')) { + nextRow.remove(); + } + } + } + + function populateEnableDisableInfo(pluginTR, infoContainer) { + var pluginMetadata = pluginTR.jenkinsPluginMetadata; + + // Remove all existing class info + infoContainer.removeAttribute('class'); + infoContainer.addClassName('enable-state-info'); + + if (pluginTR.hasClassName('has-disabled-dependency')) { + var dependenciesDiv = pluginMetadata.dependenciesDiv; + var dependencySpans = pluginMetadata.dependencies; + + infoContainer.update('

' + i18n('cannot-enable') + '
' + i18n('disabled-dependencies') + '.
'); + + // Go through each dependency element. Show the spans where the dependency is + // disabled. Hide the others. + for (var i = 0; i < dependencySpans.length; i++) { + var dependencySpan = dependencySpans[i]; + var pluginId = dependencySpan.getAttribute('data-plugin-id'); + var depPluginTR = getPluginTR(pluginId); + var depPluginMetadata = depPluginTR.jenkinsPluginMetadata; + if (depPluginMetadata.enableInput.checked) { + // It's enabled ... hide the span + dependencySpan.setStyle({display: 'none'}); + } else { + // It's disabled ... show the span + dependencySpan.setStyle({display: 'inline-block'}); + } + } + + dependenciesDiv.setStyle({display: 'inherit'}); + infoContainer.appendChild(dependenciesDiv); + + return true; + } if (pluginTR.hasClassName('has-dependants')) { + if (!pluginTR.hasClassName('all-dependants-disabled')) { + var dependantIds = pluginMetadata.dependantIds; + + // If the only dependant is jenkins-core (it's a bundle plugin), then lets + // treat it like all its dependants are disabled. We're really only interested in + // dependant plugins in this case. + // Note: This does not cover "implied" dependencies ala detached plugins. See https://goo.gl/lQHrUh + if (dependantIds.length === 1 && dependantIds[0] === 'jenkins-core') { + pluginTR.addClassName('all-dependants-disabled'); + return false; + } + + var dependantsDiv = pluginMetadata.dependantsDiv; + var dependantSpans = pluginMetadata.dependants; + + infoContainer.update('
' + i18n('cannot-disable') + '
' + i18n('enabled-dependants') + '.
'); + + // Go through each dependant element. Show the spans where the dependant is + // enabled. Hide the others. + for (var i = 0; i < dependantSpans.length; i++) { + var dependantSpan = dependantSpans[i]; + var dependantId = dependantSpan.getAttribute('data-plugin-id'); + + if (dependantId === 'jenkins-core') { + // show the span + dependantSpan.setStyle({display: 'inline-block'}); + } else { + var depPluginTR = getPluginTR(dependantId); + var depPluginMetadata = depPluginTR.jenkinsPluginMetadata; + if (depPluginMetadata.enableInput.checked) { + // It's enabled ... show the span + dependantSpan.setStyle({display: 'inline-block'}); + } else { + // It's disabled ... hide the span + dependantSpan.setStyle({display: 'none'}); + } + } + } + + dependantsDiv.setStyle({display: 'inherit'}); + infoContainer.appendChild(dependantsDiv); + + return true; + } + } + + return false; + } + + function populateUninstallInfo(pluginTR, infoContainer) { + // Remove all existing class info + infoContainer.removeAttribute('class'); + infoContainer.addClassName('uninstall-state-info'); + + if (pluginTR.hasClassName('has-dependants')) { + var pluginMetadata = pluginTR.jenkinsPluginMetadata; + var dependantsDiv = pluginMetadata.dependantsDiv; + var dependantSpans = pluginMetadata.dependants; + + infoContainer.update('
' + i18n('cannot-uninstall') + '
' + i18n('installed-dependants') + '.
'); + + // Go through each dependant element. Show them all. + for (var i = 0; i < dependantSpans.length; i++) { + var dependantSpan = dependantSpans[i]; + dependantSpan.setStyle({display: 'inline-block'}); + } + + dependantsDiv.setStyle({display: 'inherit'}); + infoContainer.appendChild(dependantsDiv); + + return true; + } + + return false; + } + + function initPluginRowHandling(pluginTR) { + var enableInput = select('.enable input', pluginTR); + var dependenciesDiv = select('.dependency-list', pluginTR); + var dependantsDiv = select('.dependant-list', pluginTR); + var enableTD = select('td.enable', pluginTR); + var uninstallTD = select('td.uninstall', pluginTR); + + pluginTR.jenkinsPluginMetadata = { + enableInput: enableInput, + dependenciesDiv: dependenciesDiv, + dependantsDiv: dependantsDiv + }; + + if (dependenciesDiv) { + pluginTR.jenkinsPluginMetadata.dependencies = selectAll('span', dependenciesDiv); + pluginTR.jenkinsPluginMetadata.dependencyIds = processSpanSet(pluginTR.jenkinsPluginMetadata.dependencies); + } + if (dependantsDiv) { + pluginTR.jenkinsPluginMetadata.dependants = selectAll('span', dependantsDiv); + pluginTR.jenkinsPluginMetadata.dependantIds = processSpanSet(pluginTR.jenkinsPluginMetadata.dependants); + } + + // Setup event handlers... + + // Toggling of the enable/disable checkbox requires a check and possible + // change of visibility on the same checkbox on other plugins. + Element.observe(enableInput, 'click', function() { + setEnableWidgetStates(); + }); + + // + var infoTR = document.createElement("tr"); + var infoTD = document.createElement("td"); + var infoDiv = document.createElement("div"); + infoTR.appendChild(infoTD) + infoTD.appendChild(infoDiv) + infoTD.setAttribute('colspan', '6'); // This is the cell that all info will be added to. + infoDiv.setStyle({display: 'inherit'}); + + // We don't want the info row to appear immediately. We wait for e.g. 1 second and if the mouse + // is still in there (hasn't left the cell) then we show. The following code is for clearing the + // show timeout where the mouse has left before the timeout has fired. + var showInfoTimeout = undefined; + function clearShowInfoTimeout() { + if (showInfoTimeout) { + clearTimeout(showInfoTimeout); + } + showInfoTimeout = undefined; + } + + // Handle mouse in/out of the enable/disable cell (left most cell). + Element.observe(enableTD, 'mouseenter', function() { + showInfoTimeout = setTimeout(function() { + showInfoTimeout = undefined; + infoDiv.update(''); + if (populateEnableDisableInfo(pluginTR, infoDiv)) { + addDependencyInfoRow(pluginTR, infoTR); + } + }, 1000); + }); + Element.observe(enableTD, 'mouseleave', function() { + clearShowInfoTimeout(); + removeDependencyInfoRow(pluginTR); + }); + + // Handle mouse in/out of the uninstall cell (right most cell). + Element.observe(uninstallTD, 'mouseenter', function() { + showInfoTimeout = setTimeout(function() { + showInfoTimeout = undefined; + infoDiv.update(''); + if (populateUninstallInfo(pluginTR, infoDiv)) { + addDependencyInfoRow(pluginTR, infoTR); + } + }, 1000); + }); + Element.observe(uninstallTD, 'mouseleave', function() { + clearShowInfoTimeout(); + removeDependencyInfoRow(pluginTR); + }); + } + + for (var i = 0; i < pluginTRs.length; i++) { + initPluginRowHandling(pluginTRs[i]); + } + + setEnableWidgetStates(); + }); +}()); \ No newline at end of file diff --git a/core/src/main/resources/hudson/PluginManager/advanced.jelly b/core/src/main/resources/hudson/PluginManager/advanced.jelly index 9b8839e983ef79154616edb40913a76b64b8c6d7..362d28e9ca87abe5ca7e6a8642f23e302231ee18 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced.jelly +++ b/core/src/main/resources/hudson/PluginManager/advanced.jelly @@ -98,11 +98,7 @@ THE SOFTWARE.
- -
- ${%lastUpdated(app.updateCenter.lastUpdatedString)} - - +
diff --git a/core/src/main/resources/hudson/PluginManager/advanced.properties b/core/src/main/resources/hudson/PluginManager/advanced.properties index 04d52f3a77d7567beb9e87ab249eabfb2a6e9b46..9cddb7e0ef2c1749662d2011bb0b0c3999b97aee 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced.properties @@ -20,6 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -lastUpdated=Update information obtained: {0} ago uploadtext=\ - You can upload a .hpi file to install a plugin from outside the central plugin repository. \ No newline at end of file + You can upload a .hpi file to install a plugin from outside the central plugin repository. diff --git a/core/src/main/resources/hudson/PluginManager/advanced_bg.properties b/core/src/main/resources/hudson/PluginManager/advanced_bg.properties index 33ffcd06ed055c8294c14ddccec8e51e49b3d047..21ede7a1563a13c07410ddc483d31b4b6ab50677 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_bg.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_bg.properties @@ -1,6 +1,5 @@ # This file is under the MIT License by authors -Check\ now=\u041F\u0440\u043E\u0432\u0435\u0440\u0438 \u0441\u0435\u0433\u0430 File=\u0424\u0430\u0439\u043B HTTP\ Proxy\ Configuration=\u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F \u043D\u0430 HTTP \u043F\u0440\u043E\u043A\u0441\u0438 Submit=\u041F\u043E\u0442\u0432\u044A\u0440\u0434\u0438 diff --git a/core/src/main/resources/hudson/PluginManager/advanced_cs.properties b/core/src/main/resources/hudson/PluginManager/advanced_cs.properties index 3e7d9961c19bcbd8cf66fcc7ad708dd960331a20..4551fc765436b07c2e6aa60b370ef2dfd19e9f35 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_cs.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_cs.properties @@ -1,6 +1,5 @@ # This file is under the MIT License by authors -Check\ now=Zkontrolovat nyn\u00ED File=Soubor HTTP\ Proxy\ Configuration=Nastaven\u00ED HTTP Proxy Submit=Odeslat diff --git a/core/src/main/resources/hudson/PluginManager/advanced_da.properties b/core/src/main/resources/hudson/PluginManager/advanced_da.properties index 372c30778596efb1bfde4d943ffb9dc93e42cc82..cea2ce412ded480e5ccc630d9e2a1ff3cee6a603 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_da.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_da.properties @@ -24,7 +24,6 @@ Update\ Site=Opdateringssite Password=Adgangskode Upload=L\u00e6g op User\ name=Brugernavn -Check\ now=Check nu File=Fil URL=URL lastUpdated=Opdateringsinformation hentet: {0} dage siden diff --git a/core/src/main/resources/hudson/PluginManager/advanced_de.properties b/core/src/main/resources/hudson/PluginManager/advanced_de.properties index 7c998113ab120978fc8abaa7425bd25582aa0bf0..13c4621559824e14ddb6eccfbd427e51dacc952f 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_de.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_de.properties @@ -26,9 +26,8 @@ Upload\ Plugin=Plugin hochladen File=Datei Upload=Hochladen lastUpdated=Letzte Datenaktualisierung des Update-Centers: Vor {0} -Check\ now=Jetzt aktualisieren uploadtext=Geben Sie hier den Pfad zu einer lokalen Plugin-Datei (Dateiendung .hpi) an, die installiert werden soll. Update\ Site=Aktualisierungsserver URL=URL Other\ Sites=Andere Aktualisierungsserver -Update\ Center=Update-Center \ No newline at end of file +Update\ Center=Update-Center diff --git a/core/src/main/resources/hudson/PluginManager/advanced_es.properties b/core/src/main/resources/hudson/PluginManager/advanced_es.properties index 16147fb3133bc90b82c190e67564220ce37c7ebc..1a5ebcf151b3e6748deb957f44fd5e3ca60986f5 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_es.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_es.properties @@ -24,7 +24,6 @@ lastUpdated=Informacion de actualizaci uploadtext=\ Puedes subir un fichero .hpi para instalar un plugin que no este en el repositorio central. Submit=Enviar -Check\ now=Comprobar ahora File=Archivo Upload\ Plugin=Subir un plugin Upload=Subir diff --git a/core/src/main/resources/hudson/PluginManager/advanced_fi.properties b/core/src/main/resources/hudson/PluginManager/advanced_fi.properties index b15f630e9a24072b8c0027e9fdc57dd79ebadef6..e406d3c570ddd905b3432e2bc388896c158df316 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_fi.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_fi.properties @@ -20,7 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Check\ now=Tarkista nyt File=Tiedosto HTTP\ Proxy\ Configuration=HTTP-v\u00E4lipalvelinasetukset Password=Salasana diff --git a/core/src/main/resources/hudson/PluginManager/advanced_fr.properties b/core/src/main/resources/hudson/PluginManager/advanced_fr.properties index 18e75bbbd86cd80c30a9efbd843f0f571364644a..85763f7c7b395ce67524abcb104bcb609e775ff9 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_fr.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_fr.properties @@ -27,7 +27,6 @@ File=Fichier Update\ Site=Site de mise \u00E0 jour Upload=Soumettre lastUpdated=Derni\u00E8re mise \u00E0 jour\u00A0: il y a {0} -Check\ now=V\u00E9rifier maintenant uploadtext=Vous pouvez t\u00E9l\u00E9verser un fichier .hpi pour installer un plugin ext\u00E9rieur au d\u00E9p\u00F4t centralis\u00E9 de plugin. Proxy\ Needs\ Authorization=Le proxy n\u00E9cessite une authentification Server=Serveur diff --git a/core/src/main/resources/hudson/PluginManager/advanced_hu.properties b/core/src/main/resources/hudson/PluginManager/advanced_hu.properties index 911b0ee43069d549cfaa77b4a2c6fd2f812838e2..01e7d77e9e2976d4773d64bcd43cc799bd857c2e 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_hu.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_hu.properties @@ -1,6 +1,5 @@ # This file is under the MIT License by authors -Check\ now=Ellen\u0151rz\u00E9s most File=\u00C1llom\u00E1ny HTTP\ Proxy\ Configuration=HTTP Proxy Be\u00E1ll\u00EDt\u00E1sok Submit=Elk\u00FCld diff --git a/core/src/main/resources/hudson/PluginManager/advanced_it.properties b/core/src/main/resources/hudson/PluginManager/advanced_it.properties index fe73e9d599fae03f46fe62230d692e02fedc9ed5..aba4a0d6df08b580264bcf1e8f681f9d12fe3e5f 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_it.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_it.properties @@ -20,7 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Check\ now=Controlla ora HTTP\ Proxy\ Configuration=Configurazione Proxy HTTP Port=Porta Submit=Invia diff --git a/core/src/main/resources/hudson/PluginManager/advanced_ja.properties b/core/src/main/resources/hudson/PluginManager/advanced_ja.properties index 4fe6117e1a0f3d1c3085cb7740d2522a844afd2c..149795c96008d2076a5051e1ff3d4d8d1238e2d1 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_ja.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_ja.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2012, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe +# Copyright (c) 2004-2015, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -25,10 +25,8 @@ Submit=\u4fdd\u5b58 Upload\ Plugin=\u30d7\u30e9\u30b0\u30a4\u30f3\u306e\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 Upload=\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9 File=\u30d5\u30a1\u30a4\u30eb -lastUpdated=\u30c7\u30fc\u30bf\u66f4\u65b0\u6642\u523b: {0} uploadtext=\ .hpi\u30d5\u30a1\u30a4\u30eb\u3092\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3057\u3066\u3001\u30d7\u30e9\u30b0\u30a4\u30f3\u30ea\u30dd\u30b8\u30c8\u30ea\u4ee5\u5916\u304b\u3089\u30d7\u30e9\u30b0\u30a4\u30f3\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3067\u304d\u307e\u3059\u3002 -Check\ now=\u66f4\u65b0 Update\ Site=\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u30b5\u30a4\u30c8 URL=URL Update\ Center=\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u30bb\u30f3\u30bf\u30fc diff --git a/core/src/main/resources/hudson/PluginManager/advanced_ko.properties b/core/src/main/resources/hudson/PluginManager/advanced_ko.properties index c7b39b4eb3db4ecede7b7b8cf7a07498c932a468..18b829d7bdeae58b2272d17ae0a6dc42a3b154df 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_ko.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_ko.properties @@ -20,7 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Check\ now=\uC9C0\uAE08 \uD655\uC778 File=\uD30C\uC77C HTTP\ Proxy\ Configuration=HTTP \uD504\uB85D\uC2DC \uC124\uC815 Password=\uC554\uD638 diff --git a/core/src/main/resources/hudson/PluginManager/advanced_lt.properties b/core/src/main/resources/hudson/PluginManager/advanced_lt.properties index cae3c771759db6886b74f0cc070bb615b80b48c9..2031c41482937e51ba38ddf75e87eabb93a9a161 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_lt.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_lt.properties @@ -1,6 +1,5 @@ # This file is under the MIT License by authors -Check\ now=Tikrinti dabar File=Failas HTTP\ Proxy\ Configuration=HTTP \u0161liuzo konfig\u016Bracija Update\ Site=Atnaujinimo svetain\u0117 diff --git a/core/src/main/resources/hudson/PluginManager/advanced_lv.properties b/core/src/main/resources/hudson/PluginManager/advanced_lv.properties index a1dcbc726fc0e03a161388117c288513786b5b72..3e103e2a01c141ee0988a7633386abfd8b774e87 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_lv.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_lv.properties @@ -1,6 +1,5 @@ # This file is under the MIT License by authors -Check\ now=P\u0101rbaud\u012Bt tagad File=Fails HTTP\ Proxy\ Configuration=HTTP Starpniekservera konfigur\u0101cija Submit=Nos\u016Bt\u012Bt diff --git a/core/src/main/resources/hudson/PluginManager/advanced_nb_NO.properties b/core/src/main/resources/hudson/PluginManager/advanced_nb_NO.properties index 06364eefc52db96b1e97bdcc77c98ebce645162d..5cec6ec57d6638dd012f69973dc516c5caf58695 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_nb_NO.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_nb_NO.properties @@ -20,7 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Check\ now=Sjekk n\u00E5 File=Fil HTTP\ Proxy\ Configuration=HTTP mellomtjener konfigurasjon Password=Passord diff --git a/core/src/main/resources/hudson/PluginManager/advanced_nl.properties b/core/src/main/resources/hudson/PluginManager/advanced_nl.properties index 5d53638e22d4d1a9eab17d0753cbbbf883675845..eddf5de9983b729c25567f112c4179e17e5d7409 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_nl.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_nl.properties @@ -26,7 +26,6 @@ Password=Wachtwoord Server=Server Port=Poortnummer User\ name=Gebruikersnaam -Check\ now=Actualiseer nu URL=URL Upload=Uploaden HTTP\ Proxy\ Configuration=HTTP-proxyconfiguratie diff --git a/core/src/main/resources/hudson/PluginManager/advanced_pl.properties b/core/src/main/resources/hudson/PluginManager/advanced_pl.properties index e2a4db4d6e20b1886f92065e8ce3a6790d69e233..2fd34ca14117d6a6b77d209ac8e149e6abe35489 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_pl.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_pl.properties @@ -20,7 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Check\ now=Sprawd\u017A teraz File=Plik HTTP\ Proxy\ Configuration=Konfiguracja HTTP Proxy Password=Has\u0142o diff --git a/core/src/main/resources/hudson/PluginManager/advanced_pt_BR.properties b/core/src/main/resources/hudson/PluginManager/advanced_pt_BR.properties index dec549256c25a8dd3558536e29997e53110d5132..6de0e5b3beaf545c65ebc05d0928b37226063585 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_pt_BR.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_pt_BR.properties @@ -23,7 +23,6 @@ lastUpdated=Informa\u00e7\u00e3o de atualiza\u00e7\u00e3o obtida: {0} atr\u00e1s uploadtext=Voc\u00EA pode fazer o upload de um arquivo .hpi para instalar um plugin fora do reposit\u00F3rio central. Update\ Site=Site de atualiza\u00e7\u00e3o -Check\ now=Verificar agora File=Arquivo Upload\ Plugin=Atualizar plugin HTTP\ Proxy\ Configuration=Configura\u00e7\u00e3o de Proxy/HTTP diff --git a/core/src/main/resources/hudson/PluginManager/advanced_pt_PT.properties b/core/src/main/resources/hudson/PluginManager/advanced_pt_PT.properties index c59e4ac3d24eafdf4bcce1addd4e548f4d3b1ebe..5f2a622c91561abba8a4ec39542aaed39da1acfd 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_pt_PT.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_pt_PT.properties @@ -1,6 +1,5 @@ # This file is under the MIT License by authors -Check\ now=Verificar agora File=Ficheiro Submit=Enviar Update\ Site=Atualizar Site diff --git a/core/src/main/resources/hudson/PluginManager/advanced_ru.properties b/core/src/main/resources/hudson/PluginManager/advanced_ru.properties index f8f4874ee47c5346e6021182cef62ba131bdd8dd..98ef9a67d9c0477a39df396e461ec66aa4be75db 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_ru.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_ru.properties @@ -20,7 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Check\ now=\u041F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u0441\u0435\u0439\u0447\u0430\u0441 File=\u0424\u0430\u0439\u043B HTTP\ Proxy\ Configuration=\u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044F HTTP Proxy Password=\u041F\u0430\u0440\u043E\u043B\u044C diff --git a/core/src/main/resources/hudson/PluginManager/advanced_sk.properties b/core/src/main/resources/hudson/PluginManager/advanced_sk.properties index f800c9d89f7a48f1ddae7dfbd46273df8a1a66e8..2b35c4933a515d7e1a8b049ad9dc59b0dd75f574 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_sk.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_sk.properties @@ -1,6 +1,5 @@ # This file is under the MIT License by authors -Check\ now=Skontroluj teraz File=S\u00FAbor HTTP\ Proxy\ Configuration=Konfigur\u00E1cia HTTP proxy Submit=Po\u0161li diff --git a/core/src/main/resources/hudson/PluginManager/advanced_sv_SE.properties b/core/src/main/resources/hudson/PluginManager/advanced_sv_SE.properties index 6df64acad5f1f91ddc0c92fffd48e6ff89c07cfb..10c631c4425c4fc8be151e753f48e622baa37b1f 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_sv_SE.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_sv_SE.properties @@ -20,7 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Check\ now=Kontrollera nu File=Fil HTTP\ Proxy\ Configuration=HTTP-proxykonfiguration Password=L\u00F6senord diff --git a/core/src/main/resources/hudson/PluginManager/advanced_tr.properties b/core/src/main/resources/hudson/PluginManager/advanced_tr.properties index edec24b16fc407162ecdd92445e3fe498096d5ab..daf9bed295c36d36e3065814568f7c2be3606f62 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_tr.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_tr.properties @@ -29,4 +29,3 @@ File=Dosya Update\ Site=G\u00FCncelleme sitesi Upload=Y\u00fckle lastUpdated=Al\u0131nan son g\u00fcncelleme bilgisi : {0} \u00f6nce -Check\ now=\u015eimdi kontrol et diff --git a/core/src/main/resources/hudson/PluginManager/advanced_uk.properties b/core/src/main/resources/hudson/PluginManager/advanced_uk.properties index a29ac8dc056fa1c0594542437dd1649cc527ea48..7e741c812254073d6014f92ab18a935b0a195cf1 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_uk.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_uk.properties @@ -1,6 +1,5 @@ # This file is under the MIT License by authors -Check\ now=\uC9C0\uAE08 \uCCB4\uD06C File=\uD30C\uC77C HTTP\ Proxy\ Configuration=HTTP \uD504\uB85D\uC2DC \uC124\uC815 Submit=\uC800\uC7A5 diff --git a/core/src/main/resources/hudson/PluginManager/advanced_zh_CN.properties b/core/src/main/resources/hudson/PluginManager/advanced_zh_CN.properties index afffdf88b25353e03b2e82ec8c85314b44822480..263213c2fbfbf86c67a49ccbb8391b6bc3d26db2 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_zh_CN.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_zh_CN.properties @@ -20,7 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Check\ now=\u7ACB\u5373\u83B7\u53D6 File=\u6587\u4EF6 HTTP\ Proxy\ Configuration=\u4EE3\u7406\u8BBE\u7F6E Password=\u5BC6\u7801 diff --git a/core/src/main/resources/hudson/PluginManager/advanced_zh_TW.properties b/core/src/main/resources/hudson/PluginManager/advanced_zh_TW.properties index db3c27fcd35c5b0cef850eff623d4f73dc7c746e..299d2013bc0a59afa01bc775deaec8a0c73d3ff9 100644 --- a/core/src/main/resources/hudson/PluginManager/advanced_zh_TW.properties +++ b/core/src/main/resources/hudson/PluginManager/advanced_zh_TW.properties @@ -36,4 +36,3 @@ URL=URL Other\ Sites=\u5176\u4ed6\u7db2\u7ad9 lastUpdated=\u66f4\u65b0\u8cc7\u8a0a\u53d6\u5f97\u6642\u9593: {0}\u4ee5\u524d -Check\ now=\u99ac\u4e0a\u6aa2\u67e5 diff --git a/core/src/main/resources/hudson/PluginManager/check.jelly b/core/src/main/resources/hudson/PluginManager/check.jelly new file mode 100644 index 0000000000000000000000000000000000000000..2270efaa512b2b51ce76ba815d81508b1831e982 --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check.jelly @@ -0,0 +1,33 @@ + + + + + + ${%lastUpdated(app.updateCenter.lastUpdatedString)} + + + + + diff --git a/test/src/main/resources/org/jvnet/hudson/test/ComputerConnectorTester/configure_pt_BR.properties b/core/src/main/resources/hudson/PluginManager/check.properties similarity index 90% rename from test/src/main/resources/org/jvnet/hudson/test/ComputerConnectorTester/configure_pt_BR.properties rename to core/src/main/resources/hudson/PluginManager/check.properties index deb9192a353e7f2540d148d7a2b5703a3e125344..e500403bce4e1ff198b317349e6c747eadadf24b 100644 --- a/test/src/main/resources/org/jvnet/hudson/test/ComputerConnectorTester/configure_pt_BR.properties +++ b/core/src/main/resources/hudson/PluginManager/check.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributers +# 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 @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Save=Salvar +lastUpdated=Update information obtained: {0} ago diff --git a/core/src/main/resources/hudson/PluginManager/check_bg.properties b/core/src/main/resources/hudson/PluginManager/check_bg.properties new file mode 100644 index 0000000000000000000000000000000000000000..563165ac538f2f47384c18bca07fff661a4f86fb --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_bg.properties @@ -0,0 +1,3 @@ +# This file is under the MIT License by authors + +Check\ now=\u041F\u0440\u043E\u0432\u0435\u0440\u0438 \u0441\u0435\u0433\u0430 diff --git a/core/src/main/resources/hudson/PluginManager/check_cs.properties b/core/src/main/resources/hudson/PluginManager/check_cs.properties new file mode 100644 index 0000000000000000000000000000000000000000..5b1339bc5e8f382a7810d72add6dc5d3057118f5 --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_cs.properties @@ -0,0 +1,3 @@ +# This file is under the MIT License by authors + +Check\ now=Zkontrolovat nyn\u00ED diff --git a/test/src/main/resources/org/jvnet/hudson/test/SleepBuilder/config_pt.properties b/core/src/main/resources/hudson/PluginManager/check_da.properties similarity index 90% rename from test/src/main/resources/org/jvnet/hudson/test/SleepBuilder/config_pt.properties rename to core/src/main/resources/hudson/PluginManager/check_da.properties index 78367259590b457602d42c9a87d269df133f85d1..3b85db1e25da667c3fe4c4e1ba0ceb1c89ece995 100644 --- a/test/src/main/resources/org/jvnet/hudson/test/SleepBuilder/config_pt.properties +++ b/core/src/main/resources/hudson/PluginManager/check_da.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributers +# Copyright (c) 2004-2010, Sun Microsystems, Inc. Kohsuke Kawaguchi. Knud Poulsen. # # 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,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Time=Tempo +Check\ now=Check nu diff --git a/core/src/main/resources/hudson/PluginManager/check_de.properties b/core/src/main/resources/hudson/PluginManager/check_de.properties new file mode 100644 index 0000000000000000000000000000000000000000..d7ad3422d8586da2918122f3a0ef9754ec8a026f --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_de.properties @@ -0,0 +1,23 @@ +# The MIT License +# +# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Harald Wellmann, Simon Wiest +# +# 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. + +Check\ now=Jetzt aktualisieren diff --git a/test/src/main/resources/org/jvnet/hudson/test/SleepBuilder/config_pt_BR.properties b/core/src/main/resources/hudson/PluginManager/check_es.properties similarity index 90% rename from test/src/main/resources/org/jvnet/hudson/test/SleepBuilder/config_pt_BR.properties rename to core/src/main/resources/hudson/PluginManager/check_es.properties index 78367259590b457602d42c9a87d269df133f85d1..ca53b0b96997a4d3d74d60cc0bffb507589ea6a2 100644 --- a/test/src/main/resources/org/jvnet/hudson/test/SleepBuilder/config_pt_BR.properties +++ b/core/src/main/resources/hudson/PluginManager/check_es.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributers +# 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 @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Time=Tempo +Check\ now=Comprobar ahora diff --git a/core/src/main/resources/hudson/PluginManager/check_fi.properties b/core/src/main/resources/hudson/PluginManager/check_fi.properties new file mode 100644 index 0000000000000000000000000000000000000000..0a3e96267cd39f9d5cd499f268b78d6b0eb456bc --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_fi.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. + +Check\ now=Tarkista nyt diff --git a/test/src/main/resources/org/jvnet/hudson/test/ComputerConnectorTester/configure_fr.properties b/core/src/main/resources/hudson/PluginManager/check_fr.properties similarity index 89% rename from test/src/main/resources/org/jvnet/hudson/test/ComputerConnectorTester/configure_fr.properties rename to core/src/main/resources/hudson/PluginManager/check_fr.properties index 87c0ef6252ecf4f8a7437b029b97651a1d44b179..6b10fb759b62381c0cdc01962714ed1430d345eb 100644 --- a/test/src/main/resources/org/jvnet/hudson/test/ComputerConnectorTester/configure_fr.properties +++ b/core/src/main/resources/hudson/PluginManager/check_fr.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributers +# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Eric Lefevre-Ardant # # 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,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Save=Sauvegarder +Check\ now=V\u00E9rifier maintenant diff --git a/core/src/main/resources/hudson/PluginManager/check_hu.properties b/core/src/main/resources/hudson/PluginManager/check_hu.properties new file mode 100644 index 0000000000000000000000000000000000000000..43ba4fec4dea98d9a1ef84c902c376427ab154ab --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_hu.properties @@ -0,0 +1,3 @@ +# This file is under the MIT License by authors + +Check\ now=Ellen\u0151rz\u00E9s most diff --git a/core/src/main/resources/hudson/PluginManager/check_it.properties b/core/src/main/resources/hudson/PluginManager/check_it.properties new file mode 100644 index 0000000000000000000000000000000000000000..e87f4933037b53ec724cecf46988d17d781d2f14 --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_it.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. + +Check\ now=Controlla ora diff --git a/core/src/main/resources/hudson/PluginManager/check_ja.properties b/core/src/main/resources/hudson/PluginManager/check_ja.properties new file mode 100644 index 0000000000000000000000000000000000000000..7421eabbdf919969b0db4415a27f5b721e5129d6 --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_ja.properties @@ -0,0 +1,24 @@ +# The MIT License +# +# Copyright (c) 2004-2015, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe +# +# 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. + +Check\ now=\u66f4\u65b0 +lastUpdated=\u30c7\u30fc\u30bf\u66f4\u65b0\u6642\u523b: {0} diff --git a/core/src/main/resources/hudson/PluginManager/check_ko.properties b/core/src/main/resources/hudson/PluginManager/check_ko.properties new file mode 100644 index 0000000000000000000000000000000000000000..e91170c8c7fc394062a4cb25f0758f5d967ec929 --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_ko.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. + +Check\ now=\uC9C0\uAE08 \uD655\uC778 diff --git a/core/src/main/resources/hudson/PluginManager/check_lt.properties b/core/src/main/resources/hudson/PluginManager/check_lt.properties new file mode 100644 index 0000000000000000000000000000000000000000..a7376ecd93faeae59be6da871f7c39672d0c9358 --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_lt.properties @@ -0,0 +1,3 @@ +# This file is under the MIT License by authors + +Check\ now=Tikrinti dabar diff --git a/core/src/main/resources/hudson/PluginManager/check_lv.properties b/core/src/main/resources/hudson/PluginManager/check_lv.properties new file mode 100644 index 0000000000000000000000000000000000000000..0ff80e36c820ee2301f685be1548007df61fc9d8 --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_lv.properties @@ -0,0 +1,3 @@ +# This file is under the MIT License by authors + +Check\ now=P\u0101rbaud\u012Bt tagad diff --git a/core/src/main/resources/hudson/PluginManager/check_nb_NO.properties b/core/src/main/resources/hudson/PluginManager/check_nb_NO.properties new file mode 100644 index 0000000000000000000000000000000000000000..0e129bdb96192be92b9085e45bc63e3629d349b9 --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_nb_NO.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. + +Check\ now=Sjekk n\u00E5 diff --git a/test/src/main/resources/org/jvnet/hudson/test/ComputerConnectorTester/configure_pt.properties b/core/src/main/resources/hudson/PluginManager/check_nl.properties similarity index 90% rename from test/src/main/resources/org/jvnet/hudson/test/ComputerConnectorTester/configure_pt.properties rename to core/src/main/resources/hudson/PluginManager/check_nl.properties index ccd0ece5e40ded27fa163c8a384ef77d6f2c866a..452853516737fe8674183dff397e90e9c882f55b 100644 --- a/test/src/main/resources/org/jvnet/hudson/test/ComputerConnectorTester/configure_pt.properties +++ b/core/src/main/resources/hudson/PluginManager/check_nl.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributers +# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Wim Rosseel # # 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,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Save=Gravar +Check\ now=Actualiseer nu diff --git a/core/src/main/resources/hudson/PluginManager/check_pl.properties b/core/src/main/resources/hudson/PluginManager/check_pl.properties new file mode 100644 index 0000000000000000000000000000000000000000..579836ad90c039adcb03bdddd90640ac2a38e7e6 --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_pl.properties @@ -0,0 +1,24 @@ +# 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. + +Check\ now=Sprawd\u017A teraz +lastUpdated=Ostatnie sprawdzenie: {0} temu \ No newline at end of file diff --git a/core/src/main/resources/hudson/PluginManager/check_pt_BR.properties b/core/src/main/resources/hudson/PluginManager/check_pt_BR.properties new file mode 100644 index 0000000000000000000000000000000000000000..5c3a37adc75227081e9c208dd77fe2dc39b68949 --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_pt_BR.properties @@ -0,0 +1,23 @@ +# The MIT License +# +# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Reginaldo L. Russinholi, Cleiber Silva, Fernando Boaglio +# +# 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. + +Check\ now=Verificar agora diff --git a/core/src/main/resources/hudson/PluginManager/check_pt_PT.properties b/core/src/main/resources/hudson/PluginManager/check_pt_PT.properties new file mode 100644 index 0000000000000000000000000000000000000000..8d4b91ea30877c09a2ee41b31707cbe37c6c882e --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_pt_PT.properties @@ -0,0 +1,3 @@ +# This file is under the MIT License by authors + +Check\ now=Verificar agora diff --git a/core/src/main/resources/hudson/PluginManager/check_ru.properties b/core/src/main/resources/hudson/PluginManager/check_ru.properties new file mode 100644 index 0000000000000000000000000000000000000000..37a558a5e3dee913585a45f3fcb6e81fc60d84ec --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_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. + +Check\ now=\u041F\u0440\u043E\u0432\u0435\u0440\u0438\u0442\u044C \u0441\u0435\u0439\u0447\u0430\u0441 diff --git a/core/src/main/resources/hudson/PluginManager/check_sk.properties b/core/src/main/resources/hudson/PluginManager/check_sk.properties new file mode 100644 index 0000000000000000000000000000000000000000..39c01a995062957fc43b90626674f9e10f354e20 --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_sk.properties @@ -0,0 +1,3 @@ +# This file is under the MIT License by authors + +Check\ now=Skontroluj teraz diff --git a/core/src/main/resources/hudson/PluginManager/check_sv_SE.properties b/core/src/main/resources/hudson/PluginManager/check_sv_SE.properties new file mode 100644 index 0000000000000000000000000000000000000000..87e2c89db6eeb9b6af910d8c745726fb7498a973 --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_sv_SE.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. + +Check\ now=Kontrollera nu diff --git a/core/src/main/resources/hudson/PluginManager/check_tr.properties b/core/src/main/resources/hudson/PluginManager/check_tr.properties new file mode 100644 index 0000000000000000000000000000000000000000..a7188cd0440aaf247b4a78aa7368c4a660f7e180 --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_tr.properties @@ -0,0 +1,23 @@ +# The MIT License +# +# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Oguz Dag +# +# 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. + +Check\ now=\u015eimdi kontrol et diff --git a/core/src/main/resources/hudson/PluginManager/check_uk.properties b/core/src/main/resources/hudson/PluginManager/check_uk.properties new file mode 100644 index 0000000000000000000000000000000000000000..3059e359bed2de07abec3e81139e12c69f124f67 --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_uk.properties @@ -0,0 +1,3 @@ +# This file is under the MIT License by authors + +Check\ now=\uC9C0\uAE08 \uCCB4\uD06C diff --git a/core/src/main/resources/hudson/PluginManager/check_zh_CN.properties b/core/src/main/resources/hudson/PluginManager/check_zh_CN.properties new file mode 100644 index 0000000000000000000000000000000000000000..8283cb0a15acce4df9813bcacabcb90279e2f431 --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_zh_CN.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. + +Check\ now=\u7ACB\u5373\u83B7\u53D6 diff --git a/core/src/main/resources/hudson/PluginManager/check_zh_TW.properties b/core/src/main/resources/hudson/PluginManager/check_zh_TW.properties new file mode 100644 index 0000000000000000000000000000000000000000..58ed12c22ec6586463429987c95f0c87d011fef7 --- /dev/null +++ b/core/src/main/resources/hudson/PluginManager/check_zh_TW.properties @@ -0,0 +1,24 @@ +# The MIT License +# +# Copyright (c) 2004-2013, Sun Microsystems, Inc., Chunghwa Telecom Co., Ltd., +# and Pei-Tang Huang +# +# 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. + +Check\ now=\u99ac\u4e0a\u6aa2\u67e5 diff --git a/core/src/main/resources/hudson/PluginManager/installed.jelly b/core/src/main/resources/hudson/PluginManager/installed.jelly index 2d439b335e0597c54eee66207d29e3abd244435c..35b29471530480ad28bc83936c29a7e366e3c44b 100644 --- a/core/src/main/resources/hudson/PluginManager/installed.jelly +++ b/core/src/main/resources/hudson/PluginManager/installed.jelly @@ -35,10 +35,23 @@ THE SOFTWARE. ${%Filter}: + + +
${%Warning}: ${%requires.restart}
+
+
- +
+
- + - - - diff --git a/core/src/main/resources/hudson/PluginManager/installed.properties b/core/src/main/resources/hudson/PluginManager/installed.properties index ad37e72885f246853d7a0041a17e0586c91cddb1..2fa0cafb8083f2b150ecd074aeb95ea0321dc2b7 100644 --- a/core/src/main/resources/hudson/PluginManager/installed.properties +++ b/core/src/main/resources/hudson/PluginManager/installed.properties @@ -20,4 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. wiki.url=http://wiki.jenkins-ci.org/display/JENKINS/Pinned+Plugins -downgradeTo=Downgrade to {0} \ No newline at end of file +downgradeTo=Downgrade to {0} +requires.restart=This Jenkins instance requires a restart. Changing the state of plugins at this time is strongly discouraged. Restart Jenkins before proceeding. \ No newline at end of file diff --git a/core/src/main/resources/hudson/PluginManager/installed_ja.properties b/core/src/main/resources/hudson/PluginManager/installed_ja.properties index 2734eafebe7248580aedc6c57039e4ac8adb407d..cca9a2797f7350e2a3c8134cd565fddc7811f0d7 100644 --- a/core/src/main/resources/hudson/PluginManager/installed_ja.properties +++ b/core/src/main/resources/hudson/PluginManager/installed_ja.properties @@ -33,5 +33,7 @@ wiki.url=http://wiki.jenkins-ci.org/display/JA/Pinned+Plugins Previously\ installed\ version=\u524d\u56de\u30d0\u30fc\u30b8\u30e7\u30f3 downgradeTo={0} \u306b\u30c0\u30a6\u30f3\u30b0\u30ec\u30fc\u30c9 Update\ Center=\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u30bb\u30f3\u30bf\u30fc -Uninstall=\u30A2\u30F3\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB +Filter=\u30d5\u30a3\u30eb\u30bf\u30fc +No\ description\ available.=\u8aac\u660e\u304c\u3042\u308a\u307e\u305b\u3093\u3002 +Uninstall=\u30a2\u30f3\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb Uninstallation\ pending=\u30a2\u30f3\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u5b9f\u884c\u5f85\u3061 diff --git a/core/src/main/resources/hudson/PluginManager/installed_pl.properties b/core/src/main/resources/hudson/PluginManager/installed_pl.properties index 799c461da78217eaf58e3abb3ae4028910194ac0..47bc109f1610e7bcb56bee252f1219fbbb80e717 100644 --- a/core/src/main/resources/hudson/PluginManager/installed_pl.properties +++ b/core/src/main/resources/hudson/PluginManager/installed_pl.properties @@ -31,4 +31,5 @@ Uninstall=Odinstaluj Unpin=Odepnij Version=Wersja downgradeTo=Powr\u00F3\u0107 do starszej wersji {0} +requires.restart=Wymagane jest ponowne uruchomienie Jenkinsa. Zmiany wtyczek w tym momencie s\u0105 bardzo niewskazane. Uruchom ponownie Jenkinsa, zanim wprowadzisz zmiany. wiki.url=http://wiki.jenkins-ci.org/display/JENKINS/Pinned+Plugins diff --git a/core/src/main/resources/hudson/PluginManager/table.jelly b/core/src/main/resources/hudson/PluginManager/table.jelly index 4ed0a6385acf206326349f377faca0c477fb4433..e8c75170b412f01cdc4ac3fa8b082801d1057be6 100644 --- a/core/src/main/resources/hudson/PluginManager/table.jelly +++ b/core/src/main/resources/hudson/PluginManager/table.jelly @@ -147,6 +147,7 @@ THE SOFTWARE. + diff --git a/core/src/main/resources/hudson/TcpSlaveAgentListener/index.jelly b/core/src/main/resources/hudson/TcpSlaveAgentListener/index.jelly index a47151e632f2251449595323c7e1b6aed01e4727..9e65250be24c2ba2ddbed7b2c3cc8abc0fd855b4 100644 --- a/core/src/main/resources/hudson/TcpSlaveAgentListener/index.jelly +++ b/core/src/main/resources/hudson/TcpSlaveAgentListener/index.jelly @@ -30,6 +30,10 @@ THE SOFTWARE. --> + + Jenkins diff --git a/core/src/main/resources/hudson/cli/CLIAction/command.jelly b/core/src/main/resources/hudson/cli/CLIAction/command.jelly index 3dcecdc1ffd01bc975e1b2fc65828032bcc702f0..02acaa65b4c4a46d9944018956d30d9bcac9ed3f 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 816471090802d1d71daa8cb814a658d63851b44b..94ecddfb23b09d3c0a1525e6c712c57fd8fe64d3 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. - +

diff --git a/core/src/main/resources/hudson/cli/Messages.properties b/core/src/main/resources/hudson/cli/Messages.properties index 57c9299f81b6032667f2cc4efaa2150af0fb3f12..3f7340334103b56d782d1ae2a3a49632f5776561 100644 --- a/core/src/main/resources/hudson/cli/Messages.properties +++ b/core/src/main/resources/hudson/cli/Messages.properties @@ -21,7 +21,9 @@ CreateViewCommand.ShortDescription=\ DeleteBuildsCommand.ShortDescription=\ Deletes build record(s). DeleteViewCommand.ShortDescription=\ - Deletes view. + Deletes view(s). +DeleteJobCommand.ShortDescription=\ + Deletes job(s). GroovyCommand.ShortDescription=\ Executes the specified Groovy script. GroovyshCommand.ShortDescription=\ @@ -78,3 +80,9 @@ BuildCommand.CLICause.CannotBuildConfigNotSaved=\ Cannot build {0} because its configuration has not been saved. BuildCommand.CLICause.CannotBuildUnknownReasons=\ Cannot build {0} for unknown reasons. + +DeleteNodeCommand.ShortDescription=Deletes node(s) + +ReloadJobCommand.ShortDescription=Reload job(s) + +OnlineNodeCommand.ShortDescription=Resume using a node for performing builds, to cancel out the earlier "offline-node" command. diff --git a/core/src/main/resources/hudson/cli/Messages_bg.properties b/core/src/main/resources/hudson/cli/Messages_bg.properties new file mode 100644 index 0000000000000000000000000000000000000000..c218a653cf413ea7e4488dccad3bd2905bbd3022 --- /dev/null +++ b/core/src/main/resources/hudson/cli/Messages_bg.properties @@ -0,0 +1,124 @@ +# The MIT License +# +# Bulgarian translation copyright 2015 Alexander Shopov . +# +# 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. + +InstallPluginCommand.DidYouMean=\ + \u201e{0}\u201c \u0435 \u043a\u0440\u0430\u0442\u043a\u043e \u0438\u043c\u0435 \u0437\u0430 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430. \u201e{1}\u201c \u043b\u0438 \u0438\u043c\u0430\u0442\u0435 \u043f\u0440\u0435\u0434\u0432\u0438\u0434? +InstallPluginCommand.InstallingFromUpdateCenter=\ + \u0418\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430\u0442\u0430 \u201e{0}\u201c \u043e\u0442 \u0441\u0430\u0439\u0442\u0430 \u0437\u0430 \u043e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 +InstallPluginCommand.InstallingPluginFromLocalFile=\ + \u0418\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430 \u043e\u0442 \u043b\u043e\u043a\u0430\u043b\u0435\u043d \u0444\u0430\u0439\u043b \u201e{0}\u201c +InstallPluginCommand.InstallingPluginFromUrl=\ + \u0418\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430 \u043e\u0442 \u0430\u0434\u0440\u0435\u0441 \u201e{0}\u201c +InstallPluginCommand.NoUpdateCenterDefined=\ + \u041d\u0435 \u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d \u0441\u0430\u0439\u0442 \u0437\u0430 \u043e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 \u0432 \u0442\u0430\u0437\u0438 \u0438\u043d\u0441\u0442\u0430\u043b\u0430\u0446\u0438\u044f \u043d\u0430 Jenkins. +InstallPluginCommand.NoUpdateDataRetrieved=\ + \u0412\u0441\u0435 \u043e\u0449\u0435 \u043d\u0435 \u0441\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438 \u043d\u0438\u043a\u0430\u043a\u0432\u0438 \u0434\u0430\u043d\u043d\u0438 \u043e\u0442 \u0446\u0435\u043d\u0442\u044a\u0440\u0430 \u0437\u0430 \u043e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435: {0} +InstallPluginCommand.NotAValidSourceName=\ + \u201e{0}\u201c \u043d\u0435 \u0435 \u043d\u0438\u0442\u043e \u0444\u0430\u0439\u043b \u0441 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430, \u043d\u0438\u0442\u043e \u0430\u0434\u0440\u0435\u0441, \u043d\u0438\u0442\u043e \u0438\u043c\u0435 \u043d\u0430 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442 \u043e\u0442 \u0441\u0430\u0439\u0442\u0430 \u0437\u0430\ + \u043e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435. + +AddJobToViewCommand.ShortDescription=\ + \u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0438 \u043a\u044a\u043c \u0438\u0437\u0433\u043b\u0435\u0434. +BuildCommand.ShortDescription=\ + \u0418\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u0438 \u0438\u0437\u0447\u0430\u043a\u0432\u0430\u043d\u0435 \u043d\u0430 \u0437\u0430\u0432\u044a\u0440\u0448\u0432\u0430\u043d\u0435\u0442\u043e \u045d (\u043f\u043e \u0438\u0437\u0431\u043e\u0440). +ConsoleCommand.ShortDescription=\ + \u0418\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0438\u0437\u0445\u043e\u0434\u0430 \u043e\u0442 \u0437\u0430\u0434\u0430\u0447\u0430 \u043a\u044a\u043c \u043a\u043e\u043d\u0437\u043e\u043b\u0430\u0442\u0430. +CopyJobCommand.ShortDescription=\ + \u041a\u043e\u043f\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430. +CreateJobCommand.ShortDescription=\ + \u0421\u044a\u0437\u0434\u0430\u0432\u0430\u043d\u0435 \u043d\u0430 \u043d\u043e\u0432\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u043d\u0430 \u0431\u0430\u0437\u0430\u0442\u0430 \u043d\u0430 \u043f\u0440\u043e\u0447\u0435\u0442\u0435\u043d\u043e\u0442\u043e \u043e\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438\u044f \u0432\u0445\u043e\u0434 \u0432\u044a\u0432\ + \u0444\u043e\u0440\u043c\u0430\u0442 XML. +CreateNodeCommand.ShortDescription=\ + \u0421\u044a\u0437\u0434\u0430\u0432\u0430\u043d\u0435 \u043d\u0430 \u043d\u043e\u0432\u0430 \u043c\u0430\u0448\u0438\u043d\u0430 \u043d\u0430 \u0431\u0430\u0437\u0430\u0442\u0430 \u043d\u0430 \u043f\u0440\u043e\u0447\u0435\u0442\u0435\u043d\u043e\u0442\u043e \u043e\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438\u044f \u0432\u0445\u043e\u0434 \u0432\u044a\u0432\ + \u0444\u043e\u0440\u043c\u0430\u0442 XML. +DeleteBuildsCommand.ShortDescription=\ + \u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430\u0442\u0430 \u0437\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f\u0442\u0430. +DeleteViewCommand.ShortDescription=\ + \u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u0438\u0437\u0433\u043b\u0435\u0434\u0438. +DeleteJobCommand.ShortDescription=\ + \u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0438. +GroovyCommand.ShortDescription=\ + \u0418\u0437\u043f\u044a\u043b\u043d\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u043a\u0440\u0438\u043f\u0442 \u043d\u0430 Groovy. +GroovyshCommand.ShortDescription=\ + \u0418\u0437\u043f\u044a\u043b\u043d\u0435\u043d\u0438\u0435 \u043d\u0430 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u0435\u043d \u0438\u043d\u0442\u0435\u0440\u043f\u0440\u0435\u0442\u0430\u0442\u043e\u0440 \u043d\u0430 Groovy. +HelpCommand.ShortDescription=\ + \u0418\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0432\u0441\u0438\u0447\u043a\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u0438 \u0438\u043b\u0438 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 \u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430. +InstallPluginCommand.ShortDescription=\ + \u0418\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430 \u043e\u0442 \u0444\u0430\u0439\u043b, \u0430\u0434\u0440\u0435\u0441 \u0438\u043b\u0438 \u0446\u0435\u043d\u0442\u044a\u0440\u0430 \u0437\u0430 \u043e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435. +InstallToolCommand.ShortDescription=\ + \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u043e \u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u0438 \u0438\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u043c\u0435\u0441\u0442\u043e\u043f\u043e\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u0442\u043e \u043c\u0443 \u043d\u0430\ + \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438\u044f \u0438\u0437\u0445\u043e\u0434. \u041c\u043e\u0436\u0435 \u0434\u0430 \u0441\u0435 \u0438\u0437\u0432\u0438\u043a\u0432\u0430 \u0441\u0430\u043c\u043e \u043e\u0442 \u0437\u0430\u0434\u0430\u0447\u0430. +ListChangesCommand.ShortDescription=\ + \u0418\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0436\u0443\u0440\u043d\u0430\u043b\u0430 \u0441 \u043f\u0440\u043e\u043c\u0435\u043d\u0438 \u0437\u0430 \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u0442\u0435 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f. +ListJobsCommand.ShortDescription=\ + \u0418\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0432\u0441\u0438\u0447\u043a\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d \u0438\u0437\u0433\u043b\u0435\u0434 \u0438\u043b\u0438 \u0433\u0440\u0443\u043f\u0430. +ListPluginsCommand.ShortDescription=\ + \u0418\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0441\u043f\u0438\u0441\u044a\u043a\u0430 \u0441 \u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0438\u0442\u0435 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0438. +LoginCommand.ShortDescription=\ + \u0417\u0430\u043f\u0430\u0437\u0432\u0430\u043d\u0435 \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0438\u0442\u0435 \u0434\u0430\u043d\u043d\u0438 \u0437\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f, \u0437\u0430 \u0434\u0430 \u043c\u043e\u0433\u0430\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u0432\u0430\u0449\u0438\u0442\u0435\ + \u043a\u043e\u043c\u0430\u043d\u0434\u0438 \u0434\u0430 \u0441\u0435 \u0438\u0437\u043f\u044a\u043b\u043d\u044f\u0432\u0430\u0442, \u0431\u0435\u0437 \u0442\u0435\u0437\u0438 \u0434\u0430\u043d\u043d\u0438 \u0434\u0430 \u0441\u0435 \u0432\u044a\u0432\u0435\u0436\u0434\u0430\u0442 \u043d\u0430\u043d\u043e\u0432\u043e. +LogoutCommand.ShortDescription=\ + \u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u0434\u0430\u043d\u043d\u0438\u0442\u0435 \u0437\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f, \u0437\u0430\u043f\u0430\u0437\u0435\u043d\u0438 \u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u0442\u0430 \u0437\u0430 \u0432\u043b\u0438\u0437\u0430\u043d\u0435. +MailCommand.ShortDescription=\ + \u0418\u0437\u0447\u0438\u0442\u0430\u043d\u0435 \u043d\u0430 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438\u044f \u0432\u0445\u043e\u0434 \u0438 \u0438\u0437\u043f\u0440\u0430\u0449\u0430\u043d\u0435 \u043f\u043e \u0435-\u043f\u043e\u0449\u0430. +SetBuildDescriptionCommand.ShortDescription=\ + \u0417\u0430\u0434\u0430\u0432\u0430\u043d\u0435 \u043d\u0430 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u0442\u043e \u043d\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435. +SetBuildParameterCommand.ShortDescription=\ + \u041f\u0440\u043e\u043c\u044f\u043d\u0430/\u0437\u0430\u0434\u0430\u0432\u0430\u043d\u0435 \u043d\u0430 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0442\u0435 \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u043e\u0442\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435. +SetBuildResultCommand.ShortDescription=\ + \u0417\u0430\u0434\u0430\u0432\u0430\u043d\u0435 \u043d\u0430 \u0440\u0435\u0437\u0443\u043b\u0442\u0430\u0442\u0430 \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u043e\u0442\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435. \u041c\u043e\u0436\u0435 \u0434\u0430 \u0441\u0435 \u0438\u0437\u0432\u0438\u043a\u0432\u0430 \u0441\u0430\u043c\u043e \u043e\u0442\ + \u0437\u0430\u0434\u0430\u0447\u0430. +RemoveJobFromViewCommand.ShortDescription=\ + \u0418\u0437\u0432\u0430\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0438 \u043e\u0442 \u0438\u0437\u0433\u043b\u0435\u0434. +VersionCommand.ShortDescription=\ + \u0418\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u044f\u0442\u0430 \u043d\u0430 Jenkins. +GetJobCommand.ShortDescription=\ + \u0418\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0434\u0435\u0444\u0438\u043d\u0438\u0446\u0438\u044f\u0442\u0430 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430\u0442\u0430 \u0432\u044a\u0432 \u0444\u043e\u0440\u043c\u0430\u0442 XML \u043a\u044a\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438\u044f \u0438\u0437\u0445\u043e\u0434. +GetNodeCommand.ShortDescription=\ + \u0418\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0434\u0435\u0444\u0438\u043d\u0438\u0446\u0438\u044f\u0442\u0430 \u043d\u0430 \u0441\u044a\u0440\u0432\u044a\u0440 \u0432\u044a\u0432 \u0444\u043e\u0440\u043c\u0430\u0442 XML \u043a\u044a\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438\u044f \u0438\u0437\u0445\u043e\u0434. +GetViewCommand.ShortDescription=\ + \u0418\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0434\u0435\u0444\u0438\u043d\u0438\u0446\u0438\u044f\u0442\u0430 \u043d\u0430 \u0438\u0437\u0433\u043b\u0435\u0434\u0430 \u0432\u044a\u0432 \u0444\u043e\u0440\u043c\u0430\u0442 XML \u043a\u044a\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438\u044f \u0438\u0437\u0445\u043e\u0434. +SetBuildDisplayNameCommand.ShortDescription=\ + \u0417\u0430\u0434\u0430\u0432\u0430\u043d\u0435 \u043d\u0430 \u0438\u043c\u0435\u0442\u043e (displayName) \u043d\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435. +WhoAmICommand.ShortDescription=\ + \u0418\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0434\u0430\u043d\u043d\u0438\u0442\u0435 \u0437\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0438 \u043f\u0440\u0430\u0432\u0430\u0442\u0430. +UpdateJobCommand.ShortDescription=\ + \u041e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u0434\u0435\u0444\u0438\u043d\u0438\u0446\u0438\u044f\u0442\u0430 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u043e\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438\u044f \u0432\u0445\u043e\u0434 \u0432\u044a\u0432 \u0444\u043e\u0440\u043c\u0430\u0442 XML.\ + \u041e\u0431\u0440\u0430\u0442\u043d\u043e\u0442\u043e \u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u0442\u0430 \u201eget-job\u201c. +UpdateNodeCommand.ShortDescription=\ + \u041e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u0434\u0435\u0444\u0438\u043d\u0438\u0446\u0438\u044f\u0442\u0430 \u043d\u0430 \u0441\u044a\u0440\u0432\u044a\u0440 \u043e\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438\u044f \u0432\u0445\u043e\u0434 \u0432\u044a\u0432 \u0444\u043e\u0440\u043c\u0430\u0442 XML.\ + \u041e\u0431\u0440\u0430\u0442\u043d\u043e\u0442\u043e \u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u0442\u0430 \u201eget-node\u201c. +SessionIdCommand.ShortDescription=\ + \u0418\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u0430 \u043d\u0430 \u0441\u0435\u0441\u0438\u044f\u0442\u0430. \u0422\u043e\u0439 \u0441\u0435 \u0441\u043c\u0435\u043d\u044f \u043f\u0440\u0438 \u0432\u0441\u044f\u043a\u043e \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430\ + Jenkins. +UpdateViewCommand.ShortDescription=\ + \u041e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u0434\u0435\u0444\u0438\u043d\u0438\u0446\u0438\u044f\u0442\u0430 \u043d\u0430 \u0438\u0437\u0433\u043b\u0435\u0434 \u043e\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438\u044f \u0432\u0445\u043e\u0434 \u0432\u044a\u0432 \u0444\u043e\u0440\u043c\u0430\u0442 XML.\ + \u041e\u0431\u0440\u0430\u0442\u043d\u043e\u0442\u043e \u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u0442\u0430 \u201eget-view\u201c. + +BuildCommand.CLICause.ShortDescription=\ + \u0417\u0430\u0434\u0430\u0447\u0430\u0442\u0430 \u0435 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0430 \u043e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u0438\u044f \u0440\u0435\u0434 \u043e\u0442 \u201e{0}\u201c +BuildCommand.CLICause.CannotBuildDisabled=\ + \u0417\u0430\u0434\u0430\u0447\u0430\u0442\u0430 \u201e{0}\u201c \u0435 \u0438\u0437\u043a\u043b\u044e\u0447\u0435\u043d\u0430 \u0438 \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0441\u0435 \u0438\u0437\u0433\u0440\u0430\u0434\u0438. +BuildCommand.CLICause.CannotBuildConfigNotSaved=\ + \u0417\u0430\u0434\u0430\u0447\u0430\u0442\u0430 \u201e{0}\u201c \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0441\u0435 \u0438\u0437\u0433\u0440\u0430\u0434\u0438, \u0437\u0430\u0449\u043e\u0442\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u0442\u0435 \u045d \u043d\u0435 \u0441\u0430 \u0437\u0430\u043f\u0430\u0437\u0435\u043d\u0438. +BuildCommand.CLICause.CannotBuildUnknownReasons=\ + \u0417\u0430\u0434\u0430\u0447\u0430\u0442\u0430 \u201e{0}\u201c \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0441\u0435 \u0438\u0437\u0433\u0440\u0430\u0434\u0438 \u043f\u043e \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u0438 \u043f\u0440\u0438\u0447\u0438\u043d\u0438. diff --git a/core/src/main/resources/hudson/cli/Messages_da.properties b/core/src/main/resources/hudson/cli/Messages_da.properties new file mode 100644 index 0000000000000000000000000000000000000000..1bee62f87b20bc52ce0243212a8300ef09f7582b --- /dev/null +++ b/core/src/main/resources/hudson/cli/Messages_da.properties @@ -0,0 +1,4 @@ +DeleteNodeCommand.ShortDescription=Sletter en node +DeleteJobCommand.ShortDescription=Sletter et job + +OnlineNodeCommand.ShortDescription=Genoptag brugen af en byggenode, for at annullere en tidligere udstedt "offline-node" kommando. diff --git a/core/src/main/resources/hudson/cli/Messages_de.properties b/core/src/main/resources/hudson/cli/Messages_de.properties new file mode 100644 index 0000000000000000000000000000000000000000..4df178a57b934293074e75d074e894f332541248 --- /dev/null +++ b/core/src/main/resources/hudson/cli/Messages_de.properties @@ -0,0 +1,4 @@ +DeleteNodeCommand.ShortDescription=Knoten l\u00f6schen. +DeleteJobCommand.ShortDescription=Job l\u00f6schen. + +OnlineNodeCommand.ShortDescription=Knoten wird wieder f\u00fcr neue Builds verwendet. Hebt ein vorausgegangenes "offline-node"-Kommando auf. diff --git a/core/src/main/resources/hudson/cli/Messages_es.properties b/core/src/main/resources/hudson/cli/Messages_es.properties index 9f56ca37c0347dceaad00cd22a141f753fb64856..b0f51daa044a63beca169ec37d91e0415368617e 100644 --- a/core/src/main/resources/hudson/cli/Messages_es.properties +++ b/core/src/main/resources/hudson/cli/Messages_es.properties @@ -47,4 +47,8 @@ WhoAmICommand.ShortDescription=Muestra tus credenciales y permisos UpdateJobCommand.ShortDescription=Actualiza el fichero XML de la definicin de una tarea desde la entrada estndard. Es lo contrario al comando get-job. GroovyshCommand.ShortDescription=Ejecuta una shell interactiva de groovy. SetBuildDescriptionCommand.ShortDescription=Establece la descripcin de una ejecucin. +DeleteJobCommand.ShortDescription=Borrar una tarea +DeleteNodeCommand.ShortDescription=Borrar un nodo + +OnlineNodeCommand.ShortDescription=Continuar usando un nodo y candelar el comando "offline-node" mas reciente. diff --git a/core/src/main/resources/hudson/cli/Messages_it.properties b/core/src/main/resources/hudson/cli/Messages_it.properties new file mode 100644 index 0000000000000000000000000000000000000000..c5010ed77ac2b102ffd3a803b9dedf6f92d8855d --- /dev/null +++ b/core/src/main/resources/hudson/cli/Messages_it.properties @@ -0,0 +1,4 @@ +DeleteNodeCommand.ShortDescription=Cancella un nodo +DeleteJobCommand.ShortDescription=Cancella un job + +OnlineNodeCommand.ShortDescription=Resume using a node for performing builds, to cancel out the earlier "offline-node" command. diff --git a/core/src/main/resources/hudson/cli/Messages_ja.properties b/core/src/main/resources/hudson/cli/Messages_ja.properties index 9399b7f78b733d69672f691addf780d04b1f0a97..908949a71c403673ae54c37123b0ebdfb6a38b78 100644 --- a/core/src/main/resources/hudson/cli/Messages_ja.properties +++ b/core/src/main/resources/hudson/cli/Messages_ja.properties @@ -68,4 +68,9 @@ BuildCommand.CLICause.CannotBuildDisabled=\ BuildCommand.CLICause.CannotBuildConfigNotSaved=\ \u8a2d\u5b9a\u304c\u4fdd\u5b58\u3055\u308c\u3066\u3044\u306a\u3044\u306e\u3067{0}\u3092\u30d3\u30eb\u30c9\u3067\u304d\u307e\u305b\u3093\u3002 BuildCommand.CLICause.CannotBuildUnknownReasons=\ - \u30d3\u30eb\u30c9\u3067\u304d\u307e\u305b\u3093(\u539f\u56e0\u4e0d\u660e)\u3002 \ No newline at end of file + \u30d3\u30eb\u30c9\u3067\u304d\u307e\u305b\u3093(\u539f\u56e0\u4e0d\u660e)\u3002 + +DeleteNodeCommand.ShortDescription=\u30ce\u30fc\u30c9\u3092\u524a\u9664\u3057\u307e\u3059\u3002 +DeleteJobCommand.ShortDescription=\u30b8\u30e7\u30d6\u3092\u524a\u9664\u3057\u307e\u3059\u3002 + +OnlineNodeCommand.ShortDescription=\u76f4\u524d\u306b\u5b9f\u884c\u3057\u305f"online-node"\u30b3\u30de\u30f3\u30c9\u3092\u53d6\u308a\u6d88\u3057\u3001\u30d3\u30eb\u30c9\u3092\u5b9f\u884c\u3059\u308b\u30ce\u30fc\u30c9\u306e\u4f7f\u7528\u3092\u518d\u958b\u3057\u307e\u3059\u3002 diff --git a/core/src/main/resources/hudson/cli/Messages_pt_BR.properties b/core/src/main/resources/hudson/cli/Messages_pt_BR.properties index 007038f34b8275742e361079a317f772816391a4..6b924aa8de399970a79782b81ec04dfd3c3fa0f4 100644 --- a/core/src/main/resources/hudson/cli/Messages_pt_BR.properties +++ b/core/src/main/resources/hudson/cli/Messages_pt_BR.properties @@ -110,3 +110,13 @@ SessionIdCommand.ShortDescription=Exibe o ID de sess\u00e3o, que muda toda vez q InstallPluginCommand.InstallingPluginFromUrl=Instalando um plugin de {0} # Installs a plugin either from a file, an URL, or from update center. InstallPluginCommand.ShortDescription=Instala um plugin a partir de um arquivo, uma URL, ou da central de atualiza\u00e7\u00f5es. + +# Deletes a node +CLI.delete-node.shortDescription=Remover o n\u00f3 +# Deletes a job +DeleteJobCommand.ShortDescription=Remover uma job(s) + +ReloadJobCommand.ShortDescription=\ + Recarrega job(s) do disco. + +OnlineNodeCommand.ShortDescription=Continuar usando um n\u00f3 para realizar os builds diff --git a/core/src/main/resources/hudson/cli/Messages_zh_CN.properties b/core/src/main/resources/hudson/cli/Messages_zh_CN.properties new file mode 100644 index 0000000000000000000000000000000000000000..62e09b76124e6f7d9c29c2990c4826288b6e536c --- /dev/null +++ b/core/src/main/resources/hudson/cli/Messages_zh_CN.properties @@ -0,0 +1,2 @@ +DeleteNodeCommand.ShortDescription=Deletes a node +DeleteJobCommand.ShortDescription=Deletes a job diff --git a/core/src/main/resources/hudson/cli/Messages_zh_TW.properties b/core/src/main/resources/hudson/cli/Messages_zh_TW.properties index 0cf6f8ec1827d85f589883432376fa19127a50fe..7921933ce69354c5c064dd08faf88f688979fa7d 100644 --- a/core/src/main/resources/hudson/cli/Messages_zh_TW.properties +++ b/core/src/main/resources/hudson/cli/Messages_zh_TW.properties @@ -72,3 +72,6 @@ WhoAmICommand.ShortDescription=\ UpdateJobCommand.ShortDescription=\ \u7531 stdin \u66f4\u65b0\u4f5c\u696d\u5b9a\u7fa9 XML\u3002get-job \u6307\u4ee4\u7684\u76f8\u53cd BuildCommand.CLICause.ShortDescription=\u7531 {0} \u7684\u547d\u4ee4\u5217\u4ecb\u9762\u555f\u52d5 + +DeleteNodeCommand.ShortDescription=\u522a\u9664\u6307\u5b9a\u7bc0\u9ede\u3002 +DeleteJobCommand.ShortDescription=\u522a\u9664\u4f5c\u696d\u3002 diff --git a/core/src/main/resources/hudson/diagnosis/Messages_bg.properties b/core/src/main/resources/hudson/diagnosis/Messages_bg.properties new file mode 100644 index 0000000000000000000000000000000000000000..e3c18a009a1f322e8202958291c60a30b731efc5 --- /dev/null +++ b/core/src/main/resources/hudson/diagnosis/Messages_bg.properties @@ -0,0 +1,33 @@ +# The MIT License +# +# Bulgarian translation copyright 2015 Alexander Shopov . +# +# 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. + +MemoryUsageMonitor.USED=\ + \u0418\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u043d\u0438 +MemoryUsageMonitor.TOTAL=\ + \u041e\u0431\u0449\u043e +OldDataMonitor.Description=\ + \u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u0444\u0430\u0439\u043b\u043e\u0432\u0435\u0442\u0435 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438, \u0437\u0430 \u0434\u0430 \u0441\u0435 \u0438\u0437\u0447\u0438\u0441\u0442\u044f\u0442 \u043e\u0441\u0442\u0430\u0442\u044a\u0446\u0438\u0442\u0435 \u043e\u0442 \u0441\u0442\u0430\u0440\u0438\ + \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0438 \u0438 \u0432\u0435\u0440\u0441\u0438\u0438. +OldDataMonitor.DisplayName=\ + \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u0442\u0430\u0440\u0438\u0442\u0435 \u0434\u0430\u043d\u043d\u0438 +HudsonHomeDiskUsageMonitor.DisplayName=\ + \u0418\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u043d\u043e \u0434\u0438\u0441\u043a\u043e\u0432\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e diff --git a/core/src/main/resources/hudson/diagnosis/Messages_ja.properties b/core/src/main/resources/hudson/diagnosis/Messages_ja.properties index ea31b5ffb48486be05cc791eee6fb3bb5a01225d..56ebaace8b5eabcd68b844e806771acbf012d907 100644 --- a/core/src/main/resources/hudson/diagnosis/Messages_ja.properties +++ b/core/src/main/resources/hudson/diagnosis/Messages_ja.properties @@ -25,4 +25,5 @@ MemoryUsageMonitor.TOTAL=\u5408\u8a08 OldDataMonitor.DisplayName=\u65e7\u30c7\u30fc\u30bf\u306e\u7ba1\u7406 OldDataMonitor.Description=\ \u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u3092\u6574\u7406\u3057\u3066\u3001\u53e4\u3044\u30d7\u30e9\u30b0\u30a4\u30f3\u3084\u524d\u30d0\u30fc\u30b8\u30e7\u30f3\u306e\u4e0d\u8981\u306a\u60c5\u5831\u3092\u53d6\u308a\u9664\u304d\u307e\u3059\u3002 +HudsonHomeDiskUsageMonitor.DisplayName=\u30c7\u30a3\u30b9\u30af\u4f7f\u7528\u91cf\u30e2\u30cb\u30bf diff --git a/core/src/main/resources/hudson/diagnosis/NullIdDescriptorMonitor/message_ja.properties b/core/src/main/resources/hudson/diagnosis/NullIdDescriptorMonitor/message_ja.properties index 7464882b73af3aeda2613db7b2d850ede08b4581..4956a88dd19fc1dd35bd854675489bc5e063c270 100644 --- a/core/src/main/resources/hudson/diagnosis/NullIdDescriptorMonitor/message_ja.properties +++ b/core/src/main/resources/hudson/diagnosis/NullIdDescriptorMonitor/message_ja.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2011, Seiji Sogabe +# Copyright (c) 2011-2015, Seiji Sogabe # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -23,4 +23,4 @@ blurb=\ \u6b21\u306e\u30d7\u30e9\u30b0\u30a4\u30f3\u306f\u3001ID\u3092\u6301\u3063\u3066\u3044\u306a\u3044\u306e\u3067\u554f\u984c\u3092\u8d77\u3053\u3059\u53ef\u80fd\u6027\u304c\u3042\u308a\u307e\u3059\u3002\u30d7\u30e9\u30b0\u30a4\u30f3\u3092\u6700\u65b0\u306e\u7269\u306b\u30a2\u30c3\u30d7\u30b0\u30ec\u30fc\u30c9\u3057\u3066\u304f\u3060\u3055\u3044\u3002\ \u6700\u65b0\u306e\u7269\u3067\u3042\u308c\u3070\u3001\u4fee\u6b63\u3067\u304d\u308b\u3088\u3046\u306bJIRA\u306b\u30d0\u30b0\u3068\u3057\u3066\u767b\u9332\u3057\u3066\u304f\u3060\u3055\u3044\u3002 -problem=Descriptor {0} from plugin {2} with display name {1} \ No newline at end of file +problem=\u30d7\u30e9\u30b0\u30a4\u30f3 {2} \u306e\u30c7\u30a3\u30b9\u30af\u30ea\u30d7\u30bf {0} (\u8868\u793a\u540d {1}) \ No newline at end of file diff --git a/core/src/main/resources/hudson/fsp/Messages_bg.properties b/core/src/main/resources/hudson/fsp/Messages_bg.properties new file mode 100644 index 0000000000000000000000000000000000000000..c7382a4a99a360cec90dc4f435c7b9ca6b2449d8 --- /dev/null +++ b/core/src/main/resources/hudson/fsp/Messages_bg.properties @@ -0,0 +1,36 @@ +# The MIT License +# +# Bulgarian translation copyright 2015 Alexander Shopov . +# +# 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. + +WorkspaceSnapshotSCM.NoSuchJob=\ + \u0417\u0430\u0434\u0430\u0447\u0430 \u0441 \u0438\u043c\u0435 \u201e{0}\u201c \u043d\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430. \u201e{1}\u201c \u043b\u0438 \u0438\u043c\u0430\u0442\u0435 \u043f\u0440\u0435\u0434\u0432\u0438\u0434? +WorkspaceSnapshotSCM.IncorrectJobType=\ + \u0417\u0430\u0434\u0430\u0447\u0430\u0442\u0430 \u201e{0}\u201c \u043d\u044f\u043c\u0430 \u0440\u0430\u0431\u043e\u0442\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e. +WorkspaceSnapshotSCM.NoBuild=\ + \u041d\u0438\u043a\u043e\u0435 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u043d\u0435 \u0441\u044a\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0430 \u043d\u0430 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u0430\u0442\u0430 \u0432\u0440\u044a\u0437\u043a\u0430 \u201e{0}\u201c \u043a\u044a\u043c \u043d\u0430\u0441\u043b\u0435\u0434\u0435\u043d\u043e\u0442\u043e\ + \u0440\u0430\u0431\u043e\u0442\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u043e\u0442 \u201e{1}\u201c. +WorkspaceSnapshotSCM.NoSuchPermalink=\ + \u041b\u0438\u043f\u0441\u0432\u0430 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u0430\u0442\u0430 \u0432\u0440\u044a\u0437\u043a\u0430 \u201e{0}\u201c \u043a\u044a\u043c \u043d\u0430\u0441\u043b\u0435\u0434\u0435\u043d\u043e\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u043e\u0442 \u201e{1}\u201c. +WorkspaceSnapshotSCM.NoWorkspace=\ + \u041b\u0438\u043f\u0441\u0432\u0430 \u0440\u0430\u0431\u043e\u0442\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u043a\u044a\u043c \u0437\u0430\u0434\u0430\u0447\u0430 {0} \u0441 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u0430 \u0432\u0440\u044a\u0437\u043a\u0430\ + {1}.\n\u041d\u0430\u0439-\u0432\u0435\u0440\u043e\u044f\u0442\u043d\u0430\u0442\u0430 \u043f\u0440\u0438\u0447\u0438\u043d\u0430 \u0435, \u0447\u0435 \u043d\u0438\u043a\u043e\u044f \u0434\u0440\u0443\u0433\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u043d\u0435 \u0441\u0435 \u0435 \u043d\u0443\u0436\u0434\u0430\u0435\u043b\u0430 \u043e\u0442\ + \u0440\u0430\u0431\u043e\u0442\u043d\u043e\u0442\u043e \u045d \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u043f\u043e \u0432\u0440\u0435\u043c\u0435 \u043d\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435\u0442\u043e.\n\u0421\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u0439\u0442\u0435 \u043d\u043e\u0432\u043e\ + \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 {0}, \u0437\u0430 \u0434\u0430 \u0441\u0435 \u0437\u0430\u043f\u0430\u0437\u0438 \u0441\u044a\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u0442\u043e \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u043d\u043e\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e. diff --git a/core/src/main/resources/hudson/init/impl/Messages_bg.properties b/core/src/main/resources/hudson/init/impl/Messages_bg.properties new file mode 100644 index 0000000000000000000000000000000000000000..01a1bfd123673058c312d8b4f4daa790347dabb7 --- /dev/null +++ b/core/src/main/resources/hudson/init/impl/Messages_bg.properties @@ -0,0 +1,26 @@ +# The MIT License +# +# Bulgarian translation copyright 2015 Alexander Shopov . +# +# 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. + +GroovyInitScript.init=\ + \u0418\u0437\u043f\u044a\u043b\u043d\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0430\u0449 \u0441\u043a\u0440\u0438\u043f\u0442 +InitialUserContent.init=\ + \u041f\u043e\u0434\u0433\u043e\u0442\u0432\u044f\u043d\u0435 \u043d\u0430 \u043f\u044a\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u043d\u043e\u0442\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u043e \u0441\u044a\u0434\u044a\u0440\u0436\u0430\u043d\u0438\u0435 diff --git a/core/src/main/resources/hudson/lifecycle/Messages_bg.properties b/core/src/main/resources/hudson/lifecycle/Messages_bg.properties new file mode 100644 index 0000000000000000000000000000000000000000..9c994c04f81a78e38c5077b95c8daeac2bcaf703 --- /dev/null +++ b/core/src/main/resources/hudson/lifecycle/Messages_bg.properties @@ -0,0 +1,36 @@ +# The MIT License +# +# Bulgarian translation copyright 2015 Alexander Shopov . +# +# 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. + +WindowsInstallerLink.DisplayName=\ + \u0418\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0435 \u043a\u0430\u0442\u043e \u0443\u0441\u043b\u0443\u0433\u0430 \u043d\u0430 Windows +WindowsInstallerLink.Description=\ + \u0418\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 Jenkins \u043a\u0430\u0442\u043e \u0443\u0441\u043b\u0443\u0433\u0430 \u043d\u0430 \u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0438\u044f \u043d\u0430 \u0442\u0430\u0437\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 Windows, \u0437\u0430\ + \u0434\u0430 \u043c\u043e\u0436\u0435 \u0442\u043e\u0439 \u0434\u0430 \u0441\u0435 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430 \u0437\u0430\u0435\u0434\u043d\u043e \u0441 \u043c\u0430\u0448\u0438\u043d\u0430\u0442\u0430. +WindowsSlaveInstaller.ConfirmInstallation=\ + \u0422\u043e\u0432\u0430 \u0449\u0435 \u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d \u0430\u0433\u0435\u043d\u0442 \u043a\u0430\u0442\u043e \u0443\u0441\u043b\u0443\u0433\u0430 \u043d\u0430 \u0438\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0438\u044f \u043d\u0430 \u0442\u0430\u0437\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\ + Windows, \u0437\u0430 \u0434\u0430 \u043c\u043e\u0436\u0435 \u0442\u043e\u0439 \u0434\u0430 \u0441\u0435 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430 \u0437\u0430\u0435\u0434\u043d\u043e \u0441 \u043c\u0430\u0448\u0438\u043d\u0430\u0442\u0430. +WindowsSlaveInstaller.DotNetRequired=\ + \u0417\u0430 \u0442\u043e\u0432\u0430 \u0441\u0435 \u0438\u0437\u0438\u0441\u043a\u0432\u0430 .NET Framework, \u0432\u0435\u0440\u0441\u0438\u044f 2.0 \u0438\u043b\u0438 \u043f\u043e-\u0432\u0438\u0441\u043e\u043a\u0430 +WindowsSlaveInstaller.InstallationSuccessful=\ + \u0423\u0441\u043f\u0435\u0448\u043d\u0430 \u0438\u043d\u0441\u0442\u0430\u043b\u0430\u0446\u0438\u044f. \u0414\u0430 \u0441\u0435 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430 \u043b\u0438 \u0443\u0441\u043b\u0443\u0433\u0430\u0442\u0430? +WindowsSlaveInstaller.RootFsDoesntExist=\ + \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u0442\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u043d\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d\u0438\u044f \u0430\u0433\u0435\u043d\u0442 \u201e{0}\u201c \u043d\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430. diff --git a/core/src/main/resources/hudson/lifecycle/WindowsInstallerLink/_restart.properties b/core/src/main/resources/hudson/lifecycle/WindowsInstallerLink/_restart.properties index f1188ae173b20eb2b643c8f847bbaddacdcc0f41..31eae4527a8bad551066df5b8e82304b580ead06 100644 --- a/core/src/main/resources/hudson/lifecycle/WindowsInstallerLink/_restart.properties +++ b/core/src/main/resources/hudson/lifecycle/WindowsInstallerLink/_restart.properties @@ -21,5 +21,5 @@ # THE SOFTWARE. blurb=You should be taken automatically to the new Jenkins in a few seconds. \ - If for some reasons the service fails to start, check Windows event log for errors and consult \ - online wiki page. + If for some reason the service fails to start, please check the Windows event log for errors and consult the wiki page \ + located at the official wiki. diff --git a/core/src/main/resources/hudson/logging/LogRecorder/index_ja.properties b/core/src/main/resources/hudson/logging/LogRecorder/index_ja.properties new file mode 100644 index 0000000000000000000000000000000000000000..14d9e2bf96c7defdfa6c9925679d96799b951047 --- /dev/null +++ b/core/src/main/resources/hudson/logging/LogRecorder/index_ja.properties @@ -0,0 +1,23 @@ +# The MIT License +# +# Copyright (c) 2004-2015, Seiji Sogabe +# +# 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. + +Clear\ This\ Log=\u30af\u30ea\u30a2 diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_bg.properties b/core/src/main/resources/hudson/logging/Messages_bg.properties similarity index 73% rename from core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_bg.properties rename to core/src/main/resources/hudson/logging/Messages_bg.properties index de74757cf3f2dddf32bf796284d3e344d6aba49d..2c8f53b916e6a82f1ccfb608d95e335153bd5da7 100644 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_bg.properties +++ b/core/src/main/resources/hudson/logging/Messages_bg.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2010, Sun Microsystems, Inc. +# Bulgarian translation copyright 2015 Alexander Shopov . # # 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,5 +20,7 @@ # 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 +LogRecorderManager.init=\ + \u041f\u043e\u0434\u0433\u043e\u0442\u0432\u044f\u043d\u0435 \u043d\u0430 \u0437\u0430\u043f\u0438\u0441\u0432\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0436\u0443\u0440\u043d\u0430\u043b\u0438\u0442\u0435 +LogRecorderManager.DisplayName=\ + \u0436\u0443\u0440\u043d\u0430\u043b diff --git a/core/src/main/resources/hudson/markup/EscapedMarkupFormatter/config_ja.properties b/core/src/main/resources/hudson/markup/EscapedMarkupFormatter/config_ja.properties new file mode 100644 index 0000000000000000000000000000000000000000..996b78979c0099802fef4b84717cc46cbcbdbf19 --- /dev/null +++ b/core/src/main/resources/hudson/markup/EscapedMarkupFormatter/config_ja.properties @@ -0,0 +1 @@ +blurb=\u5165\u529b\u3092\u3059\u3079\u3066\u30c6\u30ad\u30b9\u30c8\u3068\u3057\u3066\u6271\u3044\u307e\u3059\u3002HTML\u3067\u5b89\u5168\u3067\u306a\u3044'<'\u3084'&'\u3092\u5bfe\u5fdc\u3059\u308b\u6587\u5b57\u53c2\u7167\u306b\u30a8\u30b9\u30b1\u30fc\u30d7\u3057\u307e\u3059\u3002 diff --git a/core/src/main/resources/hudson/markup/Messages.properties b/core/src/main/resources/hudson/markup/Messages.properties index 24c2921e9b0a2764ffc54dbaea53d6e091b1606a..9b79e845e2ba2445434b5cb934210ed960f11ed5 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=Escaped HTML +EscapedMarkupFormatter.DisplayName=Plain text diff --git a/core/src/main/resources/hudson/markup/Messages_bg.properties b/core/src/main/resources/hudson/markup/Messages_bg.properties new file mode 100644 index 0000000000000000000000000000000000000000..e1a1c9c1e804aec5d45db5e4d42203b4f4b776d3 --- /dev/null +++ b/core/src/main/resources/hudson/markup/Messages_bg.properties @@ -0,0 +1,24 @@ +# The MIT License +# +# Bulgarian translation copyright 2015 Alexander Shopov . +# +# 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. + +EscapedMarkupFormatter.DisplayName=\ + \u041e\u0431\u0438\u043a\u043d\u043e\u0432\u0435\u043d \u0442\u0435\u043a\u0441\u0442 diff --git a/core/src/main/resources/hudson/markup/Messages_ja.properties b/core/src/main/resources/hudson/markup/Messages_ja.properties new file mode 100644 index 0000000000000000000000000000000000000000..e32b5aed7fe7f5d4b13d887c8db00561e3885d62 --- /dev/null +++ b/core/src/main/resources/hudson/markup/Messages_ja.properties @@ -0,0 +1,23 @@ +# The MIT License +# +# Copyright (c) 2015, Seiji Sogabe +# +# 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. + +EscapedMarkupFormatter.DisplayName=HTML\u3092\u30a8\u30b9\u30b1\u30fc\u30d7 diff --git a/core/src/main/resources/hudson/model/AbstractBuild/changes.jelly b/core/src/main/resources/hudson/model/AbstractBuild/changes.jelly index 8b357557fff90a16869f5640f75582124a5a3c39..f030f796e3f2bc7c7c0b0379b5a96758713a4597 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}) + + 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 e601d09c8842e6b38dd72d7e18d6c01974388abf..7e954f685444d58667af666a494eb47f63e5b33c 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 cb85ec5b930365cab2c9f674b4f0a8b4f3775848..8a54bd9d030ae6c22d33a6b5ad8cf9affc54ac1a 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 70b25b6c110bed38804a5c559fe960458aa145ff..8695d88bf5bf29de187b7f09b606153f3599d723 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 diff --git a/core/src/main/resources/hudson/model/AbstractBuild/tasks_ja.properties b/core/src/main/resources/hudson/model/AbstractBuild/tasks_ja.properties index 4ac300d2ee7574e1877fc79d63baa28108e2b89c..1782f6be5e803677bd9151f99ba103b9146e9585 100644 --- a/core/src/main/resources/hudson/model/AbstractBuild/tasks_ja.properties +++ b/core/src/main/resources/hudson/model/AbstractBuild/tasks_ja.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2012, Sun Microsystems, Inc.,Seiji Sogabe +# Copyright (c) 2004-2015, Sun Microsystems, Inc.,Seiji Sogabe # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -23,8 +23,4 @@ Back\ to\ Project=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3078\u623b\u308b Status=\u72b6\u614b Changes=\u5909\u66f4\u5c65\u6b74 -Console\ Output=\u30b3\u30f3\u30bd\u30fc\u30eb\u51fa\u529b -View\ as\ plain\ text=\u30D7\u30EC\u30FC\u30F3\u30C6\u30AD\u30B9\u30C8\u3067\u8868\u793A -raw=\u672a\u52a0\u5de5 Edit\ Build\ Information=\u8aac\u660e\u306e\u7de8\u96c6 -View\ Build\ Information=\u8aac\u660e\u3092\u53c2\u7167 diff --git a/core/src/main/resources/hudson/model/AbstractBuild/tasks_pt_BR.properties b/core/src/main/resources/hudson/model/AbstractBuild/tasks_pt_BR.properties index 149bfe88fccf44a683ba7dc7b7280a8054717a39..49ae1e411c5f49d79982a291986902d68bddf8cc 100644 --- a/core/src/main/resources/hudson/model/AbstractBuild/tasks_pt_BR.properties +++ b/core/src/main/resources/hudson/model/AbstractBuild/tasks_pt_BR.properties @@ -24,48 +24,3 @@ Back\ to\ Project=Voltar ao projeto Changes=Altera\u00E7\u00F5es Edit\ Build\ Information=Editar informa\u00E7\u00F5es de compila\u00E7\u00E3o Status=Estado pessoal -Jenkins -\u2026 -Translation Assistance Plugin -License of contribution to Jenkins translation -Edit -Add -Page -Gliffy Diagram -Comment -Attachment -Tools -Attachments (0) -Page History -Restrictions -Edit in Word -Favourite -Watch -Info -Link to this Page\u2026 -View in Hierarchy -View Wiki Markup -Export to PDF -Export to Word -Import Word Document -Copy -Move - License of contribution to Jenkins translation -Added by Kohsuke Kawaguchi, last edited by Kohsuke Kawaguchi on Aug 29, 2011 -Jenkins -Home -Mailing lists -Source code -Bugtracker -Security Advisories -Donation -Commercial Support -Wiki Site Map -Documents -Meet Jenkins -Use Jenkins -Extend Jenkins -Plugins -Servlet Container Notes - This page is the landing page for the translation assistance plugin''s "contribute" link -When you check the "I contribute my translations to the Jenkins project" link, you acknowledge that your submission will be licensed under the MIT license (the same license that the rest of the Jenkins core uses) and you have the rights to release them under the said license. diff --git a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_ja.properties b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_ja.properties index 16f95aea299ab75402458388ab14cbe2e5e2624e..6f2a4b51856d7332072df660c644f2c24b776ab4 100644 --- a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_ja.properties +++ b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_ja.properties @@ -32,4 +32,4 @@ The\ slave\ this\ project\ has\ run\ on\ for\ the\ last\ time\ was\ removed.=\ li3=\u30ef\u30fc\u30af\u30b9\u30da\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\uff08{0}\uff09\u304cJenkins\u306e\u7ba1\u7406\u5916\u3078\u53d6\u308a\u9664\u304b\u308c\u305f\u3002 text=\u30d3\u30eb\u30c9\u3092\u5b9f\u884c\u3057\u3066\u3001\u30ef\u30fc\u30af\u30b9\u30da\u30fc\u30b9\u3092\u4f5c\u6210\u3057\u3066\u304f\u3060\u3055\u3044\u3002 The\ workspace\ was\ wiped\ out\ and\ no\ build\ has\ been\ done\ since\ then.=\ - \u30ef\u30fc\u30af\u30b9\u30da\u30fc\u30b9\u304c\u524a\u9664\u3055\u308c\u3066\u304b\u3089\u4e00\u5ea6\u3082\u30d3\u30eb\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 + \u30ef\u30fc\u30af\u30b9\u30da\u30fc\u30b9\u304c\u524a\u9664\u3055\u308c\u3066\u304b\u3089\u4e00\u5ea6\u3082\u30d3\u30eb\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 \ No newline at end of file diff --git a/core/src/main/resources/hudson/model/AbstractProject/configure-common_ja.properties b/core/src/main/resources/hudson/model/AbstractProject/configure-common_ja.properties index 4f16cd9df2bbe9d7c59f7909a875f29c1e0bc02c..e80eeec69ee8c04616da4e2ad5e90c3afbde1f16 100644 --- a/core/src/main/resources/hudson/model/AbstractProject/configure-common_ja.properties +++ b/core/src/main/resources/hudson/model/AbstractProject/configure-common_ja.properties @@ -22,6 +22,5 @@ JDK\ to\ be\ used\ for\ this\ project=\u3053\u306e\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u3067\u4f7f\u7528\u3059\u308bJDK Advanced\ Project\ Options=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u9ad8\u5ea6\u306a\u30aa\u30d7\u30b7\u30e7\u30f3 -default.value=\u30c7\u30d5\u30a9\u30eb\u30c8 Display\ Name=\u8868\u793a\u7528\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u540d Keep\ the\ build\ logs\ of\ dependencies=\u4f9d\u5b58\u3057\u3066\u3044\u308b\u4e0a\u6d41\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u30d3\u30eb\u30c9\u3092\u4fdd\u5b58 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 diff --git a/core/src/main/resources/hudson/model/AbstractProject/sidepanel_ja.properties b/core/src/main/resources/hudson/model/AbstractProject/sidepanel_ja.properties index 4ec1e1eb7f592f6f223c11f3830f3a46058d13b2..3c841671ad938d780891203c7b87c25b048ed8f0 100644 --- a/core/src/main/resources/hudson/model/AbstractProject/sidepanel_ja.properties +++ b/core/src/main/resources/hudson/model/AbstractProject/sidepanel_ja.properties @@ -26,3 +26,4 @@ Changes=\u5909\u66f4\u5c65\u6b74 Workspace=\u30ef\u30fc\u30af\u30b9\u30da\u30fc\u30b9 Wipe\ Out\ Workspace=\u30ef\u30fc\u30af\u30b9\u30da\u30fc\u30b9\u306e\u30af\u30ea\u30a2 wipe.out.confirm=\u30ef\u30fc\u30af\u30b9\u30da\u30fc\u30b9\u3092\u30af\u30ea\u30a2\u3057\u3066\u3082\u3088\u308d\u3057\u3044\u3067\u3059\u304b? +Up=\u4e0a\u3078 \ No newline at end of file diff --git a/core/src/main/resources/hudson/model/AllView/noJob_es.properties b/core/src/main/resources/hudson/model/AllView/noJob_es.properties index 7b9fbb90aac32aae861a88f9ef9ed2cad5bf0781..064002b28d15ebc2be3d623199741b7f500b31ee 100644 --- a/core/src/main/resources/hudson/model/AllView/noJob_es.properties +++ b/core/src/main/resources/hudson/model/AllView/noJob_es.properties @@ -24,8 +24,7 @@ newJob=Por favor, crea una nueva tarea para empezar. login=Entra para crear nuevas tareas. -signup=Si no tienes una cuenta, puedes crear una ahora. -newJob=Por favor, crea una nueva tarea para empezar. -Welcome\ to\ Jenkins!=\u00A1Bienvenido a Jenkins! -signup=Registrarse - +# TODO pick one: +#signup=Si no tienes una cuenta, puedes crear una ahora. +#signup=Registrarse +Welcome\ to\ Jenkins!=\u00a1Bienvenido a Jenkins! diff --git a/core/src/main/resources/hudson/model/AllView/noJob_ja.properties b/core/src/main/resources/hudson/model/AllView/noJob_ja.properties index 451095c8112536e7e17d73ecc6dba3734f9e0793..51ea581c99690124e25224b0f7f0386a2b4d4e70 100644 --- a/core/src/main/resources/hudson/model/AllView/noJob_ja.properties +++ b/core/src/main/resources/hudson/model/AllView/noJob_ja.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe +# Copyright (c) 2004-2015, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe # # 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,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Welcome\ to\ Jenkins!=Jenkins\u3078\u3088\u3046\u3053\u305D\uFF01 -newJob=\u958B\u59CB\u3059\u308B\u305F\u3081\u306B\u65B0\u3057\u3044\u30B8\u30E7\u30D6\u3092\u4F5C\u6210\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -login=\u65B0\u3057\u3044\u30B8\u30E7\u30D6\u3092\u4F5C\u6210\u3059\u308B\u306B\u306F\u3001\u30ED\u30B0\u30A4\u30F3\u3057\u3066\u304F\u3060\u3055\u3044\u3002 -signup=\u3082\u3057\u3042\u306A\u305F\u304C\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u6301\u3063\u3066\u3044\u306A\u3051\u308C\u3070\u3001\u4ECA\u53C2\u52A0\u3059\u308B\u3053\u3068\u304C\u3067\u304D\u307E\u3059\u3002 +Welcome\ to\ Jenkins!=Jenkins\u3078\u3088\u3046\u3053\u305d\uff01 +newJob=\u65b0\u3057\u3044\u30b8\u30e7\u30d6\u3092\u4f5c\u6210\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +login=\u65b0\u3057\u3044\u30b8\u30e7\u30d6\u3092\u4f5c\u6210\u3059\u308b\u306b\u306f\u3001\u30ed\u30b0\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +signup=\u3082\u3057\u3042\u306a\u305f\u304c\u30a2\u30ab\u30a6\u30f3\u30c8\u3092\u6301\u3063\u3066\u3044\u306a\u3051\u308c\u3070\u3001\u4eca\u53c2\u52a0\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002 diff --git a/core/src/main/resources/hudson/model/Computer/index_ja.properties b/core/src/main/resources/hudson/model/Computer/index_ja.properties index 7fd43bc04626afc617539ff912446e132a6968f2..16b6e48a217718817d27eb182fbd7d50f403ab37 100644 --- a/core/src/main/resources/hudson/model/Computer/index_ja.properties +++ b/core/src/main/resources/hudson/model/Computer/index_ja.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe +# Copyright (c) 2004-2015, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -23,7 +23,7 @@ submit.temporarilyOffline=\u3053\u306e\u30ce\u30fc\u30c9\u3092\u30aa\u30f3\u30e9\u30a4\u30f3\u306b\u623b\u3059 submit.not.temporarilyOffline=\u3053\u306e\u30ce\u30fc\u30c9\u3092\u4e00\u6642\u7684\u306b\u30aa\u30d5\u30e9\u30a4\u30f3\u306b\u3059\u308b None=\u306a\u3057 -Labels\:=\u30e9\u30d9\u30eb: +Labels\=\u30e9\u30d9\u30eb title.projects_tied_on={0}\u3067\u306e\u307f\u8d77\u52d5\u3059\u308b\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 title.no_manual_launch=\u3053\u306e\u30ce\u30fc\u30c9\u306e\u53ef\u7528\u6027\u306e\u30dd\u30ea\u30b7\u30fc\u306f''{0}''\u3067\u3059\u3002\u73fe\u5728\u3001\u305d\u306e\u30dd\u30ea\u30b7\u30fc\u306b\u57fa\u3065\u3044\u3066\u3001\u3053\u306e\u30ce\u30fc\u30c9\u306f\u30aa\u30d5\u30e9\u30a4\u30f3\u306b\u306a\u3063\u3066\u3044\u307e\u3059\u3002 Created\ by=\u30ce\u30fc\u30c9\u4f5c\u6210\u8005 diff --git a/core/src/main/resources/hudson/model/Computer/sidepanel.jelly b/core/src/main/resources/hudson/model/Computer/sidepanel.jelly index 7d81d64346332571927305f64a676785c731ceb2..2a74c154e76ab2050b44ae38808e9a37c0a71610 100644 --- a/core/src/main/resources/hudson/model/Computer/sidepanel.jelly +++ b/core/src/main/resources/hudson/model/Computer/sidepanel.jelly @@ -36,7 +36,9 @@ THE SOFTWARE. - + + + @@ -45,4 +47,4 @@ THE SOFTWARE. - \ No newline at end of file + 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 8c6eea983d6254acd088f87d083b0549055c8421..bc7f5949bde8e7c69e08481fd3381264c54eb0b8 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 diff --git a/core/src/main/resources/hudson/model/ComputerSet/new_de.properties b/core/src/main/resources/hudson/model/ComputerSet/new_de.properties index 3cb16aa6f4cbc0ac72ae5910376211e34beb1102..eef62f4d85eda30ebf7126913d8214325ba4fd73 100644 --- a/core/src/main/resources/hudson/model/ComputerSet/new_de.properties +++ b/core/src/main/resources/hudson/model/ComputerSet/new_de.properties @@ -1,2 +1,2 @@ -Node\ name=Name des Knoten +Node\ name=Name des Knotens Copy\ Existing\ Node=Kopiere bestehenden Knoten diff --git a/core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly b/core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly index a0036a1727bbb112829481d555359da17cb7b307..831ca12d7e73ba95db63cb7d54cb86df59a0b0f0 100644 --- a/core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly +++ b/core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly @@ -36,7 +36,7 @@ THE SOFTWARE. - + \ No newline at end of file diff --git a/core/src/main/resources/hudson/model/Fingerprint/index.jelly b/core/src/main/resources/hudson/model/Fingerprint/index.jelly index 88cf473961517e773cd4b28851f554b02c0658d8..e76741d3eebf1f266b57e6f66a2f18f6727ccc62 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}:

@@ -55,16 +68,16 @@ THE SOFTWARE. ${%Uninstall}
+ + @@ -106,16 +119,30 @@ THE SOFTWARE. +

${%Uninstallation pending}

- -
- -
-
+ + +
+ + + +
+
+ +
+ + + +
+
+
+ +
+
+ - - - - - + + + + + + +
- - - ${j} - - - ${j} - - - - -
+ ${j} + + +
diff --git a/core/src/main/resources/hudson/model/Job/_api.jelly b/core/src/main/resources/hudson/model/Job/_api.jelly index 684e8cc9fe37bafe70fb54bfe89ccb3e048af949..f2ee7bcf00c8b92ff746d6c6fb07a60dc67002e4 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 diff --git a/core/src/main/resources/hudson/model/Job/buildTimeTrend_ja.properties b/core/src/main/resources/hudson/model/Job/buildTimeTrend_ja.properties index 37d51aefd31648648958db50c8e4206c5d3cb471..c147732ca4688bf3f66b5993e091b8b4ea0f83a9 100644 --- a/core/src/main/resources/hudson/model/Job/buildTimeTrend_ja.properties +++ b/core/src/main/resources/hudson/model/Job/buildTimeTrend_ja.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe +# Copyright (c) 2004-2015, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe # # 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,10 +20,9 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -title={0}\u306E\u30D3\u30EB\u30C9\u6642\u9593\u306E\u50BE\u5411 -Timeline=\u30BF\u30A4\u30E0\u30E9\u30A4\u30F3 -Build=\u30D3\u30EB\u30C9 -Build\ Time\ Trend=\u30D3\u30EB\u30C9\u6642\u9593\u306E\u63A8\u79FB +title={0}\u306e\u30d3\u30eb\u30c9\u6642\u9593\u306e\u50be\u5411 +Timeline=\u30bf\u30a4\u30e0\u30e9\u30a4\u30f3 +Build=\u30d3\u30eb\u30c9 +Build\ Time\ Trend=\u30d3\u30eb\u30c9\u6642\u9593\u306e\u63a8\u79fb Duration=\u6240\u8981\u6642\u9593 -Slave=\u30B9\u30EC\u30FC\u30D6 -More\ than\ 1\ builds\ are\ needed\ for\ the\ trend\ report.=\u30B0\u30E9\u30D5\u3092\u63CF\u753B\u3059\u308B\u305F\u3081\u306B\u306F\u6700\u4F4E\uFF12\u3064\u306E\u30D3\u30EB\u30C9\u304C\u5FC5\u8981\u3067\u3059\u3002 +Slave=\u30b9\u30ec\u30fc\u30d6 diff --git a/core/src/main/resources/hudson/model/Job/configure.jelly b/core/src/main/resources/hudson/model/Job/configure.jelly index afe44da1bd374befb5c4130690570ccb5afc823f..ec2a5b68397f7c8884782e2ef29e03f02d2d0d0c 100644 --- a/core/src/main/resources/hudson/model/Job/configure.jelly +++ b/core/src/main/resources/hudson/model/Job/configure.jelly @@ -45,17 +45,7 @@ THE SOFTWARE. - - - - - - - - - + diff --git a/core/src/main/resources/hudson/model/Job/configure_bg.properties b/core/src/main/resources/hudson/model/Job/configure_bg.properties index 5d8f2e70290e730c5c17a2606ed3b2fb62d2f2b4..ce529367c73812f6c6f02c42d70e458401cc4a97 100644 --- a/core/src/main/resources/hudson/model/Job/configure_bg.properties +++ b/core/src/main/resources/hudson/model/Job/configure_bg.properties @@ -21,7 +21,6 @@ # THE SOFTWARE. Description=\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 -Discard\ Old\ Builds=\u041F\u0440\u0435\u043D\u0435\u0431\u0440\u0435\u0433\u0432\u0430\u043D\u0435 \u043D\u0430 \u0441\u0442\u0430\u0440\u0438\u0442\u0435 \u0431\u0438\u043B\u0434\u043E\u0432\u0435 LOADING=\u0417\u0430\u0440\u0435\u0436\u0434\u0430\u043D\u0435 Save=\u0417\u0430\u043F\u0438\u0448\u0438 name=\u0438\u043C\u0435 diff --git a/core/src/main/resources/hudson/model/Job/configure_cs.properties b/core/src/main/resources/hudson/model/Job/configure_cs.properties index a3242e7567da4b4ce04638638af87a0938029a90..c898b2bb2828ae9fee62e4a304ac8ebe1fcb76e9 100644 --- a/core/src/main/resources/hudson/model/Job/configure_cs.properties +++ b/core/src/main/resources/hudson/model/Job/configure_cs.properties @@ -1,6 +1,5 @@ # This file is under the MIT License by authors Description=Popis -Discard\ Old\ Builds=Zahodit star\u00E9 sestaven\u00ED LOADING=Nahr\u00E1v\u00E1n\u00ED name=jm\u00E9no diff --git a/core/src/main/resources/hudson/model/Job/configure_da.properties b/core/src/main/resources/hudson/model/Job/configure_da.properties index fa65b1a3d76999aa0ba224b4709cffdc1bd37e2d..52acd6704606d304f2650dbc028811ea44293af5 100644 --- a/core/src/main/resources/hudson/model/Job/configure_da.properties +++ b/core/src/main/resources/hudson/model/Job/configure_da.properties @@ -22,7 +22,6 @@ Strategy=Strategi name={0} navn -Discard\ Old\ Builds=Fjern Gamle Byg Save=Gem LOADING=INDL\u00c6SER Description=Beskrivelse diff --git a/core/src/main/resources/hudson/model/Job/configure_de.properties b/core/src/main/resources/hudson/model/Job/configure_de.properties index 553598aa9f0cfc43250ddf7b12c67f8ab5677d7b..6112e05e9a298b36b2f12aa3372c77510b922461 100644 --- a/core/src/main/resources/hudson/model/Job/configure_de.properties +++ b/core/src/main/resources/hudson/model/Job/configure_de.properties @@ -23,6 +23,5 @@ Strategy=Strategie name={0}name Description=Beschreibung -Discard\ Old\ Builds=Alte Builds verwerfen Save=Speichern LOADING=LADE DATEN diff --git a/core/src/main/resources/hudson/model/Job/configure_es.properties b/core/src/main/resources/hudson/model/Job/configure_es.properties index fe6860662559eda2151fe0f0ab3cd89a631c2c11..6c3bdab63a43f000273e2dce4f0bb298469c533a 100644 --- a/core/src/main/resources/hudson/model/Job/configure_es.properties +++ b/core/src/main/resources/hudson/model/Job/configure_es.properties @@ -22,7 +22,6 @@ Strategy=Estrategia name={0} nombre -Discard\ Old\ Builds=Desechar ejecuciones antiguas Save=Guardar Description=Descripcin LOADING=CARGANDO diff --git a/core/src/main/resources/hudson/model/Job/configure_es_AR.properties b/core/src/main/resources/hudson/model/Job/configure_es_AR.properties index 48a45961759ca16ee1dd42e6c11e22c3576a236e..9f83c8326196542d97c8d719bc7c46e595792f0f 100644 --- a/core/src/main/resources/hudson/model/Job/configure_es_AR.properties +++ b/core/src/main/resources/hudson/model/Job/configure_es_AR.properties @@ -1,6 +1,5 @@ # This file is under the MIT License by authors Description=Descripci\u00F3n -Discard\ Old\ Builds=Descargar build antiguos LOADING=CARGANDO name={0} nombre diff --git a/core/src/main/resources/hudson/model/Job/configure_et.properties b/core/src/main/resources/hudson/model/Job/configure_et.properties index b128ff63ca5b08783f053b7f17d518cb83df9654..9014e9008a021c4afc3f99b1ffef908e89fb5f54 100644 --- a/core/src/main/resources/hudson/model/Job/configure_et.properties +++ b/core/src/main/resources/hudson/model/Job/configure_et.properties @@ -1,6 +1,5 @@ # This file is under the MIT License by authors Description=Kirjeldus -Discard\ Old\ Builds=Eemalda vanad bildid LOADING=Laen name={0} nimi diff --git a/core/src/main/resources/hudson/model/Job/configure_fi.properties b/core/src/main/resources/hudson/model/Job/configure_fi.properties index bfb65f20a1c5bf6bc6d90c95af1ed6231322c0d3..03769c1d17c4644ee2f20ec3b703c36d939176c0 100644 --- a/core/src/main/resources/hudson/model/Job/configure_fi.properties +++ b/core/src/main/resources/hudson/model/Job/configure_fi.properties @@ -21,5 +21,4 @@ # THE SOFTWARE. Description=Kuvaus -Discard\ Old\ Builds=H\u00E4vit\u00E4 vanhat k\u00E4\u00E4nn\u00F6kset Save=Tallenna diff --git a/core/src/main/resources/hudson/model/Job/configure_fr.properties b/core/src/main/resources/hudson/model/Job/configure_fr.properties index 264d85c33f4e01bc0f610bf8cd351bfb52682741..252a92d8af0280f5216132d7a3936b563b6e9ea3 100644 --- a/core/src/main/resources/hudson/model/Job/configure_fr.properties +++ b/core/src/main/resources/hudson/model/Job/configure_fr.properties @@ -22,7 +22,6 @@ name=Nom du {0} Description=Description -Discard\ Old\ Builds=Supprimer les anciens builds Save=Sauver LOADING=CHARGEMENT Strategy=Strat\u00E9gie diff --git a/core/src/main/resources/hudson/model/Job/configure_he.properties b/core/src/main/resources/hudson/model/Job/configure_he.properties index bf8a3c763b0727b8d9337f89b9b2d6dff41b2164..1f1a76f0de19ddcb9f5c6fe73086ebe9f1131ab9 100644 --- a/core/src/main/resources/hudson/model/Job/configure_he.properties +++ b/core/src/main/resources/hudson/model/Job/configure_he.properties @@ -1,6 +1,5 @@ # This file is under the MIT License by authors Description=\u05EA\u05D0\u05D5\u05E8 -Discard\ Old\ Builds=\u05D4\u05E9\u05DE\u05D3 \u05D1\u05E0\u05D9\u05D5\u05EA \u05D9\u05E9\u05E0\u05D5\u05EA LOADING=\u05D8\u05D5\u05E2\u05DF name=\u05E9\u05DD {0} diff --git a/core/src/main/resources/hudson/model/Job/configure_hu.properties b/core/src/main/resources/hudson/model/Job/configure_hu.properties index b8c94eb8719da7858f64d8170b17dd24f42a1ae9..885ae20793d853efa8e0052b027b690aed0a0e53 100644 --- a/core/src/main/resources/hudson/model/Job/configure_hu.properties +++ b/core/src/main/resources/hudson/model/Job/configure_hu.properties @@ -1,7 +1,6 @@ # This file is under the MIT License by authors Description=Le\u00EDr\u00E1s -Discard\ Old\ Builds=R\u00E9gi \u00E9p\u00EDt\u00E9sek t\u00F6rl\u00E9se LOADING=BET\u00D6LT\u00C9S Strategy=Strat\u00E9gia name={0} n\u00E9v diff --git a/core/src/main/resources/hudson/model/Job/configure_it.properties b/core/src/main/resources/hudson/model/Job/configure_it.properties index f60881e74bc20e3c3aa4ad0ade64ce78da556514..516070295cd0cab3c363d9a3e9bcf09b92fe29d6 100644 --- a/core/src/main/resources/hudson/model/Job/configure_it.properties +++ b/core/src/main/resources/hudson/model/Job/configure_it.properties @@ -21,7 +21,6 @@ # THE SOFTWARE. Description=Descrizione -Discard\ Old\ Builds=Elimina Build Precedenti LOADING=CARICAMENTO Save=Salva Strategy=Strategia diff --git a/core/src/main/resources/hudson/model/Job/configure_ja.properties b/core/src/main/resources/hudson/model/Job/configure_ja.properties index 6e5c2ee080959707df3b437b2f4447244d344072..8a94d9d2037b2f4d0efba71627bab41376b414f4 100644 --- a/core/src/main/resources/hudson/model/Job/configure_ja.properties +++ b/core/src/main/resources/hudson/model/Job/configure_ja.properties @@ -22,7 +22,6 @@ name={0}\u540d Description=\u8aac\u660e -Discard\ Old\ Builds=\u53e4\u3044\u30d3\u30eb\u30c9\u306e\u7834\u68c4 Save=\u4fdd\u5b58 LOADING=\u30ed\u30fc\u30c9\u4e2d... -Strategy=\u65b9\u91dd \ No newline at end of file +Strategy=\u65b9\u91dd diff --git a/core/src/main/resources/hudson/model/Job/configure_ko.properties b/core/src/main/resources/hudson/model/Job/configure_ko.properties index 6e4b97f731333666cf10f75ace4fe8163ea07d33..e232a25de0a816d751e443cb5ba184e706cb1c71 100644 --- a/core/src/main/resources/hudson/model/Job/configure_ko.properties +++ b/core/src/main/resources/hudson/model/Job/configure_ko.properties @@ -21,7 +21,6 @@ # THE SOFTWARE. Description=\uC124\uBA85 -Discard\ Old\ Builds=\uC624\uB798\uB41C \uBE4C\uB4DC \uC0AD\uC81C LOADING=\uBD88\uB7EC\uC624\uB294 \uC911 Save=\uC800\uC7A5 Strategy=\uC804\uB7B5 diff --git a/core/src/main/resources/hudson/model/Job/configure_lt.properties b/core/src/main/resources/hudson/model/Job/configure_lt.properties index b594bec592a19975fa64165b227ea0b5b6eb1a38..fa183c864c97f0a0fa70767b842fd2e481ae59f7 100644 --- a/core/src/main/resources/hudson/model/Job/configure_lt.properties +++ b/core/src/main/resources/hudson/model/Job/configure_lt.properties @@ -1,7 +1,6 @@ # This file is under the MIT License by authors Description=Apra\u0161ymas -Discard\ Old\ Builds=Pa\u0161alinti senus darbus LOADING=\u012EKELIAMA Save=\u012Era\u0161yti Strategy=Strategija diff --git a/core/src/main/resources/hudson/model/Job/configure_lv.properties b/core/src/main/resources/hudson/model/Job/configure_lv.properties index b5608a91ae718fbed3734f715477d19c07a31e11..130eafbf90a4a3e541965df980082cec9f7ae215 100644 --- a/core/src/main/resources/hudson/model/Job/configure_lv.properties +++ b/core/src/main/resources/hudson/model/Job/configure_lv.properties @@ -21,7 +21,6 @@ # THE SOFTWARE. Description=Apraksts -Discard\ Old\ Builds=Dz\u0113st vecos b\u016Bv\u0113jumus LOADING=IEL\u0100D\u0112 Save=Saglab\u0101t name={0} nosaukums diff --git a/core/src/main/resources/hudson/model/Job/configure_nb_NO.properties b/core/src/main/resources/hudson/model/Job/configure_nb_NO.properties index 06330e0c48b3b4a0eda2408dc48f776f9b3816aa..9b6ee83290bca22933766e5f3356ff156d89c683 100644 --- a/core/src/main/resources/hudson/model/Job/configure_nb_NO.properties +++ b/core/src/main/resources/hudson/model/Job/configure_nb_NO.properties @@ -21,6 +21,5 @@ # THE SOFTWARE. Description=Beskrivelse -Discard\ Old\ Builds=Slett gamle bygg LOADING=LASTER name={0} navn diff --git a/core/src/main/resources/hudson/model/Job/configure_nl.properties b/core/src/main/resources/hudson/model/Job/configure_nl.properties index 332107a25516863719d16b7d1e3297779ccfa74b..bdec1d286a9af2bf37edf0017154911e22242b1b 100644 --- a/core/src/main/resources/hudson/model/Job/configure_nl.properties +++ b/core/src/main/resources/hudson/model/Job/configure_nl.properties @@ -23,6 +23,5 @@ Strategy=Strategie name={0} naam Description=Omschrijving -Discard\ Old\ Builds=Oude builds automatisch verwijderen LOADING=LADEN Save=Opslaan diff --git a/core/src/main/resources/hudson/model/Job/configure_pl.properties b/core/src/main/resources/hudson/model/Job/configure_pl.properties index d71bd2df454f20248acca854916fdd3b84dccd10..11394275e7a0d5c5b6f130b4bd6bed54afe57cfb 100644 --- a/core/src/main/resources/hudson/model/Job/configure_pl.properties +++ b/core/src/main/resources/hudson/model/Job/configure_pl.properties @@ -21,7 +21,6 @@ # THE SOFTWARE. Description=Opis -Discard\ Old\ Builds=Porzu\u0107 stare buildy LOADING=\u0141ADOWANIE Save=Zapisz Strategy=Strategia diff --git a/core/src/main/resources/hudson/model/Job/configure_pt_BR.properties b/core/src/main/resources/hudson/model/Job/configure_pt_BR.properties index 32d486e561bf255ed4f13dbc29944e1d7ba43d53..19b04234431c27473cd3f5e97e525b8ea627a6f2 100644 --- a/core/src/main/resources/hudson/model/Job/configure_pt_BR.properties +++ b/core/src/main/resources/hudson/model/Job/configure_pt_BR.properties @@ -23,6 +23,5 @@ Strategy=Estrat\u00E9gia name=Nome do {0} Description=Descri\u00e7\u00e3o -Discard\ Old\ Builds=Descartar builds antigos Save=Salvar LOADING=CARREGANDO diff --git a/core/src/main/resources/hudson/model/Job/configure_pt_PT.properties b/core/src/main/resources/hudson/model/Job/configure_pt_PT.properties index 7de593bdf3fc754f74a53407bdf0d6066bf42597..2e2937ce6bacb52f32506022fdfe016cdf362560 100644 --- a/core/src/main/resources/hudson/model/Job/configure_pt_PT.properties +++ b/core/src/main/resources/hudson/model/Job/configure_pt_PT.properties @@ -1,6 +1,5 @@ # This file is under the MIT License by authors Description=Descri\u00E7\u00E3o -Discard\ Old\ Builds=Descartar compila\u00E7\u00F5es antigas LOADING=A CARREGAR name={0} nome diff --git a/core/src/main/resources/hudson/model/Job/configure_ro.properties b/core/src/main/resources/hudson/model/Job/configure_ro.properties index 2260b1a4b107f9fe7882fc3efeb7cc75f3433140..1168eebe56233d9ebae89f73d050777abbc95872 100644 --- a/core/src/main/resources/hudson/model/Job/configure_ro.properties +++ b/core/src/main/resources/hudson/model/Job/configure_ro.properties @@ -1,7 +1,6 @@ # This file is under the MIT License by authors Description=Descriere -Discard\ Old\ Builds=Anuleaza Build-urile vechi LOADING=SE INCARCA Strategy=Strategie name=numele {0} diff --git a/core/src/main/resources/hudson/model/Job/configure_ru.properties b/core/src/main/resources/hudson/model/Job/configure_ru.properties index 721111e40d7cd697b2511888ed91d57edb89db35..795374cdf8335098e90ff91f100687ccae38ab9c 100644 --- a/core/src/main/resources/hudson/model/Job/configure_ru.properties +++ b/core/src/main/resources/hudson/model/Job/configure_ru.properties @@ -23,6 +23,5 @@ Strategy=\u0421\u0442\u0440\u0430\u0442\u0435\u0433\u0438\u044f name={0} Description=\u041e\u043f\u0438\u0441\u0430\u043d\u0438\u0435 -Discard\ Old\ Builds=\u0423\u0434\u0430\u043b\u044f\u0442\u044c \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0435 \u0441\u0431\u043e\u0440\u043a\u0438 LOADING=\u0417\u0410\u0413\u0420\u0423\u0417\u041a\u0410 Save=\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c diff --git a/core/src/main/resources/hudson/model/Job/configure_sk.properties b/core/src/main/resources/hudson/model/Job/configure_sk.properties index a218d7afe5fa38161387c06266e10d0a2d2e6b42..b08d5e7931880b3b0da8c9c4bc0d20fddfdabad7 100644 --- a/core/src/main/resources/hudson/model/Job/configure_sk.properties +++ b/core/src/main/resources/hudson/model/Job/configure_sk.properties @@ -1,7 +1,6 @@ # This file is under the MIT License by authors Description=Popis -Discard\ Old\ Builds=Vymazanie star\u00FDch zostaven\u00ED LOADING=Nahr\u00E1vanie Strategy=Strat\u00E9gia name={0} meno diff --git a/core/src/main/resources/hudson/model/Job/configure_sv_SE.properties b/core/src/main/resources/hudson/model/Job/configure_sv_SE.properties index 862e6868eade3e97a065cedfaca17e53fa9d097a..43f4e32f31f4175d0e8ad5efb9103b5e83186e0b 100644 --- a/core/src/main/resources/hudson/model/Job/configure_sv_SE.properties +++ b/core/src/main/resources/hudson/model/Job/configure_sv_SE.properties @@ -21,7 +21,6 @@ # THE SOFTWARE. Description=Beskrivning -Discard\ Old\ Builds=Ta bort gamla byggen LOADING=LADDAR Save=Spara Strategy=Strategi diff --git a/core/src/main/resources/hudson/model/Job/configure_tr.properties b/core/src/main/resources/hudson/model/Job/configure_tr.properties index a530c119d24354a90dd2c9fcfb78379858c6f1bf..f65678e2fefcbc4ac9013713b9df8a45e7389535 100644 --- a/core/src/main/resources/hudson/model/Job/configure_tr.properties +++ b/core/src/main/resources/hudson/model/Job/configure_tr.properties @@ -23,6 +23,5 @@ Strategy=Strateji name={0} isim Description=A\u00e7\u0131klama -Discard\ Old\ Builds=Eski Yap\u0131land\u0131rmalardan Kurtul LOADING=Y\u00DCKLEN\u0130YOR Save=Kaydet diff --git a/core/src/main/resources/hudson/model/Job/configure_uk.properties b/core/src/main/resources/hudson/model/Job/configure_uk.properties index afbf1a51cccc36b07fe2ecf0cae1002e18e3fe9c..293d8113074a98938573f04de32adc6219bd0425 100644 --- a/core/src/main/resources/hudson/model/Job/configure_uk.properties +++ b/core/src/main/resources/hudson/model/Job/configure_uk.properties @@ -1,7 +1,6 @@ # This file is under the MIT License by authors Description=\u041E\u043F\u0438\u0441 -Discard\ Old\ Builds=\u0421\u043A\u0430\u0441\u0443\u0432\u0430\u0442\u0438 \u0441\u0442\u0430\u0440\u0456 \u0431\u0456\u043B\u0434\u0438 LOADING=\u0417\u0410\u0412\u0410\u041D\u0422\u0410\u0416\u0423\u0404\u0422\u042C\u0421\u042F Save=\u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438 Strategy=\u0421\u0442\u0440\u0430\u0442\u0435\u0433\u0456\u044F diff --git a/core/src/main/resources/hudson/model/Job/configure_zh_CN.properties b/core/src/main/resources/hudson/model/Job/configure_zh_CN.properties index 68143f6235b60bc4779d18c105fc21260c0991b9..307ce3d03f7c87178f1fc13b8b241407d97f3405 100644 --- a/core/src/main/resources/hudson/model/Job/configure_zh_CN.properties +++ b/core/src/main/resources/hudson/model/Job/configure_zh_CN.properties @@ -21,7 +21,6 @@ # THE SOFTWARE. Description=\u63CF\u8FF0 -Discard\ Old\ Builds=\u4E22\u5F03\u65E7\u7684\u6784\u5EFA LOADING=\u52A0\u8F7D\u4E2D Save=\u4FDD\u5B58 Strategy=\u7B56\u7565 diff --git a/core/src/main/resources/hudson/model/Job/configure_zh_TW.properties b/core/src/main/resources/hudson/model/Job/configure_zh_TW.properties index 7f09adb310104dc97cab56e8b00b81e3dfe8ea64..44bf241205fd815a13f1e500c1ddae37e44c15da 100644 --- a/core/src/main/resources/hudson/model/Job/configure_zh_TW.properties +++ b/core/src/main/resources/hudson/model/Job/configure_zh_TW.properties @@ -25,7 +25,6 @@ LOADING=\u8B80\u53D6\u4E2D name={0} \u540D\u7A31 Description=\u63CF\u8FF0 -Discard\ Old\ Builds=\u5FFD\u7565\u820ABuilds Strategy=\u7b56\u7565 Save=\u5132\u5b58 diff --git a/core/src/main/resources/hudson/model/Job/index_ja.properties b/core/src/main/resources/hudson/model/Job/index_ja.properties index f206a6b3bc8127f9fe2550d1ef027497b0f685f7..4cf10f00b946223a5299ed3cc3867e264783a64e 100644 --- a/core/src/main/resources/hudson/model/Job/index_ja.properties +++ b/core/src/main/resources/hudson/model/Job/index_ja.properties @@ -20,4 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Project\ name=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u540d \ No newline at end of file +Project\ name=\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u540d +Full\ project\ name=\u7d76\u5bfe\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u540d \ No newline at end of file diff --git a/core/src/main/resources/hudson/model/Job/permalinks_pl.properties b/core/src/main/resources/hudson/model/Job/permalinks_pl.properties index f5ff9bd483199b1fa40443a30574ab97bc50e350..ce59813bf36d95ebb56041f523722ed9f3750089 100644 --- a/core/src/main/resources/hudson/model/Job/permalinks_pl.properties +++ b/core/src/main/resources/hudson/model/Job/permalinks_pl.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Permalinks=Odno\u015Bniki permanentne +Permalinks=Odno\u015Bniki niezmienne diff --git a/core/src/main/resources/hudson/model/Label/sidepanel_ja.properties b/core/src/main/resources/hudson/model/Label/sidepanel_ja.properties index 0132b0e426f59b95dd850b271de51d067d8649a8..c1483cf11aa6e0f622d8ebbef17830a94f54f6a6 100644 --- a/core/src/main/resources/hudson/model/Label/sidepanel_ja.properties +++ b/core/src/main/resources/hudson/model/Label/sidepanel_ja.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe +# Copyright (c) 2004-2015, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe # # 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,6 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Back\ to\ Dashboard=\u30C0\u30C3\u30B7\u30E5\u30DC\u30FC\u30C9\u3078\u623B\u308B +Back\ to\ Dashboard=\u30c0\u30c3\u30b7\u30e5\u30dc\u30fc\u30c9\u3078\u623b\u308b Overview=\u6982\u8981 -Load\ Statistics=\u8CA0\u8377\u7D71\u8A08 +Load\ Statistics=\u8ca0\u8377\u7d71\u8a08 +Configure=\u8a2d\u5b9a \ No newline at end of file diff --git a/core/src/main/resources/hudson/model/LoadStatistics/main.properties b/core/src/main/resources/hudson/model/LoadStatistics/main.properties index da47168272deb036004e842341aab6de589f667e..9fc34ab657e72c4b27cf78520634411704d5af79 100644 --- a/core/src/main/resources/hudson/model/LoadStatistics/main.properties +++ b/core/src/main/resources/hudson/model/LoadStatistics/main.properties @@ -22,22 +22,31 @@ title=Load statistics: {0} blurb=\ - Load statistics keep track of three key metrics of resource utilization: \ + Load statistics keep track of four key metrics of resource utilization: \

\ -
Total number of executors
\ +
Number of online executors
\
\ - For a computer, this is the number of executors that the computer has. \ - For a label, this is the sum of all executors across all computers in this label. \ - For the entire Jenkins, this is the sum of all executors across all computers in this Jenkins installation. \ + For a computer: if the computer is online then this is the number of executors that \ + the computer has; if the computer is offline then this is zero.
\ + For a label: this is the sum of all executors across all online computers in this label.
\ + For the entire Jenkins: this is the sum of all executors across all online computers in this Jenkins \ + installation.
\ Other than configuration changes, this value can also change when slaves go offline. \
\
Number of busy executors
\
\ This line tracks the number of executors (among the executors counted above) \ - that are carrying out builds. The ratio of this to the total number of executors \ + that are carrying out builds. The ratio of this to the number of online executors \ gives you the resource utilization. If all your executors are busy for \ a prolonged period of time, consider adding more computers to your Jenkins cluster.\
\ +
Number of available executors
\ +
\ + This line tracks the number of executors (among the online executors counted above) \ + that are available to carry out builds. The ratio of this to the total number of executors \ + gives you the resource availability. If none of your executors are available for \ + a prolonged period of time, consider adding more computers to your Jenkins cluster.\ +
\
Queue length
\
\ This is the number of jobs that are in the build queue, waiting for an \ @@ -48,5 +57,8 @@ blurb=\ adding more computers.\
\
\ - The graph is exponential moving average of periodically collected data values. \ - 3 timespans are updated every 10 seconds, 1 minute, and 1 hour respectively. +

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.

diff --git a/core/src/main/resources/hudson/model/Messages.properties b/core/src/main/resources/hudson/model/Messages.properties index 33dfb245cdfe42c0247e909407e7b4a8dbc477ee..571ec8867f121c276b7ce7086b24c59c5c368955 100644 --- a/core/src/main/resources/hudson/model/Messages.properties +++ b/core/src/main/resources/hudson/model/Messages.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2012, Sun Microsystems, Inc., Kohsuke Kawaguchi, +# Copyright (c) 2004-2015, Sun Microsystems, Inc., Kohsuke Kawaguchi, # Eric Lefevre-Ardant, Erik Ramfelt, Seiji Sogabe, id:cactusman, # Manufacture Francaise des Pneumatiques Michelin, Romain Seguy # @@ -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. @@ -36,13 +37,9 @@ 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. @@ -77,7 +74,7 @@ AbstractProject.AssignedLabelString.InvalidBooleanExpression=\ AbstractProject.AssignedLabelString.NoMatch=\ There's no slave/cloud that matches this assignment AbstractProject.CustomWorkspaceEmpty=Custom workspace is empty. -AbstractProject.LabelLink=Slaves in label: {2} +AbstractProject.LabelLink=Label is serviced by {2,choice,0#no nodes|1#1 node|1<{2} nodes}{3,choice,0#|1# and 1 cloud|1< and {3} clouds} Api.MultipleMatch=XPath "{0}" matched {1} nodes. \ Create XPath that only matches one, or use the "wrapper" query parameter to wrap them all under a root element. @@ -92,15 +89,12 @@ BallColor.Pending=Pending BallColor.Success=Success BallColor.Unstable=Unstable +Build.post_build_steps_failed=Post-build steps failed CLI.clear-queue.shortDescription=Clears the build queue. -CLI.delete-job.shortDescription=Deletes a job. -CLI.reload-job.shortDescription=Reloads this job from disk. CLI.disable-job.shortDescription=Disables a job. CLI.enable-job.shortDescription=Enables a job. -CLI.delete-node.shortDescription=Deletes a node. CLI.disconnect-node.shortDescription=Disconnects from a node. CLI.connect-node.shortDescription=Reconnect to a node. -CLI.online-node.shortDescription=Resume using a node for performing builds, to cancel out the earlier "offline-node" command. CLI.offline-node.shortDescription=Stop using a node for performing builds temporarily, until the next "online-node" command. CLI.wait-node-online.shortDescription=Wait for a node to become online. CLI.wait-node-offline.shortDescription=Wait for a node to become offline. @@ -120,7 +114,7 @@ Computer.BadChannel=Slave node offline or not a remote channel (such as master n ComputerSet.NoSuchSlave=No such slave: {0} ComputerSet.SlaveAlreadyExists=Slave called \u2018{0}\u2019 already exists ComputerSet.SpecifySlaveToCopy=Specify which slave to copy -ComputerSet.DisplayName=nodes +ComputerSet.DisplayName=Nodes Descriptor.From=(from {0}) @@ -225,6 +219,7 @@ Run.ArtifactsPermission.Description=\ builds. If you don\u2019t want an user to access the artifacts, you can do so by \ revoking this permission. Run.InProgressDuration={0} and counting +Run.NotStartedYet=Not started yet Run.ArtifactsBrowserTitle=Artifacts of {0} {1} Run.Summary.Stable=stable @@ -244,11 +239,15 @@ Slave.Launching={0} Launching slave agent Slave.Network.Mounted.File.System.Warning=Are you sure you want to use network mounted file system for FS root? Note that this directory does not need to be visible to the master. Slave.Remote.Director.Mandatory=Remote directory is mandatory Slave.Terminated={0} slave agent was terminated -Slave.the_remote_root_must_be_an_absolute_path=The remote root must be an absolute path. +Slave.Remote.Relative.Path.Warning=Are you sure you want to use a relative path for the FS root? Note that relative \ + paths require that you can assure that the selected launcher provides a consistent current working directory. Using \ + an absolute path is highly recommended. Slave.UnableToLaunch=Unable to launch the slave agent for {0}{1} Slave.UnixSlave=This is a Unix slave Slave.WindowsSlave=This is a Windows slave +TopLevelItemDescriptor.NotApplicableIn={0} items are not applicable within {1} + UpdateCenter.DownloadButNotActivated=Downloaded Successfully. Will be activated during the next boot UpdateCenter.n_a=N/A View.Permissions.Title=View @@ -272,25 +271,42 @@ 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.cloud=Cloud Providers 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.python=Python Development UpdateCenter.PluginCategory.report=Build Reports +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}) @@ -300,9 +316,10 @@ 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 +ParametersDefinitionProperty.DisplayName=This build is parameterized StringParameterDefinition.DisplayName=String Parameter TextParameterDefinition.DisplayName=Text Parameter FileParameterDefinition.DisplayName=File Parameter @@ -313,6 +330,7 @@ RunParameterDefinition.DisplayName=Run Parameter PasswordParameterDefinition.DisplayName=Password Parameter Node.BecauseNodeIsReserved={0} is reserved for jobs with matching label expression +Node.BecauseNodeIsNotAcceptingTasks={0} is not accepting tasks Node.LabelMissing={0} doesn\u2019t have label {1} Node.LackingBuildPermission={0} doesn\u2019t have a permission to run on {1} Node.Mode.NORMAL=Utilize this node as much as possible @@ -322,8 +340,13 @@ ListView.DisplayName=List View MyView.DisplayName=My View +LoadStatistics.Legends.DefinedExecutors=Defined executors +LoadStatistics.Legends.OnlineExecutors=Online executors +LoadStatistics.Legends.ConnectingExecutors=Connecting executors LoadStatistics.Legends.TotalExecutors=Total executors LoadStatistics.Legends.BusyExecutors=Busy executors +LoadStatistics.Legends.IdleExecutors=Idle executors +LoadStatistics.Legends.AvailableExecutors=Available executors LoadStatistics.Legends.QueueLength=Queue length Cause.LegacyCodeCause.ShortDescription=Legacy code started this job. No cause information is available @@ -356,3 +379,6 @@ Jenkins.CheckDisplayName.DisplayNameNotUniqueWarning=The display name, "{0}", is Jenkins.NotAllowedName="{0}" is not allowed name Jenkins.IsRestarting=Jenkins is restarting + +User.IllegalUsername="{0}" is prohibited as a username for security reasons. +User.IllegalFullname="{0}" is prohibited as a full name for security reasons. 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 0000000000000000000000000000000000000000..0230072deaf6390b3de845844b74379b9bdf7c9d --- /dev/null +++ b/core/src/main/resources/hudson/model/Messages_bg.properties @@ -0,0 +1,682 @@ +# The MIT License +# +# Bulgarian translation copyright 2015 Alexander Shopov . +# +# 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. + +AbstractBuild.BuildingRemotely=\ + \u041e\u0442\u0434\u0430\u043b\u0435\u0447\u0435\u043d\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u0432\u044a\u0440\u0445\u0443 \u201e{0}\u201c +AbstractBuild.BuildingOnMaster=\ + \u0418\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u0432\u044a\u0440\u0445\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u0438\u044f \u0441\u044a\u0440\u0432\u044a\u0440 +AbstractBuild_Building=\ + \u0418\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +AbstractBuild.BuildingInWorkspace=\ + \ \u0432 \u0440\u0430\u0431\u043e\u0442\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u201e{0}\u201c +AbstractBuild.KeptBecause=\ + \u0422\u043e\u0432\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u0441\u0435 \u043f\u0430\u0437\u0438, \u0437\u0430\u0440\u0430\u0434\u0438 \u201e{0}\u201c. + +AbstractItem.NoSuchJobExists=\ + \u041d\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u043d\u0430 \u0438\u043c\u0435 \u201e{0}\u201c. \u201e{1}\u201c \u043b\u0438 \u0438\u043c\u0430\u0445\u0442\u0435 \u043f\u0440\u0435\u0434\u0432\u0438\u0434? +AbstractItem.NoSuchJobExistsWithoutSuggestion=\ + \u041d\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u043d\u0430 \u0438\u043c\u0435 \u201e{0}\u201c. +AbstractItem.Pronoun=\ + \u0415\u043b\u0435\u043c\u0435\u043d\u0442 +AbstractProject.AssignedLabelString_NoMatch_DidYouMean=\ + \u041d\u0438\u043a\u043e\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u043d\u0435 \u043e\u0442\u0433\u043e\u0432\u0430\u0440\u044f \u0437\u0430 \u0442\u0430\u0437\u0438 \u0437\u0430\u0434\u0430\u0447\u0430. \u0414\u0430 \u043d\u044f\u043c\u0430\u0442\u0435 \u043f\u0440\u0435\u0434\u0432\u0438\u0434 \u201e{1}\u201c \u0432\u043c\u0435\u0441\u0442\u043e \u201e{0}\u201c? +AbstractProject.NewBuildForWorkspace=\ + \u041d\u0430\u0441\u0440\u043e\u0447\u0432\u0430\u043d\u0435 \u043d\u0430 \u043d\u043e\u0432\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435, \u0437\u0430 \u0434\u0430 \u0441\u0435 \u043f\u043e\u043b\u0443\u0447\u0438 \u0440\u0430\u0431\u043e\u0442\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e. +AbstractProject.AwaitingBuildForWorkspace=\ + \u0418\u0437\u0447\u0430\u043a\u0432\u0430\u043d\u0435 \u043d\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435, \u0437\u0430 \u0434\u0430 \u0441\u0435 \u043f\u043e\u043b\u0443\u0447\u0438 \u0440\u0430\u0431\u043e\u0442\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e. +AbstractProject.AwaitingWorkspaceToComeOnline=\ + \u0422\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0441\u0435 \u043d\u0430\u0441\u0440\u043e\u0447\u0438 \u043d\u043e\u0432\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435, \u0437\u0430 \u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0438 \u0440\u0430\u0431\u043e\u0442\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e.\ + \u0417\u0430\u0431\u0430\u0432\u044f\u043d\u0435 \u043e\u0442 {0}\u200ams \u0441 \u043d\u0430\u0434\u0435\u0436\u0434\u0430 \u0434\u0430 \u0441\u0435 \u043e\u0441\u0432\u043e\u0431\u043e\u0434\u0438 \u043d\u044f\u043a\u043e\u0435 \u0440\u0430\u0431\u043e\u0442\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e +AbstractProject.Pronoun=\ + \u041f\u0440\u043e\u0435\u043a\u0442 +AbstractProject.Aborted=\ + \u041f\u0440\u0435\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0435\u043d +AbstractProject.BuildInProgress=\ + \u0418\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u2116\u200a{0} \u0432\u0435\u0447\u0435 \u0441\u0435 \u0438\u0437\u043f\u044a\u043b\u043d\u044f\u0432\u0430{1} +AbstractProject.BuildNow=\ + \u041d\u0435\u0437\u0430\u0431\u0430\u0432\u043d\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +AbstractProject.build_with_parameters=\ + \u0418\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438 +AbstractProject.UpstreamBuildInProgress=\ + \u201e{0}\u201c \u2014 \u0437\u0430\u0434\u0430\u0447\u0430, \u043e\u0442 \u043a\u043e\u044f\u0442\u043e \u0437\u0430\u0432\u0438\u0441\u0438 \u0442\u0435\u043a\u0443\u0449\u043e\u0442\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435, \u0432\u0435\u0447\u0435 \u0435 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0430. +AbstractProject.DownstreamBuildInProgress=\ + \u201e{0}\u201c \u2014 \u0437\u0430\u0434\u0430\u0447\u0430, \u043a\u043e\u044f\u0442\u043e \u0437\u0430\u0432\u0438\u0441\u0438 \u043e\u0442 \u0442\u0435\u043a\u0443\u0449\u043e\u0442\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435, \u0432\u0435\u0447\u0435 \u0435 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0430. +AbstractProject.Disabled=\ + \u0418\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435\u0442\u043e \u0435 \u0438\u0437\u043a\u043b\u044e\u0447\u0435\u043d\u043e +AbstractProject.ETA=\ + \ (\u043e\u0441\u0442\u0430\u0432\u0430\u0442:{0}) +AbstractProject.NoBuilds=\ + \u041d\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435. \u041d\u0430\u0441\u0440\u043e\u0447\u0432\u0430 \u0441\u0435 \u043d\u043e\u0432\u043e. +AbstractProject.NoSCM=\ + \u041d\u044f\u043c\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0437\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u0438\u0442\u0435 +AbstractProject.NoWorkspace=\ + \u041d\u044f\u043c\u0430 \u0441\u0432\u043e\u0431\u043e\u0434\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0438 \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0441\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u0438 \u0437\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f. +AbstractProject.WorkspaceTitle=\ + \u0420\u0430\u0431\u043e\u0442\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u201e{0}\u201c +AbstractProject.WorkspaceTitleOnComputer=\ + \u0420\u0430\u0431\u043e\u0442\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u201e{0}\u201c \u043d\u0430 \u201e{1}\u201c +AbstractProject.PollingABorted=\ + \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430\u0442\u0430 \u043d\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0438\u0442\u0435 \u0437\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u0438\u0442\u0435 \u0435 \u043f\u0440\u0435\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0435\u043d\u0430 +AbstractProject.ScmAborted=\ + \u0418\u0437\u0442\u0435\u0433\u043b\u044f\u043d\u0435\u0442\u043e \u043e\u0442 \u0441\u0438\u0441\u0442\u0435\u043c\u0438\u0442\u0435 \u0437\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u0438\u0442\u0435 \u0435 \u043f\u0440\u0435\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0435\u043d\u043e +AbstractProject.WorkspaceOffline=\ + \u0420\u0430\u0431\u043e\u0442\u043d\u043e\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u043d\u0435 \u0435 \u043d\u0430\u043b\u0438\u0447\u043d\u043e. +AbstractProject.BuildPermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e\u0442\u043e \u0437\u0430 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043d\u043e\u0432\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435. +AbstractProject.WorkspacePermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0434\u0430 \u0441\u0435 \u0440\u0430\u0437\u0433\u043b\u0435\u0436\u0434\u0430 \u0441\u044a\u0434\u044a\u0440\u0436\u0430\u043d\u0438\u0435\u0442\u043e \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u043d\u043e\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u043f\u0440\u0438\ + \u0438\u0437\u0432\u044a\u0440\u0448\u0432\u0430\u043d\u0435 \u043d\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f \u043e\u0442 Jenkins. \u041e\u0442\u043d\u0435\u043c\u0435\u0442\u0435 \u0433\u043e, \u0430\u043a\u043e \u043d\u0435 \u0438\u0441\u043a\u0430\u0442\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\ + \u0434\u0430 \u0434\u043e\u0441\u0442\u044a\u043f\u0432\u0430 \u0444\u0430\u0439\u043b\u043e\u0432\u0435\u0442\u0435 \u0432 \u0440\u0430\u0431\u043e\u0442\u043d\u043e\u0442\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e (\u043d\u0430\u043f\u0440. \u0438\u0437\u0445\u043e\u0434\u043d\u0438\u044f \u043a\u043e\u0434, \u0438\u0437\u0442\u0435\u0433\u043b\u0435\u043d\ + \u043e\u0442 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0430 \u0437\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u0438\u0442\u0435 \u0438\u043b\u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0438\u0442\u0435 \u0444\u0430\u0439\u043b\u043e\u0432\u0435 \u043f\u0440\u0438 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435\u0442\u043e). +AbstractProject.ExtendedReadPermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u0434\u043e\u0441\u0442\u044a\u043f \u0434\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u0442\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430\u0442\u0430 \u0437\u0430 \u0447\u0435\u0442\u0435\u043d\u0435 \u0438 \u043c\u043e\u0436\u0435 \u0434\u0430\ + \u0434\u043e\u0432\u0435\u0434\u0435 \u0434\u043e \u0440\u0430\u0437\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u0442\u0430\u0439\u043d\u0438, \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u043d\u0438 \u0437\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f\u0442\u0430 \u2014 \u043a\u0430\u0442\u043e \u043f\u0430\u0440\u043e\u043b\u0438\ + \u0437\u0430 \u0434\u043e\u0441\u0442\u044a\u043f \u0434\u043e \u0441\u0438\u0441\u0442\u0435\u043c\u0438 \u0437\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u0438\u0442\u0435. +AbstractProject.DiscoverPermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u043e\u0442\u043a\u0440\u0438\u0432\u0430\u043d\u0435 \u0438 \u0438\u0437\u0431\u0440\u043e\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0438\u0442\u0435. \u041f\u0440\u0430\u0432\u043e\u0442\u043e \u0435 \u043f\u043e-\u0441\u043b\u0430\u0431\u043e \u043e\u0442\ + \u0434\u043e\u0441\u0442\u044a\u043f\u0430 \u0434\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u0442\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430\u0442\u0430 \u0437\u0430 \u0447\u0435\u0442\u0435\u043d\u0435, \u043d\u043e \u0432\u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0432\u0430 \u0434\u0430 \u043f\u0440\u0435\u043d\u0430\u0441\u043e\u0447\u0438\u0442\u0435\ + \u0430\u043d\u043e\u043d\u0438\u043c\u043d\u0438\u0442\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0438 \u043a\u044a\u043c \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u0442\u0430 \u0437\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f, \u043a\u043e\u0433\u0430\u0442\u043e \u0441\u0435 \u043e\u043f\u0438\u0442\u0430\u0442 \u0434\u0430\ + \u043e\u0442\u0432\u043e\u0440\u044f\u0442 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430\u0442\u0430 \u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430. \u0410\u043a\u043e \u043f\u0440\u0430\u0432\u043e\u0442\u043e \u043d\u0435 \u0435 \u0434\u0430\u0434\u0435\u043d\u043e, \u043e\u0442\u0433\u043e\u0432\u043e\u0440\u044a\u0442\ + \u043d\u0430 \u0437\u0430\u044f\u0432\u043a\u0438\u0442\u0435 \u0437\u0430 \u0434\u043e\u0441\u0442\u044a\u043f \u0434\u043e \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0438\u0442\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0438\u0442\u0435 \u0449\u0435 \u0435 \u0433\u0440\u0435\u0448\u043a\u0430 404 \u0438 \u0430\u043d\u043e\u043d\u0438\u043c\u043d\u0438\u0442\u0435\ + \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0438 \u043d\u044f\u043c\u0430 \u0434\u0430 \u043d\u0430\u0443\u0447\u0430\u0432\u0430\u0442 \u0438\u043c\u0435\u043d\u0430\u0442\u0430 \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0442\u0435. +# hudson.security.WipeOutPermission is set to true +AbstractProject.WipeOutPermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u0438\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u0446\u044f\u043b\u043e\u0442\u043e \u0441\u044a\u0434\u044a\u0440\u0436\u0430\u043d\u0438\u0435 \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e. +AbstractProject.CancelPermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u043e\u0442\u043c\u044f\u043d\u0430 \u043d\u0430 \u0437\u0430\u043f\u043b\u0430\u043d\u0443\u0432\u0430\u043d\u043e \u0438 \u0441\u043f\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0438\u0437\u043f\u044a\u043b\u043d\u044f\u0432\u0430\u043d\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435. +AbstractProject.AssignedLabelString.InvalidBooleanExpression=\ + \u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u0435\u043d \u0431\u0443\u043b\u0435\u0432 \u0438\u0437\u0440\u0430\u0437: {0} +AbstractProject.AssignedLabelString.NoMatch=\ + \u041d\u0438\u043a\u043e\u044f \u043c\u0430\u0448\u0438\u043d\u0430 \u0438\u043b\u0438 \u043e\u0431\u043b\u0430\u043a \u043d\u0435 \u043e\u0442\u0433\u043e\u0432\u0430\u0440\u044f \u043d\u0430 \u0442\u0430\u0437\u0438 \u0437\u0430\u0434\u0430\u0447\u0430. +AbstractProject.CustomWorkspaceEmpty=\ + \u041f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u043e\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u043e \u0435 \u043f\u0440\u0430\u0437\u043d\u043e. +AbstractProject.LabelLink=\ + \u0415\u0442\u0438\u043a\u0435\u0442\u044a\u0442 \u0441\u0435 \u043e\u0431\u0441\u043b\u0443\u0436\u0432\u0430 \u043e\u0442\ + {2,choice,0#\u043d\u0438\u043a\u043e\u043b\u043a\u043e \u043c\u0430\u0448\u0438\u043d\u0438|1#1 \u043c\u0430\u0448\u0438\u043d\u0430|1<{2} \u043c\u0430\u0448\u0438\u043d\u0438}{3,choice,0#|1# \u0438 1 \u043e\u0431\u043b\u0430\u043a|1< \u0438 {3} \u043e\u0431\u043b\u0430\u043a\u0430} + +Api.MultipleMatch=\ + \u0418\u0437\u0440\u0430\u0437\u044a\u0442 \u0447\u0440\u0435\u0437 XPath \u201e{0}\u201c \u043e\u0442\u0433\u043e\u0432\u0430\u0440\u044f \u043d\u0430 {1} \u043c\u0430\u0448\u0438\u043d\u0438. \u0417\u0430\u0434\u0430\u0439\u0442\u0435 \u0438\u0437\u0440\u0430\u0437, \u043a\u043e\u0439\u0442\u043e \u0434\u0430 + \u043d\u0430\u043f\u0430\u0441\u0432\u0430 \u0441\u0430\u043c\u043e \u0435\u0434\u043d\u0430 \u043c\u0430\u0448\u0438\u043d\u0430 \u0438\u043b\u0438 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0439\u0442\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u044a\u0440\u0430 \u201ewrapper\u201c, \u0437\u0430 \u0434\u0430 \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u0435\ + \u0432\u0441\u0438\u0447\u043a\u0438 \u0442\u0435\u0437\u0438 \u043c\u0430\u0448\u0438\u043d\u0438 \u0432 \u043e\u0431\u0449 \u0435\u043b\u0435\u043c\u0435\u043d\u0442. +Api.NoXPathMatch=\ + \u0418\u0437\u0440\u0430\u0437\u044a\u0442 \u0447\u0440\u0435\u0437 XPath \u201e{0}\u201c \u043d\u0435 \u043d\u0430\u043f\u0430\u0441\u0432\u0430 \u0441 \u043d\u0438\u043a\u043e\u044f \u043c\u0430\u0448\u0438\u043d\u0430. + +BallColor.Aborted=\ + \u041e\u0442\u043c\u0435\u043d\u0435\u043d\u043e +BallColor.Disabled=\ + \u0418\u0437\u043a\u043b\u044e\u0447\u0435\u043d\u043e +BallColor.Failed=\ + \u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e +BallColor.InProgress=\ + \u0418\u0437\u043f\u044a\u043b\u043d\u0435\u043d\u0438\u0435 +BallColor.NotBuilt=\ + \u041d\u0435\u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u043e +BallColor.Pending=\ + \u041f\u0440\u0435\u0434\u0441\u0442\u043e\u0438 +BallColor.Success=\ + \u0423\u0441\u043f\u0435\u0448\u043d\u043e +BallColor.Unstable=\ + \u041d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u043d\u043e + +Build.post_build_steps_failed=\ + \u0421\u0442\u044a\u043f\u043a\u0438\u0442\u0435 \u0441\u043b\u0435\u0434 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435\u0442\u043e \u0441\u0430 \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u0438 +CLI.clear-queue.shortDescription=\ + \u0418\u0437\u0447\u0438\u0441\u0442\u0432\u0430\u043d\u0435 \u043d\u0430 \u043e\u043f\u0430\u0448\u043a\u0430\u0442\u0430 \u0441\u044a\u0441 \u0437\u0430\u0434\u0430\u0447\u0438. +CLI.delete-job.shortDescription=\ + \u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430. +CLI.reload-job.shortDescription=\ + \u041f\u0440\u0435\u0437\u0430\u0440\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430\u0442\u0430 \u043e\u0442 \u0434\u0438\u0441\u043a\u0430. +CLI.disable-job.shortDescription=\ + \u0418\u0437\u043a\u043b\u044e\u0447\u0432\u0430\u043d\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430. +CLI.enable-job.shortDescription=\ + \u0412\u043a\u043b\u044e\u0447\u0432\u0430\u043d\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430. +CLI.delete-node.shortDescription=\ + \u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u043c\u0430\u0448\u0438\u043d\u0430. +CLI.disconnect-node.shortDescription=\ + \u041f\u0440\u0435\u043a\u044a\u0441\u0432\u0430\u043d\u0435 \u043d\u0430 \u0432\u0440\u044a\u0437\u043a\u0430\u0442\u0430 \u0441 \u043c\u0430\u0448\u0438\u043d\u0430. +CLI.connect-node.shortDescription=\ + \u0421\u0432\u044a\u0440\u0437\u0432\u0430\u043d\u0435 \u043a\u044a\u043c \u043c\u0430\u0448\u0438\u043d\u0430. +CLI.online-node.shortDescription=\ + \u041e\u0442\u043d\u043e\u0432\u043e \u0434\u0430 \u0441\u0435 \u043f\u043e\u043b\u0437\u0432\u0430 \u043c\u0430\u0448\u0438\u043d\u0430 \u0437\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f. \u041e\u0442\u043c\u0435\u043d\u044f\u043d\u0435 \u043d\u0430 \u043f\u0440\u0435\u0434\u0445\u043e\u0434\u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\ + \u201eoffline-node\u201c. +CLI.offline-node.shortDescription=\ + \u0412\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043f\u0440\u0435\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u043f\u043e\u043b\u0437\u0432\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u043c\u0430\u0448\u0438\u043d\u0430 \u0437\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f \u0434\u043e\u043a\u0430\u0442\u043e \u043d\u0435 \u0441\u0435\ + \u0432\u044a\u0432\u0435\u0434\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u0442\u0430 \u201eonline-node\u201c. +CLI.wait-node-online.shortDescription=\ + \u0418\u0437\u0447\u0430\u043a\u0432\u0430\u043d\u0435 \u043d\u0430 \u043c\u0430\u0448\u0438\u043d\u0430 \u0434\u0430 \u0435 \u043d\u0430 \u043b\u0438\u043d\u0438\u044f. +CLI.wait-node-offline.shortDescription=\ + \u0418\u0437\u0447\u0430\u043a\u0432\u0430\u043d\u0435 \u043d\u0430 \u043c\u0430\u0448\u0438\u043d\u0430 \u0434\u0430 \u043d\u0435 \u0435 \u043d\u0430 \u043b\u0438\u043d\u0438\u044f. + +Computer.Caption=\ + \u041a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 \u201e{0}\u201c +Computer.NoSuchSlaveExists=\ + \u041d\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 \u201e{0}\u201c. \u201e{1}\u201c \u043b\u0438 \u0438\u043c\u0430\u0442\u0435 \u043f\u0440\u0435\u0434\u0432\u0438\u0434? +Computer.Permissions.Title=\ + \u041f\u043e\u0434\u0447\u0438\u043d\u0435\u043d \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 +Computer.ExtendedReadPermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u0434\u043e\u0441\u0442\u044a\u043f \u0437\u0430 \u0447\u0435\u0442\u0435\u043d\u0435 \u0434\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u0442\u0435 \u043d\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d\u0438\u0442\u0435 \u043a\u043e\u043c\u043f\u044e\u0442\u0440\u0438. +Computer.ConfigurePermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u0432\u0430\u043d\u0435 \u043d\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d\u0438 \u043a\u043e\u043c\u043f\u044e\u0442\u0440\u0438. +Computer.DeletePermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u043c\u0430\u0445\u0430\u043d\u0435 \u043d\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d\u0438 \u043a\u043e\u043c\u043f\u044e\u0442\u0440\u0438. +Computer.CreatePermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u0434\u043e\u0431\u0430\u0432\u044f\u043d\u0435 \u043d\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d\u0438 \u043a\u043e\u043c\u043f\u044e\u0442\u0440\u0438. +Computer.ConnectPermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u0434\u043e\u0431\u0430\u0432\u044f\u043d\u0435 \u043d\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d\u0438 \u043a\u043e\u043c\u043f\u044e\u0442\u0440\u0438 \u0438 \u043e\u0431\u044f\u0432\u044f\u0432\u0430\u043d\u0435\u0442\u043e \u0438\u043c, \u0447\u0435 \u0441\u0430 \u043d\u0430\ + \u043b\u0438\u043d\u0438\u044f. +Computer.DisconnectPermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u043c\u0430\u0445\u0430\u043d\u0435 \u043d\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d\u0438 \u043a\u043e\u043c\u043f\u044e\u0442\u0440\u0438 \u0438 \u043e\u0431\u044f\u0432\u044f\u0432\u0430\u043d\u0435\u0442\u043e \u0438\u043c, \u0447\u0435 \u043d\u0435 \u0441\u0430 \u043d\u0430\ + \u043b\u0438\u043d\u0438\u044f. +Computer.BuildPermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u043d\u0430 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0438\u0442\u0435 \u0434\u0430 \u0438\u0437\u043f\u044a\u043b\u043d\u044f\u0432\u0430\u0442 \u0437\u0430\u0434\u0430\u0447\u0438 \u043e\u0442 \u0441\u0432\u043e\u0435 \u0438\u043c\u0435 \u043d\u0430\ + \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d\u0438\u0442\u0435 \u043a\u043e\u043c\u043f\u044e\u0442\u0440\u0438. +Computer.BadChannel=\ + \u0410\u043a\u043e \u0442\u043e\u0432\u0430 \u0435 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440, \u0442\u043e\u0439 \u043d\u0435 \u0435 \u043d\u0430 \u043b\u0438\u043d\u0438\u044f. + +ComputerSet.NoSuchSlave=\ + \u041d\u044f\u043c\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 \u043d\u0430 \u0438\u043c\u0435 \u201e{0}\u201c. +ComputerSet.SlaveAlreadyExists=\ + \u0412\u0435\u0447\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 \u043d\u0430 \u0438\u043c\u0435 \u201e{0}\u201c. +ComputerSet.SpecifySlaveToCopy=\ + \u0412\u044a\u0432\u0435\u0434\u0435\u0442\u0435 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 \u0437\u0430 \u043a\u043e\u043f\u0438\u0440\u0430\u043d\u0435 +ComputerSet.DisplayName=\ + \u041a\u043e\u043c\u043f\u044e\u0442\u0440\u0438 + +Descriptor.From=\ + (\u043e\u0442 {0}) + +Executor.NotAvailable=\ + \u041b\u0438\u043f\u0441\u0432\u0430 + +FreeStyleProject.DisplayName=\ + \u041f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 + +HealthReport.EmptyString= + +Hudson.BadPortNumber=\ + \u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u0435\u043d \u043d\u043e\u043c\u0435\u0440 \u043d\u0430 \u043f\u043e\u0440\u0442 \u201e{0}\u201c +Hudson.Computer.Caption=\ + \u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0432\u0430\u0449 \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 +Hudson.Computer.DisplayName=\ + \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0432\u0430\u0449 \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 +Hudson.ControlCodeNotAllowed=\ + \u041a\u043e\u043d\u0442\u0440\u043e\u043b\u043d\u0438 \u0437\u043d\u0430\u0446\u0438 \u043d\u0435 \u0441\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u0435\u043d\u0438: {0} +Hudson.DisplayName=\ + Jenkins +Hudson.JobAlreadyExists=\ + \u0412\u0435\u0447\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u043d\u0430 \u0438\u043c\u0435 \u201e{0}\u201c. +Hudson.NoJavaInPath=\ + \u0418\u0437\u043f\u044a\u043b\u043d\u0438\u043c\u0438\u044f\u0442 \u0444\u0430\u0439\u043b \u201ejava\u201c \u043d\u0435 \u0435 \u0432 \u043f\u044a\u0442\u0438\u0449\u0430\u0442\u0430, \u0432\u043a\u043b\u044e\u0447\u0435\u043d\u0438 \u0432 \u043f\u0440\u043e\u043c\u0435\u043d\u043b\u0438\u0432\u0430\u0442\u0430 \u043d\u0430 \u0441\u0440\u0435\u0434\u0430\u0442\u0430\ + \u201ePATH\u201c. \u041f\u0440\u043e\u0431\u0432\u0430\u0439\u0442\u0435 \u0434\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u0435 \u0441\u0440\u0435\u0434\u0430\u0442\u0430 \u0437\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430\ + \u043d\u0430 Java (JDK). +Hudson.NoName=\ + \u041d\u0435 \u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043e \u0438\u043c\u0435. +Hudson.NoSuchDirectory=\ + \u041d\u044f\u043c\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u043d\u0430 \u0438\u043c\u0435 \u201e{0}\u201c +Hudson.NodeBeingRemoved=\ + \u041a\u043e\u043c\u043f\u044e\u0442\u044a\u0440\u0430 \u0441\u0435 \u0438\u0437\u0432\u0430\u0436\u0434\u0430 \u043e\u0442 \u043a\u043b\u044a\u0441\u0442\u044a\u0440\u0430 +Hudson.NotAPlugin=\ + \u201e{0}\u201c \u043d\u0435 \u0435 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430 \u043d\u0430 Jenkins. +Hudson.NotJDKDir=\ + \u201e{0}\u201c \u043d\u0435 \u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u043d\u0430 \u0441\u0440\u0435\u0434\u0430\u0442\u0430 \u0437\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043d\u0430 Java (JDK). +Hudson.Permissions.Title=\ + \u041e\u0431\u0449\u043e +Hudson.USER_CONTENT_README=\ + \u0424\u0430\u0439\u043b\u043e\u0432\u0435\u0442\u0435 \u0432 \u0442\u0430\u0437\u0438 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u0449\u0435 \u0441\u0430 \u0434\u043e\u0441\u0442\u044a\u043f\u043d\u0438 \u043f\u0440\u0435\u0437 \u0430\u0434\u0440\u0435\u0441\u0430 \ + \u201ehttp://server/jenkins/userContent/\u201c. +Hudson.UnsafeChar=\ + \u041e\u043f\u0430\u0441\u043d\u043e \u0435 \u0434\u0430 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0442\u0435 \u0437\u043d\u0430\u043a\u0430 \u201e{0}\u201c. +Hudson.ViewAlreadyExists=\ + \u0412\u0435\u0447\u0435 \u0438\u043c\u0430 \u0438\u0437\u0433\u043b\u0435\u0434 \u0441 \u0438\u043c\u0435 \u201e{0}\u201c. +Hudson.ViewName=\ + \u0412\u0441\u0438\u0447\u043a\u0438 +Hudson.NotANumber=\ + \u041d\u0435 \u0435 \u0447\u0438\u0441\u043b\u043e. +Hudson.NotAPositiveNumber=\ + \u041d\u0435 \u0435 \u043f\u043e\u043b\u043e\u0436\u0438\u0442\u0435\u043b\u043d\u043e \u0447\u0438\u0441\u043b\u043e. +Hudson.NotANonNegativeNumber=\ + \u0427\u0438\u0441\u043b\u043e\u0442\u043e \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0435 \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u043d\u043e. +Hudson.NotANegativeNumber=\ + \u0427\u0438\u0441\u043b\u043e\u0442\u043e \u043d\u0435 \u0435 \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u043d\u043e. +Hudson.NotUsesUTF8ToDecodeURL=\ + \u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044a\u0442 \u0437\u0430 \u0441\u044a\u0440\u0432\u043b\u0435\u0442\u0438 \u043d\u0435 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430 UTF-8 \u0437\u0430 \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0430\u0434\u0440\u0435\u0441\u0438. \u0417\u043d\u0430\u0446\u0438\ + \u0438\u0437\u0432\u044a\u043d ASCII \u0432 \u0438\u043c\u0435\u043d\u0430\u0442\u0430 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0438 \u0438 \u0434\u0440. \u0449\u0435 \u043f\u0440\u0438\u0447\u0438\u043d\u044f\u0442 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0438. \u0417\u0430 \u043f\u043e\u0432\u0435\u0447\u0435\ + \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043f\u043e\u0433\u043b\u0435\u0434\u043d\u0435\u0442\u0435\ + \u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0438\ + \u0438\ + \ + \u0418\u043d\u0442\u0435\u0440\u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0430 Tomcat. +Hudson.AdministerPermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u043f\u0440\u043e\u043c\u044f\u043d\u0430 \u043d\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438, \u043a\u0430\u043a\u0442\u043e \u0438 \u043f\u044a\u043b\u0435\u043d \u0434\u043e\u0441\u0442\u044a\u043f \u0434\u043e\ + \u043b\u043e\u043a\u0430\u043b\u043d\u0430\u0442\u0430 \u0444\u0430\u0439\u043b\u043e\u0432\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 \u0432 \u0440\u0430\u043c\u043a\u0438\u0442\u0435 \u043d\u0430 \u043f\u0440\u0430\u0432\u0430\u0442\u0430 \u0441\u043f\u043e\u0440\u0435\u0434 \u0440\u0430\u0431\u043e\u0442\u0435\u0449\u0430\u0442\u0430 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u0430\ + \u0441\u0438\u0441\u0442\u0435\u043c\u0430. +Hudson.ReadPermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u0440\u0430\u0437\u0433\u043b\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u043f\u043e\u0447\u0442\u0438 \u0432\u0441\u0438\u0447\u043a\u0438 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0438 \u043d\u0430 Jenkins. \u0410\u043a\u043e \u043d\u0435\ + \u0438\u0441\u043a\u0430\u0442\u0435 \u043d\u0435\u043f\u043e\u0437\u043d\u0430\u0442\u0438\u0442\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0438 \u0434\u0430 \u0432\u0438\u0436\u0434\u0430\u0442 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0438\u0442\u0435 \u043d\u0430 Jenkins, \u043e\u0442\u043d\u0435\u043c\u0435\u0442\u0435 \u0442\u043e\u0432\u0430\ + \u043f\u0440\u0430\u0432\u043e \u043d\u0430 \u0430\u043d\u043e\u043d\u0438\u043c\u043d\u0438\u044f \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b (\u201eanonymous\u201c) \u0438 \u0433\u043e \u0434\u0430\u0439\u0442\u0435 \u043d\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0430\u043b\u0438\u0442\u0435 \u0441\u0435\ + \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0438 (\u201eauthenticated\u201c). +Hudson.RunScriptsPermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u0438\u0437\u043f\u044a\u043b\u043d\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u043a\u0440\u0438\u043f\u0442\u043e\u0432\u0435 \u043e\u0442 \u043f\u0440\u043e\u0446\u0435\u0441\u0430 \u043d\u0430 \u043f\u0440\u0435\u0437 \u043a\u043e\u043d\u0437\u043e\u043b\u0430\u0442\u0430 \u043d\u0430\ + Groovy \u0438\u043b\u0438 \u0441 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0438\u0442\u0435 \u043d\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u0438\u044f \u0440\u0435\u0434. +Hudson.NodeDescription=\ + \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0432\u0430\u0449\u0438\u044f\u0442 \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 \u043d\u0430 Jenkins + +Item.Permissions.Title=\ + \u0417\u0430\u0434\u0430\u0447\u0430 +Item.CREATE.description=\ + \u0421\u044a\u0437\u0434\u0430\u0432\u0430\u043d\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430. +Item.DELETE.description=\ + \u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430. +Item.CONFIGURE.description=\ + \u041f\u0440\u043e\u043c\u044f\u043d\u0430 \u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u0442\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430. +Item.READ.description=\ + \u041f\u0440\u0435\u0433\u043b\u0435\u0434 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430. (\u041c\u043e\u0436\u0435 \u0434\u0430 \u043e\u0442\u043c\u0435\u043d\u0438\u0442\u0435 \u0442\u043e\u0432\u0430 \u043f\u0440\u0430\u0432\u043e, \u043d\u043e \u0447\u0440\u0435\u0437 \u043f\u0440\u0430\u0432\u043e\u0442\u043e \u0437\u0430 \u043e\u0442\u043a\u0440\u0438\u0432\u0430\u043d\u0435\ + \u0434\u0430 \u043d\u0430\u043a\u0430\u0440\u0430\u0442\u0435 \u0430\u043d\u043e\u043d\u0438\u043c\u043d\u0438\u0442\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0438 \u0434\u0430 \u0441\u0435 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u0446\u0438\u0440\u0430\u0442, \u0437\u0430 \u0434\u0430 \u0432\u0438\u0434\u044f\u0442 \u0437\u0430\u0434\u0430\u0447\u0430\u0442\u0430.) + +Job.AllRecentBuildFailed=\ + \u0412\u0441\u0438\u0447\u043a\u0438 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f \u0441\u0430 \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u0438. +Job.BuildStability=\ + \u0421\u0442\u0430\u0431\u0438\u043b\u043d\u043e\u0441\u0442 \u043d\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f\u0442\u0430: {0} +Job.NOfMFailed=\ + {0} \u043e\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0442\u0435 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f {1} \u0441\u0430 \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u0438. +Job.NoRecentBuildFailed=\ + \u0421\u043a\u043e\u0440\u043e \u043d\u0435 \u0435 \u0438\u043c\u0430\u043b\u043e \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u0438 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f. +Job.Pronoun=\ + \u041f\u0440\u043e\u0435\u043a\u0442 +Job.minutes=\ + \u043c\u0438\u043d. + +Job.you_must_use_the_save_button_if_you_wish=\ + \u0417\u0430 \u0434\u0430 \u043f\u0440\u0435\u0438\u043c\u0435\u043d\u0443\u0432\u0430\u0442\u0435 \u0437\u0430\u0434\u0430\u0447\u0430, \u043d\u0430\u0442\u0438\u0441\u043d\u0435\u0442\u0435 \u0431\u0443\u0442\u043e\u043d\u0430 \u201e\u0417\u0430\u043f\u0430\u0437\u0432\u0430\u043d\u0435\u201c. +Label.GroupOf=\ + \u0433\u0440\u0443\u043f\u0430\u0442\u0430 \u043d\u0430 {0} +Label.InvalidLabel=\ + \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u0435\u043d \u0435\u0442\u0438\u043a\u0435\u0442 +Label.ProvisionedFrom=\ + \u041d\u0430\u0431\u0430\u0432\u0435\u043d\u0430 \u043e\u0442 {0} +ManageJenkinsAction.DisplayName=\ + \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 Jenkins +MultiStageTimeSeries.EMPTY_STRING= +Queue.AllNodesOffline=\ + \u041d\u0438\u043a\u043e\u044f \u043c\u0430\u0448\u0438\u043d\u0430 \u0441 \u0435\u0442\u0438\u043a\u0435\u0442 \u201e{0}\u201c \u043d\u0435 \u0435 \u043d\u0430 \u043b\u0438\u043d\u0438\u044f. +Queue.LabelHasNoNodes=\ + \u041d\u044f\u043c\u0430 \u043c\u0430\u0448\u0438\u043d\u0430 \u0441 \u0435\u0442\u0438\u043a\u0435\u0442 \u201e{0}\u201c. +Queue.BlockedBy=\ + \u0411\u043b\u043e\u043a\u0438\u0440\u0430\u043d\u043e \u043e\u0442 \u201e{0}\u201c. +Queue.HudsonIsAboutToShutDown=\ + Jenkins \u0449\u0435 \u0441\u0435 \u0441\u043f\u0440\u0435. +Queue.InProgress=\ + \u0418\u0437\u0432\u044a\u0440\u0448\u0432\u0430 \u0441\u0435 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435. +Queue.InQuietPeriod=\ + \u0418\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u0442\u0438\u0448\u0438\u043d\u0430, \u0438\u0437\u0442\u0438\u0447\u0430 \u0441\u043b\u0435\u0434 {0} +Queue.NodeOffline=\ + \u201e{0}\u201c \u043d\u0435 \u0435 \u043d\u0430 \u043b\u0438\u043d\u0438\u044f. +Queue.Unknown=\ + \u041d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e +Queue.WaitingForNextAvailableExecutor=\ + \u0418\u0437\u0447\u0430\u043a\u0432\u0430\u043d\u0435 \u043d\u0430 \u0441\u043b\u0435\u0434\u0432\u0430\u0449\u0438\u044f \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440. +Queue.WaitingForNextAvailableExecutorOn=\ + \u0418\u0437\u0447\u0430\u043a\u0432\u0430\u043d\u0435 \u043d\u0430 \u0441\u043b\u0435\u0434\u0432\u0430\u0449\u0438\u044f \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 \u0437\u0430 \u201e{0}\u201c. +Queue.init=\ + \u0412\u044a\u0437\u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u043e\u043f\u0430\u0448\u043a\u0430\u0442\u0430 \u0441 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f. + +ResultTrend.Aborted=\ + \u041f\u0440\u0435\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0435\u043d\u043e +ResultTrend.Failure=\ + \u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e +ResultTrend.Fixed=\ + \u041e\u043f\u0440\u0430\u0432\u0435\u043d\u043e +ResultTrend.NotBuilt=\ + \u041d\u0435\u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u043e +ResultTrend.NowUnstable=\ + \u041d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u043d\u043e +ResultTrend.StillFailing=\ + \u0412\u0441\u0435 \u043e\u0449\u0435 \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e +ResultTrend.StillUnstable=\ + \u0412\u0441\u0435 \u043e\u0449\u0435 \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u043d\u043e +ResultTrend.Success=\ + \u0423\u0441\u043f\u0435\u0448\u043d\u043e +ResultTrend.Unstable=\ + \u041d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u043d\u043e +Run._is_waiting_for_a_checkpoint_on_=\ + {0} \u0438\u0437\u0447\u0430\u043a\u0432\u0430 \u043f\u0440\u0430\u0432\u0438\u043b\u043d\u0438\u044f \u043c\u043e\u043c\u0435\u043d\u0442 \u0437\u0430 {1} +Run.BuildAborted=\ + \u041f\u0440\u0435\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0435\u043d\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +Run.MarkedExplicitly=\ + \u0422\u043e\u0437\u0438 \u0437\u0430\u043f\u0438\u0441 \u0435 \u043e\u0442\u0431\u0435\u043b\u044f\u0437\u0430\u043d \u0437\u0430 \u0441\u044a\u0445\u0440\u0430\u043d\u0435\u043d\u0438\u0435. +Run.Permissions.Title=\ + \u0418\u0437\u043f\u044a\u043b\u043d\u0435\u043d\u0438\u0435 +Run.running_as_=\ + \u0418\u0437\u043f\u044a\u043b\u043d\u0435\u043d\u0438\u0435 \u043a\u0430\u0442\u043e \u201e{0}\u201c +Run.UnableToDelete=\ + \u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u201e{0}\u201c: {1} +Run.DeletePermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u0438\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u043f\u043e\u0441\u043e\u0447\u0435\u043d\u0438 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f \u043e\u0442 \u0438\u0441\u0442\u043e\u0440\u0438\u044f\u0442\u0430 \u043d\u0430\ + \u0437\u0430\u0434\u0430\u0447\u0438\u0442\u0435. +Run.UpdatePermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u043f\u0440\u043e\u043c\u044f\u043d\u0430\u0442\u0430 \u043d\u0430 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u0442\u043e \u0438 \u0434\u0440\u0443\u0433\u0438\u0442\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435.\ + \u0422\u0430\u043a\u0430 \u043c\u043e\u0433\u0430\u0442 \u0434\u0430 \u0441\u0435 \u0437\u0430\u043f\u0430\u0437\u0432\u0430\u0442 \u043f\u0440\u0438\u0447\u0438\u043d\u0438\u0442\u0435 \u0437\u0430 \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440. +Run.ArtifactsPermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u0434\u043e\u0441\u0442\u044a\u043f \u0434\u043e \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u0438\u0442\u0435, \u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438 \u043e\u0442 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f\u0442\u0430. \u041d\u0435\ + \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u0442\u043e\u0432\u0430 \u043f\u0440\u0430\u0432\u043e, \u0430\u043a\u043e \u0438\u0441\u043a\u0430\u0442\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0438\u0442\u0435 \u0434\u0430 \u043d\u0435 \u043c\u043e\u0433\u0430\u0442 \u0434\u0430 \u0438\u0437\u0442\u0435\u0433\u043b\u044f\u0442\ + \u0438\u0437\u0433\u0440\u0430\u0434\u0435\u043d\u043e\u0442\u043e. +Run.InProgressDuration=\ + {0} \u0438 \u0440\u0430\u0441\u0442\u0435 +Run.NotStartedYet=\ + \u041e\u0449\u0435 \u043d\u0435 \u0435 \u0437\u0430\u043f\u043e\u0447\u043d\u0430\u043b\u043e +Run.ArtifactsBrowserTitle= + \u0410\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u0438 \u043d\u0430 {0} {1} + +Run.Summary.Stable=\ + \u0441\u0442\u0430\u0431\u0438\u043b\u043d\u043e +Run.Summary.Unstable=\ + \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u043d\u043e +Run.Summary.Aborted=\ + \u043f\u0440\u0435\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0435\u043d\u043e +Run.Summary.NotBuilt=\ + \u043d\u0435\u0438\u0437\u0433\u0440\u0430\u0434\u0435\u043d\u043e +Run.Summary.BackToNormal=\ + \u043d\u043e\u0440\u043c\u0430\u043b\u043d\u043e +Run.Summary.BrokenForALongTime=\ + \u0441\u0447\u0443\u043f\u0435\u043d\u043e \u043e\u0442 \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435 +Run.Summary.BrokenSinceThisBuild=\ + \u0441\u0447\u0443\u043f\u0435\u043d\u043e \u043e\u0442 \u0442\u043e\u0432\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +Run.Summary.BrokenSince=\ + \u0441\u0447\u0443\u043f\u0435\u043d\u043e \u043e\u0442 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u2116\u200a{0} +Run.Summary.Unknown=\ + \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u043d\u043e + +Slave.InvalidConfig.Executors=\ + \u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u043d\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 \u201e{0}\u201c \u2014 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u0435\u043d \u0431\u0440\u043e\u0439 \u043d\u0430\ + \u0438\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u0438\u0442\u0435. +Slave.InvalidConfig.NoName=\ + \u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u043d\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 \u2014 \u0438\u043c\u0435\u0442\u043e \u0435 \u043f\u0440\u0430\u0437\u043d\u043e. +Slave.InvalidConfig.NoRemoteDir=\ + \u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u043d\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 \u201e{0}\u201c \u2014 \u043b\u0438\u043f\u0441\u0432\u0430 \u043e\u0442\u0434\u0430\u043b\u0435\u0447\u0435\u043d\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f. +Slave.Launching=\ + {0} \u2014 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d \u043f\u0440\u043e\u0446\u0435\u0441 +Slave.Network.Mounted.File.System.Warning=\ + \u0421\u0438\u0433\u0443\u0440\u043d\u0438 \u043b\u0438 \u0441\u0442\u0435, \u0447\u0435 \u0438\u0441\u043a\u0430\u0442\u0435 \u0441\u0430 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0442\u0435 \u0444\u0430\u0439\u043b\u043e\u0432\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430, \u043c\u043e\u043d\u0442\u0438\u0440\u0430\u043d\u0430 \u043f\u043e\ + \u043c\u0440\u0435\u0436\u0430\u0442\u0430, \u043a\u0430\u0442\u043e \u043a\u043e\u0440\u0435\u043d\u043e\u0432\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f? \u041d\u044f\u043c\u0430 \u043d\u0443\u0436\u0434\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f\u0442\u0430 \u0434\u0430 \u0441\u0435 \u0432\u0438\u0436\u0434\u0430 \u043e\u0442\ + \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0432\u0430\u0449\u0438\u044f \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440. +Slave.Remote.Director.Mandatory=\ + \u041e\u0442\u0434\u0430\u043b\u0435\u0447\u0435\u043d\u0430\u0442\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f \u0435 \u0437\u0430\u0434\u044a\u043b\u0436\u0438\u0442\u0435\u043b\u043d\u0430. +Slave.Terminated=\ + {0} \u2014 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d\u0438\u044f\u0442 \u043f\u0440\u043e\u0446\u0435\u0441 \u0431\u0435 \u043f\u0440\u0435\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0435\u043d +Slave.Remote.Relative.Path.Warning=\ + \u0421\u0438\u0433\u0443\u0440\u043d\u0438 \u043b\u0438 \u0441\u0442\u0435, \u0447\u0435 \u0438\u0441\u043a\u0430\u0442\u0435 \u0441\u0430 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0442\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u0435\u043d \u043f\u044a\u0442 \u043a\u0430\u0442\u043e \u043a\u043e\u0440\u0435\u043d\u043e\u0432\u0430\ + \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f? \u041f\u0440\u043e\u0432\u0435\u0440\u0435\u0442\u0435 \u0434\u0430\u043b\u0438 \u0438\u0437\u0431\u0440\u0430\u043d\u0438\u044f\u0442 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u0449 \u043f\u0440\u043e\u0446\u0435\u0441 \u043e\u0441\u0438\u0433\u0443\u0440\u044f\u0432\u0430 \u043a\u043e\u043d\u0441\u0438\u0441\u0442\u0435\u043d\u0442\u043d\u043e\u0441\u0442\ + \u043d\u0430 \u0442\u0435\u043a\u0443\u0449\u0430\u0442\u0430 \u0440\u0430\u0431\u043e\u0442\u043d\u0430 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044f. \u041f\u0440\u0435\u043f\u043e\u0440\u044a\u0447\u0438\u0442\u0435\u043b\u043d\u043e \u0435 \u0434\u0430 \u043f\u043e\u043b\u0437\u0432\u0430\u0442\u0435 \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u0435\u043d \u043f\u044a\u0442. +Slave.UnableToLaunch=\ + \u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d \u043f\u0440\u043e\u0446\u0435\u0441 \u0437\u0430 \u201e{0}{1}\u201c +Slave.UnixSlave=\ + \u041f\u043e\u0434\u0447\u0438\u043d\u0435\u043d \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 \u0441 Unix. +Slave.WindowsSlave=\ + \u041f\u043e\u0434\u0447\u0438\u043d\u0435\u043d \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 \u0441 Windows. + +TopLevelItemDescriptor.NotApplicableIn=\ + {0} \u0435\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043d\u0435 \u043c\u043e\u0433\u0430\u0442 \u0434\u0430 \u0441\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0430\u0442 \u0432 {1} + +UpdateCenter.DownloadButNotActivated=\ + \u0423\u0441\u043f\u0435\u0448\u043d\u043e \u0438\u0437\u0442\u0435\u0433\u043b\u044f\u043d\u0435. \u0429\u0435 \u0441\u0440\u0430\u0431\u043e\u0442\u0438 \u0441\u043b\u0435\u0434 \u0441\u043b\u0435\u0434\u0432\u0430\u0449\u043e\u0442\u043e \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435. +UpdateCenter.n_a=\ + \u041b\u0438\u043f\u0441\u0432\u0430 +View.Permissions.Title=\ + \u0418\u0437\u0433\u043b\u0435\u0434 +View.CreatePermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u0441\u044a\u0437\u0434\u0430\u0432\u0430\u043d\u0435 \u043d\u0430 \u043d\u043e\u0432\u0438 \u0438\u0437\u0433\u043b\u0435\u0434\u0438. +View.DeletePermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u0438\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430\u0449\u0438 \u0438\u0437\u0433\u043b\u0435\u0434\u0438. +View.ConfigurePermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u043f\u0440\u043e\u043c\u044f\u043d\u0430 \u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u0442\u0435 \u043d\u0430 \u0438\u0437\u0433\u043b\u0435\u0434\u0438\u0442\u0435. +View.ReadPermission.Description=\ + \u0422\u043e\u0432\u0430 \u0434\u0430\u0432\u0430 \u043f\u0440\u0430\u0432\u043e \u0437\u0430 \u0432\u0438\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0438\u0437\u0433\u043b\u0435\u0434\u0438\u0442\u0435 (\u043f\u043e\u0434\u0440\u0430\u0437\u0431\u0438\u0440\u0430 \u0441\u0435 \u043f\u0440\u0438 \u043e\u0431\u0449\u043e \u043f\u0440\u0430\u0432\u043e \u0437\u0430\ + \u0434\u043e\u0441\u0442\u044a\u043f). +View.MissingMode=\ + \u0412\u0438\u0434\u044a\u0442 \u043d\u0430 \u0438\u0437\u0433\u043b\u0435\u0434\u0430 \u043d\u0435 \u0435 \u0438\u0437\u0431\u0440\u0430\u043d. + +UpdateCenter.Status.CheckingInternet=\ + \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0432\u0440\u044a\u0437\u043a\u0430\u0442\u0430 \u043a\u044a\u043c \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442 +UpdateCenter.Status.CheckingJavaNet=\ + \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0432\u0440\u044a\u0437\u043a\u0430\u0442\u0430 \u043a\u044a\u043c \u0446\u0435\u043d\u0442\u044a\u0440\u0430 \u0437\u0430 \u043e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 +UpdateCenter.Status.Success=\ + \u0423\u0441\u043f\u0435\u0445 +UpdateCenter.Status.UnknownHostException=\ + \u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0430\u0434\u0440\u0435\u0441\u0430 \u201e{0}\u201c.\ + \u0412\u0435\u0440\u043e\u044f\u0442\u043d\u043e \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u0435\ + \u0441\u044a\u0440\u0432\u044a\u0440-\u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a \u0437\u0430 HTTP. +UpdateCenter.Status.ConnectionFailed=\ + \u0412\u0435\u0440\u043e\u044f\u0442\u043d\u043e \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u0435\ + \u0441\u044a\u0440\u0432\u044a\u0440-\u043f\u043e\u0441\u0440\u0435\u0434\u043d\u0438\u043a \u0437\u0430 HTTP. +UpdateCenter.init=\ + \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0446\u0435\u043d\u0442\u044a\u0440\u0430 \u0437\u0430 \u043e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 +UpdateCenter.PluginCategory.android=\ + \u041f\u0440\u043e\u0433\u0440\u0430\u043c\u0438\u0440\u0430\u043d\u0435 \u0437\u0430 Android +UpdateCenter.PluginCategory.builder=\ + \u0418\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0438 \u0437\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +UpdateCenter.PluginCategory.buildwrapper=\ + \u0421\u043a\u0440\u0438\u043f\u0442\u043e\u0432\u0435, \u043e\u0431\u0432\u0438\u0432\u0430\u0449\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0438\u0442\u0435 \u0437\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +UpdateCenter.PluginCategory.cli=\ + \u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0434\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u0438\u044f \u0440\u0435\u0434 +UpdateCenter.PluginCategory.cloud=\ + \u0414\u043e\u0441\u0442\u0430\u0432\u0447\u0438\u0446\u0438 \u043d\u0430 \u043e\u0431\u043b\u0430\u0447\u043d\u0438 \u0443\u0441\u043b\u0443\u0433\u0438 +UpdateCenter.PluginCategory.cluster=\ + \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u043a\u043b\u044a\u0441\u0442\u044a\u0440\u0430 \u0438 \u0440\u0430\u0437\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043e\u0442\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +UpdateCenter.PluginCategory.database=\ + \u0411\u0430\u0437\u0438 \u043e\u0442 \u0434\u0430\u043d\u043d\u0438 +UpdateCenter.PluginCategory.deployment=\ + \u0418\u043d\u0441\u0442\u0430\u043b\u0438\u0440\u0430\u043d\u0435 +UpdateCenter.PluginCategory.devops=\ + DevOps +UpdateCenter.PluginCategory.dotnet=\ + \u041f\u0440\u043e\u0433\u0440\u0430\u043c\u0438\u0440\u0430\u043d\u0435 \u0437\u0430 .NET +UpdateCenter.PluginCategory.external=\ + \u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0441\u044a\u0441 \u0441\u0430\u0439\u0442\u043e\u0432\u0435 \u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0438 +UpdateCenter.PluginCategory.groovy-related=\ + \u0421\u0432\u044a\u0440\u0437\u0430\u043d\u0438 \u0441 Groovy +UpdateCenter.PluginCategory.ios=\ + \u041f\u0440\u043e\u0433\u0440\u0430\u043c\u0438\u0440\u0430\u043d\u0435 \u0437\u0430 iOS +UpdateCenter.PluginCategory.library=\ + \u041f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0438-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 (\u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0442 \u0441\u0435 \u043e\u0442 \u0434\u0440\u0443\u0433\u0438 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0438) +UpdateCenter.PluginCategory.listview-column=\ + \u041a\u043e\u043b\u043e\u043d\u0438 \u0432 \u0441\u043f\u0438\u0441\u044a\u0447\u043d\u0438\u044f \u0438\u0437\u0433\u043b\u0435\u0434 +UpdateCenter.PluginCategory.maven=\ + Maven +UpdateCenter.PluginCategory.misc=\ + \u0420\u0430\u0437\u043d\u0438 +UpdateCenter.PluginCategory.notifier=\ + \u0418\u0437\u0432\u0435\u0441\u0442\u044f\u0432\u0430\u043d\u0435 \u043f\u0440\u0438 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +UpdateCenter.PluginCategory.page-decorator=\ + \u0414\u0435\u043a\u043e\u0440\u0430\u0446\u0438\u044f \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0438\u0442\u0435 +UpdateCenter.PluginCategory.parameter=\ + \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438 \u0437\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +UpdateCenter.PluginCategory.post-build=\ + \u0414\u043e\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u043d\u0438 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u043b\u0435\u0434 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +UpdateCenter.PluginCategory.python=\ + \u041f\u0440\u043e\u0433\u0440\u0430\u043c\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 Python +UpdateCenter.PluginCategory.report=\ + \u041e\u0442\u0447\u0435\u0442\u0438 \u0437\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f\u0442\u0430 +UpdateCenter.PluginCategory.ruby=\ + \u041f\u0440\u043e\u0433\u0440\u0430\u043c\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 Ruby +UpdateCenter.PluginCategory.runcondition=\ + \u0423\u0441\u043b\u043e\u0432\u0438\u044f \u0437\u0430 \u0438\u0437\u043f\u044a\u043b\u043d\u0435\u043d\u0438\u0435 (\u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430 \u0441\u0435 \u043e\u0442 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0430\u0442 RunConditions) +UpdateCenter.PluginCategory.scala=\ + \u041f\u0440\u043e\u0433\u0440\u0430\u043c\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 Scala +UpdateCenter.PluginCategory.scm=\ + \u0421\u0438\u0441\u0442\u0435\u043c\u0430 \u0437\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u0438\u0442\u0435 +UpdateCenter.PluginCategory.scm-related=\ + \u041e\u0449\u0435 \u0437\u0430 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435\u0442\u043e \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u0438\u0442\u0435 +UpdateCenter.PluginCategory.security=\ + \u0421\u0438\u0433\u0443\u0440\u043d\u043e\u0441\u0442 +UpdateCenter.PluginCategory.slaves=\ + \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u043e\u0434\u0447\u0438\u043d\u0435\u043d\u0438\u0442\u0435 \u0438\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u0438 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0438 +UpdateCenter.PluginCategory.test=\ + \u0422\u0435\u0441\u0442\u0432\u0430\u043d\u0435 +UpdateCenter.PluginCategory.trigger=\ + \u0410\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u043e \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f +UpdateCenter.PluginCategory.ui=\ + \u041f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u0438 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 +UpdateCenter.PluginCategory.upload=\ + \u041a\u0430\u0447\u0432\u0430\u043d\u0435 \u043d\u0430 \u0430\u0440\u0442\u0435\u0444\u0430\u043a\u0442\u0438 +UpdateCenter.PluginCategory.user=\ + \u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0438 +UpdateCenter.PluginCategory.view=\ + \u0418\u0437\u0433\u043b\u0435\u0434\u0438 +UpdateCenter.PluginCategory.must-be-labeled=\ + \u0411\u0435\u0437 \u043a\u0430\u0442\u0435\u0433\u043e\u0440\u0438\u044f +UpdateCenter.PluginCategory.unrecognized=\ + \u0420\u0430\u0437\u043d\u0438 ({0}) + +Permalink.LastBuild=\ + \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +Permalink.LastStableBuild=\ + \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u043e \u0441\u0442\u0430\u0431\u0438\u043b\u043d\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +Permalink.LastUnstableBuild=\ + \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u043e \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u043d\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +Permalink.LastUnsuccessfulBuild=\ + \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u043e \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +Permalink.LastSuccessfulBuild=\ + \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u043e \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +Permalink.LastFailedBuild=\ + \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u043e \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +Permalink.LastCompletedBuild=\ + \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u043e \u0437\u0430\u0432\u044a\u0440\u0448\u0435\u043d\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 + +ParameterAction.DisplayName=\ + \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438 +ParametersDefinitionProperty.DisplayName=\ + \u0422\u043e\u0432\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u0435 \u043f\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438 +StringParameterDefinition.DisplayName=\ + \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u044a\u0440-\u043d\u0438\u0437 +TextParameterDefinition.DisplayName=\ + \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u044a\u0440-\u0442\u0435\u043a\u0441\u0442 +FileParameterDefinition.DisplayName=\ + \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u044a\u0440-\u0444\u0430\u0439\u043b +BooleanParameterDefinition.DisplayName=\ + \u0411\u0443\u043b\u0435\u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u044a\u0440 +ChoiceParameterDefinition.DisplayName=\ + \u0421\u043f\u0438\u0441\u044a\u0447\u0435\u043d \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u044a\u0440 +ChoiceParameterDefinition.MissingChoices=\ + \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c \u0435 \u0441\u043f\u0438\u0441\u044a\u043a \u043e\u0442 \u0441\u0442\u043e\u0439\u043d\u043e\u0441\u0442\u0438. +RunParameterDefinition.DisplayName=\ + \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u044a\u0440 \u0437\u0430 \u0438\u0437\u043f\u044a\u043b\u043d\u0435\u043d\u0438\u0435 +PasswordParameterDefinition.DisplayName=\ + \u041f\u0430\u0440\u0430\u043c\u0435\u0442\u044a\u0440-\u043f\u0430\u0440\u043e\u043b\u0430 + +Node.BecauseNodeIsReserved=\ + \u201e{0}\u201c \u0435 \u0437\u0430\u043f\u0430\u0437\u0435\u043d\u0430 \u0437\u0430 \u0437\u0430\u0434\u0430\u0447\u0438 \u0441 \u043e\u0442\u0433\u043e\u0432\u0430\u0440\u044f\u0449 \u0435\u0442\u0438\u043a\u0435\u0442. +Node.BecauseNodeIsNotAcceptingTasks=\ + \u201e{0}\u201c \u043d\u0435 \u043f\u0440\u0438\u0435\u043c\u0430 \u0437\u0430\u0434\u0430\u0447\u0438. +Node.LabelMissing=\ + \u201e{0}\u201c \u043d\u044f\u043c\u0430 \u0435\u0442\u0438\u043a\u0435\u0442\u0430 \u201e{1}\u201c. +Node.LackingBuildPermission=\ + \u201e{0}\u201c \u043d\u044f\u043c\u0430 \u043f\u0440\u0430\u0432\u043e \u0434\u0430 \u0441\u0435 \u0438\u0437\u043f\u044a\u043b\u043d\u044f\u0432\u0430 \u043e\u0442 \u201e{1}\u201c. +Node.Mode.NORMAL=\ + \u0422\u0430\u0437\u0438 \u043c\u0430\u0448\u0438\u043d\u0430 \u0434\u0435 \u0441\u0435 \u043f\u043e\u043b\u0437\u0432\u0430 \u0432\u044a\u0437\u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0439-\u043c\u043d\u043e\u0433\u043e. +Node.Mode.EXCLUSIVE=\ + \u0414\u0430 \u0441\u0435 \u0438\u0437\u043f\u044a\u043b\u043d\u044f\u0432\u0430\u0442 \u0437\u0430\u0434\u0430\u0447\u0438 \u0441 \u0435\u0442\u0438\u043a\u0435\u0442\u0438 \u043e\u0442\u0433\u043e\u0432\u0430\u0440\u044f\u0449\u0438 \u043d\u0430 \u0442\u0430\u0437\u0438 \u043c\u0430\u0448\u0438\u043d\u0430. + +ListView.DisplayName=\ + \u0421\u043f\u0438\u0441\u044a\u0447\u0435\u043d \u0438\u0437\u0433\u043b\u0435\u0434 + +MyView.DisplayName=\ + \u041c\u043e\u044f\u0442 \u0438\u0437\u0433\u043b\u0435\u0434 + +LoadStatistics.Legends.DefinedExecutors=\ + \u0414\u0435\u0444\u0438\u043d\u0438\u0440\u0430\u043d\u0438 \u043c\u0430\u0448\u0438\u043d\u0438-\u0438\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u0438 +LoadStatistics.Legends.OnlineExecutors=\ + \u041c\u0430\u0448\u0438\u043d\u0438-\u0438\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u0438 \u043d\u0430 \u043b\u0438\u043d\u0438\u044f +LoadStatistics.Legends.ConnectingExecutors=\ + \u0421\u0432\u044a\u0440\u0437\u0430\u043d\u0438 \u043c\u0430\u0448\u0438\u043d\u0438-\u0438\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u0438 +LoadStatistics.Legends.TotalExecutors=\ + \u041e\u0431\u0449\u043e \u043c\u0430\u0448\u0438\u043d\u0438-\u0438\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u0438 +LoadStatistics.Legends.BusyExecutors=\ + \u0417\u0430\u0435\u0442\u0438 \u043c\u0430\u0448\u0438\u043d\u0438-\u0438\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u0438 +LoadStatistics.Legends.IdleExecutors=\ + \u0421\u0432\u043e\u0431\u043e\u0434\u043d\u0438 \u043c\u0430\u0448\u0438\u043d\u0438-\u0438\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u0438 +LoadStatistics.Legends.AvailableExecutors=\ + \u041d\u0430\u043b\u0438\u0447\u043d\u0438 \u043c\u0430\u0448\u0438\u043d\u0438-\u0438\u0437\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u0438 +LoadStatistics.Legends.QueueLength=\ + \u0414\u044a\u043b\u0436\u0438\u043d\u0430 \u043d\u0430 \u043e\u043f\u0430\u0448\u043a\u0430\u0442\u0430 + +Cause.LegacyCodeCause.ShortDescription=\ + \u0421\u0442\u0430\u0440 \u043a\u043e\u0434 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430 \u0442\u0430\u0437\u0438 \u0437\u0430\u0434\u0430\u0447\u0430 \u2014 \u043b\u0438\u043f\u0441\u0432\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0437\u0430 \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u0442\u0430. +Cause.UpstreamCause.ShortDescription=\ + \u0421\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0430 \u043e\u0442 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u201e{0}\u201c, \u043e\u0442 \u043a\u043e\u0439\u0442\u043e \u0442\u044f \u0437\u0430\u0432\u0438\u0441\u0438, \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u2116\u200a{1} +Cause.UpstreamCause.CausedBy=\ + \u043f\u044a\u0440\u0432\u043e\u043d\u0430\u0447\u0430\u043b\u043d\u043e \u043f\u043e\u0440\u0430\u0434\u0438: +Cause.UserCause.ShortDescription=\ + \u0421\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0430 \u043e\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b: \u201e{0}\u201c +Cause.UserIdCause.ShortDescription=\ + \u0421\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0430 \u043e\u0442 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b: \u201e{0}\u201c +Cause.RemoteCause.ShortDescription=\ + \u0421\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u043e \u043e\u0442 \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440\u0430: \u201e{0}\u201c +Cause.RemoteCause.ShortDescriptionWithNote=\ + \u0421\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u043e \u043e\u0442 \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440\u0430: \u201e{0}\u201c \u0441\u044a\u0441 \u0441\u043b\u0435\u0434\u043d\u0430\u0442\u0430 \u0431\u0435\u043b\u0435\u0436\u043a\u0430: \u201e{1}\u201c + +ProxyView.NoSuchViewExists=\ + \u0413\u043b\u043e\u0431\u0430\u043b\u043d\u0438\u044f\u0442 \u0438\u0437\u0433\u043b\u0435\u0434 \u201e{0}\u201c \u043d\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430 +ProxyView.DisplayName=\ + \u0412\u043a\u043b\u044e\u0447\u0432\u0430\u043d\u0435 \u043d\u0430 \u0433\u043b\u043e\u0431\u0430\u043b\u0435\u043d \u0438\u0437\u0433\u043b\u0435\u0434 + +MyViewsProperty.DisplayName=\ + \u041c\u043e\u0438\u0442\u0435 \u0438\u0437\u0433\u043b\u0435\u0434\u0438 +MyViewsProperty.GlobalAction.DisplayName=\ + \u041c\u043e\u0438\u0442\u0435 \u0438\u0437\u0433\u043b\u0435\u0434\u0438 +MyViewsProperty.ViewExistsCheck.NotExist=\ + \u0418\u0437\u0433\u043b\u0435\u0434 \u0441 \u0438\u043c\u0435 \u201e{0}\u201c \u043d\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430 +MyViewsProperty.ViewExistsCheck.AlreadyExists=\ + \u0418\u0437\u0433\u043b\u0435\u0434 \u0441 \u0438\u043c\u0435 \u201e{0}\u201c \u0432\u0435\u0447\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430 + +CLI.restart.shortDescription=\ + \u0420\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 Jenkins +CLI.safe-restart.shortDescription=\ + \u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 Jenkins +CLI.keep-build.shortDescription=\ + \u041e\u0442\u0431\u0435\u043b\u044f\u0437\u0432\u0430\u043d\u0435 \u043d\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435\u0442\u043e \u0434\u0430 \u0441\u0435 \u0437\u0430\u043f\u0430\u0437\u0438 \u0437\u0430\u0432\u0438\u043d\u0430\u0433\u0438. +CLI.quiet-down.shortDescription=\ + \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u043d\u0430 Jenkins \u0437\u0430 \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435. \u0414\u0430 \u043d\u0435 \u0441\u0435 \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0442 \u043d\u043e\u0432\u0438 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f. +CLI.cancel-quiet-down.shortDescription=\ + \u041e\u0442\u043c\u044f\u043d\u0430 \u043d\u0430 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430\u0442\u0430 \u0437\u0430 \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u2014 \u0449\u0435 \u0441\u0435 \u0434\u043e\u043f\u0443\u0441\u043a\u0430\u0442 \u043d\u043e\u0432\u0438 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f. +CLI.reload-configuration.shortDescription=\ + \u0418\u0437\u0447\u0438\u0441\u0442\u0432\u0430\u043d\u0435 \u043d\u0430 \u043f\u0430\u043c\u0435\u0442\u0442\u0430 \u0438 \u043f\u0440\u0435\u0437\u0430\u0440\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0432\u0441\u0438\u0447\u043a\u043e \u043d\u0430\u043d\u043e\u0432\u043e \u043e\u0442 \u0444\u0430\u0439\u043b\u043e\u0432\u0430\u0442\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430.\ + \u0422\u043e\u0432\u0430 \u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u043f\u0440\u0438 \u043f\u0440\u043e\u043c\u044f\u043d\u0430 \u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u0442\u0435 \u0434\u0438\u0440\u0435\u043a\u0442\u043d\u043e \u043f\u043e \u0434\u0438\u0441\u043a\u0430. + +BuildAuthorizationToken.InvalidTokenProvided=\ + \u0417\u0430\u0434\u0430\u0434\u0435\u043d \u0435 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u0435\u043d \u0436\u0435\u0442\u043e\u043d \u0437\u0430 \u0441\u0438\u0433\u0443\u0440\u043d\u043e\u0441\u0442. + +Jenkins.CheckDisplayName.NameNotUniqueWarning=\ + \u0418\u043c\u0435\u0442\u043e \u201e{0}\u201c \u0441\u0435 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430 \u0438 \u0437\u0430 \u0437\u0430\u0434\u0430\u0447\u0430, \u043a\u043e\u0435\u0442\u043e \u043c\u043e\u0436\u0435 \u0434\u0430 \u0434\u043e\u0432\u0435\u0434\u0435 \u0434\u043e \u043e\u0431\u044a\u0440\u043a\u0432\u0430\u043d\u0435 \u043f\u0440\u0438\ + \u0442\u044a\u0440\u0441\u0435\u043d\u0435. +Jenkins.CheckDisplayName.DisplayNameNotUniqueWarning=\ + \u0418\u043c\u0435\u0442\u043e \u201e{0}\u201c \u0441\u0435 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430 \u0437\u0430 \u0434\u0440\u0443\u0433\u0430 \u0437\u0430\u0434\u0430\u0447\u0430, \u043a\u043e\u0435\u0442\u043e \u043c\u043e\u0436\u0435 \u0434\u0430 \u0434\u043e\u0432\u0435\u0434\u0435 \u0434\u043e \u0437\u0430\u0431\u0430\u0432\u044f\u043d\u0435 \u0438\ + \u043e\u0431\u044a\u0440\u043a\u0432\u0430\u043d\u0435 \u043f\u0440\u0438 \u0442\u044a\u0440\u0441\u0435\u043d\u0435. + +Jenkins.NotAllowedName=\ + \u041d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0442\u0435 \u0438\u043c\u0435\u0442\u043e \u201e{0}\u201c +Jenkins.IsRestarting=\ + Jenkins \u0441\u0435 \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430 \u0432 \u043c\u043e\u043c\u0435\u043d\u0442\u0430 + +User.IllegalUsername=\ + \u041d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0442\u0435 \u201e{0}\u201c \u0437\u0430 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u043e \u0438\u043c\u0435 \u0437\u0430\u0440\u0430\u0434\u0438 \u0441\u0438\u0433\u0443\u0440\u043d\u043e\u0441\u0442\u0442\u0430. +User.IllegalFullname=\ + \u041d\u0435 \u043c\u043e\u0436\u0435\u0442\u0435 \u0434\u0430 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0442\u0435 \u201e{0}\u201c \u0437\u0430 \u043f\u044a\u043b\u043d\u043e \u0438\u043c\u0435 \u0437\u0430\u0440\u0430\u0434\u0438 \u0441\u0438\u0433\u0443\u0440\u043d\u043e\u0441\u0442\u0442\u0430. diff --git a/core/src/main/resources/hudson/model/Messages_ca.properties b/core/src/main/resources/hudson/model/Messages_ca.properties index 0f88dbec7e946d33d0d0a7509a1a95738a14d19c..2237bbee1d9d5e28d6d40a073b68246a58fb9936 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 f17335347aff67bf5bd2371dd056fa0a712ea3f1..398a544ac9dd98663a442ebdfeaa229cc6333d45 100644 --- a/core/src/main/resources/hudson/model/Messages_da.properties +++ b/core/src/main/resources/hudson/model/Messages_da.properties @@ -82,7 +82,6 @@ UpdateCenter.PluginCategory.cli=Kommandolinieinterface UpdateCenter.PluginCategory.builder=Byggev\u00e6rkt\u00f8jer Slave.UnixSlave=Dette er en Unix slave FileParameterDefinition.DisplayName=Filparametre -CLI.delete-job.shortDescription=Sletter et job Run.Summary.Unstable=Ustabil CLI.reload-configuration.shortDescription=Genindl\u00e6s alle data fra filsystemet. \ Nyttigt hvis du har modificeret konfigurationsfiler direkte, udenom Jenkins. @@ -98,11 +97,11 @@ Slave.Remote.Director.Mandatory=Fjerndirektorie er obligatorisk BallColor.Disabled=Sl\u00e5et fra Run.InProgressDuration={0} og t\u00e6ller UpdateCenter.Status.UnknownHostException=Ukendt v\u00e6rt undtagelse -Hudson.NotUsesUTF8ToDecodeURL=\ -Din container bruger ikke UTF-8 til at afkode URLer. Hvis du bruger ikke-ASCII tegn i jobnavne etc, \ +Hudson.NotUsesUTF8ToDecodeURL=\ +Din container bruger ikke UTF-8 til at afkode URLer. Hvis du bruger ikke-ASCII tegn i jobnavne etc, \ vil dette skabe problemer. UpdateCenter.Status.CheckingInternet=Checker internet forbindelse -View.DeletePermission.Description=\ +View.DeletePermission.Description=\ Denne rettighed tillader brugerne at slette eksisterende visninger. UpdateCenter.Status.CheckingJavaNet=Checker jenkins-ci.org forbindelse UpdateCenter.PluginCategory.user=Authentificering og brugerh\u00e5ndtering @@ -128,7 +127,7 @@ UpdateCenter.PluginCategory.buildwrapper=Byggeomslag Hudson.ReadPermission.Description=\ L\u00e6serettigheden er n\u00f8dvendig for at se n\u00e6sten alle sider i Jenkins. \ Denne rettighed kan bruges n\u00e5r du ikke vil have uauthentificerede brugere til at \ -se Jenkins sider — tilbagekald denne rettighed fra den anonyme bruger, tilf\u00f8j \ +se Jenkins sider — tilbagekald denne rettighed fra den anonyme bruger, tilf\u00f8j \ derefter en "authentificeret" pseudo-bruger og giv denne l\u00e6serettigheder. Hudson.NodeBeingRemoved=Node bliver fjernet Hudson.ViewAlreadyExists=En visning ved navn "{0}" findes allerede @@ -144,7 +143,6 @@ UpdateCenter.PluginCategory.scm=Kildekodestyring (SCM) View.ConfigurePermission.Description=Denne rettighed tillader brugere at \u00e6ndre konfigurationen af visninger. AbstractProject.NewBuildForWorkspace=Skedulerer et nyt byg for at f\u00e5 et arbejdsomr\u00e5de Node.LabelMissing={0} har ikke etiket {1} -CLI.delete-node.shortDescription=Sletter en node Queue.BlockedBy=Blokeret af {0} Node.BecauseNodeIsReserved={0} er reserveret til jobs bundet(tied) til den Job.minutes=min @@ -155,15 +153,14 @@ AbstractBuild.KeptBecause=beholdt pga. {0} Hudson.NotADirectory={0} er ikke et direktorie Cause.RemoteCause.ShortDescription=Startet af fjernv\u00e6rt {0} Slave.WindowsSlave=Dette er en Windows slave -Run.ArtifactsPermission.Description=\ -Denne rettighed g\u00f8r det muligt at hente byggeartifakter. \ +Run.ArtifactsPermission.Description=\ +Denne rettighed g\u00f8r det muligt at hente byggeartifakter. \ Hvis du ikke vil have at en bruger skal kunne tilg\u00e5 byggeartifakter kan \ du fratage vedkommende denne rettighed. Computer.BadChannel=Slave node offline eller ikke en fjernkanal (f.eks. en masternode). 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 @@ -173,9 +170,9 @@ MyViewsProperty.DisplayName=Mine visninger UpdateCenter.PluginCategory.must-be-labeled=Ukatagoriserede AbstractProject.Disabled=Byg sl\u00e5et fra MyViewsProperty.ViewExistsCheck.AlreadyExists=En visning ved navn {0} eksisterer allerede -Hudson.AdministerPermission.Description=\ -Denne rettighed g\u00f8r det muligt at lave konfigurations\u00e6ndringer p\u00e5 tv\u00e6rs af hele systemet, \ -s\u00e5vel som at k\u00f8re yderst f\u00f8lsomme operationer der effektivt svarer til fuld lokal system adgang \ +Hudson.AdministerPermission.Description=\ +Denne rettighed g\u00f8r det muligt at lave konfigurations\u00e6ndringer p\u00e5 tv\u00e6rs af hele systemet, \ +s\u00e5vel som at k\u00f8re yderst f\u00f8lsomme operationer der effektivt svarer til fuld lokal system adgang \ (indenfor rettighedsrammerne af det underliggende operativsystem.) Hudson.NotJDKDir={0} ligner ikke et JDK direktorie AbstractProject.WorkspaceOffline=Arbejdsomr\u00e5det er offline. @@ -219,14 +216,12 @@ Queue.InProgress=Et byg er allerede i gang Computer.DeletePermission.Description=Denne rettighed tillader brugere at slette eksisterende slaver. UpdateCenter.Status.ConnectionFailed= UpdateCenter.PluginCategory.maven=Maven -CLI.online-node.shortDescription=Genoptag brugen af en byggenode, for at annullere en tidligere udstedt "offline-node" kommando. Computer.Permissions.Title=Slave BallColor.Success=Succes UpdateCenter.PluginCategory.upload=Artifaktsendere Permalink.LastUnstableBuild=Seneste ustabile byg CLI.enable-job.shortDescription=Sl\u00e5r et job til Run.Summary.Unknown=? -ParametersDefinitionProperty.DisplayName=Parametre AbstractProject.BuildPermission.Description=\ Denne rettighed giver mulighed for at starte et nyt byg. Job.NOfMFailed={0} af de seneste {1} byg fejlede. @@ -235,10 +230,9 @@ 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= MultiStageTimeSeries.EMPTY_STRING= -AbstractProject.BuildNow=Byg nu 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 90cc3429225b2c4edba4f905627469d7b57cb67e..5200d02ed06f78362f24a38be9987befe418ebd2 100644 --- a/core/src/main/resources/hudson/model/Messages_de.properties +++ b/core/src/main/resources/hudson/model/Messages_de.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Simon Wiest +# Copyright (c) 2004-2015, Sun Microsystems, Inc., Kohsuke Kawaguchi, Simon Wiest # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -31,13 +31,9 @@ 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. @@ -83,16 +79,12 @@ CLI.quiet-down.shortDescription=Jenkins' Aktivit\u00e4t reduzieren, z.B. zur Vor CLI.cancel-quiet-down.shortDescription=Wirkung des Befehls "quiet-down" wieder aufheben. CLI.reload-configuration.shortDescription=Alle Daten im Speicher verwerfen und Konfiguration neu von Festplatte laden. Dies ist n\u00fctzlich, wenn Sie \u00c4nderungen direkt im Dateisystem vorgenommen haben. CLI.clear-queue.shortDescription=Build-Warteschlange l\u00f6schen. -CLI.delete-job.shortDescription=Job l\u00f6schen. CLI.disable-job.shortDescription=Job deaktivieren. CLI.enable-job.shortDescription=Job aktivieren. CLI.connect-node.shortDescription=Erneut mit Knoten verbinden. CLI.disconnect-node.shortDescription=Knoten trennen. -CLI.delete-node.shortDescription=Knoten l\u00f6schen. CLI.offline-node.shortDescription=Knoten wird bis zum n\u00e4chsten "online-node"-Kommando f\u00fcr keine neuen Builds verwendet. -CLI.online-node.shortDescription=Knoten wird wieder f\u00fcr neue Builds verwendet. Hebt ein vorausgegangenes "offline-node"-Kommando auf. CLI.safe-restart.shortDescription=Startet Jenkins neu. -MyViewsProperty.GlobalAction.DisplayName=Meine Ansichten Queue.init=Build-Warteschlange neu initialisieren Computer.Caption=Slave {0} @@ -106,6 +98,7 @@ Computer.DisconnectPermission.Description=Dieses Recht erlaubt, bestehende Slave ComputerSet.NoSuchSlave=Slave ''{0}'' existiert nicht. ComputerSet.SlaveAlreadyExists=Ein Slave mit Namen ''{0}'' existiert bereits. ComputerSet.SpecifySlaveToCopy=Geben Sie an, welcher Slave kopiert werden soll +ComputerSet.DisplayName=Knoten Executor.NotAvailable=nicht verf\u00fcgbar @@ -281,7 +274,6 @@ Permalink.LastUnstableBuild=Letzter instabiler Build Permalink.LastUnsuccessfulBuild=Letzter erfolgloser Build ParameterAction.DisplayName=Parameter -ParametersDefinitionProperty.DisplayName=Parameter StringParameterDefinition.DisplayName=Text-Parameter TextParameterDefinition.DisplayName=Textbox-Parameter FileParameterDefinition.DisplayName=Datei-Parameter @@ -309,3 +301,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 0000000000000000000000000000000000000000..9e18978be2cb4e9857a91904fb68e493509324ea --- /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 02b9081a433a15de7a8d1162ecb95a433e64ada6..6d34cc004d8a602fcf46a04dd46bbf035b5dba0b 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 @@ -59,13 +57,10 @@ BallColor.Success=Correcto BallColor.Unstable=Inestable CLI.clear-queue.shortDescription=Limpiar la cola de trabajos -CLI.delete-job.shortDescription=Borrar una tarea CLI.disable-job.shortDescription=Desactivar una tarea CLI.enable-job.shortDescription=Activar una tarea -CLI.delete-node.shortDescription=Borrar un nodo CLI.disconnect-node.shortDescription=Desconectarse de un nodo CLI.connect-node.shortDescription=Reconectarse con un nodo -CLI.online-node.shortDescription=Continuar usando un nodo y candelar el comando "offline-node" mas reciente. CLI.offline-node.shortDescription=Dejar de utilizar un nodo temporalmente hasta que se ejecute el comando "online-node". Computer.Caption=Remoto {0} @@ -218,7 +213,6 @@ Permalink.LastSuccessfulBuild=\u00daltima ejecuci\u00f3n correcta Permalink.LastFailedBuild=\u00daltima ejecuci\u00f3n fallida ParameterAction.DisplayName=Par\u00e1metros -ParametersDefinitionProperty.DisplayName=Par\u00e1metros StringParameterDefinition.DisplayName=Par\u00e1metro de cadena FileParameterDefinition.DisplayName=Par\u00e1metro de fichero BooleanParameterDefinition.DisplayName=Valor booleano @@ -281,7 +275,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. Quizs se est refiriendo a {1}? ResultTrend.StillFailing=Todava falla @@ -316,3 +309,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 ejecucin debe parametrizarse diff --git a/core/src/main/resources/hudson/model/Messages_fi.properties b/core/src/main/resources/hudson/model/Messages_fi.properties index a5937f2baf73e1fd215188eaff1bb4fd10741675..b8537b44036f301d6087a600e14ceab5df103f43 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 82d0d98072736e273db4887efba567fb8b2f2172..8808e4727c147e4b7d03a442f5ee56ba794c4b6a 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 @@ -163,7 +161,6 @@ Permalink.LastSuccessfulBuild=Dernier build avec succ\u00e8s Permalink.LastFailedBuild=Dernier build en \u00e9chec ParameterAction.DisplayName=Param\u00e8tres -ParametersDefinitionProperty.DisplayName=Param\u00e8tres StringParameterDefinition.DisplayName=Param\u00e8tre String TextParameterDefinition.DisplayName=Param\u00e8tre texte FileParameterDefinition.DisplayName=Param\u00e8tre fichier @@ -193,5 +190,5 @@ 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 +ParametersDefinitionProperty.DisplayName=Ce build a des paramtres 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 0000000000000000000000000000000000000000..749fbe732d68257317835ddb25e4af01a620271c --- /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 cbad071927f6add017668d5edb34a95fc1d0bce1..949132eb7f5dadd39bd24b1054c24d5985d730d6 100644 --- a/core/src/main/resources/hudson/model/Messages_hu.properties +++ b/core/src/main/resources/hudson/model/Messages_hu.properties @@ -1,2 +1,2 @@ -AbstractProject.BuildNow=\u00C9p\u00EDt\u00E9s Most 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 e8b51dcaa4ec98123475babc1034887f5a34f71f..6b5ceb21165669099603bffdc655d962cc3743b6 100644 --- a/core/src/main/resources/hudson/model/Messages_it.properties +++ b/core/src/main/resources/hudson/model/Messages_it.properties @@ -33,12 +33,9 @@ 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. @@ -77,13 +74,10 @@ BallColor.Success=Successo BallColor.Unstable=Instabile CLI.clear-queue.shortDescription=Pulisce la coda di lavoro -CLI.delete-job.shortDescription=Cancella un job CLI.disable-job.shortDescription=Disabilita un job CLI.enable-job.shortDescription=Abilita un job -CLI.delete-node.shortDescription=Cancella un nodo CLI.disconnect-node.shortDescription=Disconnects from a node CLI.connect-node.shortDescription=Riconnettersi ad un nodo -CLI.online-node.shortDescription=Resume using a node for performing builds, to cancel out the earlier "offline-node" command. CLI.offline-node.shortDescription=Stop using a node for performing builds temporarily, until the next "online-node" command. CLI.wait-node-online.shortDescription=Attende che il nodo sia attivo CLI.wait-node-offline.shortDescription=Attende che un nodo sia disattivo @@ -272,7 +266,6 @@ Permalink.LastSuccessfulBuild=Last successful build Permalink.LastFailedBuild=Last failed build ParameterAction.DisplayName=Parameters -ParametersDefinitionProperty.DisplayName=Parameters StringParameterDefinition.DisplayName=String Parameter TextParameterDefinition.DisplayName=Text Parameter FileParameterDefinition.DisplayName=File Parameter @@ -315,3 +308,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 f47d7cb6859bf894c0ff368b92bc7a88d7431f11..a861286d6799f628597e55a1af2ecc0c50a24270 100644 --- a/core/src/main/resources/hudson/model/Messages_ja.properties +++ b/core/src/main/resources/hudson/model/Messages_ja.properties @@ -34,13 +34,9 @@ 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 @@ -272,10 +268,10 @@ 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 -ParametersDefinitionProperty.DisplayName=\u30d1\u30e9\u30e1\u30fc\u30bf StringParameterDefinition.DisplayName=\u6587\u5b57\u5217 TextParameterDefinition.DisplayName=\u30c6\u30ad\u30b9\u30c8 FileParameterDefinition.DisplayName=\u30d5\u30a1\u30a4\u30eb @@ -320,13 +316,10 @@ CLI.quiet-down.shortDescription=Jenkins\u306f\u518d\u8d77\u52d5\u306b\u5411\u305 CLI.cancel-quiet-down.shortDescription="quite-down"\u30b3\u30de\u30f3\u30c9\u306e\u51e6\u7406\u3092\u30ad\u30e3\u30f3\u30bb\u30eb\u3057\u307e\u3059\u3002 CLI.reload-configuration.shortDescription=\u30e1\u30e2\u30ea\u306b\u3042\u308b\u3059\u3079\u3066\u306e\u30c7\u30fc\u30bf\u3092\u7834\u68c4\u3057\u3066\u3001\u30d5\u30a1\u30a4\u30eb\u304b\u3089\u518d\u30ed\u30fc\u30c9\u3057\u307e\u3059\u3002\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u3092\u76f4\u63a5\u4fee\u6b63\u3057\u305f\u5834\u5408\u306b\u5f79\u306b\u7acb\u3061\u307e\u3059\u3002 CLI.clear-queue.shortDescription=\u30d3\u30eb\u30c9\u30ad\u30e5\u30fc\u3092\u30af\u30ea\u30a2\u3057\u307e\u3059\u3002 -CLI.delete-job.shortDescription=\u30b8\u30e7\u30d6\u3092\u524a\u9664\u3057\u307e\u3059\u3002 CLI.disable-job.shortDescription=\u30b8\u30e7\u30d6\u3092\u7121\u52b9\u5316\u3057\u307e\u3059\u3002 CLI.enable-job.shortDescription=\u30b8\u30e7\u30d6\u3092\u6709\u52b9\u5316\u3057\u307e\u3059\u3002 -CLI.delete-node.shortDescription=\u30ce\u30fc\u30c9\u3092\u524a\u9664\u3057\u307e\u3059\u3002 CLI.disconnect-node.shortDescription=\u30ce\u30fc\u30c9\u3068\u306e\u63a5\u7d9a\u3092\u5207\u65ad\u3057\u307e\u3059\u3002 CLI.connect-node.shortDescription=\u30ce\u30fc\u30c9\u3068\u518d\u63a5\u7d9a\u3057\u307e\u3059\u3002 -CLI.online-node.shortDescription=\u76f4\u524d\u306b\u5b9f\u884c\u3057\u305f"online-node"\u30b3\u30de\u30f3\u30c9\u3092\u53d6\u308a\u6d88\u3057\u3001\u30d3\u30eb\u30c9\u3092\u5b9f\u884c\u3059\u308b\u30ce\u30fc\u30c9\u306e\u4f7f\u7528\u3092\u518d\u958b\u3057\u307e\u3059\u3002 CLI.offline-node.shortDescription="online-node"\u30b3\u30de\u30f3\u30c9\u304c\u5b9f\u884c\u3055\u308c\u308b\u307e\u3067\u3001\u30d3\u30eb\u30c9\u3092\u5b9f\u884c\u3059\u308b\u30ce\u30fc\u30c9\u306e\u4f7f\u7528\u3092\u4e00\u6642\u7684\u306b\u505c\u6b62\u3057\u307e\u3059\u3002 CLI.wait-node-online.shortDescription=\u30ce\u30fc\u30c9\u304c\u30aa\u30f3\u30e9\u30a4\u30f3\u306b\u306a\u308b\u306e\u3092\u5f85\u3061\u307e\u3059\u3002 CLI.wait-node-offline.shortDescription=\u30ce\u30fc\u30c9\u304c\u30aa\u30d5\u30e9\u30a4\u30f3\u306b\u306a\u308b\u306e\u3092\u5f85\u3061\u307e\u3059\u3002 @@ -338,3 +331,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 a19ef38f9960cafa1f2054cfc4ac8dec681117b7..70020b26be130e6b02a27701a150adec4277d9be 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 0000000000000000000000000000000000000000..4dac83724aa1ecfbabc6c86ed6a896524317aa60 --- /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 02c96d98304627acf6b57ee6e4684d224370d4c1..fe7187183a53d6c908961e8946cb90b4da0003d6 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,2 @@ 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 f4a178a28db5a8cd7aafec2197b3e7bce2b8fa31..e7b5b57aa62939b06c2c9e2773ee241a201ce1ec 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 actiev {1} -AbstractProject.Disabled=Bouwen gedesactiveerd -AbstractProject.ETA= (einde voorzien op:{0}) +AbstractProject.Disabled=Bouwen gedeactiveerd 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. @@ -39,7 +37,7 @@ Api.MultipleMatch=XPath "{0}" komt overeen met {1} knopen. Cre\u00eber een XPath Api.NoXPathMatch=XPath {0} komt met geen enkele knoop overeen BallColor.Aborted=Afgebroken -BallColor.Disabled=Gedesactiveerd +BallColor.Disabled=Gedeactiveerd BallColor.Failed=Gefaald BallColor.InProgress=In verwerking BallColor.Pending=In afwachting @@ -102,5 +100,5 @@ 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 +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 0000000000000000000000000000000000000000..df63df844e2a1b25ac38b25770490ec9d3e72b61 --- /dev/null +++ b/core/src/main/resources/hudson/model/Messages_pl.properties @@ -0,0 +1,36 @@ +ParametersDefinitionProperty.DisplayName=To budowanie jest sparametryzowane +ManageJenkinsAction.DisplayName=Zarz\u0105dzaj Jenkinsem + +Job.AllRecentBuildFailed=Wszystkie ostatnie budowania nie powiod\u0142y si\u0119. +Job.BuildStability=Stabilno\u015B\u0107 budowa\u0144: {0} +Job.NOfMFailed={0} spo\u015Br\u00F3d {1} ostatnich budowa\u0144 nie powiod\u0142o si\u0119. +Job.NoRecentBuildFailed=Brak ostatnich budowa\u0144 zako\u0144czonych niepowodzeniem. +AbstractProject.Pronoun=Projekt + +BallColor.Aborted=Przerwane +BallColor.Disabled=Zablokowane +BallColor.Failed=Nie powiod\u0142o si\u0119 +BallColor.InProgress=W trakcie +BallColor.NotBuilt=Nie zbudowane +BallColor.Pending=W oczekiwaniu +BallColor.Success=Pomy\u015Blne +BallColor.Unstable=Niestabilne + +Permalink.LastBuild=Ostatnie budowanie +Permalink.LastStableBuild=Ostatnie stabilne budowanie +Permalink.LastUnstableBuild=Ostatnie niestabilne budowanie +Permalink.LastUnsuccessfulBuild=Ostatnie niepomy\u015Blne budowanie +Permalink.LastSuccessfulBuild=Ostatnie pomy\u015Blne budowanie +Permalink.LastFailedBuild=Ostatnie niepomy\u015Blne budowanie +Permalink.LastCompletedBuild=Ostatnie zako\u0144czone budowanie + +Run.Summary.Stable=stabilny +Run.Summary.Unstable=niestabilny +Run.Summary.Aborted=przerwany +Run.Summary.NotBuilt=brak budowa\u0144 +Run.Summary.BackToNormal=powr\u00F3t do stabilno\u015Bci +Run.Summary.BrokenForALongTime=nieudany od dawna +Run.Summary.BrokenSinceThisBuild=nieudany od tego budowania +Run.Summary.BrokenSince=nieudany od budowania {0} +Run.Summary.Unknown=? + 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 a095bef6dd06191b659d1feda72c404891d7dd02..4f2f98122bdd8643c10e66a941b9c84de04c351d 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 @@ -187,8 +185,6 @@ UpdateCenter.PluginCategory.builder=Ferramentas de build # File Parameter FileParameterDefinition.DisplayName=Par\u00e2metros de arquivo # {0} {0,choice,0#tests are|1#test is|1label: {2} -AbstractProject.LabelLink=Slaves em label: {2} # Artifacts of {0} {1} Run.ArtifactsBrowserTitle=Artefatos de {0} {1} # Build with Parameters -AbstractProject.build_with_parameters=Constru\u00eddo com par\u00e2metros # Still unstable ResultTrend.StillUnstable=Ainda inst\u00e1vel # Running as {0} @@ -524,3 +509,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 0000000000000000000000000000000000000000..106056997c74b267aad75bab53ddffa7a2df4f18 --- /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 c0be7aa273b0a8f8c13fea50fe32e8e25abd2d54..b966716ec0685421d4dc357233abac60b274876d 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 @@ -102,5 +100,5 @@ 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 +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 0000000000000000000000000000000000000000..d3cf7721e0e164ad7bf7a545fe62165e1a786cc2 --- /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_sl.properties b/core/src/main/resources/hudson/model/Messages_sl.properties index a9fc958501caf4cf0407d8d5a0757fc2fec9373b..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 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 7c0ec4d60adb1b6cd0dc1ea1aff1545791ae073e..278c4193047e0661c862dd0566551295de08085a 100644 --- a/core/src/main/resources/hudson/model/Messages_sv_SE.properties +++ b/core/src/main/resources/hudson/model/Messages_sv_SE.properties @@ -1,7 +1,7 @@ AbstractProject.Pronoun=Projekt -AbstractProject.BuildNow=Starta bygge nu 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 3ea32148cadfcfa2925ae4cd974445bc53238d39..2d3aaf217950d973a1087118b1f2a2577a46d507 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 @@ -103,5 +101,5 @@ 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 +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 0000000000000000000000000000000000000000..e48bfb0375776662270ad353f349706da23e0daf --- /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 68850858d4c57e50d28625d88b15d23f351eba6a..cb2ea0fdf6386cd86c10fa93074561973286d0a5 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. @@ -63,10 +61,8 @@ BallColor.Success=Success BallColor.Unstable=Unstable CLI.clear-queue.shortDescription=Clears the build queue -CLI.delete-job.shortDescription=Deletes a job CLI.disable-job.shortDescription=Disables a job CLI.enable-job.shortDescription=Enables a job -CLI.delete-node.shortDescription=Deletes a node CLI.disconnect-node.shortDescription=Disconnects from a node CLI.connect-node.shortDescription=Reconnect to a node CLI.online-node.shortDescription=Resume using a node for performing builds, to cancel out the earlier "offline-node" command. @@ -232,7 +228,6 @@ Permalink.LastSuccessfulBuild=Last successful build Permalink.LastFailedBuild=Last failed build ParameterAction.DisplayName=Parameters -ParametersDefinitionProperty.DisplayName=Parameters StringParameterDefinition.DisplayName=String Parameter FileParameterDefinition.DisplayName=File Parameter BooleanParameterDefinition.DisplayName=Boolean Value @@ -272,5 +267,5 @@ 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 +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 b6fd160a90b76490cf48314d44446af7124ecad6..87a733d27b8c419a3b06bf379689eea6b37e9f04 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,9 @@ 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 @@ -82,10 +79,8 @@ BallColor.Success=\u6210\u529f BallColor.Unstable=\u4e0d\u7a69\u5b9a CLI.clear-queue.shortDescription=\u6e05\u9664\u5efa\u7f6e\u4f47\u5217\u3002 -CLI.delete-job.shortDescription=\u522a\u9664\u4f5c\u696d\u3002 CLI.disable-job.shortDescription=\u505c\u7528\u4f5c\u696d\u3002 CLI.enable-job.shortDescription=\u555f\u7528\u4f5c\u696d\u3002 -CLI.delete-node.shortDescription=\u522a\u9664\u6307\u5b9a\u7bc0\u9ede\u3002 CLI.disconnect-node.shortDescription=\u4e2d\u65b7\u8207\u6307\u5b9a\u7bc0\u9ede\u7684\u9023\u7dda\u3002 CLI.connect-node.shortDescription=\u9023\u7dda\u5230\u6307\u5b9a\u7bc0\u9ede\u3002 CLI.online-node.shortDescription=\u7e7c\u7e8c\u4f7f\u7528\u6307\u5b9a\u7bc0\u9ede\u4f86\u5efa\u7f6e\uff0c\u53d6\u6d88\u5148\u524d\u7684 "offline-node" \u6307\u4ee4\u3002 @@ -281,7 +276,6 @@ Permalink.LastSuccessfulBuild=\u6700\u65b0\u6210\u529f\u5efa\u7f6e Permalink.LastFailedBuild=\u6700\u65b0\u5931\u6557\u5efa\u7f6e ParameterAction.DisplayName=\u53c3\u6578 -ParametersDefinitionProperty.DisplayName=\u53c3\u6578 StringParameterDefinition.DisplayName=\u5b57\u4e32\u53c3\u6578 TextParameterDefinition.DisplayName=\u6587\u5b57\u53c3\u6578 FileParameterDefinition.DisplayName=\u6a94\u6848\u53c3\u6578 @@ -330,3 +324,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/Node/help-numExecutors_fr.html b/core/src/main/resources/hudson/model/Node/help-numExecutors_fr.html index 2ff14c73c1b01984ffda6174f9f80ff9c87e5ac3..4f454f4841f3917e3a6b034c837e4f5cb7f57466 100644 --- a/core/src/main/resources/hudson/model/Node/help-numExecutors_fr.html +++ b/core/src/main/resources/hudson/model/Node/help-numExecutors_fr.html @@ -1,16 +1,16 @@
- Ceci contrle le nombre de builds simultans que Jenkins peut excuter. - Cette valeur impacte donc la charge gnrale du systme. + Ceci contrôle le nombre de builds simultanés que Jenkins peut exécuter. + Cette valeur impacte donc la charge générale du système. Une bonne valeur pour commencer serait le nombre de processeurs sur - votre systme. + votre systéme.

- Un nombre de builds simultans suprieur cette valeur augmentera la - dure individuelle de chaque build. Nanmoins, la capacit globale - peut tre suprieure, puisqu'un processeur peut se charger d'un build - pendant qu'un autre build est en attente sur les entres/sorties. + Un nombre de builds simultanés supérieur à cette valeur augmentera la + durée individuelle de chaque build. Néanmoins, la capacité globale + peut être supérieure, puisqu'un processeur peut se charger d'un build + pendant qu'un autre build est en attente sur les entrées/sorties.

- En mode matre/esclave, une valeur de 0 garantit que le matre ne fera - pas lui-mme de build. + En mode maître/esclave, une valeur de 0 garantit que le maître ne fera + pas lui-même de build.

diff --git a/core/src/main/resources/hudson/model/ParametersAction/index.jelly b/core/src/main/resources/hudson/model/ParametersAction/index.jelly index 2c25579adcd2ace3e9f8c02960e87f95ac57fa94..72ed664c447665a08eaea60229fc43f8c5ff69dd 100644 --- a/core/src/main/resources/hudson/model/ParametersAction/index.jelly +++ b/core/src/main/resources/hudson/model/ParametersAction/index.jelly @@ -35,12 +35,21 @@ THE SOFTWARE.

${%Build} ${build.displayName}

- - - - - +
+
+
${%Parameters}
+
+ + + + + + +
+
+
+
diff --git a/test/src/main/resources/org/jvnet/hudson/test/FailureBuilder/config.jelly b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details.jelly similarity index 83% rename from test/src/main/resources/org/jvnet/hudson/test/FailureBuilder/config.jelly rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details.jelly index 9d137d24a0b893d9610c894370a04e80f25eaed2..a2d545e0d3f0874c32f33f8e500d4edecfd8bf1c 100644 --- a/test/src/main/resources/org/jvnet/hudson/test/FailureBuilder/config.jelly +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details.jelly @@ -1,7 +1,7 @@ - \ 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 0000000000000000000000000000000000000000..3669d1453314241e726e96a15f5f4ea88e5b0a08 --- /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 f18767a9ff2521145a3c3cf0b7b40623373b18b3..3b313b6542412539fabd6bc0486ebe7cfe586f59 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 0000000000000000000000000000000000000000..315117f2c31c2abf02e15581fcc8617b063c5bd5 --- /dev/null +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_de.properties @@ -0,0 +1 @@ +Add\ Parameter=Parameter hinzufgen 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 29bf30e7594c0a25da45da0ef2a45bf299f4cdfc..dbfed3fa2544887e54505fecf30442e83f2ef935 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 ejecucin debe parametrizarse Add\ Parameter=Aadir un parmetro 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 6c9fe1823c0ea9509d174f71614c2327bb57b5b3..bab6b2cbeabdb71d2be6228a79abb2c1e706c5ea 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 paramtres Add\ Parameter=Ajouter un paramtre 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 0000000000000000000000000000000000000000..3ffb627eec0d0fb383684947dc25905e88ed7bdd --- /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 7eb7f4cee30b553b75d22221e648ea17aad70143..265e1c7a5cb0744c562212a23e59e9024842e764 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 df1251f2fd0713259d30df1a3c0f95ef92f6b9da..a362612239e9fc6da39e225cf2a75870a65b6edc 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 c466a762ce0908e64e4b1c534eb37c4a22e8df13..c4fabe7ca95ee646be1499fadbea9d7d70c44f9f 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 0000000000000000000000000000000000000000..6ebd2a13ecaa81ebe1be68754ef059a684b244a0 --- /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 4c66949799af17a1dc2bac0f338fbbaf624350a6..d1aace2dae62c9969a870e18d686bc30e2ffa854 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 7a09188ef889f25bf028f84af446b36ad468ca48..0e081ccb9fb5b8e2c0724e1459398a7726eb0c73 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 7b7fe50685655e2144d8016278afee46e00bef6f..dcdd5a5287d8b0179d9546c9be92963399ce81dd 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 3fccb98d7ae1053fe32cfb44ca31765aecf57ad0..e929a96a2ccaa7dac993a9c969d9dcc422d94d7b 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 602308ba2224dd17f4231f14ef66ecbcd12f65de..0f269cfdd6894eb3d4d48e9a1855644616f962a9 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 1f84c50491177cb89cf4465993fd21cc2797c430..bda5b182eb53f3df4045c723d79c8b1d55fe84d8 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 0000000000000000000000000000000000000000..af02f213e56ae8d96930b12c680ee2a21d8ffbca --- /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 bcc1f6c9c4f998b7a4febc6650393c037d1675a8..2dbb26fa0301e89a9c58ca410944aceb410b3723 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 d2cac0e4bbf5e1f1863cae84b7da1452f0203ee0..9c8d2bc11650417404a4e4744c1d79de5d734f70 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 269e5de81bbe610c7b59dab2a25c551a9c5672c4..3ce3029f744969f02a419e6044308f29825a13f5 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 0000000000000000000000000000000000000000..0c6b712511d6cacec9b6039c953373965886a0ff --- /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 b760379d98691b2ff8007b461d0795ff6b70b225..572578efad90ad55c3f899f7c4afaed0022fba93 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/test/src/main/resources/org/jvnet/hudson/test/ComputerConnectorTester/configure_zh_TW.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_zh_TW.properties similarity index 96% rename from test/src/main/resources/org/jvnet/hudson/test/ComputerConnectorTester/configure_zh_TW.properties rename to core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_zh_TW.properties index 16bed198fe4e0b226bb759221326742ca560e783..1ba5e442e094b6dbf4eda8b6a88c0ef98b5be8f1 100644 --- a/test/src/main/resources/org/jvnet/hudson/test/ComputerConnectorTester/configure_zh_TW.properties +++ b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config-details_zh_TW.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Save=\u5132\u5b58 +Add\ Parameter=\u65B0\u589E\u53C3\u6578 diff --git a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config.jelly b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config.jelly deleted file mode 100644 index b2a1f6ba1016621432632f0264d1f5e55f4a5325..0000000000000000000000000000000000000000 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config.jelly +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - \ No newline at end of file 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 b095c4e88032cdaa819b7a9594421360171311c3..0000000000000000000000000000000000000000 --- 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 hinzufgen 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 76261e71cdeee54d5bfc7947de95a60c00ee56b7..0000000000000000000000000000000000000000 --- 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 9417ad6eeff56b805a2ce93a8acdffb5feaa65f5..0000000000000000000000000000000000000000 --- 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 daaae005f86b6f519cf1d9e9aaf3d540c6a8128a..0000000000000000000000000000000000000000 --- 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 52c610189d77dd70fc7b325acc9d6a79485ddea9..0000000000000000000000000000000000000000 --- 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 a0875e36a55d944a3f1f38449747ef9cd1e7ec24..0000000000000000000000000000000000000000 --- 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/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_zh_TW.properties b/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_zh_TW.properties deleted file mode 100644 index 2e4dc6bccab125f1c36558c610e91718313135c7..0000000000000000000000000000000000000000 --- a/core/src/main/resources/hudson/model/ParametersDefinitionProperty/config_zh_TW.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2013, Chunghwa Telecom Co., Ltd., Pei-Tang Huang -# -# 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. - -This\ build\ is\ parameterized=\u53c3\u6578\u5316\u5efa\u7f6e -Add\ Parameter=\u65B0\u589E\u53C3\u6578 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 diff --git a/core/src/main/resources/hudson/model/Run/delete_pl.properties b/core/src/main/resources/hudson/model/Run/delete_pl.properties index 2a23b65679804a818e05aff1ced8570b0d3c673f..2591ced2881f652afe6fa7c701466d2aa77b34e8 100644 --- a/core/src/main/resources/hudson/model/Run/delete_pl.properties +++ b/core/src/main/resources/hudson/model/Run/delete_pl.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Delete\ this\ build=Usu\u0144 t\u0105 wersje +Delete\ this\ build=Usu\u0144 t\u0119 wersj\u0119 diff --git a/core/src/main/resources/hudson/model/Slave/help-remoteFS.html b/core/src/main/resources/hudson/model/Slave/help-remoteFS.html index f8c77ed7fc40462e847816ea0f6d78b5a7abf1f0..477c19c6a081db2b71fb6647b690ea500ca5488b 100644 --- a/core/src/main/resources/hudson/model/Slave/help-remoteFS.html +++ b/core/src/main/resources/hudson/model/Slave/help-remoteFS.html @@ -1,14 +1,36 @@

A slave needs to have a directory dedicated to Jenkins. Specify - the absolute path of this work directory on the slave, such as - '/var/jenkins' or 'c:\jenkins'. This should be a path local to the slave - machine. There's no need for this path to be visible from the master, - under normal circumstances. + the path of this work directory on the slave. It is best to use + an absolute path, such as '/var/jenkins' or 'c:\jenkins'. This + should be a path local to the slave machine. There's no need for + this path to be visible from the master, under normal circumstances.

Slaves do not maintain important data (other than active workspaces of projects last built on it), so you can possibly set the slave workspace to a temporary directory. The only downside of doing this is that you may lose the up-to-date workspace if the slave is turned off. + +

+ If you use a relative path, such as './jenkins-slave', the path will + be relative to the current working directory that the launcher provides. +

    +
  • For launchers where Jenkins controls starting the slave process, such + as SSH, the current working directory will typically be consistent, + e.g. the user's home directory. This means that Jenkins will be able to + rely on the caching of tool installations and workspaces from previous + builds. +
  • +
  • For launchers where Jenkins has no control over starting the slave + process, such as JNLP when launched from either the command line or via + a web browser link, the current working directory may change between + launches of the slave and use of a relative path may prove problematic. + The principal issue encountered when using relative paths with launchers + like JNLP is the proliferation of stale workspaces and tool installation + on the slave machine. This can cause disk space issues. + Note: there are some cloud providers that specifically use relative + paths with the JNLP launcher to allow for dynamically provisioned pools + of semi-heterogeneous slaves.
  • +
diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.jelly b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.jelly index 48e602863cf6c6435a0d0fdd9abeaf2f6fd52c93..cdb895fde6e12fb9572a3e334f3b7d48f0db7adc 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.jelly +++ b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.jelly @@ -39,6 +39,14 @@ THE SOFTWARE. + +
+ ${%UpgradeFailed(ucData.core.version,upJob.errorMessage,rootURL+'/updateCenter/')} + + + +
+
${%UpgradeProgress(ucData.core.version,rootURL+'/updateCenter/')} diff --git a/core/src/main/resources/hudson/model/UpdateCenter/PageDecoratorImpl/footer.jelly b/core/src/main/resources/hudson/model/UpdateCenter/PageDecoratorImpl/footer.jelly index 777f1192c77f7b3216ceb9c42a866c432ad58083..684bc26bb054257e39347db2cd2415503f5ce9ae 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/PageDecoratorImpl/footer.jelly +++ b/core/src/main/resources/hudson/model/UpdateCenter/PageDecoratorImpl/footer.jelly @@ -31,8 +31,8 @@ THE SOFTWARE. --> - - + + diff --git a/debian/build.sh b/core/src/main/resources/hudson/views/BuildButtonColumn/column.properties old mode 100755 new mode 100644 similarity index 85% rename from debian/build.sh rename to core/src/main/resources/hudson/views/BuildButtonColumn/column.properties index 97abf8321627451008086d6e76631206a3639d79..9557233e6b7bf393c9b2541b88d3fe9498ffd4d7 --- a/debian/build.sh +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column.properties @@ -1,7 +1,6 @@ -#!/bin/bash -ex # The MIT License # -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Jamie Whitehouse +# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, id:sorokh, Martin Eigenbrodt # # 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,13 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -if [ -z "$1" ]; then - echo "Usage: build.sh path/to/jenkins.war" - exit 1 -fi - -d=$(dirname $0) -cp "$1" $d/jenkins.war - -cd $d -exec debuild -us -uc -A +Build_scheduled=Build scheduled +Schedule_a_build=Schedule a build for {0} +Schedule_a_build_with_parameters=Schedule a build with parameters for {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_ar.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_ar.properties index 1453a1656cf9cce66e25825a5dd0ca76389a85b2..ecd7fa7c47f75c24b8d89ca78d3bab78da069994 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_ar.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_ar.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=\u0627\u0644\u0628\u0646\u0627\u0621 \u0645\u0642\u0631\u0631 -Schedule\ a\ build=\u062A\u062D\u062F\u064A\u062F \u0645\u0648\u0639\u062F \u0644\u0644\u0628\u0646\u0627\u0621 +Build_scheduled=\u0627\u0644\u0628\u0646\u0627\u0621 \u0645\u0642\u0631\u0631 +Schedule_a_build=\u062A\u062D\u062F\u064A\u062F \u0645\u0648\u0639\u062F \u0644\u0644\u0628\u0646\u0627\u0621\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_bg.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_bg.properties index 47b62710c7b2f7ee52547697d2abcfc8db6a0b40..400d3577717b2ee3bd4b528e8b5c82c35c465495 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_bg.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_bg.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=\u0411\u0438\u043B\u0434\u0430 \u0431\u0435\u0448\u0435 \u043D\u0430\u0441\u0440\u043E\u0447\u0435\u043D -Schedule\ a\ build=\u041D\u0430\u0441\u0440\u043E\u0447\u0438 \u0431\u0438\u043B\u0434 +Build_scheduled=\u0411\u0438\u043B\u0434\u0430 \u0431\u0435\u0448\u0435 \u043D\u0430\u0441\u0440\u043E\u0447\u0435\u043D +Schedule_a_build=\u041D\u0430\u0441\u0440\u043E\u0447\u0438 \u0431\u0438\u043B\u0434 \u0437\u0430 {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_ca.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_ca.properties index 9720f61697f02fd53081c7ec7c33606319d261e1..f951cfe05a0bde53c2af9fe4ef0e7418bd48c85a 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_ca.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_ca.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=S''ha planificat el muntatge -Schedule\ a\ build=Planifica un muntatge -Schedule\ a\ build\ with\ parameters=Planifica un muntatge amb par\u00E0metres +Build_scheduled=S''ha planificat el muntatge +Schedule_a_build=Planifica un muntatge per {0} +Schedule_a_build_with_parameters=Planifica un muntatge amb par\u00E0metres per {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_cs.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_cs.properties index bfbbf8962941bd1b58a048eb5dabb89b06e8ea6e..b4c7da1f5f1e9f4cb0fb47d7cf13430589434b3d 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_cs.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_cs.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Build napl\u00E1nov\u00E1n -Schedule\ a\ build=Napl\u00E1novat build +Build_scheduled=Build napl\u00E1nov\u00E1n +Schedule_a_build=Napl\u00E1novat build pro {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_da.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_da.properties index bf7e9a5c2a4eff66a2da0032b795d62892f5c3dc..35a096259a7abdd3063e7238a814c691694db21c 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_da.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_da.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Byg er planlagt -Schedule\ a\ build=Planl\u00E6g et byggeri +Build_scheduled=Byg er planlagt +Schedule_a_build=Planl\u00E6g et byggeri til {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_de.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_de.properties index 004c66fc7d56078611a71ce666b0e11d0b2e7085..a85db0e735d233ef0ad271e77bc90722897db994 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_de.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_de.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Build geplant -Schedule\ a\ build=Build planen -Schedule\ a\ build\ with\ parameters=Build mit Parametern planen +Build_scheduled=Build geplant +Schedule_a_build=Build planen f\u00FCr {0} +Schedule_a_build_with_parameters=Build mit Parametern planen f\u00FCr {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_el.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_el.properties index f8d9f96a10db38d4c60a737b3d8f808f1e04f372..c31c100730f6ccab5c9f377de4ddd732b719453c 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_el.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_el.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Schedule\ a\ build=\u0395\u03BA\u03C4\u03AD\u03BB\u03B5\u03C3\u03B7 \u0394\u03B9\u03B5\u03C1\u03B3\u03B1\u03C3\u03AF\u03B1\u03C2 +Schedule_a_build=\u0395\u03BA\u03C4\u03AD\u03BB\u03B5\u03C3\u03B7 \u0394\u03B9\u03B5\u03C1\u03B3\u03B1\u03C3\u03AF\u03B1\u03C2 \u03B3\u03B9\u03B1 {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_eo.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_eo.properties index 22823e099a7975f4d3c8bef990d29134cf1ba3c6..9a226e1ff5540441c1d35212a83892878de5aefe 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_eo.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_eo.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Schedule\ a\ build=Enhorarigi konstruon +Schedule_a_build=Enhorarigi konstruon por {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_es.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_es.properties index b78021b7ac1eae8a1178f21a2315c08c52057851..039c98f4bff8b94540955c2f2d34bde3a46eac52 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_es.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_es.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Ejecuci\u00F3n programada -Schedule\ a\ build=Programar una construcci\u00F3n -Schedule\ a\ build\ with\ parameters=Planificar una construcci\u00F3n con parametros +Build_scheduled=Ejecuci\u00F3n programada +Schedule_a_build=Programar una construcci\u00F3n de {0} +Schedule_a_build_with_parameters=Planificar una construcci\u00F3n con parametros de {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_es_AR.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_es_AR.properties index 134ec50ed38c768537752a60ecf1926a72979495..014de880f19c86952d61d7bd5a699030565fe02f 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_es_AR.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_es_AR.properties @@ -1,4 +1,4 @@ # This file is under the MIT License by authors -Build\ scheduled=Corrida en espera -Schedule\ a\ build=Activar una corrida +Build_scheduled=Corrida en espera +Schedule_a_build=Activar una corrida de {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_et.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_et.properties index 4141aa4e93e70ca488628ae2c58067de6b8248fb..689c082d1c0d860af040f9872eca80416c1fdc72 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_et.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_et.properties @@ -1,4 +1,4 @@ # This file is under the MIT License by authors -Build\ scheduled=Ehitus planeeritud -Schedule\ a\ build=Plaani uus t\u00F6\u00F6 +Build_scheduled=Ehitus planeeritud +Schedule_a_build=Plaani uus t\u00F6\u00F6\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_eu.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_eu.properties index 9b523420094ab2ce9f62ea9c5c47c740f7158b99..7d21004037a2faf671d7157d31f105738ee31088 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_eu.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_eu.properties @@ -1,4 +1,4 @@ # This file is under the MIT License by authors -Build\ scheduled=Exekuzioa planifikatu da -Schedule\ a\ build=Eraikuntza antolatu +Build_scheduled=Exekuzioa planifikatu da +Schedule_a_build=Eraikuntza antolatu\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_fi.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_fi.properties index 6855452b44f50c86bb130d751d699c4473338074..c29801ba3b57e7d0de90b0b34ef8c9f9c39972a9 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_fi.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_fi.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Ajastettu buildi -Schedule\ a\ build=Aloita k\u00E4\u00E4nn\u00F6s +Build_scheduled=Ajastettu buildi +Schedule_a_build=Aloita k\u00E4\u00E4nn\u00F6s\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_fr.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_fr.properties index 578991008bb7ee11bdc3c40d036837e042ca1288..3ae8f854b6bec9a03d4fcd77e273ff5cd8529451 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_fr.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_fr.properties @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Prochaines ex\u00E9cutions +Build_scheduled=Prochaines ex\u00E9cutions -Schedule\ a\ build=Programmer une construction -Schedule\ a\ build\ with\ parameters=Planifier une construction avec des param\u00E8tres +Schedule_a_build=Programmer une construction pour {0} +Schedule_a_build_with_parameters=Planifier une construction avec des param\u00E8tres pour {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_ga_IE.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_ga_IE.properties index 18961d1cd59e222307d53f71d856b3a5ba0bdfed..73e43fa66bc8d06d26a9d50ff73fe4c91daff831 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_ga_IE.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_ga_IE.properties @@ -1,3 +1,3 @@ # This file is under the MIT License by authors -Schedule\ a\ build=Sceideal t\u00F3g\u00E1il +Schedule_a_build=Sceideal t\u00F3g\u00E1il\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_he.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_he.properties index 376d7403840073af6de4f08ec62f4cf58e61f07e..16e0cef6b33089b3cdab0503a2fb989206ef79d5 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_he.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_he.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=\u05D1\u05E0\u05D9\u05D4 \u05DE\u05EA\u05D5\u05D6\u05DE\u05E0\u05EA -Schedule\ a\ build=\u05EA\u05D6\u05DE\u05DF \u05D1\u05E0\u05D9\u05D4 -Schedule\ a\ build\ with\ parameters=\u05EA\u05D6\u05DE\u05DF \u05D1\u05E0\u05D9\u05D4 \u05E2\u05DD \u05E4\u05E8\u05DE\u05D8\u05E8\u05D9\u05DD +Build_scheduled=\u05D1\u05E0\u05D9\u05D4 \u05DE\u05EA\u05D5\u05D6\u05DE\u05E0\u05EA +Schedule_a_build=\u05EA\u05D6\u05DE\u05DF \u05D1\u05E0\u05D9\u05D4\u003a {0} +Schedule_a_build_with_parameters=\u05EA\u05D6\u05DE\u05DF \u05D1\u05E0\u05D9\u05D4 \u05E2\u05DD \u05E4\u05E8\u05DE\u05D8\u05E8\u05D9\u05DD\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_hi_IN.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_hi_IN.properties index dbf7395bbe8bee535c0bb6b97560ca16144749a1..5e60575fecb889c000853db8cad6763e6d6fc2f7 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_hi_IN.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_hi_IN.properties @@ -1,3 +1,3 @@ # This file is under the MIT License by authors -Schedule\ a\ build=Build \u0915\u0940 \u0938\u092E\u092F \u0938\u093E\u0930\u0923\u0940 \u092C\u0928\u093E\u092F\u0947 +Schedule_a_build=Build \u0915\u0940 \u0938\u092E\u092F \u0938\u093E\u0930\u0923\u0940 \u092C\u0928\u093E\u092F\u0947\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_hu.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_hu.properties index ec02fb2e8db9a87e9510baee617167568f5d4c8a..612478b4f0457d9780f201ce3cf80c2132cc5b7b 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_hu.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_hu.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Build \u00FCtemezve -Schedule\ a\ build=Build \u00FCtemez\u00E9se +Build_scheduled=Build \u00FCtemezve +Schedule_a_build=Build \u00FCtemez\u00E9se\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_id.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_id.properties index 0d9f4ef82c0dccbbabf601dd977a00b12823577c..72dbfb41f9c33a557e3e6dcd45843c301a0a0c98 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_id.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_id.properties @@ -1,4 +1,4 @@ # This file is under the MIT License by authors -Build\ scheduled=Pekerjaan terjadwal -Schedule\ a\ build=Jadwalkan pekerjaan +Build_scheduled=Pekerjaan terjadwal +Schedule_a_build=Jadwalkan pekerjaan\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_is.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_is.properties index b8e8e21713f5faa7c3a87c7f681c2bd1f33769d0..d3d4d38df05dbf269549b2435eef9403e3e2ad0b 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_is.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_is.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Schedule\ a\ build=Setja keyrslu \u00ED r\u00F6\u00F0 +Schedule_a_build=Setja keyrslu \u00ED r\u00F6\u00F0 fyrir {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_it.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_it.properties index 0d6a1dbc4a8cc07b86f2f3541e260daace1ef12c..7f47abbc68a5209d242e840eda72742f3b12249c 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_it.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_it.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Build pianificata -Schedule\ a\ build=Pianifica una build -Schedule\ a\ build\ with\ parameters=Pianifica una build personalizzata +Build_scheduled=Build pianificata +Schedule_a_build=Pianifica una build per {0} +Schedule_a_build_with_parameters=Pianifica una build personalizzata per {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_ja.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_ja.properties index 8eb3c9e0a18b6e9e1e540fa6b5d6bca519f4d39a..ba9f00f5dd46933e15599faf675d6aa924d91c5b 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_ja.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_ja.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Schedule\ a\ build=\u30d3\u30eb\u30c9\u5b9f\u884c -Schedule\ a\ build\ with\ parameters=\u30d1\u30e9\u30e1\u30fc\u30bf\u4ed8\u304d\u30d3\u30eb\u30c9\u5b9f\u884c -Build\ scheduled=\u30d3\u30eb\u30c9\u306f\u30b9\u30b1\u30b8\u30e5\u30fc\u30eb\u3055\u308c\u307e\u3057\u305f\u3002 \ No newline at end of file +Schedule_a_build=\u30d3\u30eb\u30c9\u5b9f\u884c\u003a {0} +Schedule_a_build_with_parameters=\u30d1\u30e9\u30e1\u30fc\u30bf\u4ed8\u304d\u30d3\u30eb\u30c9\u5b9f\u884c\u003a {0} +Build_scheduled=\u30d3\u30eb\u30c9\u306f\u30b9\u30b1\u30b8\u30e5\u30fc\u30eb\u3055\u308c\u307e\u3057\u305f\u3002 diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_kn.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_kn.properties index bfa73ab9e7db7a02e487f5ea0c443574af81c724..3b703fea3d55c943beb6071f4ab1c196c438e344 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_kn.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_kn.properties @@ -1,4 +1,4 @@ # This file is under the MIT License by authors -Build\ scheduled=\u0CA8\u0CBF\u0C97\u0CA6\u0CBF\u0CA4 \u0CA8\u0CBF\u0CB0\u0CCD\u0CAE\u0CBE\u0CA3 -Schedule\ a\ build=\u0C92\u0C82\u0CA6\u0CC1 \u0CA8\u0CBF\u0CB0\u0CCD\u0CAE\u0CBE\u0CA3 \u0CB5\u0CC6\u0CD5\u0CB3\u0CBE\u0CAA\u0C9F\u0CCD\u0C9F\u0CBF +Build_scheduled=\u0CA8\u0CBF\u0C97\u0CA6\u0CBF\u0CA4 \u0CA8\u0CBF\u0CB0\u0CCD\u0CAE\u0CBE\u0CA3 \u003a {0} +Schedule_a_build=\u0C92\u0C82\u0CA6\u0CC1 \u0CA8\u0CBF\u0CB0\u0CCD\u0CAE\u0CBE\u0CA3 \u0CB5\u0CC6\u0CD5\u0CB3\u0CBE\u0CAA\u0C9F\u0CCD\u0C9F\u0CBF\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_ko.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_ko.properties index 46e31d22c53222441b1d182760b9f3f1729f23ca..d97a057e194cbde3fe9fff23cbac830a7c73185d 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_ko.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_ko.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=\uBE4C\uB4DC\uAC00 \uC608\uC57D\uB418\uC5C8\uC2B5\uB2C8\uB2E4. -Schedule\ a\ build=\uBE4C\uB4DC \uC989\uC2DC \uC2E4\uD589 +Build_scheduled=\uBE4C\uB4DC\uAC00 \uC608\uC57D\uB418\uC5C8\uC2B5\uB2C8\uB2E4. +Schedule_a_build=\uBE4C\uB4DC \uC989\uC2DC \uC2E4\uD589\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_lt.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_lt.properties index ad3501938eefafc74c3c03c36d8787f8dc488225..77fe4d6a89ec0d6921bd3210b54134cad397f67b 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_lt.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_lt.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Kompiliavimo tvarkara\u0161tis -Schedule\ a\ build=Planuoti u\u017Eduot\u012F +Build_scheduled=Kompiliavimo tvarkara\u0161tis +Schedule_a_build=Planuoti u\u017Eduot\u012F\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_lv.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_lv.properties index e6b5fd6797eb878e8bf695bc1e64042ce686d6a0..c539dc58807eca61a08d2feef3e296c319bf8c13 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_lv.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_lv.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=B\u016Bv\u0113jums iepl\u0101nots -Schedule\ a\ build=Iepl\u0101not b\u016Bv\u0113jumu -Schedule\ a\ build\ with\ parameters=Iepl\u0101not parametriz\u0113tu b\u016Bv\u0113jumu +Build_scheduled=B\u016Bv\u0113jums iepl\u0101nots +Schedule_a_build=Iepl\u0101not b\u016Bv\u0113jumu\u003a {0} +Schedule_a_build_with_parameters=Iepl\u0101not parametriz\u0113tu b\u016Bv\u0113jumu\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_mk.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_mk.properties index 443ad83ee15c403e43fca71ba26f8239b1723102..f57328abaf96403e97a717c358ff4f0d719084b3 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_mk.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_mk.properties @@ -1,3 +1,3 @@ # This file is under the MIT License by authors -Schedule\ a\ build=\u0417\u0430\u043A\u0430\u0436\u0438 build-\u0430\u045A\u0435 +Schedule_a_build=\u0417\u0430\u043A\u0430\u0436\u0438 build-\u0430\u045A\u0435\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_mr.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_mr.properties index bda448f08fa1163c61e3ddcf25ec02c0225105a4..b29f7be1cd83b342f0777de2064a45298c893668 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_mr.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_mr.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Schedule\ a\ build=\u092A\u0941\u0922\u0940\u0932 \u092C\u093E\u0902\u0927\u094D\u0915\u093E\u092E\u091A\u0940 \u0935\u0947\u0933 \u0920\u0930\u0935\u093E +Schedule_a_build=\u092A\u0941\u0922\u0940\u0932 \u092C\u093E\u0902\u0927\u094D\u0915\u093E\u092E\u091A\u0940 \u0935\u0947\u0933 \u0920\u0930\u0935\u093E\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_nb_NO.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_nb_NO.properties index d47451fa99bc35b944a39aec8197811f87459c3b..d066866c0d63a2f378ffa1f116cc67479e2f40cc 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_nb_NO.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_nb_NO.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Bygg planlagt -Schedule\ a\ build=Planlegg et bygg +Build_scheduled=Bygg planlagt +Schedule_a_build=Planlegg et bygg for {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_nl.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_nl.properties index 995b60a3561410c0c4bdac9db79733e6619ef293..3dfee37435428be952afc305ed6468ab5d2df332 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_nl.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_nl.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Build geplanned -Schedule\ a\ build=Plan een project -Schedule\ a\ build\ with\ parameters=Plan een build met parameters +Build_scheduled=Build geplanned +Schedule_a_build=Plan een project voor {0} +Schedule_a_build_with_parameters=Plan een build met parameters voor {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_pl.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_pl.properties index a7238a8669ad4a2ce18544f1235641df33c2719b..e462d92c6208773205588489ed17a81e56832514 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_pl.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_pl.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Zaplanowany build -Schedule\ a\ build=Dodaj kompilacj\u0119 do kolejki -Schedule\ a\ build\ with\ parameters=Zbuduj z parametrami +Build_scheduled=Budowanie zosta\u0142o zaplanowane +Schedule_a_build=Dodaj budowanie do kolejki dla {0} +Schedule_a_build_with_parameters=Zbuduj z parametrami dla {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_pt_BR.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_pt_BR.properties index 378d2544ae30439fea65cee340acea0fe74b5487..04959a2886aeaf07f7b4b90b51e70cba8a457400 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_pt_BR.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_pt_BR.properties @@ -22,6 +22,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Builds agendados -Schedule\ a\ build=Agendar um build -Schedule\ a\ build\ with\ parameters=Agendar compila\u00e7\u00e3o com par\u00e2metros +Build_scheduled=Builds agendados +Schedule_a_build=Agendar um build\u003a {0} +Schedule_a_build_with_parameters=Agendar compila\u00e7\u00e3o com par\u00e2metros\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_pt_PT.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_pt_PT.properties index acaa0d75b5e7d65a960eabf293e9ab5562bb99f5..e23e3567c34574bbd4db8adc91cbaf7e4b45998f 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_pt_PT.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_pt_PT.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Compila\u00E7\u00E3o agendada -Schedule\ a\ build=Agendar uma compila\u00E7\u00E3o -Schedule\ a\ build\ with\ parameters=Agendar compila\u00E7\u00E3o com par\u00E2metros +Build_scheduled=Compila\u00E7\u00E3o agendada +Schedule_a_build=Agendar uma compila\u00E7\u00E3o\u003a {0} +Schedule_a_build_with_parameters=Agendar compila\u00E7\u00E3o com par\u00E2metros\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_ro.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_ro.properties index 3b354623e610058988754aeeac5c878320ba4284..b461a98be284a04e8b94e70b8596dc7de70168c8 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_ro.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_ro.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Build programat -Schedule\ a\ build=Programeaz\u0103 un build +Build_scheduled=Build programat +Schedule_a_build=Programeaz\u0103 un build pentru {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_ru.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_ru.properties index 8af8df211cf960c91a5f4980ac8e68e1ecc746c2..ff02568785e49052df923b06ff80ba034cf82332 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_ru.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_ru.properties @@ -20,8 +20,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=\u0421\u0431\u043e\u0440\u043a\u0430 \u0437\u0430\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0430 +Build_scheduled=\u0421\u0431\u043e\u0440\u043a\u0430 \u0437\u0430\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0430 !!! NB Change my previsous translation of this field to this value!!! -Schedule\ a\ build=\u0417\u0430\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0431\u043e\u0440\u043a\u0443 -Schedule\ a\ build\ with\ parameters=\u0417\u0430\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0431\u043e\u0440\u043a\u0443 \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 +Schedule_a_build=\u0417\u0430\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0431\u043e\u0440\u043a\u0443\u003a {0} +Schedule_a_build_with_parameters=\u0417\u0430\u043f\u043b\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0431\u043e\u0440\u043a\u0443 \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_sk.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_sk.properties index 1a9f7aca6521bd0c1d818a2bc8a5b32f45a4fbec..6dde922e369186590ddd1575badb80a1edd28f0d 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_sk.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_sk.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Napl\u00E1novan\u00E9 zostavenia -Schedule\ a\ build=Napl\u00E1nuj zostavenie -Schedule\ a\ build\ with\ parameters=Napl\u00E1nuj zostavenie s parametrami +Build_scheduled=Napl\u00E1novan\u00E9 zostavenia +Schedule_a_build=Napl\u00E1nuj zostavenie pre {0} +Schedule_a_build_with_parameters=Napl\u00E1nuj zostavenie s parametrami pre {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_sl.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_sl.properties index 708ade0e43cc8ed1e25a47054cc46e6587595817..1038c11c9147ff65085a5ef3b8fcb1dfa4080c7a 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_sl.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_sl.properties @@ -1,3 +1,3 @@ # This file is under the MIT License by authors -Schedule\ a\ build=Na\u010Drtuj build +Schedule_a_build=Na\u010Drtuj build\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_sr.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_sr.properties index 74507a6d5fb15fab99106ca8b574064a0bc1cdad..98c763b42ce4280a77c7f6bec05e9523f67bb62a 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_sr.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_sr.properties @@ -1,4 +1,4 @@ # This file is under the MIT License by authors -Build\ scheduled=Plan pokretanja -Schedule\ a\ build=Zaka\u017Ei gradnju +Build_scheduled=Plan pokretanja +Schedule_a_build=Zaka\u017Ei gradnju \u0437\u0430 {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_sv_SE.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_sv_SE.properties index 636fd065f24f0a3311789b8762c73eb34aab3ea7..1b20eb77db88c6a6b75b0c842c81f974fe589fc8 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_sv_SE.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_sv_SE.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Bygge schemalagt -Schedule\ a\ build=Schemal\u00E4gg ett bygge -Schedule\ a\ build\ with\ parameters=Schemal\u00E4gg ett bygge med parametrar. +Build_scheduled=Bygge schemalagt +Schedule_a_build=Schemal\u00E4gg ett bygge f\u00FCr {0} +Schedule_a_build_with_parameters=Schemal\u00E4gg ett bygge med parametrar f\u00FCr {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_te.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_te.properties index 98239657966224ba12d6b38d5fee6b9ed56279be..f8a5ebae595475d21e8e3821c4867c4e71040a76 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_te.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_te.properties @@ -1,4 +1,4 @@ # This file is under the MIT License by authors -Build\ scheduled=Build varusa kramamu lo unchabadinadi -Schedule\ a\ build=Build ni varusa kramamu lo pettumu +Build_scheduled=Build varusa kramamu lo unchabadinadi +Schedule_a_build=Build ni varusa kramamu lo pettumu\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_tr.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_tr.properties index 591f06da278480a56fc56487c2ac87579febabc2..bbfd79a2061fce1c60cc74a605778de8606565c2 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_tr.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_tr.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=Yap\u0131land\u0131rma planland\u0131 -Schedule\ a\ build=Bir\ yap\u0131land\u0131rma\ planla -Schedule\ a\ build\ with\ parameters=Parametreli yap\u0131land\u0131rma planla +Build_scheduled=Yap\u0131land\u0131rma planland\u0131 +Schedule_a_build=Bir\ yap\u0131land\u0131rma\ planla\u003a {0} +Schedule_a_build_with_parameters=Parametreli yap\u0131land\u0131rma planla\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_uk.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_uk.properties index 2b563879c56fd0b9568f9a9890c6fd2f5ba187fa..506c29ee130434f7acae8cf752e4b59fd68f7572 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_uk.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_uk.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=\u0417\u0431\u0456\u0440\u043A\u0438 \u0437\u0430\u043F\u043B\u0430\u043D\u043E\u0432\u0430\u043D\u0430 -Schedule\ a\ build=\u0417\u0430\u043F\u043B\u0430\u043D\u0443\u0432\u0430\u0442\u0438 \u043F\u043E\u0431\u0443\u0434\u043E\u0432\u0443 +Build_scheduled=\u0417\u0431\u0456\u0440\u043A\u0438 \u0437\u0430\u043F\u043B\u0430\u043D\u043E\u0432\u0430\u043D\u0430 +Schedule_a_build=\u0417\u0430\u043F\u043B\u0430\u043D\u0443\u0432\u0430\u0442\u0438 \u043F\u043E\u0431\u0443\u0434\u043E\u0432\u0443\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_zh_CN.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_zh_CN.properties index 307d778972da10242c7c4798d1e1606436490e55..c5222b638b6e2fff56fbeed2447e7bfa010ff4c8 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_zh_CN.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_zh_CN.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Build\ scheduled=\u6784\u5EFA\u8BA1\u5212 -Schedule\ a\ build=\u8ba1\u5212\u4e00\u6b21\u6784\u5efa -Schedule\ a\ build\ with\ parameters=\u8BA1\u5212\u4E00\u6B21\u5E26\u53C2\u6570\u7684\u6784\u5EFA +Build_scheduled=\u6784\u5EFA\u8BA1\u5212 +Schedule_a_build=\u8ba1\u5212\u4e00\u6b21\u6784\u5efa\u003a {0} +Schedule_a_build_with_parameters=\u8BA1\u5212\u4E00\u6B21\u5E26\u53C2\u6570\u7684\u6784\u5EFA\u003a {0} diff --git a/core/src/main/resources/hudson/views/BuildButtonColumn/column_zh_TW.properties b/core/src/main/resources/hudson/views/BuildButtonColumn/column_zh_TW.properties index 077a59224b015b77cbf85956ff87beaa054ea2f2..fc76ede1fd470e2f550680499b5d1b8786293850 100644 --- a/core/src/main/resources/hudson/views/BuildButtonColumn/column_zh_TW.properties +++ b/core/src/main/resources/hudson/views/BuildButtonColumn/column_zh_TW.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Schedule\ a\ build=\u6392\u7a0b\u5efa\u7f6e\u4f5c\u696d -Build\ scheduled=\u5efa\u7f6e\u5df2\u52a0\u9032\u6392\u7a0b -Schedule\ a\ build\ with\ parameters=\u53C3\u6578\u5316\u5EFA\u7F6E +Schedule_a_build=\u6392\u7a0b\u5efa\u7f6e\u4f5c\u696d +Build_scheduled=\u5efa\u7f6e\u5df2\u52a0\u9032\u6392\u7a0b\u003a {0} +Schedule_a_build_with_parameters=\u53C3\u6578\u5316\u5EFA\u7F6E\u003a {0} diff --git a/core/src/main/resources/hudson/views/JobColumn/column.jelly b/core/src/main/resources/hudson/views/JobColumn/column.jelly index 56dbbb86220756f3dd57d100e56b215c298458f8..ecb560cfce9214e56da97aafa6ffec16d9fe9e2f 100644 --- a/core/src/main/resources/hudson/views/JobColumn/column.jelly +++ b/core/src/main/resources/hudson/views/JobColumn/column.jelly @@ -25,6 +25,7 @@ THE SOFTWARE. + diff --git a/core/src/main/resources/hudson/views/LastDurationColumn/columnHeader_pl.properties b/core/src/main/resources/hudson/views/LastDurationColumn/columnHeader_pl.properties index a7ea02acbfffaf3ef403e72f865367f87dfd7b99..772faa8053d15631a2b02fae7bfae90766908531 100644 --- a/core/src/main/resources/hudson/views/LastDurationColumn/columnHeader_pl.properties +++ b/core/src/main/resources/hudson/views/LastDurationColumn/columnHeader_pl.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Last\ Duration=Ostatni Czas Trwania +Last\ Duration=Czas ostatniego budowania diff --git a/core/src/main/resources/hudson/views/LastFailureColumn/columnHeader_pl.properties b/core/src/main/resources/hudson/views/LastFailureColumn/columnHeader_pl.properties index 4cd147a02b6cf6ab0ed297c86bcae4b59a3a0f7a..37b1ca45e7681a1e163d65e01b5361205ae7ff48 100644 --- a/core/src/main/resources/hudson/views/LastFailureColumn/columnHeader_pl.properties +++ b/core/src/main/resources/hudson/views/LastFailureColumn/columnHeader_pl.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Last\ Failure=Ostatni B\u0142\u0105d +Last\ Failure=Ostatni b\u0142\u0105d diff --git a/core/src/main/resources/hudson/views/LastSuccessColumn/columnHeader_pl.properties b/core/src/main/resources/hudson/views/LastSuccessColumn/columnHeader_pl.properties index c09e14ce7cda04cb21a2bbaed23616057af63b5b..d188be71e23297a0a682dff79ab55de84c5156e4 100644 --- a/core/src/main/resources/hudson/views/LastSuccessColumn/columnHeader_pl.properties +++ b/core/src/main/resources/hudson/views/LastSuccessColumn/columnHeader_pl.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Last\ Success=Ostatni Sukces +Last\ Success=Ostatni sukces diff --git a/core/src/main/resources/hudson/views/Messages_bg.properties b/core/src/main/resources/hudson/views/Messages_bg.properties new file mode 100644 index 0000000000000000000000000000000000000000..517870597a0dce58459be144d546c1d9210b0442 --- /dev/null +++ b/core/src/main/resources/hudson/views/Messages_bg.properties @@ -0,0 +1,42 @@ +# The MIT License +# +# Bulgarian translation copyright 2015 Alexander Shopov . +# +# 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. + +BuildButtonColumn.DisplayName=\ + \u0418\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +JobColumn.DisplayName=\ + \u0418\u043c\u0435 +LastDurationColumn.DisplayName=\ + \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u043e \u0432\u0440\u0435\u043c\u0435\u0442\u0440\u0430\u0435\u043d\u0435 +LastFailureColumn.DisplayName=\ + \u041f\u043e\u0441\u043b\u0435\u0434\u0435\u043d \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +LastStableColumn.DisplayName=\ + \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0430 \u0441\u0442\u0430\u0431\u0438\u043b\u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u044f +LastSuccessColumn.DisplayName=\ + \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u043e \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 +StatusColumn.DisplayName=\ + \u0421\u044a\u0441\u0442\u043e\u044f\u043d\u0438\u0435 +WeatherColumn.DisplayName=\ + \u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430 \u043d\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f\u0442\u0430 +DefaultViewsTabsBar.DisplayName=\ + \u041b\u0435\u043d\u0442\u0430 \u0437\u0430 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438\u0442\u0435 \u0438\u0437\u0433\u043b\u0435\u0434\u0438 +DefaultMyViewsTabsBar.DisplayName=\ + \u041b\u0435\u043d\u0442\u0430 \u0437\u0430 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438\u0442\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u0441\u043a\u0438 \u0438\u0437\u0433\u043b\u0435\u0434\u0438 diff --git a/core/src/main/resources/hudson/views/Messages_pl.properties b/core/src/main/resources/hudson/views/Messages_pl.properties new file mode 100644 index 0000000000000000000000000000000000000000..088bf10ca230014164cfc1d1eb346b085b8de59b --- /dev/null +++ b/core/src/main/resources/hudson/views/Messages_pl.properties @@ -0,0 +1,23 @@ +# The MIT License +# +# Copyright (c) 2016, Damian Szczepanik +# +# 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. + +JobColumn.DisplayName=Nazwa diff --git a/core/src/main/resources/hudson/views/StatusColumn/columnHeader_pl.properties b/core/src/main/resources/hudson/views/StatusColumn/columnHeader_pl.properties index ba4a18392195d71c1592aff0d729d721ecb90efc..5e9c9c7f7bc159d9e998017227ac3c8f2376542d 100644 --- a/core/src/main/resources/hudson/views/StatusColumn/columnHeader_pl.properties +++ b/core/src/main/resources/hudson/views/StatusColumn/columnHeader_pl.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Status\ of\ the\ last\ build=Status ostatniej kompilacji +Status\ of\ the\ last\ build=Status ostatniego budowania diff --git a/core/src/main/resources/hudson/views/WeatherColumn/columnHeader_pl.properties b/core/src/main/resources/hudson/views/WeatherColumn/columnHeader_pl.properties index f518d43c5a30ff1dfb8aebfe3916a6bb7ff8311e..50c75740e6f938ea551b823a842ee5634f7686e9 100644 --- a/core/src/main/resources/hudson/views/WeatherColumn/columnHeader_pl.properties +++ b/core/src/main/resources/hudson/views/WeatherColumn/columnHeader_pl.properties @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Weather\ report\ showing\ aggregated\ status\ of\ recent\ builds=Raport z ostatnich wykona\u0144 +Weather\ report\ showing\ aggregated\ status\ of\ recent\ builds=Raport z ostatnich budowa\u0144 diff --git a/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly b/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries.jelly index 639002d53743ce96b2b80efb63c2a83df8eb18ba..54309319f0a3533df9717e4d36a4cd8e44a57e8f 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. --> - - - - - - - - -
-
- -
- -
- #${queuedItems.size()==1 ? it.owner.nextBuildNumber - : it.owner.nextBuildNumber+queuedItems.size()-i-1} -
-
-
- - - - (${%pending}—) - - - (${%pending}) - - - -
- -
-
-
-
-
- - - -
-
-
- - -
-
- - + + diff --git a/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries_ja.properties b/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries_ja.properties index 570d6e0bab8e188833a96fbba6c9272ec40dc85f..9241f393f7f2b62257c03ae9c37e23a635ceb224 100644 --- a/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries_ja.properties +++ b/core/src/main/resources/hudson/widgets/BuildHistoryWidget/entries_ja.properties @@ -20,6 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -pending=\u4FDD\u7559 -cancel\ this\ build=\u3053\u306E\u30D3\u30EB\u30C9\u3092\u4E2D\u6B62 +pending=\u4fdd\u7559 +cancel\ this\ build=\u3053\u306e\u30d3\u30eb\u30c9\u3092\u4e2d\u6b62 +Expected\ build\ number=\u6b21\u30d3\u30eb\u30c9No diff --git a/core/src/main/resources/hudson/widgets/HistoryWidget/ajaxBuildHistory.jelly b/core/src/main/resources/hudson/widgets/HistoryWidget/ajaxBuildHistory.jelly index 1011d9510eb2df5d3f58a5af9cce7bdec13c1d29..4d01266f09a95774f36cc3b215f4c989b08ccd1e 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 2a49d5a6981c971ed4f312d492dd6668c7df5713..8c07368d68f839346b02583f5aed2daa88097b86 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 44e3f664e383bbd25f77308ed718ecf1d0c96866..215cb4d54a339fe7c29e4369de4f90896450c7ef 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 f43ba940688401f2bda57cb516e1c844a4497ba6..fbb461b9ce3d87db46d140a2f3ac62271b7cb801 100644 --- a/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly +++ b/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly @@ -51,10 +51,30 @@ THE SOFTWARE. - + +
+
+ + + +
+ - - + + + + + + +
+ x + +
+ + + + + - ${%More ...} -
+
diff --git a/core/src/main/resources/hudson/widgets/Messages_bg.properties b/core/src/main/resources/hudson/widgets/Messages_bg.properties new file mode 100644 index 0000000000000000000000000000000000000000..861f6002f359a8b9f1cf55048558dc8a0bdb5df5 --- /dev/null +++ b/core/src/main/resources/hudson/widgets/Messages_bg.properties @@ -0,0 +1,24 @@ +# The MIT License +# +# Bulgarian translation copyright 2015 Alexander Shopov . +# +# 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. + +BuildHistoryWidget.DisplayName=\ + \u0418\u0441\u0442\u043e\u0440\u0438\u044f \u043d\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f\u0442\u0430 diff --git a/core/src/main/resources/hudson/widgets/Messages_pl.properties b/core/src/main/resources/hudson/widgets/Messages_pl.properties new file mode 100644 index 0000000000000000000000000000000000000000..0bf1fc9fa93fed78443c9ddc296eb6dfb8bc19d9 --- /dev/null +++ b/core/src/main/resources/hudson/widgets/Messages_pl.properties @@ -0,0 +1,23 @@ +# The MIT License +# +# Copyright (c) 2016, Damian Szczepanik +# +# 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. + +BuildHistoryWidget.DisplayName=Historia zada\u0144 diff --git a/core/src/main/resources/hudson/win32errors_ja.properties b/core/src/main/resources/hudson/win32errors_ja.properties index e5332c59037a73a4c1f91133ab4a23026a176c67..3fec9b845efb3fc010a50cc69078de94d0489d3e 100644 --- a/core/src/main/resources/hudson/win32errors_ja.properties +++ b/core/src/main/resources/hudson/win32errors_ja.properties @@ -574,8 +574,6 @@ error273= \ \u672A\u77E5\u306E\u30A8\u30E9\u30FC (0x111) error274= \ \u672A\u77E5\u306E\u30A8\u30E9\u30FC (0x112) -error267= \ -\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u540D\u304C\u7121\u52B9\u3067\u3059\u3002 error275= \ \u62E1\u5F35\u5C5E\u6027\u304C\u30D0\u30C3\u30D5\u30A1\u306B\u304A\u3055\u307E\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002 error276= \ diff --git a/core/src/main/resources/jenkins/diagnosis/HsErrPidList/index_ja.properties b/core/src/main/resources/jenkins/diagnosis/HsErrPidList/index_ja.properties new file mode 100644 index 0000000000000000000000000000000000000000..87ab4dcf68d75edbd5c8e10bda7246a588754f53 --- /dev/null +++ b/core/src/main/resources/jenkins/diagnosis/HsErrPidList/index_ja.properties @@ -0,0 +1,31 @@ +# The MIT License +# +# Copyright (c) 2004-2015, Seiji Sogabe +# +# 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. + +Java\ VM\ Crash\ Reports=JVM\u30af\u30e9\u30c3\u30b7\u30e5\u30ec\u30dd\u30fc\u30c8 +Name=\u540d\u524d +Date=\u5e74\u6708\u65e5 +Delete=\u524a\u9664 +blurb=Jenkins\u306eJVM\u30af\u30e9\u30c3\u30b7\u30e5\u30ec\u30dd\u30fc\u30c8\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f\u3002\ + Jenkins\u306e\u554f\u984c\u3067\u3042\u308c\u3070\u3001\u5831\u544a\u3057\u3066\u304f\u3060\u3055\u3044\u3002 \ + Jenkins relies on some heuristics to find these files. \u3088\u308a\u6b63\u78ba\u306b\u898b\u3064\u3051\u308b\u306b\u306f\u3001\ + JVM\u30aa\u30d7\u30b7\u30e7\u30f3\u306b-XX:ErrorFile=/path/to/hs_err_pid%p.log\u3092\u8ffd\u52a0\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +ago={0} \u524d \ No newline at end of file diff --git a/core/src/main/resources/jenkins/diagnosis/HsErrPidList/message_ja.properties b/core/src/main/resources/jenkins/diagnosis/HsErrPidList/message_ja.properties new file mode 100644 index 0000000000000000000000000000000000000000..ab0409a9a4d2ce9e895ae388fea868b404ff65be --- /dev/null +++ b/core/src/main/resources/jenkins/diagnosis/HsErrPidList/message_ja.properties @@ -0,0 +1,23 @@ +# The MIT License +# +# Copyright (c) 2004-2015, Seiji Sogabe +# +# 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. + +blurb=\u3053\u306eJenkins\u306f\u30af\u30e9\u30c3\u30b7\u30e5\u3057\u305f\u3088\u3046\u3067\u3059\u3002\u30ed\u30b0\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002 \ No newline at end of file diff --git a/core/src/main/resources/jenkins/diagnostics/PinningIsBlockingBundledPluginMonitor/message_ja.properties b/core/src/main/resources/jenkins/diagnostics/PinningIsBlockingBundledPluginMonitor/message_ja.properties new file mode 100644 index 0000000000000000000000000000000000000000..b0eb2a9b606174b1117c21dfbf600f4fa8aa8d50 --- /dev/null +++ b/core/src/main/resources/jenkins/diagnostics/PinningIsBlockingBundledPluginMonitor/message_ja.properties @@ -0,0 +1,32 @@ +# The MIT License +# +# Copyright (c) 2015, Seiji Sogabe +# +# 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. + +# This version of Jenkins comes with new versions of the following plugins that are currently \ +# pinned in \ +# the plugin manager. \ +# It is recommended to upgrade them to at least the version bundled with Jenkins. + + +blurb=\u3053\u306e\u30d0\u30fc\u30b8\u30e7\u30f3\u306eJenkins\u3067\u306f\u3001\u30d7\u30e9\u30b0\u30a4\u30f3\u30de\u30cd\u30fc\u30b8\u30e3\u30fc\u3067\ +\u30d4\u30f3\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u308b\u6b21\u306e\u30d7\u30e9\u30b0\u30a4\u30f3\u304c\ +\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3055\u308c\u3066\u3044\u307e\u3059\u3002\ +\u30d4\u30f3\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u308b\u30d7\u30e9\u30b0\u30a4\u30f3\u3092\u3001\u5c11\u306a\u304f\u3068\u3082Jenkins\u306b\u30d0\u30f3\u30c9\u30eb\u3055\u308c\u3066\u3044\u308b\u30d0\u30fc\u30b8\u30e7\u30f3\u306b\u30a2\u30c3\u30d7\u30c7\u30fc\u30c8\u3059\u308b\u3053\u3068\u3092\u63a8\u5968\u3057\u307e\u3059\u3002 diff --git a/core/src/main/resources/jenkins/management/Messages_bg.properties b/core/src/main/resources/jenkins/management/Messages_bg.properties index f5fcc33c85c93655b5576e2f4673d1431e63ef35..960e9bf8edf588e2cb45dae13f10a76a95a219b9 100644 --- a/core/src/main/resources/jenkins/management/Messages_bg.properties +++ b/core/src/main/resources/jenkins/management/Messages_bg.properties @@ -1,7 +1,6 @@ -# # The MIT License # -# Copyright (c) 2012, CloudBees, Intl., Nicolas De loof +# Bulgarian translation copyright 2015 Alexander Shopov . # # 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,16 +19,61 @@ # 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. -# -PluginsLink.Description=\u0414\u043E\u0431\u0430\u0432\u044F\u043D\u0435, \u043F\u0440\u0435\u043C\u0430\u0445\u0432\u0430\u043D\u0435, \u0441\u043F\u0438\u0440\u0430\u043D\u0435 \u0438 \u043F\u0443\u0441\u043A\u0430\u043D\u0435 \u043D\u0430 \u043F\u043B\u044A\u0433\u0438\u043D\u0438, \u043A\u043E\u0438\u0442\u043E \u043C\u043E\u0433\u0430\u0442 \u0434\u0430 \u0440\u0430\u0437\u0448\u0438\u0440\u044F\u0442 \u0444\u0443\u043D\u043A\u0446\u0438\u043E\u043D\u0430\u043B\u043D\u043E\u0441\u0442\u0442\u0430 \u043D\u0430 Jenkins. -ConfigureLink.DisplayName=\u0421\u0438\u0441\u0442\u0435\u043C\u043D\u0430 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430 -ConfigureLink.Description=\u041A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0438\u0440\u0430\u043D\u0435 \u043D\u0430 \u0433\u043B\u0430\u0432\u043D\u0438\u0442\u0435 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u0438 \u043F\u044A\u0442\u0435\u043A\u0438 -SystemInfoLink.Description=\u041F\u043E\u043A\u0430\u0437\u0432\u0430 \u0440\u0430\u0437\u043D\u043E\u043E\u0431\u0440\u0430\u0437\u043D\u0430 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F \u0437\u0430 \u0441\u0440\u0435\u0434\u0430\u0442\u0430 \u0441 \u0446\u0435\u043B \u0434\u0430 \u0430\u0441\u0438\u0441\u0442\u0438\u0440\u0430 \u043E\u0442\u0441\u0442\u0440\u0430\u043D\u044F\u0432\u0430\u043D\u0435\u0442\u043E \u043D\u0430 \u043F\u0440\u043E\u0431\u043B\u0435\u043C\u0438. -StatisticsLink.DisplayName=\u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043A\u0430 \u043D\u0430 \u0437\u0430\u0440\u0435\u0436\u0434\u0430\u043D\u0435\u0442\u043E -NodesLink.DisplayName=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043D\u0430 \u043C\u0430\u0448\u0438\u043D\u0438 -PluginsLink.DisplayName=\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043D\u0430 \u043F\u043B\u044A\u0433\u0438\u043D\u0438 -ShutdownLink.DisplayName_prepare=\u041F\u043E\u0434\u0433\u043E\u0442\u043E\u0432\u043A\u0430 \u0437\u0430 \u0438\u0437\u043A\u043B\u044E\u0447\u0432\u0430\u043D\u0435 -ReloadLink.DisplayName=\u041F\u0440\u0435\u0437\u0430\u0440\u0435\u0436\u0434\u0430\u043D\u0435 \u043D\u0430 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u043E\u0442 \u0434\u0438\u0441\u043A\n\ - \u041F\u043E\u043B\u0435\u0437\u043D\u043E \u0435 \u0430\u043A\u043E \u0441\u0442\u0435 \u043C\u043E\u0434\u0438\u0444\u0438\u0446\u0438\u0440\u0430\u043B\u0438 \u043A\u043E\u043D\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043E\u043D\u043D\u0438\u0442\u0435 \u0444\u0430\u0439\u043B\u043E\u0432\u0435 \u0434\u0438\u0440\u0435\u043A\u0442\u043D\u043E \u043D\u0430 \u0434\u0438\u0441\u043A\u0430. -SystemInfoLink.DisplayName=\u0421\u0438\u0441\u0442\u0435\u043C\u043D\u0430 \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F. +ConfigureLink.DisplayName=\ + \u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0430 +ConfigureLink.Description=\ + \u041e\u0431\u0449\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0438 \u043f\u044a\u0442\u0438\u0449\u0430. + +ReloadLink.DisplayName=\ + \u041f\u0440\u0435\u0437\u0430\u0440\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u0442\u0435 \u043e\u0442 \u0434\u0438\u0441\u043a\u0430 +ReloadLink.Description=\ + \u0418\u0437\u0447\u0438\u0441\u0442\u0432\u0430\u043d\u0435 \u043d\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438\u0442\u0435 \u0432 \u043f\u0430\u043c\u0435\u0442\u0442\u0430 \u0438 \u043f\u0440\u0435\u0437\u0430\u0440\u0435\u0436\u0434\u0430\u043d\u0435 \u043e\u0442\ + \u0434\u0438\u0441\u043a\u0430.\n\u0422\u043e\u0432\u0430 \u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u043e, \u043a\u043e\u0433\u0430\u0442\u043e \u0441\u0442\u0435 \u043f\u0440\u043e\u043c\u0435\u043d\u044f\u043b\u0438 \u0444\u0430\u0439\u043b\u043e\u0432\u0435\u0442\u0435 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u043e \u0434\u0438\u0441\u043a\u0430. + +PluginsLink.DisplayName=\ + \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0438\u0442\u0435 +PluginsLink.Description=\ + \u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435, \u043f\u0440\u0435\u043c\u0430\u0445\u0432\u0430\u043d\u0435, \u0441\u043f\u0438\u0440\u0430\u043d\u0435 \u0438 \u043f\u0443\u0441\u043a\u0430\u043d\u0435 \u043d\u0430 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0438, \u043a\u043e\u0438\u0442\u043e \u0434\u043e\u043f\u044a\u043b\u0432\u0430\u0442 \u0438\ + \u0440\u0430\u0437\u0448\u0438\u0440\u044f\u0432\u0430\u0442 \u0432\u044a\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438\u0442\u0435 \u043d\u0430 Jenkins. + +SystemInfoLink.DisplayName=\ + \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0437\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0430 +SystemInfoLink.Description=\ + \u0418\u0437\u0432\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0437\u0430 \u0441\u0440\u0435\u0434\u0430\u0442\u0430 \u0441 \u0446\u0435\u043b \u043e\u0442\u0441\u0442\u0440\u0430\u043d\u044f\u0432\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0438. + +SystemLogLink.DisplayName=\ + \u0421\u0438\u0441\u0442\u0435\u043c\u0435\u043d \u0436\u0443\u0440\u043d\u0430\u043b +SystemLogLink.Description=\ + \u0412 \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u0438\u044f \u0436\u0443\u0440\u043d\u0430\u043b \u0441\u0435 \u0437\u0430\u043f\u0438\u0441\u0432\u0430 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f\u0442\u0430 \u043e\u0442 java.util.logging \u0437\u0430\ + Jenkins. + +StatisticsLink.DisplayName=\ + \u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430 \u043d\u0430 \u043d\u0430\u0442\u043e\u0432\u0430\u0440\u0432\u0430\u043d\u0435\u0442\u043e +StatisticsLink.Description=\ + \u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 \u043d\u0430 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u043d\u0438\u0442\u0435 \u0440\u0435\u0441\u0443\u0440\u0441\u0438, \u0437\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u043d\u0435 \u043d\u0430 \u0435\u0432\u0435\u043d\u0442\u0443\u0430\u043b\u043d\u0430\u0442\u0430 \u043d\u0443\u0436\u0434\u0430 \u043e\u0442 \u043e\u0449\u0435\ + \u043c\u0430\u0448\u0438\u043d\u0438 \u0437\u0430 Jenkins. + +CliLink.DisplayName=\ + Jenkins \u043e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u0438\u044f \u0440\u0435\u0434 +CliLink.Description=\ + \u0414\u043e\u0441\u0442\u044a\u043f \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 Jenkins \u043e\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u043d\u0438\u044f \u0440\u0435\u0434 \u0438\u043b\u0438 \u0441\u043a\u0440\u0438\u043f\u0442. + +ConsoleLink.DisplayName=\ + \u041a\u043e\u043d\u0437\u043e\u043b\u0430 +ConsoleLink.Description=\ + \u0418\u0437\u043f\u044a\u043b\u043d\u0435\u043d\u0438\u0435 \u043d\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u043b\u0435\u043d \u0441\u043a\u0440\u0438\u043f\u0442 \u0437\u0430 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0438\u0440\u0430\u043d\u0435, \u043e\u0442\u043a\u0440\u0438\u0432\u0430\u043d\u0435 \u0438 \u043e\u0442\u0441\u0442\u0440\u0430\u043d\u044f\u0432\u0430\u043d\u0435\ + \u043d\u0430 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0438. + +NodesLink.DisplayName=\ + \u0423\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u043c\u0430\u0448\u0438\u043d\u0438 +NodesLink.Description=\ + \u0414\u043e\u0431\u0430\u0432\u044f\u043d\u0435, \u043f\u0440\u0435\u043c\u0430\u0445\u0432\u0430\u043d\u0435, \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u0438\u0442\u0435 \u043c\u0430\u0448\u0438\u043d\u0438, \u043d\u0430 \u043a\u043e\u0438\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0438 Jenkins. + +ShutdownLink.DisplayName_prepare=\ + \u041f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430 \u0437\u0430 \u0438\u0437\u043a\u043b\u044e\u0447\u0432\u0430\u043d\u0435 +ShutdownLink.DisplayName_cancel=\ + \u041e\u0442\u043c\u044f\u043d\u0430 \u043d\u0430 \u0438\u0437\u043a\u043b\u044e\u0447\u0432\u0430\u043d\u0435\u0442\u043e +ShutdownLink.Description=\ + \u041d\u0435\u0434\u043e\u043f\u0443\u0441\u043a\u0430\u043d\u0435 \u043d\u0430 \u043d\u043e\u0432\u0438 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f, \u0437\u0430 \u0434\u0430 \u043c\u043e\u0436\u0435 \u0432 \u0434\u0430\u0434\u0435\u043d \u043c\u043e\u043c\u0435\u043d\u0442 \u043c\u0430\u0448\u0438\u043d\u0430\u0442\u0430 \u0434\u0430 \u0431\u044a\u0434\u0435\ + \u0441\u043f\u0440\u044f\u043d\u0430. diff --git a/core/src/main/resources/jenkins/management/Messages_pl.properties b/core/src/main/resources/jenkins/management/Messages_pl.properties index 174a79fbe61708fa9782c72467b3748f44e46531..bcd68eabf1b17254a6296916ec581dbece0a5ab7 100644 --- a/core/src/main/resources/jenkins/management/Messages_pl.properties +++ b/core/src/main/resources/jenkins/management/Messages_pl.properties @@ -22,15 +22,34 @@ # THE SOFTWARE. # -PluginsLink.Description=Dodaj, usu\u0144, wy\u0142\u0105cz lub w\u0142\u0105cz wtyczki kt\u00F3re mog\u0105 rozszerzy\u0107 funkcjonalno\u015B\u0107 Jenkinsa. ConfigureLink.DisplayName=Skonfiguruj system ConfigureLink.Description=Konfiguruj ustawienia globalne i \u015Bcie\u017Cki. + +ReloadLink.DisplayName=Odczytaj ponownie konfiguracj\u0119 z dysku ReloadLink.Description=Porzu\u0107 wszystkie dane za\u0142adowane w pami\u0119ci i za\u0142aduj wszystko z systemu plik\u00F3w.\n\ Opcja u\u017Cyteczna gdy zmodyfikowano pliki konfiguracyjne bezpo\u015Brednio z dysku. -StatisticsLink.DisplayName=Statystyki Obci\u0105\u017Cenia + PluginsLink.DisplayName=Zarz\u0105dzaj dodatkami +PluginsLink.Description=Dodaj, usu\u0144, wy\u0142\u0105cz lub w\u0142\u0105cz wtyczki kt\u00F3re mog\u0105 rozszerzy\u0107 funkcjonalno\u015B\u0107 Jenkinsa. + +SystemInfoLink.DisplayName=Informacje o systemie +SystemInfoLink.Description=Wy\u015Bwietla wiele \u015Brodowiskowych informacji pomocnych przy rozwi\u0105zywaniu problem\u00F3w. + +StatisticsLink.DisplayName=Statystyki obci\u0105\u017Cenia +StatisticsLink.Description=Sprawd\u017A obci\u0105\u017Cenie zasob\u00F3w systemowych i dowiedz si\u0119, czy nie potrzebujesz wi\u0119cej maszyn do budowania. + +SystemLogLink.DisplayName=Dziennik systemowy +SystemLogLink.Description=Dziennik systemowy gromadzi wywoy\u0142ania java.util.logging powi\u0105zane z Jenkinsem. + +CliLink.DisplayName=Wiersz polece\u0144 Jenkinsa +CliLink.Description=Zarz\u0105dzaj Jenkinsem poziomu z wiersza polece\u0144 lub systemu. + +ConsoleLink.DisplayName=Konsola skrypt\u00F3w +ConsoleLink.Description=Wykonuje dowolny skrypt pomocny do cel\u00F3w administracyjnych, usuwania usterek i diagnostyki. + +NodesLink.DisplayName=Zarz\u0105dzaj w\u0119z\u0142ami +NodesLink.Description=Dodawaj, usuwaj, kontroluj i monitoruj r\u00F3\u017Cne w\u0119z\u0142y, na kt\u00F3rych Jenkins uruchamia zadania. + ShutdownLink.DisplayName_prepare=Przygotuj do wy\u0142\u0105czenia -ReloadLink.DisplayName=Odczytaj ponownie konfiguracj\u0119 z dysku -ShutdownLink.Description=Zatrzyma wykonanie nowych build\u00F3w, tak by system m\u00F3g\u0142by\u0107 bezpiecznie wy\u0142\u0105czony. ShutdownLink.DisplayName_cancel=Anuluj wy\u0142\u0105czenie -SystemInfoLink.DisplayName=Informacje o systemie +ShutdownLink.Description=Zatrzyma wykonanie nowych build\u00F3w, tak by system m\u00F3g\u0142by\u0107 bezpiecznie wy\u0142\u0105czony. diff --git a/test/src/main/resources/org/jvnet/hudson/test/SleepBuilder/config.jelly b/core/src/main/resources/jenkins/model/BuildDiscarderProperty/config-details.jelly similarity index 87% rename from test/src/main/resources/org/jvnet/hudson/test/SleepBuilder/config.jelly rename to core/src/main/resources/jenkins/model/BuildDiscarderProperty/config-details.jelly index d5da4406d2ff61bef3692435670febeefd8fefc8..a5f3d0a4d713c9d65e3a25e3fd2908cd2d4f8cdd 100644 --- a/test/src/main/resources/org/jvnet/hudson/test/SleepBuilder/config.jelly +++ b/core/src/main/resources/jenkins/model/BuildDiscarderProperty/config-details.jelly @@ -1,7 +1,8 @@ + - \ No newline at end of file + +
+
+ + + +
+
diff --git a/core/src/main/resources/jenkins/model/DownloadSettings/Warning/message.properties b/core/src/main/resources/jenkins/model/DownloadSettings/Warning/message.properties new file mode 100644 index 0000000000000000000000000000000000000000..57c6a3b68dbf987ff13efbd627d9d6410ca5c9d3 --- /dev/null +++ b/core/src/main/resources/jenkins/model/DownloadSettings/Warning/message.properties @@ -0,0 +1,26 @@ +# 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. + +blurb=\ + You currently are using browser-based download to retrieve metadata for Jenkins plugins and tools. \ + This has reliability issues and is not considered fully secure. \ + Consider switching to server-based download. diff --git a/core/src/main/resources/jenkins/model/DownloadSettings/Warning/message_de.properties b/core/src/main/resources/jenkins/model/DownloadSettings/Warning/message_de.properties new file mode 100644 index 0000000000000000000000000000000000000000..e0bb5e6898783ea7c16a67760212f4d739efccc5 --- /dev/null +++ b/core/src/main/resources/jenkins/model/DownloadSettings/Warning/message_de.properties @@ -0,0 +1,27 @@ +# The MIT License +# +# Copyright 2015 Jesse Glick, Harald Albers. +# +# 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. + +blurb=\ + Sie verwenden momentan Ihren Browser zum Download von Metadaten ber Plugins und Tools. \ + Dieses Verfahren gilt als unzuverlssig und unsicher. \ + Sie sollten erwgen, zu Server-basierten Downloads zu wechseln. +Dismiss=Ignorieren \ No newline at end of file diff --git a/core/src/main/resources/jenkins/model/DownloadSettings/config.groovy b/core/src/main/resources/jenkins/model/DownloadSettings/config.groovy index 9c8987f561b0b4b1c7f41e7a53d7560ef546e110..6b0751e5634286586463211f2dd690d829b11321 100644 --- a/core/src/main/resources/jenkins/model/DownloadSettings/config.groovy +++ b/core/src/main/resources/jenkins/model/DownloadSettings/config.groovy @@ -2,8 +2,7 @@ package jenkins.security.DownloadSettings def f = namespace(lib.FormTagLib) -f.section(title: _("Download Preferences")) { - f.entry(title: _("Use Browser"), field: "useBrowser") { - f.checkbox() - } +// TODO avoid indentation somehow +f.entry(field: "useBrowser") { + f.checkbox(title: _("Use browser for metadata download")) } diff --git a/core/src/main/resources/jenkins/model/DownloadSettings/config_de.properties b/core/src/main/resources/jenkins/model/DownloadSettings/config_de.properties index 2d8110051f024d0a014389a86436c313f1d49c54..be68d8e226d42a639969ed172780500177258d1a 100644 --- a/core/src/main/resources/jenkins/model/DownloadSettings/config_de.properties +++ b/core/src/main/resources/jenkins/model/DownloadSettings/config_de.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2014, Harald Albers +# Copyright (c) 2014-2015, Harald Albers # # 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,5 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Download\ Preferences = Downloads -Use\ Browser = Browser verwenden +Use\ browser\ for\ metadata\ download = Browser zum Download von Metadaten verwenden diff --git a/test/src/main/resources/org/jvnet/hudson/test/ComputerConnectorTester/configure_es.properties b/core/src/main/resources/jenkins/model/DownloadSettings/config_ja.properties similarity index 89% rename from test/src/main/resources/org/jvnet/hudson/test/ComputerConnectorTester/configure_es.properties rename to core/src/main/resources/jenkins/model/DownloadSettings/config_ja.properties index 14e5ddf52195242740774afba3901620ad541ea4..3f7949a961a2fbec73d6f934360734668cc9126b 100644 --- a/test/src/main/resources/org/jvnet/hudson/test/ComputerConnectorTester/configure_es.properties +++ b/core/src/main/resources/jenkins/model/DownloadSettings/config_ja.properties @@ -1,17 +1,17 @@ # The MIT License -# -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributers -# +# +# Copyright (c) 2014-2015, Harald Albers, Seiji Sogabe +# # 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 @@ -20,4 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Save=Guardar +Use\ Browser = \u30d6\u30e9\u30a6\u30b6\u3092\u4f7f\u7528 diff --git a/core/src/main/resources/jenkins/model/DownloadSettings/help-useBrowser.html b/core/src/main/resources/jenkins/model/DownloadSettings/help-useBrowser.html index ffe660600830b2cb755a51bb52bfbc5feb16a51c..1357dbaa056ec31c5a142c5b1fe4b395fd06d08c 100644 --- a/core/src/main/resources/jenkins/model/DownloadSettings/help-useBrowser.html +++ b/core/src/main/resources/jenkins/model/DownloadSettings/help-useBrowser.html @@ -1,7 +1,11 @@ -
+

Check to force the user’s browser to download metadata (lists of available plugins, tools etc.) rather than Jenkins itself doing it. Actual file downloads (plugins, tools) will still happen from Jenkins itself, but this can be used to at least see new metadata when Jenkins cannot access the Internet (but your own browser can, perhaps using some special proxy that Jenkins is not configured to use). -

+

+

+ Use of browser mode is discouraged. + It has robustness problems and has been limited to users with Overall/Administer. +

diff --git a/core/src/main/resources/jenkins/model/DownloadSettings/help-useBrowser_ja.html b/core/src/main/resources/jenkins/model/DownloadSettings/help-useBrowser_ja.html new file mode 100644 index 0000000000000000000000000000000000000000..5d819f0ae2c1da7e38341dbc4f48973ea56734d6 --- /dev/null +++ b/core/src/main/resources/jenkins/model/DownloadSettings/help-useBrowser_ja.html @@ -0,0 +1,7 @@ +
+ チェックすると、Jenkinsではなく使用しているブラウザで、使用可能なプラグインやツールなどのメタ情報をダウンロードします。 + プラグインやツールのファイルはjenkins自身がダウンロードしますが、 + ブラウザを使用することで、Jenkinsがインターネットにアクセスできないときでも、少なくとも新規のメタ情報を参照することができます + (おそらく、ある特別なプロキシーを使用していて、Jenkinsがそれを使用するように設定できなくても、 + ブラウザは設定できるでしょう)。 +
diff --git a/core/src/main/resources/jenkins/model/Jenkins/_restart.jelly b/core/src/main/resources/jenkins/model/Jenkins/_restart.jelly index 7816f469c52d73847f4b9001be5bdfd70eb77708..cfead03b2d27171ff8d00d04dbf15b46a188a48c 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/_restart.jelly +++ b/core/src/main/resources/jenkins/model/Jenkins/_restart.jelly @@ -28,10 +28,17 @@ THE SOFTWARE. -
- ${%Are you sure about restarting Jenkins?} - - + + +
+ ${%Are you sure about restarting Jenkins?} + + +
+ + ${%Jenkins cannot restart itself as currently configured.} + +
\ No newline at end of file diff --git a/core/src/main/resources/jenkins/model/Jenkins/_safeRestart.jelly b/core/src/main/resources/jenkins/model/Jenkins/_safeRestart.jelly index 3a76e6af82abdabe53343f0d2e28ee7fbf161641..e37bf2ece0b8f5fdb646cda9b656d41abf2f29c4 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/_safeRestart.jelly +++ b/core/src/main/resources/jenkins/model/Jenkins/_safeRestart.jelly @@ -28,10 +28,17 @@ THE SOFTWARE. -
- ${%Are you sure about restarting Jenkins? Jenkins will restart once all running jobs are finished.} - - + + +
+ ${%Are you sure about restarting Jenkins? Jenkins will restart once all running jobs are finished.} + + +
+ + ${%Jenkins cannot restart itself as currently configured.} + +
\ No newline at end of file diff --git a/core/src/main/resources/jenkins/model/Jenkins/downgrade_pl.properties b/core/src/main/resources/jenkins/model/Jenkins/downgrade_pl.properties index a7ca7cdb6ae107267e6fd7d56bbbe30c27c1e0c2..4e6685245c8e350f39a038863c2bff10595f39da 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/downgrade_pl.properties +++ b/core/src/main/resources/jenkins/model/Jenkins/downgrade_pl.properties @@ -21,4 +21,4 @@ # THE SOFTWARE. Restore\ the\ previous\ version\ of\ Jenkins=Przywr\u00F3\u0107 poprzedni\u0105 wersj\u0119 Jenkins''a -buttonText=Obni\u017C do +buttonText=Obni\u017C do {0} diff --git a/core/src/main/resources/jenkins/model/Jenkins/fingerprintCheck_et.properties b/core/src/main/resources/jenkins/model/Jenkins/fingerprintCheck_et.properties index a34ae03918583dfd2e282d439e127bf27487b75a..3c4ef25a9641625076808e004b39c855a6cd7692 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/fingerprintCheck_et.properties +++ b/core/src/main/resources/jenkins/model/Jenkins/fingerprintCheck_et.properties @@ -4,6 +4,6 @@ Check=Kontrolli Check\ File\ Fingerprint=Kontrolli Faili Signatuuri File\ to\ check=Kontrolli faili description=Sul on jar fail aga sa ei tea tema versiooninumbrit?
Leia see kontrollides faili signatuuri Jenkinsi andmebaasist. -
Leia see Jenkinsi s\u00F5rmej\u00E4lgede andmebaasist. -
Leia see Jenkinsi s\u00F5rmej\u00E4lgede andmebaasist. +# TODO was this supposed to be part of the previous description? +#
Leia see Jenkinsi s\u00F5rmej\u00E4lgede andmebaasist. more\ details=lisadetailid diff --git a/core/src/main/resources/jenkins/model/Jenkins/legend_pl.properties b/core/src/main/resources/jenkins/model/Jenkins/legend_pl.properties index 3e072ee7641986b9668a374d67486eb8b376c406..5dcd092fc61cf677add99e3b4f83d6a12a54a8ad 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/legend_pl.properties +++ b/core/src/main/resources/jenkins/model/Jenkins/legend_pl.properties @@ -4,7 +4,12 @@ blue=Ostatnie budowanie projektu zako\u0144czy\u0142o si\u0119 pomy\u015Blnie. blue_anime=Ostatnie budowanie projektu zako\u0144czy\u0142o si\u0119 pomy\u015Blnie. Nowa wersja jest w trakcie budowy. grey=Projekt nie zosta\u0142 dotychczas zbudowany lub jest wy\u0142\u0105czony. grey_anime=Trwa pierwsze budowanie projektu. -red=Ostatnia wgrywka nie powiod\u0142a si\u0119. -red_anime=Ostatnia wgrywka nie powiod\u0142a si\u0119. Nowa wersja jest w trakcie budowy. +red=Ostatnie budowanie projektu nie powiod\u0142o si\u0119. +red_anime=Ostatnie budowanie projektu nie powiod\u0142o si\u0119. Nowa wersja jest w trakcie budowy. yellow=Ostatnie budowanie projektu zako\u0144czy\u0142o si\u0119 pomy\u015Blnie, lecz wersja jest niestabilna. To oznaczenie stosowane jest dla projekt\u00F3w, w kt\u00F3rych testy zako\u0144czy\u0142y si\u0119 niepowodzeniem. yellow_anime=Ostatnie budowanie projektu zako\u0144czy\u0142o si\u0119 pomy\u015Blnie, lecz wersja jest niestabilna. Nowa wersja jest w trakcie budowy. +health-81plus=Budowanie zako\u0144czone pomy\u015Blnie w ponad 80 procent przypadk\u00F3w. Przesu\u0144 myszk\u0119 nad ikon\u0119 projektu, aby sprawdzi\u0107 szczeg\u00F3\u0142y. +health-61to80=Budowanie zako\u0144czone pomy\u015Blnie pomi\u0119dzy 60 a 80 procent przypadk\u00F3w. Przesu\u0144 myszk\u0119 nad ikon\u0119 projektu, aby sprawdzi\u0107 szczeg\u00F3\u0142y. +health-41to60=Budowanie zako\u0144czone pomy\u015Blnie pomi\u0119dzy 40 a 60 procent przypadk\u00F3w. Przesu\u0144 myszk\u0119 nad ikon\u0119 projektu, aby sprawdzi\u0107 szczeg\u00F3\u0142y. +health-21to40=Budowanie zako\u0144czone pomy\u015Blnie pomi\u0119dzy 20 a 40 procent przypadk\u00F3w. Przesu\u0144 myszk\u0119 nad ikon\u0119 projektu, aby sprawdzi\u0107 szczeg\u00F3\u0142y. +health-00to20=Budowanie zako\u0144czone pomy\u015Blnie w poni\u017Cej 20 procent przypadk\u00F3w. Przesu\u0144 myszk\u0119 nad ikon\u0119 projektu, aby sprawdzi\u0107 szczeg\u00F3\u0142y. diff --git a/core/src/main/resources/jenkins/model/Jenkins/login.jelly b/core/src/main/resources/jenkins/model/Jenkins/login.jelly index a5f68b1178875730d3c1618d2d17ba09d11a87e7..f7e02a5f50567bae4b018ae0134ddfc46abae007 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. - + diff --git a/core/src/main/resources/jenkins/model/Jenkins/login_pl.properties b/core/src/main/resources/jenkins/model/Jenkins/login_pl.properties index d62d74ae145e05c523ffa5fb309d6d29ea7dd35c..45c8799cacc94b54bc7664936723a2e1744bd17c 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/login_pl.properties +++ b/core/src/main/resources/jenkins/model/Jenkins/login_pl.properties @@ -4,5 +4,5 @@ Password=Has\u0142o Remember\ me\ on\ this\ computer=Zapami\u0119taj mnie na tym komputerze User=Login login=zaloguj -signUp=Za\u0142u\u017C konto je\u015Bli nie jeste\u015B jeszcze uczestnikiem. +signUp=Za\u0142\u00F3\u017C konto je\u015Bli nie jeste\u015B jeszcze uczestnikiem. diff --git a/core/src/main/resources/jenkins/model/Messages.properties b/core/src/main/resources/jenkins/model/Messages.properties index 98c360e524506acacac37ba3a86c45b0f361071f..63ffa92e530f97c692192c85aef463b9523b9990 100644 --- a/core/src/main/resources/jenkins/model/Messages.properties +++ b/core/src/main/resources/jenkins/model/Messages.properties @@ -66,3 +66,8 @@ 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 +BlockedBecauseOfBuildInProgress.shortDescription=Build #{0} is already in progress{1} +BlockedBecauseOfBuildInProgress.ETA=\ (ETA:{0}) +BuildDiscarderProperty.displayName=Discard Old Builds diff --git a/core/src/main/resources/jenkins/model/Messages_bg.properties b/core/src/main/resources/jenkins/model/Messages_bg.properties new file mode 100644 index 0000000000000000000000000000000000000000..21bcd85721db047101c63e4095f268ead70e0f21 --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_bg.properties @@ -0,0 +1,116 @@ +# The MIT License +# +# Bulgarian translation copyright 2015 Alexander Shopov . +# +# 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. + +Hudson.BadPortNumber=\ + \u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u0435\u043d \u043d\u043e\u043c\u0435\u0440 \u043d\u0430 \u043f\u043e\u0440\u0442: {0} +Hudson.Computer.Caption=\ + \u041e\u0441\u043d\u043e\u0432\u0435\u043d \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 +Hudson.Computer.DisplayName=\ + \u043e\u0441\u043d\u043e\u0432\u0435\u043d \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 +Hudson.ControlCodeNotAllowed=\ + \u041d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u043f\u043e\u043b\u0437\u0432\u0430\u0442\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043d\u0438 \u0437\u043d\u0430\u0446\u0438: {0} +Hudson.DisplayName=\ + Jenkins +Hudson.JobAlreadyExists=\ + \u0412\u0435\u0447\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u0441 \u0438\u043c\u0435 \u201e{0}\u201c +Hudson.NoJavaInPath=\ + \u0412 \u043f\u044a\u0442\u0438\u0449\u0430\u0442\u0430 \u0441\u043e\u0447\u0435\u043d\u0438 \u043e\u0442 \u043f\u0440\u043e\u043c\u0435\u043d\u043b\u0438\u0432\u0430\u0442\u0430 \u201ePATH\u201c \u043b\u0438\u043f\u0441\u0432\u0430 \u043a\u043e\u043c\u0430\u043d\u0434\u0430\u0442\u0430 \u201ejava\u201c.\u00a0\u0412\u0435\u0440\u043e\u044f\u0442\u043d\u043e\ + \u0442\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u0435 \u043a\u043e\u043c\u043f\u043b\u0435\u043a\u0442 \u0437\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u043d\u0430 JAVA\ + \u2014 JDK? +Hudson.NoName=\ + \u041b\u0438\u043f\u0441\u0432\u0430 \u0438\u043c\u0435 +Hudson.NodeBeingRemoved=\ + \u0418\u0437\u0432\u0430\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u043c\u0430\u0448\u0438\u043d\u0430\u0442\u0430 \u043e\u0442 \u0433\u0440\u0443\u043f\u0430\u0442\u0430 +Hudson.UnsafeChar=\ + \u0417\u043d\u0430\u0446\u0438 \u043a\u0430\u0442\u043e \u201e{0}\u201c \u0435 \u043e\u043f\u0430\u0441\u043d\u043e \u0434\u0430 \u0441\u0435 \u043f\u043e\u043b\u0437\u0432\u0430\u0442 +Hudson.JobNameConventionNotApplyed=\ + \u201e{0}\u201c \u043d\u0435 \u043d\u0430\u043f\u0430\u0441\u0432\u0430 \u043d\u0430 \u0448\u0430\u0431\u043b\u043e\u043d\u0430 \u0437\u0430 \u0438\u043c\u0435 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u201e{1}\u201c +Hudson.ViewAlreadyExists=\ + \u0412\u0435\u0447\u0435 \u0441\u044a\u0449\u0435\u0441\u0442\u0432\u0443\u0432\u0430 \u0438\u0437\u0433\u043b\u0435\u0434 \u0441 \u0438\u043c\u0435 \u201e{0}\u201c +Hudson.ViewName=\ + \u0412\u0441\u0438\u0447\u043a\u0438 +Hudson.NotUsesUTF8ToDecodeURL=\ + \u041a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044a\u0442 \u0437\u0430 \u0441\u044a\u0440\u0432\u043b\u0435\u0442\u0438, \u0432 \u043a\u043e\u0439\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0438 Jenkins, \u043d\u0435 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430 UTF-8 \u0437\u0430\ + \u0434\u0435\u043a\u043e\u0434\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 \u0430\u0434\u0440\u0435\u0441\u0438\u0442\u0435. \u0418\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0437\u043d\u0430\u0446\u0438 \u0438\u0437\u0432\u044a\u043d ASCII \u0432 \u0438\u043c\u0435\u043d\u0430\u0442\u0430 \u043d\u0430 \u0437\u0430\u0434\u0430\u0447\u0438\ + \u0438 \u0434\u0440. \u043c\u043e\u0436\u0435 \u0434\u0430 \u0434\u043e\u0432\u0435\u0434\u0435 \u0434\u043e \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0438. \u0417\u0430 \u043f\u043e\u0432\u0435\u0447\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043f\u043e\u0433\u043b\u0435\u0434\u043d\u0435\u0442\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u0437\u0430\ + \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0438\ + \u0438 \u0440\u0430\u0437\u0434\u0435\u043b\u0430 \u0437\u0430 \ + \u0438\u043d\u0442\u0435\u0440\u043d\u0430\u0446\u0438\u043e\u043d\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0430 Tomcat i18n. +Hudson.NodeDescription=\ + \u043e\u0441\u043d\u043e\u0432\u043d\u0438\u044f\u0442 \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 \u043d\u0430 Jenkins + + +CLI.restart.shortDescription=\ + \u0420\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 Jenkins. +CLI.safe-restart.shortDescription=\ + \u0411\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 Jenkins. +CLI.keep-build.shortDescription=\ + \u0422\u043e\u0432\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u0434\u0430 \u0441\u0435 \u0437\u0430\u043f\u0430\u0437\u0438 \u0437\u0430\u0432\u0438\u043d\u0430\u0433\u0438. +CLI.quiet-down.shortDescription=\ + \u041f\u0440\u0438\u0432\u044a\u0440\u0448\u0432\u0430\u043d\u0435 \u043d\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u0430 \u043d\u0430 Jenkins \u043f\u0440\u0438 \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0430\u0442\u0430 \u0437\u0430 \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435. \u0414\u0430 \u043d\u0435\ + \u0437\u0430\u043f\u043e\u0447\u0432\u0430\u0442 \u043d\u043e\u0432\u0438 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f. +CLI.cancel-quiet-down.shortDescription=\ + \u041e\u0442\u043c\u044f\u043d\u0430 \u043d\u0430 \u0435\u0444\u0435\u043a\u0442\u0430 \u043d\u0430 \u043f\u0440\u0438\u0432\u044a\u0440\u0448\u0432\u0430\u043d\u0435\u0442\u043e. +CLI.reload-configuration.shortDescription=\ + \u0418\u0437\u0447\u0438\u0441\u0442\u0432\u0430\u043d\u0435 \u043d\u0430 \u043f\u0430\u043c\u0435\u0442\u0442\u0430 \u0438 \u043f\u0440\u0435\u0437\u0430\u0440\u0435\u0436\u0434\u0430\u043d\u0435 \u043d\u0430 \u0432\u0441\u0438\u0447\u043a\u043e \u043e\u0442 \u0444\u0430\u0439\u043b\u043e\u0432\u0430\u0442\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430.\ + \u0418\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0439\u0442\u0435 \u043f\u0440\u0438 \u043f\u0440\u043e\u043c\u044f\u043d\u0430 \u043d\u0430 \u0444\u0430\u0439\u043b\u043e\u0432\u0435 \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043f\u043e \u0434\u0438\u0441\u043a\u0430. +CauseOfInterruption.ShortDescription=\ + \u041f\u0440\u0435\u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0435\u043d\u043e \u043e\u0442 \u201e{0}\u201c +CLI.shutdown.shortDescription=\ + \u041d\u0435\u0437\u0430\u0431\u0430\u0432\u043d\u043e \u0441\u043f\u0438\u0440\u0430\u043d\u0435 \u043d\u0430 Jenkins. +CLI.safe-shutdown.shortDescription=\ + \u041f\u043e\u0441\u0442\u0430\u0432\u044f\u043d\u0435 \u043d\u0430 Jenkins \u0432 \u0440\u0435\u0436\u0438\u043c \u043d\u0430 \u043f\u0440\u0438\u0432\u044a\u0440\u0448\u0432\u0430\u043d\u0435 \u2014 \u043d\u0435 \u0441\u0435 \u043f\u0440\u0438\u0435\u043c\u0430\u0442 \u043d\u043e\u0432\u0438 \u0437\u0430\u0434\u0430\u0447\u0438 \u0437\u0430\ + \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435, \u0430 \u0432\u0435\u0447\u0435 \u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0438\u0442\u0435 \u0441\u0435 \u0438\u0437\u0447\u0430\u043a\u0432\u0430\u0442. + +DefaultProjectNamingStrategy.DisplayName=\ + \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e + +IdStrategy.CaseInsensitive.DisplayName=\ + \u0411\u0435\u0437 \u0440\u0430\u0437\u043b\u0438\u043a\u0430 \u0433\u043b\u0430\u0432\u043d\u0438/\u043c\u0430\u043b\u043a\u0438 +IdStrategy.CaseSensitive.DisplayName=\ + \u0420\u0430\u0437\u043b\u0438\u043a\u0430 \u0433\u043b\u0430\u0432\u043d\u0438/\u043c\u0430\u043b\u043a\u0438 +IdStrategy.CaseSensitiveEmailAddress.DisplayName=\ + \u0420\u0430\u0437\u043b\u0438\u043a\u0430 \u0433\u043b\u0430\u0432\u043d\u0438/\u043c\u0430\u043b\u043a\u0438 (\u0437\u0430 \u0430\u0434\u0440\u0435\u0441\u0430 \u0437\u0430 \u0435-\u043f\u043e\u0449\u0430) + +Mailer.Address.Not.Configured=\ + \u0430\u0434\u0440\u0435\u0441\u044a\u0442 \u043d\u0435 \u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d +Mailer.Localhost.Error=\ + \u0417\u0430\u0434\u0430\u0439\u0442\u0435 \u0434\u0440\u0443\u0433\u043e \u0438\u043c\u0435 \u043d\u0430 \u0445\u043e\u0441\u0442, \u0430 \u043d\u0435 \u201elocalhost\u201c + +PatternProjectNamingStrategy.DisplayName=\ + \u0428\u0430\u0431\u043b\u043e\u043d +PatternProjectNamingStrategy.NamePatternRequired=\ + \u0418\u0437\u0438\u0441\u043a\u0432\u0430 \u0441\u0435 \u0448\u0430\u0431\u043b\u043e\u043d \u0437\u0430 \u0438\u043c\u0435\u0442\u043e +PatternProjectNamingStrategy.NamePatternInvalidSyntax=\ + \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u0435\u043d \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u0435\u043d \u0438\u0437\u0440\u0430\u0437. +ParameterizedJobMixIn.build_with_parameters=\ + \u0418\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438 +ParameterizedJobMixIn.build_now=\ + \u0418\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u0441\u0435\u0433\u0430 +BlockedBecauseOfBuildInProgress.shortDescription=\ + \u0418\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u2116\u200a{0} \u0432\u0435\u0447\u0435 \u0441\u0435 \u0438\u0437\u043f\u044a\u043b\u043d\u044f\u0432\u0430{1} +BlockedBecauseOfBuildInProgress.ETA=\ + \ (\u043e\u0441\u0442\u0430\u0432\u0430\u0442: {0}) +BuildDiscarderProperty.displayName=\ + \u0418\u0437\u0442\u0440\u0438\u0432\u0430\u043d\u0435 \u043d\u0430 \u0441\u0442\u0430\u0440\u0438\u0442\u0435 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0438\u044f 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 0000000000000000000000000000000000000000..a5ded4670ca1e42649250be69f05f7dfa7346b56 --- /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_cs.properties b/core/src/main/resources/jenkins/model/Messages_cs.properties new file mode 100644 index 0000000000000000000000000000000000000000..ef85dc5059f5062c07cc4513f8825c98bd8ab60a --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_cs.properties @@ -0,0 +1 @@ +BuildDiscarderProperty.displayName=Zahodit star\u00E9 sestaven\u00ED diff --git a/core/src/main/resources/jenkins/model/Messages_da.properties b/core/src/main/resources/jenkins/model/Messages_da.properties index c355612da1804ac128df68223f378b6e59d8bb7e..5aff31f66ba0439db7ac3a2de2ad069807bfd8ef 100644 --- a/core/src/main/resources/jenkins/model/Messages_da.properties +++ b/core/src/main/resources/jenkins/model/Messages_da.properties @@ -52,3 +52,7 @@ 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 +BlockedBecauseOfBuildInProgress.shortDescription=Byg #{0} er allerede i gang {1} +BlockedBecauseOfBuildInProgress.ETA=(ETA:{0}) +BuildDiscarderProperty.displayName=Fjern Gamle Byg diff --git a/core/src/main/resources/jenkins/model/Messages_de.properties b/core/src/main/resources/jenkins/model/Messages_de.properties index dc2b7ce5479efbb8264edada5cadb01b05212be4..44f27164ab37753a29a0b22621950a1550272fe9 100644 --- a/core/src/main/resources/jenkins/model/Messages_de.properties +++ b/core/src/main/resources/jenkins/model/Messages_de.properties @@ -61,3 +61,8 @@ 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 +BlockedBecauseOfBuildInProgress.shortDescription=Build #{0} ist bereits in Arbeit{1} +BlockedBecauseOfBuildInProgress.ETA=\ (ETA:{0}) +BuildDiscarderProperty.displayName=Alte Builds verwerfen diff --git a/core/src/main/resources/jenkins/model/Messages_es.properties b/core/src/main/resources/jenkins/model/Messages_es.properties index 4b4c61a764537fcc52da83543e0121ad5e9a0d6d..dbcea9d5d48e69895aa6b9303fa5c2450f64b509 100644 --- a/core/src/main/resources/jenkins/model/Messages_es.properties +++ b/core/src/main/resources/jenkins/model/Messages_es.properties @@ -62,3 +62,7 @@ PatternProjectNamingStrategy.NamePatternInvalidSyntax=La sintaxis de la expresi Mailer.Address.Not.Configured=Direccin no configurada todava Mailer.Localhost.Error=Escriba un nombre de servidor correcto en lugar de "localhost" +ParameterizedJobMixIn.build_now=Construir ahora +BlockedBecauseOfBuildInProgress.shortDescription=La ejecuci\u00f3n #{0} ya est\u00e1 en progreso {1} +BlockedBecauseOfBuildInProgress.ETA= (ETA:{0}) +BuildDiscarderProperty.displayName=Desechar ejecuciones antiguas diff --git a/core/src/main/resources/jenkins/model/Messages_es_AR.properties b/core/src/main/resources/jenkins/model/Messages_es_AR.properties new file mode 100644 index 0000000000000000000000000000000000000000..9fd7aaa53ab68df0f4ed062b2da0b75e3bf41e32 --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_es_AR.properties @@ -0,0 +1 @@ +BuildDiscarderProperty.displayName=Descargar build antiguos diff --git a/core/src/main/resources/jenkins/model/Messages_et.properties b/core/src/main/resources/jenkins/model/Messages_et.properties new file mode 100644 index 0000000000000000000000000000000000000000..37ea99b75f7c99933fce5a143da640282a3119cf --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_et.properties @@ -0,0 +1 @@ +BuildDiscarderProperty.displayName=Eemalda vanad bildid 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 0000000000000000000000000000000000000000..e05f4ad601a65e16f791fd7fcbabf3f11a758f1c --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_fi.properties @@ -0,0 +1,2 @@ +ParameterizedJobMixIn.build_now=K\u00E4\u00E4nn\u00E4 nyt +BuildDiscarderProperty.displayName=H\u00E4vit\u00E4 vanhat k\u00E4\u00E4nn\u00F6kset diff --git a/core/src/main/resources/jenkins/model/Messages_fr.properties b/core/src/main/resources/jenkins/model/Messages_fr.properties index ee643ff342b2a23caff453ddf9f70400f70f94be..22adb88b5ab38baa2f4c06bd5b212b37c4a8cb77 100644 --- a/core/src/main/resources/jenkins/model/Messages_fr.properties +++ b/core/src/main/resources/jenkins/model/Messages_fr.properties @@ -42,3 +42,7 @@ 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 +BlockedBecauseOfBuildInProgress.shortDescription=Le build #{0} est d\u00e9j\u00e0 en cours {1} +BlockedBecauseOfBuildInProgress.ETA=\ (fin pr\u00e9vue \u00e0: {0}) +BuildDiscarderProperty.displayName=Supprimer les anciens builds diff --git a/core/src/main/resources/jenkins/model/Messages_he.properties b/core/src/main/resources/jenkins/model/Messages_he.properties new file mode 100644 index 0000000000000000000000000000000000000000..cd432a7c6c5ea050398c58de4262ef54ba1d5c61 --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_he.properties @@ -0,0 +1 @@ +BuildDiscarderProperty.displayName=\u05D4\u05E9\u05DE\u05D3 \u05D1\u05E0\u05D9\u05D5\u05EA \u05D9\u05E9\u05E0\u05D5\u05EA 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 0000000000000000000000000000000000000000..5855bc949f4b77ebaaa2ad0140d7d6ab7b2e70f6 --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_hu.properties @@ -0,0 +1,2 @@ +ParameterizedJobMixIn.build_now=\u00C9p\u00EDt\u00E9s Most +BuildDiscarderProperty.displayName=R\u00E9gi \u00E9p\u00EDt\u00E9sek t\u00F6rl\u00E9se 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 0000000000000000000000000000000000000000..2267c9beb9d2b7f3f7ff5efed4ef2ad0d4ef5777 --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_it.properties @@ -0,0 +1,4 @@ +ParameterizedJobMixIn.build_now=Effettua build +BlockedBecauseOfBuildInProgress.shortDescription=Build #{0} is already in progress{1} +BlockedBecauseOfBuildInProgress.ETA=\ (ETA:{0}) +BuildDiscarderProperty.displayName=Elimina Build Precedenti diff --git a/core/src/main/resources/jenkins/model/Messages_ja.properties b/core/src/main/resources/jenkins/model/Messages_ja.properties index 115d02941b98d3b222a023a0f9be823b42d469fe..a881b1699e034737f8c60078584d5e731d907e4c 100644 --- a/core/src/main/resources/jenkins/model/Messages_ja.properties +++ b/core/src/main/resources/jenkins/model/Messages_ja.properties @@ -62,3 +62,8 @@ 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 +BlockedBecauseOfBuildInProgress.shortDescription=\u30d3\u30eb\u30c9 #{0} \u306f\u65e2\u306b\u5b9f\u884c\u4e2d\u3067\u3059\u3002{1} +BlockedBecauseOfBuildInProgress.ETA=\ (\u4e88\u5b9a\u6642\u9593:{0}) +BuildDiscarderProperty.displayName=\u53e4\u3044\u30d3\u30eb\u30c9\u306e\u7834\u68c4 diff --git a/core/src/main/resources/jenkins/model/Messages_ko.properties b/core/src/main/resources/jenkins/model/Messages_ko.properties new file mode 100644 index 0000000000000000000000000000000000000000..04b2ab8b4109b607cc818eeffdb33401bb4fa0ae --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_ko.properties @@ -0,0 +1 @@ +BuildDiscarderProperty.displayName=\uC624\uB798\uB41C \uBE4C\uB4DC \uC0AD\uC81C diff --git a/core/src/main/resources/jenkins/model/Messages_lt.properties b/core/src/main/resources/jenkins/model/Messages_lt.properties new file mode 100644 index 0000000000000000000000000000000000000000..4679c2595b0b10fbb2acec3de07567181a4512dc --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_lt.properties @@ -0,0 +1 @@ +BuildDiscarderProperty.displayName=Pa\u0161alinti senus darbus diff --git a/core/src/main/resources/jenkins/model/Messages_lv.properties b/core/src/main/resources/jenkins/model/Messages_lv.properties new file mode 100644 index 0000000000000000000000000000000000000000..b94712621426b8c5dd6bd2a74a9510d68e9a362e --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_lv.properties @@ -0,0 +1 @@ +BuildDiscarderProperty.displayName=Dz\u0113st vecos b\u016Bv\u0113jumus diff --git a/core/src/main/resources/jenkins/model/Messages_nb_NO.properties b/core/src/main/resources/jenkins/model/Messages_nb_NO.properties new file mode 100644 index 0000000000000000000000000000000000000000..317bc593783b345b0e27f8955c635fbc6f5d4403 --- /dev/null +++ b/core/src/main/resources/jenkins/model/Messages_nb_NO.properties @@ -0,0 +1 @@ +BuildDiscarderProperty.displayName=Slett gamle bygg diff --git a/core/src/main/resources/jenkins/model/Messages_nl.properties b/core/src/main/resources/jenkins/model/Messages_nl.properties index 6e0492c7620f3f7c3272d73cbbf1e9e316a8f9e5..80bb36bf42f5bc7c8e46ef72146fe4e6361726a1 100644 --- a/core/src/main/resources/jenkins/model/Messages_nl.properties +++ b/core/src/main/resources/jenkins/model/Messages_nl.properties @@ -30,3 +30,7 @@ Hudson.NoJavaInPath=java is niet beschikbaar op uw pad. Misschien moet je een + + + + + + + + + + diff --git a/core/src/main/resources/jenkins/mvn/Messages_bg.properties b/core/src/main/resources/jenkins/mvn/Messages_bg.properties new file mode 100644 index 0000000000000000000000000000000000000000..c74aae881b563f0dd4c0e5693c1de1a4d015b37a --- /dev/null +++ b/core/src/main/resources/jenkins/mvn/Messages_bg.properties @@ -0,0 +1,30 @@ +# The MIT License +# +# Bulgarian translation copyright 2015 Alexander Shopov . +# +# 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. + +DefaultSettingsProvider.DisplayName=\ + \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430 maven +DefaultGlobalSettingsProvider.DisplayName=\ + \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0438 \u0433\u043b\u043e\u0431\u0430\u043b\u043d\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430 maven +FilePathGlobalSettingsProvider.DisplayName=\ + \u0413\u043b\u043e\u0431\u0430\u043b\u043d\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043e\u0442 \u0444\u0430\u0439\u043b\u043e\u0432\u0430\u0442\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 +FilePathSettingsProvider.DisplayName=\ + \u0424\u0430\u0439\u043b \u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432\u044a\u0432 \u0444\u0430\u0439\u043b\u043e\u0432\u0430\u0442\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430 diff --git a/core/src/main/resources/jenkins/security/Messages.properties b/core/src/main/resources/jenkins/security/Messages.properties index fc71097d03319ea6664c5325a8535c65bd252c24..e09dca3e79758277e4fc1be3e1a943366d9053c2 100644 --- a/core/src/main/resources/jenkins/security/Messages.properties +++ b/core/src/main/resources/jenkins/security/Messages.properties @@ -21,5 +21,7 @@ # THE SOFTWARE. ApiTokenProperty.DisplayName=API Token -ApiTokenProperty.ChangeToken.Success=
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/core/src/main/resources/jenkins/security/Messages_bg.properties b/core/src/main/resources/jenkins/security/Messages_bg.properties new file mode 100644 index 0000000000000000000000000000000000000000..f11e5d4a0b37bd66577c1159b67d6b87958959dc --- /dev/null +++ b/core/src/main/resources/jenkins/security/Messages_bg.properties @@ -0,0 +1,33 @@ +# The MIT License +# +# Bulgarian translation copyright 2015 Alexander Shopov . +# +# 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. + +ApiTokenProperty.DisplayName=\ + \u041d\u0438\u0437 \u0437\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0437\u0430 API +ApiTokenProperty.ChangeToken.TokenIsHidden=\ + \u041d\u0438\u0437\u044a\u0442 \u0437\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0435 \u0441\u043a\u0440\u0438\u0442 +ApiTokenProperty.ChangeToken.Success=\ +
\u041f\u0440\u043e\u043c\u0435\u043d\u0435\u043d. \u041d\u043e\u0432\u0438\u044f\u0442 \u043d\u0438\u0437 \u0437\u0430 \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u0435 \u0432 \u043f\u043e\u043b\u0435\u0442\u043e \u043e\u0442\u0433\u043e\u0440\u0435
+ApiTokenProperty.ChangeToken.SuccessHidden=\ +
\u041f\u0440\u043e\u043c\u0435\u043d\u0435\u043d. \u0422\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0432\u043b\u0435\u0437\u0435\u0442\u0435 \u043a\u0430\u0442\u043e \u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0435\u043b\u044f, \u0437\u0430 \u0434\u0430 \u0432\u0438\u0434\u0438\u0442\u0435 \u043d\u0438\u0437\u0430 \u0437\u0430\ + \u0438\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f
+RekeySecretAdminMonitor.DisplayName=\ + \u0421\u044a\u0437\u0434\u0430\u0432\u0430\u043d\u0435 \u043d\u0430 \u043d\u043e\u0432 \u043a\u043b\u044e\u0447 diff --git a/core/src/main/resources/jenkins/security/s2m/AdminWhitelistRule/index_ja.properties b/core/src/main/resources/jenkins/security/s2m/AdminWhitelistRule/index_ja.properties new file mode 100644 index 0000000000000000000000000000000000000000..4b360251eb3569fc8ae93e88da0b54800f637f94 --- /dev/null +++ b/core/src/main/resources/jenkins/security/s2m/AdminWhitelistRule/index_ja.properties @@ -0,0 +1,25 @@ +# The MIT License +# +# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributers +# +# 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. + +Slave\ &\#8594;\ Master\ Access\ Control=\u30b9\u30ec\u30fc\u30d6 - \u30de\u30b9\u30bf\u9593 \u30a2\u30af\u30bb\u30b9\u5236\u5fa1 +Whitelist=\u30db\u30ef\u30a4\u30c8\u30ea\u30b9\u30c8 +Update=\u66f4\u65b0 diff --git a/core/src/main/resources/jenkins/security/s2m/AdminWhitelistRule/index_pt_BR.properties b/core/src/main/resources/jenkins/security/s2m/AdminWhitelistRule/index_pt_BR.properties index 708dd2f2e76540c1b6c44c01bdbf8e49f48ba58c..8ec4887e0ecc9cd7db2653157758908400ad7146 100644 --- a/core/src/main/resources/jenkins/security/s2m/AdminWhitelistRule/index_pt_BR.properties +++ b/core/src/main/resources/jenkins/security/s2m/AdminWhitelistRule/index_pt_BR.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributers +# Copyright (c) 2004-2015, Seiji Sogabe # # 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/core/src/main/resources/jenkins/security/s2m/filepath-filter.conf b/core/src/main/resources/jenkins/security/s2m/filepath-filter.conf index faa7cffa16235e5d7fc7ae7c9318d2cf52133086..c1883cc56295d1a4aa9940a04223fa989306a732 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/main/resources/jenkins/slaves/systemInfo/Messages_bg.properties b/core/src/main/resources/jenkins/slaves/systemInfo/Messages_bg.properties new file mode 100644 index 0000000000000000000000000000000000000000..7a8edaa248322a7a8d9cc4d5beb2aa161509aafd --- /dev/null +++ b/core/src/main/resources/jenkins/slaves/systemInfo/Messages_bg.properties @@ -0,0 +1,30 @@ +# The MIT License +# +# Bulgarian translation copyright 2015 Alexander Shopov . +# +# 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. + +SystemPropertySlaveInfo.DisplayName=\ + \u0418\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0437\u0430 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0442\u0430 +EnvVarsSlaveInfo.DisplayName=\ + \u041f\u0440\u043e\u043c\u0435\u043d\u043b\u0438\u0432\u0438 \u043d\u0430 \u0441\u0440\u0435\u0434\u0430\u0442\u0430 +ThreadDumpSlaveInfo.DisplayName=\ + \u0421\u044a\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u0438 \u0441\u0442\u0435\u043a\u043e\u0432\u0435 \u043d\u0430 \u043d\u0438\u0448\u043a\u0438\u0442\u0435 +ClassLoaderStatisticsSlaveInfo.DisplayName=\ + \u0421\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0430 \u043d\u0430 \u0437\u0430\u0440\u0435\u0436\u0434\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u043e\u0442\u0434\u0430\u043b\u0435\u0447\u0435\u043d\u0438 \u043a\u043b\u0430\u0441\u043e\u0432\u0435 diff --git a/core/src/main/resources/jenkins/triggers/Messages_bg.properties b/core/src/main/resources/jenkins/triggers/Messages_bg.properties new file mode 100644 index 0000000000000000000000000000000000000000..0037907e8a976dc2ca56c8311a8669996af9f00b --- /dev/null +++ b/core/src/main/resources/jenkins/triggers/Messages_bg.properties @@ -0,0 +1,27 @@ +# The MIT License +# +# Bulgarian translation copyright 2015 Alexander Shopov . +# +# 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. + +ReverseBuildTrigger.build_after_other_projects_are_built=\ + \u0418\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435 \u0441\u043b\u0435\u0434 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0434\u0440\u0443\u0433\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0438. +ReverseBuildTrigger.running_as_cannot_even_see_for_trigger_f=\ + \u041f\u0440\u043e\u0446\u0435\u0441, \u0440\u0430\u0431\u043e\u0442\u0435\u0449 \u0441 \u043f\u0440\u0430\u0432\u0430\u0442\u0430 \u043d\u0430 \u201e{0}\u201c \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0432\u0438\u0434\u0438 \u0437\u0430\u0434\u0430\u0447\u0430\u0442\u0430 \u201e{1}\u201c \u043e\u0442\ + \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u043e\u0442\u043e \u0438\u0437\u043f\u044a\u043b\u043d\u0435\u043d\u0438\u0435 \u043d\u0430 \u201e{2}\u201c. diff --git a/core/src/main/resources/jenkins/triggers/Messages_de.properties b/core/src/main/resources/jenkins/triggers/Messages_de.properties new file mode 100644 index 0000000000000000000000000000000000000000..e819499d8c4cde915829bdaba26c09888969560e --- /dev/null +++ b/core/src/main/resources/jenkins/triggers/Messages_de.properties @@ -0,0 +1,23 @@ +# The MIT License +# +# Copyright 2015 Harald Albers +# +# 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. + +ReverseBuildTrigger.build_after_other_projects_are_built=Starte Build, nachdem andere Projekte gebaut wurden diff --git a/core/src/main/resources/jenkins/triggers/Messages_ja.properties b/core/src/main/resources/jenkins/triggers/Messages_ja.properties new file mode 100644 index 0000000000000000000000000000000000000000..24f8bce1822fafeb31dce25f6419367ef3c744a4 --- /dev/null +++ b/core/src/main/resources/jenkins/triggers/Messages_ja.properties @@ -0,0 +1,24 @@ +# The MIT License +# +# Copyright 2015 Seiji Sogabe +# +# 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. + +ReverseBuildTrigger.build_after_other_projects_are_built=\u4ed6\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u306e\u5f8c\u306b\u30d3\u30eb\u30c9 +ReverseBuildTrigger.running_as_cannot_even_see_for_trigger_f=Running as {0} cannot even see {1} for trigger from {2} diff --git a/core/src/main/resources/jenkins/triggers/ReverseBuildTrigger/config_de.properties b/core/src/main/resources/jenkins/triggers/ReverseBuildTrigger/config_de.properties new file mode 100644 index 0000000000000000000000000000000000000000..764ba9822777472d82935c21773c929ff9a670d1 --- /dev/null +++ b/core/src/main/resources/jenkins/triggers/ReverseBuildTrigger/config_de.properties @@ -0,0 +1,26 @@ +# The MIT License +# +# Copyright (c) 2004-2015, Sun Microsystems, Inc., Kohsuke Kawaguchi, Simon Wiest +# +# 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. + +Projects\ to\ watch=Zu berwachende Projekte +Trigger\ only\ if\ build\ is\ stable=Nur auslsen, wenn der Build stabil ist +Trigger\ even\ if\ the\ build\ is\ unstable=Auslsen, selbst wenn der Build instabil ist +Trigger\ even\ if\ the\ build\ fails=Auslsen, selbst wenn der Build fehlschlgt \ No newline at end of file diff --git a/core/src/main/resources/jenkins/triggers/ReverseBuildTrigger/config_ja.properties b/core/src/main/resources/jenkins/triggers/ReverseBuildTrigger/config_ja.properties new file mode 100644 index 0000000000000000000000000000000000000000..377a8abc436e27bb9e1e283a72b0ead2d01da468 --- /dev/null +++ b/core/src/main/resources/jenkins/triggers/ReverseBuildTrigger/config_ja.properties @@ -0,0 +1,26 @@ +# The MIT License +# +# Copyright 2015 Seiji Sogabe +# +# 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. + +Projects\ to\ watch=\u5bfe\u8c61\u30d7\u30ed\u30b8\u30a7\u30af\u30c8 +Trigger\ only\ if\ build\ is\ stable=\u5b89\u5b9a\u3057\u3066\u3044\u308b\u5834\u5408\u306e\u307f\u8d77\u52d5 +Trigger\ even\ if\ the\ build\ is\ unstable=\u4e0d\u5b89\u5b9a\u3067\u3082\u8d77\u52d5 +Trigger\ even\ if\ the\ build\ fails=\u5931\u6557\u3057\u305f\u5834\u5408\u3067\u3082\u8d77\u52d5 diff --git a/core/src/main/resources/jenkins/widgets/BuildQueueWidget/index.groovy b/core/src/main/resources/jenkins/widgets/BuildQueueWidget/index.groovy index 94cccd7979e1336d9bcbeb8fb3161ffa0ca5957d..ae013561c731f279200176e245fe04c5bd70c258 100644 --- a/core/src/main/resources/jenkins/widgets/BuildQueueWidget/index.groovy +++ b/core/src/main/resources/jenkins/widgets/BuildQueueWidget/index.groovy @@ -2,4 +2,4 @@ package jenkins.widgets.BuildQueueWidget; def t = namespace(lib.JenkinsTagLib.class) -t.queue(items:view.approximateQueueItemsQuickly, it:view, filtered:view.filterQueue) +t.queue(items:view.queueItems, it:view, filtered:view.filterQueue) diff --git a/core/src/main/resources/jenkins/widgets/HistoryPageFilter/ajaxBuildHistory.jelly b/core/src/main/resources/jenkins/widgets/HistoryPageFilter/ajaxBuildHistory.jelly new file mode 100644 index 0000000000000000000000000000000000000000..6fdf095c515a066caf759207480b52cc7e230680 --- /dev/null +++ b/core/src/main/resources/jenkins/widgets/HistoryPageFilter/ajaxBuildHistory.jelly @@ -0,0 +1,41 @@ + + + + + + + + +
${%User}:
${%Password}:
+ +
+ + +
+
+ + +
\ No newline at end of file diff --git a/test/src/main/resources/org/jvnet/hudson/test/UnstableBuilder/config.jelly b/core/src/main/resources/jenkins/widgets/HistoryPageFilter/entries.jelly similarity index 86% rename from test/src/main/resources/org/jvnet/hudson/test/UnstableBuilder/config.jelly rename to core/src/main/resources/jenkins/widgets/HistoryPageFilter/entries.jelly index 9d137d24a0b893d9610c894370a04e80f25eaed2..622a838738fe7d97b7baa7c1e70bf9eb544842b3 100644 --- a/test/src/main/resources/org/jvnet/hudson/test/UnstableBuilder/config.jelly +++ b/core/src/main/resources/jenkins/widgets/HistoryPageFilter/entries.jelly @@ -23,4 +23,7 @@ THE SOFTWARE. --> - \ No newline at end of file + + + + \ No newline at end of file diff --git a/core/src/main/resources/jenkins/widgets/HistoryPageFilter/queue-items.jelly b/core/src/main/resources/jenkins/widgets/HistoryPageFilter/queue-items.jelly new file mode 100644 index 0000000000000000000000000000000000000000..be46285a1329341cf6e0878f05b698708b85e7c5 --- /dev/null +++ b/core/src/main/resources/jenkins/widgets/HistoryPageFilter/queue-items.jelly @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + +
+
+ +
+ +
+ #${queuedItems.size()==1 ? it.widget.owner.nextBuildNumber + : it.widget.owner.nextBuildNumber+queuedItems.size()-i-1} +
+
+
+
+
+ + + +
+
+
+ + +
+
+
diff --git a/core/src/main/resources/lib/form/class-entry.jelly b/core/src/main/resources/lib/form/class-entry.jelly index e03af3a754661f219fbe7e7c1695192eb1a601a3..16f139f91a3955f5b09fb11d4f72916c0fccf94e 100644 --- a/core/src/main/resources/lib/form/class-entry.jelly +++ b/core/src/main/resources/lib/form/class-entry.jelly @@ -26,6 +26,16 @@ THE SOFTWARE. xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form"> Invisible <f:entry> type for embedding a descriptor's $class field. + + Most of the time a Descriptor has an unique class name that we can use to instantiate the right Describable + class, so we use the '$class' to represent that to clarify the intent. + + In some other times, such as templates, there are multiple Descriptors with the same Descriptor.clazz + but different IDs, and in that case we put 'kind' to indicate that. In this case, to avoid confusing + readers we do not put non-unique '$class'. + + See Descriptor.newInstancesFromHeteroList for how the reader side is handled. + The describable class that we are instantiating via structured form submission. @@ -36,12 +46,14 @@ THE SOFTWARE. - - - - - - - + + + + + + + + + -
\ No newline at end of file + diff --git a/core/src/main/resources/lib/form/confirm.js b/core/src/main/resources/lib/form/confirm.js index d5948c3aa28c742ffb8d0cd3ae4b3883a4efba09..64f40eb26717c77113423101eeb4a2f839a82617 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/dropdownDescriptorSelector.jelly b/core/src/main/resources/lib/form/dropdownDescriptorSelector.jelly index aad0a87e5161d71d3cb99f8b05fe1c3d2cf9cb64..9004073739b52a47694d953223746a9da87bf6df 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,13 +56,14 @@ THE SOFTWARE. + + lazy="descriptor,it,${capture}"> - + diff --git a/core/src/main/resources/lib/form/enum.jelly b/core/src/main/resources/lib/form/enum.jelly index 667f0c10d2556da9cd81bf1f645b9a9d9044e77f..9cfb41829cdf62810b5cc519491bca06b2ed3f75 100644 --- a/core/src/main/resources/lib/form/enum.jelly +++ b/core/src/main/resources/lib/form/enum.jelly @@ -32,10 +32,13 @@ THE SOFTWARE. Used for databinding. TBD. + + The name of the enum to set as default value for the first configuration. + -
- -
- - - - -

${%Result}

-
-
+

${%Script Console}

+ + + +

+ ${%description} +

+ + +

+ ${%description2} +

+ +
+ +
+ +
+
+ + + +

${%Result}

+
+
+
+ + ${%It is not possible to run scripts when slave is offline.} + +
- \ No newline at end of file + diff --git a/core/src/main/resources/lib/hudson/scriptConsole.properties b/core/src/main/resources/lib/hudson/scriptConsole.properties index 518475dc89de11dad1d2a77774e0af89b2a4f5c0..69c972a938fdaec0a663588b57b826995f32c8ee 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 4593448d0097efb52f5803bb662db0de579df4a2..cf1afc4cbb27ea09e217b166ddddc0955dc3e17d 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 488a8941a9f57884b3cdb9a8ef6d5a754461631a..df68cd002f6b4f94ef4ac3cd284f148e66b98acd 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=Ausfhren -description=Geben Sie ein beliebiges Groovy-Skript \ +description=Geben Sie ein beliebiges Groovy-Skript \ ein und fhren Sie dieses auf dem Server aus. Dies ist ntzlich 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 9531839f146aa3c72fd321e1850da9bf944f2148..d7df2acb0d19b25f4559adf848b7eb57f2f22b8c 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 ms difcil 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 ea256983eb4cae91b993f990e6c2746d677e5119..6f17fa4ae47f4488324ef3dc4f67402c5b048754 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=Rsultat Run=Excuter -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 da54325180e398e7832f68436bdbb41e5b804530..136087823925c0b5dc5831f3c5ae9387f0d2cbf5 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 6e8c7a8bf99564a58757d95f367e7a2e5626bfa9..523c9f712664aeec1069dc144ab788c2f4c76aa9 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 524bfd281b04bcbc999f65e475169931db5f6b0e..ef03bcb2ec48b0841d7a5c0b127aad22d237b103 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 68b9130c6f38bdc9358edfbc6dd749b512814afd..263f9a0fa13106c6892d0c865c13d1fb72814e85 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 bb22871fb60c8cdc83a960cc33d42088efaf4e0c..666edf81bf48ab405d1f4f0c086d248483ea1c0a 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 04f4d0a53fefb54995b5cb970922eb1c7e3bbab3..9013530e50cded5a22648686010f78becd0dfd61 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 7149e33861877cd25df954871a983c3db1b89e72..b0b68ceaf595a26195f2a3f49e090406ea539d34 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 1710048f28de0d73f0176ab068bf6cdb5066af83..eb6893c691d2421dfd1f5baaed2a35b10ab60836 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 0a474875c71bbe6a9b154497d4a52ab7f101d52c..6e968873db38ed5d3866bd92f96c5351a7c6b9b0 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 diff --git a/core/src/main/resources/lib/layout/layout.jelly b/core/src/main/resources/lib/layout/layout.jelly index d41c186864523b581e31846848493c6b100d47ba..9746a6a1734af29dfcf7c017a424584c3343ad3e 100644 --- a/core/src/main/resources/lib/layout/layout.jelly +++ b/core/src/main/resources/lib/layout/layout.jelly @@ -69,11 +69,14 @@ ${h.initPageVariables(context)} + ${h.advertiseHeaders(response)} - - - + + + + + @@ -92,6 +95,7 @@ ${h.initPageVariables(context)} + @@ -126,9 +130,11 @@ ${h.initPageVariables(context)} + + + @@ -143,16 +149,18 @@ ${h.initPageVariables(context)} - - - + + + + + + +
+
+ + +
+ - - -
- +
- + + diff --git a/core/src/main/resources/lib/layout/pane.jelly b/core/src/main/resources/lib/layout/pane.jelly index 38d7e767b9e486b898fb829fdbf2e72c2804737b..5c8f19f41eb54938cb1d2d1df10d0a3a15fb1c7d 100644 --- a/core/src/main/resources/lib/layout/pane.jelly +++ b/core/src/main/resources/lib/layout/pane.jelly @@ -48,19 +48,20 @@ THE SOFTWARE. Footer of the box. Can include HTML. -
+ +
- +
${attrs.collapsedText}
diff --git a/core/src/main/resources/lib/layout/pane_ja.properties b/core/src/main/resources/lib/layout/pane_ja.properties new file mode 100644 index 0000000000000000000000000000000000000000..396d2754444c4ac7a0fa3b8f127fc7736c905583 --- /dev/null +++ b/core/src/main/resources/lib/layout/pane_ja.properties @@ -0,0 +1,23 @@ +# The MIT License +# +# Copyright (c) 2004-2015, Seiji Sogabe +# +# 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. + +expand=\u62e1\u5f35 diff --git a/core/src/main/resources/lib/layout/task.jelly b/core/src/main/resources/lib/layout/task.jelly index d95a3a395db3963832a954c8137ec2d370e36a96..fa08cc56fa1e9d517c0a9e8843cebca253e103d5 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. - + @@ -207,7 +207,7 @@ THE SOFTWARE. - + ${title} diff --git a/core/src/main/resources/windows-service/jenkins.xml b/core/src/main/resources/windows-service/jenkins.xml index 6e151b36ddc5dae3058d63f20820ecc7f8ca78e0..d677bacf0acb141d16e2eeee22a332909fc7c783 100644 --- a/core/src/main/resources/windows-service/jenkins.xml +++ b/core/src/main/resources/windows-service/jenkins.xml @@ -38,7 +38,7 @@ THE SOFTWARE. The following value assumes that you have java in your PATH. --> java - -Xrs -Xmx256m -Dhudson.lifecycle=hudson.lifecycle.WindowsServiceLifecycle -jar "%BASE%\jenkins.war" --httpPort=8080 + -Xrs -Xmx256m -Dhudson.lifecycle=hudson.lifecycle.WindowsServiceLifecycle -jar "%BASE%\jenkins.war" --httpPort=8080 --webroot="%BASE%\war" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ips/proto.py b/ips/proto.py deleted file mode 100644 index 1d4532074f761b3974f4a7d6eccc466d91067c86..0000000000000000000000000000000000000000 --- a/ips/proto.py +++ /dev/null @@ -1,51 +0,0 @@ -# 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. - - -# definition of the IPS package. -# see https://wikis.oracle.com/display/IpsBestPractices/Producing+and+Maintaining+Packages for more about this - -import builder; - -# IPS can't do SNAPSHOT -version = builder.props['version'] -if version.endswith("-SNAPSHOT"): - version = version[:-9]; - -pkg = builder.build_pkg(name="jenkins", version=version+",0-0") -pkg.update({ - "attributes" : { - "pkg.summary" : "Jenkins", - "pkg.description" : "Extensible continuous integration system", - } -}) - - -# restart_fmri instructs IPS to reload the manifest -pkg.addfile("/usr/local/bin/jenkins.war",{"file":"./target/jenkins.war"}) -pkg.addfile("/var/svc/manifest/application/jenkins.xml",{"file":"../ips/jenkins.xml","restart_fmri":"svc:/system/manifest-import:default"}) -# this is the Hudson home directory -pkg.mkdirs("/var/lib/jenkins") - -# TODO: register SMF when the feature is available? -# see http://www.pauloswald.com/article/29/hudson-solaris-smf-manifest -# see http://blogs.sun.com/wittyman/entry/postgresql_packages_from_ips_repository diff --git a/ips/readme.txt b/ips/readme.txt deleted file mode 100644 index 9de007a0003353daefef4ba7466c9fadfc1e48a7..0000000000000000000000000000000000000000 --- a/ips/readme.txt +++ /dev/null @@ -1,9 +0,0 @@ -This directory hosts files to create Solaris IPS packages. -To build, "mvn -P ips package" from the main/war directory. - - -Current status -============== -Auto-installation of SMF fails due to: - http://defect.opensolaris.org/bz/show_bug.cgi?id=5742 - http://defect.opensolaris.org/bz/show_bug.cgi?id=5743 diff --git a/licenseCompleter.groovy b/licenseCompleter.groovy index 802b266659efab05d42e465ab35c6d648fada130..3db5130ae3c1a38a35506bc8216fed65a931108c 100644 --- a/licenseCompleter.groovy +++ b/licenseCompleter.groovy @@ -72,12 +72,6 @@ complete { rewriteLicense([],jenkinsLicense) } - match(["org.jvnet.localizer:localizer"]) { - // see http://java.net/projects/localizer - // see http://java.net/projects/trilead-putty-extension/ - rewriteLicense([],mitLicense); - } - match("org.codehaus.plexus:plexus-interactivity-api") { rewriteLicense([],mitLicense) } diff --git a/msi/FindJava.java b/msi/FindJava.java deleted file mode 100644 index d6b2ebd9072f95e62771832232ab4e56e8ba464e..0000000000000000000000000000000000000000 --- a/msi/FindJava.java +++ /dev/null @@ -1,5 +0,0 @@ -public class FindJava { - public static void main(String[] args) { - System.out.print(System.getProperty("java.home")); - } -} diff --git a/msi/build-on-jenkins.sh b/msi/build-on-jenkins.sh deleted file mode 100755 index 2978890eefa33ab94e52ea197be7271e085a3e8a..0000000000000000000000000000000000000000 --- a/msi/build-on-jenkins.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -ex -if [ "$2" == "" ]; then - echo "Usage: build-on-jenkins path/to/war path/to/output/msi" - exit 1 -fi -tar cvzf bundle.tgz FindJava.java build.sh jenkins.wxs -v=$(unzip -p "$1" META-INF/MANIFEST.MF | grep Implementation-Version | cut -d ' ' -f2 | tr -d '\r') -java -jar jenkins-cli.jar dist-fork -z bundle.tgz -f jenkins.war="$1" -l windows -F "jenkins-$v.msi=$2" bash -ex build.sh jenkins.war - diff --git a/msi/build.sh b/msi/build.sh deleted file mode 100755 index ad8c962ba5665ab4612060472ee3db4c5d70420e..0000000000000000000000000000000000000000 --- a/msi/build.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -ex -export PATH=~/tools/native/wix:$PATH - -war="$1" -if [ ! -e "$war" ]; then - echo "build.sh path/to/jenkins.war" - exit 1 -fi - -rm -rf tmp || true -mkdir tmp || true -unzip -p "$war" 'WEB-INF/lib/jenkins-core-*.jar' > tmp/core.jar -unzip -p tmp/core.jar windows-service/jenkins.exe > tmp/jenkins.exe -unzip -p tmp/core.jar windows-service/jenkins.exe.config > tmp/jenkins.exe.config -unzip -p tmp/core.jar windows-service/jenkins.xml > tmp/jenkins.xm_ -# replace executable name to the bundled JRE -sed -e 's|executable.*|executable>%BASE%\\jre\\bin\\java|' < tmp/jenkins.xm_ > tmp/jenkins.xml - -# capture JRE -javac FindJava.java -JREDIR=$(java -cp . FindJava) -echo "JRE=$JREDIR" -heat dir "$JREDIR" -o jre.wxs -sfrag -sreg -nologo -srd -gg -cg JreComponents -dr JreDir -var var.JreDir - -# version -v=$(unzip -p "$war" META-INF/MANIFEST.MF | grep Implementation-Version | cut -d ' ' -f2 | tr -d '\r') -echo version=$v - -candle -dVERSION=$v -dJreDir="$JREDIR" -dWAR="$war" -nologo -ext WixUIExtension -ext WixUtilExtension jenkins.wxs jre.wxs -# '-sval' skips validation. without this, light somehow doesn't work on automated build environment -light -o jenkins-$v.msi -sval -nologo -dcl:high -ext WixUIExtension -ext WixUtilExtension jenkins.wixobj jre.wixobj - -# avoid bringing back files that we don't care -rm -rf tmp *.class *.wixpdb *.wixobj diff --git a/msi/jenkins.wxs b/msi/jenkins.wxs deleted file mode 100644 index 2c4995cae20da553b4c9f4abf9041f0eccc015b9..0000000000000000000000000000000000000000 --- a/msi/jenkins.wxs +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - 1 - - 1 - - 1 - - 1 - 1 - 1 - - - - NOT installed - - - - - - - - - - diff --git a/msi/readme.txt b/msi/readme.txt deleted file mode 100644 index 53e9ee7162fbe6660ac3ab82925c3ddff67329d1..0000000000000000000000000000000000000000 --- a/msi/readme.txt +++ /dev/null @@ -1,8 +0,0 @@ -TOOO: ask for installation directory and port number?` - -Runtime requirements: - - JRE - - WiX toolkit - -Digital signature - - generate .pfx format by using a tool from http://www.microsoft.com/downloads/details.aspx?FamilyID=F9992C94-B129-46BC-B240-414BDFF679A7&displaylang=EN diff --git a/msi/remote-execute.sh b/msi/remote-execute.sh deleted file mode 100644 index 95ee766b1722ab94656df50eb0a0d877cb6b9e15..0000000000000000000000000000000000000000 --- a/msi/remote-execute.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -ex -tar cvzf send.tgz FindJava.java build.sh jenkins.wxs -java -jar jenkins-cli.jar dist-fork -z send.tgz -l windows -f jenkins.war="$1" -Z result.tgz bash build.sh jenkins.war diff --git a/msi/sign.js b/msi/sign.js deleted file mode 100644 index 5220832cb2aa971fdaf91de2df0670ed8cc3860e..0000000000000000000000000000000000000000 --- a/msi/sign.js +++ /dev/null @@ -1,12 +0,0 @@ -// digitally sign an MSI file by the specified PKCS12 key - -var sc= new ActiveXObject('CAPICOM.SignedCode'); -var signer = new ActiveXObject('CAPICOM.Signer'); - -var args = WScript.Arguments; - -signer.Load(args(1)); -sc.FileName = args(0); -sc.Description = args(2); -sc.DescriptionURL = "http://jenkins-ci.org/"; -sc.Sign(signer); diff --git a/opensuse/SOURCES/jenkins.init.in b/opensuse/SOURCES/jenkins.init.in deleted file mode 100644 index c36d345ef1fa2a8c1d418f0056f1dcc47f185dc1..0000000000000000000000000000000000000000 --- a/opensuse/SOURCES/jenkins.init.in +++ /dev/null @@ -1,170 +0,0 @@ -#!/bin/sh -# -# SUSE system statup script for Jenkins -# Copyright (C) 2007 Pascal Bleser -# -# This library is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or (at -# your option) any later version. -# -# This library is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, -# USA. -# -### BEGIN INIT INFO -# Provides: jenkins -# Required-Start: $local_fs $remote_fs $network $named -# Should-Start: $time sendmail -# Required-Stop: $local_fs $remote_fs $network $named -# Should-Stop: $time sendmail -# Default-Start: 3 5 -# Default-Stop: 0 1 2 6 -# Short-Description: Jenkins continuous build server -# Description: Start the Jenkins continuous build server -### END INIT INFO - -# Check for missing binaries (stale symlinks should not happen) -JENKINS_WAR="@@WAR@@" -test -r "$JENKINS_WAR" || { echo "$JENKINS_WAR not installed"; - if [ "$1" = "stop" ]; then exit 0; - else exit 5; fi; } - -# Check for existence of needed config file and read it -JENKINS_CONFIG=/etc/sysconfig/jenkins -test -r "$JENKINS_CONFIG" || { echo "$JENKINS_CONFIG not existing"; - if [ "$1" = "stop" ]; then exit 0; - else exit 6; fi; } - -JENKINS_PID_FILE="/var/run/jenkins.pid" -JENKINS_USER="jenkins" -JENKINS_NICE="0" - -# Read config -. "$JENKINS_CONFIG" - -. /etc/rc.status -rc_reset # Reset status of this service - -# Set up environment accordingly to the configuration settings -[ -n "$JENKINS_HOME" ] || { echo "JENKINS_HOME not configured in $JENKINS_CONFIG"; - if [ "$1" = "stop" ]; then exit 0; - else exit 6; fi; } -[ -d "$JENKINS_HOME" ] || { echo "JENKINS_HOME directory does not exist: $JENKINS_HOME"; - if [ "$1" = "stop" ]; then exit 0; - else exit 1; fi; } - -if [ -z "$JENKINS_JAVA_HOME" ]; then - . /etc/profile.d/alljava.sh - [ -n "$JAVA_HOME" ] || { echo "Failed to determine JAVA_HOME, set JENKINS_JAVA_HOME in $JENKINS_CONFIG"; - if [ "$1" = "stop" ]; then exit 0; - else exit 6; fi; } -else - JAVA_HOME="$JENKINS_JAVA_HOME" -fi -[ -d "$JAVA_HOME" ] || { echo "Invalid JENKINS_JAVA_HOME: directory does not exist: $JAVA_HOME"; - if [ "$1" = "stop" ]; then exit 0; - else exit 6; fi; } -[ -e "$JAVA_HOME/bin/java" ] || { echo "Invalid JENKINS_JAVA_HOME: bin/java not found under $JAVA_HOME"; - if [ "$1" = "stop" ]; then exit 0; - else exit 6; fi; } -export JAVA_HOME - -JAVA_CMD="$JAVA_HOME/bin/java $JENKINS_JAVA_OPTIONS -DJENKINS_HOME=$JENKINS_HOME -jar $JENKINS_WAR" -PARAMS="--javaHome=$JAVA_HOME --logfile=/var/log/jenkins/jenkins.log --webroot=/var/cache/jenkins/war" -[ -n "$JENKINS_PORT" ] && PARAMS="$PARAMS --httpPort=$JENKINS_PORT" -[ -n "$JENKINS_AJP_PORT" ] && PARAMS="$PARAMS --ajp13Port=$JENKINS_AJP_PORT" -[ -n "$JENKINS_DEBUG_LEVEL" ] && PARAMS="$PARAMS --debug=$JENKINS_DEBUG_LEVEL" -[ -n "$JENKINS_HANDLER_STARTUP" ] && PARAMS="$PARAMS --handlerCountStartup=$JENKINS_HANDLER_STARTUP" -[ -n "$JENKINS_HANDLER_MAX" ] && PARAMS="$PARAMS --handlerCountMax=$JENKINS_HANDLER_MAX" -[ -n "$JENKINS_HANDLER_IDLE" ] && PARAMS="$PARAMS --handlerCountMaxIdle=$JENKINS_HANDLER_IDLE" -[ -n "$JENKINS_ARGS" ] && PARAMS="$PARAMS $JENKINS_ARGS" - -if [ "$JENKINS_ENABLE_ACCESS_LOG" = "yes" ]; then - PARAMS="$PARAMS --accessLoggerClassName=winstone.accesslog.SimpleAccessLogger --simpleAccessLogger.format=combined --simpleAccessLogger.file=/var/log/jenkins/access_log" -fi - -[ -z "$JENKINS_INIT_SHELL" -o -x "$JENKINS_INIT_SHELL" ] || { echo "JENKINS_INIT_SHELL does not refer to a shell: $JENKINS_INIT_SHELL"; - if [ "$1" = "stop" ]; then exit 0; - else exit 6; fi; } - -case "$1" in - start) - echo -n "Starting Jenkins " - /sbin/checkproc -k -p "$JENKINS_PID_FILE" "$JAVA_HOME/bin/java" >/var/log/jenkins.rc 2>&1 - CHECK=$? - if [ $CHECK -eq 7 ]; then - rm -f "$JENKINS_PID_FILE" - if [ -x "$JENKINS_INIT_SHELL" ]; then - startproc -n $JENKINS_NICE -s -e -l /var/log/jenkins.rc -p "$JENKINS_PID_FILE" -t 1 /bin/su -l -s "$JENKINS_INIT_SHELL" -c "$JAVA_CMD $PARAMS &" "$JENKINS_USER" - else - HOME=$JENKINS_HOME startproc -n $JENKINS_NICE -s -e -l /var/log/jenkins.rc -u "$JENKINS_USER" -p "$JENKINS_PID_FILE" $JAVA_CMD $PARAMS - fi - JPROC=$( find /proc -maxdepth 2 -user $JENKINS_USER -name exe -lname "*/bin/java" ) - if [ -n "$JPROC" ]; then - basename `dirname $JPROC` >"$JENKINS_PID_FILE" - rc_status -v - else - rc_failed - rc_status -v - fi - else - rc_failed $CHECK - rc_status -v - fi - ;; - stop) - echo -n "Shutting down Jenkins " - /sbin/killproc -p "$JENKINS_PID_FILE" "$JAVA_HOME/bin/java" - rc_status -v - ;; - try-restart|condrestart) - if test "$1" = "condrestart"; then - echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}" - fi - $0 status - if test $? = 0; then - $0 restart - else - rc_reset # Not running is not a failure. - fi - rc_status - ;; - restart) - $0 stop - $0 start - rc_status - ;; - force-reload) - echo -n "Reload service Jenkins " - $0 try-restart - rc_status - ;; - reload) - rc_failed 3 - rc_status -v - ;; - status) - echo -n "Checking for service Jenkins " - /sbin/checkproc -p "$JENKINS_PID_FILE" "$JAVA_HOME/bin/java" - rc_status -v - ;; - probe) - ## Optional: Probe for the necessity of a reload, print out the - ## argument to this init script which is required for a reload. - ## Note: probe is not (yet) part of LSB (as of 1.9) - - test "$JENKINS_CONFIG" -nt "$JENKINS_PID_FILE" && echo reload - ;; - *) - echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}" - exit 1 - ;; -esac -rc_exit diff --git a/opensuse/SOURCES/jenkins.logrotate b/opensuse/SOURCES/jenkins.logrotate deleted file mode 100644 index c067b57b818d53591707d6ef45e59d72e6bcd34a..0000000000000000000000000000000000000000 --- a/opensuse/SOURCES/jenkins.logrotate +++ /dev/null @@ -1,17 +0,0 @@ -/var/log/jenkins/jenkins.log /var/log/jenkins/access_log { - compress - dateext - maxage 365 - rotate 99 - size=+4096k - notifempty - missingok - create 644 - postrotate - [ -r /etc/sysconfig/jenkins ] && source /etc/sysconfig/jenkins - if [ -s /var/run/jenkins.pid ]; then - JPID=`cat /var/run/jenkins.pid` - test -n "`find /proc/$JPID -maxdepth 0 -user ${JENKINS_USER:-jenkins} 2>/dev/null`" && kill -s ALRM $JPID || : - fi - endscript -} diff --git a/opensuse/SOURCES/jenkins.repo.in b/opensuse/SOURCES/jenkins.repo.in deleted file mode 100644 index 2981b8a2e249400d98fa68407be4bcff7aee78c6..0000000000000000000000000000000000000000 --- a/opensuse/SOURCES/jenkins.repo.in +++ /dev/null @@ -1,7 +0,0 @@ -[jenkins] -name=jenkins -enabled=1 -autorefresh=0 -baseurl=@URL@ -type=rpm-md -keeppackages=0 diff --git a/opensuse/SOURCES/jenkins.sysconfig.in b/opensuse/SOURCES/jenkins.sysconfig.in deleted file mode 100644 index 2893f3a01a464690916e8205f2dc170f298aa11e..0000000000000000000000000000000000000000 --- a/opensuse/SOURCES/jenkins.sysconfig.in +++ /dev/null @@ -1,119 +0,0 @@ -## Path: Development/Jenkins -## Description: Configuration for the Jenkins continuous build server -## Type: string -## Default: "@@HOME@@" -## ServiceRestart: jenkins -# -# Directory where Jenkins store its configuration and working -# files (checkouts, build reports, artifacts, ...). -# -JENKINS_HOME="@@HOME@@" - -## Type: string -## Default: "/bin/bash" -## ServiceRestart: jenkins -# -# Shell used to initialize the Jenkins server's environment. -# Setting this option to the path of a shell executable allows -# initialization of the Jenkins server environment using -# standard shell startup scripts. -# Disabling this option causes the Jenkins server to be run -# with a minimal environment. -# -JENKINS_INIT_SHELL="/bin/bash" - -## Type: string -## Default: "" -## ServiceRestart: jenkins -# -# Java runtime to run Jenkins -# When left empty, the current system default JRE, as defined -# by update-alternatives(8), is used. -# -JENKINS_JAVA_HOME="" - -## Type: string -## Default: "jenkins" -## ServiceRestart: jenkins -# -# Unix user account that runs the Jenkins daemon -# Be careful when you change this, as you need to update -# permissions of $JENKINS_HOME and /var/log/jenkins. -# -JENKINS_USER="jenkins" - -## Type: integer(-20:20) -## Default: 0 -## ServiceRestart: jenkins -# -# The nice level at which the Jenkins server (and its build jobs) run. -# -JENKINS_NICE="0" - -## Type: string -## Default: "-Djava.awt.headless=true" -## ServiceRestart: jenkins -# -# Options to pass to java when running Jenkins. -# -JENKINS_JAVA_OPTIONS="-Djava.awt.headless=true" - -## Type: integer(0:65535) -## Default: 8080 -## ServiceRestart: jenkins -# -# Port Jenkins is listening on. -# Set to -1 to disable -# -JENKINS_PORT="8080" - -## Type: integer(0:65535) -## Default: 8009 -## ServiceRestart: jenkins -# -# Ajp13 Port Jenkins is listening on. -# Set to -1 to disable -# -JENKINS_AJP_PORT="8009" - -## Type: integer(1:9) -## Default: 5 -## ServiceRestart: jenkins -# -# Debug level for logs -- the higher the value, the more verbose. -# 5 is INFO. -# -JENKINS_DEBUG_LEVEL="5" - -## Type: yesno -## Default: no -## ServiceRestart: jenkins -# -# Whether to enable access logging or not. -# -JENKINS_ENABLE_ACCESS_LOG="no" - -## Type: integer -## Default: 100 -## ServiceRestart: jenkins -# -# Maximum number of HTTP worker threads. -# -JENKINS_HANDLER_MAX="100" - -## Type: integer -## Default: 20 -## ServiceRestart: jenkins -# -# Maximum number of idle HTTP worker threads. -# -JENKINS_HANDLER_IDLE="20" - -## Type: string -## Default: "" -## ServiceRestart: jenkins -# -# Pass arbitrary arguments to Jenkins. -# Full option list: java -jar jenkins.war --help -# -JENKINS_ARGS="" diff --git a/opensuse/SPECS/jenkins.spec b/opensuse/SPECS/jenkins.spec deleted file mode 100644 index edc81bf3e1f9d3fb8167c652b5f57f1b222c7f39..0000000000000000000000000000000000000000 --- a/opensuse/SPECS/jenkins.spec +++ /dev/null @@ -1,141 +0,0 @@ -# TODO: -# - how to add to the trusted service of the firewall? - -%define _prefix %{_usr}/lib/jenkins -%define workdir %{_var}/lib/jenkins - -Name: jenkins -Version: %{ver} -Release: 1.2 -Summary: Continous Build Server -Source: jenkins.war -Source1: jenkins.init.in -Source2: jenkins.sysconfig.in -Source3: jenkins.logrotate -Source4: jenkins.repo -URL: http://jenkins-ci.org/ -Group: Development/Tools/Building -License: MIT/X License, GPL/CDDL, ASL2 -BuildRoot: %{_tmppath}/build-%{name}-%{version} -# see the comment below from java-1.6.0-openjdk.spec that explains this dependency -# java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons, -# and this change was brought into RHEL-4. java-1.5.0-ibm packages -# also included the epoch in their virtual provides. This created a -# situation where in-the-wild java-1.5.0-ibm packages provided "java = -# 1:1.5.0". In RPM terms, "1.6.0 < 1:1.5.0" since 1.6.0 is -# interpreted as 0:1.6.0. So the "java >= 1.6.0" requirement would be -# satisfied by the 1:1.5.0 packages. Thus we need to set the epoch in -# JDK package >= 1.6.0 to 1, and packages referring to JDK virtual -# provides >= 1.6.0 must specify the epoch, "java >= 1:1.6.0". -# -# java-1_6_0-sun provides this at least -Requires: java >= 1.6 -Obsoletes: hudson -PreReq: /usr/sbin/groupadd /usr/sbin/useradd -#PreReq: %{fillup_prereq} -BuildArch: noarch - -%description -Jenkins monitors executions of repeated jobs, such as building a software -project or jobs run by cron. Among those things, current Jenkins focuses on the -following two jobs: -- Building/testing software projects continuously, just like CruiseControl or - DamageControl. In a nutshell, Jenkins provides an easy-to-use so-called - continuous integration system, making it easier for developers to integrate - changes to the project, and making it easier for users to obtain a fresh - build. The automated, continuous build increases the productivity. -- Monitoring executions of externally-run jobs, such as cron jobs and procmail - jobs, even those that are run on a remote machine. For example, with cron, - all you receive is regular e-mails that capture the output, and it is up to - you to look at them diligently and notice when it broke. Jenkins keeps those - outputs and makes it easy for you to notice when something is wrong. - - - - -Authors: --------- - Kohsuke Kawaguchi - -%prep -%setup -q -T -c - -%build - -%install -rm -rf "%{buildroot}" -%__install -D -m0644 "%{SOURCE0}" "%{buildroot}%{_prefix}/%{name}.war" -%__install -d "%{buildroot}%{workdir}" -%__install -d "%{buildroot}%{workdir}/plugins" - -%__install -d "%{buildroot}/var/log/jenkins" -%__install -d "%{buildroot}/var/cache/jenkins" - -%__install -D -m0755 "%{SOURCE1}" "%{buildroot}/etc/init.d/%{name}" -%__sed -i 's,@@WAR@@,%{_prefix}/%{name}.war,g' "%{buildroot}/etc/init.d/%{name}" -%__install -d "%{buildroot}/usr/sbin" -%__ln_s "../../etc/init.d/%{name}" "%{buildroot}/usr/sbin/rc%{name}" - -%__install -D -m0644 "%{SOURCE2}" "%{buildroot}/etc/sysconfig/%{name}" -%__sed -i 's,@@HOME@@,%{workdir},g' "%{buildroot}/etc/sysconfig/%{name}" - -%__install -D -m0644 "%{SOURCE3}" "%{buildroot}/etc/logrotate.d/%{name}" - -%__install -D -m0644 "%{SOURCE4}" "%{buildroot}/etc/zypp/repos.d/jenkins.repo" -%pre -/usr/sbin/groupadd -r jenkins &>/dev/null || : -# SUSE version had -o here, but in Fedora -o isn't allowed without -u -/usr/sbin/useradd -g jenkins -s /bin/false -r -c "Jenkins Continuous Build server" \ - -d "%{workdir}" jenkins &>/dev/null || : - -%post -[ $1 -eq 1 ] && /sbin/chkconfig --add jenkins - -# If we have an old hudson install, rename it to jenkins -if test -d /var/lib/hudson; then - # leave a marker to indicate this came from Hudson. - # could be useful down the road - # This also ensures that the .??* wildcard matches something - touch /var/lib/hudson/.moving-hudson - mv -f /var/lib/hudson/* /var/lib/hudson/.??* /var/lib/jenkins - rmdir /var/lib/hudson - find /var/lib/jenkins -user hudson -exec chown jenkins {} + || true -fi -if test -d /var/run/hudson; then - mv -f /var/run/hudson/* /var/run/jenkins - rmdir /var/run/hudson -fi - -%preun -if [ "$1" = 0 ] ; then - # if this is uninstallation as opposed to upgrade, delete the service - /sbin/service jenkins stop > /dev/null 2>&1 - /sbin/chkconfig --del jenkins -fi -exit 0 - -%postun -if [ "$1" -ge 1 ]; then - /sbin/service jenkins condrestart > /dev/null 2>&1 -fi -exit 0 - -%clean -%__rm -rf "%{buildroot}" - -%files -%defattr(-,root,root) -%dir %{_prefix} -%{_prefix}/%{name}.war -%attr(0755,jenkins,jenkins) %dir %{workdir} -%attr(0750,jenkins,jenkins) /var/log/jenkins -%attr(0750,jenkins,jenkins) /var/cache/jenkins -%config(noreplace) /etc/logrotate.d/%{name} -%config /etc/init.d/%{name} -%config(noreplace) /etc/sysconfig/%{name} -%config(noreplace) /etc/zypp/repos.d/jenkins.repo -/usr/sbin/rc%{name} - -%changelog -* Wed Sep 28 2011 kk@kohsuke.org -- See [http://jenkins-ci.org/changelog] for complete details diff --git a/opensuse/build.sh b/opensuse/build.sh deleted file mode 100755 index f543cde44c8e4989c2d3d7286e464a14f78d2221..0000000000000000000000000000000000000000 --- a/opensuse/build.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -e -if [ -z "$1" ]; then - echo "Usage: build.sh path/to/jenkins.war [version]" - exit 1 -fi - -# figure out the version to package -cp "$1" $(dirname $0)/SOURCES/jenkins.war -pushd $(dirname $0) -if [ -z "$2" ]; then - version=$(unzip -p SOURCES/jenkins.war META-INF/MANIFEST.MF | grep Implementation-Version | cut -d ' ' -f2 | tr - .) -else - version="$2" -fi -echo Version is $version - -# prepare fresh directories -rm -rf BUILD RPMS SRPMS tmp || true -mkdir -p BUILD RPMS SRPMS - -cat SOURCES/jenkins.repo.in | sed -e "s#@URL@#${SUSE_URL}/#g" > SOURCES/jenkins.repo - -# real action happens here -rpmbuild -ba --define="_topdir $PWD" --define="_tmppath $PWD/tmp" --define="ver $version" SPECS/jenkins.spec diff --git a/opensuse/readme.html b/opensuse/readme.html deleted file mode 100644 index 2b7a18da2a34bba22a5513ef3d617189786668c4..0000000000000000000000000000000000000000 --- a/opensuse/readme.html +++ /dev/null @@ -1,10 +0,0 @@ -

Jenkins RPM for openSUSE

-

-To use this repository, run the following command: - -

-sudo zypper addrepo http://pkg.jenkins-ci.org/opensuse/ jenkins
-
- -

-With that set up, the Jenkins package can be installed with zypper install jenkins diff --git a/osx/JenkinsInstaller.pmdoc/01jenkins-contents.xml b/osx/JenkinsInstaller.pmdoc/01jenkins-contents.xml deleted file mode 100644 index 3248aa522ecf50a89ec0e6acf29b981c904663a9..0000000000000000000000000000000000000000 --- a/osx/JenkinsInstaller.pmdoc/01jenkins-contents.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/osx/JenkinsInstaller.pmdoc/01jenkins.xml b/osx/JenkinsInstaller.pmdoc/01jenkins.xml deleted file mode 100644 index f08f32b8398654d767dc1c470e7bdfe6b4d4a68e..0000000000000000000000000000000000000000 --- a/osx/JenkinsInstaller.pmdoc/01jenkins.xml +++ /dev/null @@ -1 +0,0 @@ -org.jenkins-ci.jenkins.osx.pkg1.1405/path/to/jenkins.war/Applications/JenkinsdiscardResourceForksinstallFrom.isAbsoluteTypescripts.postinstall.isAbsoluteTypeinstallToscripts.postinstall.pathscripts.postinstall.isRelativeTypeinstallFrom.isRelativeTypeversionparentscripts.scriptsDirectoryPath.pathrequireAuthorizationidentifierinstallFrom.pathextraFilesinstallTo.pathpostInstallscripts/postinstall-war01jenkins-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ \ No newline at end of file diff --git a/osx/JenkinsInstaller.pmdoc/02org-contents.xml b/osx/JenkinsInstaller.pmdoc/02org-contents.xml deleted file mode 100644 index d652a7a46939181bc59b51c578ec6df1239f9c50..0000000000000000000000000000000000000000 --- a/osx/JenkinsInstaller.pmdoc/02org-contents.xml +++ /dev/null @@ -1 +0,0 @@ -groupowner \ No newline at end of file diff --git a/osx/JenkinsInstaller.pmdoc/02org.xml b/osx/JenkinsInstaller.pmdoc/02org.xml deleted file mode 100644 index 4108d65edb6a5df3266edc9ad4eaa692fc1f7409..0000000000000000000000000000000000000000 --- a/osx/JenkinsInstaller.pmdoc/02org.xml +++ /dev/null @@ -1 +0,0 @@ -org.jenkins-ci.launchd.pkg1.0launchd_conf_daemon/org.jenkins-ci.plist/Library/LaunchDaemonsinstallFrom.isRelativeTypeinstallToscripts.scriptsDirectoryPath.pathscripts.preinstall.isRelativeTypeidentifierparentscripts.scriptsDirectoryPath.isAbsoluteTypeinstallTo.pathscripts.postinstall.isRelativeTypescripts.scriptsDirectoryPath.isRelativeTypescripts/preinstall-launchdscripts/postinstall-launchd02org-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ \ No newline at end of file diff --git a/osx/JenkinsInstaller.pmdoc/03jenkins-contents.xml b/osx/JenkinsInstaller.pmdoc/03jenkins-contents.xml deleted file mode 100644 index 0214650b482058f3da94ea4599cc12673a73dab2..0000000000000000000000000000000000000000 --- a/osx/JenkinsInstaller.pmdoc/03jenkins-contents.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - group - owner - - diff --git a/osx/JenkinsInstaller.pmdoc/03jenkins.xml b/osx/JenkinsInstaller.pmdoc/03jenkins.xml deleted file mode 100644 index 7f6b6869d32e6e1868a92f9a1c4ffa70f3c08fb9..0000000000000000000000000000000000000000 --- a/osx/JenkinsInstaller.pmdoc/03jenkins.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - org.jenkins-ci.support.pkg - 1.0 - - - - Library/Application Support/Jenkins - /Library/Application Support - - - - - installTo.path - installFrom.isRelativeType - identifier - includeRoot - parent - installTo - - - 03jenkins-contents.xml - /CVS$ - /\.svn$ - /\.cvsignore$ - /\.cvspass$ - /\.DS_Store$ - - diff --git a/osx/JenkinsInstaller.pmdoc/04jenkins-contents.xml b/osx/JenkinsInstaller.pmdoc/04jenkins-contents.xml deleted file mode 100644 index 447a50de76e1ba7e395ff481ced9bb7d957031fa..0000000000000000000000000000000000000000 --- a/osx/JenkinsInstaller.pmdoc/04jenkins-contents.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/osx/JenkinsInstaller.pmdoc/04jenkins.xml b/osx/JenkinsInstaller.pmdoc/04jenkins.xml deleted file mode 100644 index ee366210efbbdd614f19034985c8ea2dd2b2cdd3..0000000000000000000000000000000000000000 --- a/osx/JenkinsInstaller.pmdoc/04jenkins.xml +++ /dev/null @@ -1 +0,0 @@ -org.jenkins-ci.documentation.pkg1.0Library/Documentation/Jenkins/Library/DocumentationinstallTo.pathinstallFrom.isRelativeTypeinstallToparentincludeRootidentifier04jenkins-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ \ No newline at end of file diff --git a/osx/JenkinsInstaller.pmdoc/05org-contents.xml b/osx/JenkinsInstaller.pmdoc/05org-contents.xml deleted file mode 100644 index bbe68015d61936b6c89003cf87f022d441805def..0000000000000000000000000000000000000000 --- a/osx/JenkinsInstaller.pmdoc/05org-contents.xml +++ /dev/null @@ -1 +0,0 @@ -groupowner \ No newline at end of file diff --git a/osx/JenkinsInstaller.pmdoc/05org.xml b/osx/JenkinsInstaller.pmdoc/05org.xml deleted file mode 100644 index d5980f2d4bafed4cc786c6b416ea84a503694384..0000000000000000000000000000000000000000 --- a/osx/JenkinsInstaller.pmdoc/05org.xml +++ /dev/null @@ -1 +0,0 @@ -org.jenkins-ci.launchd-jenkins.pkg1.0launchd_conf_jenkins/org.jenkins-ci.plist/Library/LaunchDaemonsinstallToscripts.preinstall.isRelativeTypeidentifierparentinstallTo.pathinstallFrom.isRelativeTypescripts.postinstall.isRelativeTypescripts/preinstall-launchdscripts/postinstall-launchd-jenkins05org-contents.xml/CVS$/\.svn$/\.cvsignore$/\.cvspass$/\.DS_Store$ \ No newline at end of file diff --git a/osx/JenkinsInstaller.pmdoc/index.xml b/osx/JenkinsInstaller.pmdoc/index.xml deleted file mode 100644 index 5acb3b2b066e787fe7f41d803db57c1cdd3f8178..0000000000000000000000000000000000000000 --- a/osx/JenkinsInstaller.pmdoc/index.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - Jenkins CI Server - /Users/irichter/Desktop/Jenkins.pkg - org.jenkins-ci - - - - - - - - - The Jenkins continuous integration server. - - - - - - - - - - - - - - - - - - - - artwork/banner-200.png - docs/Jenkins-LICENSE.txt - docs/JenkinsWelcomePanel.rtf - - - - - /System/Library/Frameworks/JavaVM.framework/Versions/A/Commands/java - Java Runtime Not Found - You need Java runtime to run Jenkins. Open /Applications/Utilities/Java Preferences, install Java and then run this installer again. - - - - - - http://localhost:8080/ - - - - 01jenkins.xml - 02org.xml - 03jenkins.xml - 04jenkins.xml - 05org.xml - description - properties.title - properties.systemDomain - properties.userDomain - properties.customizeOption - extraFiles - postinstallActions.actions - properties.anywhereDomain - diff --git a/osx/Library/Application Support/Jenkins/Uninstall.command b/osx/Library/Application Support/Jenkins/Uninstall.command deleted file mode 100755 index 160a1c62c5b444a2b6bcb3d3adfb9acf8020380e..0000000000000000000000000000000000000000 --- a/osx/Library/Application Support/Jenkins/Uninstall.command +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -echo -echo -echo "Jenkins uninstallation script" -echo -echo "The following commands are executed using sudo, so you need to be logged" -echo "in as an administrator. Please provide your password when prompted." -echo -set -x -sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plist -sudo rm /Library/LaunchDaemons/org.jenkins-ci.plist -sudo rm -rf /Applications/Jenkins "/Library/Application Support/Jenkins" /Library/Documentation/Jenkins -sudo rm -rf /Users/Shared/Jenkins -sudo rm -rf /var/log/jenkins -sudo rm -f /etc/newsyslog.d/jenkins.conf -sudo dscl . -delete /Users/jenkins -sudo dscl . -delete /Groups/jenkins -pkgutil --pkgs | grep 'org\.jenkins-ci\.' | xargs -n 1 sudo pkgutil --forget -set +x -echo -echo "Jenkins has been uninstalled." diff --git a/osx/Library/Application Support/Jenkins/jenkins-runner.sh b/osx/Library/Application Support/Jenkins/jenkins-runner.sh deleted file mode 100755 index c50fb6364b0977f96fdfed8e8f1f1eaf0ab5f19b..0000000000000000000000000000000000000000 --- a/osx/Library/Application Support/Jenkins/jenkins-runner.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -# -# Startup script used by Jenkins launchd job. -# Mac OS X launchd process calls this script to customize -# the java process command line used to run Jenkins. -# -# Customizable parameters are found in -# /Library/Preferences/org.jenkins-ci.plist -# -# You can manipulate it using the "defaults" utility. -# See "man defaults" for details. - -defaults="defaults read /Library/Preferences/org.jenkins-ci" - -war=`$defaults war` || war="/Applications/Jenkins/jenkins.war" - -javaArgs="-Dfile.encoding=UTF-8" - -minPermGen=`$defaults minPermGen` && javaArgs="$javaArgs -XX:PermSize=${minPermGen}" -permGen=`$defaults permGen` && javaArgs="$javaArgs -XX:MaxPermSize=${permGen}" - -minHeapSize=`$defaults minHeapSize` && javaArgs="$javaArgs -Xms${minHeapSize}" -heapSize=`$defaults heapSize` && javaArgs="$javaArgs -Xmx${heapSize}" - -tmpdir=`$defaults tmpdir` && javaArgs="$javaArgs -Djava.io.tmpdir=${tmpdir}" - -home=`$defaults JENKINS_HOME` && export JENKINS_HOME="$home" - -add_to_args() { - val=`$defaults $1` && args="$args --${1}=${val}" -} - -args="" -add_to_args prefix -add_to_args httpPort -add_to_args httpListenAddress -add_to_args httpsPort -add_to_args httpsListenAddress -add_to_args ajp13Port -add_to_args ajp13ListenAddress - -echo "JENKINS_HOME=$JENKINS_HOME" -echo "Jenkins command line for execution:" -echo /usr/bin/java $javaArgs -jar "$war" $args -exec /usr/bin/java $javaArgs -jar "$war" $args diff --git a/osx/Library/Documentation/Jenkins/command-line-preferences.html b/osx/Library/Documentation/Jenkins/command-line-preferences.html deleted file mode 100644 index 3031cca012e357fddea6ae741af813cb7e16a5dd..0000000000000000000000000000000000000000 --- a/osx/Library/Documentation/Jenkins/command-line-preferences.html +++ /dev/null @@ -1,55 +0,0 @@ - - -Jenkins command-line preferences - - -

Jenkins command-line preferences

- -

The Jenkins Wiki page tells you how to change settings like which port number Jenkins will listen to. These settings need to be specified on the command line when Jenkins is started. - -

Launch daemon

- -

For the Mac, Jenkins is deployed as a launch daemon. (If you want to know more about launchd and daemons, see here and here) - -

The launch daemon picks up the command line options from a standard preferences file, /Library/Preferences/org.jenkins-ci.plist. If the file does not exist, built-in defaults are used. The preference files are manipulated using the standard utility defaults. - -

How To Use the defaults Command

- -

To view all settings in the file, run: -defaults read /Library/Preferences/org.jenkins-ci - -

To get the value of a single setting, run: -defaults read /Library/Preferences/org.jenkins-ci SETTING - -

To set the value of a setting, run: -defaults write /Library/Preferences/org.jenkins-ci SETTING VALUE - -

For more information, see man defaults - -

Supported Settings

- -

The list of settings supported by the Jenkins launch daemon (see documentation): - -

    -
  • prefix -
  • httpPort -
  • httpListenAddress -
  • httpsPort -
  • httpsListenAddress -
  • ajp13Port -
  • ajp13ListenAddress -
- -

Additionally, you can set also these: - -

    -
  • war (Full path name to jenkins.war file. Defaults to /Applications/Jenkins/jenkins.war) -
  • JENKINS_HOME (Full path to JENKINS_HOME directory where Jenkins keeps its files. Defaults to /Users/Shared/Jenkins) -
  • minHeapSize (Passed to java command-line -Xms parameter. Defaults to 256m on 64bit architectures and 64m on 32bit) -
  • heapSize (Passed to java command-line -Xmx parameter. Defaults to 512m on 64bit architectures and 128m on 32bit) -
  • minPermGen (Passed to java command-line -XX:PermSize parameter. Defaults to 256m on 64bit architectures and 64m on 32bit) -
  • permGen (Passed to java command-line -XX:MaxPermSize parameter. Defaults to 512m on 64bit architectures and 128m on 32bit) -
- - - diff --git a/osx/README.md b/osx/README.md deleted file mode 100644 index fb20366e16de8021138377fac9ebdce403092a22..0000000000000000000000000000000000000000 --- a/osx/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Jenkins OS X Installer Project - -To create the Jenkins Installer for OS X you need an OS X machine with Developer Tools installed. -You can download the Developer Tools from [Apple's Developer Connection website](http://developer.apple.com) - -## Build the Installer - -To build the installer package you will need a copy of the jenkins.war file. You can download it from the -[Jenkins home page](http://mirrors.jenkins-ci.org/war/latest/). Then open a terminal, navigate to this -directory, and run the build script - - ./build.sh /path/to/jenkins.war - -## Some Links - -* [Jenkins](http://jenkins-ci.org) -* [Apple Developer Center](http://www.developer.apple.com) - -## License - - Original Copyright (C) 2011 by Ingo Richter - Portions Copyright (C) 2011 by Will Ross - - 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. - diff --git a/osx/artwork/banner-200.png b/osx/artwork/banner-200.png deleted file mode 100644 index 4da025832e624db1d7241e4d5c39c58dd1d18e74..0000000000000000000000000000000000000000 Binary files a/osx/artwork/banner-200.png and /dev/null differ diff --git a/osx/build.sh b/osx/build.sh deleted file mode 100755 index 0a2c1cd907d95d2da3804d646da27458301a2e99..0000000000000000000000000000000000000000 --- a/osx/build.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash - -# Usage -if [ -z "$1" ]; then - echo "Usage: build.sh path/to/jenkins.war" - exit 1 -fi - -# Set up build tools -PACKAGEMAKER_APP=$(mdfind "kMDItemCFBundleIdentifier == com.apple.PackageMaker") -if [ -z "$PACKAGEMAKER_APP" ]; then - PACKAGEMAKER_APP=/Applications/PackageMaker.app - if [ ! -d "$PACKAGEMAKER_APP" ]; then - echo "Error: PackageMaker.app not found" >&2 - exit 1 - fi -fi - -PACKAGEMAKER="${PACKAGEMAKER_APP}/Contents/MacOS/PackageMaker" - -# Get the Jenkins version number -cp "$1" $(dirname $0)/jenkins.war.tmp -if [ -z "$2" ]; then - version=$(unzip -p $(dirname $0)/jenkins.war.tmp META-INF/MANIFEST.MF | grep Implementation-Version | cut -d ' ' -f2 | tr -d '\r' | sed -e "s/-SNAPSHOT//" | tr - . ) -else - version="$2" -fi -echo Version is $version -PKG_NAME="jenkins-${version}.pkg" -PKG_TITLE="Jenkins ${version}" -rm $(dirname $0)/jenkins.war.tmp - -# Fiddle with the package document so it points to the jenkins.war file provided -PACKAGEMAKER_DOC="$(dirname $0)/JenkinsInstaller.pmdoc" -mv $PACKAGEMAKER_DOC/01jenkins-contents.xml $PACKAGEMAKER_DOC/01jenkins-contents.xml.orig -sed s,"pt=\".*\" m=","pt=\"${1}\" m=",g $PACKAGEMAKER_DOC/01jenkins-contents.xml.orig > $PACKAGEMAKER_DOC/01jenkins-contents.xml -mv $PACKAGEMAKER_DOC/01jenkins.xml $PACKAGEMAKER_DOC/01jenkins.xml.orig -sed s,".*","${1}",g $PACKAGEMAKER_DOC/01jenkins.xml.orig > $PACKAGEMAKER_DOC/01jenkins.xml - -# Build the package -"${PACKAGEMAKER}" \ - --doc "${PACKAGEMAKER_DOC}" \ - --out "${PKG_NAME}" \ - --version "${version}" \ - --title "${PKG_TITLE}" - -# Reset the fiddling so git doesn't get confused -mv $PACKAGEMAKER_DOC/01jenkins.xml.orig $PACKAGEMAKER_DOC/01jenkins.xml -mv $PACKAGEMAKER_DOC/01jenkins-contents.xml.orig $PACKAGEMAKER_DOC/01jenkins-contents.xml diff --git a/osx/docs/Jenkins-LICENSE.txt b/osx/docs/Jenkins-LICENSE.txt deleted file mode 100644 index 9f519f85cf7539c4dfc12e469c0edafdb3c0ce21..0000000000000000000000000000000000000000 --- a/osx/docs/Jenkins-LICENSE.txt +++ /dev/null @@ -1,8 +0,0 @@ -The MIT License - -Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributers - -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. diff --git a/osx/docs/JenkinsWelcomePanel.rtf b/osx/docs/JenkinsWelcomePanel.rtf deleted file mode 100644 index 8608732f06679678b7a611b6a9a6c4d81aa16c67..0000000000000000000000000000000000000000 --- a/osx/docs/JenkinsWelcomePanel.rtf +++ /dev/null @@ -1,19 +0,0 @@ -{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf350 -{\fonttbl\f0\fswiss\fcharset0 ArialMT;} -{\colortbl;\red255\green255\blue255;} -{\*\listtable{\list\listtemplateid1\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid1\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid1}} -{\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}} -\margl1440\margr1440\vieww12440\viewh12240\viewkind0 -\deftab720 -\pard\pardeftab720\sl320\ql\qnatural - -\f0\fs24 \cf0 Jenkins monitors executions of repeated jobs, such as building a software project or jobs run by cron. Among those things, current Jenkins focuses on the following two jobs:\ -\ -\pard\tx220\tx720\pardeftab720\li720\fi-720\sl320\ql\qnatural -\ls1\ilvl0\cf0 {\listtext \'95 }Building/testing software projects continuously, just like CruiseControl or\'a0DamageControl. In a nutshell, Jenkins provides an easy-to-use so-called continuous integration system, making it easier for developers to integrate\'a0changes to the project, and making it easier for users to obtain a fresh\'a0build. The automated, continuous build increases the productivity.\ -{\listtext \'95 }Monitoring executions of externally-run jobs, such as cron jobs and procmail\'a0jobs, even those that are run on a remote machine. For example, with cron,\'a0all you receive is regular e-mails that capture the output, and it is up to\'a0you to look at them diligently and notice when it broke. Jenkins keeps those\'a0outputs and makes it easy for you to notice when something is wrong\ -\pard\pardeftab720\sl320\ql\qnatural -\cf0 \ -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardeftab720\ql\qnatural\pardirnatural -\cf0 For information on CI see http://www.martinfowler.com/articles/continuousIntegration.html\ -} \ No newline at end of file diff --git a/osx/launchd_conf_daemon/org.jenkins-ci.plist b/osx/launchd_conf_daemon/org.jenkins-ci.plist deleted file mode 100644 index dcdd6a408d7fdeac96791c5494aefe22a0297eae..0000000000000000000000000000000000000000 --- a/osx/launchd_conf_daemon/org.jenkins-ci.plist +++ /dev/null @@ -1,30 +0,0 @@ - - - - - StandardOutPath - /var/log/jenkins/jenkins.log - StandardErrorPath - /var/log/jenkins/jenkins.log - EnvironmentVariables - - JENKINS_HOME - /Users/Shared/Jenkins/Home - - GroupName - daemon - KeepAlive - - Label - org.jenkins-ci - ProgramArguments - - /bin/bash - /Library/Application Support/Jenkins/jenkins-runner.sh - - RunAtLoad - - UserName - daemon - - diff --git a/osx/launchd_conf_jenkins/org.jenkins-ci.plist b/osx/launchd_conf_jenkins/org.jenkins-ci.plist deleted file mode 100644 index 6e3f34050190c72a7898411ebf3f6a4dee5264ea..0000000000000000000000000000000000000000 --- a/osx/launchd_conf_jenkins/org.jenkins-ci.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - StandardOutPath - /var/log/jenkins/jenkins.log - StandardErrorPath - /var/log/jenkins/jenkins.log - EnvironmentVariables - - JENKINS_HOME - /Users/Shared/Jenkins/Home - - GroupName - daemon - KeepAlive - - Label - org.jenkins-ci - ProgramArguments - - /bin/bash - /Library/Application Support/Jenkins/jenkins-runner.sh - - RunAtLoad - - UserName - jenkins - SessionCreate - - - diff --git a/osx/scripts/postinstall-launchd b/osx/scripts/postinstall-launchd deleted file mode 100755 index a56439eca819e02652c6d73838554f8ff29af85a..0000000000000000000000000000000000000000 --- a/osx/scripts/postinstall-launchd +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -JENKINS_PLIST="/Library/LaunchDaemons/org.jenkins-ci.plist" - -# Because PackageMaker just copies the components, we need to fix the permissions -chown root:wheel ${JENKINS_PLIST} -chmod 644 ${JENKINS_PLIST} -mkdir -p /Users/Shared/Jenkins -find /Users/Shared/Jenkins \( -not -user daemon -or -not -group daemon \) -print0 | xargs -0 chown daemon:daemon - -# Create log directory, which can be written by Jenkins daemon -mkdir -p /var/log/jenkins -chown daemon:daemon /var/log/jenkins - -# Enable log rotation by newsyslog -cat <<_EOT_ > /etc/newsyslog.d/jenkins.conf -# logfilename [owner:group] mode count size when flags [/pid_file] [sig_num] -# Rotate jenkins log at midnight, and preserve old logs in 3 days -/var/log/jenkins/jenkins.log 644 3 * \$D0 J -_EOT_ - -# Load and start the launch daemon -/bin/launchctl load -w ${JENKINS_PLIST} - -# Wait for port 8080 to start accepting connections. -# But don't wait forever. -timeout=$(($(date +%s) + 60)) -while [ $(date +%s) -lt $timeout ] && ! curl -s http://localhost:8080 >/dev/null; do - sleep 1 -done - -if [ $(date +%s) -ge $timeout ]; then - echo "Timed out waiting for Jenkins port 8080 to start listening!" - echo "Either Jenkins did not load or this system is very slow." -fi diff --git a/osx/scripts/postinstall-launchd-jenkins b/osx/scripts/postinstall-launchd-jenkins deleted file mode 100755 index a01db883ea10c5f4558cdde4b3636a7a04666468..0000000000000000000000000000000000000000 --- a/osx/scripts/postinstall-launchd-jenkins +++ /dev/null @@ -1,94 +0,0 @@ -#!/bin/bash - -JENKINS_PLIST="/Library/LaunchDaemons/org.jenkins-ci.plist" -DEFAULTS_PLIST="/Library/Preferences/org.jenkins-ci.plist" - -# Because PackageMaker just copies the components, we need to fix the permissions -chown root:wheel ${JENKINS_PLIST} -chmod 644 ${JENKINS_PLIST} - -JENKINS_HOMEDIR="/Users/Shared/Jenkins" -mkdir -p $JENKINS_HOMEDIR - -if dscl . -list /Users/jenkins; then - echo 'jenkins user already exists, attempting to change the shell to /bin/bash' - # Will fail if UserShell is not /usr/bin/false, but that's ok. - # Then we will assume an admin has changed it. - dscl . -change /Users/jenkins UserShell /usr/bin/false /bin/bash -else - echo 'No jenkins user found, creating jenkins user and group' - -# Find free uid under 500 - uid=$(dscl . -list /Users uid | sort -nrk 2 | awk '$2 < 500 {print $2 + 1; exit 0}') - if [ $uid -eq 500 ]; then - echo 'ERROR: All system uids are in use!' - exit 1 - fi - echo "Using uid $uid for jenkins" - - gid=$uid - while dscl -search /Groups gid $gid | grep -q $gid; do - echo "gid $gid is not free, trying next" - gid=$(($gid + 1)) - done - echo "Using gid $gid for jenkins" - - dscl . -create /Groups/jenkins PrimaryGroupID $gid - - dscl . -create /Users/jenkins UserShell /bin/bash - dscl . -create /Users/jenkins Password '*' - dscl . -create /Users/jenkins UniqueID $uid - dscl . -create /Users/jenkins PrimaryGroupID $gid - dscl . -create /Users/jenkins NFSHomeDirectory "$JENKINS_HOMEDIR" - - dscl . -append /Groups/jenkins GroupMembership jenkins -fi - -find "$JENKINS_HOMEDIR" \( -not -user jenkins -or -not -group jenkins \) -print0 | xargs -0 chown jenkins:jenkins - -# Add defaults for heap sizing -arch=$(uname -m) -if [ $arch = 'x86_64' ]; then - defaults write $DEFAULTS_PLIST heapSize 512m - defaults write $DEFAULTS_PLIST permGen 512m - defaults write $DEFAULTS_PLIST minHeapSize 256m - defaults write $DEFAULTS_PLIST minPermGen 256m -else - # i386 - defaults write $DEFAULTS_PLIST heapSize 128m - defaults write $DEFAULTS_PLIST permGen 128m - defaults write $DEFAULTS_PLIST minHeapSize 64m - defaults write $DEFAULTS_PLIST minPermGen 64m -fi - -# Set tmpdir -JENKINS_TMPDIR="$JENKINS_HOMEDIR/tmp" -defaults write $DEFAULTS_PLIST tmpdir $JENKINS_TMPDIR -mkdir -p $JENKINS_TMPDIR -chown jenkins:jenkins $JENKINS_TMPDIR - -# Create log directory, which can be written by Jenkins daemon -mkdir -p /var/log/jenkins -chown jenkins:jenkins /var/log/jenkins - -# Enable log rotation by newsyslog -cat <<_EOT_ > /etc/newsyslog.d/jenkins.conf -# logfilename [owner:group] mode count size when flags [/pid_file] [sig_num] -# Rotate jenkins log at midnight, and preserve old logs in 3 days -/var/log/jenkins/jenkins.log 644 3 * \$D0 J -_EOT_ - -# Load and start the launch daemon -/bin/launchctl load -w ${JENKINS_PLIST} - -# Wait for port 8080 to start accepting connections. -# But don't wait forever. -timeout=$(($(date +%s) + 60)) -while [ $(date +%s) -lt $timeout ] && ! curl -s http://localhost:8080 >/dev/null; do - sleep 1 -done - -if [ $(date +%s) -ge $timeout ]; then - echo "Timed out waiting for Jenkins port 8080 to start listening!" - echo "Either Jenkins did not load or this system is very slow." -fi diff --git a/osx/scripts/postinstall-war b/osx/scripts/postinstall-war deleted file mode 100644 index e7ea061b4f2a41e1be211570cbbbfb48ebdf8810..0000000000000000000000000000000000000000 --- a/osx/scripts/postinstall-war +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -JENKINS_APP="/Applications/Jenkins" - -# Fix Jenkins Permissions -chown -R root:wheel ${JENKINS_APP} -chmod 755 ${JENKINS_APP} -chmod 644 ${JENKINS_APP}/* diff --git a/osx/scripts/preinstall-launchd b/osx/scripts/preinstall-launchd deleted file mode 100644 index 6823450f48fc8a81cef9afb49f2f9cc3f64f3f04..0000000000000000000000000000000000000000 --- a/osx/scripts/preinstall-launchd +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -# Remove the old launchd plist if needed -JENKINS_PLIST="/Library/LaunchAgents/org.jenkins-ci.plist" -if [ -f ${JENKINS_PLIST} ]; then - rm ${JENKINS_PLIST} -fi - -JENKINS_DAEMON_PLIST="/Library/LaunchDaemons/org.jenkins-ci.plist" -launchctl unload ${JENKINS_DAEMON_PLIST} || echo 'Failed to unload old Jenkins launch daemon. Maybe it is was not loaded?' diff --git a/plugins/pom.xml b/plugins/pom.xml deleted file mode 100644 index fbc82cb8bc52ceed7c1f0407b3ab5e624718ce27..0000000000000000000000000000000000000000 --- a/plugins/pom.xml +++ /dev/null @@ -1,359 +0,0 @@ - - - 4.0.0 - - - org.jenkins-ci - jenkins - 1.34 - - - - org.jenkins-ci.plugins - plugin - Jenkins plugin POM - 1.599-SNAPSHOT - pom - - - - scm:svn:https://svn.jenkins-ci.org/trunk/hudson/plugins/ - scm:svn:https://svn.jenkins-ci.org/trunk/hudson/plugins/ - https://svn.jenkins-ci.org/trunk/hudson/plugins/ - HEAD - - - - JIRA - http://issues.jenkins-ci.org/ - - - - UTF-8 - 2 - - - - - org.jenkins-ci.main - jenkins-war - war - 1.599-SNAPSHOT - test - - - org.jenkins-ci.main - jenkins-core - 1.599-SNAPSHOT - provided - - - org.jenkins-ci.main - jenkins-test-harness - 1.599-SNAPSHOT - test - - - - javax.servlet - servlet-api - 2.4 - provided - - - - org.codehaus.mojo - animal-sniffer-annotations - 1.9 - provided - true - - - - - - ${project.artifactId} - - - org.jenkins-ci.tools - maven-hpi-plugin - true - - true - /jenkins - - - - org.kohsuke.stapler - maven-stapler-plugin - - true - - - maven-release-plugin - - - deploy - - - - org.jvnet.localizer - maven-localizer-plugin - - - - - generate - - - Messages.properties - target/generated-sources/localizer - - - - - - maven-javadoc-plugin - - - - org.codehaus.gmaven - gmaven-plugin - - - - test-in-groovy - - - generateTestStubs - testCompile - - - - - - ant - ant - 1.6.5 - - - - - maven-surefire-plugin - 2.16 - - - - hudson.udp - 33849 - - - true - ${concurrency} - - - - com.cloudbees - maven-license-plugin - - - - - process - - prepare-package - - - target/${project.artifactId}/WEB-INF/licenses.xml - - if (e.value.packaging=="hpi") - plugins.add(e.key.id) - } - - // filter out dependencies that don't belong to this plugin - models.entrySet().removeAll(models.entrySet().findAll { e -> - def a = e.key; - - if (a.dependencyTrail.size()>0 && plugins.contains(a.dependencyTrail[1])) - return true; // ignore transitive dependencies through other plugins - - // if the dependency goes through jenkins core, we don't need to bundle it in the war - // because jenkins-core comes in the scope, I think this is a bug in Maven that it puts such - // dependencies into the artifact list. - if (a.dependencyTrail.find { trail -> trail.contains(":hudson-core:") || trail.contains(":jenkins-core:") }) - return true; - - return false; - }) - } - ]]> - - - - - - - - - - org.apache.maven.plugins - maven-eclipse-plugin - - target/eclipse-classes - - - org.eclipse.jdt.groovy.core.groovyNature - - - - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - org.apache.maven.plugins - maven-enforcer-plugin - [1.0,) - - display-info - - - - - - - - - org.codehaus.gmaven - gmaven-plugin - [1.0,) - - testCompile - generateTestStubs - - - - - - - - - - - - - org.codehaus.mojo - animal-sniffer-maven-plugin - 1.9 - - - - check - - test - - - - - - org.codehaus.mojo.signature - java15 - 1.0 - - - - - - - - org.kohsuke - wagon-gitsite - 0.3.5 - - - - - - - repo.jenkins-ci.org - http://repo.jenkins-ci.org/public/ - - true - - - false - - - - - - - repo.jenkins-ci.org - http://repo.jenkins-ci.org/public/ - - true - - - false - - - - - - - github-pages - gitsite:git@github.com/jenkinsci/maven-site.git:plugin-parent - - - maven.jenkins-ci.org - http://maven.jenkins-ci.org:8081/content/repositories/snapshots - - - - - - all-tests - - - !test - - - - true - - - - diff --git a/pom.xml b/pom.xml index b47ab0f72dc4f76c23ba9f3e93e874e06e3cbad0..a374158bcb29dc356f2238ddc202f87a71bb97b4 100644 --- a/pom.xml +++ b/pom.xml @@ -28,12 +28,12 @@ THE SOFTWARE. org.jenkins-ci jenkins - 1.34 + 1.35 org.jenkins-ci.main pom - 1.599-SNAPSHOT + 1.648-SNAPSHOT pom Jenkins main module @@ -52,7 +52,6 @@ THE SOFTWARE. war test cli - plugins @@ -98,9 +97,14 @@ THE SOFTWARE. 1.7.7 2.7.1 + 1.4.1 ${skipTests} + 3.0.1 + 1.2 - 6 + 7 + + https://jenkins-ci.org/changelog @@ -146,24 +150,24 @@ THE SOFTWARE. junit junit - 4.11 + 4.12 org.mockito mockito-core - 1.8.5 + 1.10.19 org.powermock powermock-module-junit4 - 1.4.10 + 1.6.2 org.powermock powermock-api-mockito - 1.4.10 + 1.6.2 @@ -175,7 +179,7 @@ THE SOFTWARE. org.jenkins-ci.main remoting - 2.49 + 2.53.2 @@ -187,7 +191,7 @@ THE SOFTWARE. com.google.inject guice - 4.0-beta5 + 4.0-beta @@ -215,6 +219,18 @@ THE SOFTWARE. commons-logging commons-logging 1.1.3 + provided + + + org.slf4j + log4j-over-slf4j + ${slf4jVersion} + + + log4j + log4j + 1.2.17 + provided org.samba.jcifs @@ -236,7 +252,7 @@ THE SOFTWARE. org.jenkins-ci test-annotations - 1.1 + ${test-annotations.version} test @@ -341,23 +357,24 @@ THE SOFTWARE. org.apache.maven.plugins maven-javadoc-plugin - 2.8 + 2.10.3 org.apache.maven.plugins maven-jar-plugin - 2.4 + 2.6 org.apache.maven.plugins maven-war-plugin - 2.3 + 2.6 org.apache.maven.plugins maven-surefire-plugin 2.16 + -noverify ${project.build.directory} 3600 @@ -440,7 +457,7 @@ THE SOFTWARE. org.jvnet.localizer maven-localizer-plugin - 1.15 + 1.23 UTF-8 @@ -473,7 +490,6 @@ THE SOFTWARE. org.codehaus.mojo findbugs-maven-plugin - 2.5.2 org.apache.maven.plugins @@ -494,12 +510,12 @@ THE SOFTWARE. org.jenkins-ci.tools maven-hpi-plugin - 1.110 + 1.114 org.apache.maven.plugins maven-site-plugin - 3.1 + 3.3 org.kohsuke @@ -632,7 +648,7 @@ THE SOFTWARE. - 1.6.0-18 + 1.7.0 3.0 @@ -656,6 +672,10 @@ THE SOFTWARE. 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 @@ -760,7 +780,6 @@ THE SOFTWARE. org.codehaus.mojo findbugs-maven-plugin - 2.5.2 High @@ -836,6 +855,12 @@ THE SOFTWARE. + + lts-release + + https://jenkins-ci.org/changelog-stable + + m2e diff --git a/rpm/SOURCES/jenkins.init.in b/rpm/SOURCES/jenkins.init.in deleted file mode 100644 index 83371a0bf4df6c13bbe838f7955e85b5c0d2acd4..0000000000000000000000000000000000000000 --- a/rpm/SOURCES/jenkins.init.in +++ /dev/null @@ -1,174 +0,0 @@ -#!/bin/sh -# -# SUSE system statup script for Jenkins -# Copyright (C) 2007 Pascal Bleser -# -# This library is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or (at -# your option) any later version. -# -# This library is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, -# USA. -# -### BEGIN INIT INFO -# Provides: jenkins -# Required-Start: $local_fs $remote_fs $network $time $named -# Should-Start: $time sendmail -# Required-Stop: $local_fs $remote_fs $network $time $named -# Should-Stop: $time sendmail -# Default-Start: 3 5 -# Default-Stop: 0 1 2 6 -# Short-Description: Jenkins continuous build server -# Description: Start the Jenkins continuous build server -### END INIT INFO - -# Check for missing binaries (stale symlinks should not happen) -JENKINS_WAR="@@WAR@@" -test -r "$JENKINS_WAR" || { echo "$JENKINS_WAR not installed"; - if [ "$1" = "stop" ]; then exit 0; - else exit 5; fi; } - -# Check for existence of needed config file and read it -JENKINS_CONFIG=/etc/sysconfig/jenkins -test -e "$JENKINS_CONFIG" || { echo "$JENKINS_CONFIG not existing"; - if [ "$1" = "stop" ]; then exit 0; - else exit 6; fi; } -test -r "$JENKINS_CONFIG" || { echo "$JENKINS_CONFIG not readable. Perhaps you forgot 'sudo'?"; - if [ "$1" = "stop" ]; then exit 0; - else exit 6; fi; } - -JENKINS_PID_FILE="/var/run/jenkins.pid" - -# Source function library. -. /etc/init.d/functions - -# Read config -[ -f "$JENKINS_CONFIG" ] && . "$JENKINS_CONFIG" - -# Set up environment accordingly to the configuration settings -[ -n "$JENKINS_HOME" ] || { echo "JENKINS_HOME not configured in $JENKINS_CONFIG"; - if [ "$1" = "stop" ]; then exit 0; - else exit 6; fi; } -[ -d "$JENKINS_HOME" ] || { echo "JENKINS_HOME directory does not exist: $JENKINS_HOME"; - if [ "$1" = "stop" ]; then exit 0; - else exit 1; fi; } - -# Search usable Java. We do this because various reports indicated -# that /usr/bin/java may not always point to Java >= 1.6 -# see http://www.nabble.com/guinea-pigs-wanted-----Hudson-RPM-for-RedHat-Linux-td25673707.html -candidates=" -/etc/alternatives/java -/usr/lib/jvm/java-1.6.0/bin/java -/usr/lib/jvm/jre-1.6.0/bin/java -/usr/lib/jvm/java-1.7.0/bin/java -/usr/lib/jvm/jre-1.7.0/bin/java -/usr/lib/jvm/java-1.8.0/bin/java -/usr/lib/jvm/jre-1.8.0/bin/java -/usr/bin/java -" -for candidate in $candidates -do - [ -x "$JENKINS_JAVA_CMD" ] && break - JENKINS_JAVA_CMD="$candidate" -done - -JAVA_CMD="$JENKINS_JAVA_CMD $JENKINS_JAVA_OPTIONS -DJENKINS_HOME=$JENKINS_HOME -jar $JENKINS_WAR" -PARAMS="--logfile=/var/log/jenkins/jenkins.log --webroot=/var/cache/jenkins/war --daemon" -[ -n "$JENKINS_PORT" ] && PARAMS="$PARAMS --httpPort=$JENKINS_PORT" -[ -n "$JENKINS_LISTEN_ADDRESS" ] && PARAMS="$PARAMS --httpListenAddress=$JENKINS_LISTEN_ADDRESS" -[ -n "$JENKINS_HTTPS_PORT" ] && PARAMS="$PARAMS --httpsPort=$JENKINS_HTTPS_PORT" -[ -n "$JENKINS_HTTPS_KEYSTORE" ] && PARAMS="$PARAMS --httpsKeyStore=$JENKINS_HTTPS_KEYSTORE" -[ -n "$JENKINS_HTTPS_KEYSTORE_PASSWORD" ] && PARAMS="$PARAMS --httpsKeyStorePassword='$JENKINS_HTTPS_KEYSTORE_PASSWORD'" -[ -n "$JENKINS_HTTPS_LISTEN_ADDRESS" ] && PARAMS="$PARAMS --httpsListenAddress=$JENKINS_HTTPS_LISTEN_ADDRESS" -[ -n "$JENKINS_AJP_PORT" ] && PARAMS="$PARAMS --ajp13Port=$JENKINS_AJP_PORT" -[ -n "$JENKINS_AJP_LISTEN_ADDRESS" ] && PARAMS="$PARAMS --ajp13ListenAddress=$JENKINS_AJP_LISTEN_ADDRESS" -[ -n "$JENKINS_DEBUG_LEVEL" ] && PARAMS="$PARAMS --debug=$JENKINS_DEBUG_LEVEL" -[ -n "$JENKINS_HANDLER_STARTUP" ] && PARAMS="$PARAMS --handlerCountStartup=$JENKINS_HANDLER_STARTUP" -[ -n "$JENKINS_HANDLER_MAX" ] && PARAMS="$PARAMS --handlerCountMax=$JENKINS_HANDLER_MAX" -[ -n "$JENKINS_HANDLER_IDLE" ] && PARAMS="$PARAMS --handlerCountMaxIdle=$JENKINS_HANDLER_IDLE" -[ -n "$JENKINS_ARGS" ] && PARAMS="$PARAMS $JENKINS_ARGS" - -if [ "$JENKINS_ENABLE_ACCESS_LOG" = "yes" ]; then - PARAMS="$PARAMS --accessLoggerClassName=winstone.accesslog.SimpleAccessLogger --simpleAccessLogger.format=combined --simpleAccessLogger.file=/var/log/jenkins/access_log" -fi - -RETVAL=0 - -case "$1" in - start) - echo -n "Starting Jenkins " - daemon --user "$JENKINS_USER" --pidfile "$JENKINS_PID_FILE" $JAVA_CMD $PARAMS > /dev/null - RETVAL=$? - if [ $RETVAL = 0 ]; then - success - echo > "$JENKINS_PID_FILE" # just in case we fail to find it - MY_SESSION_ID=`/bin/ps h -o sess -p $$` - # get PID - /bin/ps hww -u "$JENKINS_USER" -o sess,ppid,pid,cmd | \ - while read sess ppid pid cmd; do - [ "$ppid" = 1 ] || continue - # this test doesn't work because Jenkins sets a new Session ID - # [ "$sess" = "$MY_SESSION_ID" ] || continue - echo "$cmd" | grep $JENKINS_WAR > /dev/null - [ $? = 0 ] || continue - # found a PID - echo $pid > "$JENKINS_PID_FILE" - done - else - failure - fi - echo - ;; - stop) - echo -n "Shutting down Jenkins " - killproc jenkins - RETVAL=$? - echo - ;; - try-restart|condrestart) - if test "$1" = "condrestart"; then - echo "${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}" - fi - $0 status - if test $? = 0; then - $0 restart - else - : # Not running is not a failure. - fi - ;; - restart) - $0 stop - $0 start - ;; - force-reload) - echo -n "Reload service Jenkins " - $0 try-restart - ;; - reload) - $0 restart - ;; - status) - status jenkins - RETVAL=$? - ;; - probe) - ## Optional: Probe for the necessity of a reload, print out the - ## argument to this init script which is required for a reload. - ## Note: probe is not (yet) part of LSB (as of 1.9) - - test "$JENKINS_CONFIG" -nt "$JENKINS_PID_FILE" && echo reload - ;; - *) - echo "Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload|probe}" - exit 1 - ;; -esac -exit $RETVAL diff --git a/rpm/SOURCES/jenkins.logrotate b/rpm/SOURCES/jenkins.logrotate deleted file mode 100644 index f68f4cc74878d370cf73d1a995cd1fc4b1a3c5f4..0000000000000000000000000000000000000000 --- a/rpm/SOURCES/jenkins.logrotate +++ /dev/null @@ -1,11 +0,0 @@ -/var/log/jenkins/jenkins.log /var/log/jenkins/access_log { - compress - dateext - maxage 365 - rotate 99 - size=+4096k - notifempty - missingok - create 644 - copytruncate -} diff --git a/rpm/SOURCES/jenkins.repo.in b/rpm/SOURCES/jenkins.repo.in deleted file mode 100644 index 8c411bfd4e43cd3a3b5570be999334a2370c7f42..0000000000000000000000000000000000000000 --- a/rpm/SOURCES/jenkins.repo.in +++ /dev/null @@ -1,4 +0,0 @@ -[jenkins] -name=Jenkins -baseurl=@URL@ -gpgcheck=1 diff --git a/rpm/SOURCES/jenkins.sysconfig.in b/rpm/SOURCES/jenkins.sysconfig.in deleted file mode 100644 index 38d716afcf6c942549945fe8989b864fa492a0ae..0000000000000000000000000000000000000000 --- a/rpm/SOURCES/jenkins.sysconfig.in +++ /dev/null @@ -1,151 +0,0 @@ -## Path: Development/Jenkins -## Description: Configuration for the Jenkins continuous build server -## Type: string -## Default: "@@HOME@@" -## ServiceRestart: jenkins -# -# Directory where Jenkins store its configuration and working -# files (checkouts, build reports, artifacts, ...). -# -JENKINS_HOME="@@HOME@@" - -## Type: string -## Default: "" -## ServiceRestart: jenkins -# -# Java executable to run Jenkins -# When left empty, we'll try to find the suitable Java. -# -JENKINS_JAVA_CMD="" - -## Type: string -## Default: "jenkins" -## ServiceRestart: jenkins -# -# Unix user account that runs the Jenkins daemon -# Be careful when you change this, as you need to update -# permissions of $JENKINS_HOME and /var/log/jenkins. -# -JENKINS_USER="jenkins" - -## Type: string -## Default: "-Djava.awt.headless=true" -## ServiceRestart: jenkins -# -# Options to pass to java when running Jenkins. -# -JENKINS_JAVA_OPTIONS="-Djava.awt.headless=true" - -## Type: integer(0:65535) -## Default: 8080 -## ServiceRestart: jenkins -# -# Port Jenkins is listening on. -# Set to -1 to disable -# -JENKINS_PORT="8080" - -## Type: string -## Default: "" -## ServiceRestart: jenkins -# -# IP address Jenkins listens on for HTTP requests. -# Default is all interfaces (0.0.0.0). -# -JENKINS_LISTEN_ADDRESS="" - -## Type: integer(0:65535) -## Default: "" -## ServiceRestart: jenkins -# -# HTTPS port Jenkins is listening on. -# Default is disabled. -# -JENKINS_HTTPS_PORT="" - -## Type: string -## Default: "" -## ServiceRestart: jenkins -# -# Path to the keystore in JKS format (as created by the JDK 'keytool'). -# Default is disabled. -# -JENKINS_HTTPS_KEYSTORE="" - -## Type: string -## Default: "" -## ServiceRestart: jenkins -# -# Password to access the keystore defined in JENKINS_HTTPS_KEYSTORE. -# Default is disabled. -# -JENKINS_HTTPS_KEYSTORE_PASSWORD="" - -## Type: string -## Default: "" -## ServiceRestart: jenkins -# -# IP address Jenkins listens on for HTTPS requests. -# Default is disabled. -# -JENKINS_HTTPS_LISTEN_ADDRESS="" - -## Type: integer(0:65535) -## Default: 8009 -## ServiceRestart: jenkins -# -# Ajp13 Port Jenkins is listening on. -# Set to -1 to disable -# -JENKINS_AJP_PORT="8009" - -## Type: string -## Default: "" -## ServiceRestart: jenkins -# -# IP address Jenkins listens on for Ajp13 requests. -# Default is all interfaces (0.0.0.0). -# -JENKINS_AJP_LISTEN_ADDRESS="" - -## Type: integer(1:9) -## Default: 5 -## ServiceRestart: jenkins -# -# Debug level for logs -- the higher the value, the more verbose. -# 5 is INFO. -# -JENKINS_DEBUG_LEVEL="5" - -## Type: yesno -## Default: no -## ServiceRestart: jenkins -# -# Whether to enable access logging or not. -# -JENKINS_ENABLE_ACCESS_LOG="no" - -## Type: integer -## Default: 100 -## ServiceRestart: jenkins -# -# Maximum number of HTTP worker threads. -# -JENKINS_HANDLER_MAX="100" - -## Type: integer -## Default: 20 -## ServiceRestart: jenkins -# -# Maximum number of idle HTTP worker threads. -# -JENKINS_HANDLER_IDLE="20" - -## Type: string -## Default: "" -## ServiceRestart: jenkins -# -# Pass arbitrary arguments to Jenkins. -# Full option list: java -jar jenkins.war --help -# -JENKINS_ARGS="" diff --git a/rpm/SPECS/jenkins.spec b/rpm/SPECS/jenkins.spec deleted file mode 100644 index 552dca56bcde54e2ba2b51c47c084807411b98e6..0000000000000000000000000000000000000000 --- a/rpm/SPECS/jenkins.spec +++ /dev/null @@ -1,150 +0,0 @@ -# TODO: -# - how to add to the trusted service of the firewall? - -%define _prefix %{_usr}/lib/jenkins -%define workdir %{_var}/lib/jenkins - -Name: jenkins -Version: %{ver} -Release: 1.1 -Summary: Continous Build Server -Source: jenkins.war -Source1: jenkins.init.in -Source2: jenkins.sysconfig.in -Source3: jenkins.logrotate -URL: http://jenkins-ci.org/ -Group: Development/Tools/Building -License: MIT/X License, GPL/CDDL, ASL2 -BuildRoot: %{_tmppath}/build-%{name}-%{version} -# see the comment below from java-1.6.0-openjdk.spec that explains this dependency -# java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons, -# and this change was brought into RHEL-4. java-1.5.0-ibm packages -# also included the epoch in their virtual provides. This created a -# situation where in-the-wild java-1.5.0-ibm packages provided "java = -# 1:1.5.0". In RPM terms, "1.6.0 < 1:1.5.0" since 1.6.0 is -# interpreted as 0:1.6.0. So the "java >= 1.6.0" requirement would be -# satisfied by the 1:1.5.0 packages. Thus we need to set the epoch in -# JDK package >= 1.6.0 to 1, and packages referring to JDK virtual -# provides >= 1.6.0 must specify the epoch, "java >= 1:1.6.0". -# -# Kohsuke - 2009/09/29 -# test by mrooney on what he believes to be RHEL 5.2 indicates -# that there's no such packages. JRE/JDK RPMs from java.sun.com -# do not have this virtual package declarations. So for now, -# I'm dropping this requirement. -# Requires: java >= 1:1.6.0 -Obsoletes: hudson -PreReq: /usr/sbin/groupadd /usr/sbin/useradd -#PreReq: %{fillup_prereq} -BuildArch: noarch - -%description -Jenkins monitors executions of repeated jobs, such as building a software -project or jobs run by cron. Among those things, current Jenkins focuses on the -following two jobs: -- Building/testing software projects continuously, just like CruiseControl or - DamageControl. In a nutshell, Jenkins provides an easy-to-use so-called - continuous integration system, making it easier for developers to integrate - changes to the project, and making it easier for users to obtain a fresh - build. The automated, continuous build increases the productivity. -- Monitoring executions of externally-run jobs, such as cron jobs and procmail - jobs, even those that are run on a remote machine. For example, with cron, - all you receive is regular e-mails that capture the output, and it is up to - you to look at them diligently and notice when it broke. Jenkins keeps those - outputs and makes it easy for you to notice when something is wrong. - - - - -Authors: --------- - Kohsuke Kawaguchi - -%prep -%setup -q -T -c - -%build - -%install -rm -rf "%{buildroot}" -%__install -D -m0644 "%{SOURCE0}" "%{buildroot}%{_prefix}/%{name}.war" -%__install -d "%{buildroot}%{workdir}" -%__install -d "%{buildroot}%{workdir}/plugins" - -%__install -d "%{buildroot}/var/log/jenkins" -%__install -d "%{buildroot}/var/cache/jenkins" - -%__install -D -m0755 "%{SOURCE1}" "%{buildroot}/etc/init.d/%{name}" -%__sed -i 's,@@WAR@@,%{_prefix}/%{name}.war,g' "%{buildroot}/etc/init.d/%{name}" -%__install -d "%{buildroot}/usr/sbin" -%__ln_s "../../etc/init.d/%{name}" "%{buildroot}/usr/sbin/rc%{name}" - -%__install -D -m0600 "%{SOURCE2}" "%{buildroot}/etc/sysconfig/%{name}" -%__sed -i 's,@@HOME@@,%{workdir},g' "%{buildroot}/etc/sysconfig/%{name}" - -%__install -D -m0644 "%{SOURCE3}" "%{buildroot}/etc/logrotate.d/%{name}" - -%pre -/usr/sbin/groupadd -r jenkins &>/dev/null || : -# SUSE version had -o here, but in Fedora -o isn't allowed without -u -/usr/sbin/useradd -g jenkins -s /bin/false -r -c "Jenkins Continuous Build server" \ - -d "%{workdir}" jenkins &>/dev/null || : - -%post -/sbin/chkconfig --add jenkins - -# If we have an old hudson install, rename it to jenkins -if test -d /var/lib/hudson; then - # leave a marker to indicate this came from Hudson. - # could be useful down the road - # This also ensures that the .??* wildcard matches something - touch /var/lib/hudson/.moving-hudson - mv -f /var/lib/hudson/* /var/lib/hudson/.??* /var/lib/jenkins - rmdir /var/lib/hudson - find /var/lib/jenkins -user hudson -exec chown jenkins {} + || true -fi -if test -d /var/run/hudson; then - mv -f /var/run/hudson/* /var/run/jenkins - rmdir /var/run/hudson -fi - -# Ensure the right ownership on files -. /etc/sysconfig/jenkins -chown -R ${JENKINS_USER:-jenkins} /var/log/jenkins -chown -R ${JENKINS_USER:-jenkins} ${JENKINS_HOME:-%{workdir}} - -%preun -if [ "$1" = 0 ] ; then - # if this is uninstallation as opposed to upgrade, delete the service - /sbin/service jenkins stop > /dev/null 2>&1 - /sbin/chkconfig --del jenkins -fi -exit 0 - -%postun -if [ "$1" -ge 1 ]; then - /sbin/service jenkins condrestart > /dev/null 2>&1 -fi -exit 0 - -%clean -%__rm -rf "%{buildroot}" - -%files -%defattr(-,root,root) -%dir %{_prefix} -%{_prefix}/%{name}.war -%attr(0755,jenkins,jenkins) %dir %{workdir} -%attr(0750,jenkins,jenkins) /var/log/jenkins -%attr(0750,jenkins,jenkins) /var/cache/jenkins -%config /etc/logrotate.d/%{name} -%config(noreplace) /etc/init.d/%{name} -%config(noreplace) /etc/sysconfig/%{name} -/usr/sbin/rc%{name} - -%changelog -* Sat Apr 19 2014 mbarr@mbarr.net -- Removed the jenkins.repo installation. Per https://issues.jenkins-ci.org/browse/JENKINS-22690 -* Wed Sep 28 2011 kk@kohsuke.org -- See [http://jenkins-ci.org/changelog] for complete details - diff --git a/rpm/build.sh b/rpm/build.sh deleted file mode 100755 index 7f55c85a7e00d3c0ae5397971fc9834d6338386b..0000000000000000000000000000000000000000 --- a/rpm/build.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -e -if [ -z "$1" ]; then - echo "Usage: build.sh path/to/jenkins.war [version]" - exit 1 -fi - -which rpm > /dev/null 2>&1 -if [ $? != 0 ]; then - sudo apt-get install -y rpm expect || true -fi - - -# figure out the version to package -cp "$1" $(dirname $0)/SOURCES/jenkins.war -pushd $(dirname $0) -if [ -z "$2" ]; then - version=$(unzip -p SOURCES/jenkins.war META-INF/MANIFEST.MF | grep Implementation-Version | cut -d ' ' -f2 | tr - .) -else - version="$2" -fi -echo Version is $version - -# prepare fresh directories -rm -rf BUILD RPMS SRPMS tmp || true -mkdir -p BUILD RPMS SRPMS - -cat SOURCES/jenkins.repo.in | sed -e "s#@URL@#${RPM_URL}/#g" > SOURCES/jenkins.repo - -# real action happens here -rpmbuild -ba --define="_topdir $PWD" --define="_tmppath $PWD/tmp" --define="ver $version" SPECS/jenkins.spec diff --git a/test/pom.xml b/test/pom.xml index 6f8cde84a183861b31d7eb81f11ce8bce6f273ed..d7897b4b94ea079fa66b14e51ec8c57fb3fdd90b 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -28,13 +28,13 @@ THE SOFTWARE. org.jenkins-ci.main pom - 1.599-SNAPSHOT + 1.648-SNAPSHOT - jenkins-test-harness + test - Test harness for Jenkins and plugins - Unit test harness (src/main) and Unit tests for Jenkins core (src/test) + Tests for Jenkins core + Functional tests for Jenkins core 2 @@ -62,23 +62,48 @@ THE SOFTWARE. ${project.groupId} - maven-plugin - ${maven-plugin.version} + jenkins-test-harness + 2.0 + test - org.jenkins-ci.plugins - ant - 1.2 + ${project.groupId} + jenkins-test-harness-tools + 2.0 + test + ${project.groupId} + maven-plugin + ${maven-plugin.version} + + + org.apache.httpcomponents + httpclient + + + org.apache.httpcomponents + httpcore + + + + org.jenkins-ci + SECURITY-144-compat + + + commons-codec + commons-codec + + + + org.jenkins-ci.plugins subversion 1.45 - - - org.jenkins-ci.plugins - mailer - 1.10 + test org.jenkins-ci.plugins @@ -89,65 +114,40 @@ THE SOFTWARE. org.jenkins-ci.plugins antisamy-markup-formatter 1.0 + test org.jenkins-ci.plugins matrix-project - 1.0-beta-1 + ${matrix-project.version} org.jenkins-ci.plugins junit 1.2-beta-4 - - - org.mortbay.jetty - jetty - 6.1.26 - - - org.jenkins-ci - test-annotations - 1.1 - compile - + test org.jvnet.mock-javamail mock-javamail 1.7 - - junit - junit - org.hamcrest - hamcrest-library + hamcrest-core 1.3 - - org.jenkins-ci - htmlunit - 2.6-jenkins-6 + + xalan + xalan + 2.7.1 - xml-apis xml-apis - - xalan - xalan - 2.7.1 - - - org.jvnet.hudson - embedded-rhino-debugger - 1.2 - org.jvnet.hudson @@ -165,19 +165,21 @@ THE SOFTWARE. test - org.netbeans.modules - org-netbeans-insane - RELEASE72 + org.codehaus.geb + geb-implicit-assertions + 0.7.2 - com.github.stephenc.findbugs - findbugs-annotations - 1.3.9-1 + org.javassist + javassist + 3.19.0-GA + test - org.codehaus.geb - geb-implicit-assertions - 0.7.2 + org.apache.commons + commons-collections4 + 4.0 + test @@ -219,16 +221,6 @@ THE SOFTWARE. testCompile - - preset-packager - process-resources - - execute - - - ${pom.basedir}/src/main/preset-data/package.groovy - - diff --git a/test/src/main/java/hudson/cli/CLICommandInvoker.java b/test/src/main/java/hudson/cli/CLICommandInvoker.java deleted file mode 100644 index ad8ac1f229a72aad2afbfb823d22c9664a576814..0000000000000000000000000000000000000000 --- a/test/src/main/java/hudson/cli/CLICommandInvoker.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * The MIT License - * - * Copyright 2013 Red Hat, 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.cli; - -import hudson.Extension; -import hudson.model.User; -import hudson.security.ACL; -import hudson.security.Permission; -import hudson.security.GlobalMatrixAuthorizationStrategy; - -import java.io.ByteArrayOutputStream; -import java.io.InputStream; -import java.io.PrintStream; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Locale; - -import jenkins.model.Jenkins; - -import org.hamcrest.Description; -import org.hamcrest.TypeSafeMatcher; -import org.jvnet.hudson.test.JenkinsRule; - -/** - * Helper class to invoke {@link CLICommand} and check the response. - * - * @author ogondza - */ -public class CLICommandInvoker { - - private static final String username = "user"; - private final JenkinsRule rule; - private final CLICommand command; - - private InputStream stdin; - private List args = Collections.emptyList(); - private List permissions = Collections.emptyList(); - private Locale locale = Locale.ENGLISH; - - public CLICommandInvoker(final JenkinsRule rule, final CLICommand command) { - - if (command.getClass().getAnnotation(Extension.class) == null) { - - throw new AssertionError(String.format( - "Command %s is missing @Extension annotation.", - command.getClass() - )); - } - - this.rule = rule; - this.command = command; - } - - public CLICommandInvoker(final JenkinsRule rule, final String command) { - this.rule = rule; - this.command = CLICommand.clone(command); - - if (this.command == null) throw new AssertionError("No such command: " + command); - } - - public CLICommandInvoker authorizedTo(final Permission... permissions) { - - this.permissions = Arrays.asList(permissions); - return this; - } - - public CLICommandInvoker withStdin(final InputStream stdin) { - - if (stdin == null) throw new NullPointerException("No stdin provided"); - - this.stdin = stdin; - return this; - } - - public CLICommandInvoker withArgs(final String... args) { - - this.args = Arrays.asList(args); - return this; - } - - public Result invokeWithArgs(final String... args) { - - return withArgs(args).invoke(); - } - - public Result invoke() { - - setAuth(); - - final ByteArrayOutputStream out = new ByteArrayOutputStream(); - final ByteArrayOutputStream err = new ByteArrayOutputStream(); - - final int returnCode = command.main( - args, locale, stdin, new PrintStream(out), new PrintStream(err) - ); - - return new Result(returnCode, out, err); - } - - private void setAuth() { - - if (permissions.isEmpty()) return; - - JenkinsRule.DummySecurityRealm realm = rule.createDummySecurityRealm(); - realm.addGroups(username, "group"); - rule.jenkins.setSecurityRealm(realm); - - GlobalMatrixAuthorizationStrategy auth = new GlobalMatrixAuthorizationStrategy(); - for(Permission p: permissions) { - p.setEnabled(true); - auth.add(p, username); - } - rule.jenkins.setAuthorizationStrategy(auth); - - command.setTransportAuth(user().impersonate()); - // Otherwise it is SYSTEM, which would be relevant for a command overriding main: - ACL.impersonate(Jenkins.ANONYMOUS); - } - - public User user() { - - return User.get(username); - } - - public static class Result { - - private final int result; - private final ByteArrayOutputStream out; - private final ByteArrayOutputStream err; - - private Result( - final int result, - final ByteArrayOutputStream out, - final ByteArrayOutputStream err - ) { - - this.result = result; - this.out = out; - this.err = err; - } - - public int returnCode() { - - return result; - } - - public String stdout() { - - return out.toString(); - } - - public String stderr() { - - return err.toString(); - } - - @Override - public String toString() { - - StringBuilder builder = new StringBuilder("CLI command exited with ").append(result); - String stdout = stdout(); - if (!"".equals(stdout)) { - builder.append("\nSTDOUT:\n").append(stdout); - } - String stderr = stderr(); - if (!"".equals(stderr)) { - builder.append("\nSTDERR:\n").append(stderr); - } - - return builder.toString(); - } - } - - public abstract static class Matcher extends TypeSafeMatcher { - - private final String description; - - private Matcher(String description) { - this.description = description; - } - - @Override - protected void describeMismatchSafely(Result result, Description description) { - description.appendText(result.toString()); - } - - public void describeTo(Description description) { - description.appendText(this.description); - } - - public static Matcher hasNoStandardOutput() { - return new Matcher("No standard output") { - @Override protected boolean matchesSafely(Result result) { - return "".equals(result.stdout()); - } - }; - } - - public static Matcher hasNoErrorOutput() { - return new Matcher("No error output") { - @Override protected boolean matchesSafely(Result result) { - return "".equals(result.stderr()); - } - }; - } - - public static Matcher succeeded() { - return new Matcher("Exited with 0 return code") { - @Override protected boolean matchesSafely(Result result) { - return result.result == 0; - } - }; - } - - public static Matcher succeededSilently() { - return new Matcher("Succeeded silently") { - @Override protected boolean matchesSafely(Result result) { - return result.result == 0 && "".equals(result.stderr()) && "".equals(result.stdout()); - } - }; - } - - public static Matcher failedWith(final long expectedCode) { - return new Matcher("Exited with " + expectedCode + " return code") { - @Override protected boolean matchesSafely(Result result) { - return result.result == expectedCode; - } - }; - } - } -} diff --git a/test/src/main/java/hudson/util/SecretHelper.java b/test/src/main/java/hudson/util/SecretHelper.java deleted file mode 100644 index b76b1f8be41cbbfe7ed76c91a86f950a2ddae0d3..0000000000000000000000000000000000000000 --- a/test/src/main/java/hudson/util/SecretHelper.java +++ /dev/null @@ -1,10 +0,0 @@ -package hudson.util; - -/** - * @author Kohsuke Kawaguchi - */ -public class SecretHelper { - public static void set(String s) { - Secret.SECRET = s; - } -} diff --git a/test/src/main/java/jenkins/model/JenkinsAdaptor.java b/test/src/main/java/jenkins/model/JenkinsAdaptor.java deleted file mode 100644 index efe14b9cb10a19483ada62fc5dc5aefd855b9e1c..0000000000000000000000000000000000000000 --- a/test/src/main/java/jenkins/model/JenkinsAdaptor.java +++ /dev/null @@ -1,11 +0,0 @@ -package jenkins.model; - -/** - * Access the package protected quiet period - */ -public class JenkinsAdaptor { - public static void setQuietPeriod(Jenkins jenkins, int quietPeriod) { - jenkins.quietPeriod = quietPeriod; - } - -} diff --git a/test/src/main/java/org/jvnet/hudson/test/CaptureEnvironmentBuilder.java b/test/src/main/java/org/jvnet/hudson/test/CaptureEnvironmentBuilder.java deleted file mode 100644 index 775eb8d14648ed06ed9d9d0fd5101a8b470b333b..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/CaptureEnvironmentBuilder.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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; - -import hudson.Launcher; -import hudson.Extension; -import hudson.EnvVars; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.model.Descriptor; -import hudson.tasks.Builder; -import net.sf.json.JSONObject; -import org.kohsuke.stapler.StaplerRequest; - -import java.io.IOException; - -/** - * {@link Builder} that captures the environment variables used during a build. - * - * @author Kohsuke Kawaguchi - */ -public class CaptureEnvironmentBuilder extends Builder { - - private EnvVars envVars; - - public EnvVars getEnvVars() { - return envVars; - } - - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - envVars = build.getEnvironment(listener); - return true; - } - - @Extension - public static final class DescriptorImpl extends Descriptor { - public Builder newInstance(StaplerRequest req, JSONObject data) { - throw new UnsupportedOperationException(); - } - - public String getDisplayName() { - return "Capture Environment Variables"; - } - } -} diff --git a/test/src/main/java/org/jvnet/hudson/test/ChannelShutdownListener.java b/test/src/main/java/org/jvnet/hudson/test/ChannelShutdownListener.java deleted file mode 100644 index 935aeca28fdebc4f8823b03a0c1b00dd58310155..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/ChannelShutdownListener.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.jvnet.hudson.test; - -import hudson.Extension; -import hudson.model.Computer; -import hudson.model.TaskListener; -import hudson.remoting.Channel; -import hudson.remoting.VirtualChannel; -import hudson.slaves.ComputerListener; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -/** - * Runs at the end of the test to cleanup any live channels. - * -* @author Kohsuke Kawaguchi -*/ -@Extension -public class ChannelShutdownListener extends ComputerListener implements EndOfTestListener { - /** - * Remember channels that are created, to release them at the end. - */ - private List channels = new ArrayList(); - - @Override - public synchronized void onOnline(Computer c, TaskListener listener) throws IOException, InterruptedException { - VirtualChannel ch = c.getChannel(); - if (ch instanceof Channel) { - channels.add((Channel)ch); - } - } - - @Override - public synchronized void onTearDown() throws Exception { - for (Channel c : channels) - c.close(); - for (Channel c : channels) - c.join(); - channels.clear(); - } -} diff --git a/test/src/main/java/org/jvnet/hudson/test/ClosureExecuterAction.java b/test/src/main/java/org/jvnet/hudson/test/ClosureExecuterAction.java deleted file mode 100644 index 9feb531faf3d15299b04e35da700d7604e92badd..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/ClosureExecuterAction.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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; - -import hudson.Extension; -import hudson.model.RootAction; -import org.kohsuke.stapler.QueryParameter; -import org.kohsuke.stapler.StaplerResponse; - -import java.io.IOException; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -/** - * Server-side logic that implements {@link HudsonTestCase#executeOnServer(Callable)}. - * - * @author Kohsuke Kawaguchi - */ -@Extension -public final class ClosureExecuterAction implements RootAction { - private final Map runnables = Collections.synchronizedMap(new HashMap()); - - public void add(UUID uuid, Runnable r) { - runnables.put(uuid,r); - } - - public void doIndex(StaplerResponse rsp, @QueryParameter("uuid") String uuid) throws IOException { - Runnable r = runnables.remove(UUID.fromString(uuid)); - if (r!=null) { - r.run(); - } else { - rsp.sendError(404); - } - } - - public String getIconFileName() { - return null; - } - - public String getDisplayName() { - return null; - } - - public String getUrlName() { - return "closures"; - } -} diff --git a/test/src/main/java/org/jvnet/hudson/test/ComputerConnectorTester.java b/test/src/main/java/org/jvnet/hudson/test/ComputerConnectorTester.java deleted file mode 100644 index d69d2279ff9d9c7bce71b857c3ec5d7fdd2e7151..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/ComputerConnectorTester.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2010, InfraDNA, 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; - -import hudson.Extension; -import hudson.model.AbstractDescribableImpl; -import hudson.model.Descriptor; -import hudson.slaves.ComputerConnector; -import hudson.slaves.ComputerConnectorDescriptor; -import org.kohsuke.stapler.StaplerRequest; - -import javax.servlet.ServletException; -import java.io.IOException; -import java.util.List; - -/** - * Test bed to verify the configuration roundtripness of the {@link ComputerConnector}. - * - * @author Kohsuke Kawaguchi - * @see HudsonTestCase#computerConnectorTester - */ -public class ComputerConnectorTester extends AbstractDescribableImpl { - public final HudsonTestCase testCase; - public ComputerConnector connector; - - public ComputerConnectorTester(HudsonTestCase testCase) { - this.testCase = testCase; - } - - public void doConfigSubmit(StaplerRequest req) throws IOException, ServletException { - connector = req.bindJSON(ComputerConnector.class, req.getSubmittedForm().getJSONObject("connector")); - } - - public List getConnectorDescriptors() { - return ComputerConnectorDescriptor.all(); - } - - @Extension - public static class DescriptorImpl extends Descriptor { - @Override - public String getDisplayName() { - return ""; - } - } -} diff --git a/test/src/main/java/org/jvnet/hudson/test/DefaultConstructorChecker.java b/test/src/main/java/org/jvnet/hudson/test/DefaultConstructorChecker.java deleted file mode 100644 index 9c862edc4773d6a89af2497dcc74a39b9d124130..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/DefaultConstructorChecker.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.jvnet.hudson.test; - -import junit.framework.TestCase; - -/** - * Tests that the specified class has the default constructor. - * - * @author Kohsuke Kawaguchi - */ -public class DefaultConstructorChecker extends TestCase { - private final Class clazz; - - public DefaultConstructorChecker(Class clazz) { - this.clazz = clazz; - setName(clazz.getName()+".verifyDefaultConstructor"); - } - - @Override - protected void runTest() throws Throwable { - try { - clazz.getConstructor(); - } catch (NoSuchMethodException e) { - throw new Error(clazz+" must have the default constructor",e); - } catch (SecurityException e) { - throw new Error(clazz+" must have the default constructor",e); - } - } -} diff --git a/test/src/main/java/org/jvnet/hudson/test/EndOfTestListener.java b/test/src/main/java/org/jvnet/hudson/test/EndOfTestListener.java deleted file mode 100644 index e6d9c143cfd99c3f15a0f99bf8bbe527e517d06f..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/EndOfTestListener.java +++ /dev/null @@ -1,16 +0,0 @@ -package org.jvnet.hudson.test; - -import hudson.ExtensionPoint; - -/** - * Gets notified before the test completes to perform additional cleanup. - * - * @author Kohsuke Kawaguchi - * @since 1.520 - */ -public interface EndOfTestListener extends ExtensionPoint { - /** - * Called for clean up. - */ - void onTearDown() throws Exception; -} diff --git a/test/src/main/java/org/jvnet/hudson/test/ExtractChangeLogParser.java b/test/src/main/java/org/jvnet/hudson/test/ExtractChangeLogParser.java deleted file mode 100644 index a2bd723e6b4c72f028d1e30feaeb43a1fab43357..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/ExtractChangeLogParser.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * 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; - -import hudson.model.AbstractBuild; -import hudson.model.User; -import hudson.scm.ChangeLogParser; -import hudson.scm.ChangeLogSet; -import org.apache.commons.digester.Digester; -import org.kohsuke.stapler.export.Exported; -import org.kohsuke.stapler.export.ExportedBean; -import org.xml.sax.SAXException; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -/** - * @author Andrew Bayer - */ -public class ExtractChangeLogParser extends ChangeLogParser { - @SuppressWarnings("rawtypes") - @Override - public ExtractChangeLogSet parse(AbstractBuild build, File changeLogFile) throws IOException, SAXException { - if (changeLogFile.exists()) { - FileInputStream fis = new FileInputStream(changeLogFile); - ExtractChangeLogSet logSet = parse(build, fis); - fis.close(); - return logSet; - } else { - return new ExtractChangeLogSet(build, new ArrayList()); - } - } - - @SuppressWarnings("rawtypes") - public ExtractChangeLogSet parse(AbstractBuild build, InputStream changeLogStream) throws IOException, SAXException { - - ArrayList changeLog = new ArrayList(); - - Digester digester = new Digester(); - digester.setClassLoader(ExtractChangeLogSet.class.getClassLoader()); - digester.push(changeLog); - digester.addObjectCreate("*/extractChanges/entry", ExtractChangeLogEntry.class); - - digester.addBeanPropertySetter("*/extractChanges/entry/zipFile"); - - digester.addObjectCreate("*/extractChanges/entry/file", - FileInZip.class); - digester.addBeanPropertySetter("*/extractChanges/entry/file/fileName"); - digester.addSetNext("*/extractChanges/entry/file", "addFile"); - digester.addSetNext("*/extractChanges/entry", "add"); - - digester.parse(changeLogStream); - - return new ExtractChangeLogSet(build, changeLog); - } - - - @ExportedBean(defaultVisibility = 999) - public static class ExtractChangeLogEntry extends ChangeLogSet.Entry { - private List files = new ArrayList(); - private String zipFile; - - public ExtractChangeLogEntry() { - } - - public ExtractChangeLogEntry(String zipFile) { - this.zipFile = zipFile; - } - - public void setZipFile(String zipFile) { - this.zipFile = zipFile; - } - - @Exported - public String getZipFile() { - return zipFile; - } - - @Override - public void setParent(ChangeLogSet parent) { - super.setParent(parent); - } - - @Override - public Collection getAffectedPaths() { - Collection paths = new ArrayList(files.size()); - for (FileInZip file : files) { - paths.add(file.getFileName()); - } - return paths; - } - - @Override - @Exported - public User getAuthor() { - return User.get("testuser"); - } - - @Override - @Exported - public String getMsg() { - return "Extracted from " + zipFile; - } - - public void addFile(FileInZip fileName) { - files.add(fileName); - } - - public void addFiles(Collection fileNames) { - this.files.addAll(fileNames); - } - } - - @ExportedBean(defaultVisibility = 999) - public static class FileInZip { - private String fileName = ""; - - public FileInZip() { - } - - public FileInZip(String fileName) { - this.fileName = fileName; - } - - @Exported - public String getFileName() { - return fileName; - } - - public void setFileName(String fileName) { - this.fileName = fileName; - } - } - -} diff --git a/test/src/main/java/org/jvnet/hudson/test/ExtractResourceSCM.java b/test/src/main/java/org/jvnet/hudson/test/ExtractResourceSCM.java deleted file mode 100644 index 743eecde22a9f4d9469facabfc8b2b2472a63561..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/ExtractResourceSCM.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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; - -import hudson.FilePath; -import hudson.Launcher; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.scm.NullSCM; -import hudson.scm.SCM; -import org.apache.commons.io.FileUtils; - -import java.io.File; -import java.io.IOException; -import java.net.URL; - -/** - * {@link SCM} useful for testing that extracts the given resource as a zip file. - * - * @author Kohsuke Kawaguchi - */ -public class ExtractResourceSCM extends NullSCM { - private final URL zip; - - private String parentFolder; - - /** - * - * @param zip - */ - public ExtractResourceSCM(URL zip) { - if(zip==null) - throw new IllegalArgumentException(); - this.zip = zip; - } - - /** - * with this constructor your zip can contains a folder - * more usefull to create a project test zip foo.zip foo - * @param zip - * @param parentFolder - */ - public ExtractResourceSCM(URL zip, String parentFolder) { - if(zip==null) - throw new IllegalArgumentException(); - this.zip = zip; - this.parentFolder = parentFolder; - } - - @Override - public boolean checkout(AbstractBuild build, Launcher launcher, FilePath workspace, BuildListener listener, File changeLogFile) throws IOException, InterruptedException { - if (workspace.exists()) { - listener.getLogger().println("Deleting existing workspace " + workspace.getRemote()); - workspace.deleteRecursive(); - } - listener.getLogger().println("Staging "+zip); - workspace.unzipFrom(zip.openStream()); - if (parentFolder != null) { - FileUtils.copyDirectory( new File(workspace.getRemote() + "/" + parentFolder), new File( workspace.getRemote())); - } - return true; - } -} diff --git a/test/src/main/java/org/jvnet/hudson/test/ExtractResourceWithChangesSCM.java b/test/src/main/java/org/jvnet/hudson/test/ExtractResourceWithChangesSCM.java deleted file mode 100644 index cf2d9193fbf49b22912d391c0ad5eac5aaf32d84..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/ExtractResourceWithChangesSCM.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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; - -import hudson.FilePath; -import hudson.Launcher; -import hudson.Util; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.scm.ChangeLogParser; -import hudson.scm.NullSCM; -import hudson.scm.SCM; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.net.URL; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -/** - * {@link SCM} useful for testing that extracts the given resource as a zip file. - * - * @author Kohsuke Kawaguchi - */ -public class ExtractResourceWithChangesSCM extends NullSCM { - private final URL firstZip; - private final URL secondZip; - private final String moduleRoot; - - public ExtractResourceWithChangesSCM(URL firstZip, URL secondZip) { - if ((firstZip == null) || (secondZip == null)) - throw new IllegalArgumentException(); - this.firstZip = firstZip; - this.secondZip = secondZip; - this.moduleRoot = null; - } - - public ExtractResourceWithChangesSCM(URL firstZip, URL secondZip, String moduleRoot) { - if ((firstZip == null) || (secondZip == null)) - throw new IllegalArgumentException(); - this.firstZip = firstZip; - this.secondZip = secondZip; - this.moduleRoot = moduleRoot; - } - - @Override - public FilePath getModuleRoot(FilePath workspace) { - if (moduleRoot!=null) { - return workspace.child(moduleRoot); - } - return workspace; - } - - @Override - public boolean checkout(AbstractBuild build, Launcher launcher, FilePath workspace, BuildListener listener, File changeLogFile) throws IOException, InterruptedException { - if (workspace.exists()) { - listener.getLogger().println("Deleting existing workspace " + workspace.getRemote()); - workspace.deleteRecursive(); - } - listener.getLogger().println("Staging first zip: " + firstZip); - workspace.unzipFrom(firstZip.openStream()); - listener.getLogger().println("Staging second zip: " + secondZip); - workspace.unzipFrom(secondZip.openStream()); - - // Get list of files changed in secondZip. - ZipInputStream zip = new ZipInputStream(secondZip.openStream()); - ZipEntry e; - ExtractChangeLogParser.ExtractChangeLogEntry changeLog = new ExtractChangeLogParser.ExtractChangeLogEntry(secondZip.toString()); - - try { - while ((e = zip.getNextEntry()) != null) { - if (!e.isDirectory()) - changeLog.addFile(new ExtractChangeLogParser.FileInZip(e.getName())); - } - } - finally { - zip.close(); - } - saveToChangeLog(changeLogFile, changeLog); - - return true; - } - - @Override - public ChangeLogParser createChangeLogParser() { - return new ExtractChangeLogParser(); - } - - private static String escapeForXml(String string) { - return Util.xmlEscape(Util.fixNull(string)); - } - - public void saveToChangeLog(File changeLogFile, ExtractChangeLogParser.ExtractChangeLogEntry changeLog) throws IOException { - FileOutputStream outputStream = new FileOutputStream(changeLogFile); - - PrintStream stream = new PrintStream(outputStream, false, "UTF-8"); - - stream.println(""); - stream.println(""); - stream.println(""); - stream.println("" + escapeForXml(changeLog.getZipFile()) + ""); - - for (String fileName : changeLog.getAffectedPaths()) { - stream.println(""); - stream.println("" + escapeForXml(fileName) + ""); - stream.println(""); - } - - stream.println(""); - stream.println(""); - - stream.close(); - } - - /** - * Don't write 'this', so that subtypes can be implemented as anonymous class. - */ - private Object writeReplace() { return new Object(); } -} diff --git a/test/src/main/java/org/jvnet/hudson/test/FakeChangeLogSCM.java b/test/src/main/java/org/jvnet/hudson/test/FakeChangeLogSCM.java deleted file mode 100644 index e569e35ac88f21683c28b35ed4e545f0ba64de4f..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/FakeChangeLogSCM.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2011, 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.test; - -import hudson.FilePath; -import hudson.Launcher; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.model.InvisibleAction; -import hudson.model.User; -import hudson.scm.ChangeLogParser; -import hudson.scm.ChangeLogSet; -import hudson.scm.ChangeLogSet.Entry; -import hudson.scm.NullSCM; -import hudson.scm.SCM; -import hudson.scm.SCMDescriptor; -import org.xml.sax.SAXException; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -/** - * Fake SCM implementation that can report arbitrary commits from arbitrary users. - * - * @author Kohsuke Kawaguchi - */ -public class FakeChangeLogSCM extends NullSCM { - - /** - * Changes to be reported in the next build. - */ - private List entries = new ArrayList(); - - public EntryImpl addChange() { - EntryImpl e = new EntryImpl(); - entries.add(e); - return e; - } - - @Override - public boolean checkout(AbstractBuild build, Launcher launcher, FilePath remoteDir, BuildListener listener, File changeLogFile) throws IOException, InterruptedException { - new FilePath(changeLogFile).touch(0); - build.addAction(new ChangelogAction(entries)); - entries = new ArrayList(); - return true; - } - - @Override - public ChangeLogParser createChangeLogParser() { - return new FakeChangeLogParser(); - } - - @Override public SCMDescriptor getDescriptor() { - return new SCMDescriptor(null) { - @Override public String getDisplayName() { - return ""; - } - }; - } - - public static class ChangelogAction extends InvisibleAction { - private final List entries; - - public ChangelogAction(List entries) { - this.entries = entries; - } - } - - public static class FakeChangeLogParser extends ChangeLogParser { - @SuppressWarnings("rawtypes") - @Override - public FakeChangeLogSet parse(AbstractBuild build, File changelogFile) throws IOException, SAXException { - return new FakeChangeLogSet(build, build.getAction(ChangelogAction.class).entries); - } - } - - public static class FakeChangeLogSet extends ChangeLogSet { - private List entries; - - public FakeChangeLogSet(AbstractBuild build, List entries) { - super(build); - this.entries = entries; - } - - @Override - public boolean isEmptySet() { - return entries.isEmpty(); - } - - public Iterator iterator() { - return entries.iterator(); - } - } - - public static class EntryImpl extends Entry { - private String msg = "some commit message"; - private String author = "someone"; - - public EntryImpl withAuthor(String author) { - this.author = author; - return this; - } - - public EntryImpl withMsg(String msg) { - this.msg = msg; - return this; - } - - @Override - public String getMsg() { - return msg; - } - - @Override - public User getAuthor() { - return User.get(author); - } - - @Override - public Collection getAffectedPaths() { - return Collections.singleton("path"); - } - } -} diff --git a/test/src/main/java/org/jvnet/hudson/test/FakeLauncher.java b/test/src/main/java/org/jvnet/hudson/test/FakeLauncher.java deleted file mode 100644 index 9ca68019d4991ee5172bcf51c57a951fb057e182..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/FakeLauncher.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.jvnet.hudson.test; - -import hudson.Launcher.ProcStarter; -import hudson.Proc; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Fake a process launch. - * - * @author Kohsuke Kawaguchi - * @see PretendSlave - */ -public interface FakeLauncher { - /** - * Called whenever a {@link PretendSlave} is asked to fork a new process. - * - *

- * The callee can inspect the {@link ProcStarter} object to determine what process is being launched, - * and if necessary, fake a process launch by either returning a valid {@link Proc} object, or let - * the normal process launch happen by returning null. - */ - Proc onLaunch(ProcStarter p) throws IOException; - - /** - * Fake {@link Proc} implementation that represents a completed process. - */ - class FinishedProc extends Proc { - public final int exitCode; - - public FinishedProc(int exitCode) { - this.exitCode = exitCode; - } - - @Override - public boolean isAlive() throws IOException, InterruptedException { - return false; - } - - @Override - public void kill() throws IOException, InterruptedException { - throw new UnsupportedOperationException(); - } - - @Override - public int join() throws IOException, InterruptedException { - return exitCode; - } - - @Override - public InputStream getStdout() { - // TODO - throw new UnsupportedOperationException(); - } - - @Override - public InputStream getStderr() { - // TODO - throw new UnsupportedOperationException(); - } - - @Override - public OutputStream getStdin() { - // TODO - throw new UnsupportedOperationException(); - } - } -} diff --git a/test/src/main/java/org/jvnet/hudson/test/GroovyHudsonTestCase.java b/test/src/main/java/org/jvnet/hudson/test/GroovyHudsonTestCase.java deleted file mode 100644 index 9e7a90d431c04b764e4fe1d6c4b069a5b021c6bf..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/GroovyHudsonTestCase.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.jvnet.hudson.test; - -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; -import groovy.lang.Closure; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.tasks.Builder; -import hudson.Launcher; - -import java.util.concurrent.Callable; -import java.io.IOException; - -/** - * {@link HudsonTestCase} with more convenience methods for Groovy. - * - * @author Kohsuke Kawaguchi - * @deprecated Use {@link GroovyJenkinsRule} instead. - */ -@Deprecated -public abstract class GroovyHudsonTestCase extends HudsonTestCase { - /** - * Executes the given closure on the server, in the context of an HTTP request. - * This is useful for testing some methods that require {@link StaplerRequest} and {@link StaplerResponse}. - * - *

- * The closure will get the request and response as parameters. - */ - public Object executeOnServer(final Closure c) throws Exception { - return executeOnServer(new Callable() { - public Object call() throws Exception { - return c.call(); - } - }); - } - - /** - * Wraps a closure as a {@link Builder}. - */ - public Builder builder(final Closure c) { - return new TestBuilder() { - public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - Object r = c.call(new Object[]{build,launcher,listener}); - if (r instanceof Boolean) return (Boolean)r; - return true; - } - }; - } -} diff --git a/test/src/main/java/org/jvnet/hudson/test/GroovyJenkinsRule.java b/test/src/main/java/org/jvnet/hudson/test/GroovyJenkinsRule.java deleted file mode 100644 index 3c20aa713577a9fcaefadf4140e26ccedd1bcecf..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/GroovyJenkinsRule.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * The MIT License - * - * Copyright 2013 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 org.jvnet.hudson.test; - -import groovy.lang.Closure; -import hudson.Launcher; -import hudson.model.AbstractBuild; -import hudson.model.BuildListener; -import hudson.tasks.Builder; -import java.io.IOException; -import java.util.concurrent.Callable; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; - -/** - * {@link JenkinsRule} variant with special options for tests written in Groovy. - * @since 1.535 - */ -public class GroovyJenkinsRule extends JenkinsRule { - - /** - * Executes the given closure on the server, in the context of an HTTP request. - * This is useful for testing some methods that require {@link StaplerRequest} and {@link StaplerResponse}. - * - *

- * The closure will get the request and response as parameters. - */ - public Object executeOnServer(final Closure c) throws Exception { - return executeOnServer(new Callable() { - @Override public Object call() throws Exception { - return c.call(); - } - }); - } - - /** - * Wraps a closure as a {@link Builder}. - */ - public Builder builder(final Closure c) { - return new TestBuilder() { - @Override public boolean perform(AbstractBuild build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { - Object r = c.call(new Object[] {build, launcher, listener}); - if (r instanceof Boolean) { - return (Boolean) r; - } - return true; - } - }; - } - -} diff --git a/test/src/main/java/org/jvnet/hudson/test/HudsonHomeLoader.java b/test/src/main/java/org/jvnet/hudson/test/HudsonHomeLoader.java deleted file mode 100644 index 303de9593ee947c6e02a5b71f55fc7bbeca4a978..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/HudsonHomeLoader.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * 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. - */ -package org.jvnet.hudson.test; - -import hudson.FilePath; -import org.apache.commons.io.FileUtils; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; - -/** - * Controls how a {@link HudsonTestCase} initializes JENKINS_HOME. - * - * @author Kohsuke Kawaguchi - */ -public interface HudsonHomeLoader { - /** - * Returns a directory to be used as JENKINS_HOME - * - * @throws Exception - * to cause a test to fail. - */ - File allocate() throws Exception; - - /** - * Allocates a new empty directory, meaning this will emulate the fresh Hudson installation. - */ - HudsonHomeLoader NEW = new HudsonHomeLoader() { - public File allocate() throws IOException { - return TestEnvironment.get().temporaryDirectoryAllocator.allocate(); - } - }; - - /** - * Allocates a new directory by copying from an existing directory, or unzipping from a zip file. - */ - final class CopyExisting implements HudsonHomeLoader { - private final URL source; - - /** - * Either a zip file or a directory that contains the home image. - */ - public CopyExisting(File source) throws MalformedURLException { - this(source.toURI().toURL()); - } - - /** - * Extracts from a zip file in the resource. - * - *

- * This is useful in case you want to have a test data in the resources. - * Only file URL is supported. - */ - public CopyExisting(URL source) { - this.source = source; - } - - public File allocate() throws Exception { - File target = NEW.allocate(); - if(source.getProtocol().equals("file")) { - File src = new File(source.toURI()); - if(src.isDirectory()) - new FilePath(src).copyRecursiveTo("**/*",new FilePath(target)); - else - if(src.getName().endsWith(".zip")) - new FilePath(src).unzip(new FilePath(target)); - } else { - File tmp = File.createTempFile("hudson","zip"); - try { - FileUtils.copyURLToFile(source,tmp); - new FilePath(tmp).unzip(new FilePath(target)); - } finally { - tmp.delete(); - } - } - return target; - } - } - - /** - * Allocates a new directory by copying from a test resource - */ - final class Local implements HudsonHomeLoader { - private final Method testMethod; - - public Local(Method testMethod) { - this.testMethod = testMethod; - } - - public File allocate() throws Exception { - URL res = findDataResource(); - if(!res.getProtocol().equals("file")) - throw new AssertionError("Test data is not available in the file system: "+res); - // if we picked up a directory, it's one level above config.xml - File home = new File(res.toURI()); - if(!home.getName().endsWith(".zip")) - home = home.getParentFile(); - - return new CopyExisting(home).allocate(); - } - - private URL findDataResource() { - // first, check method specific resource - Class clazz = testMethod.getDeclaringClass(); - - for( String middle : new String[]{ '/'+testMethod.getName(), "" }) { - for( String suffix : SUFFIXES ) { - URL res = clazz.getResource(clazz.getSimpleName() + middle+suffix); - if(res!=null) return res; - } - } - - throw new AssertionError("No test resource was found for "+testMethod); - } - - private static final String[] SUFFIXES = {"/config.xml",".zip"}; - } -} diff --git a/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java b/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java deleted file mode 100644 index 7c62154b98a86669c11ed2bbe146a4c37cc82cda..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/HudsonTestCase.java +++ /dev/null @@ -1,2035 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2004-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi, Erik Ramfelt, - * Yahoo! Inc., Tom Huybrechts, Olivier Lamy - * - * 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 com.gargoylesoftware.htmlunit.AlertHandler; -import com.gargoylesoftware.htmlunit.html.HtmlImage; -import com.google.inject.Injector; - -import hudson.ClassicPluginStrategy; -import hudson.CloseProofOutputStream; -import hudson.DNSMultiCast; -import hudson.DescriptorExtensionList; -import hudson.EnvVars; -import hudson.Extension; -import hudson.ExtensionList; -import hudson.FilePath; -import hudson.Functions; -import hudson.Functions.ThreadGroupMap; -import hudson.Launcher; -import hudson.Launcher.LocalLauncher; -import hudson.Main; -import hudson.PluginManager; -import hudson.Util; -import hudson.WebAppMain; -import hudson.matrix.MatrixBuild; -import hudson.matrix.MatrixProject; -import hudson.matrix.MatrixRun; -import hudson.maven.MavenBuild; -import hudson.maven.MavenEmbedder; -import hudson.maven.MavenEmbedderException; -import hudson.maven.MavenModule; -import hudson.maven.MavenModuleSet; -import hudson.maven.MavenModuleSetBuild; -import hudson.maven.MavenUtil; -import hudson.model.*; -import hudson.model.Executor; -import hudson.model.Node.Mode; -import hudson.model.Queue.Executable; -import hudson.os.PosixAPI; -import hudson.remoting.Which; -import hudson.security.ACL; -import hudson.security.AbstractPasswordBasedSecurityRealm; -import hudson.security.GroupDetails; -import hudson.security.SecurityRealm; -import hudson.security.csrf.CrumbIssuer; -import hudson.slaves.CommandLauncher; -import hudson.slaves.ComputerConnector; -import hudson.slaves.ComputerListener; -import hudson.slaves.DumbSlave; -import hudson.slaves.NodeProperty; -import hudson.slaves.RetentionStrategy; -import hudson.tasks.Ant; -import hudson.tasks.Ant.AntInstallation; -import hudson.tasks.BuildWrapper; -import hudson.tasks.BuildWrapperDescriptor; -import hudson.tasks.Builder; -import hudson.tasks.Mailer; -import hudson.tasks.Maven; -import hudson.tasks.Maven.MavenInstallation; -import hudson.tasks.Publisher; -import hudson.tools.ToolProperty; -import hudson.util.PersistedList; -import hudson.util.ReflectionUtils; -import hudson.util.StreamTaskListener; - -import java.beans.PropertyDescriptor; -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.annotation.Annotation; -import java.lang.management.ThreadInfo; -import java.lang.reflect.Array; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Timer; -import java.util.TimerTask; -import java.util.UUID; -import java.util.concurrent.*; -import java.util.jar.Manifest; -import java.util.logging.Filter; -import java.util.logging.Level; -import java.util.logging.LogRecord; -import java.util.logging.Logger; - -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; - -import jenkins.model.Jenkins; -import jenkins.model.JenkinsAdaptor; -import junit.framework.TestCase; -import net.sf.json.JSONObject; -import net.sourceforge.htmlunit.corejs.javascript.Context; -import net.sourceforge.htmlunit.corejs.javascript.ContextFactory.Listener; - -import org.acegisecurity.AuthenticationException; -import org.acegisecurity.BadCredentialsException; -import org.acegisecurity.GrantedAuthority; -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; -import org.codehaus.plexus.component.repository.exception.ComponentLookupException; -import org.jvnet.hudson.test.HudsonHomeLoader.CopyExisting; -import org.jvnet.hudson.test.recipes.Recipe; -import org.jvnet.hudson.test.recipes.Recipe.Runner; -import org.jvnet.hudson.test.recipes.WithPlugin; -import org.jvnet.hudson.test.rhino.JavaScriptDebugger; -import org.kohsuke.stapler.ClassDescriptor; -import org.kohsuke.stapler.DataBoundConstructor; -import org.kohsuke.stapler.Dispatcher; -import org.kohsuke.stapler.MetaClass; -import org.kohsuke.stapler.MetaClassLoader; -import org.kohsuke.stapler.Stapler; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; -import org.mortbay.jetty.MimeTypes; -import org.mortbay.jetty.Server; -import org.mortbay.jetty.bio.SocketConnector; -import org.mortbay.jetty.security.HashUserRealm; -import org.mortbay.jetty.security.UserRealm; -import org.mortbay.jetty.webapp.Configuration; -import org.mortbay.jetty.webapp.WebAppContext; -import org.mortbay.jetty.webapp.WebXmlConfiguration; -import org.mozilla.javascript.tools.debugger.Dim; -import org.mozilla.javascript.tools.shell.Global; -import org.springframework.dao.DataAccessException; -import org.w3c.css.sac.CSSException; -import org.w3c.css.sac.CSSParseException; -import org.w3c.css.sac.ErrorHandler; -import org.xml.sax.SAXException; - -import com.gargoylesoftware.htmlunit.AjaxController; -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; -import com.gargoylesoftware.htmlunit.html.HtmlForm; -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.xml.XmlPage; - -import java.net.HttpURLConnection; - -import jenkins.model.JenkinsLocationConfiguration; - -/** - * Base class for all Jenkins test cases. - * - * @see Wiki article about unit testing in Hudson - * @author Kohsuke Kawaguchi - * @deprecated New code should use {@link JenkinsRule}. - */ -@Deprecated -@SuppressWarnings("rawtypes") -public abstract class HudsonTestCase extends TestCase implements RootAction { - /** - * Points to the same object as {@link #jenkins} does. - */ - public Hudson hudson; - - public Jenkins jenkins; - - protected final TestEnvironment env = new TestEnvironment(this); - protected HudsonHomeLoader homeLoader = HudsonHomeLoader.NEW; - /** - * TCP/IP port that the server is listening on. - */ - protected int localPort; - protected Server server; - - /** - * Where in the {@link Server} is Hudson deployed? - *

- * Just like {@link ServletContext#getContextPath()}, starts with '/' but doesn't end with '/'. - */ - protected String contextPath = ""; - - /** - * {@link Runnable}s to be invoked at {@link #tearDown()}. - */ - protected List tearDowns = new ArrayList(); - - protected List recipes = new ArrayList(); - - /** - * Remember {@link WebClient}s that are created, to release them properly. - */ - private List clients = new ArrayList(); - - /** - * JavaScript "debugger" that provides you information about the JavaScript call stack - * and the current values of the local variables in those stack frame. - * - *

- * Unlike Java debugger, which you as a human interfaces directly and interactively, - * this JavaScript debugger is to be interfaced by your program (or through the - * expression evaluation capability of your Java debugger.) - */ - protected JavaScriptDebugger jsDebugger = new JavaScriptDebugger(); - - /** - * If this test case has additional {@link WithPlugin} annotations, set to true. - * This will cause a fresh {@link PluginManager} to be created for this test. - * Leaving this to false enables the test harness to use a pre-loaded plugin manager, - * which runs faster. - * - * @deprecated - * Use {@link #pluginManager} - */ - public boolean useLocalPluginManager; - - /** - * Number of seconds until the test times out. - */ - public int timeout = Integer.getInteger("jenkins.test.timeout", 180); - - private volatile Timer timeoutTimer; - - /** - * Set the plugin manager to be passed to {@link Jenkins} constructor. - * - * For historical reasons, {@link #useLocalPluginManager}==true will take the precedence. - */ - private PluginManager pluginManager = TestPluginManager.INSTANCE; - - public ComputerConnectorTester computerConnectorTester = new ComputerConnectorTester(this); - - /** - * The directory where a war file gets exploded. - */ - protected File explodedWarDir; - - protected HudsonTestCase(String name) { - super(name); - } - - protected HudsonTestCase() { - } - - @Override - public void runBare() throws Throwable { - // override the thread name to make the thread dump more useful. - Thread t = Thread.currentThread(); - String o = getClass().getName()+'.'+t.getName(); - t.setName("Executing "+getName()); - try { - super.runBare(); - } finally { - t.setName(o); - } - } - - @Override - protected void setUp() throws Exception { - env.pin(); - recipe(); - for (Runner r : recipes) { - if (r instanceof WithoutJenkins.RunnerImpl) - return; // no setup - } - AbstractProject.WORKSPACE.toString(); - User.clear(); - - // just in case tearDown failed in the middle, make sure to really clean them up so that there's no left-over from earlier tests - ExtensionList.clearLegacyInstances(); - DescriptorExtensionList.clearLegacyInstances(); - - try { - jenkins = hudson = newHudson(); - } catch (Exception e) { - // if Jenkins instance fails to initialize, it leaves the instance field non-empty and break all the rest of the tests, so clean that up. - Field f = Jenkins.class.getDeclaredField("theInstance"); - f.setAccessible(true); - f.set(null,null); - throw e; - } - jenkins.setNoUsageStatistics(true); // collecting usage stats from tests are pointless. - - jenkins.setCrumbIssuer(new TestCrumbIssuer()); - - jenkins.servletContext.setAttribute("app", jenkins); - jenkins.servletContext.setAttribute("version","?"); - WebAppMain.installExpressionFactory(new ServletContextEvent(jenkins.servletContext)); - Mailer.descriptor().setHudsonUrl(getURL().toExternalForm()); // for compatibility only - JenkinsLocationConfiguration.get().setUrl(getURL().toString()); // in case we are using older mailer plugin - - // set a default JDK to be the one that the harness is using. - jenkins.getJDKs().add(new JDK("default",System.getProperty("java.home"))); - - configureUpdateCenter(); - - // expose the test instance as a part of URL tree. - // this allows tests to use a part of the URL space for itself. - jenkins.getActions().add(this); - - // cause all the descriptors to reload. - // ideally we'd like to reset them to properly emulate the behavior, but that's not possible. - for( Descriptor d : jenkins.getExtensionList(Descriptor.class) ) - d.load(); - - // allow the test class to inject Jenkins components - jenkins.lookup(Injector.class).injectMembers(this); - - setUpTimeout(); - } - - protected void setUpTimeout() { - if (timeout<=0) return; // no timeout - - final Thread testThread = Thread.currentThread(); - timeoutTimer = new Timer(); - timeoutTimer.schedule(new TimerTask() { - @Override - public void run() { - if (timeoutTimer!=null) { - LOGGER.warning(String.format("Test timed out (after %d seconds).", timeout)); - testThread.interrupt(); - } - } - }, TimeUnit.SECONDS.toMillis(timeout)); - } - - - /** - * Configures the update center setting for the test. - * By default, we load updates from local proxy to avoid network traffic as much as possible. - */ - protected void configureUpdateCenter() throws Exception { - final String updateCenterUrl = "http://localhost:"+ JavaNetReverseProxy.getInstance().localPort+"/update-center.json"; - - // don't waste bandwidth talking to the update center - DownloadService.neverUpdate = true; - UpdateSite.neverUpdate = true; - - PersistedList sites = jenkins.getUpdateCenter().getSites(); - sites.clear(); - sites.add(new UpdateSite("default", updateCenterUrl)); - } - - @Override - protected void tearDown() throws Exception { - try { - if (jenkins!=null) { - for (EndOfTestListener tl : jenkins.getExtensionList(EndOfTestListener.class)) - 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 - client.getPage("about:blank"); - client.closeAllWindows(); - } - clients.clear(); - } finally { - if (server!=null) - server.stop(); - for (LenientRunnable r : tearDowns) - r.run(); - - if (jenkins!=null) - jenkins.cleanUp(); - env.dispose(); - ExtensionList.clearLegacyInstances(); - DescriptorExtensionList.clearLegacyInstances(); - - // Jenkins 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. - // see http://bugs.sun.com/view_bug.do?bug_id=4950148 - System.gc(); - } - } - - @Override - protected void runTest() throws Throwable { - System.out.println("=== Starting "+ getClass().getSimpleName() + "." + getName()); - // so that test code has all the access to the system - ACL.impersonate(ACL.SYSTEM); - - try { - super.runTest(); - } catch (Throwable t) { - // allow the late attachment of a debugger in case of a failure. Useful - // for diagnosing a rare failure - try { - throw new BreakException(); - } catch (BreakException e) {} - - // dump threads - ThreadInfo[] threadInfos = Functions.getThreadInfos(); - ThreadGroupMap m = Functions.sortThreadsAndGetGroupMap(threadInfos); - for (ThreadInfo ti : threadInfos) { - System.err.println(Functions.dumpThreadInfo(ti, m)); - } - throw t; - } - } - - @SuppressWarnings("serial") - public static class BreakException extends Exception {} - - public String getIconFileName() { - return null; - } - - public String getDisplayName() { - return null; - } - - public String getUrlName() { - return "self"; - } - - /** - * Creates a new instance of {@link jenkins.model.Jenkins}. If the derived class wants to create it in a different way, - * you can override it. - */ - protected Hudson newHudson() throws Exception { - File home = homeLoader.allocate(); - for (Runner r : recipes) - r.decorateHome(this,home); - return new Hudson(home, createWebServer(), useLocalPluginManager ? null : pluginManager); - } - - /** - * Sets the {@link PluginManager} to be used when creating a new {@link Jenkins} instance. - * - * @param pluginManager - * null to let Jenkins create a new instance of default plugin manager, like it normally does when running as a webapp outside the test. - */ - public void setPluginManager(PluginManager pluginManager) { - this.useLocalPluginManager = false; - this.pluginManager = pluginManager; - if (jenkins !=null) - throw new IllegalStateException("Too late to override the plugin manager"); - } - - /** - * Prepares a webapp hosting environment to get {@link ServletContext} implementation - * that we need for testing. - */ - protected ServletContext createWebServer() throws Exception { - server = new Server(); - - explodedWarDir = WarExploder.getExplodedDir(); - WebAppContext context = new WebAppContext(explodedWarDir.getPath(), contextPath); - context.setClassLoader(getClass().getClassLoader()); - context.setConfigurations(new Configuration[]{new WebXmlConfiguration(), new NoListenerConfiguration()}); - server.setHandler(context); - context.setMimeTypes(MIME_TYPES); - - SocketConnector connector = new SocketConnector(); - connector.setHeaderBufferSize(12*1024); // use a bigger buffer as Stapler traces can get pretty large on deeply nested URL - - server.setThreadPool(new ThreadPoolImpl(new ThreadPoolExecutor(10, 10, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue(),new ThreadFactory() { - public Thread newThread(Runnable r) { - Thread t = new Thread(r); - t.setName("Jetty Thread Pool"); - return t; - } - }))); - server.addConnector(connector); - server.addUserRealm(configureUserRealm()); - server.start(); - - localPort = connector.getLocalPort(); - - return context.getServletContext(); - } - - /** - * Configures a security realm for a test. - */ - protected UserRealm configureUserRealm() { - HashUserRealm realm = new HashUserRealm(); - realm.setName("default"); // this is the magic realm name to make it effective on everywhere - realm.put("alice","alice"); - realm.put("bob","bob"); - realm.put("charlie","charlie"); - - realm.addUserToRole("alice","female"); - realm.addUserToRole("bob","male"); - realm.addUserToRole("charlie","male"); - - return realm; - } - - /** - * Returns the older default Maven, while still allowing specification of other bundled Mavens. - */ - protected MavenInstallation configureDefaultMaven() throws Exception { - return configureDefaultMaven("apache-maven-2.2.1", MavenInstallation.MAVEN_20); - } - - protected MavenInstallation configureMaven3() throws Exception { - MavenInstallation mvn = configureDefaultMaven("apache-maven-3.0.1", MavenInstallation.MAVEN_30); - - MavenInstallation m3 = new MavenInstallation("apache-maven-3.0.1",mvn.getHome(), NO_PROPERTIES); - jenkins.getDescriptorByType(Maven.DescriptorImpl.class).setInstallations(m3); - return m3; - } - - protected MavenInstallation configureMaven31() throws Exception { - MavenInstallation mvn = configureDefaultMaven("apache-maven-3.1.0", MavenInstallation.MAVEN_30); - - MavenInstallation m3 = new MavenInstallation("apache-maven-3.1.0",mvn.getHome(), NO_PROPERTIES); - jenkins.getDescriptorByType(Maven.DescriptorImpl.class).setInstallations(m3); - return m3; - } - - /** - * Locates Maven and configures that as the only Maven in the system. - */ - protected MavenInstallation configureDefaultMaven(String mavenVersion, int mavenReqVersion) throws Exception { - // Does it exists in the buildDirectory - i.e. already extracted from previous test? - // defined in jenkins-test-harness POM, but not plugins; TODO should not use relative paths as we do not know what CWD is - File buildDirectory = new File(System.getProperty("buildDirectory", "target")); - File mvnHome = new File(buildDirectory, mavenVersion); - if (mvnHome.exists()) { - MavenInstallation mavenInstallation = new MavenInstallation("default", mvnHome.getAbsolutePath(), NO_PROPERTIES); - jenkins.getDescriptorByType(Maven.DescriptorImpl.class).setInstallations(mavenInstallation); - return mavenInstallation; - } - - // Does maven.home point to a Maven installation which satisfies mavenReqVersion? - String home = System.getProperty("maven.home"); - if(home!=null) { - MavenInstallation mavenInstallation = new MavenInstallation("default",home, NO_PROPERTIES); - if (mavenInstallation.meetsMavenReqVersion(createLocalLauncher(), mavenReqVersion)) { - jenkins.getDescriptorByType(Maven.DescriptorImpl.class).setInstallations(mavenInstallation); - return mavenInstallation; - } - } - - // otherwise extract the copy we have. - // this happens when a test is invoked from an IDE, for example. - LOGGER.warning("Extracting a copy of Maven bundled in the test harness into " + mvnHome + ". " + - "To avoid a performance hit, set the system property 'maven.home' to point to a Maven2 installation."); - FilePath mvn = jenkins.getRootPath().createTempFile("maven", "zip"); - mvn.copyFrom(HudsonTestCase.class.getClassLoader().getResource(mavenVersion + "-bin.zip")); - mvn.unzip(new FilePath(buildDirectory)); - // TODO: switch to tar that preserves file permissions more easily - if(!Functions.isWindows()) { - PosixAPI.jnr().chmod(new File(mvnHome, "bin/mvn").getPath(), 0755); - } - - MavenInstallation mavenInstallation = new MavenInstallation("default", - mvnHome.getAbsolutePath(), NO_PROPERTIES); - jenkins.getDescriptorByType(Maven.DescriptorImpl.class).setInstallations(mavenInstallation); - return mavenInstallation; - } - - /** - * Extracts Ant and configures it. - */ - protected Ant.AntInstallation configureDefaultAnt() throws Exception { - Ant.AntInstallation antInstallation; - if (System.getenv("ANT_HOME") != null) { - antInstallation = new AntInstallation("default", System.getenv("ANT_HOME"), NO_PROPERTIES); - } else { - LOGGER.warning("Extracting a copy of Ant bundled in the test harness. " + - "To avoid a performance hit, set the environment variable ANT_HOME to point to an Ant installation."); - FilePath ant = jenkins.getRootPath().createTempFile("ant", "zip"); - ant.copyFrom(HudsonTestCase.class.getClassLoader().getResource("apache-ant-1.8.1-bin.zip")); - File antHome = createTmpDir(); - ant.unzip(new FilePath(antHome)); - // TODO: switch to tar that preserves file permissions more easily - if(!Functions.isWindows()) { - PosixAPI.jnr().chmod(new File(antHome,"apache-ant-1.8.1/bin/ant").getPath(),0755); - } - - antInstallation = new AntInstallation("default", new File(antHome,"apache-ant-1.8.1").getAbsolutePath(),NO_PROPERTIES); - } - jenkins.getDescriptorByType(Ant.DescriptorImpl.class).setInstallations(antInstallation); - return antInstallation; - } - -// -// Convenience methods -// - - protected FreeStyleProject createFreeStyleProject() throws IOException { - return createFreeStyleProject(createUniqueProjectName()); - } - - protected FreeStyleProject createFreeStyleProject(String name) throws IOException { - return jenkins.createProject(FreeStyleProject.class, name); - } - - protected MatrixProject createMatrixProject() throws IOException { - return createMatrixProject(createUniqueProjectName()); - } - - protected MatrixProject createMatrixProject(String name) throws IOException { - return jenkins.createProject(MatrixProject.class, name); - } - - /** - * Creates a empty Maven project with an unique name. - * - * @see #configureDefaultMaven() - */ - protected MavenModuleSet createMavenProject() throws IOException { - return createMavenProject(createUniqueProjectName()); - } - - /** - * Creates a empty Maven project with the given name. - * - * @see #configureDefaultMaven() - */ - protected MavenModuleSet createMavenProject(String name) throws IOException { - MavenModuleSet mavenModuleSet = jenkins.createProject(MavenModuleSet.class,name); - mavenModuleSet.setRunHeadless( true ); - return mavenModuleSet; - } - - protected String createUniqueProjectName() { - return "test"+ jenkins.getItems().size(); - } - - /** - * Creates {@link LocalLauncher}. Useful for launching processes. - */ - protected LocalLauncher createLocalLauncher() { - return new LocalLauncher(StreamTaskListener.fromStdout()); - } - - /** - * Allocates a new temporary directory for the duration of this test. - */ - public File createTmpDir() throws IOException { - return env.temporaryDirectoryAllocator.allocate(); - } - - public DumbSlave createSlave() throws Exception { - return createSlave("",null); - } - - /** - * Creates and launches a new slave on the local host. - */ - public DumbSlave createSlave(Label l) throws Exception { - return createSlave(l, null); - } - - /** - * Creates a test {@link SecurityRealm} that recognizes username==password as valid. - */ - public SecurityRealm createDummySecurityRealm() { - return new AbstractPasswordBasedSecurityRealm() { - @Override - protected UserDetails authenticate(String username, String password) throws AuthenticationException { - if (username.equals(password)) - return loadUserByUsername(username); - throw new BadCredentialsException(username); - } - - @Override - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { - return new org.acegisecurity.userdetails.User(username,"",true,true,true,true,new GrantedAuthority[]{AUTHENTICATED_AUTHORITY}); - } - - @Override - public GroupDetails loadGroupByGroupname(String groupname) throws UsernameNotFoundException, DataAccessException { - throw new UsernameNotFoundException(groupname); - } - }; - } - - /** - * Returns the URL of the webapp top page. - * URL ends with '/'. - */ - public URL getURL() throws IOException { - return new URL("http://localhost:"+localPort+contextPath+"/"); - } - - public DumbSlave createSlave(EnvVars env) throws Exception { - return createSlave("",env); - } - - public DumbSlave createSlave(Label l, EnvVars env) throws Exception { - return createSlave(l==null ? null : l.getExpression(), env); - } - - /** - * Creates a slave with certain additional environment variables - */ - public DumbSlave createSlave(String labels, EnvVars env) throws Exception { - synchronized (jenkins) { - int sz = jenkins.getNodes().size(); - return createSlave("slave" + sz,labels,env); - } - } - - public DumbSlave createSlave(String nodeName, String labels, EnvVars env) throws Exception { - synchronized (jenkins) { - DumbSlave slave = new DumbSlave(nodeName, "dummy", - createTmpDir().getPath(), "1", Mode.NORMAL, labels==null?"":labels, createComputerLauncher(env), - RetentionStrategy.NOOP, Collections.>emptyList()); - jenkins.addNode(slave); - return slave; - } - } - - public PretendSlave createPretendSlave(FakeLauncher faker) throws Exception { - synchronized (jenkins) { - int sz = jenkins.getNodes().size(); - PretendSlave slave = new PretendSlave("slave" + sz, createTmpDir().getPath(), "", createComputerLauncher(null), faker); - jenkins.addNode(slave); - return slave; - } - } - - /** - * Creates a {@link CommandLauncher} for launching a slave locally. - * - * @param env - * Environment variables to add to the slave process. Can be null. - */ - public CommandLauncher createComputerLauncher(EnvVars env) throws URISyntaxException, MalformedURLException { - int sz = jenkins.getNodes().size(); - return new CommandLauncher( - String.format("\"%s/bin/java\" %s -jar \"%s\"", - System.getProperty("java.home"), - SLAVE_DEBUG_PORT>0 ? " -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address="+(SLAVE_DEBUG_PORT+sz): "", - new File(jenkins.getJnlpJars("slave.jar").getURL().toURI()).getAbsolutePath()), - env); - } - - /** - * Create a new slave on the local host and wait for it to come onilne - * before returning. - */ - public DumbSlave createOnlineSlave() throws Exception { - return createOnlineSlave(null); - } - - /** - * Create a new slave on the local host and wait for it to come onilne - * before returning. - */ - public DumbSlave createOnlineSlave(Label l) throws Exception { - return createOnlineSlave(l, null); - } - - /** - * Create a new slave on the local host and wait for it to come online - * before returning - */ - @SuppressWarnings("deprecation") - public DumbSlave createOnlineSlave(Label l, EnvVars env) throws Exception { - final CountDownLatch latch = new CountDownLatch(1); - ComputerListener waiter = new ComputerListener() { - @Override - public void onOnline(Computer C, TaskListener t) { - latch.countDown(); - unregister(); - } - }; - waiter.register(); - - DumbSlave s = createSlave(l, env); - latch.await(); - - return s; - } - - /** - * Blocks until the ENTER key is hit. - * This is useful during debugging a test so that one can inspect the state of Jenkins through the web browser. - */ - public void interactiveBreak() throws Exception { - System.out.println("Jenkins is running at http://localhost:"+localPort+"/"); - new BufferedReader(new InputStreamReader(System.in)).readLine(); - } - - /** - * Returns the last item in the list. - */ - protected T last(List items) { - return items.get(items.size()-1); - } - - /** - * Pauses the execution until ENTER is hit in the console. - *

- * This is often very useful so that you can interact with Hudson - * from an browser, while developing a test case. - */ - protected void pause() throws IOException { - new BufferedReader(new InputStreamReader(System.in)).readLine(); - } - - /** - * Performs a search from the search box. - */ - protected Page search(String q) throws Exception { - return new WebClient().search(q); - } - - /** - * Hits the Hudson system configuration and submits without any modification. - */ - protected void configRoundtrip() throws Exception { - submit(createWebClient().goTo("configure").getFormByName("config")); - } - - /** - * Loads a configuration page and submits it without any modifications, to - * perform a round-trip configuration test. - *

- * See http://wiki.jenkins-ci.org/display/JENKINS/Unit+Test#UnitTest-Configurationroundtriptesting - */ - protected

P configRoundtrip(P job) throws Exception { - submit(createWebClient().getPage(job,"configure").getFormByName("config")); - return job; - } - - protected

P configRoundtrip(P job) throws Exception { - submit(createWebClient().getPage(job, "configure").getFormByName("config")); - return job; - } - - /** - * Performs a configuration round-trip testing for a builder. - */ - @SuppressWarnings("unchecked") - protected B configRoundtrip(B before) throws Exception { - FreeStyleProject p = createFreeStyleProject(); - p.getBuildersList().add(before); - configRoundtrip((Item)p); - return (B)p.getBuildersList().get(before.getClass()); - } - - /** - * Performs a configuration round-trip testing for a publisher. - */ - @SuppressWarnings("unchecked") - protected

P configRoundtrip(P before) throws Exception { - FreeStyleProject p = createFreeStyleProject(); - p.getPublishersList().add(before); - configRoundtrip((Item) p); - return (P)p.getPublishersList().get(before.getClass()); - } - - @SuppressWarnings("unchecked") - protected C configRoundtrip(C before) throws Exception { - computerConnectorTester.connector = before; - submit(createWebClient().goTo("self/computerConnectorTester/configure").getFormByName("config")); - return (C)computerConnectorTester.connector; - } - - protected User configRoundtrip(User u) throws Exception { - submit(createWebClient().goTo(u.getUrl()+"/configure").getFormByName("config")); - return u; - } - - @SuppressWarnings("unchecked") - protected N configRoundtrip(N node) throws Exception { - submit(createWebClient().goTo("/computer/" + node.getNodeName() + "/configure").getFormByName("config")); - return (N) jenkins.getNode(node.getNodeName()); - } - - protected V configRoundtrip(V view) throws Exception { - submit(createWebClient().getPage(view, "configure").getFormByName("viewConfig")); - return view; - } - - - /** - * Asserts that the outcome of the build is a specific outcome. - */ - public R assertBuildStatus(Result status, R r) throws Exception { - if(status==r.getResult()) - return r; - - // dump the build output in failure message - String msg = "unexpected build status; build log was:\n------\n" + getLog(r) + "\n------\n"; - if(r instanceof MatrixBuild) { - MatrixBuild mb = (MatrixBuild)r; - for (MatrixRun mr : mb.getRuns()) { - msg+="--- "+mr.getParent().getCombination()+" ---\n"+getLog(mr)+"\n------\n"; - } - } - assertEquals(msg, status,r.getResult()); - return r; - } - - /** Determines whether the specified HTTP status code is generally "good" */ - public boolean isGoodHttpStatus(int status) { - if ((400 <= status) && (status <= 417)) { - return false; - } - if ((500 <= status) && (status <= 505)) { - return false; - } - return true; - } - - /** Assert that the specified page can be served with a "good" HTTP status, - * eg, the page is not missing and can be served without a server error - * @param page - */ - public void assertGoodStatus(Page page) { - assertTrue(isGoodHttpStatus(page.getWebResponse().getStatusCode())); - } - - - public R assertBuildStatusSuccess(R r) throws Exception { - assertBuildStatus(Result.SUCCESS, r); - return r; - } - - public R assertBuildStatusSuccess(Future r) throws Exception { - assertNotNull("build was actually scheduled", r); - return assertBuildStatusSuccess(r.get()); - } - - public ,R extends AbstractBuild> R buildAndAssertSuccess(J job) throws Exception { - return assertBuildStatusSuccess(job.scheduleBuild2(0)); - } - - /** - * Avoids need for cumbersome {@code this.buildAndAssertSuccess(...)} type hints under JDK 7 javac (and supposedly also IntelliJ). - */ - public FreeStyleBuild buildAndAssertSuccess(FreeStyleProject job) throws Exception { - return assertBuildStatusSuccess(job.scheduleBuild2(0)); - } - public MavenModuleSetBuild buildAndAssertSuccess(MavenModuleSet job) throws Exception { - return assertBuildStatusSuccess(job.scheduleBuild2(0)); - } - public MavenBuild buildAndAssertSuccess(MavenModule job) throws Exception { - return assertBuildStatusSuccess(job.scheduleBuild2(0)); - } - - /** - * Asserts that the console output of the build contains the given substring. - */ - public void assertLogContains(String substring, Run run) throws Exception { - String log = getLog(run); - assertTrue("Console output of "+run+" didn't contain "+substring+":\n"+log,log.contains(substring)); - } - - /** - * Asserts that the console output of the build does not contain the given substring. - */ - public void assertLogNotContains(String substring, Run run) throws Exception { - String log = getLog(run); - assertFalse("Console output of "+run+" contains "+substring+":\n"+log,log.contains(substring)); - } - - /** - * Get entire log file (this method is deprecated in hudson.model.Run, - * but in tests it is OK to load entire log). - */ - protected static String getLog(Run run) throws IOException { - return Util.loadFile(run.getLogFile(), run.getCharset()); - } - - /** - * Asserts that the XPath matches. - */ - public void assertXPath(HtmlPage page, String xpath) { - assertNotNull("There should be an object that matches XPath:" + xpath, - page.getDocumentElement().selectSingleNode(xpath)); - } - - /** Asserts that the XPath matches the contents of a DomNode page. This - * variant of assertXPath(HtmlPage page, String xpath) allows us to - * examine XmlPages. - * @param page - * @param xpath - */ - public void assertXPath(DomNode page, String xpath) { - List< ? extends Object> nodes = page.getByXPath(xpath); - assertFalse("There should be an object that matches XPath:" + xpath, nodes.isEmpty()); - } - - public void assertXPathValue(DomNode page, String xpath, String expectedValue) { - Object node = page.getFirstByXPath(xpath); - assertNotNull("no node found", node); - assertTrue("the found object was not a Node " + xpath, node instanceof org.w3c.dom.Node); - - org.w3c.dom.Node n = (org.w3c.dom.Node) node; - String textString = n.getTextContent(); - assertEquals("xpath value should match for " + xpath, expectedValue, textString); - } - - public void assertXPathValueContains(DomNode page, String xpath, String needle) { - Object node = page.getFirstByXPath(xpath); - assertNotNull("no node found", node); - assertTrue("the found object was not a Node " + xpath, node instanceof org.w3c.dom.Node); - - org.w3c.dom.Node n = (org.w3c.dom.Node) node; - String textString = n.getTextContent(); - assertTrue("needle found in haystack", textString.contains(needle)); - } - - public void assertXPathResultsContainText(DomNode page, String xpath, String needle) { - List nodes = page.getByXPath(xpath); - assertFalse("no nodes matching xpath found", nodes.isEmpty()); - boolean found = false; - for (Object o : nodes) { - if (o instanceof org.w3c.dom.Node) { - org.w3c.dom.Node n = (org.w3c.dom.Node) o; - String textString = n.getTextContent(); - if ((textString != null) && textString.contains(needle)) { - found = true; - break; - } - } - } - assertTrue("needle found in haystack", found); - } - - /** - * Makes sure that all the images in the page loads successfully. - * (By default, HtmlUnit doesn't load images.) - */ - public void assertAllImageLoadSuccessfully(HtmlPage p) { - for (HtmlImage img : p.selectNodes("//IMG")) { - try { - img.getHeight(); - } catch (IOException e) { - throw new Error("Failed to load "+img.getSrcAttribute(),e); - } - } - } - - - public void assertStringContains(String message, String haystack, String needle) { - assertTrue(message + " (seeking '" + needle + "')",haystack.contains(needle)); - } - - public void assertStringContains(String haystack, String needle) { - assertTrue("Could not find '" + needle + "'.",haystack.contains(needle)); - } - - /** - * Asserts that help files exist for the specified properties of the given instance. - * - * @param type - * The describable class type that should have the associated help files. - * @param properties - * ','-separated list of properties whose help files should exist. - */ - public void assertHelpExists(final Class type, final String properties) throws Exception { - executeOnServer(new Callable() { - public Object call() throws Exception { - Descriptor d = jenkins.getDescriptor(type); - WebClient wc = createWebClient(); - for (String property : listProperties(properties)) { - String url = d.getHelpFile(property); - assertNotNull("Help file for the property "+property+" is missing on "+type, url); - wc.goTo(url); // make sure it successfully loads - } - return null; - } - }); - } - - /** - * Tokenizes "foo,bar,zot,-bar" and returns "foo,zot" (the token that starts with '-' is handled as - * a cancellation. - */ - private List listProperties(String properties) { - List props = new ArrayList(Arrays.asList(properties.split(","))); - for (String p : props.toArray(new String[props.size()])) { - if (p.startsWith("-")) { - props.remove(p); - props.remove(p.substring(1)); - } - } - return props; - } - - /** - * Submits the form. - * - * 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"))); - } - - /** - * Submits the form by clikcing the submit button of the given name. - * - * @param name - * This corresponds to the @name of <f:submit /> - */ - 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); - } - } - 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()]"); - } - - protected HtmlButton getButtonByCaption(HtmlForm f, String s) { - for (HtmlElement b : f.getHtmlElementsByTagName("button")) { - if(b.getTextContent().trim().equals(s)) - return (HtmlButton)b; - } - return null; - } - - /** - * Creates a {@link TaskListener} connected to stdout. - */ - public TaskListener createTaskListener() { - return new StreamTaskListener(new CloseProofOutputStream(System.out)); - } - - /** - * Asserts that two JavaBeans are equal as far as the given list of properties are concerned. - * - *

- * This method takes two objects that have properties (getXyz, isXyz, or just the public xyz field), - * and makes sure that the property values for each given property are equals (by using {@link #assertEquals(Object, Object)}) - * - *

- * Property values can be null on both objects, and that is OK, but passing in a property that doesn't - * exist will fail an assertion. - * - *

- * This method is very convenient for comparing a large number of properties on two objects, - * for example to verify that the configuration is identical after a config screen roundtrip. - * - * @param lhs - * One of the two objects to be compared. - * @param rhs - * The other object to be compared - * @param properties - * ','-separated list of property names that are compared. - * @since 1.297 - */ - public void assertEqualBeans(Object lhs, Object rhs, String properties) throws Exception { - assertNotNull("lhs is null",lhs); - assertNotNull("rhs is null",rhs); - for (String p : properties.split(",")) { - PropertyDescriptor pd = PropertyUtils.getPropertyDescriptor(lhs, p); - Object lp,rp; - if(pd==null) { - // field? - try { - Field f = lhs.getClass().getField(p); - lp = f.get(lhs); - rp = f.get(rhs); - } catch (NoSuchFieldException e) { - assertNotNull("No such property "+p+" on "+lhs.getClass(),pd); - return; - } - } else { - lp = PropertyUtils.getProperty(lhs, p); - rp = PropertyUtils.getProperty(rhs, p); - } - - if (lp!=null && rp!=null && lp.getClass().isArray() && rp.getClass().isArray()) { - // deep array equality comparison - int m = Array.getLength(lp); - int n = Array.getLength(rp); - assertEquals("Array length is different for property "+p, m,n); - for (int i=0; i primitiveProperties = new ArrayList(); - - String[] names = ClassDescriptor.loadParameterNames(lc); - Class[] types = lc.getParameterTypes(); - assertEquals(names.length,types.length); - for (int i=0; i lhs, List rhs) throws Exception { - assertEquals(lhs.size(), rhs.size()); - for (int i=0; i findDataBoundConstructor(Class c) { - for (Constructor m : c.getConstructors()) { - if (m.getAnnotation(DataBoundConstructor.class)!=null) - return m; - } - return null; - } - - /** - * Gets the descriptor instance of the current Hudson by its type. - */ - protected > T get(Class d) { - return jenkins.getDescriptorByType(d); - } - - - /** - * Returns true if Hudson is building something or going to build something. - */ - protected boolean isSomethingHappening() { - if (!jenkins.getQueue().isEmpty()) - return true; - for (Computer n : jenkins.getComputers()) - if (!n.isIdle()) - return true; - return false; - } - - /** - * Waits until Hudson finishes building everything, including those in the queue. - *

- * This method uses a default time out to prevent infinite hang in the automated test execution environment. - */ - protected void waitUntilNoActivity() throws Exception { - waitUntilNoActivityUpTo(60*1000); - } - - /** - * Waits until Jenkins finishes building everything, including those builds in the queue, or fail the test - * if the specified timeout milliseconds is exceeded. - */ - protected void waitUntilNoActivityUpTo(int timeout) throws Exception { - long startTime = System.currentTimeMillis(); - int streak = 0; - - while (true) { - Thread.sleep(100); - if (isSomethingHappening()) - streak=0; - else - streak++; - - if (streak>2) // the system is quiet for a while - return; - - if (System.currentTimeMillis()-startTime > timeout) { - List building = new ArrayList(); - for (Computer c : jenkins.getComputers()) { - for (Executor e : c.getExecutors()) { - if (e.isBusy()) - building.add(e.getCurrentExecutable()); - } - } - throw new AssertionError(String.format("Jenkins is still doing something after %dms: queue=%s building=%s", - timeout, Arrays.asList(jenkins.getQueue().getItems()), building)); - } - } - } - - - -// -// recipe methods. Control the test environments. -// - - /** - * Called during the {@link #setUp()} to give a test case an opportunity to - * control the test environment in which Hudson is run. - * - *

- * One could override this method and call a series of {@code withXXX} methods, - * or you can use the annotations with {@link Recipe} meta-annotation. - */ - protected void recipe() throws Exception { - recipeLoadCurrentPlugin(); - // look for recipe meta-annotation - try { - Method runMethod= getClass().getMethod(getName()); - for( final Annotation a : runMethod.getAnnotations() ) { - Recipe r = a.annotationType().getAnnotation(Recipe.class); - if(r==null) continue; - final Runner runner = r.value().newInstance(); - recipes.add(runner); - tearDowns.add(new LenientRunnable() { - public void run() throws Exception { - runner.tearDown(HudsonTestCase.this,a); - } - }); - runner.setup(this,a); - } - } catch (NoSuchMethodException e) { - // not a plain JUnit test. - } - } - - /** - * If this test harness is launched for a Jenkins plugin, locate the target/test-classes/the.jpl - * and add a recipe to install that to the new Jenkins. - * - *

- * This file is created by maven-hpi-plugin at the testCompile phase when the current - * packaging is hpi. - */ - protected void recipeLoadCurrentPlugin() throws Exception { - final Enumeration jpls = getClass().getClassLoader().getResources("the.jpl"); - final Enumeration hpls = getClass().getClassLoader().getResources("the.hpl"); - - final List all = Collections.list(jpls); - all.addAll(Collections.list(hpls)); - - if(all.isEmpty()) return; // nope - - recipes.add(new Runner() { - @Override - public void decorateHome(HudsonTestCase testCase, File home) throws Exception { - - for (URL hpl : all) { - - // make the plugin itself available - Manifest m = new Manifest(hpl.openStream()); - String shortName = m.getMainAttributes().getValue("Short-Name"); - if(shortName==null) - throw new Error(hpl+" doesn't have the Short-Name attribute"); - FileUtils.copyURLToFile(hpl,new File(home,"plugins/"+shortName+".jpl")); - - // make dependency plugins available - // TODO: probably better to read POM, but where to read from? - // TODO: this doesn't handle transitive dependencies - - // Tom: plugins are now searched on the classpath first. They should be available on - // the compile or test classpath. As a backup, we do a best-effort lookup in the Maven repository - // For transitive dependencies, we could evaluate Plugin-Dependencies transitively. - - String dependencies = m.getMainAttributes().getValue("Plugin-Dependencies"); - if(dependencies!=null) { - MavenEmbedder embedder = MavenUtil.createEmbedder(new StreamTaskListener(System.out,Charset.defaultCharset()),(File)null,null); - for( String dep : dependencies.split(",")) { - String suffix = ";resolution:=optional"; - boolean optional = dep.endsWith(suffix); - if (optional) { - dep = dep.substring(0, dep.length() - suffix.length()); - } - String[] tokens = dep.split(":"); - String artifactId = tokens[0]; - String version = tokens[1]; - File dependencyJar=resolveDependencyJar(embedder,artifactId,version); - if (dependencyJar == null) { - if (optional) { - System.err.println("cannot resolve optional dependency " + dep + " of " + shortName + "; skipping"); - continue; - } - throw new IOException("Could not resolve " + dep); - } - - File dst = new File(home, "plugins/" + artifactId + ".jpi"); - if(!dst.exists() || dst.lastModified()!=dependencyJar.lastModified()) { - FileUtils.copyFile(dependencyJar, dst); - } - } - } - } - } - - private File resolveDependencyJar(MavenEmbedder embedder, String artifactId, String version) throws Exception { - // try to locate it from manifest - Enumeration manifests = getClass().getClassLoader().getResources("META-INF/MANIFEST.MF"); - while (manifests.hasMoreElements()) { - URL manifest = manifests.nextElement(); - InputStream is = manifest.openStream(); - Manifest m = new Manifest(is); - is.close(); - - if (artifactId.equals(m.getMainAttributes().getValue("Short-Name"))) - return Which.jarFile(manifest); - } - - // need to search multiple group IDs - // TODO: extend manifest to include groupID:artifactID:version - Exception resolutionError=null; - for (String groupId : new String[]{"org.jvnet.hudson.plugins","org.jvnet.hudson.main"}) { - - // first try to find it on the classpath. - // this takes advantage of Maven POM located in POM - URL dependencyPomResource = getClass().getResource("/META-INF/maven/"+groupId+"/"+artifactId+"/pom.xml"); - if (dependencyPomResource != null) { - // found it - return Which.jarFile(dependencyPomResource); - } else { - - try { - // currently the most of the plugins are still hpi - return resolvePluginFile(embedder, artifactId, version, groupId, "hpi"); - } catch(AbstractArtifactResolutionException x){ - try { - // but also try with the new jpi - return resolvePluginFile(embedder, artifactId, version, groupId, "jpi"); - } catch(AbstractArtifactResolutionException x2){ - // could be a wrong groupId - resolutionError = x; - } - } - - } - } - - throw new Exception("Failed to resolve plugin (tryied with types: 'jpi' and 'hpi'): "+artifactId+" version "+version, resolutionError); - } - - private File resolvePluginFile(MavenEmbedder embedder, String artifactId, String version, String groupId, String type) - throws MavenEmbedderException, ComponentLookupException, AbstractArtifactResolutionException { - final Artifact jpi = embedder.createArtifact(groupId, artifactId, version, "compile"/*doesn't matter*/, type); - embedder.resolve(jpi, Arrays.asList(embedder.createRepository("http://maven.glassfish.org/content/groups/public/","repo")),embedder.getLocalRepository()); - return jpi.getFile(); - - } - }); - } - - public HudsonTestCase withNewHome() { - return with(HudsonHomeLoader.NEW); - } - - public HudsonTestCase withExistingHome(File source) throws Exception { - return with(new CopyExisting(source)); - } - - /** - * Declares that this test case expects to start with one of the preset data sets. - * See {@code test/src/main/preset-data/} - * for available datasets and what they mean. - */ - public HudsonTestCase withPresetData(String name) { - name = "/" + name + ".zip"; - URL res = getClass().getResource(name); - if(res==null) throw new IllegalArgumentException("No such data set found: "+name); - - return with(new CopyExisting(res)); - } - - public HudsonTestCase with(HudsonHomeLoader homeLoader) { - this.homeLoader = homeLoader; - return this; - } - - - /** - * Executes the given closure on the server, by the servlet request handling thread, - * in the context of an HTTP request. - * - *

- * In {@link HudsonTestCase}, a thread that's executing the test code is different from the thread - * that carries out HTTP requests made through {@link WebClient}. But sometimes you want to - * make assertions and other calls with side-effect from within the request handling thread. - * - *

- * This method allows you to do just that. It is useful for testing some methods that - * require {@link StaplerRequest} and {@link StaplerResponse}, or getting the credential - * of the current user (via {@link jenkins.model.Jenkins#getAuthentication()}, and so on. - * - * @param c - * The closure to be executed on the server. - * @return - * The return value from the closure. - * @throws Exception - * If a closure throws any exception, that exception will be carried forward. - */ - public V executeOnServer(Callable c) throws Exception { - return createWebClient().executeOnServer(c); - } - - /** - * Sometimes a part of a test case may ends up creeping into the serialization tree of {@link Saveable#save()}, - * so detect that and flag that as an error. - */ - private Object writeReplace() { - throw new AssertionError("HudsonTestCase "+getName()+" is not supposed to be serialized"); - } - - /** - * This is to assist Groovy test clients who are incapable of instantiating the inner classes properly. - */ - public WebClient createWebClient() { - return new WebClient(); - } - - /** - * Extends {@link com.gargoylesoftware.htmlunit.WebClient} and provide convenience methods - * for accessing Hudson. - */ - public class WebClient extends com.gargoylesoftware.htmlunit.WebClient { - private static final long serialVersionUID = 5808915989048338267L; - - 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); - - 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) { - return false; - } - }); - - setCssErrorHandler(new ErrorHandler() { - final ErrorHandler defaultHandler = new DefaultCssErrorHandler(); - - public void warning(CSSParseException exception) throws CSSException { - if (!ignore(exception)) - defaultHandler.warning(exception); - } - - public void error(CSSParseException exception) throws CSSException { - if (!ignore(exception)) - defaultHandler.error(exception); - } - - public void fatalError(CSSParseException exception) throws CSSException { - if (!ignore(exception)) - defaultHandler.fatalError(exception); - } - - private boolean ignore(CSSParseException e) { - return e.getURI().contains("/yui/"); - } - }); - - // if no other debugger is installed, install jsDebugger, - // so as not to interfere with the 'Dim' class. - getJavaScriptEngine().getContextFactory().addListener(new Listener() { - public void contextCreated(Context cx) { - if (cx.getDebugger() == null) - cx.setDebugger(jsDebugger, null); - } - - public void contextReleased(Context cx) { - } - }); - - setAlertHandler(new AlertHandler() { - public void handleAlert(Page page, String message) { - throw new AssertionError("Alert dialog poped up: "+message); - } - }); - - // avoid a hang by setting a time out. It should be long enough to prevent - // false-positive timeout on slow systems - setTimeout(60*1000); - } - - /** - * Logs in to Jenkins. - */ - public WebClient login(String username, String password) throws Exception { - HtmlPage page = goTo("/login"); - - HtmlForm form = page.getFormByName("login"); - form.getInputByName("j_username").setValueAttribute(username); - form.getInputByName("j_password").setValueAttribute(password); - form.submit(null); - return this; - } - - /** - * Logs in to Hudson, by using the user name as the password. - * - *

- * See {@link HudsonTestCase#configureUserRealm()} for how the container is set up with the user names - * and passwords. All the test accounts have the same user name and password. - */ - public WebClient login(String username) throws Exception { - login(username,username); - return this; - } - - /** - * Executes the given closure on the server, by the servlet request handling thread, - * in the context of an HTTP request. - * - *

- * In {@link HudsonTestCase}, a thread that's executing the test code is different from the thread - * that carries out HTTP requests made through {@link WebClient}. But sometimes you want to - * make assertions and other calls with side-effect from within the request handling thread. - * - *

- * This method allows you to do just that. It is useful for testing some methods that - * require {@link StaplerRequest} and {@link StaplerResponse}, or getting the credential - * of the current user (via {@link jenkins.model.Jenkins#getAuthentication()}, and so on. - * - * @param c - * The closure to be executed on the server. - * @return - * The return value from the closure. - * @throws Exception - * If a closure throws any exception, that exception will be carried forward. - */ - public V executeOnServer(final Callable c) throws Exception { - final Exception[] t = new Exception[1]; - final List r = new ArrayList(1); // size 1 list - - ClosureExecuterAction cea = jenkins.getExtensionList(RootAction.class).get(ClosureExecuterAction.class); - UUID id = UUID.randomUUID(); - cea.add(id,new Runnable() { - public void run() { - try { - StaplerResponse rsp = Stapler.getCurrentResponse(); - rsp.setStatus(200); - rsp.setContentType("text/html"); - r.add(c.call()); - } catch (Exception e) { - t[0] = e; - } - } - }); - goTo("closures/?uuid="+id); - - if (t[0]!=null) - throw t[0]; - return r.get(0); - } - - public HtmlPage search(String q) throws IOException, SAXException { - HtmlPage top = goTo(""); - HtmlForm search = top.getFormByName("search"); - search.getInputByName("q").setValueAttribute(q); - return (HtmlPage)search.submit(null); - } - - /** - * Short for {@code getPage(r,"")}, to access the top page of a build. - */ - public HtmlPage getPage(Run r) throws IOException, SAXException { - return getPage(r,""); - } - - /** - * Accesses a page inside {@link Run}. - * - * @param relative - * Relative URL within the build URL, like "changes". Doesn't start with '/'. Can be empty. - */ - public HtmlPage getPage(Run r, String relative) throws IOException, SAXException { - return goTo(r.getUrl()+relative); - } - - public HtmlPage getPage(Item item) throws IOException, SAXException { - return getPage(item,""); - } - - public HtmlPage getPage(Item item, String relative) throws IOException, SAXException { - return goTo(item.getUrl()+relative); - } - - public HtmlPage getPage(Node item) throws IOException, SAXException { - return getPage(item,""); - } - - public HtmlPage getPage(Node item, String relative) throws IOException, SAXException { - return goTo(item.toComputer().getUrl()+relative); - } - - public HtmlPage getPage(View view) throws IOException, SAXException { - return goTo(view.getUrl()); - } - - public HtmlPage getPage(View view, String relative) throws IOException, SAXException { - return goTo(view.getUrl()+relative); - } - - /** - * @deprecated - * This method expects a full URL. This method is marked as deprecated to warn you - * that you probably should be using {@link #goTo(String)} method, which accepts - * a relative path within the Hudson being tested. (IOW, if you really need to hit - * a website on the internet, there's nothing wrong with using this method.) - */ - @SuppressWarnings("unchecked") - @Override - public Page getPage(String url) throws IOException, FailingHttpStatusCodeException { - return super.getPage(url); - } - - /** - * Requests a page within Hudson. - * - * @param relative - * Relative path within Hudson. Starts without '/'. - * For example, "job/test/" to go to a job top page. - */ - public HtmlPage goTo(String relative) throws IOException, SAXException { - Page p = goTo(relative, "text/html"); - if (p instanceof HtmlPage) { - return (HtmlPage) p; - } else { - throw new AssertionError("Expected text/html but instead the content type was "+p.getWebResponse().getContentType()); - } - } - - public Page goTo(String relative, String expectedContentType) throws IOException, SAXException { - while (relative.startsWith("/")) relative = relative.substring(1); - Page p; - try { - p = super.getPage(getContextPath() + relative); - } catch (IOException x) { - if (x.getCause() != null) { - x.getCause().printStackTrace(); - } - throw x; - } - assertEquals(expectedContentType,p.getWebResponse().getContentType()); - return p; - } - - /** Loads a page as XML. Useful for testing Hudson's xml api, in concert with - * assertXPath(DomNode page, String xpath) - * @param path the path part of the url to visit - * @return the XmlPage found at that url - * @throws IOException - * @throws SAXException - */ - public XmlPage goToXml(String path) throws IOException, SAXException { - Page page = goTo(path, "application/xml"); - if (page instanceof XmlPage) - return (XmlPage) page; - else - return null; - } - - /** - * Verify that the server rejects an attempt to load the given page. - * @param url a URL path (relative to Jenkins root) - * @param statusCode the expected failure code (such as {@link HttpURLConnection#HTTP_FORBIDDEN}) - * @since 1.502 - */ - public void assertFails(String url, int statusCode) throws Exception { - try { - fail(url + " should have been rejected but produced: " + super.getPage(getContextPath() + url).getWebResponse().getContentAsString()); - } catch (FailingHttpStatusCodeException x) { - assertEquals(statusCode, x.getStatusCode()); - } - } - - /** - * Returns the URL of the webapp top page. - * URL ends with '/'. - */ - public String getContextPath() throws IOException { - return getURL().toExternalForm(); - } - - /** - * 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 )); - - req.setRequestParameters(Arrays.asList( crumb )); - return req; - } - - /** - * Creates a URL with crumb parameters relative to {{@link #getContextPath()} - */ - public URL createCrumbedUrl(String relativePath) throws IOException { - CrumbIssuer issuer = jenkins.getCrumbIssuer(); - String crumbName = issuer.getDescriptor().getCrumbRequestField(); - String crumb = issuer.getCrumb(null); - - return new URL(getContextPath()+relativePath+"?"+crumbName+"="+crumb); - } - - /** - * Makes an HTTP request, process it with the given request handler, and returns the response. - */ - public HtmlPage eval(final Runnable requestHandler) throws IOException, SAXException { - ClosureExecuterAction cea = jenkins.getExtensionList(RootAction.class).get(ClosureExecuterAction.class); - UUID id = UUID.randomUUID(); - cea.add(id,requestHandler); - return goTo("closures/?uuid="+id); - } - - /** - * Starts an interactive JavaScript debugger, and break at the next JavaScript execution. - * - *

- * This is useful during debugging a test so that you can step execute and inspect state of JavaScript. - * This will launch a Swing GUI, and the method returns immediately. - * - *

- * Note that installing a debugger appears to make an execution of JavaScript substantially slower. - * - *

- * TODO: because each script block evaluation in HtmlUnit is done in a separate Rhino context, - * if you step over from one script block, the debugger fails to kick in on the beginning of the next script block. - * This makes it difficult to set a break point on arbitrary script block in the HTML page. We need to fix this - * by tweaking {@link Dim.StackFrame#onLineChange(Context, int)}. - */ - public Dim interactiveJavaScriptDebugger() { - Global global = new Global(); - HtmlUnitContextFactory cf = getJavaScriptEngine().getContextFactory(); - global.init(cf); - - Dim dim = org.mozilla.javascript.tools.debugger.Main.mainEmbedded(cf, global, "Rhino debugger: " + getName()); - - // break on exceptions. this catch most of the errors - dim.setBreakOnExceptions(true); - - return dim; - } - } - - // needs to keep reference, or it gets GC-ed. - private static final Logger XML_HTTP_REQUEST_LOGGER = Logger.getLogger(XMLHttpRequest.class.getName()); - - static { - // screen scraping relies on locale being fixed. - Locale.setDefault(Locale.ENGLISH); - - {// enable debug assistance, since tests are often run from IDE - Dispatcher.TRACE = true; - MetaClass.NO_CACHE=true; - // load resources from the source dir. - File dir = new File("src/main/resources"); - if(dir.exists() && MetaClassLoader.debugLoader==null) - try { - MetaClassLoader.debugLoader = new MetaClassLoader( - new URLClassLoader(new URL[]{dir.toURI().toURL()})); - } catch (MalformedURLException e) { - throw new AssertionError(e); - } - } - - // suppress INFO output from Spring, which is verbose - Logger.getLogger("org.springframework").setLevel(Level.WARNING); - - // hudson-behavior.js relies on this to decide whether it's running unit tests. - Main.isUnitTest = true; - - // prototype.js calls this method all the time, so ignore this warning. - XML_HTTP_REQUEST_LOGGER.setFilter(new Filter() { - public boolean isLoggable(LogRecord record) { - return !record.getMessage().contains("XMLHttpRequest.getResponseHeader() was called before the response was available."); - } - }); - - // remove the upper bound of the POST data size in Jetty. - System.setProperty("org.mortbay.jetty.Request.maxFormContentSize","-1"); - } - - private static final Logger LOGGER = Logger.getLogger(HudsonTestCase.class.getName()); - - protected static final List> NO_PROPERTIES = Collections.>emptyList(); - - /** - * Specify this to a TCP/IP port number to have slaves started with the debugger. - */ - public static int SLAVE_DEBUG_PORT = Integer.getInteger(HudsonTestCase.class.getName()+".slaveDebugPort",-1); - - public static final MimeTypes MIME_TYPES = new MimeTypes(); - static { - MIME_TYPES.addMimeMapping("js","application/javascript"); - Functions.DEBUG_YUI = true; - - // during the unit test, predictably releasing classloader is important to avoid - // file descriptor leak. - ClassicPluginStrategy.useAntClassLoader = true; - - // DNS multicast support takes up a lot of time during tests, so just disable it altogether - // this also prevents tests from falsely advertising Hudson - DNSMultiCast.disabled = true; - - if (!Functions.isWindows()) { - try { - PosixAPI.jnr().unsetenv("MAVEN_OPTS"); - PosixAPI.jnr().unsetenv("MAVEN_DEBUG_OPTS"); - } catch (Exception e) { - LOGGER.log(Level.WARNING,"Failed to cancel out MAVEN_OPTS",e); - } - } - } - - public static class TestBuildWrapper extends BuildWrapper { - public Result buildResultInTearDown; - - @Override - public Environment setUp(AbstractBuild build, Launcher launcher, BuildListener listener) throws IOException, InterruptedException { - return new BuildWrapper.Environment() { - @Override - public boolean tearDown(AbstractBuild build, BuildListener listener) throws IOException, InterruptedException { - buildResultInTearDown = build.getResult(); - return true; - } - }; - } - - @Extension - public static class TestBuildWrapperDescriptor extends BuildWrapperDescriptor { - @Override - public boolean isApplicable(AbstractProject project) { - return true; - } - - @Override - 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/JavaNetReverseProxy.java b/test/src/main/java/org/jvnet/hudson/test/JavaNetReverseProxy.java deleted file mode 100644 index ccc3df518cdf17cff8d3b02fccdd669fef2850dc..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/JavaNetReverseProxy.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.jvnet.hudson.test; - -import hudson.Util; -import hudson.util.IOUtils; -import org.apache.commons.io.FileUtils; -import org.mortbay.jetty.Server; -import org.mortbay.jetty.bio.SocketConnector; -import org.mortbay.jetty.handler.ContextHandlerCollection; -import org.mortbay.jetty.servlet.Context; -import org.mortbay.jetty.servlet.ServletHolder; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.File; -import java.io.IOException; -import java.net.URL; - -/** - * Acts as a reverse proxy, so that during a test we can avoid hitting updates.jenkins-ci.org. - * - *

- * The contents are cached locally. - * - * @author Kohsuke Kawaguchi - */ -public class JavaNetReverseProxy extends HttpServlet { - private final Server server; - public final int localPort; - - private final File cacheFolder; - - public JavaNetReverseProxy(File cacheFolder) throws Exception { - this.cacheFolder = cacheFolder; - cacheFolder.mkdirs(); - - server = new Server(); - - ContextHandlerCollection contexts = new ContextHandlerCollection(); - server.setHandler(contexts); - - Context root = new Context(contexts, "/", Context.SESSIONS); - root.addServlet(new ServletHolder(this), "/"); - - SocketConnector connector = new SocketConnector(); - server.addConnector(connector); - server.start(); - - localPort = connector.getLocalPort(); - } - - public void stop() throws Exception { - server.stop(); - } - -// class Response { -// final URL url; -// final String contentType; -// final ByteArrayOutputStream data = new ByteArrayOutputStream(); -// -// Response(URL url) throws IOException { -// this.url = url; -// URLConnection con = url.openConnection(); -// contentType = con.getContentType(); -// IOUtils.copy(con.getInputStream(),data); -// } -// -// void reproduceTo(HttpServletResponse rsp) throws IOException { -// rsp.setContentType(contentType); -// data.writeTo(rsp.getOutputStream()); -// } -// } - - @Override - protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - String path = req.getServletPath(); - String d = Util.getDigestOf(path); - - File cache = new File(cacheFolder, d); - if(!cache.exists()) { - URL url = new URL("http://updates.jenkins-ci.org/" + path); - FileUtils.copyURLToFile(url,cache); - } - - resp.setContentType(getMimeType(path)); - IOUtils.copy(cache,resp.getOutputStream()); - } - - private String getMimeType(String path) { - int idx = path.indexOf('?'); - if(idx>=0) - path = path.substring(0,idx); - if(path.endsWith(".json")) return "text/javascript"; - return getServletContext().getMimeType(path); - } - - private static volatile JavaNetReverseProxy INSTANCE; - - /** - * Gets the default instance. - */ - public static synchronized JavaNetReverseProxy getInstance() throws Exception { - if(INSTANCE==null) - // TODO: think of a better location --- ideally inside the target/ dir so that clean would wipe them out - INSTANCE = new JavaNetReverseProxy(new File(new File(System.getProperty("java.io.tmpdir")),"jenkins-ci.org-cache2")); - return INSTANCE; - } -} diff --git a/test/src/main/java/org/jvnet/hudson/test/JellyTestSuiteBuilder.java b/test/src/main/java/org/jvnet/hudson/test/JellyTestSuiteBuilder.java deleted file mode 100644 index 3607273be4343ea147f4599200a3daf40cf1757f..0000000000000000000000000000000000000000 --- a/test/src/main/java/org/jvnet/hudson/test/JellyTestSuiteBuilder.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 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; - -import junit.framework.TestCase; -import junit.framework.TestResult; -import junit.framework.TestSuite; -import org.apache.commons.io.FileUtils; -import org.dom4j.Document; -import org.dom4j.ProcessingInstruction; -import org.dom4j.io.SAXReader; -import org.jvnet.hudson.test.junit.GroupedTest; -import org.kohsuke.stapler.MetaClassLoader; -import org.kohsuke.stapler.jelly.JellyClassLoaderTearOff; - -import java.io.File; -import java.net.URL; -import java.util.Collection; -import java.util.Enumeration; -import java.util.concurrent.Callable; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -/** - * Builds up a {@link TestSuite} for performing static syntax checks on Jelly scripts. - * - * @author Kohsuke Kawaguchi - */ -public class JellyTestSuiteBuilder { - /** - * Given a jar file or a class file directory, recursively search all the Jelly files and build a {@link TestSuite} - * that performs static syntax checks. - */ - public static TestSuite build(File res, boolean requirePI) throws Exception { - TestSuite ts = new JellyTestSuite(); - - final JellyClassLoaderTearOff jct = new MetaClassLoader(JellyTestSuiteBuilder.class.getClassLoader()).loadTearOff(JellyClassLoaderTearOff.class); - - if (res.isDirectory()) { - for (final File jelly : (Collection )FileUtils.listFiles(res,new String[]{"jelly"},true)) - ts.addTest(new JellyCheck(jelly.toURI().toURL(), jelly.getAbsolutePath().substring((res.getAbsolutePath() + File.separator).length()), jct, requirePI)); - } - if (res.getName().endsWith(".jar")) { - String jarUrl = res.toURI().toURL().toExternalForm(); - JarFile jf = new JarFile(res); - Enumeration e = jf.entries(); - while (e.hasMoreElements()) { - JarEntry ent = e.nextElement(); - if (ent.getName().endsWith(".jelly")) - ts.addTest(new JellyCheck(new URL("jar:"+jarUrl+"!/"+ent.getName()), ent.getName(), jct, requirePI)); - } - jf.close(); - } - return ts; - } - - private static class JellyCheck extends TestCase { - private final URL jelly; - private final JellyClassLoaderTearOff jct; - private final boolean requirePI; - - JellyCheck(URL jelly, String name, JellyClassLoaderTearOff jct, boolean requirePI) { - super(name); - this.jelly = jelly; - this.jct = jct; - this.requirePI = requirePI; - } - - @Override - protected void runTest() throws Exception { - jct.createContext().compileScript(jelly); - Document dom = new SAXReader().read(jelly); - checkLabelFor(dom); - if (requirePI) { - ProcessingInstruction pi = dom.processingInstruction("jelly"); - if (pi==null || !pi.getText().contains("escape-by-default")) - throw new AssertionError(" is missing in "+jelly); - - } - // TODO: what else can we check statically? use of taglibs? - } - - /** - * Makes sure that <label for=...> is not used inside config.jelly nor global.jelly - */ - private void checkLabelFor(Document dom) { - if (isConfigJelly() || isGlobalJelly()) { - if (!dom.selectNodes("//label[@for]").isEmpty()) - throw new AssertionError("