diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7257307587..df64fc700f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -21,11 +21,15 @@ If the issue is not fully described in the ticket, add more information here (ju +### Proposed upgrade guidelines + +N/A + ### Submitter checklist - [ ] JIRA issue is well described -- [ ] Changelog entry appropriate for the audience affected by the change (users or developer, depending on the change). [Examples](https://github.com/jenkins-infra/jenkins.io/blob/master/content/_data/changelogs/weekly.yml) - * Use the `Internal: ` prefix if the change has no user-visible impact (API, test frameworks, etc.) +- [ ] Changelog entries and upgrade guidelines are appropriate for the audience affected by the change (users or developer, depending on the change). [Examples](https://github.com/jenkins-infra/jenkins.io/blob/master/content/_data/changelogs/weekly.yml) + * Fill-in the `Proposed changelog entries` section only if there are breaking changes or other changes which may require extra steps from users during the upgrade - [ ] Appropriate autotests or explanation to why this change has no tests - [ ] For dependency updates: links to external changelogs and, if possible, full diffs @@ -38,3 +42,15 @@ The changelogs will be integrated by the core maintainers after the merge. See + +### Maintainer checklist + +Before the changes are marked as `ready-for-merge`: + +- [ ] There are at least 2 approvals for the pull request and no outstanding requests for change +- [ ] Conversations in the pull request are over OR it is explicit that a reviewer does not block the change +- [ ] Changelog entries in the PR title and/or `Proposed changelog entries` are correct +- [ ] Proper changelog labels are set so that the changelog can be generated automatically +- [ ] If the change needs additional upgrade steps from users, `upgrade-guide-needed` label is set and there is a `Proposed upgrade guidelines` section in the PR title. ([example](https://github.com/jenkinsci/jenkins/pull/4387)) +- [ ] If it would make sense to backport the change to LTS, a JIRA issue should exist and be labeled as `lts-candidate` + diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 84656fc8eb..17abd66723 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -1,29 +1,18 @@ # Configuration for Release Drafter: https://github.com/toolmantim/release-drafter -name-template: $NEXT_PATCH_VERSION -# Uses a more common 2-digit versioning in Jenkins weekly releases. +_extends: .github +# We use the 2-digit versioning in Jenkins weekly releases. version-template: $MAJOR.$MINOR +name-template: $NEXT_MINOR_VERSION tag-template: jenkins-$NEXT_MINOR_VERSION -exclude-labels: - - reverted - - no-changelog - - skip-changelog - - invalid -change-template: |- - - type: todo - message: |- - $TITLE - pull: $NUMBER - authors: - - $AUTHOR - template: | **Disclaimer**: This is an automatically generated changelog draft for Jenkins weekly releases. - See https://jenkins.io/changelog/ for the official changelogs. + See https://jenkins.io/changelog/ for the official changelogs. + For `changelog.yaml` drafts see GitHub action artifacts attached to release commits. - ```yaml $CHANGES - ``` + + All contributors: $CONTRIBUTORS # Categories will be commented out, because we use YAML # Now we use categories only for sorting @@ -44,17 +33,3 @@ categories: label: developer - title: Internal changes label: internal - -replacers: - - search: '/\[*JENKINS-(\d+)\]*\s*-*\s*/g' - replace: |- - issue: $1 - message: |- - - - search: |- - message: |- - issue: - replace: "issue:" - - - search: "##" - replace: "#" diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml new file mode 100644 index 0000000000..1c16d431d0 --- /dev/null +++ b/.github/workflows/changelog.yml @@ -0,0 +1,43 @@ +# Automates creation of changelog drafts using Release Drafter +# More Info: https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc +name: Changelog Drafter + +on: + push: + # branches to consider in the event; optional, defaults to all + branches: + - master + +jobs: + update_draft_release: + runs-on: ubuntu-latest + steps: + # Drafts your next Release notes as Pull Requests are merged into "master" + - name: Generate GitHub Release Draft + id: release-drafter + uses: release-drafter/release-drafter@v5.6.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Generates a YAML changelog file using https://github.com/jenkinsci/jenkins-core-changelog-generator + - name: Generate YAML changelog draft + id: jenkins-core-changelog-generator + uses: jenkinsci/jenkins-core-changelog-generator@master + env: + GITHUB_AUTH: github-actions:${{ secrets.GITHUB_TOKEN }} + - name: Upload Changelog YAML + uses: actions/upload-artifact@v1 + with: + name: changelog.yaml + path: changelog.yaml +#TODO(oleg-nenashev): It will not work well with Release Drafter which does not recreated releases. Asset does not get overwritten, and there is no ready-to-go API for overriding assets + # Upload YAML to the release draft assets +# - name: Upload changelog.yaml to the Release Draft +# id: upload-changelog-yaml +# uses: actions/upload-release-asset@v1.0.1 +# env: +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# with: +# upload_url: ${{ steps.release-drafter.outputs.upload_url }} +# asset_path: ./changelog.yaml +# asset_name: changelog.yaml +# asset_content_type: text/yaml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d0bd4d9eea..1c6cd2c431 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,7 +31,9 @@ There is a description of the [building and debugging process]. If you want simply to have the `jenkins.war` file as fast as possible without tests, run: - mvn clean package -pl war -am -DskipTests -Dspotbugs.skip +```sh +mvn -am -pl war,bom -DskipTests -Dspotbugs.skip clean install +``` The WAR file will be created in `war/target/jenkins.war`. After that you can start Jenkins using Java CLI ([guide]). @@ -39,16 +41,13 @@ If you want to debug this WAR file without using Maven plugins, You can just start the executable with [Remote Debug Flags] and then attach IDE Debugger to it. -To compile and launch a development instance, run: +To launch a development instance, after the above command run: - mvn hudson-dev:run +```sh +mvn -pl war jetty:run +``` - +(Beware that `maven-plugin` builds will not work in this mode due to class loading conflicts.) ## Testing changes diff --git a/Jenkinsfile b/Jenkinsfile index 8f9e81bdd1..fd76d7f129 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -43,7 +43,7 @@ for(j = 0; j < jdks.size(); j++) { "MAVEN_OPTS=-Xmx1536m -Xms512m"], buildType, jdk) { // Actually run Maven! // -Dmaven.repo.local=… tells Maven to create a subdir in the temporary directory for the local Maven repository - def mvnCmd = "mvn -Pdebug -U -Dset.changelist help:evaluate -Dexpression=changelist -Doutput=$changelistF clean install ${runTests ? '-Dmaven.test.failure.ignore' : '-DskipTests'} -V -B -Dmaven.repo.local=$m2repo -s settings-azure.xml -e" + def mvnCmd = "mvn -Pdebug -U -Dset.changelist help:evaluate -Dexpression=changelist -Doutput=$changelistF clean install ${runTests ? '-Dmaven.test.failure.ignore' : '-DskipTests'} -V -B -ntp -Dmaven.repo.local=$m2repo -s settings-azure.xml -e" if(isUnix()) { sh mvnCmd @@ -77,7 +77,6 @@ for(j = 0; j < jdks.size(); j++) { // TODO: Restore ATH once https://groups.google.com/forum/#!topic/jenkinsci-dev/v9d-XosOp2s is resolved // TODO: ATH flow now supports Java 8 only, it needs to be reworked (INFRA-1690) -/* builds.ath = { node("docker&&highmem") { // Just to be safe @@ -88,7 +87,7 @@ builds.ath = { checkout scm withMavenEnv(["JAVA_OPTS=-Xmx1536m -Xms512m", "MAVEN_OPTS=-Xmx1536m -Xms512m"], 8) { - sh "mvn --batch-mode --show-version -DskipTests -am -pl war package -Dmaven.repo.local=${pwd tmp: true}/m2repo -s settings-azure.xml" + sh "mvn --batch-mode --show-version -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -DskipTests -am -pl war package -Dmaven.repo.local=${pwd tmp: true}/m2repo -s settings-azure.xml" } dir("war/target") { fileUri = "file://" + pwd() + "/jenkins.war" @@ -99,7 +98,7 @@ builds.ath = { runATH jenkins: fileUri, metadataFile: metadataPath } } -}*/ +} builds.failFast = failFast parallel builds diff --git a/bom/pom.xml b/bom/pom.xml index bef9f8bb9d..6b93b53647 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -148,11 +148,11 @@ THE SOFTWARE. servlet-api [0] provided diff --git a/cli/pom.xml b/cli/pom.xml index 9f483141d4..c9ca340dbe 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -16,6 +16,7 @@ Medium + 5.5.2 @@ -31,26 +32,38 @@ + + org.junit.jupiter + junit-jupiter-api + ${junit.jupiter.version} + test + + + org.junit.jupiter + junit-jupiter-engine + ${junit.jupiter.version} + test + + + org.junit.jupiter + junit-jupiter + ${junit.jupiter.version} + test + org.kohsuke access-modifier-annotation + provided org.jenkins-ci annotation-indexer - - - commons-codec - commons-codec + true commons-io commons-io - - - ${project.groupId} - remoting - + true junit @@ -61,61 +74,88 @@ org.jvnet.localizer localizer 1.26 + true org.apache.sshd sshd-core 1.7.0 - true + true + + + + net.i2p.crypto + eddsa + 0.3.0 + true - - - net.i2p.crypto - eddsa - 0.3.0 - org.slf4j slf4j-jdk14 - true + true + + + org.glassfish.tyrus.bundles + tyrus-standalone-client-jdk + 1.12 + true com.github.spotbugs spotbugs-annotations - true + provided commons-lang commons-lang + true - maven-assembly-plugin - - - - - single - - package - - - jar-with-dependencies - - - - hudson.cli.CLI - - - ${project.version} - - - - - + maven-surefire-plugin + 2.22.2 + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.1 + + + package + + shade + + + false + + + javax.websocket + io.jenkins.cli.shaded.javax.websocket + + + org + io.jenkins.cli.shaded.org + + + net + io.jenkins.cli.shaded.net + + + + + hudson.cli.CLI + + ${project.version} + + + + + + + org.jvnet.localizer diff --git a/cli/src/main/java/hudson/cli/CLI.java b/cli/src/main/java/hudson/cli/CLI.java index b66f092448..1b9b4856ad 100644 --- a/cli/src/main/java/hudson/cli/CLI.java +++ b/cli/src/main/java/hudson/cli/CLI.java @@ -24,6 +24,7 @@ package hudson.cli; import hudson.cli.client.Messages; +import java.io.DataInputStream; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; @@ -33,22 +34,33 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.URI; import java.net.URL; import java.net.URLConnection; +import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.security.GeneralSecurityException; import java.security.KeyPair; import java.security.SecureRandom; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Properties; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; import static java.util.logging.Level.*; +import javax.websocket.ClientEndpointConfig; +import javax.websocket.Endpoint; +import javax.websocket.EndpointConfig; +import javax.websocket.Session; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; +import org.glassfish.tyrus.client.ClientManager; +import org.glassfish.tyrus.client.ClientProperties; +import org.glassfish.tyrus.container.jdk.client.JdkClientContainer; /** * CLI entry point to Jenkins. @@ -91,7 +103,7 @@ public static void main(final String[] _args) throws Exception { } } - private enum Mode {HTTP, SSH} + private enum Mode {HTTP, SSH, WEB_SOCKET} public static int _main(String[] _args) throws Exception { List args = Arrays.asList(_args); PrivateKeyProvider provider = new PrivateKeyProvider(); @@ -101,8 +113,9 @@ public static int _main(String[] _args) throws Exception { if (url==null) url = System.getenv("HUDSON_URL"); - boolean tryLoadPKey = true; + boolean noKeyAuth = false; + // TODO perhaps allow mode to be defined by environment variable too (assuming $JENKINS_USER_ID can be used for -user) Mode mode = null; String user = null; @@ -137,6 +150,15 @@ public static int _main(String[] _args) throws Exception { args = args.subList(1, args.size()); continue; } + if (head.equals("-webSocket")) { + if (mode != null) { + printUsage("-webSocket clashes with previously defined mode " + mode); + return -1; + } + mode = Mode.WEB_SOCKET; + args = args.subList(1, args.size()); + continue; + } if (head.equals("-remoting")) { printUsage("-remoting mode is no longer supported"); return -1; @@ -161,7 +183,7 @@ public boolean verify(String s, SSLSession sslSession) { continue; } if (head.equals("-noKeyAuth")) { - tryLoadPKey = false; + noKeyAuth = true; args = args.subList(1,args.size()); continue; } @@ -229,9 +251,6 @@ public boolean verify(String s, SSLSession sslSession) { if(args.isEmpty()) args = Arrays.asList("help"); // default to help - if (tryLoadPKey && !provider.hasKeys()) - provider.readFromDefaultLocations(); - if (mode == null) { mode = Mode.HTTP; } @@ -248,6 +267,9 @@ public boolean verify(String s, SSLSession sslSession) { LOGGER.warning("-user required when using -ssh"); return -1; } + if (!noKeyAuth && !provider.hasKeys()) { + provider.readFromDefaultLocations(); + } return SSHCLI.sshConnection(url, user, args, provider, strictHostKey); } @@ -255,6 +277,10 @@ public boolean verify(String s, SSLSession sslSession) { LOGGER.warning("-strictHostKey meaningful only with -ssh"); } + if (noKeyAuth) { + LOGGER.warning("-noKeyAuth meaningful only with -ssh"); + } + if (user != null) { LOGGER.warning("Warning: -user ignored unless using -ssh"); } @@ -271,66 +297,63 @@ public boolean verify(String s, SSLSession sslSession) { return plainHttpConnection(url, args, factory); } + if (mode == Mode.WEB_SOCKET) { + return webSocketConnection(url, args, factory); + } + throw new AssertionError(); } - private static int plainHttpConnection(String url, List args, CLIConnectionFactory factory) throws IOException, InterruptedException { - LOGGER.log(FINE, "Trying to connect to {0} via plain protocol over HTTP", url); - FullDuplexHttpStream streams = new FullDuplexHttpStream(new URL(url), "cli?remoting=false", factory.authorization); - class ClientSideImpl extends PlainCLIProtocol.ClientSide { - boolean complete; - int exit = -1; - ClientSideImpl(InputStream is, OutputStream os) throws IOException { - super(is, os); - if (is.read() != 0) { // cf. FullDuplexHttpService - throw new IOException("expected to see initial zero byte; perhaps you are connecting to an old server which does not support -http?"); - } - } + private static int webSocketConnection(String url, List args, CLIConnectionFactory factory) throws Exception { + LOGGER.fine(() -> "Trying to connect to " + url + " via plain protocol over WebSocket"); + class CLIEndpoint extends Endpoint { @Override - protected void onExit(int code) { - this.exit = code; - finished(); - } + public void onOpen(Session session, EndpointConfig config) {} + } + class Authenticator extends ClientEndpointConfig.Configurator { @Override - protected void onStdout(byte[] chunk) throws IOException { - System.out.write(chunk); + public void beforeRequest(Map> headers) { + if (factory.authorization != null) { + headers.put("Authorization", Collections.singletonList(factory.authorization)); + } } + } + ClientManager client = ClientManager.createClient(JdkClientContainer.class.getName()); // ~ ContainerProvider.getWebSocketContainer() + client.getProperties().put(ClientProperties.REDIRECT_ENABLED, true); // https://tyrus-project.github.io/documentation/1.13.1/index/tyrus-proprietary-config.html#d0e1775 + Session session = client.connectToServer(new CLIEndpoint(), ClientEndpointConfig.Builder.create().configurator(new Authenticator()).build(), URI.create(url.replaceFirst("^http", "ws") + "cli/ws")); + PlainCLIProtocol.Output out = new PlainCLIProtocol.Output() { @Override - protected void onStderr(byte[] chunk) throws IOException { - System.err.write(chunk); + public void send(byte[] data) throws IOException { + session.getBasicRemote().sendBinary(ByteBuffer.wrap(data)); } @Override - protected void handleClose() { - finished(); - } - private synchronized void finished() { - complete = true; - notifyAll(); + public void close() throws IOException { + session.close(); } + }; + try (ClientSideImpl connection = new ClientSideImpl(out)) { + session.addMessageHandler(InputStream.class, is -> { + try { + connection.handle(new DataInputStream(is)); + } catch (IOException x) { + LOGGER.log(Level.WARNING, null, x); + } + }); + connection.start(args); + return connection.exit(); } - try (final ClientSideImpl connection = new ClientSideImpl(streams.getInputStream(), streams.getOutputStream())) { - for (String arg : args) { - connection.sendArg(arg); + } + + private static int plainHttpConnection(String url, List args, CLIConnectionFactory factory) throws IOException, InterruptedException { + LOGGER.log(FINE, "Trying to connect to {0} via plain protocol over HTTP", url); + FullDuplexHttpStream streams = new FullDuplexHttpStream(new URL(url), "cli?remoting=false", factory.authorization); + try (final ClientSideImpl connection = new ClientSideImpl(new PlainCLIProtocol.FramedOutput(streams.getOutputStream()))) { + connection.start(args); + InputStream is = streams.getInputStream(); + if (is.read() != 0) { // cf. FullDuplexHttpService + throw new IOException("expected to see initial zero byte; perhaps you are connecting to an old server which does not support -http?"); } - connection.sendEncoding(Charset.defaultCharset().name()); - connection.sendLocale(Locale.getDefault().toString()); - connection.sendStart(); - connection.begin(); - new Thread("input reader") { - @Override - public void run() { - try { - final OutputStream stdin = connection.streamStdin(); - int c; - while (!connection.complete && (c = System.in.read()) != -1) { - stdin.write(c); - } - connection.sendEndStdin(); - } catch (IOException x) { - LOGGER.log(Level.WARNING, null, x); - } - } - }.start(); + new PlainCLIProtocol.FramedReader(connection, is).start(); new Thread("ping") { // JENKINS-46659 @Override public void run() { @@ -347,13 +370,77 @@ public void run() { } }.start(); - synchronized (connection) { - while (!connection.complete) { - connection.wait(); + return connection.exit(); + } + } + + private static final class ClientSideImpl extends PlainCLIProtocol.ClientSide { + + volatile boolean complete; + private int exit = -1; + + ClientSideImpl(PlainCLIProtocol.Output out) { + super(out); + } + + void start(List args) throws IOException { + for (String arg : args) { + sendArg(arg); + } + sendEncoding(Charset.defaultCharset().name()); + sendLocale(Locale.getDefault().toString()); + sendStart(); + new Thread("input reader") { + @Override + public void run() { + try { + final OutputStream stdin = streamStdin(); + int c; + // TODO check available to avoid sending lots of one-byte frames + while (!complete && (c = System.in.read()) != -1) { + stdin.write(c); + } + sendEndStdin(); + } catch (IOException x) { + LOGGER.log(Level.WARNING, null, x); + } } + }.start(); + } + + @Override + protected synchronized void onExit(int code) { + this.exit = code; + finished(); + } + + @Override + protected void onStdout(byte[] chunk) throws IOException { + System.out.write(chunk); + } + + @Override + protected void onStderr(byte[] chunk) throws IOException { + System.err.write(chunk); + } + + @Override + protected void handleClose() { + finished(); + } + + private synchronized void finished() { + complete = true; + notifyAll(); + } + + synchronized int exit() throws InterruptedException { + while (!complete) { + wait(); } - return connection.exit; + return exit; } + } private static String computeVersion() { diff --git a/cli/src/main/java/hudson/cli/PlainCLIProtocol.java b/cli/src/main/java/hudson/cli/PlainCLIProtocol.java index ed5c453360..5359b7c738 100644 --- a/cli/src/main/java/hudson/cli/PlainCLIProtocol.java +++ b/cli/src/main/java/hudson/cli/PlainCLIProtocol.java @@ -37,6 +37,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.io.IOUtils; +import org.apache.commons.io.input.BoundedInputStream; import org.apache.commons.io.input.CountingInputStream; /** @@ -76,111 +77,143 @@ private enum Op { } } - static abstract class EitherSide implements Closeable { + interface Output extends Closeable { + void send(byte[] data) throws IOException; + } - private final CountingInputStream cis; - private final FlightRecorderInputStream flightRecorder; - final DataInputStream dis; - final DataOutputStream dos; + static final class FramedOutput implements Output { - protected EitherSide(InputStream is, OutputStream os) { - cis = new CountingInputStream(is); - flightRecorder = new FlightRecorderInputStream(cis); - dis = new DataInputStream(flightRecorder); + private final DataOutputStream dos; + + FramedOutput(OutputStream os) { dos = new DataOutputStream(os); } - final void begin() { - new Reader().start(); + @Override + public void send(byte[] data) throws IOException { + dos.writeInt(data.length - 1); // not counting the opcode + dos.write(data); + dos.flush(); + } + + @Override + public void close() throws IOException { + dos.close(); } - private class Reader extends Thread { + } - Reader() { - super("PlainCLIProtocol"); // TODO set distinctive Thread.name - } + static final class FramedReader extends Thread { - @Override - public void run() { - try { - while (true) { - LOGGER.finest("reading frame"); - int framelen; - try { - framelen = dis.readInt(); - } catch (EOFException x) { - handleClose(); - break; // TODO verify that we hit EOF immediately, not partway into framelen - } - if (framelen < 0) { - throw new IOException("corrupt stream: negative frame length"); - } - byte b = dis.readByte(); - if (b < 0) { // i.e., >127 - throw new IOException("corrupt stream: negative operation code"); - } - if (b >= Op.values().length) { - LOGGER.log(Level.WARNING, "unknown operation #{0}: {1}", new Object[] {b, HexDump.toHex(flightRecorder.getRecord())}); - IOUtils.skipFully(dis, framelen); - continue; - } - Op op = Op.values()[b]; - long start = cis.getByteCount(); - LOGGER.log(Level.FINEST, "handling frame with {0} of length {1}", new Object[] {op, framelen}); - boolean handled = handle(op, framelen); - if (handled) { - long actuallyRead = cis.getByteCount() - start; - if (actuallyRead != framelen) { - throw new IOException("corrupt stream: expected to read " + framelen + " bytes from " + op + " but read " + actuallyRead); - } - } else { - LOGGER.log(Level.WARNING, "unexpected {0}: {1}", new Object[] {op, HexDump.toHex(flightRecorder.getRecord())}); - IOUtils.skipFully(dis, framelen); + private final EitherSide side; + private final CountingInputStream cis; + private final FlightRecorderInputStream flightRecorder; + private final DataInputStream dis; + + FramedReader(EitherSide side, InputStream is) { + super("PlainCLIProtocol"); // TODO set distinctive Thread.name + this.side = side; + cis = new CountingInputStream(is); + flightRecorder = new FlightRecorderInputStream(cis); + dis = new DataInputStream(flightRecorder); + } + + @Override + public void run() { + try { + while (true) { + LOGGER.finest("reading frame"); + int framelen; + try { + framelen = dis.readInt(); + } catch (EOFException x) { + side.handleClose(); + break; // TODO verify that we hit EOF immediately, not partway into framelen + } + if (framelen < 0) { + throw new IOException("corrupt stream: negative frame length"); + } + LOGGER.finest("read frame length " + framelen); + long start = cis.getByteCount(); + try { + side.handle(new DataInputStream(new BoundedInputStream(dis, /* op byte not counted */framelen + 1))); + } catch (ProtocolException x) { + LOGGER.log(Level.WARNING, null, x); + // but read another frame + } finally { + long actuallyRead = cis.getByteCount() - start; + long unread = framelen + 1 - actuallyRead; + if (unread > 0) { + LOGGER.warning(() -> "Did not read " + unread + " bytes"); + IOUtils.skipFully(dis, unread); } } - } catch (ClosedChannelException x) { - LOGGER.log(Level.FINE, null, x); - handleClose(); - } catch (IOException x) { - LOGGER.log(Level.WARNING, null, flightRecorder.analyzeCrash(x, "broken stream")); - } catch (ReadPendingException x) { - // in case trick in CLIAction does not work - LOGGER.log(Level.FINE, null, x); - handleClose(); - } catch (RuntimeException x) { - LOGGER.log(Level.WARNING, null, x); - handleClose(); } + } catch (ClosedChannelException x) { + LOGGER.log(Level.FINE, null, x); + side.handleClose(); + } catch (IOException x) { + LOGGER.log(Level.WARNING, null, flightRecorder.analyzeCrash(x, "broken stream")); + } catch (ReadPendingException x) { + // in case trick in CLIAction does not work + LOGGER.log(Level.FINE, null, x); + side.handleClose(); + } catch (RuntimeException x) { + LOGGER.log(Level.WARNING, null, x); + side.handleClose(); } + } + } + + private static final class ProtocolException extends IOException { + ProtocolException(String message) { + super(message); } + } - protected abstract void handleClose(); + static abstract class EitherSide implements Closeable { - protected abstract boolean handle(Op op, int framelen) throws IOException; + private final Output out; - private void writeOp(Op op) throws IOException { - dos.writeByte((byte) op.ordinal()); + protected EitherSide(Output out) { + this.out = out; } + protected abstract void handleClose(); + + final void handle(DataInputStream dis) throws IOException { + byte b = dis.readByte(); + if (b < 0) { // i.e., >127 + throw new IOException("corrupt stream: negative operation code"); + } + if (b >= Op.values().length) { + throw new ProtocolException("unknown operation #" + b); + } + Op op = Op.values()[b]; + LOGGER.finest(() -> "handling frame with " + op); + if (!handle(op, dis)) { + throw new ProtocolException("unhandled: " + op); + } + } + + protected abstract boolean handle(Op op, DataInputStream dis) throws IOException; + protected final synchronized void send(Op op) throws IOException { - dos.writeInt(0); - writeOp(op); - dos.flush(); + send(op, new byte[0], 0, 0); } - protected final synchronized void send(Op op, int number) throws IOException { - dos.writeInt(4); - writeOp(op); - dos.writeInt(number); - dos.flush(); + protected final synchronized void send(Op op, int v) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(4); + new DataOutputStream(baos).writeInt(v); + send(op, baos.toByteArray()); } protected final synchronized void send(Op op, byte[] chunk, int off, int len) throws IOException { - dos.writeInt(len); - writeOp(op); - dos.write(chunk, off, len); - dos.flush(); + byte[] data = new byte[len + 1]; + data[0] = (byte) op.ordinal(); + System.arraycopy(chunk, off, data, 1, len); + out.send(data); } protected final void send(Op op, byte[] chunk) throws IOException { @@ -193,13 +226,6 @@ protected final void send(Op op, String text) throws IOException { send(op, buf.toByteArray()); } - protected final byte[] readChunk(int framelen) throws IOException { - assert Thread.currentThread() instanceof EitherSide.Reader; - byte[] buf = new byte[framelen]; - dis.readFully(buf); - return buf; - } - protected final OutputStream stream(final Op op) { return new OutputStream() { @Override @@ -219,20 +245,19 @@ public void write(byte[] b) throws IOException { @Override public synchronized void close() throws IOException { - dos.close(); + out.close(); } } static abstract class ServerSide extends EitherSide { - ServerSide(InputStream is, OutputStream os) { - super(is, os); + ServerSide(Output out) { + super(out); } @Override - protected final boolean handle(Op op, int framelen) throws IOException { - assert Thread.currentThread() instanceof EitherSide.Reader; + protected final boolean handle(Op op, DataInputStream dis) throws IOException { assert op.clientSide; switch (op) { case ARG: @@ -248,7 +273,7 @@ protected final boolean handle(Op op, int framelen) throws IOException { onStart(); return true; case STDIN: - onStdin(readChunk(framelen)); + onStdin(IOUtils.toByteArray(dis)); return true; case END_STDIN: onEndStdin(); @@ -286,23 +311,22 @@ public final OutputStream streamStderr() { static abstract class ClientSide extends EitherSide { - ClientSide(InputStream is, OutputStream os) { - super(is, os); + ClientSide(Output out) { + super(out); } @Override - protected boolean handle(Op op, int framelen) throws IOException { - assert Thread.currentThread() instanceof EitherSide.Reader; + protected boolean handle(Op op, DataInputStream dis) throws IOException { assert !op.clientSide; switch (op) { case EXIT: onExit(dis.readInt()); return true; case STDOUT: - onStdout(readChunk(framelen)); + onStdout(IOUtils.toByteArray(dis)); return true; case STDERR: - onStderr(readChunk(framelen)); + onStderr(IOUtils.toByteArray(dis)); return true; default: return false; @@ -311,6 +335,7 @@ protected boolean handle(Op op, int framelen) throws IOException { protected abstract void onExit(int code); + // TODO more efficient to change signature to InputStream, then use IOUtils.copy protected abstract void onStdout(byte[] chunk) throws IOException; protected abstract void onStderr(byte[] chunk) throws IOException; diff --git a/cli/src/main/resources/hudson/cli/client/Messages.properties b/cli/src/main/resources/hudson/cli/client/Messages.properties index c789036505..de4cac2174 100644 --- a/cli/src/main/resources/hudson/cli/client/Messages.properties +++ b/cli/src/main/resources/hudson/cli/client/Messages.properties @@ -3,6 +3,7 @@ CLI.Usage=Jenkins CLI\n\ Options:\n\ \ -s URL : the server URL (defaults to the JENKINS_URL env var)\n\ \ -http : use a plain CLI protocol over HTTP(S) (the default; mutually exclusive with -ssh)\n\ + \ -webSocket : like -http but using WebSocket (works better with most reverse proxies)\n\ \ -ssh : use SSH protocol (requires -user; SSH port must be open on server, and user must have registered a public key)\n\ \ -i KEY : SSH private key file used for authentication (for use with -ssh)\n\ \ -noCertificateCheck : bypass HTTPS certificate check entirely. Use with caution\n\ diff --git a/cli/src/main/resources/hudson/cli/client/Messages_da.properties b/cli/src/main/resources/hudson/cli/client/Messages_da.properties index 84a2e91e10..5414bbe31f 100644 --- a/cli/src/main/resources/hudson/cli/client/Messages_da.properties +++ b/cli/src/main/resources/hudson/cli/client/Messages_da.properties @@ -22,7 +22,7 @@ CLI.VersionMismatch=Versionskonflikt. CLI''en fungerer ikke med denne Hudson server CLI.Usage=Jenkins_ CLI\n\ -Brug: java -jar jenkins-cli.jar [-s URL] command [opts...] args...\n\ +Brug: java -jar jenkins-cli.jar [-s URL] command [opts...] args...\n\ Tilvalg:\n\ De tilg\u00e6ngelige kommandoer afh\u00e6nger af serveren. K\u00f8r 'help' kommandoen for at se listen. CLI.NoURL=Hverken -s eller JENKINS_URL milj\u00f8variablen er defineret diff --git a/cli/src/test/java/hudson/cli/HexDumpTest.java b/cli/src/test/java/hudson/cli/HexDumpTest.java index 9cd1c78995..1e1aa9f70e 100644 --- a/cli/src/test/java/hudson/cli/HexDumpTest.java +++ b/cli/src/test/java/hudson/cli/HexDumpTest.java @@ -1,8 +1,12 @@ package hudson.cli; + import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; +@Execution(ExecutionMode.CONCURRENT) public class HexDumpTest { @Test diff --git a/cli/src/test/java/hudson/cli/PlainCLIProtocolTest.java b/cli/src/test/java/hudson/cli/PlainCLIProtocolTest.java index 4663fbafd5..953b01d02c 100644 --- a/cli/src/test/java/hudson/cli/PlainCLIProtocolTest.java +++ b/cli/src/test/java/hudson/cli/PlainCLIProtocolTest.java @@ -24,12 +24,16 @@ package hudson.cli; +import org.junit.jupiter.api.Test; + import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; import java.io.IOException; import java.io.PipedInputStream; import java.io.PipedOutputStream; -import static org.junit.Assert.*; -import org.junit.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + public class PlainCLIProtocolTest { @@ -41,7 +45,7 @@ class Client extends PlainCLIProtocol.ClientSide { int code = -1; final ByteArrayOutputStream stdout = new ByteArrayOutputStream(); Client() throws IOException { - super(new PipedInputStream(download), upload); + super(new PlainCLIProtocol.FramedOutput(upload)); } @Override protected synchronized void onExit(int code) { @@ -62,6 +66,7 @@ void send() throws IOException { streamStdin().write("hello".getBytes()); } void newop() throws IOException { + DataOutputStream dos = new DataOutputStream(upload); dos.writeInt(0); dos.writeByte(99); dos.flush(); @@ -72,7 +77,7 @@ class Server extends PlainCLIProtocol.ServerSide { boolean started; final ByteArrayOutputStream stdin = new ByteArrayOutputStream(); Server() throws IOException { - super(new PipedInputStream(upload), download); + super(new PlainCLIProtocol.FramedOutput(download)); } @Override protected void onArg(String text) { @@ -89,6 +94,13 @@ protected synchronized void onStart() { } @Override protected void onStdin(byte[] chunk) throws IOException { + /* To inject a race condition: + try { + Thread.sleep(1000); + } catch (InterruptedException x) { + throw new IOException(x); + } + */ stdin.write(chunk); } @Override @@ -100,6 +112,7 @@ void send() throws IOException { sendExit(2); } void newop() throws IOException { + DataOutputStream dos = new DataOutputStream(download); dos.writeInt(0); dos.writeByte(99); dos.flush(); @@ -107,8 +120,8 @@ void newop() throws IOException { } Client client = new Client(); Server server = new Server(); - client.begin(); - server.begin(); + new PlainCLIProtocol.FramedReader(client, new PipedInputStream(download)).start(); + new PlainCLIProtocol.FramedReader(server, new PipedInputStream(upload)).start(); client.send(); client.newop(); synchronized (server) { @@ -123,6 +136,9 @@ void newop() throws IOException { client.wait(); } } + while (server.stdin.size() == 0) { + Thread.sleep(100); + } assertEquals("hello", server.stdin.toString()); assertEquals("command", server.arg); assertEquals("goodbye", client.stdout.toString()); diff --git a/cli/src/test/java/hudson/cli/PrivateKeyProviderTest.java b/cli/src/test/java/hudson/cli/PrivateKeyProviderTest.java index 9c7a61b396..b186263346 100644 --- a/cli/src/test/java/hudson/cli/PrivateKeyProviderTest.java +++ b/cli/src/test/java/hudson/cli/PrivateKeyProviderTest.java @@ -1,6 +1,9 @@ package hudson.cli; -import org.junit.Test; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.parallel.Execution; +import org.junit.jupiter.api.parallel.ExecutionMode; import java.io.File; import java.io.IOException; @@ -9,11 +12,13 @@ import java.security.KeyPair; import java.security.NoSuchAlgorithmException; -import static org.junit.Assert.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; /** keys were generated with ssh-keygen from OpenSSH_7.9p1, LibreSSL 2.7.3 */ +@Execution(ExecutionMode.CONCURRENT) public class PrivateKeyProviderTest { /** @@ -78,21 +83,21 @@ public void loadKeyOpenSSH() throws IOException, GeneralSecurityException { /** key command: ssh-keygen -f openssh-unsupported -t rsa -b 1024 -p password */ - @Test(expected = NoSuchAlgorithmException.class) + @Test public void loadKeyUnsupportedCipher() throws IOException, GeneralSecurityException { File file = new File(this.getClass().getResource("openssh-unsuported").getFile()); String password = "password"; - PrivateKeyProvider.loadKey(file, password); + assertThrows(NoSuchAlgorithmException.class, () -> PrivateKeyProvider.loadKey(file, password)); } /** key command: ssh-keygen -f openssh -t rsa -b 1024 in this key we remove some lines to break the key. */ - @Test(expected = IllegalArgumentException.class) + @Test public void loadKeyBroken() throws IOException, GeneralSecurityException { File file = new File(this.getClass().getResource("openssh-broken").getFile()); String password = "password"; - PrivateKeyProvider.loadKey(file, password); + assertThrows(IllegalArgumentException.class, () -> PrivateKeyProvider.loadKey(file, password)); } } diff --git a/core/pom.xml b/core/pom.xml index 0402553742..1d3fc47089 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -642,6 +642,18 @@ THE SOFTWARE. jzlib 1.1.3-kohsuke-1 + + org.xmlunit + xmlunit-core + 2.2.1 + test + + + org.xmlunit + xmlunit-matchers + 2.2.1 + test + diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_bg.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_bg.properties deleted file mode 100644 index 95e74685ad..0000000000 --- a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_bg.properties +++ /dev/null @@ -1,32 +0,0 @@ -# The MIT License -# -# Bulgarian translation: Copyright (c) 2015, 2016, 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. - -NewVersionAvailable=\ - \u041d\u043e\u0432\u0430\u0442\u0430 \u0432\u0435\u0440\u0441\u0438\u044f \u043d\u0430 Jenkins ({0}) \u0435 \u043d\u0430\u043b\u0438\u0447\u043d\u0430 \u0437\u0430 \u0438\u0437\u0442\u0435\u0433\u043b\u044f\u043d\u0435\ - (\u0441\u043f\u0438\u0441\u044a\u043a \u0441 \u043f\u0440\u043e\u043c\u0435\u043d\u0438\u0442\u0435). -UpgradeComplete=\ - \u041e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435\u0442\u043e \u043a\u044a\u043c \u043d\u043e\u0432\u0430\u0442\u0430 \u0432\u0435\u0440\u0441\u0438\u044f Jenkins {0} \u043f\u0440\u0438\u043a\u043b\u044e\u0447\u0438. \u0422\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u0442\u0435. -UpgradeCompleteRestartNotSupported=\ -\u041e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435\u0442\u043e \u043a\u044a\u043c \u043d\u043e\u0432\u0430\u0442\u0430 \u0432\u0435\u0440\u0441\u0438\u044f Jenkins {0} \u043f\u0440\u0438\u043a\u043b\u044e\u0447\u0438. \u0422\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u0442\u0435. -UpgradeProgress=\u0418\u0437\u043f\u044a\u043b\u043d\u044f\u0432\u0430 \u0441\u0435 \u043e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 \u043a\u044a\u043c Jenkins {0}. -UpgradeFailed=\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 \u043a\u044a\u043c Jenkins {0}: {1}. diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_it.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_it.properties deleted file mode 100644 index 510a7f5f86..0000000000 --- a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_it.properties +++ /dev/null @@ -1,6 +0,0 @@ -NewVersionAvailable=Una nuova versione di Jenkins ({0}) disponibile per il download \ - (log delle modifiche). -UpgradeComplete=Aggiornamento a Jenkins {0} completato, in attesa del riavvio. -UpgradeCompleteRestartNotSupported=Aggiornamento a Jenkins {0} completato, in attesa del riavvio. -UpgradeProgress=Aggiornamento a Jenkins {0} in corso. -UpgradeFailed=Aggiornamento a Jenkins {0} non riuscito: {1}. diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ru.properties b/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ru.properties deleted file mode 100644 index 97659c57c7..0000000000 --- a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ru.properties +++ /dev/null @@ -1,27 +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. - -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. -UpgradeProgress=\u041E\u0431\u043D\u043E\u0432\u043B\u0435\u043D\u0438\u0435 \u043D\u0430 Jenkins {0} \u0432\u044B\u043F\u043E\u043B\u043D\u044F\u0435\u0442\u0441\u044F \u0438\u043B\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043B\u043E\u0441\u044C \u043D\u0435\u0443\u0434\u0430\u0447\u0435\u0439. diff --git a/core/src/filter/resources/hudson/model/hudson-version.properties b/core/src/filter/resources/hudson/model/hudson-version.properties index defbd48204..7650f6ad16 100644 --- a/core/src/filter/resources/hudson/model/hudson-version.properties +++ b/core/src/filter/resources/hudson/model/hudson-version.properties @@ -1 +1,2 @@ +# TODO unused? version=${project.version} diff --git a/core/src/filter/resources/jenkins/model/jenkins-version.properties b/core/src/filter/resources/jenkins/model/jenkins-version.properties index defbd48204..662419771c 100644 --- a/core/src/filter/resources/jenkins/model/jenkins-version.properties +++ b/core/src/filter/resources/jenkins/model/jenkins-version.properties @@ -1 +1,2 @@ version=${project.version} +changelog.url=${changelog.url} diff --git a/core/src/main/java/hudson/EnvVars.java b/core/src/main/java/hudson/EnvVars.java index 0dbec25143..e076b1e370 100644 --- a/core/src/main/java/hudson/EnvVars.java +++ b/core/src/main/java/hudson/EnvVars.java @@ -388,6 +388,15 @@ public void putIfNotNull(String key, String value) { if (value!=null) put(key,value); } + + /** + * Add entire map but filter null values out. + * @since TODO + */ + public void putAllNonNull(Map map) { + map.forEach(this::putIfNotNull); + } + /** * Takes a string that looks like "a=b" and adds that to this map. diff --git a/core/src/main/java/hudson/ExtensionFinder.java b/core/src/main/java/hudson/ExtensionFinder.java index 76a7908adc..ef5cfe1237 100644 --- a/core/src/main/java/hudson/ExtensionFinder.java +++ b/core/src/main/java/hudson/ExtensionFinder.java @@ -63,6 +63,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -482,26 +483,35 @@ public SezpozModule(List> index) { * So this is an attempt to detect subset of problems eagerly, by invoking various reflection * operations and try to find non-existent classes early. */ - private void resolve(Class c) { + private void resolve(Class c) { + resolve(c, new HashSet<>()); + } + private void resolve(Class c, Set> encountered) { + if (!encountered.add(c)) { + return; + } try { - c.getGenericSuperclass(); - c.getGenericInterfaces(); ClassLoader ecl = c.getClassLoader(); - Method m = ClassLoader.class.getDeclaredMethod("resolveClass", Class.class); - m.setAccessible(true); - m.invoke(ecl, c); - c.getConstructors(); - c.getMethods(); - for (Field f : c.getFields()) { - if (f.getAnnotation(javax.inject.Inject.class) != null || f.getAnnotation(com.google.inject.Inject.class) != null) { - resolve(f.getType()); + if (ecl != null) { // Not bootstrap classloader + Method m = ClassLoader.class.getDeclaredMethod("resolveClass", Class.class); + m.setAccessible(true); + m.invoke(ecl, c); + } + for (Class cc = c; cc != Object.class; cc = cc.getSuperclass()) { + /** + * See {@link com.google.inject.spi.InjectionPoint#getInjectionPoints(TypeLiteral, boolean, Errors)} + */ + cc.getGenericSuperclass(); + cc.getGenericInterfaces(); + cc.getDeclaredConstructors(); + cc.getDeclaredMethods(); + for (Field f : cc.getDeclaredFields()) { + if (f.getAnnotation(javax.inject.Inject.class) != null || f.getAnnotation(com.google.inject.Inject.class) != null) { + resolve(f.getType(), encountered); + } } } LOGGER.log(Level.FINER, "{0} looks OK", c); - while (c != Object.class) { - c.getGenericSuperclass(); - c = c.getSuperclass(); - } } catch (Exception x) { throw (LinkageError)new LinkageError("Failed to resolve "+c).initCause(x); } diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index 84f6d112cf..f0c866e90a 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -1520,7 +1520,7 @@ public String invoke(File dir, VirtualChannel channel) throws IOException { tempPath = Files.createTempDirectory(Util.fileToPath(dir), name, PosixFilePermissions.asFileAttribute(EnumSet.allOf(PosixFilePermission.class))); } else { - tempPath = Files.createTempDirectory(Util.fileToPath(dir), name, new FileAttribute[] {}); + tempPath = Files.createTempDirectory(Util.fileToPath(dir), name); } if (tempPath.toFile() == null) { @@ -2754,7 +2754,7 @@ public String invoke(File dir, VirtualChannel channel) throws IOException, Inter int idx = findSeparator(f); if(idx==-1) break; - prefix.append(f.substring(0, idx)).append('/'); + prefix.append(f, 0, idx).append('/'); f=f.substring(idx+1); if(hasMatch(dir,prefix+fileMask,caseSensitive)) return Messages.FilePath_validateAntFileMask_doesntMatchAndSuggest(fileMask, prefix+fileMask); diff --git a/core/src/main/java/hudson/Functions.java b/core/src/main/java/hudson/Functions.java index 3902d952f5..50339569b6 100644 --- a/core/src/main/java/hudson/Functions.java +++ b/core/src/main/java/hudson/Functions.java @@ -84,9 +84,12 @@ import hudson.views.ViewsTabBar; import hudson.widgets.RenderOnDemandClosure; + import java.io.File; import java.io.IOException; +import java.io.PrintStream; import java.io.PrintWriter; +import java.io.Serializable; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.lang.management.LockInfo; @@ -158,7 +161,7 @@ import com.google.common.base.Predicates; import hudson.model.PasswordParameterDefinition; import hudson.util.RunList; -import java.io.PrintStream; + import java.util.HashSet; import java.util.Set; import java.util.concurrent.atomic.AtomicLong; @@ -386,6 +389,11 @@ public static Area getScreenResolution() { return null; } + @Restricted(NoExternalUse.class) + public static boolean useHidingPasswordFields() { + return SystemProperties.getBoolean(Functions.class.getName() + ".hidingPasswordFields", true); + } + /** * URL decomposed for easier computation of relevant URLs. * @@ -645,6 +653,7 @@ public static void configureAutoRefresh(HttpServletRequest request, HttpServletR // to avoid conflicts with any other web apps that might be on the same machine. c.setPath("/"); c.setMaxAge(60*60*24*30); // persist it roughly for a month + c.setHttpOnly(true); response.addCookie(c); } if (refresh) { @@ -761,11 +770,15 @@ public static String encode(String s) { /** * Shortcut function for calling {@link URLEncoder#encode(String,String)} (with UTF-8 encoding).
- * Useful for encoding URL query parameters in jelly code (as in {@code "...?param=${h.urlEncode(something)}"}). + * Useful for encoding URL query parameters in jelly code (as in {@code "...?param=${h.urlEncode(something)}"}).
+ * For convenience in jelly code, it also accepts null parameter, and then returns an empty string. * * @since 2.200 */ public static String urlEncode(String s) { + if (s == null) { + return ""; + } try { return URLEncoder.encode(s, StandardCharsets.UTF_8.name()); } catch (UnsupportedEncodingException e) { @@ -1300,7 +1313,7 @@ public static ThreadGroupMap sortThreadsAndGetGroupMap(ThreadInfo[] list) { private static class ThreadSorterBase { protected Map map = new HashMap<>(); - private ThreadSorterBase() { + public ThreadSorterBase() { ThreadGroup tg = Thread.currentThread().getThreadGroup(); while (tg.getParent() != null) tg = tg.getParent(); Thread[] threads = new Thread[tg.activeCount()*2]; @@ -1320,7 +1333,9 @@ protected int compare(long idA, long idB) { } } - public static class ThreadGroupMap extends ThreadSorterBase implements Comparator { + public static class ThreadGroupMap extends ThreadSorterBase implements Comparator, Serializable { + + private static final long serialVersionUID = 7803975728695308444L; /** * @return ThreadGroup name or null if unknown @@ -1337,7 +1352,9 @@ public int compare(ThreadInfo a, ThreadInfo b) { } } - private static class ThreadSorter extends ThreadSorterBase implements Comparator { + private static class ThreadSorter extends ThreadSorterBase implements Comparator, Serializable { + + private static final long serialVersionUID = 5053631350439192685L; public int compare(Thread a, Thread b) { int result = compare(a.getId(), b.getId()); @@ -1474,12 +1491,10 @@ public static String getViewResource(Object it, String path) { if(it instanceof Descriptor) clazz = ((Descriptor)it).clazz; - StringBuilder buf = new StringBuilder(Stapler.getCurrentRequest().getContextPath()); - buf.append(Jenkins.VIEW_RESOURCE_PATH).append('/'); - buf.append(clazz.getName().replace('.','/').replace('$','/')); - buf.append('/').append(path); - - return buf.toString(); + String buf = Stapler.getCurrentRequest().getContextPath() + Jenkins.VIEW_RESOURCE_PATH + '/' + + clazz.getName().replace('.', '/').replace('$', '/') + + '/' + path; + return buf; } public static boolean hasView(Object it, String path) throws IOException { diff --git a/core/src/main/java/hudson/Launcher.java b/core/src/main/java/hudson/Launcher.java index fc688de296..d2007e14b1 100644 --- a/core/src/main/java/hudson/Launcher.java +++ b/core/src/main/java/hudson/Launcher.java @@ -23,7 +23,6 @@ */ package hudson; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.Proc.LocalProc; import hudson.model.Computer; import jenkins.util.MemoryReductionUtil; @@ -1038,8 +1037,6 @@ public RemoteLauncher(@Nonnull TaskListener listener, @Nonnull VirtualChannel ch @Override @Nonnull - @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", - justification = "We always require nonnull channel when we initialize this launcher") public VirtualChannel getChannel() { VirtualChannel vc = super.getChannel(); if (vc == null) { diff --git a/core/src/main/java/hudson/Main.java b/core/src/main/java/hudson/Main.java index 60a3a248bf..b4490d4188 100644 --- a/core/src/main/java/hudson/Main.java +++ b/core/src/main/java/hudson/Main.java @@ -220,7 +220,7 @@ private static HttpURLConnection open(URL url) throws IOException { public static boolean isUnitTest = false; /** - * Set to true if we are running inside "mvn hpi:run" or "mvn hudson-dev:run" + * Set to true if we are running inside {@code mvn hpi:run} or {@code mvn jetty:run}. */ public static boolean isDevelopmentMode = SystemProperties.getBoolean(Main.class.getName()+".development"); diff --git a/core/src/main/java/hudson/PluginManager.java b/core/src/main/java/hudson/PluginManager.java index 231b105dfe..d906466683 100644 --- a/core/src/main/java/hudson/PluginManager.java +++ b/core/src/main/java/hudson/PluginManager.java @@ -633,7 +633,7 @@ void considerDetachedPlugin(String shortName) { protected @Nonnull Set loadPluginsFromWar(@Nonnull String fromPath, @CheckForNull FilenameFilter filter) { Set names = new HashSet(); - ServletContext context = Jenkins.getActiveInstance().servletContext; + ServletContext context = Jenkins.get().servletContext; Set plugins = Util.fixNull(context.getResourcePaths(fromPath)); Set copiedPlugins = new HashSet<>(); Set dependencies = new HashSet<>(); @@ -697,7 +697,7 @@ protected static void addDependencies(URL hpiResUrl, String fromPath, Set d String dependencySpec = manifest.getMainAttributes().getValue("Plugin-Dependencies"); if (dependencySpec != null) { String[] dependencyTokens = dependencySpec.split(","); - ServletContext context = Jenkins.getActiveInstance().servletContext; + ServletContext context = Jenkins.get().servletContext; for (String dependencyToken : dependencyTokens) { if (dependencyToken.endsWith(";resolution:=optional")) { @@ -709,7 +709,7 @@ protected static void addDependencies(URL hpiResUrl, String fromPath, Set d String artifactId = artifactIdVersionPair[0]; VersionNumber dependencyVersion = new VersionNumber(artifactIdVersionPair[1]); - PluginManager manager = Jenkins.getActiveInstance().getPluginManager(); + PluginManager manager = Jenkins.get().getPluginManager(); VersionNumber installedVersion = manager.getPluginVersion(manager.rootDir, artifactId); if (installedVersion != null && !installedVersion.isOlderThan(dependencyVersion)) { // Do not downgrade dependencies that are already installed. @@ -949,23 +949,6 @@ public void dynamicLoad(File arc, boolean removeExisting, @CheckForNull List plugins) throws Exception { try (ACLContext context = ACL.as(ACL.SYSTEM)) { - Jenkins.get().refreshExtensions(); - - for (PluginWrapper p : plugins) { - p.getPlugin().postInitialize(); - } - - // run initializers in the added plugins - Reactor r = new Reactor(InitMilestone.ordering()); - Set loaders = plugins.stream().map(p -> p.classLoader).collect(Collectors.toSet()); - r.addAll(new InitializerFinder(uberClassLoader) { - @Override - protected boolean filter(Method e) { - return !loaders.contains(e.getDeclaringClass().getClassLoader()) || super.filter(e); - } - }.discoverTasks(r)); - new InitReactorRunner().run(r); - Map pluginsByName = plugins.stream().collect(Collectors.toMap(p -> p.getShortName(), p -> p)); // recalculate dependencies of plugins optionally depending the newly deployed ones. @@ -993,6 +976,20 @@ protected boolean filter(Method e) { } catch (ExtensionRefreshException e) { throw new IOException("Failed to refresh extensions after installing some plugins", e); } + for (PluginWrapper p : plugins) { + p.getPlugin().postInitialize(); + } + + // run initializers in the added plugins + Reactor r = new Reactor(InitMilestone.ordering()); + Set loaders = plugins.stream().map(p -> p.classLoader).collect(Collectors.toSet()); + r.addAll(new InitializerFinder(uberClassLoader) { + @Override + protected boolean filter(Method e) { + return !loaders.contains(e.getDeclaringClass().getClassLoader()) || super.filter(e); + } + }.discoverTasks(r)); + new InitReactorRunner().run(r); } } @@ -1376,7 +1373,7 @@ public HttpResponse doPlugins() { } response.add(pluginInfo); } - for (UpdateSite site : Jenkins.getActiveInstance().getUpdateCenter().getSiteList()) { + for (UpdateSite site : Jenkins.get().getUpdateCenter().getSiteList()) { for (UpdateSite.Plugin plugin: site.getAvailables()) { JSONObject pluginInfo = allPlugins.get(plugin.name); if(pluginInfo == null) { @@ -1669,7 +1666,10 @@ public HttpResponse doUploadPlugin(StaplerRequest req) throws IOException, Servl JSONArray dependencies = new JSONArray(); try { - Manifest m = new JarFile(t).getManifest(); + Manifest m; + try (JarFile jarFile = new JarFile(t)) { + m = jarFile.getManifest(); + } String deps = m.getMainAttributes().getValue("Plugin-Dependencies"); if (StringUtils.isNotBlank(deps)) { diff --git a/core/src/main/java/hudson/PluginWrapper.java b/core/src/main/java/hudson/PluginWrapper.java index e217789166..b5b1b9c712 100644 --- a/core/src/main/java/hudson/PluginWrapper.java +++ b/core/src/main/java/hudson/PluginWrapper.java @@ -385,6 +385,7 @@ public Dependency(String s) { String osgiProperty = osgiProperties[i].trim(); if (osgiProperty.equalsIgnoreCase("resolution:=optional")) { isOptional = true; + break; } } this.optional = isOptional; @@ -521,20 +522,30 @@ public String getShortName() { */ @Exported public String getUrl() { - // first look for the manifest entry. This is new in maven-hpi-plugin 1.30 - String url = manifest.getMainAttributes().getValue("Url"); - if(url!=null) return url; + // first look in update center metadata + List siteMetadataList = getInfoFromAllSites(); + String firstSiteUrl = null; + if (!siteMetadataList.isEmpty()) { + firstSiteUrl = siteMetadataList.get(0).wiki; + if (allUrlsMatch(firstSiteUrl, siteMetadataList)) { + return firstSiteUrl; + } + } - // fallback to update center metadata - UpdateSite.Plugin ui = getInfo(); - if(ui!=null) return ui.wiki; + // if update sites give different / empty results, + // use manifest (since maven-hpi-plugin 1.30) + String url = manifest.getMainAttributes().getValue("Url"); + if (url != null) { + return url; + } + return firstSiteUrl; + } - return null; + private boolean allUrlsMatch(String url, List uiList) { + return uiList.stream().allMatch(k -> k.wiki != null && k.wiki.equals(url)); } - - - @Override + @Override public String toString() { return "Plugin:" + getShortName(); } @@ -972,6 +983,11 @@ public UpdateSite.Plugin getInfo() { return uc.getPlugin(getShortName()); } + private List getInfoFromAllSites() { + UpdateCenter uc = Jenkins.get().getUpdateCenter(); + return uc.getPluginFromAllSites(getShortName(), getVersionNumber()); + } + /** * Returns true if this plugin has update in the update center. * @@ -1236,7 +1252,7 @@ public HttpResponse doUnpin() throws IOException { @RequirePOST public HttpResponse doDoUninstall() throws IOException { - Jenkins jenkins = Jenkins.getActiveInstance(); + Jenkins jenkins = Jenkins.get(); jenkins.checkPermission(Jenkins.ADMINISTER); archive.delete(); diff --git a/core/src/main/java/hudson/ProxyConfiguration.java b/core/src/main/java/hudson/ProxyConfiguration.java index cecd2f6843..f79d15ef1d 100644 --- a/core/src/main/java/hudson/ProxyConfiguration.java +++ b/core/src/main/java/hudson/ProxyConfiguration.java @@ -62,7 +62,10 @@ import org.apache.commons.httpclient.methods.GetMethod; import org.jenkinsci.Symbol; import org.jvnet.robust_http_client.RetryableHttpStream; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.DataBoundConstructor; +import org.kohsuke.stapler.DataBoundSetter; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.interceptor.RequirePOST; @@ -94,14 +97,15 @@ public final class ProxyConfiguration extends AbstractDescribableImpl getNoProxyHostPatterns() { return getNoProxyHostPatterns(noProxyHost); } + public String getNoProxyHost() { + return noProxyHost; + } + /** * Returns the list of properly formatted no proxy host names. */ @@ -195,6 +223,26 @@ public static List getNoProxyHostPatterns(String noProxyHost) { return r; } + @DataBoundSetter + public void setSecretPassword(Secret secretPassword) { + this.secretPassword = secretPassword; + } + + @DataBoundSetter + public void setTestUrl(String testUrl) { + this.testUrl = testUrl; + } + + @DataBoundSetter + public void setUserName(String userName) { + this.userName = userName; + } + + @DataBoundSetter + public void setNoProxyHost(String noProxyHost) { + this.noProxyHost = noProxyHost; + } + /** * @deprecated * Use {@link #createProxy(String)} @@ -332,7 +380,7 @@ private static ProxyConfiguration get() { private static ProxyConfiguration _get() { JenkinsJVM.checkJenkinsJVM(); // this code could be called between the JVM flag being set and theInstance initialized - Jenkins jenkins = Jenkins.get(); + Jenkins jenkins = Jenkins.getInstanceOrNull(); return jenkins == null ? null : jenkins.proxy; } @@ -374,9 +422,10 @@ public FormValidation doCheckPort(@QueryParameter String value) { } @RequirePOST + @Restricted(NoExternalUse.class) public FormValidation doValidateProxy( @QueryParameter("testUrl") String testUrl, @QueryParameter("name") String name, @QueryParameter("port") int port, - @QueryParameter("userName") String userName, @QueryParameter("password") String password, + @QueryParameter("userName") String userName, @QueryParameter("secretPassword") Secret password, @QueryParameter("noProxyHost") String noProxyHost) { Jenkins.get().checkPermission(Jenkins.ADMINISTER); @@ -401,7 +450,7 @@ public FormValidation doValidateProxy( HttpClient client = new HttpClient(); if (Util.fixEmptyAndTrim(name) != null && !isNoProxyHost(host, noProxyHost)) { client.getHostConfiguration().setProxy(name, port); - Credentials credentials = createCredentials(userName, password); + Credentials credentials = createCredentials(userName, password != null ? password.getPlainText() : null); AuthScope scope = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT); client.getState().setProxyCredentials(scope, credentials); } diff --git a/core/src/main/java/hudson/Util.java b/core/src/main/java/hudson/Util.java index b9f318ae87..7775b4ca6a 100644 --- a/core/src/main/java/hudson/Util.java +++ b/core/src/main/java/hudson/Util.java @@ -23,6 +23,7 @@ */ package hudson; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.model.TaskListener; import jenkins.util.MemoryReductionUtil; import hudson.util.QuotedStringTokenizer; @@ -692,6 +693,7 @@ public static byte[] fromHexString(@Nonnull String data) { * number of milliseconds. */ @Nonnull + @SuppressFBWarnings(value = "ICAST_IDIV_CAST_TO_DOUBLE", justification = "We want to truncate here.") public static String getTimeSpanString(long duration) { // Break the duration up in to units. long years = duration / ONE_YEAR_MS; @@ -1579,10 +1581,10 @@ public static long daysElapsedSince(@Nonnull Date date){ public static boolean SYMLINK_ESCAPEHATCH = SystemProperties.getBoolean(Util.class.getName()+".symlinkEscapeHatch"); /** - * The number of times we will attempt to delete files/directory trees + * The number of additional times we will attempt to delete files/directory trees * before giving up and throwing an exception.
- * Specifying a value less than 1 is invalid and will be treated as if - * a value of 1 (i.e. one attempt, no retries) was specified. + * Specifying a value less than 0 is invalid and will be treated as if + * a value of 0 (i.e. one attempt, no retries) was specified. *

* e.g. if some of the child directories are big, it might take long enough * to delete that it allows others to create new files in the directory we @@ -1593,12 +1595,12 @@ public static long daysElapsedSince(@Nonnull Date date){ * give up, thus improving build reliability. */ @Restricted(value = NoExternalUse.class) - static int DELETION_MAX = Math.max(1, SystemProperties.getInteger(Util.class.getName() + ".maxFileDeletionRetries", 3)); + static int DELETION_RETRIES = Math.max(0, SystemProperties.getInteger(Util.class.getName() + ".maxFileDeletionRetries", 2)); /** * The time (in milliseconds) that we will wait between attempts to * delete files when retrying.
- * This has no effect unless {@link #DELETION_MAX} is non-zero. + * This has no effect unless {@link #DELETION_RETRIES} is non-zero. *

* If zero, we will not delay between attempts.
* If negative, we will wait an (linearly) increasing multiple of this value @@ -1611,7 +1613,7 @@ public static long daysElapsedSince(@Nonnull Date date){ * If this flag is set to true then we will request a garbage collection * after a deletion failure before we next retry the delete.
* It defaults to {@code false} and is ignored unless - * {@link #DELETION_MAX} is greater than 1. + * {@link #DELETION_RETRIES} is non zero. *

* Setting this flag to true may resolve some problems on Windows, * and also for directory trees residing on an NFS share, but it can @@ -1632,7 +1634,7 @@ public static long daysElapsedSince(@Nonnull Date date){ static boolean GC_AFTER_FAILED_DELETE = SystemProperties.getBoolean(Util.class.getName() + ".performGCOnFailedDelete"); private static PathRemover newPathRemover(@Nonnull PathRemover.PathChecker pathChecker) { - return PathRemover.newFilteredRobustRemover(pathChecker, DELETION_MAX - 1, GC_AFTER_FAILED_DELETE, WAIT_BETWEEN_DELETION_RETRIES); + return PathRemover.newFilteredRobustRemover(pathChecker, DELETION_RETRIES, GC_AFTER_FAILED_DELETE, WAIT_BETWEEN_DELETION_RETRIES); } /** diff --git a/core/src/main/java/hudson/cli/CLIAction.java b/core/src/main/java/hudson/cli/CLIAction.java index b4116f3b58..102dbbc00b 100644 --- a/core/src/main/java/hudson/cli/CLIAction.java +++ b/core/src/main/java/hudson/cli/CLIAction.java @@ -43,20 +43,26 @@ import org.kohsuke.stapler.StaplerResponse; import hudson.Extension; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; import java.io.InputStream; import java.io.OutputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.io.PrintStream; +import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; import java.util.ArrayList; import java.util.List; import java.util.Locale; -import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; import java.util.logging.Logger; import jenkins.util.FullDuplexHttpService; +import jenkins.websocket.WebSocketSession; +import jenkins.websocket.WebSockets; +import org.acegisecurity.Authentication; +import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponses; /** @@ -85,7 +91,7 @@ public String getUrlName() { } public void doCommand(StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException { - final Jenkins jenkins = Jenkins.getActiveInstance(); + final Jenkins jenkins = Jenkins.get(); jenkins.checkPermission(Jenkins.READ); // Strip trailing slash @@ -100,6 +106,74 @@ public void doCommand(StaplerRequest req, StaplerResponse rsp) throws ServletExc req.getView(this, "command.jelly").forward(req, rsp); } + /** for Jelly */ + public boolean isWebSocketSupported() { + return WebSockets.isSupported(); + } + + /** + * WebSocket endpoint. + */ + public HttpResponse doWs() { + if (!WebSockets.isSupported()) { + return HttpResponses.notFound(); + } + Authentication authentication = Jenkins.getAuthentication(); + return WebSockets.upgrade(new WebSocketSession() { + ServerSideImpl connection; + class OutputImpl implements PlainCLIProtocol.Output { + @Override + public void send(byte[] data) throws IOException { + sendBinary(ByteBuffer.wrap(data)); + } + @Override + public void close() throws IOException { + doClose(); + } + } + private void doClose() { + close(); + } + @Override + protected void opened() { + try { + connection = new ServerSideImpl(new OutputImpl(), authentication); + } catch (IOException x) { + error(x); + return; + } + new Thread(() -> { + try { + try { + connection.run(); + } finally { + connection.close(); + } + } catch (Exception x) { + error(x); + } + }, "CLI handler for " + authentication.getName()).start(); + } + @Override + protected void binary(byte[] payload, int offset, int len) { + try { + connection.handle(new DataInputStream(new ByteArrayInputStream(payload, offset, len))); + } catch (IOException x) { + error(x); + } + } + @Override + protected void error(Throwable cause) { + LOGGER.log(Level.WARNING, null, cause); + } + @Override + protected void closed(int statusCode, String reason) { + LOGGER.fine(() -> "closed: " + statusCode + ": " + reason); + connection.handleClose(); + } + }); + } + @Override public Object getTarget() { StaplerRequest req = Stapler.getCurrentRequest(); @@ -116,6 +190,105 @@ public Object getTarget() { } } + class ServerSideImpl extends PlainCLIProtocol.ServerSide { + private Thread runningThread; + private boolean ready; + private final List args = new ArrayList<>(); + private Locale locale = Locale.getDefault(); + private Charset encoding = Charset.defaultCharset(); + private final PipedInputStream stdin = new PipedInputStream(); + private final PipedOutputStream stdinMatch = new PipedOutputStream(); + private final Authentication authentication; + ServerSideImpl(PlainCLIProtocol.Output out, Authentication authentication) throws IOException { + super(out); + stdinMatch.connect(stdin); + this.authentication = authentication; + } + @Override + protected void onArg(String text) { + args.add(text); + } + @Override + protected void onLocale(String text) { + for (Locale _locale : Locale.getAvailableLocales()) { + if (_locale.toString().equals(text)) { + locale = _locale; + return; + } + } + LOGGER.log(Level.WARNING, "unknown client locale {0}", text); + } + @Override + protected void onEncoding(String text) { + try { + encoding = Charset.forName(text); + } catch (UnsupportedCharsetException x) { + LOGGER.log(Level.WARNING, "unknown client charset {0}", text); + } + } + @Override + protected void onStart() { + ready(); + } + @Override + protected void onStdin(byte[] chunk) throws IOException { + stdinMatch.write(chunk); + } + @Override + protected void onEndStdin() throws IOException { + stdinMatch.close(); + } + @Override + protected void handleClose() { + ready(); + if (runningThread != null) { + runningThread.interrupt(); + } + } + private synchronized void ready() { + ready = true; + notifyAll(); + } + void run() throws IOException, InterruptedException { + synchronized (this) { + while (!ready) { + wait(); + } + } + PrintStream stdout = new PrintStream(streamStdout(), false, encoding.name()); + PrintStream stderr = new PrintStream(streamStderr(), true, encoding.name()); + if (args.isEmpty()) { + stderr.println("Connection closed before arguments received"); + sendExit(2); + return; + } + String commandName = args.get(0); + CLICommand command = CLICommand.clone(commandName); + if (command == null) { + stderr.println("No such command " + commandName); + sendExit(2); + return; + } + command.setTransportAuth(authentication); + command.setClientCharset(encoding); + CLICommand orig = CLICommand.setCurrent(command); + try { + runningThread = Thread.currentThread(); + int exit = command.main(args.subList(1, args.size()), locale, stdin, stdout, stderr); + stdout.flush(); + sendExit(exit); + try { // seems to avoid ReadPendingException from Jetty + Thread.sleep(1000); + } catch (InterruptedException x) { + // expected; ignore + } + } finally { + CLICommand.setCurrent(orig); + runningThread = null; + } + } + } + /** * Serves {@link PlainCLIProtocol} response. */ @@ -130,103 +303,9 @@ protected FullDuplexHttpService createService(StaplerRequest req, UUID uuid) thr return new FullDuplexHttpService(uuid) { @Override protected void run(InputStream upload, OutputStream download) throws IOException, InterruptedException { - final AtomicReference runningThread = new AtomicReference<>(); - class ServerSideImpl extends PlainCLIProtocol.ServerSide { - boolean ready; - List args = new ArrayList<>(); - Locale locale = Locale.getDefault(); - Charset encoding = Charset.defaultCharset(); - final PipedInputStream stdin = new PipedInputStream(); - final PipedOutputStream stdinMatch = new PipedOutputStream(); - ServerSideImpl(InputStream is, OutputStream os) throws IOException { - super(is, os); - stdinMatch.connect(stdin); - } - @Override - protected void onArg(String text) { - args.add(text); - } - @Override - protected void onLocale(String text) { - for (Locale _locale : Locale.getAvailableLocales()) { - if (_locale.toString().equals(text)) { - locale = _locale; - return; - } - } - LOGGER.log(Level.WARNING, "unknown client locale {0}", text); - } - @Override - protected void onEncoding(String text) { - try { - encoding = Charset.forName(text); - } catch (UnsupportedCharsetException x) { - LOGGER.log(Level.WARNING, "unknown client charset {0}", text); - } - } - @Override - protected void onStart() { - ready(); - } - @Override - protected void onStdin(byte[] chunk) throws IOException { - stdinMatch.write(chunk); - } - @Override - protected void onEndStdin() throws IOException { - stdinMatch.close(); - } - @Override - protected void handleClose() { - ready(); - Thread t = runningThread.get(); - if (t != null) { - t.interrupt(); - } - } - private synchronized void ready() { - ready = true; - notifyAll(); - } - } - try (ServerSideImpl connection = new ServerSideImpl(upload, download)) { - connection.begin(); - synchronized (connection) { - while (!connection.ready) { - connection.wait(); - } - } - PrintStream stdout = new PrintStream(connection.streamStdout(), false, connection.encoding.name()); - PrintStream stderr = new PrintStream(connection.streamStderr(), true, connection.encoding.name()); - if (connection.args.isEmpty()) { - stderr.println("Connection closed before arguments received"); - connection.sendExit(2); - return; - } - String commandName = connection.args.get(0); - CLICommand command = CLICommand.clone(commandName); - if (command == null) { - stderr.println("No such command " + commandName); - connection.sendExit(2); - return; - } - command.setTransportAuth(Jenkins.getAuthentication()); - command.setClientCharset(connection.encoding); - CLICommand orig = CLICommand.setCurrent(command); - try { - runningThread.set(Thread.currentThread()); - int exit = command.main(connection.args.subList(1, connection.args.size()), connection.locale, connection.stdin, stdout, stderr); - stdout.flush(); - connection.sendExit(exit); - try { // seems to avoid ReadPendingException from Jetty - Thread.sleep(1000); - } catch (InterruptedException x) { - // expected; ignore - } - } finally { - CLICommand.setCurrent(orig); - runningThread.set(null); - } + try (ServerSideImpl connection = new ServerSideImpl(new PlainCLIProtocol.FramedOutput(download), Jenkins.getAuthentication())) { + new PlainCLIProtocol.FramedReader(connection, upload).start(); + connection.run(); } } }; diff --git a/core/src/main/java/hudson/cli/CLICommand.java b/core/src/main/java/hudson/cli/CLICommand.java index 15d496be1b..68747a6a8c 100644 --- a/core/src/main/java/hudson/cli/CLICommand.java +++ b/core/src/main/java/hudson/cli/CLICommand.java @@ -242,10 +242,8 @@ public int main(List args, Locale locale, InputStream stdin, PrintStream sc.setAuthentication(auth = getTransportAuthentication()); if (!(this instanceof HelpCommand || this instanceof WhoAmICommand)) - Jenkins.getActiveInstance().checkPermission(Jenkins.READ); + Jenkins.get().checkPermission(Jenkins.READ); p.parseArgument(args.toArray(new String[0])); - if (!(this instanceof HelpCommand || this instanceof WhoAmICommand)) - Jenkins.getActiveInstance().checkPermission(Jenkins.READ); LOGGER.log(Level.FINE, "Invoking CLI command {0}, with {1} arguments, as user {2}.", new Object[] {getName(), args.size(), auth.getName()}); int res = run(); @@ -502,7 +500,7 @@ protected CLICommand createClone() { */ protected void registerOptionHandlers() { try { - for (Class c : Index.list(OptionHandlerExtension.class, Jenkins.getActiveInstance().pluginManager.uberClassLoader,Class.class)) { + for (Class c : Index.list(OptionHandlerExtension.class, Jenkins.get().pluginManager.uberClassLoader,Class.class)) { Type t = Types.getBaseClass(c, OptionHandler.class); CmdLineParser.registerHandler(Types.erasure(Types.getTypeArgument(t,0)), c); } diff --git a/core/src/main/java/hudson/cli/CancelQuietDownCommand.java b/core/src/main/java/hudson/cli/CancelQuietDownCommand.java index 24b2ec3018..a521de769b 100644 --- a/core/src/main/java/hudson/cli/CancelQuietDownCommand.java +++ b/core/src/main/java/hudson/cli/CancelQuietDownCommand.java @@ -47,7 +47,7 @@ public String getShortDescription() { @Override protected int run() throws Exception { - Jenkins.getActiveInstance().doCancelQuietDown(); + Jenkins.get().doCancelQuietDown(); return 0; } } diff --git a/core/src/main/java/hudson/cli/ClearQueueCommand.java b/core/src/main/java/hudson/cli/ClearQueueCommand.java index 52cd7c4063..1a1b875bc5 100644 --- a/core/src/main/java/hudson/cli/ClearQueueCommand.java +++ b/core/src/main/java/hudson/cli/ClearQueueCommand.java @@ -47,7 +47,7 @@ public String getShortDescription() { @Override protected int run() throws Exception { - Jenkins.getActiveInstance().getQueue().clear(); + Jenkins.get().getQueue().clear(); return 0; } diff --git a/cli/src/main/java/hudson/cli/Connection.java b/core/src/main/java/hudson/cli/Connection.java similarity index 100% rename from cli/src/main/java/hudson/cli/Connection.java rename to core/src/main/java/hudson/cli/Connection.java diff --git a/core/src/main/java/hudson/cli/CopyJobCommand.java b/core/src/main/java/hudson/cli/CopyJobCommand.java index 3eb8049c1f..fd6b658f8f 100644 --- a/core/src/main/java/hudson/cli/CopyJobCommand.java +++ b/core/src/main/java/hudson/cli/CopyJobCommand.java @@ -50,7 +50,7 @@ public String getShortDescription() { public String dst; protected int run() throws Exception { - Jenkins jenkins = Jenkins.getActiveInstance(); + Jenkins jenkins = Jenkins.get(); if (jenkins.getItemByFullName(dst)!=null) { throw new IllegalStateException("Job '"+dst+"' already exists"); diff --git a/core/src/main/java/hudson/cli/CreateJobCommand.java b/core/src/main/java/hudson/cli/CreateJobCommand.java index 0f0108c361..10ea5798fd 100644 --- a/core/src/main/java/hudson/cli/CreateJobCommand.java +++ b/core/src/main/java/hudson/cli/CreateJobCommand.java @@ -45,7 +45,7 @@ public String getShortDescription() { public String name; protected int run() throws Exception { - Jenkins h = Jenkins.getActiveInstance(); + Jenkins h = Jenkins.get(); if (h.getItemByFullName(name)!=null) { throw new IllegalStateException("Job '"+name+"' already exists"); diff --git a/core/src/main/java/hudson/cli/CreateNodeCommand.java b/core/src/main/java/hudson/cli/CreateNodeCommand.java index edab3f7e71..a1a826618e 100644 --- a/core/src/main/java/hudson/cli/CreateNodeCommand.java +++ b/core/src/main/java/hudson/cli/CreateNodeCommand.java @@ -52,7 +52,7 @@ public String getShortDescription() { @Override protected int run() throws Exception { - final Jenkins jenkins = Jenkins.getActiveInstance(); + final Jenkins jenkins = Jenkins.get(); jenkins.checkPermission(Computer.CREATE); final Node newNode = (Node) Jenkins.XSTREAM2.fromXML(stdin); diff --git a/core/src/main/java/hudson/cli/CreateViewCommand.java b/core/src/main/java/hudson/cli/CreateViewCommand.java index d22a0b424f..dea72441fa 100644 --- a/core/src/main/java/hudson/cli/CreateViewCommand.java +++ b/core/src/main/java/hudson/cli/CreateViewCommand.java @@ -49,7 +49,7 @@ public String getShortDescription() { @Override protected int run() throws Exception { - final Jenkins jenkins = Jenkins.getActiveInstance(); + final Jenkins jenkins = Jenkins.get(); jenkins.checkPermission(View.CREATE); View newView; diff --git a/core/src/main/java/hudson/cli/DeleteJobCommand.java b/core/src/main/java/hudson/cli/DeleteJobCommand.java index 375e158a87..d829340892 100644 --- a/core/src/main/java/hudson/cli/DeleteJobCommand.java +++ b/core/src/main/java/hudson/cli/DeleteJobCommand.java @@ -54,7 +54,7 @@ public String getShortDescription() { protected int run() throws Exception { boolean errorOccurred = false; - final Jenkins jenkins = Jenkins.getActiveInstance(); + final Jenkins jenkins = Jenkins.get(); final HashSet hs = new HashSet<>(jobs); diff --git a/core/src/main/java/hudson/cli/DeleteNodeCommand.java b/core/src/main/java/hudson/cli/DeleteNodeCommand.java index 76e5c29530..57aad43507 100644 --- a/core/src/main/java/hudson/cli/DeleteNodeCommand.java +++ b/core/src/main/java/hudson/cli/DeleteNodeCommand.java @@ -54,7 +54,7 @@ public String getShortDescription() { protected int run() throws Exception { boolean errorOccurred = false; - final Jenkins jenkins = Jenkins.getActiveInstance(); + final Jenkins jenkins = Jenkins.get(); final HashSet hs = new HashSet<>(nodes); diff --git a/core/src/main/java/hudson/cli/DisablePluginCommand.java b/core/src/main/java/hudson/cli/DisablePluginCommand.java index 101576e904..58dbbb3291 100644 --- a/core/src/main/java/hudson/cli/DisablePluginCommand.java +++ b/core/src/main/java/hudson/cli/DisablePluginCommand.java @@ -164,7 +164,7 @@ private void restartIfNecessary(List results) /** * Restart if this particular result of the disablement of a plugin and its dependent plugins (depending on the - * strategy used) has a plugin disablexd. + * strategy used) has a plugin disabled. * @param oneResult the result of a plugin (and its dependents). * @return true if it end up in restarting jenkins. */ @@ -220,15 +220,15 @@ private int getResultCode(PluginWrapper.PluginDisableResult result) { break; case NO_SUCH_PLUGIN: returnCode = RETURN_CODE_NO_SUCH_PLUGIN; - } - - if (returnCode == 0) { - for (PluginWrapper.PluginDisableResult oneDependentResult : result.getDependentsDisableStatus()) { - returnCode = getResultCode(oneDependentResult); - if (returnCode != 0) { - break; + break; + default: + for (PluginWrapper.PluginDisableResult oneDependentResult : result.getDependentsDisableStatus()) { + returnCode = getResultCode(oneDependentResult); + if (returnCode != 0) { + break; + } } - } + break; } return returnCode; diff --git a/core/src/main/java/hudson/cli/DisconnectNodeCommand.java b/core/src/main/java/hudson/cli/DisconnectNodeCommand.java index 51a02f1afb..6135c932bc 100644 --- a/core/src/main/java/hudson/cli/DisconnectNodeCommand.java +++ b/core/src/main/java/hudson/cli/DisconnectNodeCommand.java @@ -59,7 +59,7 @@ public String getShortDescription() { @Override protected int run() throws Exception { boolean errorOccurred = false; - final Jenkins jenkins = Jenkins.getActiveInstance(); + final Jenkins jenkins = Jenkins.get(); final HashSet hs = new HashSet<>(nodes); diff --git a/core/src/main/java/hudson/cli/GroovyCommand.java b/core/src/main/java/hudson/cli/GroovyCommand.java index f87ba80abc..9a802bc5a1 100644 --- a/core/src/main/java/hudson/cli/GroovyCommand.java +++ b/core/src/main/java/hudson/cli/GroovyCommand.java @@ -59,7 +59,7 @@ public String getShortDescription() { protected int run() throws Exception { // this allows the caller to manipulate the JVM state, so require the execute script privilege. - Jenkins.getActiveInstance().checkPermission(Jenkins.RUN_SCRIPTS); + Jenkins.get().checkPermission(Jenkins.RUN_SCRIPTS); Binding binding = new Binding(); binding.setProperty("out",new PrintWriter(stdout,true)); @@ -67,7 +67,7 @@ protected int run() throws Exception { binding.setProperty("stdout",stdout); binding.setProperty("stderr",stderr); - GroovyShell groovy = new GroovyShell(Jenkins.getActiveInstance().getPluginManager().uberClassLoader, binding); + GroovyShell groovy = new GroovyShell(Jenkins.get().getPluginManager().uberClassLoader, binding); groovy.run(loadScript(),"RemoteClass",remaining.toArray(new String[0])); return 0; } diff --git a/core/src/main/java/hudson/cli/GroovyshCommand.java b/core/src/main/java/hudson/cli/GroovyshCommand.java index 1048bc53d7..dd2584ebf0 100644 --- a/core/src/main/java/hudson/cli/GroovyshCommand.java +++ b/core/src/main/java/hudson/cli/GroovyshCommand.java @@ -60,7 +60,7 @@ public String getShortDescription() { @Override protected int run() { // this allows the caller to manipulate the JVM state, so require the admin privilege. - Jenkins.getActiveInstance().checkPermission(Jenkins.RUN_SCRIPTS); + Jenkins.get().checkPermission(Jenkins.RUN_SCRIPTS); // this being remote means no jline capability is available System.setProperty("jline.terminal", UnsupportedTerminal.class.getName()); @@ -85,12 +85,12 @@ protected Groovysh createShell(InputStream stdin, PrintStream stdout, Binding binding = new Binding(); // redirect "println" to the CLI binding.setProperty("out", new PrintWriter(stdout,true)); - binding.setProperty("hudson", Jenkins.getActiveInstance()); // backward compatibility - binding.setProperty("jenkins", Jenkins.getActiveInstance()); + binding.setProperty("hudson", Jenkins.get()); // backward compatibility + binding.setProperty("jenkins", Jenkins.get()); IO io = new IO(new BufferedInputStream(stdin),stdout,stderr); - final ClassLoader cl = Jenkins.getActiveInstance().pluginManager.uberClassLoader; + final ClassLoader cl = Jenkins.get().pluginManager.uberClassLoader; Closure registrar = new Closure(null, null) { private static final long serialVersionUID = 1L; diff --git a/core/src/main/java/hudson/cli/HelpCommand.java b/core/src/main/java/hudson/cli/HelpCommand.java index 071bce6a7f..a4623f5b8f 100644 --- a/core/src/main/java/hudson/cli/HelpCommand.java +++ b/core/src/main/java/hudson/cli/HelpCommand.java @@ -51,7 +51,7 @@ public String getShortDescription() { @Override protected int run() throws Exception { - if (!Jenkins.getActiveInstance().hasPermission(Jenkins.READ)) { + if (!Jenkins.get().hasPermission(Jenkins.READ)) { throw new AccessDeniedException("You must authenticate to access this Jenkins.\n" + CLI.usage()); } diff --git a/core/src/main/java/hudson/cli/ListJobsCommand.java b/core/src/main/java/hudson/cli/ListJobsCommand.java index 8dae08e674..dd7a1daf8f 100644 --- a/core/src/main/java/hudson/cli/ListJobsCommand.java +++ b/core/src/main/java/hudson/cli/ListJobsCommand.java @@ -49,7 +49,7 @@ public String getShortDescription() { public String name; protected int run() throws Exception { - Jenkins h = Jenkins.getActiveInstance(); + Jenkins h = Jenkins.get(); final Collection jobs; // If name is given retrieve jobs for the given view. diff --git a/core/src/main/java/hudson/cli/QuietDownCommand.java b/core/src/main/java/hudson/cli/QuietDownCommand.java index 4d84055c8d..740ee10864 100644 --- a/core/src/main/java/hudson/cli/QuietDownCommand.java +++ b/core/src/main/java/hudson/cli/QuietDownCommand.java @@ -54,7 +54,7 @@ public String getShortDescription() { @Override protected int run() throws Exception { - Jenkins.getActiveInstance().doQuietDown(block, timeout); + Jenkins.get().doQuietDown(block, timeout); return 0; } } diff --git a/core/src/main/java/hudson/cli/ReloadJobCommand.java b/core/src/main/java/hudson/cli/ReloadJobCommand.java index 68a2bfda12..e8c51f9583 100644 --- a/core/src/main/java/hudson/cli/ReloadJobCommand.java +++ b/core/src/main/java/hudson/cli/ReloadJobCommand.java @@ -60,7 +60,7 @@ public String getShortDescription() { protected int run() throws Exception { boolean errorOccurred = false; - final Jenkins jenkins = Jenkins.getActiveInstance(); + final Jenkins jenkins = Jenkins.get(); final HashSet hs = new HashSet<>(jobs); diff --git a/core/src/main/java/hudson/cli/handlers/ViewOptionHandler.java b/core/src/main/java/hudson/cli/handlers/ViewOptionHandler.java index 6107855812..2c901b06b4 100644 --- a/core/src/main/java/hudson/cli/handlers/ViewOptionHandler.java +++ b/core/src/main/java/hudson/cli/handlers/ViewOptionHandler.java @@ -94,7 +94,7 @@ public int parseArguments(Parameters params) throws CmdLineException { @CheckForNull public View getView(final String name) { - ViewGroup group = Jenkins.getActiveInstance(); + ViewGroup group = Jenkins.get(); View view = null; final StringTokenizer tok = new StringTokenizer(name, "/"); diff --git a/core/src/main/java/hudson/console/ConsoleNote.java b/core/src/main/java/hudson/console/ConsoleNote.java index 6625812e0e..4d2e2c2530 100644 --- a/core/src/main/java/hudson/console/ConsoleNote.java +++ b/core/src/main/java/hudson/console/ConsoleNote.java @@ -270,7 +270,8 @@ public static ConsoleNote readFrom(DataInputStream in) throws IOException, Class } } - Jenkins jenkins = Jenkins.get(); + Jenkins jenkins = Jenkins.getInstanceOrNull(); + try (ObjectInputStream ois = new ObjectInputStreamEx(new GZIPInputStream(new ByteArrayInputStream(buf)), jenkins != null ? jenkins.pluginManager.uberClassLoader : ConsoleNote.class.getClassLoader(), ClassFilter.DEFAULT)) { diff --git a/core/src/main/java/hudson/init/InitStrategy.java b/core/src/main/java/hudson/init/InitStrategy.java index c6c5795e54..d4ba7d85b9 100644 --- a/core/src/main/java/hudson/init/InitStrategy.java +++ b/core/src/main/java/hudson/init/InitStrategy.java @@ -72,7 +72,7 @@ private void listPluginFiles(PluginManager pm, String extension, Collection r) { diff --git a/core/src/main/java/hudson/logging/LogRecorder.java b/core/src/main/java/hudson/logging/LogRecorder.java index 61bb1bb187..c6ec3e1b41 100644 --- a/core/src/main/java/hudson/logging/LogRecorder.java +++ b/core/src/main/java/hudson/logging/LogRecorder.java @@ -50,6 +50,7 @@ import javax.servlet.ServletException; import java.io.File; import java.io.IOException; +import java.io.Serializable; import java.text.Collator; import java.util.*; import java.util.logging.Level; @@ -252,7 +253,9 @@ public void disable() { } - private static class TargetComparator implements Comparator { + private static class TargetComparator implements Comparator, Serializable { + + private static final long serialVersionUID = 9285340752515798L; @Override public int compare(Target left, Target right) { diff --git a/core/src/main/java/hudson/markup/EscapedMarkupFormatter.java b/core/src/main/java/hudson/markup/EscapedMarkupFormatter.java index f97e5e94c4..ca356e9499 100644 --- a/core/src/main/java/hudson/markup/EscapedMarkupFormatter.java +++ b/core/src/main/java/hudson/markup/EscapedMarkupFormatter.java @@ -47,7 +47,9 @@ public EscapedMarkupFormatter() { @Override public void translate(String markup, Writer output) throws IOException { - output.write(Util.escape(markup)); + if (markup != null) { + output.write(Util.escape(markup)); + } } @Extension @Symbol("plainText") diff --git a/core/src/main/java/hudson/model/AbstractBuild.java b/core/src/main/java/hudson/model/AbstractBuild.java index 28c2b926b9..6af442245d 100644 --- a/core/src/main/java/hudson/model/AbstractBuild.java +++ b/core/src/main/java/hudson/model/AbstractBuild.java @@ -863,8 +863,10 @@ private ChangeLogSet calcChangeSet() { public EnvVars getEnvironment(TaskListener log) throws IOException, InterruptedException { EnvVars env = super.getEnvironment(log); FilePath ws = getWorkspace(); - if (ws!=null) // if this is done very early on in the build, workspace may not be decided yet. see HUDSON-3997 + if (ws != null) { // if this is done very early on in the build, workspace may not be decided yet. see HUDSON-3997 env.put("WORKSPACE", ws.getRemote()); + env.put("WORKSPACE_TMP", WorkspaceList.tempDir(ws).getRemote()); // JENKINS-60634 + } project.getScm().buildEnvVars(this,env); diff --git a/core/src/main/java/hudson/model/AbstractItem.java b/core/src/main/java/hudson/model/AbstractItem.java index e1968ecfc1..d00fb66986 100644 --- a/core/src/main/java/hudson/model/AbstractItem.java +++ b/core/src/main/java/hudson/model/AbstractItem.java @@ -730,18 +730,16 @@ public void delete() throws IOException, InterruptedException { if (subtask != null) { Item item = Tasks.getItemOf(subtask); - if (item != null) { - while (item != null) { - if (item == this) { - buildsInProgress.put(e, e.getCurrentExecutable()); - e.interrupt(Result.ABORTED); - break; - } - if (item.getParent() instanceof Item) { - item = (Item) item.getParent(); - } else { - break; - } + while (item != null) { + if (item == this) { + buildsInProgress.put(e, e.getCurrentExecutable()); + e.interrupt(Result.ABORTED); + break; + } + if (item.getParent() instanceof Item) { + item = (Item) item.getParent(); + } else { + break; } } } diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java index 054f9f5717..52c327e350 100644 --- a/core/src/main/java/hudson/model/AbstractProject.java +++ b/core/src/main/java/hudson/model/AbstractProject.java @@ -510,6 +510,7 @@ public final FilePath getWorkspace() { * * @return An AbstractBuild for deprecated methods to use. */ + @CheckForNull private AbstractBuild getBuildForDeprecatedMethods() { Executor e = Executor.currentExecutor(); if(e!=null) { @@ -1071,7 +1072,7 @@ public CauseOfBlockage getCauseOfBlockage() { return new BlockedBecauseOfBuildInProgress(lastBuild); } else { // The build has been likely deleted after the isLogUpdated() call. - // Another cause may be an API implementation glitсh in the implementation for AbstractProject. + // Another cause may be an API implementation glitch in the implementation for AbstractProject. // Anyway, we should let the code go then. LOGGER.log(Level.FINE, "The last build has been deleted during the non-concurrent cause creation. The build is not blocked anymore"); } diff --git a/core/src/main/java/hudson/model/AsyncAperiodicWork.java b/core/src/main/java/hudson/model/AsyncAperiodicWork.java index 804f12b4a4..cd9f46b830 100644 --- a/core/src/main/java/hudson/model/AsyncAperiodicWork.java +++ b/core/src/main/java/hudson/model/AsyncAperiodicWork.java @@ -172,7 +172,7 @@ protected StreamTaskListener createListener() { } else { lastRotateMillis = System.currentTimeMillis(); // migrate old log files the first time we start-up - File oldFile = new File(Jenkins.getActiveInstance().getRootDir(), f.getName()); + File oldFile = new File(Jenkins.get().getRootDir(), f.getName()); if (oldFile.isFile()) { File newFile = new File(f.getParentFile(), f.getName() + ".1"); if (!newFile.isFile()) { diff --git a/core/src/main/java/hudson/model/AsyncPeriodicWork.java b/core/src/main/java/hudson/model/AsyncPeriodicWork.java index e4560d9d0c..80031750b7 100644 --- a/core/src/main/java/hudson/model/AsyncPeriodicWork.java +++ b/core/src/main/java/hudson/model/AsyncPeriodicWork.java @@ -157,7 +157,7 @@ protected StreamTaskListener createListener() { } else { lastRotateMillis = System.currentTimeMillis(); // migrate old log files the first time we start-up - File oldFile = new File(Jenkins.getActiveInstance().getRootDir(), f.getName()); + File oldFile = new File(Jenkins.get().getRootDir(), f.getName()); if (oldFile.isFile()) { File newFile = new File(f.getParentFile(), f.getName() + ".1"); if (!newFile.isFile()) { diff --git a/core/src/main/java/hudson/model/Cause.java b/core/src/main/java/hudson/model/Cause.java index b6f120e211..08f6655236 100644 --- a/core/src/main/java/hudson/model/Cause.java +++ b/core/src/main/java/hudson/model/Cause.java @@ -47,7 +47,7 @@ /** * Cause object base class. This class hierarchy is used to keep track of why * a given build was started. This object encapsulates the UI rendering of the cause, - * as well as providing more useful information in respective subypes. + * as well as providing more useful information in respective subtypes. * * The Cause object is connected to a build via the {@link CauseAction} object. * @@ -333,7 +333,6 @@ public static class ConverterImpl extends XStream2.PassthruConverter(); uc.upstreamCauses.add(uc.upstreamCause); uc.upstreamCause = null; OldDataMonitor.report(context, "1.288"); diff --git a/core/src/main/java/hudson/model/CheckPoint.java b/core/src/main/java/hudson/model/CheckPoint.java index 934fe7ddb5..ab4e176f6f 100644 --- a/core/src/main/java/hudson/model/CheckPoint.java +++ b/core/src/main/java/hudson/model/CheckPoint.java @@ -101,7 +101,7 @@ public String toString() { } /** - * Records that the execution of the build has reached to a check point, idenified + * Records that the execution of the build has reached to a check point, identified * by the given identifier. * *

diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index e7856b4c6c..bd0e246330 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -1069,13 +1069,13 @@ public final long getDemandStartMilliseconds() { } /** - * Returns the {@link Node} description for this computer + * Returns the {@link Node} description for this computer. Empty String if the {@link Node} is {@code null}. */ @Restricted(DoNotUse.class) @Exported public @Nonnull String getDescription() { Node node = getNode(); - return (node != null) ? node.getNodeDescription() : null; + return (node != null) ? node.getNodeDescription() : ""; } @@ -1088,6 +1088,7 @@ protected void removeExecutor(final Executor e) { public void run() { synchronized (Computer.this) { executors.remove(e); + oneOffExecutors.remove(e); addNewExecutorIfNecessary(); if (!isAlive()) { AbstractCIBase ciBase = Jenkins.getInstanceOrNull(); @@ -1475,7 +1476,7 @@ public void doConfigSubmit( StaplerRequest req, StaplerResponse rsp ) throws IOE } if ((!proposedName.equals(nodeName)) - && Jenkins.getActiveInstance().getNode(proposedName) != null) { + && Jenkins.get().getNode(proposedName) != null) { throw new FormException(Messages.ComputerSet_SlaveAlreadyExists(proposedName), "name"); } diff --git a/core/src/main/java/hudson/model/Descriptor.java b/core/src/main/java/hudson/model/Descriptor.java index be6024e6e5..463cdee366 100644 --- a/core/src/main/java/hudson/model/Descriptor.java +++ b/core/src/main/java/hudson/model/Descriptor.java @@ -59,6 +59,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; @@ -644,7 +645,7 @@ 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 { - final Descriptor descriptor = Jenkins.getActiveInstance().getDescriptor(actualType); + final Descriptor descriptor = Jenkins.get().getDescriptor(actualType); if (descriptor != null) { return descriptor.newInstance(Stapler.getCurrentRequest(), json); } else { @@ -670,7 +671,7 @@ public Object onConvert(Type targetType, Class targetTypeErasure, Object jsonSou 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); + return Jenkins.get().getDescriptor(targetTypeErasure).newInstance(Stapler.getCurrentRequest(), json); } catch (Exception x) { LOGGER.log(Level.WARNING, "falling back to default instantiation " + targetTypeErasure.getName() + " " + json, x); } @@ -690,7 +691,7 @@ public Object onConvert(Type targetType, Class targetTypeErasure, Object jsonSou private T verifyNewInstance(T t) { if (t!=null && t.getDescriptor()!=this) { // TODO: should this be a fatal error? - LOGGER.warning("Father of "+ t+" and its getDescriptor() points to two different instances. Probably malplaced @Extension. See http://hudson.361315.n4.nabble.com/Help-Hint-needed-Post-build-action-doesn-t-stay-activated-td2308833.html"); + LOGGER.warning("Father of "+ t+" and its getDescriptor() points to two different instances. Probably misplaced @Extension. See http://hudson.361315.n4.nabble.com/Help-Hint-needed-Post-build-action-doesn-t-stay-activated-td2308833.html"); } return t; } @@ -943,7 +944,7 @@ public void doHelp(StaplerRequest req, StaplerResponse rsp) throws IOException, // TODO: generalize macro expansion and perhaps even support JEXL rsp.setContentType("text/html;charset=UTF-8"); try (InputStream in = url.openStream()) { - String literal = IOUtils.toString(in,"UTF-8"); + String literal = IOUtils.toString(in, StandardCharsets.UTF_8); rsp.getWriter().println(Util.replaceMacro(literal, Collections.singletonMap("rootURL",req.getContextPath()))); } return; diff --git a/core/src/main/java/hudson/model/DirectoryBrowserSupport.java b/core/src/main/java/hudson/model/DirectoryBrowserSupport.java index 05db1a2425..fb45e0a5a6 100644 --- a/core/src/main/java/hudson/model/DirectoryBrowserSupport.java +++ b/core/src/main/java/hudson/model/DirectoryBrowserSupport.java @@ -327,11 +327,8 @@ private void serveFile(StaplerRequest req, StaplerResponse rsp, VirtualFile root boolean view = rest.equals("*view*"); if(rest.equals("*fingerprint*")) { - InputStream fingerprintInput = baseFile.open(); - try { + try (InputStream fingerprintInput = baseFile.open()) { rsp.forward(Jenkins.get().getFingerprint(Util.getDigestOf(fingerprintInput)), "/", req); - } finally { - fingerprintInput.close(); } return; } diff --git a/core/src/main/java/hudson/model/DownloadService.java b/core/src/main/java/hudson/model/DownloadService.java index f4cd34d416..dfdd4e5c7a 100644 --- a/core/src/main/java/hudson/model/DownloadService.java +++ b/core/src/main/java/hudson/model/DownloadService.java @@ -43,6 +43,7 @@ import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; @@ -111,7 +112,7 @@ public static String loadJSON(URL src) throws IOException { ((HttpURLConnection) con).setInstanceFollowRedirects(true); } try (InputStream is = con.getInputStream()) { - String jsonp = IOUtils.toString(is, "UTF-8"); + String jsonp = IOUtils.toString(is, StandardCharsets.UTF_8); int start = jsonp.indexOf('{'); int end = jsonp.lastIndexOf('}'); if (start >= 0 && end > start) { @@ -136,7 +137,7 @@ public static String loadJSONHTML(URL src) throws IOException { ((HttpURLConnection) con).setInstanceFollowRedirects(true); } try (InputStream is = con.getInputStream()) { - String jsonp = IOUtils.toString(is, "UTF-8"); + String jsonp = IOUtils.toString(is, StandardCharsets.UTF_8); String preamble = "window.parent.postMessage(JSON.stringify("; int start = jsonp.indexOf(preamble); int end = jsonp.lastIndexOf("),'*');"); @@ -256,7 +257,7 @@ public String getUrl() { */ public List getUrls() { List updateSites = new ArrayList<>(); - for (UpdateSite site : Jenkins.getActiveInstance().getUpdateCenter().getSiteList()) { + for (UpdateSite site : Jenkins.get().getUpdateCenter().getSiteList()) { String siteUrl = site.getUrl(); int baseUrlEnd = siteUrl.indexOf("update-center.json"); if (baseUrlEnd != -1) { @@ -326,7 +327,7 @@ private FormValidation load(String json, long dataTimestamp) throws IOException public FormValidation updateNow() throws IOException { List jsonList = new ArrayList<>(); boolean toolInstallerMetadataExists = false; - for (UpdateSite updatesite : Jenkins.getActiveInstance().getUpdateCenter().getSiteList()) { + for (UpdateSite updatesite : Jenkins.get().getUpdateCenter().getSiteList()) { String site = updatesite.getMetadataUrlForDownloadable(url); if (site == null) { return FormValidation.warning("The update site " + updatesite.getId() + " does not look like an update center"); diff --git a/core/src/main/java/hudson/model/Executor.java b/core/src/main/java/hudson/model/Executor.java index 1dc112c531..e69fa2100b 100644 --- a/core/src/main/java/hudson/model/Executor.java +++ b/core/src/main/java/hudson/model/Executor.java @@ -39,6 +39,7 @@ import org.acegisecurity.Authentication; import org.kohsuke.stapler.HttpResponse; import org.kohsuke.stapler.HttpResponses; +import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.export.Exported; @@ -828,7 +829,7 @@ public void start() { /** * @deprecated as of 1.489 - * Use {@link #doStop()}. + * Use {@link #doStop()} or {@link #doStopBuild(String)}. */ @RequirePOST @Deprecated @@ -837,17 +838,38 @@ public void doStop( StaplerRequest req, StaplerResponse rsp ) throws IOException } /** - * Stops the current build. + * Stops the current build.
+ * You can use {@link #doStopBuild(String)} instead to ensure what will be + * interrupted is actually what you want to interrupt. * * @since 1.489 + * @see #doStopBuild(String) */ @RequirePOST public HttpResponse doStop() { + return doStopBuild(null); + } + + /** + * Stops the current build, if matching the specified external id + * (or no id is specified, or the current {@link Executable} is not a {@link Run}). + * + * @param runExtId + * if not null, the externalizable id ({@link Run#getExternalizableId()}) + * of the build the user expects to interrupt + * @since TODO + */ + @RequirePOST + @Restricted(NoExternalUse.class) + public HttpResponse doStopBuild(@CheckForNull @QueryParameter(fixEmpty = true) String runExtId) { lock.writeLock().lock(); // need write lock as interrupt will change the field try { if (executable != null) { - getParentOf(executable).getOwnerTask().checkAbortPermission(); - interrupt(); + if (runExtId == null || runExtId.isEmpty() || ! (executable instanceof Run) + || (executable instanceof Run && runExtId.equals(((Run) executable).getExternalizableId()))) { + getParentOf(executable).getOwnerTask().checkAbortPermission(); + interrupt(); + } } } finally { lock.writeLock().unlock(); diff --git a/core/src/main/java/hudson/model/Fingerprint.java b/core/src/main/java/hudson/model/Fingerprint.java index b5644b0d5b..e628c6bd54 100644 --- a/core/src/main/java/hudson/model/Fingerprint.java +++ b/core/src/main/java/hudson/model/Fingerprint.java @@ -1203,9 +1203,7 @@ public int size() { public int compare(FingerprintFacet o1, FingerprintFacet o2) { long a = o1.getTimestamp(); long b = o2.getTimestamp(); - if (a < b) return -1; - if (a == b) return 0; - return 1; + return Long.compare(a, b); } }); return r; diff --git a/core/src/main/java/hudson/model/HealthReport.java b/core/src/main/java/hudson/model/HealthReport.java index c43cd0a132..461264ed6a 100644 --- a/core/src/main/java/hudson/model/HealthReport.java +++ b/core/src/main/java/hudson/model/HealthReport.java @@ -326,7 +326,7 @@ public boolean isAggregateReport() { @Override public int compareTo(HealthReport o) { - return (this.score < o.score ? -1 : (this.score == o.score ? 0 : 1)); + return Integer.compare(this.score, o.score); } /** diff --git a/core/src/main/java/hudson/model/Items.java b/core/src/main/java/hudson/model/Items.java index f7329c7ee3..c6b06e322c 100644 --- a/core/src/main/java/hudson/model/Items.java +++ b/core/src/main/java/hudson/model/Items.java @@ -225,10 +225,7 @@ public static List fromNameList(ItemGroup context, @Nonnull final Jenkins jenkins = Jenkins.get(); List r = new ArrayList<>(); - if (jenkins == null) { - return r; - } - + StringTokenizer tokens = new StringTokenizer(list,","); while(tokens.hasMoreTokens()) { String fullName = tokens.nextToken().trim(); diff --git a/core/src/main/java/hudson/model/Job.java b/core/src/main/java/hudson/model/Job.java index ea90279274..f62ba2bd21 100644 --- a/core/src/main/java/hudson/model/Job.java +++ b/core/src/main/java/hudson/model/Job.java @@ -403,7 +403,7 @@ public EnvVars getCharacteristicEnvVars() { } /** - * Programatically updates the next build number. + * Programmatically updates the next build number. * *

* Much of Hudson assumes that the build number is unique and monotonic, so @@ -548,7 +548,7 @@ public T removeProperty(Class clazz) throws IOExcepti public Map> getProperties() { Map result = Descriptor.toMap((Iterable) properties); if (logRotator != null) { - result.put(Jenkins.getActiveInstance().getDescriptorByType(BuildDiscarderProperty.DescriptorImpl.class), new BuildDiscarderProperty(logRotator)); + result.put(Jenkins.get().getDescriptorByType(BuildDiscarderProperty.DescriptorImpl.class), new BuildDiscarderProperty(logRotator)); } return result; } diff --git a/core/src/main/java/hudson/model/Label.java b/core/src/main/java/hudson/model/Label.java index 4a112b68a4..ddf419604a 100644 --- a/core/src/main/java/hudson/model/Label.java +++ b/core/src/main/java/hudson/model/Label.java @@ -55,6 +55,7 @@ import org.kohsuke.stapler.export.Exported; import org.kohsuke.stapler.export.ExportedBean; +import java.io.Serializable; import java.io.StringReader; import java.util.ArrayList; import java.util.Collection; @@ -71,6 +72,7 @@ import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.HierarchicalStreamReader; +import javax.annotation.Nonnull; /** * Group of {@link Node}s. @@ -84,16 +86,19 @@ public abstract class Label extends Actionable implements Comparable

  • - * Define a transient field and store ViewGroupMixIn subype, then wire up getters and setters: + * Define a transient field and store ViewGroupMixIn subtype, then wire up getters and setters: *
      * private transient ViewGroupMixIn = new ViewGroupMixIn() {
      *     List<View> views() { return views; }
    @@ -163,12 +163,14 @@ public Collection getViews() {
         }
     
         /**
    -     * Returns the primary {@link View} that renders the top-page of Hudson.
    +     * Returns the primary {@link View} that renders the top-page of Hudson or
    +     * {@code null} if there is no primary one defined.
          */
         @Exported
    +    @CheckForNull
         public View getPrimaryView() {
             View v = getView(primaryView());
    -        if(v==null) // fallback
    +        if(v==null && !views().isEmpty()) // fallback
                 v = views().get(0);
             return v;
         }
    diff --git a/core/src/main/java/hudson/model/queue/AbstractQueueSorterImpl.java b/core/src/main/java/hudson/model/queue/AbstractQueueSorterImpl.java
    index e16dd9fb38..b0d6ce25ab 100644
    --- a/core/src/main/java/hudson/model/queue/AbstractQueueSorterImpl.java
    +++ b/core/src/main/java/hudson/model/queue/AbstractQueueSorterImpl.java
    @@ -1,6 +1,9 @@
     package hudson.model.queue;
     
    +import hudson.RestrictedSince;
     import hudson.model.Queue.BuildableItem;
    +import org.kohsuke.accmod.Restricted;
    +import org.kohsuke.accmod.restrictions.NoExternalUse;
     
     import java.util.Comparator;
     import java.util.List;
    @@ -28,24 +31,28 @@ public void sortBuildableItems(List buildables) {
          * The default implementation does FIFO.
          */
         public int compare(BuildableItem lhs, BuildableItem rhs) {
    -        return compare(lhs.buildableStartMilliseconds,rhs.buildableStartMilliseconds);
    +        return Long.compare(lhs.buildableStartMilliseconds,rhs.buildableStartMilliseconds);
         }
     
         /**
    +     * @deprecated Use Long.compare instead.
          * sign(a-b).
          */
    +    @Deprecated
    +    @Restricted(NoExternalUse.class)
    +    @RestrictedSince("TODO")
         protected static int compare(long a, long b) {
    -        if (a>b)    return 1;
    -        if (ab)    return 1;
    -        if (a iterator() {
    -        return Collections.emptySet().iterator();
    +        return Collections.emptyIterator();
         }
     }
    diff --git a/core/src/main/java/hudson/scm/SCMDescriptor.java b/core/src/main/java/hudson/scm/SCMDescriptor.java
    index 1479c2463f..f156aabeaf 100644
    --- a/core/src/main/java/hudson/scm/SCMDescriptor.java
    +++ b/core/src/main/java/hudson/scm/SCMDescriptor.java
    @@ -23,14 +23,20 @@
      */
     package hudson.scm;
     
    +import hudson.RestrictedSince;
     import hudson.Util;
     import hudson.model.AbstractProject;
     import hudson.model.Descriptor;
     import hudson.model.Job;
    +import org.kohsuke.accmod.Restricted;
    +import org.kohsuke.accmod.restrictions.NoExternalUse;
    +
     import java.lang.reflect.Field;
     import java.util.Collections;
     import java.util.List;
     import static java.util.logging.Level.WARNING;
    +
    +import java.util.concurrent.atomic.AtomicInteger;
     import java.util.logging.Logger;
     
     /**
    @@ -47,16 +53,8 @@ public abstract class SCMDescriptor extends Descriptor {
          * that type. Otherwise this SCM will not have any repository browser.
          */
         public transient final Class repositoryBrowser;
    -
    -    /**
    -     * Incremented every time a new {@link SCM} instance is created from this descriptor. 
    -     * This is used to invalidate cache of {@link SCM#getEffectiveBrowser}. Due to the lack of synchronization and serialization,
    -     * this field doesn't really count the # of instances created to date,
    -     * but it's good enough for the cache invalidation.
    -     * @deprecated No longer used by default.
    -     */
    -    @Deprecated
    -    public volatile int generation = 1;
    +    
    +    private transient final AtomicInteger atomicGeneration = new AtomicInteger(1);
     
         protected SCMDescriptor(Class clazz, Class repositoryBrowser) {
             super(clazz);
    @@ -74,6 +72,29 @@ protected SCMDescriptor(Class repositoryBrowser) {
             this.repositoryBrowser = repositoryBrowser;
         }
     
    +    /**
    +     * Incremented every time a new {@link SCM} instance is created from this descriptor.
    +     * This is used to invalidate cache of {@link SCM#getEffectiveBrowser}. Due to the lack of synchronization and serialization,
    +     * this field doesn't really count the # of instances created to date,
    +     * but it's good enough for the cache invalidation.
    +     * @deprecated No longer used by default.
    +     */
    +    @Deprecated
    +    @Restricted(NoExternalUse.class) @RestrictedSince("TODO")
    +    public int getGeneration() {
    +        return atomicGeneration.get();
    +    }
    +
    +    /**
    +     * Increments the generation value {@link SCMDescriptor#getGeneration} by one atomically.
    +     * @deprecated No longer used by default.
    +     */
    +    @Deprecated
    +    @Restricted(NoExternalUse.class) @RestrictedSince("TODO")
    +    public void incrementGeneration() {
    +        atomicGeneration.incrementAndGet();
    +    }
    +
         // work around HUDSON-4514. The repositoryBrowser field was marked as non-transient until 1.325,
         // causing the field to be persisted and overwritten on the load method.
         @SuppressWarnings({"ConstantConditions"})
    diff --git a/core/src/main/java/hudson/scm/SCMS.java b/core/src/main/java/hudson/scm/SCMS.java
    index 64a0c02cd8..975d41259b 100644
    --- a/core/src/main/java/hudson/scm/SCMS.java
    +++ b/core/src/main/java/hudson/scm/SCMS.java
    @@ -60,7 +60,7 @@ public static SCM parseSCM(StaplerRequest req, AbstractProject target) throws Fo
             if (scm == null) {
                 scm = new NullSCM(); // JENKINS-36043 workaround for AbstractMultiBranchProject.submit
             }
    -        scm.getDescriptor().generation++;
    +        scm.getDescriptor().incrementGeneration();
             return scm;
         }
     
    diff --git a/core/src/main/java/hudson/security/GlobalSecurityConfiguration.java b/core/src/main/java/hudson/security/GlobalSecurityConfiguration.java
    index 5ee8971fb9..f5ba2c38b5 100644
    --- a/core/src/main/java/hudson/security/GlobalSecurityConfiguration.java
    +++ b/core/src/main/java/hudson/security/GlobalSecurityConfiguration.java
    @@ -110,14 +110,10 @@ public boolean configure(StaplerRequest req, JSONObject json) throws hudson.mode
             // for compatibility reasons, the actual value is stored in Jenkins
             Jenkins j = Jenkins.get();
             j.checkPermission(Jenkins.ADMINISTER);
    -        if (json.has("useSecurity")) {
    -            JSONObject security = json.getJSONObject("useSecurity");
    -            j.setDisableRememberMe(security.optBoolean("disableRememberMe", false));
    -            j.setSecurityRealm(SecurityRealm.all().newInstanceFromRadioList(security, "realm"));
    -            j.setAuthorizationStrategy(AuthorizationStrategy.all().newInstanceFromRadioList(security, "authorization"));    
    -        } else {
    -            j.disableSecurity();
    -        }
    +
    +        j.setDisableRememberMe(json.optBoolean("disableRememberMe", false));
    +        j.setSecurityRealm(SecurityRealm.all().newInstanceFromRadioList(json, "realm"));
    +        j.setAuthorizationStrategy(AuthorizationStrategy.all().newInstanceFromRadioList(json, "authorization"));    
     
             if (json.has("markupFormatter")) {
                 j.setMarkupFormatter(req.bindJSON(MarkupFormatter.class, json.getJSONObject("markupFormatter")));
    diff --git a/core/src/main/java/hudson/security/SecurityRealm.java b/core/src/main/java/hudson/security/SecurityRealm.java
    index 5a4e30cc24..4ee1202b92 100644
    --- a/core/src/main/java/hudson/security/SecurityRealm.java
    +++ b/core/src/main/java/hudson/security/SecurityRealm.java
    @@ -70,6 +70,8 @@
     import java.util.Map;
     import java.util.logging.Level;
     import java.util.logging.Logger;
    +import net.sf.json.JSONObject;
    +import org.jenkinsci.Symbol;
     
     /**
      * Pluggable security realm that connects external user database to Hudson.
    @@ -582,15 +584,6 @@ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundEx
                 });
             }
     
    -        /**
    -         * This special instance is not configurable explicitly,
    -         * so it doesn't have a descriptor.
    -         */
    -        @Override
    -        public Descriptor getDescriptor() {
    -            return null;
    -        }
    -
             /**
              * There's no group.
              */
    @@ -613,6 +606,21 @@ public Filter createFilter(FilterConfig filterConfig) {
             private Object readResolve() {
                 return NO_AUTHENTICATION;
             }
    +        
    +        @Extension(ordinal=-100)
    +        @Symbol("none")
    +        public static class DescriptorImpl extends Descriptor {
    +
    +            @Override
    +            public String getDisplayName() {
    +                return Messages.NoneSecurityRealm_DisplayName();
    +            }
    +            
    +            @Override
    +            public SecurityRealm newInstance(StaplerRequest req, JSONObject formData) throws Descriptor.FormException {
    +                return NO_AUTHENTICATION;
    +            }    
    +        }
         }
     
         /**
    @@ -659,7 +667,7 @@ private static RememberMeServices createRememberMeService(UserDetailsService uds
                 rms.setUserDetailsService(uds);
                 /*
                     TokenBasedRememberMeServices needs to be used in conjunction with RememberMeAuthenticationProvider,
    -                and both needs to use the same key (this is a reflection of a poor design in AcgeiSecurity, if you ask me)
    +                and both needs to use the same key (this is a reflection of a poor design in AcegiSecurity, if you ask me)
                     and various security plugins have its own groovy script that configures them.
     
                     So if we change this, it creates a painful situation for those plugins by forcing them to choose
    diff --git a/core/src/main/java/hudson/slaves/ComputerLauncher.java b/core/src/main/java/hudson/slaves/ComputerLauncher.java
    index 8b088b70cf..7efb9f4a41 100644
    --- a/core/src/main/java/hudson/slaves/ComputerLauncher.java
    +++ b/core/src/main/java/hudson/slaves/ComputerLauncher.java
    @@ -54,7 +54,7 @@
     public abstract class ComputerLauncher extends AbstractDescribableImpl implements ExtensionPoint {
         /**
          * Returns true if this {@link ComputerLauncher} supports
    -     * programatic launch of the agent in the target {@link Computer}.
    +     * programmatic launch of the agent in the target {@link Computer}.
          */
         public boolean isLaunchSupported() {
             return true;
    diff --git a/core/src/main/java/hudson/slaves/JNLPLauncher.java b/core/src/main/java/hudson/slaves/JNLPLauncher.java
    index 86f38d6b94..db006ce8bd 100644
    --- a/core/src/main/java/hudson/slaves/JNLPLauncher.java
    +++ b/core/src/main/java/hudson/slaves/JNLPLauncher.java
    @@ -27,19 +27,21 @@
     import hudson.Util;
     import hudson.model.Computer;
     import hudson.model.Descriptor;
    -import hudson.model.DescriptorVisibilityFilter;
     import hudson.model.TaskListener;
    +import hudson.util.FormValidation;
     import javax.annotation.CheckForNull;
     import javax.annotation.Nonnull;
     
     import jenkins.model.Jenkins;
     import jenkins.slaves.RemotingWorkDirSettings;
     import jenkins.util.java.JavaUtils;
    +import jenkins.websocket.WebSockets;
     import org.jenkinsci.Symbol;
     import org.kohsuke.accmod.Restricted;
     import org.kohsuke.accmod.restrictions.NoExternalUse;
     import org.kohsuke.stapler.DataBoundConstructor;
     import org.kohsuke.stapler.DataBoundSetter;
    +import org.kohsuke.stapler.QueryParameter;
     
     /**
      * {@link ComputerLauncher} via inbound connections.
    @@ -72,6 +74,8 @@ public class JNLPLauncher extends ComputerLauncher {
         @Nonnull
         private RemotingWorkDirSettings workDirSettings = RemotingWorkDirSettings.getEnabledDefaults();
     
    +    private boolean webSocket;
    +
         /**
          * Constructor.
          * @param tunnel Tunnel settings
    @@ -143,6 +147,21 @@ public boolean isLaunchSupported() {
             return false;
         }
     
    +    /**
    +     * @since TODO
    +     */
    +    public boolean isWebSocket() {
    +        return webSocket;
    +    }
    +
    +    /**
    +     * @since TODO
    +     */
    +    @DataBoundSetter
    +    public void setWebSocket(boolean webSocket) {
    +        this.webSocket = webSocket;
    +    }
    +
         @Override
         public void launch(SlaveComputer computer, TaskListener listener) {
             // do nothing as we cannot self start
    @@ -196,25 +215,23 @@ public boolean isWorkDirSupported() {
                 // Causes JENKINS-45895 in the case of includes otherwise
                 return DescriptorImpl.class.equals(getClass());
             }
    -    }
    -
    -    /**
    -     * Hides the JNLP launcher when the JNLP agent port is not enabled.
    -     *
    -     * @since 2.16
    -     */
    -    @Extension
    -    public static class DescriptorVisibilityFilterImpl extends DescriptorVisibilityFilter {
     
    -        @Override
    -        public boolean filter(@CheckForNull Object context, @Nonnull Descriptor descriptor) {
    -            return descriptor.clazz != JNLPLauncher.class || Jenkins.get().getTcpSlaveAgentListener() != null;
    +        public FormValidation doCheckWebSocket(@QueryParameter boolean webSocket, @QueryParameter String tunnel) {
    +            if (webSocket) {
    +                if (!WebSockets.isSupported()) {
    +                    return FormValidation.error("WebSocket support is not enabled in this Jenkins installation");
    +                }
    +                if (Util.fixEmptyAndTrim(tunnel) != null) {
    +                    return FormValidation.error("Tunneling is not supported in WebSocket mode");
    +                }
    +            } else {
    +                if (Jenkins.get().getTcpSlaveAgentListener() == null) {
    +                    return FormValidation.error("Either WebSocket mode is selected, or the TCP port for inbound agents must be enabled");
    +                }
    +            }
    +            return FormValidation.ok();
             }
     
    -        @Override
    -        public boolean filterType(@Nonnull Class contextClass, @Nonnull Descriptor descriptor) {
    -            return descriptor.clazz != JNLPLauncher.class || Jenkins.get().getTcpSlaveAgentListener() != null;
    -        }
         }
     
         /**
    diff --git a/core/src/main/java/hudson/slaves/NodeProvisioner.java b/core/src/main/java/hudson/slaves/NodeProvisioner.java
    index f6063aa7f3..acabe894ba 100644
    --- a/core/src/main/java/hudson/slaves/NodeProvisioner.java
    +++ b/core/src/main/java/hudson/slaves/NodeProvisioner.java
    @@ -35,6 +35,7 @@
     import jenkins.util.Timer;
     import org.jenkinsci.Symbol;
     
    +import javax.annotation.CheckForNull;
     import javax.annotation.Nonnull;
     import javax.annotation.concurrent.GuardedBy;
     import java.awt.Color;
    @@ -126,6 +127,7 @@ public void spent() {
          * Null if this {@link NodeProvisioner} is working for the entire Hudson,
          * for jobs that are unassigned to any particular node.
          */
    +    @CheckForNull
         private final Label label;
     
         private final AtomicReference> pendingLaunches
    @@ -149,7 +151,7 @@ public void spent() {
         private final MultiStageTimeSeries plannedCapacitiesEMA =
                 new MultiStageTimeSeries(Messages._NodeProvisioner_EmptyString(),Color.WHITE,0,DECAY);
     
    -    public NodeProvisioner(Label label, LoadStatistics loadStatistics) {
    +    public NodeProvisioner(@CheckForNull Label label, LoadStatistics loadStatistics) {
             this.label = label;
             this.stat = loadStatistics;
         }
    @@ -395,6 +397,7 @@ public final class StrategyState {
             /**
              * The label under consideration.
              */
    +        @CheckForNull
             private final Label label;
             /**
              * The planned capacity for this {@link #label}.
    @@ -416,7 +419,7 @@ public final class StrategyState {
              * @param label the label.
              * @param plannedCapacitySnapshot the planned executor count.
              */
    -        private StrategyState(LoadStatistics.LoadStatisticsSnapshot snapshot, Label label, int plannedCapacitySnapshot) {
    +        private StrategyState(LoadStatistics.LoadStatisticsSnapshot snapshot, @CheckForNull Label label, int plannedCapacitySnapshot) {
                 this.snapshot = snapshot;
                 this.label = label;
                 this.plannedCapacitySnapshot = plannedCapacitySnapshot;
    @@ -425,6 +428,7 @@ private StrategyState(LoadStatistics.LoadStatisticsSnapshot snapshot, Label labe
             /**
              * The label under consideration.
              */
    +        @CheckForNull
             public Label getLabel() {
                 return label;
             }
    diff --git a/core/src/main/java/hudson/slaves/SlaveComputer.java b/core/src/main/java/hudson/slaves/SlaveComputer.java
    index 095ced543b..90be73db77 100644
    --- a/core/src/main/java/hudson/slaves/SlaveComputer.java
    +++ b/core/src/main/java/hudson/slaves/SlaveComputer.java
    @@ -58,7 +58,7 @@
     import jenkins.security.ChannelConfigurator;
     import jenkins.security.MasterToSlaveCallable;
     import jenkins.slaves.EncryptedSlaveAgentJnlpFile;
    -import jenkins.slaves.JnlpSlaveAgentProtocol;
    +import jenkins.slaves.JnlpAgentReceiver;
     import jenkins.slaves.RemotingVersionInfo;
     import jenkins.slaves.systemInfo.SlaveSystemInfo;
     import jenkins.util.SystemProperties;
    @@ -75,6 +75,7 @@
     import org.kohsuke.stapler.interceptor.RequirePOST;
     
     import javax.annotation.CheckForNull;
    +import javax.annotation.CheckReturnValue;
     import javax.annotation.Nonnull;
     import javax.annotation.OverridingMethodsMustInvokeSuper;
     import java.io.File;
    @@ -180,7 +181,7 @@ public boolean isAcceptingTasks() {
          * @since 1.498
          */
         public String getJnlpMac() {
    -        return JnlpSlaveAgentProtocol.SLAVE_SECRET.mac(getName());
    +        return JnlpAgentReceiver.SLAVE_SECRET.mac(getName());
         }
     
         /**
    @@ -453,18 +454,27 @@ public void setChannel(@Nonnull ChannelBuilder cb,
     
         /**
          * Shows {@link Channel#classLoadingCount}.
    +     * @return Requested value or {@code -1} if the agent is offline.
          * @since 1.495
          */
    +    @CheckReturnValue
         public int getClassLoadingCount() throws IOException, InterruptedException {
    +        if (channel == null) {
    +            return -1;
    +        }
             return channel.call(new LoadingCount(false));
         }
     
         /**
          * Shows {@link Channel#classLoadingPrefetchCacheCount}.
    -     * @return -1 in case that capability is not supported
    +     * @return Requested value or {@code -1} in case that capability is not supported or if the agent is offline.
          * @since 1.519
          */
    +    @CheckReturnValue
         public int getClassLoadingPrefetchCacheCount() throws IOException, InterruptedException {
    +        if (channel == null) {
    +            return -1;
    +        }
             if (!channel.remoteCapability.supportsPrefetch()) {
                 return -1;
             }
    @@ -473,25 +483,40 @@ public int getClassLoadingPrefetchCacheCount() throws IOException, InterruptedEx
     
         /**
          * Shows {@link Channel#resourceLoadingCount}.
    +     * @return Requested value or {@code -1} if the agent is offline.
          * @since 1.495
          */
    +    @CheckReturnValue
         public int getResourceLoadingCount() throws IOException, InterruptedException {
    +        if (channel == null) {
    +            return -1;
    +        }
             return channel.call(new LoadingCount(true));
         }
     
         /**
          * Shows {@link Channel#classLoadingTime}.
    +     * @return Requested value or {@code -1} if the agent is offline.
          * @since 1.495
          */
    +    @CheckReturnValue
         public long getClassLoadingTime() throws IOException, InterruptedException {
    +        if (channel == null) {
    +            return -1;
    +        }
             return channel.call(new LoadingTime(false));
         }
     
         /**
          * Shows {@link Channel#resourceLoadingTime}.
    +     * @return Requested value or {@code -1} if the agent is offline.
          * @since 1.495
          */
    +    @CheckReturnValue
         public long getResourceLoadingTime() throws IOException, InterruptedException {
    +        if (channel == null) {
    +            return -1;
    +        }
             return channel.call(new LoadingTime(true));
         }
     
    @@ -740,7 +765,7 @@ public void run() {
         @Override
         public void doLaunchSlaveAgent(StaplerRequest req, StaplerResponse rsp) throws IOException {
             checkPermission(CONNECT);
    -            
    +
             if(channel!=null) {
                 try {
                     req.getView(this, "already-launched.jelly").forward(req, rsp);
    @@ -871,27 +896,36 @@ protected ComputerLauncher grabLauncher(Node node) {
         /**
          * Get the agent version
          */
    +    @CheckReturnValue
         public String getSlaveVersion() throws IOException, InterruptedException {
    +        if (channel == null) {
    +            return "Unknown (agent is offline)";
    +        }
             return channel.call(new SlaveVersion());
         }
     
         /**
          * Get the OS description.
          */
    +    @CheckReturnValue
         public String getOSDescription() throws IOException, InterruptedException {
    +        if (channel == null) {
    +            return "Unknown (agent is offline)";
    +        }
             return channel.call(new DetectOS()) ? "Unix" : "Windows";
         }
     
         /**
          * Expose real full env vars map from agent for UI presentation
          */
    +    @CheckReturnValue
         public Map getEnvVarsFull() throws IOException, InterruptedException {
    -        if(getChannel() == null) {
    +        if (channel == null) {
                 Map env = new TreeMap<> ();
                 env.put("N/A","N/A");
                 return env;
             } else {
    -            return getChannel().call(new ListFullEnvironment());
    +            return channel.call(new ListFullEnvironment());
             }
         }
     
    diff --git a/core/src/main/java/hudson/tasks/LogRotator.java b/core/src/main/java/hudson/tasks/LogRotator.java
    index 4f056a7684..b73aea0912 100644
    --- a/core/src/main/java/hudson/tasks/LogRotator.java
    +++ b/core/src/main/java/hudson/tasks/LogRotator.java
    @@ -28,6 +28,7 @@
     import static java.util.logging.Level.FINER;
     
     import java.io.IOException;
    +import java.util.ArrayList;
     import java.util.Arrays;
     import java.util.Calendar;
     import java.util.Collection;
    @@ -48,6 +49,7 @@
     import hudson.model.Run;
     import jenkins.model.BuildDiscarder;
     import jenkins.model.BuildDiscarderDescriptor;
    +import jenkins.util.io.CompositeIOException;
     
     /**
      * Default implementation of {@link BuildDiscarder}.
    @@ -60,6 +62,8 @@
      */
     public class LogRotator extends BuildDiscarder {
         
    +    /** @deprecated Replaced by more generic {@link CompositeIOException}. */
    +    @Deprecated
         public class CollatedLogRotatorException extends IOException {
             private static final long serialVersionUID = 5944233808072651101L;
             
    @@ -139,7 +143,7 @@ public LogRotator(int daysToKeep, int numToKeep, int artifactDaysToKeep, int art
         @SuppressWarnings("rawtypes")
         public void perform(Job job) throws IOException, InterruptedException {
             //Exceptions thrown by the deletion submethods are collated and reported
    -        HashMultimap, Exception> exceptionMap = HashMultimap.create();
    +        HashMultimap, IOException> exceptionMap = HashMultimap.create();
             
             LOGGER.log(FINE, "Running the log rotation for {0} with numToKeep={1} daysToKeep={2} artifactNumToKeep={3} artifactDaysToKeep={4}", new Object[] {job, numToKeep, daysToKeep, artifactNumToKeep, artifactDaysToKeep});
             
    @@ -216,8 +220,7 @@ public void perform(Job job) throws IOException, InterruptedException {
                         "Failed to rotate logs for [%s]",
                         Joiner.on(", ").join(exceptionMap.keySet())
                 );
    -            LOGGER.severe(msg);
    -            throw new CollatedLogRotatorException(msg, exceptionMap.values());
    +            throw new CompositeIOException(msg, new ArrayList<>(exceptionMap.values()));
             }
         }
     
    diff --git a/core/src/main/java/hudson/tasks/Publisher.java b/core/src/main/java/hudson/tasks/Publisher.java
    index ed2393723d..68bb1846fc 100644
    --- a/core/src/main/java/hudson/tasks/Publisher.java
    +++ b/core/src/main/java/hudson/tasks/Publisher.java
    @@ -23,6 +23,7 @@
      */
     package hudson.tasks;
     
    +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
     import hudson.DescriptorExtensionList;
     import hudson.Extension;
     import hudson.ExtensionComponent;
    @@ -128,8 +129,11 @@ public Descriptor getDescriptor() {
          *
          * @see DescriptorExtensionList#createDescriptorList(hudson.model.Hudson, Class)
          */
    +    @SuppressFBWarnings(value = "SE_COMPARATOR_SHOULD_BE_SERIALIZABLE", justification = "Since the publisher is not Serializable, " +
    +            "no need for the Comparator")
         public static final class DescriptorExtensionListImpl extends DescriptorExtensionList>
                 implements Comparator>> {
    +
             public DescriptorExtensionListImpl(Jenkins hudson) {
                 super(hudson,Publisher.class);
             }
    diff --git a/core/src/main/java/hudson/triggers/SafeTimerTask.java b/core/src/main/java/hudson/triggers/SafeTimerTask.java
    index 47654b2550..73409e4ae4 100644
    --- a/core/src/main/java/hudson/triggers/SafeTimerTask.java
    +++ b/core/src/main/java/hudson/triggers/SafeTimerTask.java
    @@ -50,6 +50,27 @@
      */
     public abstract class SafeTimerTask extends TimerTask {
     
    +    /**
    +     * Lambda-friendly means of creating a task.
    +     * @since TODO
    +     */
    +    public static SafeTimerTask of(ExceptionRunnable r) {
    +        return new SafeTimerTask() {
    +            @Override
    +            protected void doRun() throws Exception {
    +                r.run();
    +            }
    +        };
    +    }
    +    /**
    +     * @see #of
    +     * @since TODO
    +     */
    +    @FunctionalInterface
    +    public interface ExceptionRunnable {
    +        void run() throws Exception;
    +    }
    +
         /**
          * System property to change the location where (tasks) logging should be sent.
          * 

    Beware: changing it while Jenkins is running gives no guarantee logs will be sent to the new location diff --git a/core/src/main/java/hudson/triggers/SlowTriggerAdminMonitor.java b/core/src/main/java/hudson/triggers/SlowTriggerAdminMonitor.java index 864d106ee8..131181c0be 100644 --- a/core/src/main/java/hudson/triggers/SlowTriggerAdminMonitor.java +++ b/core/src/main/java/hudson/triggers/SlowTriggerAdminMonitor.java @@ -64,11 +64,12 @@ public void report(@Nonnull final String trigger, @Nonnull final String msg) { if (errors.size() >= MAX_ENTRIES && !errors.containsKey(trigger)) { String oldest_trigger = null; LocalDateTime oldest_time = null; - for (String local_trigger : errors.keySet()) { + for (Map.Entry entry : errors.entrySet()) { + String local_trigger = entry.getKey(); if (oldest_trigger == null - || errors.get(local_trigger).getTimeLDT().compareTo(oldest_time) < 0) { + || entry.getValue().getTimeLDT().compareTo(oldest_time) < 0) { oldest_trigger = local_trigger; - oldest_time = errors.get(local_trigger).getTimeLDT(); + oldest_time = entry.getValue().getTimeLDT(); } } errors.remove(oldest_trigger); diff --git a/core/src/main/java/hudson/triggers/Trigger.java b/core/src/main/java/hudson/triggers/Trigger.java index 03cda6b033..ae7ad4bba4 100644 --- a/core/src/main/java/hudson/triggers/Trigger.java +++ b/core/src/main/java/hudson/triggers/Trigger.java @@ -327,7 +327,7 @@ public static DescriptorExtensionList,TriggerDescriptor> all() { } /** - * Returns a subset of {@link TriggerDescriptor}s that applys to the given item. + * Returns a subset of {@link TriggerDescriptor}s that applies to the given item. */ public static List for_(Item i) { List r = new ArrayList<>(); diff --git a/core/src/main/java/hudson/triggers/Triggers.java b/core/src/main/java/hudson/triggers/Triggers.java index 04c04d8546..ca9f4fa0aa 100644 --- a/core/src/main/java/hudson/triggers/Triggers.java +++ b/core/src/main/java/hudson/triggers/Triggers.java @@ -51,7 +51,7 @@ public class Triggers { // ); /** - * Returns a subset of {@link TriggerDescriptor}s that applys to the given item. + * Returns a subset of {@link TriggerDescriptor}s that applies to the given item. * * @deprecated as of 1.286 * Use {@link Trigger#for_(Item)}. diff --git a/core/src/main/java/hudson/util/AtomicFileWriter.java b/core/src/main/java/hudson/util/AtomicFileWriter.java index c3da305885..48462aa693 100644 --- a/core/src/main/java/hudson/util/AtomicFileWriter.java +++ b/core/src/main/java/hudson/util/AtomicFileWriter.java @@ -149,7 +149,7 @@ public AtomicFileWriter(@Nonnull Path destinationPath, @Nonnull Charset charset, integrityOnClose = false; } - core = new FileChannelWriter(tmpPath, charset, integrityOnFlush, integrityOnClose, StandardOpenOption.WRITE); + core = new FileChannelWriter(tmpPath, charset, integrityOnFlush, integrityOnClose, StandardOpenOption.WRITE, StandardOpenOption.CREATE); } @Override diff --git a/core/src/main/java/hudson/util/ConsistentHash.java b/core/src/main/java/hudson/util/ConsistentHash.java index e1aa16990b..61ef48a94d 100644 --- a/core/src/main/java/hudson/util/ConsistentHash.java +++ b/core/src/main/java/hudson/util/ConsistentHash.java @@ -83,9 +83,7 @@ private Point(int hash, Object item) { } public int compareTo(Point that) { - if(this.hash=0) { + // this is full path + if (checkPrefix(exe, helper)) + return; + + helper.error("There's no such file: "+exe); + } else { + // look in PATH + String path = EnvVars.masterEnvVars.get("PATH"); + String tokenizedPath; + String delimiter = null; + if(path!=null) { + StringBuilder tokenizedPathBuilder = new StringBuilder(); + for (String _dir : Util.tokenize(path.replace("\\", "\\\\"),File.pathSeparator)) { + if (delimiter == null) { + delimiter = ", "; + } + else { + tokenizedPathBuilder.append(delimiter); + } + + tokenizedPathBuilder.append(_dir.replace('\\', '/')); + + if (checkPrefix(_dir + File.pathSeparator + exe, helper)) + return; + } + tokenizedPathBuilder.append('.'); + tokenizedPath = tokenizedPathBuilder.toString(); + } + else { + tokenizedPath = "unavailable."; + } + + // didn't find it + helper.error("There's no such executable "+exe+" in PATH: "+tokenizedPath); + } + } +} diff --git a/core/src/main/java/hudson/util/DoubleLaunchChecker.java b/core/src/main/java/hudson/util/DoubleLaunchChecker.java index 74c4c59933..2bf43010fa 100644 --- a/core/src/main/java/hudson/util/DoubleLaunchChecker.java +++ b/core/src/main/java/hudson/util/DoubleLaunchChecker.java @@ -133,7 +133,9 @@ public String getId() { String contextPath=""; try { Method m = ServletContext.class.getMethod("getContextPath"); - contextPath=" contextPath=\""+m.invoke(h.servletContext)+"\""; + contextPath = " contextPath=\"" + m.invoke(h.servletContext) + "\""; + } catch (RuntimeException e) { + throw e; } catch (Exception e) { // maybe running with Servlet 2.4 } diff --git a/core/src/main/java/hudson/util/FormFieldValidator.java b/core/src/main/java/hudson/util/FormFieldValidator.java index 1e63e4bb86..292d5d1141 100644 --- a/core/src/main/java/hudson/util/FormFieldValidator.java +++ b/core/src/main/java/hudson/util/FormFieldValidator.java @@ -23,17 +23,20 @@ */ package hudson.util; -import static hudson.Util.fixEmpty; -import hudson.EnvVars; import hudson.FilePath; import hudson.ProxyConfiguration; import hudson.Util; import hudson.model.AbstractProject; -import jenkins.model.Jenkins; import hudson.model.Item; -import hudson.security.Permission; import hudson.security.AccessControlled; +import hudson.security.Permission; +import jenkins.model.Jenkins; +import org.acegisecurity.AccessDeniedException; +import org.kohsuke.stapler.Stapler; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; +import javax.servlet.ServletException; import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -43,12 +46,7 @@ import java.net.URLConnection; import java.util.Locale; -import javax.servlet.ServletException; - -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; -import org.acegisecurity.AccessDeniedException; -import org.kohsuke.stapler.Stapler; +import static hudson.Util.fixEmpty; /** * Base class that provides the framework for doing on-the-fly form field validation. @@ -517,66 +515,53 @@ public Executable(StaplerRequest request, StaplerResponse response) { protected void check() throws IOException, ServletException { String exe = fixEmpty(request.getParameter("value")); - if(exe==null) { - ok(); // nothing entered yet - return; - } - - if(exe.indexOf(File.separatorChar)>=0) { - // this is full path - File f = new File(exe); - if(f.exists()) { - checkExecutable(f); - return; + FormFieldValidator.Executable self = this; + Exception exceptions[] = {null}; + DOSToUnixPathHelper.iteratePath(exe, new DOSToUnixPathHelper.Helper() { + @Override + public void ok() { + try { + self.ok(); + } catch (Exception e) { + exceptions[0] = e; + } } - File fexe = new File(exe+".exe"); - if(fexe.exists()) { - checkExecutable(fexe); - return; + @Override + public void checkExecutable(File fexe) { + try { + self.checkExecutable(fexe); + } catch (Exception e) { + exceptions[0] = e; + } } - error("There's no such file: "+exe); - } else { - // look in PATH - String path = EnvVars.masterEnvVars.get("PATH"); - String tokenizedPath; - String delimiter = null; - if(path!=null) { - StringBuilder tokenizedPathBuilder = new StringBuilder(); - for (String _dir : Util.tokenize(path.replace("\\", "\\\\"),File.pathSeparator)) { - if (delimiter == null) { - delimiter = ", "; - } - else { - tokenizedPathBuilder.append(delimiter); - } - - tokenizedPathBuilder.append(_dir.replace('\\', '/')); - - File dir = new File(_dir); - - File f = new File(dir,exe); - if(f.exists()) { - checkExecutable(f); - return; - } - - File fexe = new File(dir,exe+".exe"); - if(fexe.exists()) { - checkExecutable(fexe); - return; - } + @Override + public void error(String string) { + try { + self.error(string); + } catch (Exception e) { + exceptions[0] = e; } - tokenizedPathBuilder.append('.'); - tokenizedPath = tokenizedPathBuilder.toString(); - } - else { - tokenizedPath = "unavailable."; } - // didn't find it - error("There's no such executable "+exe+" in PATH: "+tokenizedPath); + @Override + public void validate(File fexe) { + try { + self.checkExecutable(fexe); + } catch (IOException ioe) { + exceptions[0] = ioe; + } catch (ServletException se) { + exceptions[0] = se; + } + } + }); + Exception e = exceptions[0]; + if (e != null) { + if (e instanceof IOException) + throw (IOException)e; + if (e instanceof ServletException) + throw (ServletException)e; } } diff --git a/core/src/main/java/hudson/util/FormValidation.java b/core/src/main/java/hudson/util/FormValidation.java index b3aa41cebf..e632e7bb1b 100644 --- a/core/src/main/java/hudson/util/FormValidation.java +++ b/core/src/main/java/hudson/util/FormValidation.java @@ -333,55 +333,34 @@ public static FormValidation validateExecutable(String exe) { public static FormValidation validateExecutable(String exe, FileValidator exeValidator) { // insufficient permission to perform validation? if(!Jenkins.get().hasPermission(Jenkins.ADMINISTER)) return ok(); + final FormValidation[] result = {null}; - exe = fixEmpty(exe); - if(exe==null) - return ok(); - - if(exe.indexOf(File.separatorChar)>=0) { - // this is full path - File f = new File(exe); - if(f.exists()) return exeValidator.validate(f); - - File fexe = new File(exe+".exe"); - if(fexe.exists()) return exeValidator.validate(fexe); - - return error("There's no such file: "+exe); - } - - // look in PATH - String path = EnvVars.masterEnvVars.get("PATH"); - String tokenizedPath; - String delimiter = null; - if(path!=null) { - StringBuilder tokenizedPathBuilder = new StringBuilder(); - for (String _dir : Util.tokenize(path.replace("\\", "\\\\"),File.pathSeparator)) { - if (delimiter == null) { - delimiter = ", "; - } - else { - tokenizedPathBuilder.append(delimiter); + try { + DOSToUnixPathHelper.iteratePath(exe, new DOSToUnixPathHelper.Helper() { + @Override + public void ok() { + result[0] = FormValidation.ok(); } - tokenizedPathBuilder.append(_dir.replace('\\', '/')); - - File dir = new File(_dir); - - File f = new File(dir,exe); - if(f.exists()) return exeValidator.validate(f); + @Override + public void checkExecutable(File fexe) { + result[0] = exeValidator.validate(fexe); + } - File fexe = new File(dir,exe+".exe"); - if(fexe.exists()) return exeValidator.validate(fexe); - } - tokenizedPathBuilder.append('.'); + @Override + public void error(String string) { + result[0] = FormValidation.error(string); + } - tokenizedPath = tokenizedPathBuilder.toString(); - } else { - tokenizedPath = "unavailable."; + @Override + public void validate(File fexe) { + result[0] = exeValidator.validate(fexe); + } + }); + return result[0]; + } catch (Exception e) { + return FormValidation.error(e, "Unexpected error"); } - - // didn't find it - return error("There's no such executable "+exe+" in PATH: "+tokenizedPath); } /** diff --git a/core/src/main/java/hudson/util/Iterators.java b/core/src/main/java/hudson/util/Iterators.java index 54eb00364c..25b45f0c85 100644 --- a/core/src/main/java/hudson/util/Iterators.java +++ b/core/src/main/java/hudson/util/Iterators.java @@ -50,7 +50,7 @@ public class Iterators { * Returns the empty iterator. */ public static Iterator empty() { - return Collections.emptyList().iterator(); + return Collections.emptyIterator(); } /** @@ -62,7 +62,7 @@ public static abstract class FlattenIterator implements Iterator { protected FlattenIterator(Iterator core) { this.core = core; - cur = Collections.emptyList().iterator(); + cur = Collections.emptyIterator(); } protected FlattenIterator(Iterable core) { diff --git a/core/src/main/java/hudson/util/ListBoxModel.java b/core/src/main/java/hudson/util/ListBoxModel.java index fc717cc7ef..14b747c123 100644 --- a/core/src/main/java/hudson/util/ListBoxModel.java +++ b/core/src/main/java/hudson/util/ListBoxModel.java @@ -173,7 +173,7 @@ public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object nod /** * @deprecated - * Exposed for stapler. Not meant for programatic consumption. + * Exposed for stapler. Not meant for programmatic consumption. */ @Exported @Deprecated diff --git a/core/src/main/java/hudson/util/MultipartFormDataParser.java b/core/src/main/java/hudson/util/MultipartFormDataParser.java index ffab459a8b..39cac1c987 100644 --- a/core/src/main/java/hudson/util/MultipartFormDataParser.java +++ b/core/src/main/java/hudson/util/MultipartFormDataParser.java @@ -36,7 +36,7 @@ import java.util.HashMap; /** - * Wraps commons file-upload and handles a "multipart/form-data" form submisison + * Wraps commons file-upload and handles a "multipart/form-data" form submission * (that often includes file upload.) * * @author Kohsuke Kawaguchi diff --git a/core/src/main/java/hudson/util/ProcessTree.java b/core/src/main/java/hudson/util/ProcessTree.java index ed51680129..4a0db31765 100644 --- a/core/src/main/java/hudson/util/ProcessTree.java +++ b/core/src/main/java/hudson/util/ProcessTree.java @@ -956,8 +956,7 @@ class LinuxProcess extends UnixProcess { LinuxProcess(int pid) throws IOException { super(pid); - BufferedReader r = new BufferedReader(new FileReader(getFile("status"))); - try { + try (BufferedReader r = new BufferedReader(new FileReader(getFile("status")))) { String line; while((line=r.readLine())!=null) { line=line.toLowerCase(Locale.ENGLISH); @@ -966,8 +965,6 @@ class LinuxProcess extends UnixProcess { break; } } - } finally { - r.close(); } if(ppid==-1) throw new IOException("Failed to parse PPID from /proc/"+pid+"/status"); @@ -1025,11 +1022,8 @@ public synchronized EnvVars getEnvironmentVariables() { } public byte[] readFileToByteArray(File file) throws IOException { - InputStream in = org.apache.commons.io.FileUtils.openInputStream(file); - try { + try (InputStream in = org.apache.commons.io.FileUtils.openInputStream(file)) { return org.apache.commons.io.IOUtils.toByteArray(in); - } finally { - in.close(); } } } @@ -1092,8 +1086,7 @@ private class AIXProcess extends UnixProcess { private AIXProcess(int pid) throws IOException { super(pid); - RandomAccessFile pstatus = new RandomAccessFile(getFile("status"),"r"); - try { + try (RandomAccessFile pstatus = new RandomAccessFile(getFile("status"), "r")) { // typedef struct pstatus { // uint32_t pr_flag; /* process flags from proc struct p_flag */ // uint32_t pr_flag2; /* process flags from proc struct p_flag2 */ @@ -1148,13 +1141,9 @@ private AIXProcess(int pid) throws IOException { ppid = adjust((int)pstatus.readLong()); // AIX pids are stored as a 64 bit integer, // but the first 4 bytes are always 0 - - } finally { - pstatus.close(); } - RandomAccessFile psinfo = new RandomAccessFile(getFile("psinfo"),"r"); - try { + try (RandomAccessFile psinfo = new RandomAccessFile(getFile("psinfo"), "r")) { // typedef struct psinfo { // uint32_t pr_flag; /* process flags from proc struct p_flag */ // uint32_t pr_flag2; /* process flags from proc struct p_flag2 * @@ -1200,8 +1189,6 @@ private AIXProcess(int pid) throws IOException { argc = adjust(psinfo.readInt()); pr_argp = adjustL(psinfo.readLong()); pr_envp = adjustL(psinfo.readLong()); - } finally { - psinfo.close(); } } @@ -1426,8 +1413,7 @@ private class SolarisProcess extends UnixProcess { private SolarisProcess(int pid) throws IOException { super(pid); - RandomAccessFile psinfo = new RandomAccessFile(getFile("psinfo"),"r"); - try { + try (RandomAccessFile psinfo = new RandomAccessFile(getFile("psinfo"), "r")) { // see http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/uts/common/sys/procfs.h //typedef struct psinfo { // int pr_flag; /* process flags */ @@ -1487,8 +1473,6 @@ private SolarisProcess(int pid) throws IOException { envp = to64(adjust(psinfo.readInt())); b64 = (psinfo.readByte() == PR_MODEL_LP64); } - } finally { - psinfo.close(); } if(ppid==-1) throw new IOException("Failed to parse PPID from /proc/"+pid+"/status"); diff --git a/core/src/main/java/hudson/util/RunList.java b/core/src/main/java/hudson/util/RunList.java index 44136da9b9..2fc61de3d2 100644 --- a/core/src/main/java/hudson/util/RunList.java +++ b/core/src/main/java/hudson/util/RunList.java @@ -97,9 +97,7 @@ private static Iterable combine(Iterable> runList public int compare(R o1, R o2) { long lhs = o1.getTimeInMillis(); long rhs = o2.getTimeInMillis(); - if (lhs > rhs) return -1; - if (lhs < rhs) return 1; - return 0; + return Long.compare(rhs, lhs); } }); } diff --git a/core/src/main/java/hudson/util/SecretRewriter.java b/core/src/main/java/hudson/util/SecretRewriter.java index 7970f6cd70..ec9206e865 100644 --- a/core/src/main/java/hudson/util/SecretRewriter.java +++ b/core/src/main/java/hudson/util/SecretRewriter.java @@ -1,6 +1,7 @@ package hudson.util; import hudson.Functions; +import hudson.Util; import hudson.model.TaskListener; import java.io.InputStream; @@ -15,7 +16,6 @@ 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.Base64; @@ -84,37 +84,33 @@ public boolean rewrite(File f) throws InvalidKeyException, IOException { AtomicFileWriter w = new AtomicFileWriter(f, "UTF-8"); try { - boolean modified = false; // did we actually change anything? - try (PrintWriter out = new PrintWriter(new BufferedWriter(w))) { - try (InputStream fin = Files.newInputStream(f.toPath())) { - BufferedReader r = new BufferedReader(new InputStreamReader(fin, StandardCharsets.UTF_8)); - String line; - StringBuilder buf = new StringBuilder(); - - while ((line = r.readLine()) != null) { - int copied = 0; - buf.setLength(0); - while (true) { - int sidx = line.indexOf('>', copied); - if (sidx < 0) break; - int eidx = line.indexOf('<', sidx); - if (eidx < 0) break; - - String elementText = line.substring(sidx + 1, eidx); - String replacement = tryRewrite(elementText); - if (!replacement.equals(elementText)) - modified = true; - - buf.append(line, copied, sidx + 1); - buf.append(replacement); - copied = eidx; - } - buf.append(line.substring(copied)); - out.println(buf.toString()); + try (PrintWriter out = new PrintWriter(new BufferedWriter(w)); + InputStream fin = Files.newInputStream(Util.fileToPath(f)); + BufferedReader r = new BufferedReader(new InputStreamReader(fin, StandardCharsets.UTF_8))) { + String line; + StringBuilder buf = new StringBuilder(); + + while ((line = r.readLine()) != null) { + int copied = 0; + buf.setLength(0); + while (true) { + int sidx = line.indexOf('>', copied); + if (sidx < 0) break; + int eidx = line.indexOf('<', sidx); + if (eidx < 0) break; + + String elementText = line.substring(sidx + 1, eidx); + String replacement = tryRewrite(elementText); + if (!replacement.equals(elementText)) + modified = true; + + buf.append(line, copied, sidx + 1); + buf.append(replacement); + copied = eidx; } - } catch (InvalidPathException e) { - throw new IOException(e); + buf.append(line.substring(copied)); + out.println(buf.toString()); } } @@ -143,7 +139,7 @@ public synchronized int rewriteRecursive(File dir, TaskListener listener) throws private int rewriteRecursive(File dir, String relative, TaskListener listener) throws InvalidKeyException { String canonical; try { - canonical = dir.toPath().toRealPath(new LinkOption[0]).toString(); + canonical = dir.toPath().toRealPath().toString(); } catch (IOException | InvalidPathException e) { canonical = dir.getAbsolutePath(); // } diff --git a/core/src/main/java/hudson/util/TextFile.java b/core/src/main/java/hudson/util/TextFile.java index e037c2a0b2..ee06f713a5 100644 --- a/core/src/main/java/hudson/util/TextFile.java +++ b/core/src/main/java/hudson/util/TextFile.java @@ -113,12 +113,13 @@ public String read() throws IOException { */ public void write(String text) throws IOException { file.getParentFile().mkdirs(); - AtomicFileWriter w = new AtomicFileWriter(file); - try { - w.write(text); - w.commit(); - } finally { - w.abort(); + try (AtomicFileWriter w = new AtomicFileWriter(file)) { + try { + w.write(text); + w.commit(); + } finally { + w.abort(); + } } } diff --git a/core/src/main/java/hudson/util/XStream2.java b/core/src/main/java/hudson/util/XStream2.java index f49c61f47a..43f0dfd08c 100644 --- a/core/src/main/java/hudson/util/XStream2.java +++ b/core/src/main/java/hudson/util/XStream2.java @@ -47,7 +47,6 @@ import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import com.thoughtworks.xstream.io.ReaderWrapper; import com.thoughtworks.xstream.mapper.CannotResolveClassException; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.PluginManager; import hudson.PluginWrapper; import hudson.XmlFile; @@ -516,7 +515,6 @@ class PluginClassOwnership implements ClassOwnership { private PluginManager pm; - @SuppressFBWarnings("NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE") // classOwnership checked for null so why does FB complain? @Override public String ownerOf(Class clazz) { if (classOwnership != null) { return classOwnership.ownerOf(clazz); diff --git a/core/src/main/java/hudson/util/jna/Advapi32.java b/core/src/main/java/hudson/util/jna/Advapi32.java index bef26018ac..288e9d5a33 100644 --- a/core/src/main/java/hudson/util/jna/Advapi32.java +++ b/core/src/main/java/hudson/util/jna/Advapi32.java @@ -352,7 +352,7 @@ class SERVICE_TABLE_ENTRY extends Structure { @Override protected List getFieldOrder() { - return Arrays.asList(new String[] {"lpServiceName", "lpServiceProc"}); + return Arrays.asList("lpServiceName", "lpServiceProc"); } } @@ -360,7 +360,7 @@ class ChangeServiceConfig2Info extends Structure { @Override protected List getFieldOrder() { - return Arrays.asList(new String[] {}); + return Arrays.asList(); } } diff --git a/core/src/main/java/hudson/util/jna/SHELLEXECUTEINFO.java b/core/src/main/java/hudson/util/jna/SHELLEXECUTEINFO.java index 506242c9aa..0bfc5e627f 100644 --- a/core/src/main/java/hudson/util/jna/SHELLEXECUTEINFO.java +++ b/core/src/main/java/hudson/util/jna/SHELLEXECUTEINFO.java @@ -57,7 +57,8 @@ * @author Kohsuke Kawaguchi * @see MSDN: SHELLEXECUTEINFO */ -@SuppressFBWarnings(value = "UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD", justification = "JNA Data Structure") +@SuppressFBWarnings(value = {"UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD", "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD"}, + justification = "JNA Data Structure") public class SHELLEXECUTEINFO extends Structure { public int cbSize = size(); public int fMask; @@ -87,7 +88,8 @@ protected List getFieldOrder() { "hProcess"); } - @SuppressFBWarnings(value = "UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD", justification = "JNA Data Structure") + @SuppressFBWarnings(value = {"UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD", "URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD"}, + justification = "JNA Data Structure") public static class DUMMYUNIONNAME_union extends Union { public Pointer hIcon; public Pointer hMonitor; diff --git a/core/src/main/java/hudson/util/spring/DefaultRuntimeSpringConfiguration.java b/core/src/main/java/hudson/util/spring/DefaultRuntimeSpringConfiguration.java index 9924b194c2..545402b141 100644 --- a/core/src/main/java/hudson/util/spring/DefaultRuntimeSpringConfiguration.java +++ b/core/src/main/java/hudson/util/spring/DefaultRuntimeSpringConfiguration.java @@ -201,8 +201,7 @@ public void registerBeansWithContext(StaticApplicationContext applicationContext applicationContext.registerBeanDefinition(bc.getName(), bc.getBeanDefinition()); } - for (String key : beanDefinitions.keySet()) { - BeanDefinition bd = beanDefinitions.get(key); + beanDefinitions.forEach((key, bd) -> { if (LOGGER.isLoggable(Level.FINER)) { LOGGER.finer("[RuntimeConfiguration] Registering bean [" + key + "]"); if (LOGGER.isLoggable(Level.FINEST)) { @@ -217,7 +216,7 @@ public void registerBeansWithContext(StaticApplicationContext applicationContext applicationContext.registerBeanDefinition(key, bd); - } + }); } /** diff --git a/core/src/main/java/jenkins/agents/WebSocketAgents.java b/core/src/main/java/jenkins/agents/WebSocketAgents.java new file mode 100644 index 0000000000..965c3b67eb --- /dev/null +++ b/core/src/main/java/jenkins/agents/WebSocketAgents.java @@ -0,0 +1,191 @@ +/* + * The MIT License + * + * Copyright 2019 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.agents; + +import com.google.common.collect.ImmutableMap; +import hudson.Extension; +import hudson.ExtensionList; +import hudson.model.Computer; +import hudson.model.InvisibleAction; +import hudson.model.UnprotectedRootAction; +import hudson.remoting.AbstractByteArrayCommandTransport; +import hudson.remoting.Capability; +import hudson.remoting.Channel; +import hudson.remoting.ChannelBuilder; +import hudson.remoting.Engine; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.util.Arrays; +import java.util.Collections; +import java.util.logging.Level; +import java.util.logging.Logger; +import jenkins.slaves.JnlpAgentReceiver; +import jenkins.slaves.RemotingVersionInfo; +import jenkins.websocket.WebSocketSession; +import jenkins.websocket.WebSockets; +import org.jenkinsci.remoting.engine.JnlpConnectionState; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.kohsuke.stapler.HttpResponse; +import org.kohsuke.stapler.HttpResponses; +import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; + +@Extension +@Restricted(NoExternalUse.class) +public final class WebSocketAgents extends InvisibleAction implements UnprotectedRootAction { + + private static final Logger LOGGER = Logger.getLogger(WebSocketAgents.class.getName()); + + @Override + public String getUrlName() { + return WebSockets.isSupported() ? "wsagents" : null; + } + + public HttpResponse doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException { + String agent = req.getHeader(JnlpConnectionState.CLIENT_NAME_KEY); + String secret = req.getHeader(JnlpConnectionState.SECRET_KEY); + String remoteCapabilityStr = req.getHeader(Capability.KEY); + if (agent == null || secret == null || remoteCapabilityStr == null) { + LOGGER.warning(() -> "incomplete headers: " + Collections.list(req.getHeaderNames())); + throw HttpResponses.errorWithoutStack(400, "This endpoint is only for use from agent.jar in WebSocket mode"); + } + LOGGER.fine(() -> "receiving headers: " + Collections.list(req.getHeaderNames())); + if (!JnlpAgentReceiver.DATABASE.exists(agent)) { + LOGGER.warning(() -> "no such agent " + agent); + throw HttpResponses.errorWithoutStack(400, "no such agent"); + } + if (!MessageDigest.isEqual(secret.getBytes(StandardCharsets.US_ASCII), JnlpAgentReceiver.DATABASE.getSecretOf(agent).getBytes(StandardCharsets.US_ASCII))) { + LOGGER.warning(() -> "incorrect secret for " + agent); + throw HttpResponses.forbidden(); + } + JnlpConnectionState state = new JnlpConnectionState(null, ExtensionList.lookup(JnlpAgentReceiver.class)); + state.setRemoteEndpointDescription(req.getRemoteAddr()); + state.fireBeforeProperties(); + LOGGER.fine(() -> "connecting " + agent); + state.fireAfterProperties(ImmutableMap.of( + // TODO or just pass all request headers? + JnlpConnectionState.CLIENT_NAME_KEY, agent, + JnlpConnectionState.SECRET_KEY, secret + )); + Capability remoteCapability = Capability.fromASCII(remoteCapabilityStr); + LOGGER.fine(() -> "received " + remoteCapability); + rsp.setHeader(Capability.KEY, new Capability().toASCII()); + rsp.setHeader(Engine.REMOTING_MINIMUM_VERSION_HEADER, RemotingVersionInfo.getMinimumSupportedVersion().toString()); + rsp.setHeader(JnlpConnectionState.COOKIE_KEY, JnlpAgentReceiver.generateCookie()); // TODO figure out what this is for, if anything + return WebSockets.upgrade(new Session(state, agent, remoteCapability)); + } + + private static class Session extends WebSocketSession { + + private final JnlpConnectionState state; + private final String agent; + private final Capability remoteCapability; + private AbstractByteArrayCommandTransport.ByteArrayReceiver receiver; + + Session(JnlpConnectionState state, String agent, Capability remoteCapability) { + this.state = state; + this.agent = agent; + this.remoteCapability = remoteCapability; + } + + @Override + protected void opened() { + Computer.threadPoolForRemoting.submit(() -> { + LOGGER.fine(() -> "setting up channel for " + agent); + state.fireBeforeChannel(new ChannelBuilder(agent, Computer.threadPoolForRemoting)); + state.fireAfterChannel(state.getChannelBuilder().build(new Transport())); + LOGGER.fine(() -> "set up channel for " + agent); + return null; + }); + } + + @Override + protected void binary(byte[] payload, int offset, int len) { + LOGGER.finest(() -> "reading block of length " + len + " from " + agent); + if (offset == 0 && len == payload.length) { + receiver.handle(payload); + } else { + receiver.handle(Arrays.copyOfRange(payload, offset, offset + len)); + } + } + + @Override + protected void closed(int statusCode, String reason) { + LOGGER.finest(() -> "closed " + statusCode + " " + reason); + IOException x = new ClosedChannelException(); + receiver.terminate(x); + state.fireChannelClosed(x); + state.fireAfterDisconnect(); + } + + @Override + protected void error(Throwable cause) { + LOGGER.log(Level.WARNING, null, cause); + } + + class Transport extends AbstractByteArrayCommandTransport { + + @Override + public void setup(AbstractByteArrayCommandTransport.ByteArrayReceiver bar) { + receiver = bar; + } + + @Override + public void writeBlock(Channel chnl, byte[] bytes) throws IOException { + LOGGER.finest(() -> "writing block of length " + bytes.length + " to " + agent); + try { + sendBinary(ByteBuffer.wrap(bytes)).get(); + } catch (Exception x) { + x.printStackTrace(); + throw new IOException(x); + } + } + + @Override + public Capability getRemoteCapability() throws IOException { + return remoteCapability; + } + + @Override + public void closeWrite() throws IOException { + LOGGER.finest(() -> "closeWrite"); + close(); + } + + @Override + public void closeRead() throws IOException { + LOGGER.finest(() -> "closeRead"); + close(); + } + + } + + } + +} diff --git a/core/src/main/java/jenkins/install/SetupWizard.java b/core/src/main/java/jenkins/install/SetupWizard.java index e122e45c4f..35524fd4dd 100644 --- a/core/src/main/java/jenkins/install/SetupWizard.java +++ b/core/src/main/java/jenkins/install/SetupWizard.java @@ -4,6 +4,7 @@ import static org.apache.commons.lang.StringUtils.defaultIfBlank; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -453,7 +454,7 @@ public JSONArray getPlatformPluginUpdates() { } } - String initialPluginJson = IOUtils.toString(connection.getInputStream(), "utf-8"); + String initialPluginJson = IOUtils.toString(connection.getInputStream(), StandardCharsets.UTF_8); initialPluginList = JSONArray.fromObject(initialPluginJson); break updateSiteList; } catch(Exception e) { @@ -470,7 +471,7 @@ public JSONArray getPlatformPluginUpdates() { try { ClassLoader cl = getClass().getClassLoader(); URL localPluginData = cl.getResource("jenkins/install/platform-plugins.json"); - String initialPluginJson = IOUtils.toString(localPluginData.openStream(), "utf-8"); + String initialPluginJson = IOUtils.toString(localPluginData.openStream(), StandardCharsets.UTF_8); initialPluginList = JSONArray.fromObject(initialPluginJson); } catch (Exception e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); diff --git a/core/src/main/java/jenkins/model/DirectlyModifiableTopLevelItemGroup.java b/core/src/main/java/jenkins/model/DirectlyModifiableTopLevelItemGroup.java index f08d3f3faf..79f59b100f 100644 --- a/core/src/main/java/jenkins/model/DirectlyModifiableTopLevelItemGroup.java +++ b/core/src/main/java/jenkins/model/DirectlyModifiableTopLevelItemGroup.java @@ -49,7 +49,7 @@ public interface DirectlyModifiableTopLevelItemGroup extends ModifiableTopLevelI * @param the kind of item * @param item an item to add which is currently elsewhere * @param name the desired item name in this group (might simply be the original {@link Item#getName}) - * @return normally the same {@code item}, but might be a new cppy if necessary + * @return normally the same {@code item}, but might be a new copy if necessary * @throws IOException if adding fails * @throws IllegalArgumentException if {@link #canAdd} is false, or an item with this name already exists, or this item is as yet unnamed */ diff --git a/core/src/main/java/jenkins/model/GlobalCloudConfiguration.java b/core/src/main/java/jenkins/model/GlobalCloudConfiguration.java index 9c6635ab05..9ac2222ad5 100644 --- a/core/src/main/java/jenkins/model/GlobalCloudConfiguration.java +++ b/core/src/main/java/jenkins/model/GlobalCloudConfiguration.java @@ -1,30 +1,56 @@ package jenkins.model; import hudson.Extension; +import hudson.RestrictedSince; +import hudson.model.Descriptor; +import hudson.model.RootAction; import hudson.slaves.Cloud; +import hudson.util.FormApply; import net.sf.json.JSONObject; import org.jenkinsci.Symbol; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; import org.kohsuke.stapler.StaplerRequest; +import org.kohsuke.stapler.StaplerResponse; +import org.kohsuke.stapler.verb.POST; +import javax.annotation.CheckForNull; +import javax.servlet.ServletException; import java.io.IOException; /** - * Adds the {@link Cloud} configuration to the system config page. + * Provides a configuration form for {@link Jenkins#clouds}. * - *

    - * This object just acts as a proxy to configure {@link Jenkins#clouds} - * - * @author Kohsuke Kawaguchi + * Has been overhauled in Jenkins 2.XXX to no longer contribute to Configure System, but be a standalone form. */ -@Extension(ordinal=-100) @Symbol("cloud") // historically this was placed at the very end of the configuration page -public class GlobalCloudConfiguration extends GlobalConfiguration { +@Extension +@Symbol("cloud") +@Restricted(NoExternalUse.class) +@RestrictedSince("TODO") +public class GlobalCloudConfiguration implements RootAction { + + @CheckForNull + @Override + public String getIconFileName() { + return null; + } + + @CheckForNull @Override - public boolean configure(StaplerRequest req, JSONObject json) throws FormException { - try { - Jenkins.get().clouds.rebuildHetero(req,json, Cloud.all(), "cloud"); - return true; - } catch (IOException e) { - throw new FormException(e,"clouds"); - } + public String getDisplayName() { + return Messages.GlobalCloudConfiguration_DisplayName(); + } + + @Override + public String getUrlName() { + return "configureClouds"; + } + + @POST + public void doConfigure(StaplerRequest req, StaplerResponse rsp) throws Descriptor.FormException, IOException, ServletException { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + JSONObject json = req.getSubmittedForm(); + Jenkins.get().clouds.rebuildHetero(req,json, Cloud.all(), "cloud"); + FormApply.success(req.getContextPath() + "/manage").generateResponse(req, rsp, null); } } diff --git a/core/src/main/java/jenkins/model/IdStrategy.java b/core/src/main/java/jenkins/model/IdStrategy.java index ab1a3cf921..e434343f74 100644 --- a/core/src/main/java/jenkins/model/IdStrategy.java +++ b/core/src/main/java/jenkins/model/IdStrategy.java @@ -35,6 +35,7 @@ import org.kohsuke.stapler.DataBoundConstructor; import javax.annotation.Nonnull; +import java.io.Serializable; import java.util.Comparator; import java.util.Locale; import java.util.function.Function; @@ -188,7 +189,9 @@ Character convertPseudoUnicode(String matchedGroup) { /** * The default case insensitive {@link IdStrategy} */ - public static class CaseInsensitive extends IdStrategy { + public static class CaseInsensitive extends IdStrategy implements Serializable { + + private static final long serialVersionUID = -7244768200684861085L; @DataBoundConstructor public CaseInsensitive() {} @@ -224,7 +227,9 @@ public String getDisplayName() { /** * A case sensitive {@link IdStrategy} */ - public static class CaseSensitive extends IdStrategy { + public static class CaseSensitive extends IdStrategy implements Serializable { + + private static final long serialVersionUID = 8339425353883308324L; @DataBoundConstructor public CaseSensitive() {} @@ -268,7 +273,9 @@ public String getDisplayName() { * mailbox. Most sane system administrators do not configure their accounts using case sensitive mailboxes * but the RFC does allow them the option to configure that way. Domain names are always case insensitive per RFC. */ - public static class CaseSensitiveEmailAddress extends CaseSensitive { + public static class CaseSensitiveEmailAddress extends CaseSensitive implements Serializable { + + private static final long serialVersionUID = -5713655323057260180L; @DataBoundConstructor public CaseSensitiveEmailAddress() {} diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java index aa9ff40bdd..27ea0ec81d 100644 --- a/core/src/main/java/jenkins/model/Jenkins.java +++ b/core/src/main/java/jenkins/model/Jenkins.java @@ -1065,7 +1065,28 @@ private Object readResolve() { agentProtocols = null; return this; } - + + /** + * Retrieve the proxy configuration. + * + * @return the proxy configuration + * @since TODO + */ + @CheckForNull + public ProxyConfiguration getProxy() { + return proxy; + } + + /** + * Set the proxy configuration. + * + * @param proxy the proxy to set + * @since TODO + */ + public void setProxy(@CheckForNull ProxyConfiguration proxy) { + this.proxy = proxy; + } + /** * Get the Jenkins {@link jenkins.install.InstallState install state}. * @return The Jenkins {@link jenkins.install.InstallState install state}. @@ -3672,7 +3693,7 @@ private void _cleanUpPersistQueue(List errors) { } private void _cleanUpShutdownThreadPoolForLoad(List errors) { - LOGGER.log(FINE, "Shuting down Jenkins load thread pool"); + LOGGER.log(FINE, "Shutting down Jenkins load thread pool"); try { threadPoolForLoad.shutdown(); } catch (SecurityException e) { @@ -5078,6 +5099,8 @@ private static void computeVersion(ServletContext context) { VERSION = ver; context.setAttribute("version",ver); + CHANGELOG_URL = props.getProperty("changelog.url"); + VERSION_HASH = Util.getDigestOf(ver).substring(0, 8); SESSION_HASH = Util.getDigestOf(ver+System.currentTimeMillis()).substring(0, 8); @@ -5101,9 +5124,12 @@ private static void computeVersion(ServletContext context) { */ public static String VERSION = UNCOMPUTED_VERSION; + @Restricted(NoExternalUse.class) + public static String CHANGELOG_URL; + /** * Parses {@link #VERSION} into {@link VersionNumber}, or null if it's not parseable as a version number - * (such as when Jenkins is run with "mvn hudson-dev:run") + * (such as when Jenkins is run with {@code mvn jetty:run}) */ public @CheckForNull static VersionNumber getVersion() { return toVersion(VERSION); @@ -5114,17 +5140,17 @@ private static void computeVersion(ServletContext context) { * {@link #doConfigSubmit(org.kohsuke.stapler.StaplerRequest, org.kohsuke.stapler.StaplerResponse)}. *

    * Parses the version into {@link VersionNumber}, or null if it's not parseable as a version number - * (such as when Jenkins is run with "mvn hudson-dev:run") + * (such as when Jenkins is run with {@code mvn jetty:run}) * @since 2.0 */ @Restricted(NoExternalUse.class) public @CheckForNull static VersionNumber getStoredVersion() { - return toVersion(Jenkins.getActiveInstance().version); + return toVersion(Jenkins.get().version); } /** * Parses a version string into {@link VersionNumber}, or null if it's not parseable as a version number - * (such as when Jenkins is run with "mvn hudson-dev:run") + * (such as when Jenkins is run with {@code mvn jetty:run}) */ private static @CheckForNull VersionNumber toVersion(@CheckForNull String versionString) { if (versionString == null) { diff --git a/core/src/main/java/jenkins/model/PeepholePermalink.java b/core/src/main/java/jenkins/model/PeepholePermalink.java index 57d9fa5823..8029524c99 100644 --- a/core/src/main/java/jenkins/model/PeepholePermalink.java +++ b/core/src/main/java/jenkins/model/PeepholePermalink.java @@ -179,8 +179,7 @@ protected void updateCache(@Nonnull Job job, @CheckForNull Run b) { cache.put(getId(), b == null ? RESOLVES_TO_NONE : b.getNumber()); File storage = storageFor(buildDir); LOGGER.fine(() -> "saving to " + storage + ": " + cache); - try { - AtomicFileWriter cw = new AtomicFileWriter(storage); + try (AtomicFileWriter cw = new AtomicFileWriter(storage)) { try { for (Map.Entry entry : cache.entrySet()) { cw.write(entry.getKey()); diff --git a/core/src/main/java/jenkins/model/RunIdMigrator.java b/core/src/main/java/jenkins/model/RunIdMigrator.java index ac8762a6bb..4af582072e 100644 --- a/core/src/main/java/jenkins/model/RunIdMigrator.java +++ b/core/src/main/java/jenkins/model/RunIdMigrator.java @@ -117,8 +117,7 @@ private boolean load(File dir) { private void save(File dir) { File f = new File(dir, MAP_FILE); - try { - AtomicFileWriter w = new AtomicFileWriter(f); + try (AtomicFileWriter w = new AtomicFileWriter(f)) { try { for (Map.Entry entry : idToNumber.entrySet()) { w.write(entry.getKey() + ' ' + entry.getValue() + '\n'); diff --git a/core/src/main/java/jenkins/model/SimplePageDecorator.java b/core/src/main/java/jenkins/model/SimplePageDecorator.java index f655ff271b..93d08478f5 100644 --- a/core/src/main/java/jenkins/model/SimplePageDecorator.java +++ b/core/src/main/java/jenkins/model/SimplePageDecorator.java @@ -67,7 +67,7 @@ public static List all() { } /** - * The first found LoginDecarator, there can only be one. + * The first found LoginDecorator, there can only be one. * @return the first found {@link SimplePageDecorator} */ public static SimplePageDecorator first(){ diff --git a/core/src/main/java/jenkins/model/UnlabeledLoadStatistics.java b/core/src/main/java/jenkins/model/UnlabeledLoadStatistics.java index 39369d41ab..10bcce6652 100644 --- a/core/src/main/java/jenkins/model/UnlabeledLoadStatistics.java +++ b/core/src/main/java/jenkins/model/UnlabeledLoadStatistics.java @@ -102,7 +102,7 @@ public Iterator iterator() { private static class UnlabeledNodesIterator extends Iterators.FilterIterator { protected UnlabeledNodesIterator() { - super(Jenkins.getActiveInstance().getNodes().iterator()); + super(Jenkins.get().getNodes().iterator()); } @Override diff --git a/core/src/main/java/jenkins/org/apache/commons/validator/routines/UrlValidator.java b/core/src/main/java/jenkins/org/apache/commons/validator/routines/UrlValidator.java index 7ac55ed000..b6ef84b3fe 100644 --- a/core/src/main/java/jenkins/org/apache/commons/validator/routines/UrlValidator.java +++ b/core/src/main/java/jenkins/org/apache/commons/validator/routines/UrlValidator.java @@ -266,7 +266,7 @@ public UrlValidator(RegexValidator authorityValidator, long options) { } /** - * Customizable constructor. Validation behavior is modifed by passing in options. + * Customizable constructor. Validation behavior is modified by passing in options. * @param schemes the set of valid schemes. Ignored if the ALLOW_ALL_SCHEMES option is set. * @param authorityValidator Regular expression validator used to validate the authority part * @param options Validation options. Set using the public constants of this class. @@ -381,7 +381,7 @@ protected boolean isValidScheme(String scheme) { * If a RegexValidator was supplied and it matches, then the authority is regarded * as valid with no further checks, otherwise the method checks against the * AUTHORITY_PATTERN and the DomainValidator (ALLOW_LOCAL_URLS) - * @param authority Authority value to validate, alllows IDN + * @param authority Authority value to validate, allows IDN * @return true if authority (hostname and port) is valid. */ protected boolean isValidAuthority(String authority) { diff --git a/core/src/main/java/jenkins/security/ApiTokenProperty.java b/core/src/main/java/jenkins/security/ApiTokenProperty.java index b93b2860ce..fb1afcfe3a 100644 --- a/core/src/main/java/jenkins/security/ApiTokenProperty.java +++ b/core/src/main/java/jenkins/security/ApiTokenProperty.java @@ -154,7 +154,6 @@ protected void setUser(User u) { * @since 1.426, and since 1.638 the method performs security checks */ @Nonnull - @SuppressFBWarnings("NP_NONNULL_RETURN_VIOLATION") public String getApiToken() { LOGGER.log(Level.FINE, "Deprecated usage of getApiToken"); if(LOGGER.isLoggable(Level.FINER)){ diff --git a/core/src/main/java/jenkins/security/BasicHeaderProcessor.java b/core/src/main/java/jenkins/security/BasicHeaderProcessor.java index 065236829e..19d8a502ee 100644 --- a/core/src/main/java/jenkins/security/BasicHeaderProcessor.java +++ b/core/src/main/java/jenkins/security/BasicHeaderProcessor.java @@ -119,7 +119,7 @@ protected boolean authenticationIsRequired(String username) { } // Handle unusual condition where an AnonymousAuthenticationToken is already present - // This shouldn't happen very often, as BasicProcessingFitler is meant to be earlier in the filter + // This shouldn't happen very often, as BasicProcessingFilter is meant to be earlier in the filter // chain than AnonymousProcessingFilter. Nevertheless, presence of both an AnonymousAuthenticationToken // together with a BASIC authentication request header should indicate reauthentication using the // BASIC protocol is desirable. This behaviour is also consistent with that provided by form and digest, diff --git a/core/src/main/java/jenkins/security/ConfidentialKey.java b/core/src/main/java/jenkins/security/ConfidentialKey.java index f428a5a42d..8ef998a376 100644 --- a/core/src/main/java/jenkins/security/ConfidentialKey.java +++ b/core/src/main/java/jenkins/security/ConfidentialKey.java @@ -6,7 +6,8 @@ import javax.annotation.CheckForNull; import java.io.IOException; -import jenkins.slaves.JnlpSlaveAgentProtocol; + +import jenkins.slaves.JnlpAgentReceiver; /** * Confidential information that gets stored as a singleton in Jenkins, mostly some random token value. @@ -25,7 +26,7 @@ * for the secret to leak. * *

    - * The {@link ConfidentialKey} subtypes are expected to be used as a singleton, like {@link JnlpSlaveAgentProtocol#SLAVE_SECRET}. + * The {@link ConfidentialKey} subtypes are expected to be used as a singleton, like {@link JnlpAgentReceiver#SLAVE_SECRET}. * For code that relies on XStream for persistence (such as {@link Builder}s, {@link SCM}s, and other fragment objects * around builds and jobs), {@link Secret} provides more convenient way of storing secrets. * diff --git a/core/src/main/java/jenkins/security/MasterToSlaveCallable.java b/core/src/main/java/jenkins/security/MasterToSlaveCallable.java index 5f5560a1bb..2ff780689f 100644 --- a/core/src/main/java/jenkins/security/MasterToSlaveCallable.java +++ b/core/src/main/java/jenkins/security/MasterToSlaveCallable.java @@ -36,7 +36,7 @@ public Channel getChannelOrFail() throws ChannelClosedException { return ch; } - //TODO: remove once Callable#getOpenChannelOrFail() once Minimaumsupported Remoting version is 3.15 or above + //TODO: remove Callable#getOpenChannelOrFail() once minimum supported Remoting version is 3.15 or above @Override public Channel getOpenChannelOrFail() throws ChannelClosedException { final Channel ch = getChannelOrFail(); diff --git a/core/src/main/java/jenkins/security/RekeySecretAdminMonitor.java b/core/src/main/java/jenkins/security/RekeySecretAdminMonitor.java index 9276949c4b..5dcdd43582 100644 --- a/core/src/main/java/jenkins/security/RekeySecretAdminMonitor.java +++ b/core/src/main/java/jenkins/security/RekeySecretAdminMonitor.java @@ -142,7 +142,7 @@ protected void fix(TaskListener listener) throws Exception { PrintStream log = listener.getLogger(); log.println("Started re-keying " + new Date()); int count = rewriter.rewriteRecursive(Jenkins.get().getRootDir(), listener); - log.printf("Completed re-keying %d files on %s\n",count,new Date()); + log.printf("Completed re-keying %d files on %s%n",count,new Date()); new RekeySecretAdminMonitor().done.on(); LOGGER.info("Secret re-keying completed"); } catch (Exception e) { diff --git a/core/src/main/java/jenkins/security/UpdateSiteWarningsMonitor.java b/core/src/main/java/jenkins/security/UpdateSiteWarningsMonitor.java index 36dad47d25..c6d8d05a16 100644 --- a/core/src/main/java/jenkins/security/UpdateSiteWarningsMonitor.java +++ b/core/src/main/java/jenkins/security/UpdateSiteWarningsMonitor.java @@ -82,6 +82,9 @@ public class UpdateSiteWarningsMonitor extends AdministrativeMonitor { @Override public boolean isActivated() { + if (!Jenkins.get().getUpdateCenter().isSiteDataReady()) { + return false; + } return !getActiveCoreWarnings().isEmpty() || !getActivePluginWarningsByPlugin().isEmpty(); } diff --git a/core/src/main/java/jenkins/security/apitoken/ApiTokenStore.java b/core/src/main/java/jenkins/security/apitoken/ApiTokenStore.java index 4e4f4ca0ca..9fae97e9ff 100644 --- a/core/src/main/java/jenkins/security/apitoken/ApiTokenStore.java +++ b/core/src/main/java/jenkins/security/apitoken/ApiTokenStore.java @@ -190,7 +190,6 @@ private void addLegacyToken(@Nonnull Secret legacyToken, boolean migrationFromEx return new TokenUuidAndPlainValue(token.uuid, tokenTheUserWillUse); } - @SuppressFBWarnings("NP_NONNULL_RETURN_VIOLATION") private @Nonnull String plainSecretToHashInHex(@Nonnull String secretValueInPlainText) { byte[] hashBytes = plainSecretToHashBytes(secretValueInPlainText); return Util.toHexString(hashBytes); diff --git a/core/src/main/java/jenkins/security/s2m/AdminWhitelistRule.java b/core/src/main/java/jenkins/security/s2m/AdminWhitelistRule.java index 347857b32f..36d7f1881e 100644 --- a/core/src/main/java/jenkins/security/s2m/AdminWhitelistRule.java +++ b/core/src/main/java/jenkins/security/s2m/AdminWhitelistRule.java @@ -162,7 +162,7 @@ public boolean checkFileAccess(String op, File f) { @RequirePOST public HttpResponse doSubmit(StaplerRequest req) throws IOException { StringBuilder whitelist = new StringBuilder(Util.fixNull(req.getParameter("whitelist"))); - if (whitelist.charAt(whitelist.length() - 1) != '\n') + if ((whitelist.length() > 0) && (whitelist.charAt(whitelist.length() - 1) != '\n')) whitelist.append("\n"); Enumeration e = req.getParameterNames(); diff --git a/core/src/main/java/jenkins/security/s2m/ConfigDirectory.java b/core/src/main/java/jenkins/security/s2m/ConfigDirectory.java index 6356cc038e..9905d10344 100644 --- a/core/src/main/java/jenkins/security/s2m/ConfigDirectory.java +++ b/core/src/main/java/jenkins/security/s2m/ConfigDirectory.java @@ -42,8 +42,7 @@ public boolean accept(File dir, String name) { for (String fragment : fragments) { File f = new File(dir, fragment); - try { - BufferedReader reader = new BufferedReader(new FileReader(f)); + try (BufferedReader reader = new BufferedReader(new FileReader(f))) { String line; while ((line=reader.readLine())!=null) { if (line.startsWith("#")) continue; // comment diff --git a/core/src/main/java/jenkins/security/seed/UserSeedSecurityListener.java b/core/src/main/java/jenkins/security/seed/UserSeedSecurityListener.java index 8f4fbf5d54..f87449341a 100644 --- a/core/src/main/java/jenkins/security/seed/UserSeedSecurityListener.java +++ b/core/src/main/java/jenkins/security/seed/UserSeedSecurityListener.java @@ -44,15 +44,15 @@ public class UserSeedSecurityListener extends SecurityListener { @Override protected void loggedIn(@Nonnull String username) { - putUserSeedInSession(username); + putUserSeedInSession(username, true); } @Override protected void authenticated(@Nonnull UserDetails details) { - putUserSeedInSession(details.getUsername()); + putUserSeedInSession(details.getUsername(), false); } - private void putUserSeedInSession(String username) { + private static void putUserSeedInSession(String username, boolean overwriteSessionSeed) { StaplerRequest req = Stapler.getCurrentRequest(); if (req == null) { // expected case: CLI @@ -67,6 +67,10 @@ private void putUserSeedInSession(String username) { } if (!UserSeedProperty.DISABLE_USER_SEED) { + if (!overwriteSessionSeed && session.getAttribute(UserSeedProperty.USER_SESSION_SEED) != null) { + return; + } + User user = User.getById(username, true); UserSeedProperty userSeed = user.getProperty(UserSeedProperty.class); diff --git a/core/src/main/java/jenkins/slaves/DefaultJnlpSlaveReceiver.java b/core/src/main/java/jenkins/slaves/DefaultJnlpSlaveReceiver.java index 125084320c..62cebc92d6 100644 --- a/core/src/main/java/jenkins/slaves/DefaultJnlpSlaveReceiver.java +++ b/core/src/main/java/jenkins/slaves/DefaultJnlpSlaveReceiver.java @@ -113,7 +113,7 @@ public void afterProperties(@Nonnull JnlpConnectionState event) { + "Set system property " + "jenkins.slaves.DefaultJnlpSlaveReceiver.disableStrictVerification=true to allow" + "connections until the plugin has been fixed.", - new Object[]{clientName, event.getSocket().getRemoteSocketAddress(), computer.getLauncher().getClass()}); + new Object[]{clientName, event.getRemoteEndpointDescription(), computer.getLauncher().getClass()}); event.reject(new ConnectionRefusalException(String.format("%s is not an inbound agent", clientName))); return; } @@ -149,7 +149,7 @@ public void beforeChannel(@Nonnull JnlpConnectionState event) { final OutputStream log = computer.openLogFile(); state.setLog(log); PrintWriter logw = new PrintWriter(log, true); - logw.println("Inbound agent connected from " + event.getSocket().getInetAddress()); + logw.println("Inbound agent connected from " + event.getRemoteEndpointDescription()); for (ChannelConfigurator cc : ChannelConfigurator.all()) { cc.onChannelBuilding(event.getChannelBuilder(), computer); } @@ -216,5 +216,5 @@ public void setLog(@Nonnull OutputStream log) { private static final Logger LOGGER = Logger.getLogger(DefaultJnlpSlaveReceiver.class.getName()); - private static final String COOKIE_NAME = JnlpSlaveAgentProtocol2.class.getName()+".cookie"; + private static final String COOKIE_NAME = "JnlpAgentProtocol.cookie"; } diff --git a/core/src/main/java/jenkins/slaves/DeprecatedAgentProtocolMonitor.java b/core/src/main/java/jenkins/slaves/DeprecatedAgentProtocolMonitor.java deleted file mode 100644 index b2b5843587..0000000000 --- a/core/src/main/java/jenkins/slaves/DeprecatedAgentProtocolMonitor.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2017 CloudBees, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * 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.slaves; - -import hudson.Extension; -import hudson.model.AdministrativeMonitor; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import javax.annotation.CheckForNull; -import jenkins.AgentProtocol; -import jenkins.model.Jenkins; -import org.apache.commons.lang.StringUtils; -import org.jenkinsci.Symbol; -import org.kohsuke.accmod.Restricted; -import org.kohsuke.accmod.restrictions.NoExternalUse; - - -/** - * Monitors enabled protocols and warns if an {@link AgentProtocol} is deprecated. - * - * @author Oleg Nenashev - * @since 2.75 - * @see AgentProtocol - */ -@Extension -@Symbol("deprecatedAgentProtocol") -@Restricted(NoExternalUse.class) -public class DeprecatedAgentProtocolMonitor extends AdministrativeMonitor { - - public DeprecatedAgentProtocolMonitor() { - super(); - } - - @Override - public String getDisplayName() { - return Messages.DeprecatedAgentProtocolMonitor_displayName(); - } - - @Override - public boolean isActivated() { - final Set agentProtocols = Jenkins.get().getAgentProtocols(); - for (String name : agentProtocols) { - AgentProtocol pr = AgentProtocol.of(name); - if (pr != null && pr.isDeprecated()) { - return true; - } - } - return false; - } - - @Restricted(NoExternalUse.class) - public String getDeprecatedProtocols() { - String res = getDeprecatedProtocolsString(); - return res != null ? res : "N/A"; - } - - @CheckForNull - public static String getDeprecatedProtocolsString() { - final List deprecatedProtocols = new ArrayList<>(); - final Set agentProtocols = Jenkins.get().getAgentProtocols(); - for (String name : agentProtocols) { - AgentProtocol pr = AgentProtocol.of(name); - if (pr != null && pr.isDeprecated()) { - deprecatedProtocols.add(name); - } - } - if (deprecatedProtocols.isEmpty()) { - return null; - } - return StringUtils.join(deprecatedProtocols, ','); - } -} diff --git a/core/src/main/java/jenkins/slaves/EncryptedSlaveAgentJnlpFile.java b/core/src/main/java/jenkins/slaves/EncryptedSlaveAgentJnlpFile.java index bbf6570a13..1c5f13279e 100644 --- a/core/src/main/java/jenkins/slaves/EncryptedSlaveAgentJnlpFile.java +++ b/core/src/main/java/jenkins/slaves/EncryptedSlaveAgentJnlpFile.java @@ -92,7 +92,7 @@ public void generateResponse(StaplerRequest req, final StaplerResponse res, Obje if(it instanceof SlaveComputer) { jnlpMac = Util.fromHexString(((SlaveComputer)it).getJnlpMac()); } else { - jnlpMac = JnlpSlaveAgentProtocol.SLAVE_SECRET.mac(slaveName.getBytes(StandardCharsets.UTF_8)); + jnlpMac = JnlpAgentReceiver.SLAVE_SECRET.mac(slaveName.getBytes(StandardCharsets.UTF_8)); } SecretKey key = new SecretKeySpec(jnlpMac, 0, /* export restrictions */ 128 / 8, "AES"); byte[] encrypted; diff --git a/core/src/main/java/jenkins/slaves/JnlpAgentReceiver.java b/core/src/main/java/jenkins/slaves/JnlpAgentReceiver.java index 39473d75d6..b738b3316a 100644 --- a/core/src/main/java/jenkins/slaves/JnlpAgentReceiver.java +++ b/core/src/main/java/jenkins/slaves/JnlpAgentReceiver.java @@ -6,11 +6,14 @@ import hudson.model.Slave; import java.security.SecureRandom; import javax.annotation.Nonnull; + +import jenkins.agents.WebSocketAgents; +import jenkins.security.HMACConfidentialKey; import org.jenkinsci.remoting.engine.JnlpClientDatabase; import org.jenkinsci.remoting.engine.JnlpConnectionStateListener; /** - * Receives incoming agents connecting through {@link JnlpSlaveAgentProtocol2}, {@link JnlpSlaveAgentProtocol3}, {@link JnlpSlaveAgentProtocol4}. + * Receives incoming agents connecting through the likes of {@link JnlpSlaveAgentProtocol4} or {@link WebSocketAgents}. * *

    * This is useful to establish the communication with other JVMs and use them @@ -29,6 +32,12 @@ */ public abstract class JnlpAgentReceiver extends JnlpConnectionStateListener implements ExtensionPoint { + /** + * This secret value is used as a seed for agents. + */ + public static final HMACConfidentialKey SLAVE_SECRET = + new HMACConfidentialKey(JnlpSlaveAgentProtocol.class, "secret"); + private static final SecureRandom secureRandom = new SecureRandom(); public static final JnlpClientDatabase DATABASE = new JnlpAgentDatabase(); @@ -62,7 +71,7 @@ public boolean exists(String clientName) { @Override public String getSecretOf(@Nonnull String clientName) { - return JnlpSlaveAgentProtocol.SLAVE_SECRET.mac(clientName); + return SLAVE_SECRET.mac(clientName); } } } diff --git a/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol.java b/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol.java index 4a4b55e12d..f1c3e7d2fa 100644 --- a/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol.java +++ b/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol.java @@ -1,97 +1,16 @@ package jenkins.slaves; -import hudson.Extension; -import hudson.ExtensionList; -import hudson.model.Computer; -import java.io.IOException; -import java.net.Socket; -import java.util.Collections; -import java.util.logging.Logger; -import javax.inject.Inject; -import jenkins.AgentProtocol; import jenkins.security.HMACConfidentialKey; -import org.jenkinsci.Symbol; -import org.jenkinsci.remoting.engine.JnlpConnectionState; -import org.jenkinsci.remoting.engine.JnlpProtocol1Handler; /** - * {@link AgentProtocol} that accepts connection from agents. - * - *

    Security

    - *

    - * Once connected, remote agents can send in commands to be - * executed on the master, so in a way this is like an rsh service. - * Therefore, it is important that we reject connections from - * unauthorized remote agents. - * - *

    - * We do this by computing HMAC of the agent name. - * This code is sent to the agent inside the {@code .jnlp} file - * (this file itself is protected by HTTP form-based authentication that - * we use everywhere else in Jenkins), and the agent sends this - * token back when it connects to the master. - * Unauthorized agents can't access the protected {@code .jnlp} file, - * so it can't impersonate a valid agent. - * - *

    - * We don't want to force the inbound agents to be restarted - * whenever the server restarts, so right now this secret master key - * is generated once and used forever, which makes this whole scheme - * less secure. - * - * @author Kohsuke Kawaguchi - * @since 1.467 + * This class was part of the old JNLP1 protocol, which has been removed. + * The SLAVE_SECRET was still used by some plugins. It has been moved to + * JnlpAgentReceiver as a more suitable location, but this alias retained + * for compatibility. References should be updated to the new location. */ -@Extension -@Symbol("jnlp") -public class JnlpSlaveAgentProtocol extends AgentProtocol { - /** - * Our logger - */ - private static final Logger LOGGER = Logger.getLogger(JnlpSlaveAgentProtocol.class.getName()); - /** - * This secret value is used as a seed for agents. - */ - public static final HMACConfidentialKey SLAVE_SECRET = - new HMACConfidentialKey(JnlpSlaveAgentProtocol.class, "secret"); - - private NioChannelSelector hub; - - private JnlpProtocol1Handler handler; - - @Inject - public void setHub(NioChannelSelector hub) { - this.hub = hub; - this.handler = new JnlpProtocol1Handler(JnlpAgentReceiver.DATABASE, Computer.threadPoolForRemoting, - hub.getHub(), true); - } - - @Override - public boolean isOptIn() { - return true; - } - - @Override - public boolean isDeprecated() { - return true; - } - - @Override - public String getName() { - return handler.isEnabled() ? handler.getName() : null; - } - - @Override - public String getDisplayName() { - return Messages.JnlpSlaveAgentProtocol_displayName(); - } - - @Override - public void handle(Socket socket) throws IOException, InterruptedException { - handler.handle(socket, - Collections.singletonMap(JnlpConnectionState.COOKIE_KEY, JnlpAgentReceiver.generateCookie()), - ExtensionList.lookup(JnlpAgentReceiver.class)); - } +@Deprecated +public class JnlpSlaveAgentProtocol { + public static final HMACConfidentialKey SLAVE_SECRET = JnlpAgentReceiver.SLAVE_SECRET; } diff --git a/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol2.java b/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol2.java deleted file mode 100644 index d3bc1a19cb..0000000000 --- a/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol2.java +++ /dev/null @@ -1,67 +0,0 @@ -package jenkins.slaves; - -import hudson.Extension; -import hudson.ExtensionList; -import hudson.model.Computer; -import java.io.IOException; -import java.net.Socket; -import java.util.Collections; -import javax.inject.Inject; -import jenkins.AgentProtocol; -import org.jenkinsci.Symbol; -import org.jenkinsci.remoting.engine.JnlpConnectionState; -import org.jenkinsci.remoting.engine.JnlpProtocol2Handler; - -/** - * {@link JnlpSlaveAgentProtocol} Version 2. - * - *

    - * This protocol extends the version 1 protocol by adding a per-client cookie, - * so that we can detect a reconnection from the agent and take appropriate action, - * when the connection disappeared without the master noticing. - * - * @author Kohsuke Kawaguchi - * @since 1.467 - */ -@Extension -@Symbol("jnlp2") -public class JnlpSlaveAgentProtocol2 extends AgentProtocol { - private NioChannelSelector hub; - - private JnlpProtocol2Handler handler; - - @Inject - public void setHub(NioChannelSelector hub) { - this.hub = hub; - this.handler = new JnlpProtocol2Handler(JnlpAgentReceiver.DATABASE, Computer.threadPoolForRemoting, - hub.getHub(), true); - } - - @Override - public String getName() { - return handler.isEnabled() ? handler.getName() : null; - } - - @Override - public boolean isOptIn() { - return true; - } - - @Override - public boolean isDeprecated() { - return true; - } - - @Override - public String getDisplayName() { - return Messages.JnlpSlaveAgentProtocol2_displayName(); - } - - @Override - public void handle(Socket socket) throws IOException, InterruptedException { - handler.handle(socket, - Collections.singletonMap(JnlpConnectionState.COOKIE_KEY, JnlpAgentReceiver.generateCookie()), - ExtensionList.lookup(JnlpAgentReceiver.class)); - } - -} diff --git a/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol3.java b/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol3.java deleted file mode 100644 index 6866205480..0000000000 --- a/core/src/main/java/jenkins/slaves/JnlpSlaveAgentProtocol3.java +++ /dev/null @@ -1,64 +0,0 @@ -package jenkins.slaves; - -import hudson.Extension; -import hudson.ExtensionList; -import hudson.model.Computer; -import java.io.IOException; -import java.net.Socket; -import java.util.Collections; -import javax.inject.Inject; -import jenkins.AgentProtocol; -import org.jenkinsci.Symbol; -import org.jenkinsci.remoting.engine.JnlpConnectionState; -import org.jenkinsci.remoting.engine.JnlpProtocol3Handler; - -/** - * Master-side implementation for JNLP3-connect protocol. - * - *

    @see {@link org.jenkinsci.remoting.engine.JnlpProtocol3Handler} for more details. - * - * @since 1.653 - */ -@Deprecated -@Extension -@Symbol("jnlp3") -public class JnlpSlaveAgentProtocol3 extends AgentProtocol { - private NioChannelSelector hub; - - private JnlpProtocol3Handler handler; - - @Inject - public void setHub(NioChannelSelector hub) { - this.hub = hub; - this.handler = new JnlpProtocol3Handler(JnlpAgentReceiver.DATABASE, Computer.threadPoolForRemoting, - hub.getHub(), true); - } - - @Override - public boolean isOptIn() { - return true ; - } - - @Override - public String getName() { - return handler.isEnabled() ? handler.getName() : null; - } - - @Override - public String getDisplayName() { - return Messages.JnlpSlaveAgentProtocol3_displayName(); - } - - @Override - public boolean isDeprecated() { - return true; - } - - @Override - public void handle(Socket socket) throws IOException, InterruptedException { - handler.handle(socket, - Collections.singletonMap(JnlpConnectionState.COOKIE_KEY, JnlpAgentReceiver.generateCookie()), - ExtensionList.lookup(JnlpAgentReceiver.class)); - } - -} diff --git a/core/src/main/java/jenkins/util/AntClassLoader.java b/core/src/main/java/jenkins/util/AntClassLoader.java index 7e1a67d377..36588141fb 100644 --- a/core/src/main/java/jenkins/util/AntClassLoader.java +++ b/core/src/main/java/jenkins/util/AntClassLoader.java @@ -29,10 +29,10 @@ import org.apache.tools.ant.util.JavaEnvUtils; import org.apache.tools.ant.util.LoaderUtils; import org.apache.tools.ant.util.ReflectUtil; -import org.apache.tools.ant.util.VectorSet; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; +import javax.annotation.CheckForNull; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; @@ -44,10 +44,12 @@ import java.security.CodeSource; import java.security.ProtectionDomain; import java.security.cert.Certificate; +import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; +import java.util.Iterator; import java.util.Map; import java.util.NoSuchElementException; import java.util.StringTokenizer; @@ -154,7 +156,7 @@ private void findNextResource() { URL url = null; while ((pathElementsIndex < pathComponents.size()) && (url == null)) { try { - File pathComponent = (File) pathComponents.elementAt(pathElementsIndex); + File pathComponent = pathComponents.get(pathElementsIndex); url = getResourceURL(pathComponent, this.resourceName); pathElementsIndex++; } catch (BuildException e) { @@ -180,7 +182,7 @@ private void findNextResource() { * The components of the classpath that the classloader searches * for classes. */ - private Vector pathComponents = new VectorSet(); + private ArrayList pathComponents = new ArrayList<>(); /** * The project to which this class loader belongs. @@ -361,7 +363,7 @@ public void setProject(Project project) { * jar/zip files. */ public void setClassPath(Path classpath) { - pathComponents.removeAllElements(); + pathComponents.clear(); if (classpath != null) { Path actualClasspath = classpath.concatSystemClasspath("ignore"); String[] pathElements = actualClasspath.list(); @@ -473,7 +475,7 @@ public void addPathComponent(File file) { if (pathComponents.contains(file)) { return; } - pathComponents.addElement(file); + pathComponents.add(file); } /** @@ -488,7 +490,7 @@ public void addPathComponent(File file) { */ protected void addPathFile(File pathComponent) throws IOException { if (!pathComponents.contains(pathComponent)) { - pathComponents.addElement(pathComponent); + pathComponents.add(pathComponent); } if (pathComponent.isDirectory()) { return; @@ -498,19 +500,13 @@ protected void addPathFile(File pathComponent) throws IOException { + pathComponent.lastModified() + "-" + pathComponent.length(); String classpath = (String) pathMap.get(absPathPlusTimeAndLength); if (classpath == null) { - JarFile jarFile = null; - try { - jarFile = new JarFile(pathComponent); + try (JarFile jarFile = new JarFile(pathComponent)) { Manifest manifest = jarFile.getManifest(); if (manifest == null) { return; } classpath = manifest.getMainAttributes() .getValue(Attributes.Name.CLASS_PATH); - } finally { - if (jarFile != null) { - jarFile.close(); - } } if (classpath == null) { classpath = ""; @@ -548,14 +544,13 @@ protected void addPathFile(File pathComponent) throws IOException { public String getClasspath() { StringBuilder sb = new StringBuilder(); boolean firstPass = true; - Enumeration componentEnum = pathComponents.elements(); - while (componentEnum.hasMoreElements()) { + for (File pathComponent : pathComponents) { if (!firstPass) { sb.append(System.getProperty("path.separator")); } else { firstPass = false; } - sb.append(((File) componentEnum.nextElement()).getAbsolutePath()); + sb.append(pathComponent.getAbsolutePath()); } return sb.toString(); } @@ -749,14 +744,13 @@ public InputStream getResourceAsStream(String name) { private InputStream loadResource(String name) { // we need to search the components of the path to see if we can // find the class we want. - InputStream stream = null; - - Enumeration e = pathComponents.elements(); - while (e.hasMoreElements() && stream == null) { - File pathComponent = (File) e.nextElement(); - stream = getResourceStream(pathComponent, name); + for (File pathComponent : pathComponents) { + InputStream stream = getResourceStream(pathComponent, name); + if (stream != null) { + return stream; + } } - return stream; + return null; } /** @@ -858,7 +852,7 @@ private boolean isParentFirst(String resourceName) { } /** - * Used for isolated resource seaching. + * Used for isolated resource searching. * @return the root classloader of AntClassLoader. */ private ClassLoader getRootLoader() { @@ -893,14 +887,7 @@ public URL getResource(String name) { } else { // try and load from this loader if the parent either didn't find // it or wasn't consulted. - Enumeration e = pathComponents.elements(); - while (e.hasMoreElements() && url == null) { - File pathComponent = (File) e.nextElement(); - url = getResourceURL(pathComponent, name); - if (url != null) { - log("Resource " + name + " loaded from ant loader", Project.MSG_DEBUG); - } - } + url = getUrl(pathComponents, name); } if (url == null && !isParentFirst(name)) { // this loader was first but it didn't find it - try the parent @@ -919,6 +906,26 @@ public URL getResource(String name) { return url; } + /** + * Finds a matching file by iterating pathComponents. + * + * @param pathComponents Path to a folder, split into the individual folder names + * @param name File to find + * @return Url to found object + */ + @CheckForNull + protected URL getUrl(Iterable pathComponents, String name) { + URL url = null; + for (File pathComponent : pathComponents) { + url = getResourceURL(pathComponent, name); + if (url != null) { + log("Resource " + name + " loaded from ant loader", Project.MSG_DEBUG); + break; + } + } + return url; + } + /** * Finds all the resources with the given name. A resource is some * data (images, audio, text, etc) that can be accessed by class @@ -1363,9 +1370,7 @@ private Class findClassInComponents(String name) // we need to search the components of the path to see if // we can find the class we want. String classFilename = getClassFilename(name); - Enumeration e = pathComponents.elements(); - while (e.hasMoreElements()) { - File pathComponent = (File) e.nextElement(); + for (File pathComponent : pathComponents) { try (final InputStream stream = getResourceStream(pathComponent, classFilename)) { if (stream != null) { log("Loaded from " + pathComponent + " " diff --git a/core/src/main/java/jenkins/util/AntWithFindResourceClassLoader.java b/core/src/main/java/jenkins/util/AntWithFindResourceClassLoader.java index 048dbcdf1c..d0cfc53911 100644 --- a/core/src/main/java/jenkins/util/AntWithFindResourceClassLoader.java +++ b/core/src/main/java/jenkins/util/AntWithFindResourceClassLoader.java @@ -7,16 +7,15 @@ import java.io.IOException; import java.lang.reflect.Field; import java.net.URL; +import java.util.ArrayList; import java.util.Collection; -import java.util.Enumeration; -import java.util.Vector; /** * As of 1.8.0, {@link org.apache.tools.ant.AntClassLoader} doesn't implement {@link #findResource(String)} * in any meaningful way, which breaks fast lookup. Implement it properly. */ public class AntWithFindResourceClassLoader extends AntClassLoader implements Closeable { - private final Vector pathComponents; + private final ArrayList pathComponents; public AntWithFindResourceClassLoader(ClassLoader parent, boolean parentFirst) { super(parent, parentFirst); @@ -24,7 +23,7 @@ public AntWithFindResourceClassLoader(ClassLoader parent, boolean parentFirst) { try { Field $pathComponents = AntClassLoader.class.getDeclaredField("pathComponents"); $pathComponents.setAccessible(true); - pathComponents = (Vector)$pathComponents.get(this); + pathComponents = (ArrayList)$pathComponents.get(this); } catch (NoSuchFieldException | IllegalAccessException e) { throw new Error(e); } @@ -41,20 +40,9 @@ public void close() throws IOException { @Override protected URL findResource(String name) { - URL url = null; - // try and load from this loader if the parent either didn't find // it or wasn't consulted. - Enumeration e = pathComponents.elements(); - while (e.hasMoreElements() && url == null) { - File pathComponent = (File) e.nextElement(); - url = getResourceURL(pathComponent, name); - if (url != null) { - log("Resource " + name + " loaded from ant loader", Project.MSG_DEBUG); - } - } - - return url; + return getUrl(pathComponents, name); } } diff --git a/core/src/main/java/jenkins/util/HttpSessionListener.java b/core/src/main/java/jenkins/util/HttpSessionListener.java index 3e99edb713..da362483e2 100644 --- a/core/src/main/java/jenkins/util/HttpSessionListener.java +++ b/core/src/main/java/jenkins/util/HttpSessionListener.java @@ -24,6 +24,7 @@ package jenkins.util; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.ExtensionList; import hudson.ExtensionPoint; @@ -38,6 +39,7 @@ * @author tom.fennelly@gmail.com * @since 2.2 */ +@SuppressFBWarnings(value = "NM_SAME_SIMPLE_NAME_AS_INTERFACE", justification = "Should shadow HttpSessionListener") public abstract class HttpSessionListener implements ExtensionPoint, javax.servlet.http.HttpSessionListener { /** diff --git a/core/src/main/java/jenkins/util/groovy/GroovyHookScript.java b/core/src/main/java/jenkins/util/groovy/GroovyHookScript.java index 4032541fe2..638992fc20 100644 --- a/core/src/main/java/jenkins/util/groovy/GroovyHookScript.java +++ b/core/src/main/java/jenkins/util/groovy/GroovyHookScript.java @@ -46,7 +46,7 @@ public class GroovyHookScript { @Deprecated public GroovyHookScript(String hook) { - this(hook, Jenkins.getActiveInstance()); + this(hook, Jenkins.get()); } private GroovyHookScript(String hook, Jenkins j) { diff --git a/core/src/main/java/jenkins/util/io/CompositeIOException.java b/core/src/main/java/jenkins/util/io/CompositeIOException.java index dfd347cbd6..04090859f4 100644 --- a/core/src/main/java/jenkins/util/io/CompositeIOException.java +++ b/core/src/main/java/jenkins/util/io/CompositeIOException.java @@ -29,8 +29,6 @@ import javax.annotation.Nonnull; import java.io.IOException; -import java.io.PrintStream; -import java.io.PrintWriter; import java.io.UncheckedIOException; import java.util.Arrays; import java.util.List; @@ -42,6 +40,7 @@ public class CompositeIOException extends IOException { public CompositeIOException(String message, @Nonnull List exceptions) { super(message); this.exceptions = exceptions; + exceptions.forEach(this::addSuppressed); } public CompositeIOException(String message, IOException... exceptions) { @@ -52,22 +51,6 @@ public List getExceptions() { return exceptions; } - @Override - public void printStackTrace(PrintStream s) { - super.printStackTrace(s); - for (IOException exception : exceptions) { - exception.printStackTrace(s); - } - } - - @Override - public void printStackTrace(PrintWriter s) { - super.printStackTrace(s); - for (IOException exception : exceptions) { - exception.printStackTrace(s); - } - } - public UncheckedIOException asUncheckedIOException() { return new UncheckedIOException(this); } diff --git a/core/src/main/java/jenkins/util/io/PathRemover.java b/core/src/main/java/jenkins/util/io/PathRemover.java index 8fd8688b16..570a8e1877 100644 --- a/core/src/main/java/jenkins/util/io/PathRemover.java +++ b/core/src/main/java/jenkins/util/io/PathRemover.java @@ -61,7 +61,7 @@ public static PathRemover newRemoverWithStrategy(@Nonnull RetryStrategy retryStr } public static PathRemover newFilteredRobustRemover(@Nonnull PathChecker pathChecker, int maxRetries, boolean gcAfterFailedRemove, long waitBetweenRetries) { - return new PathRemover(new PausingGCRetryStrategy(maxRetries < 1 ? 1 : maxRetries, gcAfterFailedRemove, waitBetweenRetries), pathChecker); + return new PathRemover(new PausingGCRetryStrategy(Math.max(maxRetries, 0), gcAfterFailedRemove, waitBetweenRetries), pathChecker); } private final RetryStrategy retryStrategy; diff --git a/core/src/main/java/jenkins/util/java/JavaUtils.java b/core/src/main/java/jenkins/util/java/JavaUtils.java index 9d02a3bf0e..4548c58640 100644 --- a/core/src/main/java/jenkins/util/java/JavaUtils.java +++ b/core/src/main/java/jenkins/util/java/JavaUtils.java @@ -36,7 +36,7 @@ public class JavaUtils { private JavaUtils() { - // Cannnot construct + // Cannot construct } /** diff --git a/core/src/main/java/jenkins/websocket/WebSocketEcho.java b/core/src/main/java/jenkins/websocket/WebSocketEcho.java new file mode 100644 index 0000000000..5aa8b432c2 --- /dev/null +++ b/core/src/main/java/jenkins/websocket/WebSocketEcho.java @@ -0,0 +1,67 @@ +/* + * The MIT License + * + * Copyright 2019 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.websocket; + +import hudson.Extension; +import hudson.model.InvisibleAction; +import hudson.model.RootAction; +import java.nio.ByteBuffer; +import jenkins.model.Jenkins; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.NoExternalUse; +import org.kohsuke.stapler.HttpResponse; + +@Extension +@Restricted(NoExternalUse.class) +public class WebSocketEcho extends InvisibleAction implements RootAction { + + @Override + public String getUrlName() { + return "wsecho"; + } + + public HttpResponse doIndex() { + Jenkins.get().checkPermission(Jenkins.ADMINISTER); + return WebSockets.upgrade(new WebSocketSession() { + @Override + protected void text(String message) { + sendText("hello " + message); + } + @Override + protected void binary(byte[] payload, int offset, int len) { + ByteBuffer data = ByteBuffer.allocate(len); + for (int i = 0; i < len; i++) { + byte b = payload[offset + i]; + if (b >= 'a' && b <= 'z') { + b += 'A' - 'a'; + } + data.put(i, b); + } + sendBinary(data); + } + }); + } + +} diff --git a/core/src/main/java/jenkins/websocket/WebSocketSession.java b/core/src/main/java/jenkins/websocket/WebSocketSession.java new file mode 100644 index 0000000000..95a7ed7609 --- /dev/null +++ b/core/src/main/java/jenkins/websocket/WebSocketSession.java @@ -0,0 +1,150 @@ +/* + * The MIT License + * + * Copyright 2019 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.websocket; + +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import java.util.concurrent.Future; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; +import jenkins.util.SystemProperties; +import jenkins.util.Timer; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.Beta; + +/** + * One WebSocket connection. + * @see WebSockets + * @since TODO + */ +@Restricted(Beta.class) +public abstract class WebSocketSession { + + /** + * Number of seconds between server-sent pings. + * Zero to disable. + *

    nginx docs claim 60s timeout and this seems to match experiments. + * GKE docs says 30s + * but this is a total timeout, not inactivity, so you need to set {@code BackendConfigSpec.timeoutSec} anyway. + *

    This is set for the whole Jenkins session rather than a particular service, + * since it has more to do with the environment than anything else. + * Certain services may have their own “keep alive” semantics, + * but for example {@link hudson.remoting.PingThread} may be too infrequent. + */ + private static long PING_INTERVAL_SECONDS = SystemProperties.getLong("jenkins.websocket.pingInterval", 30L); + + private static final Logger LOGGER = Logger.getLogger(WebSocketSession.class.getName()); + + private Object session; + private Object remoteEndpoint; + private ScheduledFuture pings; + + protected WebSocketSession() {} + + Object onWebSocketSomething(Object proxy, Method method, Object[] args) throws Exception { + switch (method.getName()) { + case "onWebSocketConnect": + this.session = args[0]; + this.remoteEndpoint = session.getClass().getMethod("getRemote").invoke(args[0]); + if (PING_INTERVAL_SECONDS != 0) { + pings = Timer.get().scheduleAtFixedRate(() -> { + try { + remoteEndpoint.getClass().getMethod("sendPing", ByteBuffer.class).invoke(remoteEndpoint, ByteBuffer.wrap(new byte[0])); + } catch (Exception x) { + error(x); + pings.cancel(true); + } + }, PING_INTERVAL_SECONDS / 2, PING_INTERVAL_SECONDS, TimeUnit.SECONDS); + } + opened(); + return null; + case "onWebSocketClose": + if (pings != null) { + pings.cancel(true); + // alternately, check Session.isOpen each time + } + closed((Integer) args[0], (String) args[1]); + return null; + case "onWebSocketError": + error((Throwable) args[0]); + return null; + case "onWebSocketBinary": + binary((byte[]) args[0], (Integer) args[1], (Integer) args[2]); + return null; + case "onWebSocketText": + text((String) args[0]); + return null; + default: + throw new AssertionError(); + } + } + + protected void opened() { + } + + protected void closed(int statusCode, String reason) { + } + + protected void error(Throwable cause) { + LOGGER.log(Level.WARNING, "unhandled WebSocket service error", cause); + } + + protected void binary(byte[] payload, int offset, int len) { + LOGGER.warning("unexpected binary frame"); + } + + protected void text(String message) { + LOGGER.warning("unexpected text frame"); + } + + @SuppressWarnings("unchecked") + protected final Future sendBinary(ByteBuffer data) { + try { + return (Future) remoteEndpoint.getClass().getMethod("sendBytesByFuture", ByteBuffer.class).invoke(remoteEndpoint, data); + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + @SuppressWarnings("unchecked") + protected final Future sendText(String text) { + try { + return (Future) remoteEndpoint.getClass().getMethod("sendStringByFuture", String.class).invoke(remoteEndpoint, text); + } catch (Exception x) { + throw new RuntimeException(x); + } + } + + protected final void close() { + try { + session.getClass().getMethod("close").invoke(session); + } catch (Exception x) { + throw new RuntimeException(x); + } + } + +} diff --git a/core/src/main/java/jenkins/websocket/WebSockets.java b/core/src/main/java/jenkins/websocket/WebSockets.java new file mode 100644 index 0000000000..2d856d5069 --- /dev/null +++ b/core/src/main/java/jenkins/websocket/WebSockets.java @@ -0,0 +1,117 @@ +/* + * The MIT License + * + * Copyright 2019 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.websocket; + +import hudson.Extension; +import hudson.ExtensionList; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.kohsuke.accmod.Restricted; +import org.kohsuke.accmod.restrictions.Beta; +import org.kohsuke.stapler.HttpResponse; +import org.kohsuke.stapler.HttpResponses; +import org.kohsuke.stapler.Stapler; + +/** + * Support for serving WebSocket responses. + * @since TODO + */ +@Restricted(Beta.class) +@Extension +public class WebSockets { + + private static final Logger LOGGER = Logger.getLogger(WebSockets.class.getName()); + + private static final String ATTR_SESSION = WebSockets.class.getName() + ".session"; + + // TODO ability to handle subprotocols? + + public static HttpResponse upgrade(WebSocketSession session) { + return (req, rsp, node) -> { + try { + Object factory = ExtensionList.lookupSingleton(WebSockets.class).init(); + if (!((Boolean) webSocketServletFactoryClass.getMethod("isUpgradeRequest", HttpServletRequest.class, HttpServletResponse.class).invoke(factory, req, rsp))) { + throw HttpResponses.errorWithoutStack(HttpServletResponse.SC_BAD_REQUEST, "only WS connections accepted here"); + } + req.setAttribute(ATTR_SESSION, session); + if (!((Boolean) webSocketServletFactoryClass.getMethod("acceptWebSocket", HttpServletRequest.class, HttpServletResponse.class).invoke(factory, req, rsp))) { + throw HttpResponses.errorWithoutStack(HttpServletResponse.SC_BAD_REQUEST, "did not manage to upgrade"); + } + } catch (HttpResponses.HttpResponseException x) { + throw x; + } catch (Exception x) { + LOGGER.log(Level.WARNING, null, x); + throw HttpResponses.error(x); + } + // OK! + }; + } + + private static ClassLoader cl; + private static Class webSocketServletFactoryClass; + + private static synchronized void staticInit() throws Exception { + if (webSocketServletFactoryClass == null) { + cl = ServletContext.class.getClassLoader(); + webSocketServletFactoryClass = cl.loadClass("org.eclipse.jetty.websocket.servlet.WebSocketServletFactory"); + } + } + + public static boolean isSupported() { + try { + staticInit(); + return true; + } catch (Exception x) { + LOGGER.log(Level.FINE, null, x); + return false; + } + } + + private /*WebSocketServletFactory*/Object factory; + + private synchronized Object init() throws Exception { + if (factory == null) { + staticInit(); + Class webSocketPolicyClass = cl.loadClass("org.eclipse.jetty.websocket.api.WebSocketPolicy"); + factory = cl.loadClass("org.eclipse.jetty.websocket.servlet.WebSocketServletFactory$Loader").getMethod("load", ServletContext.class, webSocketPolicyClass).invoke(null, Stapler.getCurrent().getServletContext(), webSocketPolicyClass.getMethod("newServerPolicy").invoke(null)); + webSocketServletFactoryClass.getMethod("start").invoke(factory); + Class webSocketCreatorClass = cl.loadClass("org.eclipse.jetty.websocket.servlet.WebSocketCreator"); + webSocketServletFactoryClass.getMethod("setCreator", webSocketCreatorClass).invoke(factory, Proxy.newProxyInstance(cl, new Class[] {webSocketCreatorClass}, this::createWebSocket)); + } + return factory; + } + + private Object createWebSocket(Object proxy, Method method, Object[] args) throws Exception { + Object servletUpgradeRequest = args[0]; + WebSocketSession session = (WebSocketSession) servletUpgradeRequest.getClass().getMethod("getServletAttribute", String.class).invoke(servletUpgradeRequest, ATTR_SESSION); + return Proxy.newProxyInstance(cl, new Class[] {cl.loadClass("org.eclipse.jetty.websocket.api.WebSocketListener")}, session::onWebSocketSomething); + } + +} diff --git a/core/src/main/java/jenkins/widgets/HistoryPageFilter.java b/core/src/main/java/jenkins/widgets/HistoryPageFilter.java index 8a3c421064..5f01c557c2 100644 --- a/core/src/main/java/jenkins/widgets/HistoryPageFilter.java +++ b/core/src/main/java/jenkins/widgets/HistoryPageFilter.java @@ -240,13 +240,7 @@ public int compare(Object o1, Object 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; - } + return Long.compare(o2QID, o1QID); } }); } diff --git a/core/src/main/resources/_cli_it.properties b/core/src/main/resources/_cli_it.properties deleted file mode 100644 index 2f4fffffd2..0000000000 --- a/core/src/main/resources/_cli_it.properties +++ /dev/null @@ -1 +0,0 @@ -ee diff --git a/core/src/main/resources/hudson/Messages.properties b/core/src/main/resources/hudson/Messages.properties index f8804aae4f..79fb95b90f 100644 --- a/core/src/main/resources/hudson/Messages.properties +++ b/core/src/main/resources/hudson/Messages.properties @@ -75,14 +75,14 @@ ProxyConfiguration.Success=Success Functions.NoExceptionDetails=No Exception details -PluginWrapper.missing={0} version {1} is missing. To fix, install version {1} or later. -PluginWrapper.failed_to_load_plugin={0} version {1} failed to load. -PluginWrapper.failed_to_load_dependency={0} version {1} failed to load. Fix this plugin first. -PluginWrapper.disabledAndObsolete={0} version {1} is disabled and older than required. To fix, install version {2} or later and enable it. -PluginWrapper.disabled={0} is disabled. To fix, enable it. -PluginWrapper.obsolete={0} version {1} is older than required. To fix, install version {2} or later. -PluginWrapper.obsoleteCore=You must update Jenkins from version {0} to version {1} or later to run this plugin. -PluginWrapper.obsoleteJava=You must update Java from version {0} to version {1} or later to run this plugin. +PluginWrapper.missing=Plugin is missing: {0} ({1}) +PluginWrapper.failed_to_load_plugin=Failed to load: {0} ({1}) +PluginWrapper.failed_to_load_dependency=Failed to load: {0} ({1}) +PluginWrapper.disabledAndObsolete=Update required: {0} ({1}) to {2} or higher +PluginWrapper.disabled=Required plugin is disabled: {0} +PluginWrapper.obsolete=Update required: {0} ({1}) to be updated to {2} or higher +PluginWrapper.obsoleteCore=Jenkins ({1}) or higher required +PluginWrapper.obsoleteJava=Java ({1}) or higher required PluginWrapper.PluginWrapperAdministrativeMonitor.DisplayName=Plugins Failed To Load PluginWrapper.Already.Disabled=The plugin ''{0}'' was already disabled PluginWrapper.Plugin.Has.Dependent=The plugin ''{0}'' has, at least, one dependent plugin ({1}) and the disable strategy is {2}, so it cannot be disabled diff --git a/core/src/main/resources/hudson/PluginManager/_table.js b/core/src/main/resources/hudson/PluginManager/_table.js index 07da1cb58e..dee38b4e4b 100644 --- a/core/src/main/resources/hudson/PluginManager/_table.js +++ b/core/src/main/resources/hudson/PluginManager/_table.js @@ -230,8 +230,12 @@ Behaviour.specify("#filter-box", '_table', 0, function(e) { var dependencySpan = dependencySpans[i]; var pluginId = dependencySpan.getAttribute('data-plugin-id'); var depPluginTR = getPluginTR(pluginId); - var depPluginMetadata = depPluginTR.jenkinsPluginMetadata; - if (depPluginMetadata.enableInput.checked) { + var enabled = false; + if (depPluginTR) { + var depPluginMetadata = depPluginTR.jenkinsPluginMetadata; + enabled = depPluginMetadata.enableInput.checked; + } + if (enabled) { // It's enabled ... hide the span dependencySpan.setStyle({display: 'none'}); } else { @@ -354,12 +358,13 @@ Behaviour.specify("#filter-box", '_table', 0, function(e) { } // 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(); - }); + if (enableInput) { + // 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"); @@ -382,34 +387,38 @@ Behaviour.specify("#filter-box", '_table', 0, function(e) { } // 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); - }); + if (enableTD) { + 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); - }); + if (uninstallTD) { + 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++) { diff --git a/core/src/main/resources/hudson/PluginManager/installed.jelly b/core/src/main/resources/hudson/PluginManager/installed.jelly index 3fb415248a..4660aa776e 100644 --- a/core/src/main/resources/hudson/PluginManager/installed.jelly +++ b/core/src/main/resources/hudson/PluginManager/installed.jelly @@ -47,7 +47,7 @@ THE SOFTWARE. data-cannot-enable="${%This plugin cannot be enabled}" data-cannot-disable="${%This plugin cannot be disabled}" data-cannot-uninstall="${%This plugin cannot be uninstalled}" - data-disabled-dependencies="${%It has one or more disabled dependencies}" + data-disabled-dependencies="${%It has one or more unsatisfied dependencies}" data-enabled-dependents="${%It has one or more enabled dependents}" data-installed-dependents="${%It has one or more installed dependents}" data-detached-disable="${%detached-disable}" @@ -79,7 +79,7 @@ THE SOFTWARE.

    @@ -115,7 +115,15 @@ THE SOFTWARE. - + + + + + + + + +

    ${%Uninstallation pending}

    diff --git a/core/src/main/resources/hudson/PluginManager/installed_tr.properties b/core/src/main/resources/hudson/PluginManager/installed_tr.properties index 6718e29308..f99b752ca6 100644 --- a/core/src/main/resources/hudson/PluginManager/installed_tr.properties +++ b/core/src/main/resources/hudson/PluginManager/installed_tr.properties @@ -27,6 +27,6 @@ Enabled=Devrede Name=\u0130sim Uninstall=Kald\u0131r Version=Versiyon -New\ plugins\ will\ take\ effect\ once\ you\ restart\ Jenkins=Yeni eklentiler Jenkins'\u0131 bir kere yeniden ba\u015flatt\u0131ktan sonra devreye girecektir -Changes\ will\ take\ effect\ when\ you\ restart\ Jenkins=De\u011fi\u015fiklikler Jenkins'\u0131 yeniden ba\u015flatt\u0131ktan sonra devreye girecektir +New\ plugins\ will\ take\ effect\ once\ you\ restart\ Jenkins=Yeni eklentiler Jenkins'i bir kere yeniden ba\u015flatt\u0131ktan sonra devreye girecektir +Changes\ will\ take\ effect\ when\ you\ restart\ Jenkins=De\u011fi\u015fiklikler Jenkins'i yeniden ba\u015flatt\u0131ktan sonra devreye girecektir downgradeTo={0} s\u00FCr\u00FCm\u00FCne al\u00E7alt diff --git a/core/src/main/resources/hudson/PluginManager/sidepanel_tr.properties b/core/src/main/resources/hudson/PluginManager/sidepanel_tr.properties index 2625ce21b9..6ebc26bd54 100644 --- a/core/src/main/resources/hudson/PluginManager/sidepanel_tr.properties +++ b/core/src/main/resources/hudson/PluginManager/sidepanel_tr.properties @@ -21,4 +21,4 @@ # THE SOFTWARE. Back\ to\ Dashboard=Kontrol Merkezi''ne D\u00f6n -Manage\ Jenkins=Jenkins''\u0131 Y\u00f6net +Manage\ Jenkins=Jenkins''i Y\u00f6net diff --git a/core/src/main/resources/hudson/PluginManager/table.jelly b/core/src/main/resources/hudson/PluginManager/table.jelly index 2fa7d829d6..21397954ed 100644 --- a/core/src/main/resources/hudson/PluginManager/table.jelly +++ b/core/src/main/resources/hudson/PluginManager/table.jelly @@ -96,7 +96,7 @@ THE SOFTWARE.
    - +
    diff --git a/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message.jelly b/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message.jelly index 067f0c1c97..d7adbe4b57 100644 --- a/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message.jelly +++ b/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message.jelly @@ -4,12 +4,12 @@
    -

    ${%Dependency errors}:

    ${%blurbOriginal}

    +

    ${%DirectlyDependentPlugins.title}

    -
    ${plugin.longName} version ${plugin.version}
    +
    ${plugin.longName} (${plugin.version})
    ${d}
    @@ -17,12 +17,12 @@ -

    ${%Downstream dependency errors}:

    ${%blurbDerived}

    +

    ${%IndirectlyDependentPlugins.title}

    -
    ${plugin.displayName} version ${plugin.version}
    +
    ${plugin.displayName} (${plugin.version})
    ${d}
    diff --git a/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message.properties b/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message.properties index 9313dac39c..01f084bd15 100644 --- a/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message.properties +++ b/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message.properties @@ -19,5 +19,7 @@ # 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. -blurbOriginal=Some plugins could not be loaded due to unsatisfied dependencies. Fix these issues and restart Jenkins to restore the functionality provided by these plugins. -blurbDerived=These plugins failed to load because of one or more of the errors above. Fix those and these plugins will load again. +blurbOriginal=Some plugins could not be loaded due to unsatisfied dependencies. Fix these issues and restart Jenkins to re-enable these plugins. +blurbDerived=Some of the above failures also result in additional indirectly dependent plugins not being able to load. +DirectlyDependentPlugins.title=Dependency errors: +IndirectlyDependentPlugins.title=Indirectly dependent plugins: diff --git a/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message_bg.properties b/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message_bg.properties index 4c826414ea..0081ab8a84 100644 --- a/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message_bg.properties +++ b/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message_bg.properties @@ -23,5 +23,5 @@ Correct=\ \u041e\u0442\u0433\u043e\u0432\u0430\u0440\u044f # There are dependency errors loading some plugins -Dependency\ errors=\ - \u0418\u043c\u0430 \u0433\u0440\u0435\u0448\u043a\u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438\u0442\u0435 \u043d\u0430 \u043d\u044f\u043a\u043e\u0438 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0438 +DirectlyDependentPlugins.title=\ + \u0418\u043c\u0430 \u0433\u0440\u0435\u0448\u043a\u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438\u0442\u0435 \u043d\u0430 \u043d\u044f\u043a\u043e\u0438 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0438: diff --git a/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message_de.properties b/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message_de.properties index 92f7e07ee1..57dd7bca1c 100644 --- a/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message_de.properties +++ b/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message_de.properties @@ -21,4 +21,4 @@ # THE SOFTWARE. Correct=Korrigieren -Dependency\ errors=Beim Laden einiger Plugins sind Fehler aufgetreten. +DirectlyDependentPlugins.title=Beim Laden einiger Plugins sind Fehler aufgetreten: diff --git a/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message_it.properties b/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message_it.properties index 96a114d9bd..7702217297 100644 --- a/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message_it.properties +++ b/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message_it.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Dependency\ errors=Si sono verificati degli errori relativi alle dipendenze durante il caricamento di alcuni plugin +DirectlyDependentPlugins.title=Si sono verificati degli errori relativi alle dipendenze durante il caricamento di alcuni plugin: Correct=Correggi diff --git a/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message_pl.properties b/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message_pl.properties index fb0aba2425..e7a9b7523a 100644 --- a/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message_pl.properties +++ b/core/src/main/resources/hudson/PluginWrapper/PluginWrapperAdministrativeMonitor/message_pl.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. Correct=Napraw -Dependency\ errors=Wyst\u0105pi\u0142y b\u0142\u0119dy podczas \u0142adowania niekt\u00F3rych wtyczek +DirectlyDependentPlugins.title=Wyst\u0105pi\u0142y b\u0142\u0119dy podczas \u0142adowania niekt\u00F3rych wtyczek blurbOriginal=Niekt\u00F3re wtyczki nie mog\u0142y zosta\u0107 za\u0142adowane z powodu niewystarczaj\u0105cych zale\u017Cno\u015Bci. Rozwi\u0105\u017C te problemy i uruchom ponownie Jenkinsa, aby korzysta\u0107 z funkcjonalno\u015Bci oferowanych przez te wtyczki. blurbDerived=Nast\u0119puj\u0105ce wtyczki nie mog\u0142y zosta\u0107 za\u0142adowane z powodu problem\u00F3w wymienionych wy\u017Cej. Rozwi\u0105\u017C je, a wtyczki zostan\u0105 za\u0142adowane ponownie. diff --git a/core/src/main/resources/hudson/ProxyConfiguration/config.groovy b/core/src/main/resources/hudson/ProxyConfiguration/config.groovy index 8ecce1ee51..0be2a539b6 100644 --- a/core/src/main/resources/hudson/ProxyConfiguration/config.groovy +++ b/core/src/main/resources/hudson/ProxyConfiguration/config.groovy @@ -11,8 +11,8 @@ f.entry(title:_("Port"),field:"port") { f.entry(title:_("User name"),field:"userName") { f.textbox() } -f.entry(title:_("Password"),field:"password") { - f.password(value:instance?.encryptedPassword) +f.entry(title:_("Password"),field:"secretPassword") { + f.password() } f.entry(title:_("No Proxy Host"),field:"noProxyHost") { f.textarea() diff --git a/core/src/main/resources/hudson/TcpSlaveAgentListener/index.jelly b/core/src/main/resources/hudson/TcpSlaveAgentListener/index.jelly index b837be4264..1b04d3c2c9 100644 --- a/core/src/main/resources/hudson/TcpSlaveAgentListener/index.jelly +++ b/core/src/main/resources/hudson/TcpSlaveAgentListener/index.jelly @@ -40,7 +40,8 @@ THE SOFTWARE. - + + Jenkins diff --git a/core/src/main/resources/hudson/cli/CLIAction/example.jelly b/core/src/main/resources/hudson/cli/CLIAction/example.jelly index a7e6e2cc10..5a4c4cef32 100644 --- a/core/src/main/resources/hudson/cli/CLIAction/example.jelly +++ b/core/src/main/resources/hudson/cli/CLIAction/example.jelly @@ -34,6 +34,6 @@ THE SOFTWARE. } -
    java -jar jenkins-cli.jar -s ${h.inferHudsonURL(request)} ${commandArgs}
    +
    java -jar jenkins-cli.jar -s ${h.inferHudsonURL(request)} -webSocket ${commandArgs}
    diff --git a/core/src/main/resources/hudson/diagnosis/OldDataMonitor/manage_pt.properties b/core/src/main/resources/hudson/diagnosis/OldDataMonitor/manage_pt.properties index 596e528494..de3f82b6f9 100644 --- a/core/src/main/resources/hudson/diagnosis/OldDataMonitor/manage_pt.properties +++ b/core/src/main/resources/hudson/diagnosis/OldDataMonitor/manage_pt.properties @@ -26,9 +26,9 @@ Version=Vers\u00e3o Upgrade=Upgrade Resave\ data\ files\ with\ structure\ changes\ no\ newer\ than\ Jenkins=Regravar os arquivos de dados com a mudan\u00e7a de estrutura sem ser mais nova que o Jenkins blurb.2=Algumas vezes ocorre erro ao ler os dados (se o plugin adiciona algum dado que depois \u00e9 \ -desativado, se o c\u00f3digo de migra\u00e7\u00e3o n\u00e3o estiver escrito com as mudan\u00e7as de estrutura, ou se o Jenkins sofreu \ -downgraded depois de tiver escrito algum dado que \u00e9 ileg\u00edvel por uma vers\u00e3o mais antiga). \ -Esses erros s\u00e3o logados,mas o dado ileg\u00edvel ser\u00e1 ignorado, permitindo ao Jenkins iniciar e \ +desativado, se o c\u00f3digo de migra\u00e7\u00e3o n\u00e3o estiver escrito com as mudan\u00e7as de estrutura, ou se o Jenkins sofreu \ +downgraded depois de tiver escrito algum dado que \u00e9 ileg\u00edvel por uma vers\u00e3o mais antiga). \ +Esses erros s\u00e3o logados,mas o dado ileg\u00edvel ser\u00e1 ignorado, permitindo ao Jenkins iniciar e \ funcionar corretamente. Error=Erro Unreadable\ Data=Dado ileg\u00edvel diff --git a/core/src/main/resources/hudson/fsp/Messages_da.properties b/core/src/main/resources/hudson/fsp/Messages_da.properties index 5f9ad9a99e..ab915ab316 100644 --- a/core/src/main/resources/hudson/fsp/Messages_da.properties +++ b/core/src/main/resources/hudson/fsp/Messages_da.properties @@ -24,7 +24,7 @@ WorkspaceSnapshotSCM.NoSuchPermalink=Intet permalink ''{0}'' eksisterer for {1} WorkspaceSnapshotSCM.NoBuild=Der er intet kvalificeret byg til {0} permalinket i {1} WorkspaceSnapshotSCM.IncorrectJobType={0} er ikke en jobtype der har et arbejdsomr\u00e5de. WorkspaceSnapshotSCM.NoWorkspace=\ -{0} {1} har ikke noget arbejdsomr\u00e5de\u00f8jebliksbillede tilknyttet,\n\ +{0} {1} har ikke noget arbejdsomr\u00e5de\u00f8jebliksbillede tilknyttet,\n\ formentlig skyldes dette at ingen andre jobs havde behov for dette jobs arbejdsomr\u00e5de\u00f8jebliksbillede da bygget afsluttede\n\ K\u00f8r endnu et byg i {0} for at f\u00e5 taget et arbejdsomr\u00e5de\u00f8jebliksbillede. WorkspaceSnapshotSCM.NoSuchJob=Intet job ''{0}'' eksisterer. M\u00e5ske mente du ''{1}''? diff --git a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_ar.properties b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_ar.properties index f66e9b37f6..3abb203009 100644 --- a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_ar.properties +++ b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_ar.properties @@ -1,4 +1,4 @@ # This file is under the MIT License by authors -Error:\ no\ workspace=\u062E\u0637\u0627: \u0644\u0627\u064A\u0648\u062C\u062F \u0623\u064A \u0645\u0633\u0627\u062D\u0629 \u0639\u0645\u0644 +Error\:\ no\ workspace=\u062E\u0637\u0627: \u0644\u0627\u064A\u0648\u062C\u062F \u0623\u064A \u0645\u0633\u0627\u062D\u0629 \u0639\u0645\u0644 text=\u0646\u0641\u0630 \u0628\u0646\u0627\u0621 \u0644\u0643\u064A \u064A\u0646\u0634\u0623 \u062C\u0646\u0643\u0646\u0632 \u0645\u0633\u0627\u062D\u0629 \u0639\u0645\u0644. diff --git a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_ca.properties b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_ca.properties index 4684976a8f..8dae3702bb 100644 --- a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_ca.properties +++ b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_ca.properties @@ -1,4 +1,4 @@ # This file is under the MIT License by authors -Error:\ no\ workspace=Error: sense espai de treball +Error\:\ no\ workspace=Error: sense espai de treball text=Construir ara perqu\u00E8 Jenkins construeixi un espai de treball. diff --git a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_es.properties b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_es.properties index 58f2750bb3..873d4814c7 100644 --- a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_es.properties +++ b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_es.properties @@ -20,10 +20,9 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -There''s\ no\ workspace\ for\ this\ project.\ Possible\ reasons\ are:=No hay un espacio de trabajo para este proyecto. Las posibles razones son: +There''s\ no\ workspace\ for\ this\ project.\ Possible\ reasons\ are\:=No hay un espacio de trabajo para este proyecto. Las posibles razones son: li3=El directorio de trabajo ({0}) se mover fuera de Jenkins. text=Lanzar una ejecucin para que Jenkins cree el directorio de trabajo. -There''s\ no\ workspace\ for\ this\ project.\ Possible\ reasons\ are\:=No hay espacio de trabajo para este proyecto, las causas posibles son: The\ project\ was\ renamed\ recently\ and\ no\ build\ was\ done\ under\ the\ new\ name.=El proyecto se ha renombrado y no se a ejecutado desde entonces Error\:\ no\ workspace=Error, no hay espacio de trabajo The\ agent\ this\ project\ has\ run\ on\ for\ the\ last\ time\ was\ removed.=El agente donde se ejecut la ltima vez se ha eliminado diff --git a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_et.properties b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_et.properties index 96416836ec..8ad854612e 100644 --- a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_et.properties +++ b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_et.properties @@ -1,6 +1,6 @@ # This file is under the MIT License by authors -Error:\ no\ workspace=Viga: sellist t\u00F6\u00F6 keskkonda pole -There''s\ no\ workspace\ for\ this\ project.\ Possible\ reasons\ are:=Sellel projektil ei ole t\u00F6\u00F6keskkonda. V\u00F5imalikud p\u00F5hjused on: +Error\:\ no\ workspace=Viga: sellist t\u00F6\u00F6 keskkonda pole +There''s\ no\ workspace\ for\ this\ project.\ Possible\ reasons\ are\:=Sellel projektil ei ole t\u00F6\u00F6keskkonda. V\u00F5imalikud p\u00F5hjused on: li3=T\u00F6\u00F6 keskkonna kataloog {{0}} on eemaldatud v\u00E4ljaspool Jenkinsit. text=Kompileeri bild t\u00F6\u00F6 keskkonna loomiseks. diff --git a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_ko.properties b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_ko.properties index 759f87e84c..4773b9ccac 100644 --- a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_ko.properties +++ b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_ko.properties @@ -1,4 +1,4 @@ # This file is under the MIT License by authors -Error:\ no\ workspace=\uC5D0\uB7EC: \uC791\uC5C5\uACF5\uAC04\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. +Error\:\ no\ workspace=\uC5D0\uB7EC: \uC791\uC5C5\uACF5\uAC04\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. text=\uC820\uD0A8\uC2A4\uAC00 \uC791\uC5C5\uACF5\uAC04\uC744 \uB9CC\uB4E4\uAE30 \uC704\uD574 \uBE4C\uB4DC\uC2E4\uD589. diff --git a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_lt.properties b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_lt.properties index c4c43f0c11..10ca7cd673 100644 --- a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_lt.properties +++ b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_lt.properties @@ -1,4 +1,4 @@ # This file is under the MIT License by authors -Error:\ no\ workspace=Klaida: n\u0117ra darbalaukio +Error\:\ no\ workspace=Klaida: n\u0117ra darbalaukio text=Paleisti konstrukcij\u0105, kad Jenkins sukurt\u0173 darbalauk\u012F. diff --git a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_lv.properties b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_lv.properties index 6274786530..3e34d61d04 100644 --- a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_lv.properties +++ b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_lv.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -There''s\ no\ workspace\ for\ this\ project.\ Possible\ reasons\ are:=\u0160im projektam nav nevienas darbavietas. Tam var\u0113tu b\u016Bt \u0161\u0101di iemesli: +There''s\ no\ workspace\ for\ this\ project.\ Possible\ reasons\ are\:=\u0160im projektam nav nevienas darbavietas. Tam var\u0113tu b\u016Bt \u0161\u0101di iemesli: text=Palaist b\u016Bv\u0113jumu lai izveidotu darbavietu priek\u0161 Jenkins. diff --git a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_pt_PT.properties b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_pt_PT.properties index a2abb2fce8..2f8d8ff147 100644 --- a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_pt_PT.properties +++ b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_pt_PT.properties @@ -1,4 +1,4 @@ # This file is under the MIT License by authors -Error:\ no\ workspace=Erro: nenhum espa\u00E7od e trabalho +Error\:\ no\ workspace=Erro: nenhum espa\u00E7od e trabalho text=Executa um build para que o Jenkins crie um espa\u00E7o de trabalho. diff --git a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_sk.properties b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_sk.properties index 3a9ca92f10..9e867a30cd 100644 --- a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_sk.properties +++ b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_sk.properties @@ -1,6 +1,6 @@ # This file is under the MIT License by authors -Error:\ no\ workspace=Chyba: neexistuje pracovn\u00FD priestor -There''s\ no\ workspace\ for\ this\ project.\ Possible\ reasons\ are:=Neexistuje pracovn\u00FD priestor pre tento projekt. Mo\u017En\u00E9 pr\u00ED\u010Diny s\u00FA: +Error\:\ no\ workspace=Chyba: neexistuje pracovn\u00FD priestor +There''s\ no\ workspace\ for\ this\ project.\ Possible\ reasons\ are\:=Neexistuje pracovn\u00FD priestor pre tento projekt. Mo\u017En\u00E9 pr\u00ED\u010Diny s\u00FA: li3=Adres\u00E1r pracovn\u00E9ho priestoru ({0}) bol odstr\u00E1nen\u00FD mimo Jenkinsu. text=Spusti zostavenie a Jenkins vytvor\u00ED pracovn\u00FD priestor. diff --git a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_tr.properties b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_tr.properties index 3df83ba960..6d52903a1c 100644 --- a/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_tr.properties +++ b/core/src/main/resources/hudson/model/AbstractItem/noWorkspace_tr.properties @@ -20,8 +20,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -li3=\u00c7al\u0131\u015fma alan\u0131 dizini ({0}), Jenkins''\u0131n kontrol\u00fc d\u0131\u015f\u0131nda silindi. -text=Jenkins''\u0131n bir \u00e7al\u0131\u015fma alan\u0131 yaratmas\u0131 i\u00e7in bir yap\u0131land\u0131rma \u00e7al\u0131\u015ft\u0131r\u0131n. +li3=\u00c7al\u0131\u015fma alan\u0131 dizini ({0}), Jenkins''in kontrol\u00fc d\u0131\u015f\u0131nda silindi. +text=Jenkins''in bir \u00e7al\u0131\u015fma alan\u0131 yaratmas\u0131 i\u00e7in bir yap\u0131land\u0131rma \u00e7al\u0131\u015ft\u0131r\u0131n. Error\:\ no\ workspace=Hata\: \u00c7al\u0131\u015fma Alan\u0131 mevcut de\u011fil A\ project\ won't\ have\ any\ workspace\ until\ at\ least\ one\ build\ is\ performed.=Bir proje, en az\u0131ndan bir yap\u0131land\u0131rma \u00e7al\u0131\u015ft\u0131r\u0131lmadan bir \u00e7al\u0131\u015fma alan\u0131na sahip olamaz. There's\ no\ workspace\ for\ this\ project.\ Possible\ reasons\ are\:=Bu projenin bir \u00e7al\u0131\u015fma alan\u0131 yok. Muhtemel sebepler\: diff --git a/core/src/main/resources/hudson/model/AbstractProject/wipeOutWorkspaceBlocked_fr.properties b/core/src/main/resources/hudson/model/AbstractProject/wipeOutWorkspaceBlocked_fr.properties index 035978424c..b522c2f6d3 100644 --- a/core/src/main/resources/hudson/model/AbstractProject/wipeOutWorkspaceBlocked_fr.properties +++ b/core/src/main/resources/hudson/model/AbstractProject/wipeOutWorkspaceBlocked_fr.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Error:\ Wipe\ Out\ Workspace\ blocked\ by\ SCM=Erreur : La suppression de l''espace de travail a été bloquée par le SCM +Error\:\ Wipe\ Out\ Workspace\ blocked\ by\ SCM=Erreur : La suppression de l''espace de travail a été bloquée par le SCM The\ SCM\ for\ this\ project\ has\ blocked\ this\ attempt\ to\ wipe\ out\ the\ project''s\ workspace.=Le SCM de ce projet a bloqué la tentative de suppression de l''espace de travail de ce projet diff --git a/core/src/main/resources/hudson/model/AllView/newViewDetail_da.properties b/core/src/main/resources/hudson/model/AllView/newViewDetail_da.properties index aea8a97e72..af651eb07d 100644 --- a/core/src/main/resources/hudson/model/AllView/newViewDetail_da.properties +++ b/core/src/main/resources/hudson/model/AllView/newViewDetail_da.properties @@ -21,4 +21,3 @@ # THE SOFTWARE. blurb=Denne visning viser all jobs i Jenkins. -surios diff --git a/core/src/main/resources/hudson/model/AllView/noJob_tr.properties b/core/src/main/resources/hudson/model/AllView/noJob_tr.properties index 983cb8c936..d3d0413321 100644 --- a/core/src/main/resources/hudson/model/AllView/noJob_tr.properties +++ b/core/src/main/resources/hudson/model/AllView/noJob_tr.properties @@ -23,4 +23,4 @@ newJob=L\u00FCtfen ba\u015Flamak i\u00E7in yeni i\u015Fler olu\u015Fturun login=Yeni i\u015F olu\u015Fturmak i\u00E7in l\u00FCtfen giri\u015F yap\u0131n. signup=E\u011fer bir hesab\u0131n\u0131z yoksa, hemen kaydolun. -Welcome\ to\ Jenkins\!=Jenkins'a Ho\u015fgeldiniz\! +Welcome\ to\ Jenkins\!=Jenkins''e Ho\u015fgeldiniz\! diff --git a/core/src/main/resources/hudson/model/BuildAuthorizationToken/config_ko.properties b/core/src/main/resources/hudson/model/BuildAuthorizationToken/config_ko.properties index a4867282d1..5027f76760 100644 --- a/core/src/main/resources/hudson/model/BuildAuthorizationToken/config_ko.properties +++ b/core/src/main/resources/hudson/model/BuildAuthorizationToken/config_ko.properties @@ -1,5 +1,5 @@ # This file is under the MIT License by authors Trigger\ builds\ remotely=\uBE4C\uB4DC\uB97C \uC6D0\uACA9\uC73C\uB85C \uC720\uBC1C -Use\ the\ following\ URL\ to\ trigger\ build\ remotely:=\uB2E4\uC74C URL\uC744 \uC0AC\uC6A9\uD558\uC5EC \uC6D0\uACA9 \uBE4C\uB4DC \uC720\uBC1C: +Use\ the\ following\ URL\ to\ trigger\ build\ remotely\:=\uB2E4\uC74C URL\uC744 \uC0AC\uC6A9\uD558\uC5EC \uC6D0\uACA9 \uBE4C\uB4DC \uC720\uBC1C: e.g.,\ from\ scripts=\uC608: \uC2A4\uD06C\uB9BD\uD2B8 \uC0AC\uC6A9 diff --git a/core/src/main/resources/hudson/model/Computer/builds.jelly b/core/src/main/resources/hudson/model/Computer/builds.jelly index 1ef0f89f50..09a524e510 100644 --- a/core/src/main/resources/hudson/model/Computer/builds.jelly +++ b/core/src/main/resources/hudson/model/Computer/builds.jelly @@ -31,6 +31,9 @@ THE SOFTWARE. ${%title(it.displayName)} +

    + ${%disclaimer} +

    diff --git a/core/src/main/resources/hudson/model/Computer/builds.properties b/core/src/main/resources/hudson/model/Computer/builds.properties index 9e53dba33a..c7cf214409 100644 --- a/core/src/main/resources/hudson/model/Computer/builds.properties +++ b/core/src/main/resources/hudson/model/Computer/builds.properties @@ -20,4 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -title=Build History on {0} \ No newline at end of file +title=Build History on {0} +disclaimer=This history is not guaranteed to include all subtasks executed on the node, e.g. Jenkins Pipeline subtasks will not be displayed. diff --git a/core/src/main/resources/hudson/model/Computer/index_cs.properties b/core/src/main/resources/hudson/model/Computer/index_cs.properties index ac0cf2d9f9..820e6a867a 100644 --- a/core/src/main/resources/hudson/model/Computer/index_cs.properties +++ b/core/src/main/resources/hudson/model/Computer/index_cs.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Labels:=Popisky: +Labels=Popisky submit.not.temporarilyOffline=Ozna\u010Dit uzel jako do\u010Dasn\u011B nedostupn\u00FD submit.temporarilyOffline=P\u0159ipojit uzel zp\u011Bt diff --git a/core/src/main/resources/hudson/model/Computer/index_he.properties b/core/src/main/resources/hudson/model/Computer/index_he.properties index 339f1b7023..2b964eef05 100644 --- a/core/src/main/resources/hudson/model/Computer/index_he.properties +++ b/core/src/main/resources/hudson/model/Computer/index_he.properties @@ -1,5 +1,5 @@ # This file is under the MIT License by authors -Labels:=\u05EA\u05D2\u05D9\u05D5\u05EA: +Labels=\u05EA\u05D2\u05D9\u05D5\u05EA None=\u05DC\u05DC\u05D0 title.projects_tied_on=\u05E4\u05E8\u05D5\u05D9\u05D9\u05E7\u05D8\u05D9\u05DD \u05D4\u05DE\u05E7\u05D5\u05E9\u05E8\u05D9\u05DD \u05DC 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 16b6e48a21..705dbbf99a 100644 --- a/core/src/main/resources/hudson/model/Computer/index_ja.properties +++ b/core/src/main/resources/hudson/model/Computer/index_ja.properties @@ -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/index_ko.properties b/core/src/main/resources/hudson/model/Computer/index_ko.properties index 603d74658e..a8fb5c0115 100644 --- a/core/src/main/resources/hudson/model/Computer/index_ko.properties +++ b/core/src/main/resources/hudson/model/Computer/index_ko.properties @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Labels:=\uB808\uC774\uBE14 +Labels=\uB808\uC774\uBE14 None=\uC5C6\uC74C submit.not.temporarilyOffline=\uC784\uC2DC\uB85C \uB178\uB4DC \uC624\uD504\uB77C\uC778\uC73C\uB85C \uBCC0\uACBD title.projects_tied_on={0}\uC5D0 \uC5F0\uACB0\uB41C \uD504\uB85C\uC81D\uD2B8 diff --git a/core/src/main/resources/hudson/model/Computer/index_lv.properties b/core/src/main/resources/hudson/model/Computer/index_lv.properties index 35a7a4017a..54ab4aba3a 100644 --- a/core/src/main/resources/hudson/model/Computer/index_lv.properties +++ b/core/src/main/resources/hudson/model/Computer/index_lv.properties @@ -20,6 +20,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Labels:=Birkas: +Labels=Birkas None=Neveins title.projects_tied_on=Projekti, kuri piesaist\u012Bti pie {0} diff --git a/core/src/main/resources/hudson/model/Computer/index_ru.properties b/core/src/main/resources/hudson/model/Computer/index_ru.properties index 72365b9001..cc1e2c52b6 100644 --- a/core/src/main/resources/hudson/model/Computer/index_ru.properties +++ b/core/src/main/resources/hudson/model/Computer/index_ru.properties @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Labels:=\u041c\u0435\u0442\u043a\u0438: +Labels=\u041c\u0435\u0442\u043a\u0438 None=\u041d\u0435\u0442 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 submit.not.temporarilyOffline=\u041f\u043e\u043c\u0435\u0442\u0438\u0442\u044c \u044d\u0442\u043e\u0442 \u0443\u0437\u0435\u043b \u043a\u0430\u043a \u043a\u0430\u043a \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 submit.temporarilyOffline=\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0434\u0430\u043d\u043d\u044b\u0439 \u0443\u0437\u0435\u043b diff --git a/core/src/main/resources/hudson/model/Computer/index_sk.properties b/core/src/main/resources/hudson/model/Computer/index_sk.properties index d74f30e95f..c54cc0404d 100644 --- a/core/src/main/resources/hudson/model/Computer/index_sk.properties +++ b/core/src/main/resources/hudson/model/Computer/index_sk.properties @@ -1,7 +1,7 @@ # This file is under the MIT License by authors Created\ by=Vytvoren\u00FD pou\u017E\u00EDvate\u013Eom -Labels:=Zna\u010Dky: +Labels=Zna\u010Dky None=\u017Diadny submit.not.temporarilyOffline=Ozna\u010D stroj ako do\u010Dasne odpojen\u00FD title.projects_tied_on=Projekty naviazan\u00E9 na {0} diff --git a/core/src/main/resources/hudson/model/Computer/index_sv_SE.properties b/core/src/main/resources/hudson/model/Computer/index_sv_SE.properties index 829118db6f..eeb75ab584 100644 --- a/core/src/main/resources/hudson/model/Computer/index_sv_SE.properties +++ b/core/src/main/resources/hudson/model/Computer/index_sv_SE.properties @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Labels:=Etiketter +Labels=Etiketter None=Inga submit.not.temporarilyOffline=Markera noden som tillf\u00E4lligt ifr\u00E5nkopplad submit.temporarilyOffline=Noden \u00E4r online igen diff --git a/core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly b/core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly index 59973506f5..1a9a257225 100644 --- a/core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly +++ b/core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly @@ -34,7 +34,8 @@ THE SOFTWARE. - + + diff --git a/core/src/main/resources/hudson/model/ComputerSet/sidepanel_tr.properties b/core/src/main/resources/hudson/model/ComputerSet/sidepanel_tr.properties index a0e6cc0a3a..2869102c99 100644 --- a/core/src/main/resources/hudson/model/ComputerSet/sidepanel_tr.properties +++ b/core/src/main/resources/hudson/model/ComputerSet/sidepanel_tr.properties @@ -21,4 +21,4 @@ # THE SOFTWARE. Back\ to\ Dashboard=Kontrol Merkezi'ne D\u00f6n -Manage\ Jenkins=Jenkins''\u0131 Y\u00f6net +Manage\ Jenkins=Jenkins''i Y\u00f6net diff --git a/core/src/main/resources/hudson/model/Fingerprint/index_tr.properties b/core/src/main/resources/hudson/model/Fingerprint/index_tr.properties index 52c9eeb740..37d0106d8e 100644 --- a/core/src/main/resources/hudson/model/Fingerprint/index_tr.properties +++ b/core/src/main/resources/hudson/model/Fingerprint/index_tr.properties @@ -21,7 +21,7 @@ # THE SOFTWARE. introduced={0} \u00f6nce ba\u015flad\u0131 -outside\ Jenkins=Jenkins''\u0131n d\u0131\u015f\u0131nda +outside\ Jenkins=Jenkins''in d\u0131\u015f\u0131nda This\ file\ has\ not\ been\ used\ anywhere\ else.=Bu dosya ba\u015fka yerde kullan\u0131lmamaktad\u0131r. This\ file\ has\ been\ used\ in\ the\ following\ places=Bu dosya belirtilen yerlerde kullan\u0131lmaktad\u0131r Back\ to\ Dashboard=Kontrol Merkezi''ne D\u00f6n diff --git a/core/src/main/resources/hudson/model/Messages.properties b/core/src/main/resources/hudson/model/Messages.properties index b0846ca8c3..8807077497 100644 --- a/core/src/main/resources/hudson/model/Messages.properties +++ b/core/src/main/resources/hudson/model/Messages.properties @@ -206,6 +206,8 @@ Queue.WaitingForNextAvailableExecutorOn=Waiting for next available executor on \ Queue.init=Restoring the build queue Queue.node_has_been_removed_from_configuration={0} has been removed from configuration Queue.executor_slot_already_in_use=Executor slot already in use +Queue.ExceptionCanTake=Exception evaluating if the node can take the task +Queue.ExceptionCanRun=Exception evaluating if the queue can run the task ResultTrend.Aborted=Aborted ResultTrend.Failure=Failure diff --git a/core/src/main/resources/hudson/model/Messages_bg.properties b/core/src/main/resources/hudson/model/Messages_bg.properties index d6bb585efd..dc32dc706e 100644 --- a/core/src/main/resources/hudson/model/Messages_bg.properties +++ b/core/src/main/resources/hudson/model/Messages_bg.properties @@ -104,7 +104,7 @@ AbstractProject.LabelLink=\ {3,choice,0#0 \u043c\u0430\u0448\u0438\u043d\u0438|1#1 \u043c\u0430\u0448\u0438\u043d\u0430|1<{3} \u043c\u0430\u0448\u0438\u043d\u0438}{4,choice,0#|1# \u0438 1 \u043e\u0431\u043b\u0430\u043a|1< \u0438 {4} \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 + \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=\ diff --git a/core/src/main/resources/hudson/model/Messages_es.properties b/core/src/main/resources/hudson/model/Messages_es.properties index b61a753a64..91f9d7e1ed 100644 --- a/core/src/main/resources/hudson/model/Messages_es.properties +++ b/core/src/main/resources/hudson/model/Messages_es.properties @@ -120,7 +120,7 @@ Job.NOfMFailed={0} de las {1} \u00faltimas ejecuciones fallaron. Job.NoRecentBuildFailed=No hay ejecuciones recientes con fallos. Job.Pronoun=Proyecto Job.minutes=Min -Job.NoRenameWhileBuilding=No es posible renombrar un proyecto mientras se est ejecutando. +Job.NoRenameWhileBuilding=No es posible renombrar un proyecto mientras se est\u00E1 ejecutando. Label.GroupOf=grupo de {0} Label.InvalidLabel=etiqueta inv\u00e1lida @@ -135,6 +135,8 @@ Queue.Unknown=? Queue.WaitingForNextAvailableExecutor=Esperando por un ejecutor Queue.WaitingForNextAvailableExecutorOn=Esperando por un ejecutor en {0} Queue.init=Restaurando la cola de tareas +Queue.ExceptionCanTake=Excepci\u00f3n evaluando si el nodo puede coger la tarea +Queue.ExceptionCanRun=Excepci\u00f3n evaluando si la cola puede ejecutar la tarea Run.BuildAborted=La ejecuci\u00f3n fu\u00e9 cancelada Run.MarkedExplicitly=marcado para mantener el registro @@ -268,35 +270,35 @@ Run.ArtifactsPermission.Description=\ Este permiso sirve para poder utilizar los artefactos producidos en los proyectos. AbstractProject.AssignedLabelString.InvalidBooleanExpression=Expresi\u00f3n booleana incorrecta: {0} ManageJenkinsAction.DisplayName=Administrar Jenkins -Computer.NoSuchSlaveExists=El nodo {0} no existe. Quizs se est refiriendo a {1}? -ResultTrend.StillFailing=Todava falla -Computer.DisconnectPermission.Description=Este permiso permite que los usuarios puedan desconectar nodos o marcarlos como fuera de lnea. +Computer.NoSuchSlaveExists=El nodo {0} no existe. \u00BFQuiz\u00E1s se est\u00E1 refiriendo a {1}? +ResultTrend.StillFailing=Todav\u00EDa falla +Computer.DisconnectPermission.Description=Este permiso permite que los usuarios puedan desconectar nodos o marcarlos como fuera de l\u00EDnea. Computer.CreatePermission.Description=Este permiso permite que los usuarios puedan crear nuevos nodos. -ResultTrend.StillUnstable=Todava inestable +ResultTrend.StillUnstable=Todav\u00EDa inestable View.ReadPermission.Description=Este permiso permite que los usuarion puedan crear vistas (implica acceso de lectura) Hudson.RunScriptsPermission.Description=El permiso "run scripts' es necesario para ejecutar scripts de groovy usando la consola groovy o el "cli" de groovy. ResultTrend.Fixed=Arreglado ResultTrend.Failure=Fallo UpdateCenter.PluginCategory.listview-column=Columnas de la lista ResultTrend.Aborted=Cancelado -TextParameterDefinition.DisplayName=Parmetro de texto -AbstractProject.AssignedLabelString_NoMatch_DidYouMean=No hay ningn nodo que cumpla esta asignacin. Quizs se refiera a ''{1}'' en lugar de ''{0}''? +TextParameterDefinition.DisplayName=Par\u00E1metro de texto +AbstractProject.AssignedLabelString_NoMatch_DidYouMean=No hay ning\u00FAn nodo que cumpla esta asignaci\u00F3n. \u00BFQuiz\u00E1s se refiera a ''{1}'' en lugar de ''{0}''? ResultTrend.Success=Correcto AbstractProject.CancelPermission.Description=Este permiso permite que se pueda cancelar un trabajo. Run.Summary.NotBuilt=no se ha ejecutado AbstractProject.DiscoverPermission.Description=Este permiso garantiza que se pueda descubrir tareas. \ - Siendo de menos valor que el permiso de lectura, permite que puedas redireccionar a usuarios annimos a la pgina de login. \ - Sin este permiso, los usuarios annimos recibirn un error 404, no siendo capaces de descubrir esas tareas. -Jenkins.CheckDisplayName.NameNotUniqueWarning=El nombre "{0}" ya se usa para el numbre de una tarea, lo que puede producir confusin en los resultados de bsquedas. + Siendo de menos valor que el permiso de lectura, permite que puedas redireccionar a usuarios an\u00EDnimos a la p\u00E1gina de login. \ + Sin este permiso, los usuarios an\u00F3nimos recibir\u00E1n un error 404, no siendo capaces de descubrir esas tareas. +Jenkins.CheckDisplayName.NameNotUniqueWarning=El nombre "{0}" ya se usa para el numbre de una tarea, lo que puede producir confusi\u00F3n en los resultados de b\u00FAsquedas. ResultTrend.NotBuilt=Sin ejecutar ResultTrend.NowUnstable=Ahora es inestable AbstractBuild.BuildingInWorkspace=en el espacio de trabajo {0} Descriptor.From=(desde {0}) ResultTrend.Unstable=Inestable -Jenkins.CheckDisplayName.DisplayNameNotUniqueWarning=El nombre "{0}" ya se est usando en otro trabajo, pudiendo producir confusin. +Jenkins.CheckDisplayName.DisplayNameNotUniqueWarning=El nombre "{0}" ya se est\u00E1 usando en otro trabajo, pudiendo producir confusi\u00F3n. AbstractProject.WipeOutPermission.Description=Este permiso permite que se pueda borrar todo el contenido del espacio de trabajo de una tarea. -UpdateCenter.DownloadButNotActivated=Descarga correcta. Se activar en el prximo arranque. +UpdateCenter.DownloadButNotActivated=Descarga correcta. Se activar\u00E1 en el pr\u00F3ximo arranque. 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 +ParametersDefinitionProperty.DisplayName=Esta ejecuci\u00F3n debe parametrizarse diff --git a/core/src/main/resources/hudson/model/Messages_ja.properties b/core/src/main/resources/hudson/model/Messages_ja.properties index 5bb5a55d67..d26b03892d 100644 --- a/core/src/main/resources/hudson/model/Messages_ja.properties +++ b/core/src/main/resources/hudson/model/Messages_ja.properties @@ -58,8 +58,8 @@ AbstractProject.WipeOutPermission.Description=\ AbstractProject.CancelPermission.Description=\ \u30d3\u30eb\u30c9\u306e\u30ad\u30e3\u30f3\u30bb\u30eb\u3092\u8a31\u53ef\u3057\u307e\u3059\u3002 AbstractProject.AssignedLabelString.InvalidBooleanExpression=\ - \u30e9\u30d9\u30eb\u5f0f\u306b\u9593\u9055\u3044\u304c\u3042\u308a\u307e\u3059\u3002: {0} - \u8a72\u5f53\u3059\u308b\u30b9\u30ec\u30fc\u30d6\u3082\u3057\u304f\u306f\u30af\u30e9\u30a6\u30c9\u306f\u3042\u308a\u307e\u305b\u3093\u3002 + \u30e9\u30d9\u30eb\u5f0f\u306b\u9593\u9055\u3044\u304c\u3042\u308a\u307e\u3059\u3002: {0} \ + \u8a72\u5f53\u3059\u308b\u30b9\u30ec\u30fc\u30d6\u3082\u3057\u304f\u306f\u30af\u30e9\u30a6\u30c9\u306f\u3042\u308a\u307e\u305b\u3093\u3002 \ AbstractProject.CustomWorkspaceEmpty=\u30ab\u30b9\u30bf\u30e0\u30ef\u30fc\u30af\u30b9\u30da\u30fc\u30b9\u304c\u5165\u529b\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 Api.MultipleMatch=XPath "{0}" \u306f {1} \u500b\u306e\u30ce\u30fc\u30c9\u3068\u4e00\u81f4\u3057\u307e\u3057\u305f\u3002 \ diff --git a/core/src/main/resources/hudson/model/Messages_tr.properties b/core/src/main/resources/hudson/model/Messages_tr.properties index ee48426b3b..ac5fceeddf 100644 --- a/core/src/main/resources/hudson/model/Messages_tr.properties +++ b/core/src/main/resources/hudson/model/Messages_tr.properties @@ -51,7 +51,7 @@ Executor.NotAvailable=Mevcut De\u011fil FreeStyleProject.DisplayName=Serbest-stil yaz\u0131l\u0131m projesi yap\u0131land\u0131r FreeStyleProject.Description=\ - Jenkins''\u0131n merkezi \u00f6zelli\u011fi, projelerinizi yap\u0131land\u0131rman\u0131za yard\u0131m etmesidir. Bu proje t\u00fcr\u00fcn\u00fc kullanarak, \ + Jenkins''in merkezi \u00f6zelli\u011fi, projelerinizi yap\u0131land\u0131rman\u0131za yard\u0131m etmesidir. Bu proje t\u00fcr\u00fcn\u00fc kullanarak, \ herhangi bir yap\u0131land\u0131rma sistemini herhangi bir Kaynak Kodu Y\u00f6netimi arac\u0131 ile birle\u015ftirebilirsiniz,\ ve hatta yaz\u0131l\u0131m yap\u0131land\u0131rman\u0131n d\u0131\u015f\u0131nda ba\u015fka t\u00fcr projeler i\u00e7in dahi kullanabilirsiniz. @@ -97,5 +97,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 -ManageJenkinsAction.DisplayName=Jenkins''\u0131 Y\u00f6net +ManageJenkinsAction.DisplayName=Jenkins''i Y\u00f6net ParametersDefinitionProperty.DisplayName=Bu yap\u0131land\u0131rma parametrele\u015ftirilmi\u015ftir. 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 dbf2b55745..a2ef8a6b54 100644 --- a/core/src/main/resources/hudson/model/Messages_zh_TW.properties +++ b/core/src/main/resources/hudson/model/Messages_zh_TW.properties @@ -60,7 +60,7 @@ AbstractProject.WipeOutPermission.Description=\ AbstractProject.CancelPermission.Description=\ \u6388\u8207\u53d6\u6d88\u5efa\u7f6e\u7684\u80fd\u529b\u3002 AbstractProject.AssignedLabelString.InvalidBooleanExpression=\ - \u7121\u6548\u7684\u5e03\u6797\u8868\u793a\u5f0f: {0} + \u7121\u6548\u7684\u5e03\u6797\u8868\u793a\u5f0f: {0} \ \u6c92\u6709\u7b26\u5408\u7684\u7bc0\u9ede AbstractProject.CustomWorkspaceEmpty=\u81ea\u8a02\u5de5\u4f5c\u5340\u662f\u7a7a\u7684\u3002 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 5708767b80..8419f13ce0 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.jelly +++ b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.jelly @@ -51,7 +51,7 @@ THE SOFTWARE. ${%UpgradeProgress(ucData.core.version,rootURL+'/updateCenter/')} - + ${%NewVersionAvailable(ucData.core.version,ucData.core.url,changelog_url)}
    diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties similarity index 98% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties index a76332f676..115404cdf1 100644 --- a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties +++ b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message.properties @@ -22,7 +22,6 @@ NewVersionAvailable=New version of Jenkins ({0}) is available for download \ (changelog). -ChangelogUrl=${changelog.url} 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. diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_bg.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_bg.properties index fe4ef9b629..1893ad5e2f 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_bg.properties +++ b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_bg.properties @@ -20,17 +20,17 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -UpgradeProgress=\ - \u0415\u0442\u0430\u043f \u043d\u0430 \u043e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 +UpgradeProgress=\u0418\u0437\u043f\u044a\u043b\u043d\u044f\u0432\u0430 \u0441\u0435 \u043e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 \u043a\u044a\u043c Jenkins {0}. Retry=\ \u041d\u043e\u0432 \u043e\u043f\u0438\u0442 UpgradeComplete=\ - \u041e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435\u0442\u043e \u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e -UpgradeFailed=\ - \u041e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435\u0442\u043e \u0435 \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e + \u041e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435\u0442\u043e \u043a\u044a\u043c \u043d\u043e\u0432\u0430\u0442\u0430 \u0432\u0435\u0440\u0441\u0438\u044f Jenkins {0} \u043f\u0440\u0438\u043a\u043b\u044e\u0447\u0438. \u0422\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u0442\u0435. +UpgradeFailed=\u041d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 \u043a\u044a\u043c Jenkins {0}: {1}. NewVersionAvailable=\ - \u0418\u043c\u0430 \u043d\u043e\u0432\u0430 \u0432\u0435\u0440\u0441\u0438\u044f + \u041d\u043e\u0432\u0430\u0442\u0430 \u0432\u0435\u0440\u0441\u0438\u044f \u043d\u0430 Jenkins ({0}) \u0435 \u043d\u0430\u043b\u0438\u0447\u043d\u0430 \u0437\u0430 \u0438\u0437\u0442\u0435\u0433\u043b\u044f\u043d\u0435\ + (\u0441\u043f\u0438\u0441\u044a\u043a \u0441 \u043f\u0440\u043e\u043c\u0435\u043d\u0438\u0442\u0435). Or\ Upgrade\ Automatically=\ \u0418\u043b\u0438 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435 UpgradeCompleteRestartNotSupported=\ - \u041e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435\u0442\u043e \u0437\u0430\u0432\u044a\u0440\u0448\u0438, \u043d\u043e \u043d\u0435 \u0441\u0435 \u043f\u043e\u0434\u0434\u044a\u0440\u0436\u0430 \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 + \u041e\u0431\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435\u0442\u043e \u043a\u044a\u043c \u043d\u043e\u0432\u0430\u0442\u0430 \u0432\u0435\u0440\u0441\u0438\u044f Jenkins {0} \u043f\u0440\u0438\u043a\u043b\u044e\u0447\u0438. \u0422\u0440\u044f\u0431\u0432\u0430 \u0434\u0430 \u0440\u0435\u0441\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u0442\u0435. diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_cs.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_cs.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_cs.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_cs.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_da.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_da.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_da.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_da.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_de.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_de.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_de.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_de.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_es.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_es.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_es.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_es.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_et.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_et.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_et.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_et.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fi.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fi.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fi.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fi.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fr.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fr.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fr.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_fr.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_hu.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_hu.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_hu.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_hu.properties diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_it.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_it.properties index 6d4a729976..47ffb48755 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_it.properties +++ b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_it.properties @@ -20,11 +20,11 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -NewVersionAvailable=Una nuova versione di Jenkins ({0}) disponibile per il download \ - (elenco delle modifiche). +NewVersionAvailable=Una nuova versione di Jenkins ({0}) \u00e8 disponibile per il download \ + (log delle modifiche). Retry=Riprova -UpgradeCompleteRestartNotSupported=L''aggiornamento a Jenkins {0} stato completato, in attesa del riavvio. +UpgradeCompleteRestartNotSupported=Aggiornamento a Jenkins {0} completato, in attesa del riavvio. UpgradeProgress=Aggiornamento a Jenkins {0} in corso. Or\ Upgrade\ Automatically=O esegui l''aggiornamento automaticamente -UpgradeComplete=L''aggiornamento a Jenkins {0} stato completato, in attesa del riavvio. +UpgradeComplete=Aggiornamento a Jenkins {0} completato, in attesa del riavvio. UpgradeFailed=Aggiornamento a Jenkins {0} non riuscito: {1}. diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ja.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ja.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ja.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ja.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ko.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ko.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ko.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ko.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lt.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lt.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lt.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lt.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lv.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lv.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lv.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_lv.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nb_NO.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nb_NO.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nb_NO.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nb_NO.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nl.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nl.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nl.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_nl.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pl.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pl.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pl.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pl.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_BR.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_BR.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_BR.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_BR.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_PT.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_PT.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_PT.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_pt_PT.properties diff --git a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ru.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ru.properties index 0995f00f6c..7c3dc2351e 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ru.properties +++ b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_ru.properties @@ -20,7 +20,10 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -NewVersionAvailable=\u0414\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u043d\u043e\u0432\u0430\u044f \u0432\u0435\u0440\u0441\u0438\u044f +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). Retry=\u041f\u043e\u0432\u0442\u043e\u0440\u0438\u0442\u044c -UpgradeComplete=\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u043e +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. UpgradeFailed=\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c +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 +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. +UpgradeProgress=\u041e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 Jenkins {0} \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0438\u043b\u0438 \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u043b\u043e\u0441\u044c \u043d\u0435\u0443\u0434\u0430\u0447\u0435\u0439. diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sk.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sk.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sk.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sk.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sl.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sl.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sl.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sl.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sv_SE.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sv_SE.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sv_SE.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_sv_SE.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_uk.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_uk.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_uk.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_uk.properties diff --git a/core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_TW.properties b/core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_TW.properties similarity index 100% rename from core/src/filter/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_TW.properties rename to core/src/main/resources/hudson/model/UpdateCenter/CoreUpdateMonitor/message_zh_TW.properties diff --git a/core/src/main/resources/hudson/model/UpdateCenter/body_tr.properties b/core/src/main/resources/hudson/model/UpdateCenter/body_tr.properties index 925baf803b..e7340c9577 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/body_tr.properties +++ b/core/src/main/resources/hudson/model/UpdateCenter/body_tr.properties @@ -1,5 +1,5 @@ # This file is under the MIT License by authors Go\ back\ to\ the\ top\ page=\u00DCst sayfaya geri d\u00F6n -warning=Y\u00FCkleme tamamland\u0131\u011F\u0131nda ve bekleyen bir i\u015F yoksa Jenkins''\u0131 yeniden ba\u015Flat. +warning=Y\u00FCkleme tamamland\u0131\u011F\u0131nda ve bekleyen bir i\u015F yoksa Jenkins''i yeniden ba\u015Flat. you\ can\ start\ using\ the\ installed\ plugins\ right\ away=Kurulmu\u015F eklentileri kullanmaya hemen ba\u015Flayabilirsiniz diff --git a/core/src/main/resources/hudson/model/UpdateCenter/sidepanel_tr.properties b/core/src/main/resources/hudson/model/UpdateCenter/sidepanel_tr.properties index 57b9f40ed0..56c5438119 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/sidepanel_tr.properties +++ b/core/src/main/resources/hudson/model/UpdateCenter/sidepanel_tr.properties @@ -21,5 +21,5 @@ # THE SOFTWARE. Back\ to\ Dashboard=Kontrol Merkezi''ne D\u00F6n -Manage\ Jenkins=Jenkins''\u0131 Y\u00F6net +Manage\ Jenkins=Jenkins''i Y\u00F6net Manage\ Plugins=Eklentileri y\u00F6net diff --git a/core/src/main/resources/hudson/model/User/builds.jelly b/core/src/main/resources/hudson/model/User/builds.jelly index cae284074b..5f9d042f95 100644 --- a/core/src/main/resources/hudson/model/User/builds.jelly +++ b/core/src/main/resources/hudson/model/User/builds.jelly @@ -30,6 +30,10 @@ THE SOFTWARE. ${%title(it)} +

    + ${%disclaimer} +

    + diff --git a/core/src/main/resources/hudson/model/User/builds.properties b/core/src/main/resources/hudson/model/User/builds.properties index b3a7cb0edc..efbcf60db2 100644 --- a/core/src/main/resources/hudson/model/User/builds.properties +++ b/core/src/main/resources/hudson/model/User/builds.properties @@ -20,3 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. title=Builds for {0} +disclaimer=This does not include stages from pipeline jobs. diff --git a/core/src/main/resources/hudson/model/View/builds.jelly b/core/src/main/resources/hudson/model/View/builds.jelly index 398ccff65f..536f47c88a 100644 --- a/core/src/main/resources/hudson/model/View/builds.jelly +++ b/core/src/main/resources/hudson/model/View/builds.jelly @@ -32,6 +32,9 @@ THE SOFTWARE. ${%buildHistory(it.class.name=='hudson.model.AllView' ? app.displayName : it.displayName)} +

    + ${%disclaimer} +

    diff --git a/core/src/main/resources/hudson/model/View/builds.properties b/core/src/main/resources/hudson/model/View/builds.properties index b65bd65a59..9d25cb555e 100644 --- a/core/src/main/resources/hudson/model/View/builds.properties +++ b/core/src/main/resources/hudson/model/View/builds.properties @@ -20,4 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -buildHistory=Build History of {0} \ No newline at end of file +buildHistory=Build History of {0} +disclaimer=This history is not guaranteed to include all subtasks executed on the node, e.g. Jenkins Pipeline subtasks will not be displayed. diff --git a/core/src/main/resources/hudson/model/View/configure.jelly b/core/src/main/resources/hudson/model/View/configure.jelly index 5d1193b409..8f2364c7b8 100644 --- a/core/src/main/resources/hudson/model/View/configure.jelly +++ b/core/src/main/resources/hudson/model/View/configure.jelly @@ -52,7 +52,7 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/hudson/model/queue/_api.jelly b/core/src/main/resources/hudson/model/queue/_api.jelly new file mode 100644 index 0000000000..453f2e5114 --- /dev/null +++ b/core/src/main/resources/hudson/model/queue/_api.jelly @@ -0,0 +1,17 @@ + + + +

    Canceling the build of an item in the Queue

    +

    + To programmatically cancel the build of an item in the Queue, post to this URL. + The id of the item to cancel is expected. + + Response will be: +

      +
    • 204 if the run tied with the given id was successfully cancelled
    • +
    • 422 if the provided id does not exist or match an item that cannot be cancelled
    • +
    • 500 if the provided id exists but Jenkins could not cancel the run
    • +
    +

    + +
    \ No newline at end of file diff --git a/core/src/main/resources/hudson/scheduler/Messages_de.properties b/core/src/main/resources/hudson/scheduler/Messages_de.properties index 2ae265b481..28fb211420 100644 --- a/core/src/main/resources/hudson/scheduler/Messages_de.properties +++ b/core/src/main/resources/hudson/scheduler/Messages_de.properties @@ -23,7 +23,7 @@ BaseParser.StartEndReversed=Meinten Sie {0}-{1}? BaseParser.MustBePositive=Schrittweite muss positiv sein, ist aber {0} BaseParser.OutOfRange={0} ist ein ungltiger Wert. Muss zwischen {1} und {2} liegen. -CronTab.do_you_really_mean_every_minute_when_you=Meinen sie mit \u201E{0}\u201C wirklich \u201Ejede Minute\u201C? Vielleicht meinen Sie eher \u201E{1}\u201C +CronTab.do_you_really_mean_every_minute_when_you=Meinen Sie mit \u201E{0}\u201C wirklich \u201Ejede Minute\u201C? Vielleicht meinen Sie eher \u201E{1}\u201C CronTab.short_cycles_in_the_day_of_month_field_w=Kleine Schrittweiten im Tag-Feld fhren am Monatsende zu Unregelmigkeiten. CronTab.spread_load_evenly_by_using_rather_than_=Verwenden Sie zur gleichmigen Lastverteilung \u201E{0}\u201C statt \u201E{1}\u201C CronTabList.InvalidInput=Ungltige Eingabe: \u201E{0}\u201C: {1} diff --git a/core/src/main/resources/hudson/security/FullControlOnceLoggedInAuthorizationStrategy/help_tr.html b/core/src/main/resources/hudson/security/FullControlOnceLoggedInAuthorizationStrategy/help_tr.html index 942af29935..35ed338f46 100644 --- a/core/src/main/resources/hudson/security/FullControlOnceLoggedInAuthorizationStrategy/help_tr.html +++ b/core/src/main/resources/hudson/security/FullControlOnceLoggedInAuthorizationStrategy/help_tr.html @@ -5,7 +5,7 @@

    Bu mod, kullanıcları, aksiyon almak için giriş yapmaya zorlar. Böylece kimin ne yaptığı ile ilgili kayıtları tutabilirsiniz. Bu ayarı açmanın bir sebebi de - Jenkins'ı public olarak kullanıma açmış olmaktır. Bu şekilde, sadece güvenilir + Jenkins'i public olarak kullanıma açmış olmaktır. Bu şekilde, sadece güvenilir kullanıcların kullanıcı hesapları olur, diğer tüm herkes kullanıcı girişi yapmadan (anonymous olarak) kullanır.

    \ No newline at end of file diff --git a/core/src/main/resources/hudson/security/GlobalSecurityConfiguration/config_tr.properties b/core/src/main/resources/hudson/security/GlobalSecurityConfiguration/config_tr.properties index abbb44ecbb..a8a0f390c1 100644 --- a/core/src/main/resources/hudson/security/GlobalSecurityConfiguration/config_tr.properties +++ b/core/src/main/resources/hudson/security/GlobalSecurityConfiguration/config_tr.properties @@ -21,7 +21,7 @@ # THE SOFTWARE. slaves.description=\ - Bu master Jenkins'a kaydolmu\u015f slave nodlar\u0131n listesidir. B\u00fcy\u00fck i\u015flerin idare edilebilmesi i\u00e7in i\u015fler\ + Bu master Jenkins'e kaydolmu\u015f slave nodlar\u0131n listesidir. B\u00fcy\u00fck i\u015flerin idare edilebilmesi i\u00e7in i\u015fler\ slave nodlarda \u00e7al\u0131\u015ft\u0131r\u0131lmak \u00fczere ayarlanabilir. no.such.JDK=Herhangi bir JDK yok Home\ directory=Ana dizin diff --git a/core/src/main/resources/hudson/security/GlobalSecurityConfiguration/help-useSecurity_tr.html b/core/src/main/resources/hudson/security/GlobalSecurityConfiguration/help-useSecurity_tr.html index 651dab0aef..70a68be87f 100644 --- a/core/src/main/resources/hudson/security/GlobalSecurityConfiguration/help-useSecurity_tr.html +++ b/core/src/main/resources/hudson/security/GlobalSecurityConfiguration/help-useSecurity_tr.html @@ -6,12 +6,12 @@ $TOMCAT_HOME/conf/tomcat-users.xml dosyası dikkate alınır)

    - Jenkins'ı intranet (veya başka "güvenilir" bir ortamda) içerisinde kullanıyorsanız, bu kutucuğu + Jenkins'i intranet (veya başka "güvenilir" bir ortamda) içerisinde kullanıyorsanız, bu kutucuğu işaretlemeyebilirsiniz. Bu durumda proje sahipleri, sizi rahatsız etmeden projelerini yapılandırabilirler.

    - Jenkins'ı internete açacaksanız, güvenliği mutlaka devreye alın. Jenkins'ın çalıştırdığı işlemleri + Jenkins'i internete açacaksanız, güvenliği mutlaka devreye alın. Jenkins'in çalıştırdığı işlemleri düşünürseniz, güvenlik ayarı olamayan bir Jenkins, hacklenmenin kesin bir yoludur.

    diff --git a/core/src/main/resources/hudson/security/GlobalSecurityConfiguration/index.groovy b/core/src/main/resources/hudson/security/GlobalSecurityConfiguration/index.groovy index 8a28265d1a..6e19623d43 100644 --- a/core/src/main/resources/hudson/security/GlobalSecurityConfiguration/index.groovy +++ b/core/src/main/resources/hudson/security/GlobalSecurityConfiguration/index.groovy @@ -25,14 +25,21 @@ l.layout(norefresh:true, permission:app.ADMINISTER, title:my.displayName, csscla set("instance",my) set("descriptor", my.descriptor) - f.optionalBlock( field:"useSecurity", title:_("Enable security"), checked:app.useSecurity) { + f.section(title:_("Authentication")) { f.entry() { f.checkbox(title:_("Disable remember me"), field: "disableRememberMe") } - f.entry(title:_("Access Control")) { + f.entry(title:_("Security Realm")) { table(style:"width:100%") { f.descriptorRadioList(title:_("Security Realm"),varName:"realm", instance:app.securityRealm, descriptors:h.filterDescriptors(app, SecurityRealm.all())) + } + } + } + + f.section(title:_("Authorization")) { + f.entry(title:_("Strategy")) { + table(style:"width:100%") { f.descriptorRadioList(title:_("Authorization"), varName:"authorization", instance:app.authorizationStrategy, descriptors:h.filterDescriptors(app, AuthorizationStrategy.all())) } } diff --git a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/index_tr.properties b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/index_tr.properties index 027da6ee70..2cffc93a78 100644 --- a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/index_tr.properties +++ b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/index_tr.properties @@ -21,7 +21,7 @@ # THE SOFTWARE. blurb=\ -Bu kullan\u0131c\u0131vlar Jenkins'da oturum a\u00e7abilir. Bu liste, buradakinin bir \u00fcst k\u00fcmesidir, +Bu kullan\u0131c\u0131vlar Jenkins''de oturum a\u00e7abilir. Bu liste, buradakinin bir \u00fcst k\u00fcmesidir, \ ayn\u0131 zamanda baz\u0131 projelerde commit i\u015flemi yapan, fakat direk Jenkins eri\u015fimi olmayan ve otomatik olarak yarat\u0131lan \ kullan\u0131c\u0131lar\u0131 da i\u00e7erir Name=\u0130sim diff --git a/core/src/main/resources/hudson/security/LegacyAuthorizationStrategy/help_tr.html b/core/src/main/resources/hudson/security/LegacyAuthorizationStrategy/help_tr.html index 492da226ab..f42f63b82d 100644 --- a/core/src/main/resources/hudson/security/LegacyAuthorizationStrategy/help_tr.html +++ b/core/src/main/resources/hudson/security/LegacyAuthorizationStrategy/help_tr.html @@ -1,5 +1,5 @@

    - Jenkins'ın 1.164 sürümünden önceki güvenlik davranışıdır. Yani, kullanıcı "admin" + Jenkins'in 1.164 sürümünden önceki güvenlik davranışıdır. Yani, kullanıcı "admin" rolünde ise Jenkins üzerinde tam kontrole sahiptir, aksi takdirde sadece okuma hakkına sahip olacaktır.
    \ No newline at end of file diff --git a/core/src/main/resources/hudson/security/LegacySecurityRealm/help_tr.html b/core/src/main/resources/hudson/security/LegacySecurityRealm/help_tr.html index 592048fca3..ff43926126 100644 --- a/core/src/main/resources/hudson/security/LegacySecurityRealm/help_tr.html +++ b/core/src/main/resources/hudson/security/LegacySecurityRealm/help_tr.html @@ -4,10 +4,10 @@
    1. - Jenkins'ı 1.164'ten önceki bir versiyonundan beri kullanıyor ve davranış şeklini değiştirmek istemiyorsanız. + Jenkins'i 1.164'ten önceki bir versiyonundan beri kullanıyor ve davranış şeklini değiştirmek istemiyorsanız.
    2. - Container'ınızı doğru güvenlik ayarları ile konfigüre ettiyseniz ve Jenkins'ının da buna uymasını istiyorsanız. + Container'ınızı doğru güvenlik ayarları ile konfigüre ettiyseniz ve Jenkins'in de buna uymasını istiyorsanız. (Bazı durumlarda, container, kullanıcının kullanmak istediği güvenlik metodu için daha iyi dokümantasyon veya daha kendine has altyapı sağlayabilir)
    3. diff --git a/core/src/main/resources/hudson/security/Messages.properties b/core/src/main/resources/hudson/security/Messages.properties index 06df37e231..03774c8251 100644 --- a/core/src/main/resources/hudson/security/Messages.properties +++ b/core/src/main/resources/hudson/security/Messages.properties @@ -69,3 +69,5 @@ PAMSecurityRealm.Uid=uid: {0} # not in use Permission.Permissions.Title=N/A AccessDeniedException2.MissingPermission={0} is missing the {1} permission + +NoneSecurityRealm.DisplayName=None diff --git a/core/src/main/resources/hudson/slaves/JNLPLauncher/config.jelly b/core/src/main/resources/hudson/slaves/JNLPLauncher/config.jelly index d0765ddb5b..6b33de6b80 100644 --- a/core/src/main/resources/hudson/slaves/JNLPLauncher/config.jelly +++ b/core/src/main/resources/hudson/slaves/JNLPLauncher/config.jelly @@ -28,6 +28,9 @@ THE SOFTWARE. + + + diff --git a/core/src/main/resources/hudson/slaves/JNLPLauncher/help-webSocket.html b/core/src/main/resources/hudson/slaves/JNLPLauncher/help-webSocket.html new file mode 100644 index 0000000000..90f5c28f90 --- /dev/null +++ b/core/src/main/resources/hudson/slaves/JNLPLauncher/help-webSocket.html @@ -0,0 +1,4 @@ +
      + Use WebSocket to connect to the Jenkins master rather than the TCP port. + See JEP-222 for background. +
      diff --git a/core/src/main/resources/hudson/slaves/JNLPLauncher/main.jelly b/core/src/main/resources/hudson/slaves/JNLPLauncher/main.jelly index 1348373933..404e30b9f0 100644 --- a/core/src/main/resources/hudson/slaves/JNLPLauncher/main.jelly +++ b/core/src/main/resources/hudson/slaves/JNLPLauncher/main.jelly @@ -25,7 +25,7 @@ THE SOFTWARE. - +
      ${%slaveAgentPort.disabled} ${%configure.link.text}. diff --git a/core/src/main/resources/hudson/slaves/JNLPLauncher/main_fr.properties b/core/src/main/resources/hudson/slaves/JNLPLauncher/main_fr.properties index e0bca578cf..60428c5489 100644 --- a/core/src/main/resources/hudson/slaves/JNLPLauncher/main_fr.properties +++ b/core/src/main/resources/hudson/slaves/JNLPLauncher/main_fr.properties @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Run\ from\ agent\ command\ line:=Ex\u00E9cuter l''esclave \u00E0 partir de l\u2019interpr\u00E8te de commandes +Run\ from\ agent\ command\ line\:=Ex\u00E9cuter l''esclave \u00E0 partir de l\u2019interpr\u00E8te de commandes launch\ agent=lancer l''agent -Connect\ agent\ to\ Jenkins\ one\ of\ these\ ways:=Connecter l''esclave \u00E0 Jenkins avec l''une des mani\u00E8res suivantes: +Connect\ agent\ to\ Jenkins\ one\ of\ these\ ways\:=Connecter l''esclave \u00E0 Jenkins avec l''une des mani\u00E8res suivantes: Connected\ via\ JNLP\ agent.=Connect\u00E9 via l\u2019agent JNLP. diff --git a/core/src/main/resources/hudson/slaves/JNLPLauncher/main_ru.properties b/core/src/main/resources/hudson/slaves/JNLPLauncher/main_ru.properties index 0fc4329cd2..174db0d3b7 100644 --- a/core/src/main/resources/hudson/slaves/JNLPLauncher/main_ru.properties +++ b/core/src/main/resources/hudson/slaves/JNLPLauncher/main_ru.properties @@ -21,5 +21,5 @@ # THE SOFTWARE. Connected\ via\ JNLP\ agent.=\u041F\u043E\u0434\u043A\u043B\u044E\u0447\u0435\u043D \u0447\u0435\u0440\u0435\u0437 JNLP \u0430\u0433\u0435\u043D\u0442\u0430. -Run\ from\ agent\ command\ line:=\u0412\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u0432 \u043A\u043E\u043C\u043C\u0430\u043D\u0434\u043D\u043E\u0439 \u0441\u0442\u0440\u043E\u043A\u0435 \u043F\u043E\u0434\u0447\u0438\u043D\u0435\u043D\u043D\u043E\u0433\u043E \u0443\u0437\u043B\u0430 +Run\ from\ agent\ command\ line\:=\u0412\u044B\u043F\u043E\u043B\u043D\u0438\u0442\u044C \u0432 \u043A\u043E\u043C\u043C\u0430\u043D\u0434\u043D\u043E\u0439 \u0441\u0442\u0440\u043E\u043A\u0435 \u043F\u043E\u0434\u0447\u0438\u043D\u0435\u043D\u043D\u043E\u0433\u043E \u0443\u0437\u043B\u0430 launch\ agent=\u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u0430\u0433\u0435\u043D\u0442\u0430 diff --git a/core/src/main/resources/hudson/slaves/SlaveComputer/slave-agent.jnlp.jelly b/core/src/main/resources/hudson/slaves/SlaveComputer/slave-agent.jnlp.jelly index e07b789741..173a897e9c 100644 --- a/core/src/main/resources/hudson/slaves/SlaveComputer/slave-agent.jnlp.jelly +++ b/core/src/main/resources/hudson/slaves/SlaveComputer/slave-agent.jnlp.jelly @@ -63,6 +63,9 @@ THE SOFTWARE. ${it.jnlpMac} ${it.node.nodeName} + + -webSocket + -tunnel ${launcher.tunnel} diff --git a/core/src/main/resources/hudson/slaves/SlaveComputer/systemInfo.jelly b/core/src/main/resources/hudson/slaves/SlaveComputer/systemInfo.jelly index 279fc74807..8fa1b2ba2f 100644 --- a/core/src/main/resources/hudson/slaves/SlaveComputer/systemInfo.jelly +++ b/core/src/main/resources/hudson/slaves/SlaveComputer/systemInfo.jelly @@ -45,7 +45,7 @@ THE SOFTWARE. -

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

      +

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

      ${instance.displayName}

      diff --git a/core/src/main/resources/hudson/tasks/ArtifactArchiver/help_de.html b/core/src/main/resources/hudson/tasks/ArtifactArchiver/help_de.html index 90cbe1a22a..3676704431 100644 --- a/core/src/main/resources/hudson/tasks/ArtifactArchiver/help_de.html +++ b/core/src/main/resources/hudson/tasks/ArtifactArchiver/help_de.html @@ -3,7 +3,7 @@ diese zu einem späteren Zeitpunkt heruntergeladen werden können. Archivierte Dateien sind über die Jenkins Web-Oberfläche erreichbar.
      - Normalerweise bewahrt Jenkins die Artefakte eines Builds so lange auf wie die + Normalerweise bewahrt Jenkins die Artefakte eines Builds so lange auf, wie die Protokolldatei des Builds existiert. Sollten Sie alte Artefakte hingegen nicht mehr benötigen und lieber Speicherplatz sparen wollen, so können Sie die Artefakte löschen. diff --git a/core/src/main/resources/hudson/tasks/Fingerprinter/FingerprintAction/index_tr.properties b/core/src/main/resources/hudson/tasks/Fingerprinter/FingerprintAction/index_tr.properties index d0cf7759c6..44fef2038c 100644 --- a/core/src/main/resources/hudson/tasks/Fingerprinter/FingerprintAction/index_tr.properties +++ b/core/src/main/resources/hudson/tasks/Fingerprinter/FingerprintAction/index_tr.properties @@ -25,5 +25,5 @@ File=Dosya Original\ owner=Orijinal sahibi Age=Ya\u015f more\ details=daha fazla detay -outside\ Jenkins=Jenkins'\u0131n d\u0131\u015f\u0131nda +outside\ Jenkins=Jenkins'in d\u0131\u015f\u0131nda this\ build=bu yap\u0131land\u0131rma diff --git a/core/src/main/resources/hudson/tasks/Fingerprinter/help_de.html b/core/src/main/resources/hudson/tasks/Fingerprinter/help_de.html index 5416a58285..a138d3e21d 100644 --- a/core/src/main/resources/hudson/tasks/Fingerprinter/help_de.html +++ b/core/src/main/resources/hudson/tasks/Fingerprinter/help_de.html @@ -25,7 +25,7 @@

      Um dieses Merkmal zu nützen, müssen alle Projekte (also nicht nur das Projekt, in dem eine Datei produziert wird, sondern alle Projekte, welche - die Datei verwenden) diese Funktion verenden und Fingerabdrücke aufzeichnen. + die Datei verwenden) diese Funktion verwenden und Fingerabdrücke aufzeichnen.

      Weitere Informationen (auf Englisch)

      diff --git a/core/src/main/resources/hudson/triggers/SCMTrigger/help_tr.html b/core/src/main/resources/hudson/triggers/SCMTrigger/help_tr.html index f2fb31adf4..eba539be5e 100644 --- a/core/src/main/resources/hudson/triggers/SCMTrigger/help_tr.html +++ b/core/src/main/resources/hudson/triggers/SCMTrigger/help_tr.html @@ -1,5 +1,5 @@
      - Jenkins'ın konfigürasyonunu SCM'deki değişiklikleri kontrol edecek şekilde ayarla. + Jenkins'in konfigürasyonunu SCM'deki değişiklikleri kontrol edecek şekilde ayarla.

      Unutmayın, bu işlem CVS için biraz yüklü olacaktır, çünkü her kontrolde Jenkins tüm çalışma alanını diff --git a/core/src/main/resources/hudson/triggers/TimerTrigger/help_tr.html b/core/src/main/resources/hudson/triggers/TimerTrigger/help_tr.html index 8d257bd71c..3dfa2fbb6b 100644 --- a/core/src/main/resources/hudson/triggers/TimerTrigger/help_tr.html +++ b/core/src/main/resources/hudson/triggers/TimerTrigger/help_tr.html @@ -3,14 +3,14 @@ gibi çalıştırabilmeyi sağlar.

      - Jenkins'ı cron'un alternatifi olarak kullanmak için tasarlanmıştır ve kesinlikle + Jenkins'i cron'un alternatifi olarak kullanmak için tasarlanmıştır ve kesinlikle sürekli yapılandırılan yazılım projeleri için değildir. Sürekli entegrasyon metodu olarak, düzenli gecelik/haftalık yapılandırmalar planlanabilir. Bu özellik de bu amaç için kullanılabilse de, sürekli entegrasyonun asıl noktasının herhangi bir değişiklik olur olmaz yapılandırmanın başlatılması olduğu ve bu değişikliğe ait geri bildirimin çabucak verilmesi gerektiği unutulmamalıdır. - Bunun için SCM değişikliklerini Jenkins'a bildirecek mekanizmanın + Bunun için SCM değişikliklerini Jenkins'e bildirecek mekanizmanın ayarlanması gerekir.

      Yani, bu özelliği kullanmadan önce yapmak istediğinizin bu yöntem ile mi yapılması gerektiğini sorgulayın. diff --git a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_tr.properties b/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_tr.properties index d948c8628d..4b953c3a65 100644 --- a/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_tr.properties +++ b/core/src/main/resources/hudson/util/DoubleLaunchChecker/index_tr.properties @@ -22,7 +22,7 @@ message=\ Jenkins, ''{0}'' dizinini kullanan birden fazla Jenkins uygulamas\u0131 oldu\u011funu belirledi.\ - Bu Jenkins''\u0131n garip davran\u0131\u015flar sergilemesine sebep olabilir, durumu en k\u0131sa zamanda d\u00fczeltin + Bu Jenkins''in garip davran\u0131\u015flar sergilemesine sebep olabilir, durumu en k\u0131sa zamanda d\u00fczeltin Error=Hata This\ Jenkins=Bu Jenkins Other\ Jenkins=Di\u011fer Jenkins diff --git a/core/src/main/resources/hudson/util/HudsonIsLoading/index.jelly b/core/src/main/resources/hudson/util/HudsonIsLoading/index.jelly index 11f826607f..bc3dc56f1a 100644 --- a/core/src/main/resources/hudson/util/HudsonIsLoading/index.jelly +++ b/core/src/main/resources/hudson/util/HudsonIsLoading/index.jelly @@ -31,7 +31,7 @@ THE SOFTWARE. - + ${h.initPageVariables(context)} diff --git a/core/src/main/resources/hudson/util/HudsonIsRestarting/index.jelly b/core/src/main/resources/hudson/util/HudsonIsRestarting/index.jelly index a372dda355..de7874d9df 100644 --- a/core/src/main/resources/hudson/util/HudsonIsRestarting/index.jelly +++ b/core/src/main/resources/hudson/util/HudsonIsRestarting/index.jelly @@ -31,7 +31,7 @@ THE SOFTWARE. - + ${h.initPageVariables(context)} diff --git a/core/src/main/resources/hudson/util/IncompatibleAntVersionDetected/index_tr.properties b/core/src/main/resources/hudson/util/IncompatibleAntVersionDetected/index_tr.properties index 6e188f6c42..82603e686f 100644 --- a/core/src/main/resources/hudson/util/IncompatibleAntVersionDetected/index_tr.properties +++ b/core/src/main/resources/hudson/util/IncompatibleAntVersionDetected/index_tr.properties @@ -21,9 +21,9 @@ # THE SOFTWARE. errorMessage=\ - Jenkins''\u0131n \u00fczerinde y\u00fcr\u00fct\u00fcld\u00fc\u011f\u00fc servlet container''\u0131n eski bir Ant versiyonu y\u00fckledi\u011fi tespit edildi,\ - bu da Jenkins''\u0131n kendi, daha yeni kopyas\u0131n\u0131 y\u00fcklemesini engelliyor.\ + Jenkins''in \u00fczerinde y\u00fcr\u00fct\u00fcld\u00fc\u011f\u00fc servlet container''\u0131n eski bir Ant versiyonu y\u00fckledi\u011fi tespit edildi,\ + bu da Jenkins''in kendi, daha yeni kopyas\u0131n\u0131 y\u00fcklemesini engelliyor.\ (Ant s\u0131n\u0131flar\u0131 {0} i\u00e7erisinden y\u00fckleniyor}
      \ - Container i\u00e7erisindeki kopyay\u0131 Jenkins''\u0131n WEB-INF/lib dizinindeki ile ezmeniz gerekebilir,\ - veya classloader''\u0131 delegasyonunu Jenkins''a vererek, Jenkins''\u0131n kendi kopyas\u0131n\u0131 y\u00fcklemesini sa\u011flayabilirsiniz. + Container i\u00e7erisindeki kopyay\u0131 Jenkins''in WEB-INF/lib dizinindeki ile ezmeniz gerekebilir,\ + veya classloader''\u0131 delegasyonunu Jenkins''e vererek, Jenkins''in kendi kopyas\u0131n\u0131 y\u00fcklemesini sa\u011flayabilirsiniz. Error=Hata diff --git a/core/src/main/resources/hudson/util/InsufficientPermissionDetected/index_pt_BR.properties b/core/src/main/resources/hudson/util/InsufficientPermissionDetected/index_pt_BR.properties index 16fe5d4ceb..82059ee248 100644 --- a/core/src/main/resources/hudson/util/InsufficientPermissionDetected/index_pt_BR.properties +++ b/core/src/main/resources/hudson/util/InsufficientPermissionDetected/index_pt_BR.properties @@ -29,7 +29,7 @@ # way to fix the problem is simply to turn the security manager off. errorMessage.1=N\u00f3s detectamos que o Jenkins n\u00e3 tem permiss\u00f5es suficiente para executar. \ como indicado pela informa\u00e7\u00e3o abaixo. Normalmente a causa desse problema \ -est\u00e1 no gerenciador de seguran\u00e7a. Se voc\u00ea n\u00e3o sabe como configurar o gerenciador \ +est\u00e1 no gerenciador de seguran\u00e7a. Se voc\u00ea n\u00e3o sabe como configurar o gerenciador \ de seguran\u00e7a, poder\u00e1 desativ\u00e1-lo. Error=Erro # \ diff --git a/core/src/main/resources/hudson/win32errors.properties b/core/src/main/resources/hudson/win32errors.properties index 9286f38bef..8d62add911 100644 --- a/core/src/main/resources/hudson/win32errors.properties +++ b/core/src/main/resources/hudson/win32errors.properties @@ -2034,7 +2034,7 @@ Cannot complete this function error1004= \ Invalid flags error1005= \ -The volume does not contain a recognized file system. +The volume does not contain a recognized file system. \ Please make sure that all required file system drivers are loaded and that the volume is not corrupted error1006= \ The volume for a file has been externally altered so that the opened file is no longer valid diff --git a/core/src/main/resources/hudson/win32errors_es.properties b/core/src/main/resources/hudson/win32errors_es.properties index 6b74c728b1..80c3d006bf 100644 --- a/core/src/main/resources/hudson/win32errors_es.properties +++ b/core/src/main/resources/hudson/win32errors_es.properties @@ -2034,7 +2034,7 @@ Cannot complete this function error1004= \ Invalid flags error1005= \ -The volume does not contain a recognized file system. +The volume does not contain a recognized file system. \ Please make sure that all required file system drivers are loaded and that the volume is not corrupted error1006= \ The volume for a file has been externally altered so that the opened file is no longer valid diff --git a/core/src/main/resources/hudson/win32errors_it.properties b/core/src/main/resources/hudson/win32errors_it.properties index d9bab2dd69..5ac8c7c0eb 100644 --- a/core/src/main/resources/hudson/win32errors_it.properties +++ b/core/src/main/resources/hudson/win32errors_it.properties @@ -1384,4 +1384,3 @@ error679= \ Errore sconosciuto (0x2a7) error680= \ Errore sconosciuto (0x2a8) -error681 diff --git a/core/src/main/resources/jenkins/install/SetupWizard/authenticate-security-token_de.properties b/core/src/main/resources/jenkins/install/SetupWizard/authenticate-security-token_de.properties index 9b666c0bc3..41a9e47caa 100644 --- a/core/src/main/resources/jenkins/install/SetupWizard/authenticate-security-token_de.properties +++ b/core/src/main/resources/jenkins/install/SetupWizard/authenticate-security-token_de.properties @@ -23,7 +23,7 @@ authenticate-security-token.error=FEHLER: authenticate-security-token.getting.started= authenticate-security-token.password.administrator=Administrator-Passwort -authenticate-security-token.copy.password=Bitte kopieren Sie dass Passwort von einer dieser Quellen und f\u00FCgen Sie es unten ein. +authenticate-security-token.copy.password=Bitte kopieren Sie das Passwort von einer dieser Quellen und f\u00FCgen Sie es unten ein. authenticate-security-token.unlock.jenkins=Jenkins entsperren authenticate-security-token.continue=Weiter jenkins.install.findSecurityTokenMessage=Um sicher zu stellen, dass Jenkins von einem autorisierten Administrator sicher initialisiert wird, wurde ein zuf\u00E4llig generiertes Passwort in das Log\ diff --git a/core/src/main/resources/jenkins/install/platform-plugins.json b/core/src/main/resources/jenkins/install/platform-plugins.json index 43c0c79cb9..f791b4e586 100644 --- a/core/src/main/resources/jenkins/install/platform-plugins.json +++ b/core/src/main/resources/jenkins/install/platform-plugins.json @@ -68,7 +68,6 @@ { "name": "p4" }, { "name": "repo" }, { "name": "subversion", "suggested": true }, - { "name": "teamconcert" }, { "name": "tfs" } ] }, diff --git a/core/src/main/resources/jenkins/management/Messages.properties b/core/src/main/resources/jenkins/management/Messages.properties index ce99fecf14..8e5e595a83 100644 --- a/core/src/main/resources/jenkins/management/Messages.properties +++ b/core/src/main/resources/jenkins/management/Messages.properties @@ -50,7 +50,7 @@ CliLink.Description=Access/manage Jenkins from your shell, or from your script. ConsoleLink.DisplayName=Script Console ConsoleLink.Description=Executes arbitrary script for administration/trouble-shooting/diagnostics. -NodesLink.DisplayName=Manage Nodes +NodesLink.DisplayName=Manage Nodes and Clouds NodesLink.Description=Add, remove, control and monitor the various nodes that Jenkins runs jobs on. ShutdownLink.DisplayName_prepare=Prepare for Shutdown diff --git a/core/src/main/resources/jenkins/management/Messages_nb_NO.properties b/core/src/main/resources/jenkins/management/Messages_nb_NO.properties index af5b743d7b..0321ca51e6 100644 --- a/core/src/main/resources/jenkins/management/Messages_nb_NO.properties +++ b/core/src/main/resources/jenkins/management/Messages_nb_NO.properties @@ -26,7 +26,7 @@ NodesLink.Description=Legg til, fjern, kontroller og overv\u00E5k de forskjellig PluginsLink.Description=Legg til, fjern, deaktivere eller aktivere programtillegg som kan utvide funksjonaliteten til Jenkins. ConfigureLink.DisplayName=Konfigurere systemet ConfigureLink.Description=Konfigurere globale verdier og stier -CliLink.DisplayName (Command Line Interface - Kommandolinjegrensesnitt) +CliLink.DisplayName=Command Line Interface - Kommandolinjegrensesnitt CliLink.Description=F\u00E5 tilgang til/styr Jenkins fra et shell eller skript. StatisticsLink.DisplayName=Serverlast-statistikk StatisticsLink.Description=Kontroller ressursutnyttelsen og se om du trenger flere datamaskiner for dine bygg. diff --git a/core/src/main/resources/jenkins/management/Messages_tr.properties b/core/src/main/resources/jenkins/management/Messages_tr.properties index dd80796a86..677e1ce113 100644 --- a/core/src/main/resources/jenkins/management/Messages_tr.properties +++ b/core/src/main/resources/jenkins/management/Messages_tr.properties @@ -22,7 +22,7 @@ # THE SOFTWARE. # -SystemLogLink.Description=Sistem logu Jenkins''la ilgili olan java.util.logging \u00E7\u0131kt\u0131lar\u0131n\u0131 yakalar. +SystemLogLink.Description=Sistem logu Jenkins''le ilgili olan java.util.logging \u00E7\u0131kt\u0131lar\u0131n\u0131 yakalar. ReloadLink.DisplayName=Konfig\u00FCrasayonu Disk''ten Y\u00FCkle ReloadLink.Description=Haf\u0131zada tutulan yap\u0131lm\u0131\u015F t\u00FCm de\u011Fi\u015Fiklikleri iptal et ve her\u015Feyi dosya sisteminden y\u00FCkle.\n\ Konfig\u00FCrasyon dosyalar\u0131n\u0131 do\u011Frudan diskten de\u011Fi\u015Ftirdiyseniz kullan\u0131\u015Fl\u0131d\u0131r diff --git a/core/src/main/resources/jenkins/model/BuildDiscarderProperty/help_tr.html b/core/src/main/resources/jenkins/model/BuildDiscarderProperty/help_tr.html index 8af15246d5..fd68839b0f 100644 --- a/core/src/main/resources/jenkins/model/BuildDiscarderProperty/help_tr.html +++ b/core/src/main/resources/jenkins/model/BuildDiscarderProperty/help_tr.html @@ -1,15 +1,15 @@

      - Bu kısım, yapılandırmaların kayıtlarını tutma sürelerinizi yöneterek Jenkins'ın disk + Bu kısım, yapılandırmaların kayıtlarını tutma sürelerinizi yöneterek Jenkins'in disk kullanımını kontrol eder (konsol çıktısı, yapılandırma artefaktları gibi).
      Jenkins bu yönetim için iki kriter sunar:
      1. - Tarih ile yönetme. Jenkins'ın belli bir tarihe ulaşmış dosyaları silmesini sağlayabilirsiniz. + Tarih ile yönetme. Jenkins'in belli bir tarihe ulaşmış dosyaları silmesini sağlayabilirsiniz. (mesela, 7 günlük olanlar)
      2. - Sayı ile yönetme. Jenkins'ın N yapılandırmayı yönetmesini sağlayabilirsiniz. N sayısına ulaşıldığında, yeni bir yapılandırma, + Sayı ile yönetme. Jenkins'in N yapılandırmayı yönetmesini sağlayabilirsiniz. N sayısına ulaşıldığında, yeni bir yapılandırma, en eski yapılandırmanın kayıtlarını siler.
      diff --git a/core/src/main/resources/jenkins/model/CoreEnvironmentContributor/buildEnv.groovy b/core/src/main/resources/jenkins/model/CoreEnvironmentContributor/buildEnv.groovy index 015f433e9d..090610ce76 100644 --- a/core/src/main/resources/jenkins/model/CoreEnvironmentContributor/buildEnv.groovy +++ b/core/src/main/resources/jenkins/model/CoreEnvironmentContributor/buildEnv.groovy @@ -3,7 +3,7 @@ package jenkins.model.CoreEnvironmentContributor def l = namespace(lib.JenkinsTagLib) // also advertises those contributed by Run.getCharacteristicEnvVars() -["BUILD_NUMBER","BUILD_ID","BUILD_DISPLAY_NAME","JOB_NAME", "JOB_BASE_NAME","BUILD_TAG","EXECUTOR_NUMBER","NODE_NAME","NODE_LABELS","WORKSPACE","JENKINS_HOME","JENKINS_URL","BUILD_URL","JOB_URL"].each { name -> +["BUILD_NUMBER","BUILD_ID","BUILD_DISPLAY_NAME","JOB_NAME", "JOB_BASE_NAME","BUILD_TAG","EXECUTOR_NUMBER","NODE_NAME","NODE_LABELS","WORKSPACE","WORKSPACE_TMP","JENKINS_HOME","JENKINS_URL","BUILD_URL","JOB_URL"].each { name -> l.buildEnvVar(name:name) { raw(_("${name}.blurb")) } diff --git a/core/src/main/resources/jenkins/model/CoreEnvironmentContributor/buildEnv.properties b/core/src/main/resources/jenkins/model/CoreEnvironmentContributor/buildEnv.properties index b244378815..f41589973d 100644 --- a/core/src/main/resources/jenkins/model/CoreEnvironmentContributor/buildEnv.properties +++ b/core/src/main/resources/jenkins/model/CoreEnvironmentContributor/buildEnv.properties @@ -12,6 +12,9 @@ EXECUTOR_NUMBER.blurb=\ NODE_NAME.blurb=Name of the agent if the build is on an agent, or "master" if run on master NODE_LABELS.blurb=Whitespace-separated list of labels that the node is assigned. WORKSPACE.blurb=The absolute path of the directory assigned to the build as a workspace. +WORKSPACE_TMP.blurb=\ + A temporary directory near the workspace that will not be browsable and will not interfere with SCM checkouts. \ + May not initially exist, so be sure to create the directory as needed (e.g., mkdir -p on Linux). JENKINS_HOME.blurb=The absolute path of the directory assigned on the master node for Jenkins to store data. JENKINS_URL.blurb=Full URL of Jenkins, like http://server:port/jenkins/ (note: only available if Jenkins URL set in system configuration) BUILD_URL.blurb=Full URL of this build, like http://server:port/jenkins/job/foo/15/ (Jenkins URL must be set) diff --git a/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config.groovy b/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config.groovy deleted file mode 100644 index ac31668d48..0000000000 --- a/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config.groovy +++ /dev/null @@ -1,16 +0,0 @@ -package jenkins.model.GlobalCloudConfiguration - -import hudson.slaves.Cloud - -def f=namespace(lib.FormTagLib) - -def clouds = Cloud.all() - -if (!clouds.isEmpty()) { - f.section(title:_("Cloud")) { - f.block { - f.hetero_list(name:"cloud", hasHeader:true, descriptors:Cloud.all(), items:app.clouds, - addCaption:_("Add a new cloud"), deleteCaption:_("Delete cloud")) - } - } -} diff --git a/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index.groovy b/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index.groovy new file mode 100644 index 0000000000..0d0657763e --- /dev/null +++ b/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index.groovy @@ -0,0 +1,51 @@ +package jenkins.model.GlobalCloudConfiguration + +import hudson.slaves.Cloud + + +def f = namespace(lib.FormTagLib) +def l = namespace(lib.LayoutTagLib) +def st = namespace("jelly:stapler") + +l.layout(norefresh:true, permission:app.ADMINISTER, title:my.displayName) { + l.side_panel { + l.tasks { + l.task(icon:"icon-up icon-md", href:rootURL+'/', title:_("Back to Dashboard")) + l.task(icon:"icon-gear2 icon-md", href:"${rootURL}/computer/", title:_("Manage Nodes")) + } + } + l.main_panel { + h1 { + l.icon(class: 'icon-health-40to59 icon-xlg') + // TODO more appropriate icon + text(my.displayName) + } + + def clouds = Cloud.all() + + if (!clouds.isEmpty()) { + p() + div(class:"behavior-loading", _("LOADING")) + + f.form(method:"post",name:"config",action:"configure") { + f.block { + f.hetero_list(name:"cloud", hasHeader:true, descriptors:Cloud.all(), items:app.clouds, + addCaption:_("Add a new cloud"), deleteCaption:_("Delete cloud")) + } + + f.bottomButtonBar { + f.submit(value:_("Save")) + f.apply(value:_("Apply")) + } + } + st.adjunct(includes: "lib.form.confirm") + } else { + p { + _("There are no cloud implementations for dynamically allocated agents installed.") + a(href: rootURL + "/pluginManager/available") { + _("Go to plugin manager.") + } + } + } + } +} diff --git a/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_da.properties b/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_da.properties similarity index 100% rename from core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_da.properties rename to core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_da.properties diff --git a/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_de.properties b/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_de.properties similarity index 100% rename from core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_de.properties rename to core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_de.properties diff --git a/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_es.properties b/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_es.properties similarity index 100% rename from core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_es.properties rename to core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_es.properties diff --git a/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_fr.properties b/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_fr.properties similarity index 100% rename from core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_fr.properties rename to core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_fr.properties diff --git a/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_it.properties b/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_it.properties similarity index 100% rename from core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_it.properties rename to core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_it.properties diff --git a/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_ja.properties b/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_ja.properties similarity index 100% rename from core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_ja.properties rename to core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_ja.properties diff --git a/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_pt_BR.properties b/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_pt_BR.properties similarity index 100% rename from core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_pt_BR.properties rename to core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_pt_BR.properties diff --git a/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_sr.properties b/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_sr.properties similarity index 100% rename from core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_sr.properties rename to core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_sr.properties diff --git a/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_zh_TW.properties b/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_zh_TW.properties similarity index 100% rename from core/src/main/resources/jenkins/model/GlobalCloudConfiguration/config_zh_TW.properties rename to core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index_zh_TW.properties diff --git a/core/src/main/resources/jenkins/model/GlobalQuietPeriodConfiguration/help-quietPeriod_tr.html b/core/src/main/resources/jenkins/model/GlobalQuietPeriodConfiguration/help-quietPeriod_tr.html index 58b51fbe5c..e124b298b6 100644 --- a/core/src/main/resources/jenkins/model/GlobalQuietPeriodConfiguration/help-quietPeriod_tr.html +++ b/core/src/main/resources/jenkins/model/GlobalQuietPeriodConfiguration/help-quietPeriod_tr.html @@ -14,7 +14,7 @@
    4. Eğer Jenkins, çok fazla yapılandırma ile uğraşıyorsa, sessiz periyodu uzatmak, - Jenkins'ı yükünü ve yapılandırma sayısını azaltacaktır. + Jenkins'i yükünü ve yapılandırma sayısını azaltacaktır.
    5. Proje-seviyesinde belirlenmez ise, sistemdeki varolan değer alınır. diff --git a/core/src/main/resources/jenkins/model/Jenkins/_cloud-note.groovy b/core/src/main/resources/jenkins/model/Jenkins/_cloud-note.groovy new file mode 100644 index 0000000000..9b4a929d97 --- /dev/null +++ b/core/src/main/resources/jenkins/model/Jenkins/_cloud-note.groovy @@ -0,0 +1,19 @@ +package jenkins.model.Jenkins + +import hudson.slaves.Cloud + +// TODO remove this once it's been long enough that users got used to this. + +def f = namespace(lib.FormTagLib) + +def clouds = Cloud.all() + +if (!clouds.isEmpty()) { + f.section(title: _("Cloud")) { + f.block { + div(class: 'alert alert-info') { + raw(_("note", rootURL)) + } + } + } +} diff --git a/core/src/main/resources/jenkins/model/Jenkins/_cloud-note.properties b/core/src/main/resources/jenkins/model/Jenkins/_cloud-note.properties new file mode 100644 index 0000000000..d9cada5eb8 --- /dev/null +++ b/core/src/main/resources/jenkins/model/Jenkins/_cloud-note.properties @@ -0,0 +1 @@ +note=The cloud configuration has moved to a separate configuration page. diff --git a/core/src/main/resources/jenkins/model/Jenkins/configure.jelly b/core/src/main/resources/jenkins/model/Jenkins/configure.jelly index a6154bbc4e..a85ab58ade 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/configure.jelly +++ b/core/src/main/resources/jenkins/model/Jenkins/configure.jelly @@ -52,6 +52,8 @@ THE SOFTWARE. + + diff --git a/core/src/main/resources/jenkins/model/Jenkins/fingerprintCheck_bg.properties b/core/src/main/resources/jenkins/model/Jenkins/fingerprintCheck_bg.properties index f3c3260e49..b5ca36cd29 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/fingerprintCheck_bg.properties +++ b/core/src/main/resources/jenkins/model/Jenkins/fingerprintCheck_bg.properties @@ -31,7 +31,7 @@ Check\ File\ Fingerprint=\ # Find that out by checking the fingerprint against \ # the database in Jenkins description=\ - \u041d\u0435 \u0437\u043d\u0430\u0435\u0442\u0435 \u0432\u0435\u0440\u0441\u0438\u044f\u0442\u0430 \u043d\u0430 \u043d\u044f\u043a\u043e\u0439 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u0435\u043d \u201e.jar\u201c \u0444\u0430\u0439\u043b?
      + \u041d\u0435 \u0437\u043d\u0430\u0435\u0442\u0435 \u0432\u0435\u0440\u0441\u0438\u044f\u0442\u0430 \u043d\u0430 \u043d\u044f\u043a\u043e\u0439 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u0435\u043d \u201e.jar\u201c \u0444\u0430\u0439\u043b?
      \ \u041f\u0440\u043e\u0432\u0435\u0440\u0435\u0442\u0435 \u0437\u0430 \u0446\u0438\u0444\u0440\u043e\u0432\u0438\u044f \u043c\u0443 \u043e\u0442\u043f\u0435\u0447\u0430\u0442\u044a\u043a \u0432 \u0431\u0430\u0437\u0430\u0442\u0430 \u043d\u0430 Jenkins. # https://jenkins.io/redirect/fingerprint fingerprint.link=\ diff --git a/core/src/main/resources/jenkins/model/Jenkins/fingerprintCheck_cs.properties b/core/src/main/resources/jenkins/model/Jenkins/fingerprintCheck_cs.properties index e31d158af4..21554b3384 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/fingerprintCheck_cs.properties +++ b/core/src/main/resources/jenkins/model/Jenkins/fingerprintCheck_cs.properties @@ -3,7 +3,7 @@ Check=Ov\u011B\u0159it Check\ File\ Fingerprint=Ov\u011B\u0159it otisk souboru File\ to\ check=Soubor k ov\u011B\u0159en\u00ED -description=M\u00E1te jar soubor ale nev\u00EDte k jak\u00E9 verzi pat\u0159\u00ED?
      +description=M\u00E1te jar soubor ale nev\u00EDte k jak\u00E9 verzi pat\u0159\u00ED?
      \ Ov\u011B\u0159te si jej v Jenkinsov\u011B datab\u00E1zi otisk\u016F fingerprint.link=https://jenkins.io/redirect/fingerprint more\ details=dal\u0161\u00ED informace diff --git a/core/src/main/resources/jenkins/model/Jenkins/fingerprintCheck_da.properties b/core/src/main/resources/jenkins/model/Jenkins/fingerprintCheck_da.properties index 09123b2192..c7f395b6d7 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/fingerprintCheck_da.properties +++ b/core/src/main/resources/jenkins/model/Jenkins/fingerprintCheck_da.properties @@ -24,7 +24,7 @@ Check\ File\ Fingerprint=Check filfingeraftryk File\ to\ check=Fil der skal checkes fingerprint.link=https://jenkins.io/redirect/fingerprint description=\ -Har du f\u00e5et en jar fil, men ved ikke hvilken version den har?
      \ +Har du f\u00e5et en jar fil, men ved ikke hvilken version den har?
      \ Find ud af det ved at checke imod filfingeraftryksdatabasen i Jenkins more\ details=flere detaljer Check=Check diff --git a/core/src/main/resources/jenkins/model/Jenkins/login.jelly b/core/src/main/resources/jenkins/model/Jenkins/login.jelly index e3eaaee00f..c65dd137b9 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/login.jelly +++ b/core/src/main/resources/jenkins/model/Jenkins/login.jelly @@ -40,7 +40,7 @@ THE SOFTWARE. without it we would add ";jsessionid=" to the url which will result in a 404 --> - + ${h.initPageVariables(context)} diff --git a/core/src/main/resources/jenkins/model/Jenkins/manage_tr.properties b/core/src/main/resources/jenkins/model/Jenkins/manage_tr.properties index b22e438404..bbcdc89662 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/manage_tr.properties +++ b/core/src/main/resources/jenkins/model/Jenkins/manage_tr.properties @@ -20,5 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -Manage\ Jenkins=Jenkins''\u0131 Y\u00F6net +Manage\ Jenkins=Jenkins''i Y\u00F6net are.you.sure={0}: emin misin? diff --git a/core/src/main/resources/jenkins/model/Jenkins/projectRelationship-help_et.properties b/core/src/main/resources/jenkins/model/Jenkins/projectRelationship-help_et.properties index f16d6f0955..9967d4a849 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/projectRelationship-help_et.properties +++ b/core/src/main/resources/jenkins/model/Jenkins/projectRelationship-help_et.properties @@ -1,6 +1,6 @@ # This file is under the MIT License by authors -For\ this\ feature\ to\ work,\ the\ following\ conditions\ need\ to\ be\ met:=Selle funktsiooni t\u00F6\u00F6tamiseks peavad olema t\u00E4idetud j\u00E4rgnevad tingimused: +For\ this\ feature\ to\ work,\ the\ following\ conditions\ need\ to\ be\ met\:=Selle funktsiooni t\u00F6\u00F6tamiseks peavad olema t\u00E4idetud j\u00E4rgnevad tingimused: The\ downstream\ project\ records\ the\ fingerprints\ of\ the\ upstream\ files\ it\ uses.=Allavoolu projekt salvestab nende \u00FClesvoolu failide s\u00F5rmej\u00E4ljed mida ta kasutab. The\ upstream\ project\ records\ the\ fingerprints\ of\ its\ build\ artifacts.=\u00DClesvoolu projekt salvestab oma j\u00E4rkude tulemuste s\u00F5rmej\u00E4ljed. This\ allows\ Jenkins\ to\ correlate\ two\ projects.=See lubab Jenkinsil seostada kaks projekti. diff --git a/core/src/main/resources/jenkins/model/Jenkins/projectRelationship-help_tr.properties b/core/src/main/resources/jenkins/model/Jenkins/projectRelationship-help_tr.properties index afcdcbed14..64af732691 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/projectRelationship-help_tr.properties +++ b/core/src/main/resources/jenkins/model/Jenkins/projectRelationship-help_tr.properties @@ -28,4 +28,4 @@ body=\ For\ this\ feature\ to\ work,\ the\ following\ conditions\ need\ to\ be\ met\:=Bu \u00f6zelli\u011fin \u00e7al\u0131\u015fabilmesi i\u00e7in devam\u0131ndaki \u015fartlar\u0131n sa\u011flanmas\u0131 gerekir: The\ upstream\ project\ records\ the\ fingerprints\ of\ its\ build\ artifacts.=Upstream proje\, kendi yap\u0131land\u0131rma artefaktlar\u0131n\u0131n parmakizlerini kaydeder. The\ downstream\ project\ records\ the\ fingerprints\ of\ the\ upstream\ jar\ files\ it\ uses.=Downstream proje, upstream projeden kulland\u0131\u011f\u0131 jar\'lar\u0131n parmakizini kaydeder. -This\ allows\ Jenkins\ to\ correlate\ two\ projects.=Bu, Jenkins\'a iki projeyi kar\u015f\u0131l\u0131kl\u0131 ili\u015fkilendirme yetene\u011fini verir. +This\ allows\ Jenkins\ to\ correlate\ two\ projects.=Bu, Jenkins\'e iki projeyi kar\u015f\u0131l\u0131kl\u0131 ili\u015fkilendirme yetene\u011fini verir. diff --git a/core/src/main/resources/jenkins/model/Messages.properties b/core/src/main/resources/jenkins/model/Messages.properties index c07ec98272..eb5effcbfd 100644 --- a/core/src/main/resources/jenkins/model/Messages.properties +++ b/core/src/main/resources/jenkins/model/Messages.properties @@ -74,3 +74,5 @@ BuildDiscarderProperty.displayName=Discard old builds EnforceSlaveAgentPortAdministrativeMonitor.displayName=Enforce TCP Agent Port CLI.disable-job.shortDescription=Disables a job. CLI.enable-job.shortDescription=Enables a job. + +GlobalCloudConfiguration.DisplayName=Configure Clouds diff --git a/core/src/main/resources/jenkins/model/Messages_da.properties b/core/src/main/resources/jenkins/model/Messages_da.properties index cdac5eebba..d640aaad0e 100644 --- a/core/src/main/resources/jenkins/model/Messages_da.properties +++ b/core/src/main/resources/jenkins/model/Messages_da.properties @@ -33,12 +33,12 @@ Hudson.UnsafeChar=''{0}'' er et usikkert tegn Hudson.ViewAlreadyExists=En visning ved navn "{0}" findes allerede Hudson.ViewName=Alle Hudson.NotUsesUTF8ToDecodeURL=\ -Din container bruger ikke UTF-8 til at afkode URLer. Hvis du bruger ikke-ASCII tegn i jobnavne etc, \ +Din container bruger ikke UTF-8 til at afkode URLer. Hvis du bruger ikke-ASCII tegn i jobnavne etc, \ vil dette skabe problemer. 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.NodeDescription=master Jenkins noden diff --git a/core/src/main/resources/jenkins/security/s2m/AdminWhitelistRule/index.jelly b/core/src/main/resources/jenkins/security/s2m/AdminWhitelistRule/index.jelly index 128a924bf3..19dba8c4b9 100644 --- a/core/src/main/resources/jenkins/security/s2m/AdminWhitelistRule/index.jelly +++ b/core/src/main/resources/jenkins/security/s2m/AdminWhitelistRule/index.jelly @@ -94,17 +94,17 @@ THE SOFTWARE.

       # deny access to anything in the SkunkWorks folder, regardless of what later rules say
      -deny read <JENKINS_HOME>/jobs/SkunkWorks/.*
      +deny read &lt;JENKINS_HOME>/jobs/SkunkWorks/.*
       
       # allow any access under builds
      -allow all <BUILDDIR>/.*
      +allow all &lt;BUILDDIR>/.*
       
       # allow read-only access under userContent
      -allow read,stat <JENKINS_HOME>/userContent/.*
      -
      -# GENERAL SYNTAX: (allow|deny) Op,Op,Op,... PathRegExp
      +allow read,stat &lt;JENKINS_HOME>/userContent/.*
       
      - +

      + General syntax: (allow|deny) Op,Op,Op,... PathRegExp, +

      diff --git a/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchWarning/message_pt_BR.properties b/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchWarning/message_pt_BR.properties index bd5c7db995..8719f15b74 100644 --- a/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchWarning/message_pt_BR.properties +++ b/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchWarning/message_pt_BR.properties @@ -22,5 +22,5 @@ Examine= Dismiss= -# Please read the documentation and consider turning it on. +blurb=O agente para o master security subsystem est\u00e1 desligado. \ Por favor leia a documenta\u00e7\u00e3o e ligue novamente. diff --git a/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message.jelly b/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message.jelly deleted file mode 100644 index e81dd150c9..0000000000 --- a/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message.jelly +++ /dev/null @@ -1,7 +0,0 @@ - - -
      - ${%blurb(it.deprecatedProtocols)} - ${%See Protocol Configuration(rootURL)} -
      -
      diff --git a/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message.properties b/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message.properties deleted file mode 100644 index a418a180c6..0000000000 --- a/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message.properties +++ /dev/null @@ -1,5 +0,0 @@ -blurb=This Jenkins instance uses deprecated protocols: {0}. \ - It may impact stability of the instance. \ - If newer protocol versions are supported by all system components (agents, CLI and other clients), \ - it is highly recommended to disable the deprecated protocols. -Protocol\ Configuration=Protocol Configuration. diff --git a/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message_bg.properties b/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message_bg.properties deleted file mode 100644 index a001cdd2ab..0000000000 --- a/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message_bg.properties +++ /dev/null @@ -1,35 +0,0 @@ -# The MIT License -# -# Bulgarian translation: Copyright (c) 2017, 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. - -# This Jenkins instance uses deprecated protocols: {0}. \ -# It may impact stability of the instance. \ -# If newer protocol versions are supported by all system components (agents, CLI and other clients), \ -# it is highly recommended to disable the deprecated protocols. -blurb=\ - \u0422\u0430\u0437\u0438 \u0438\u043D\u0441\u0442\u0430\u043B\u0430\u0446\u0438\u044F \u043D\u0430 Jenkins \u0438\u0437\u043F\u043E\u043B\u0437\u0432\u0430 \u043E\u0441\u0442\u0430\u0440\u0435\u043B\u0438 \u043F\u0440\u043E\u0442\u043E\u043A\u043E\u043B\u0438: {0}. \u0422\u043E\u0432\u0430 \u043C\u043E\u0436\u0435 \u0434\u0430 \u0441\u0435\ - \u043E\u0442\u0440\u0430\u0437\u0438 \u043D\u0430 \u0441\u0442\u0430\u0431\u0438\u043B\u043D\u043E\u0441\u0442\u0442\u0430 \u045D. \u0410\u043A\u043E \u0432\u0441\u0438\u0447\u043A\u0438 \u0441\u0438\u0441\u0442\u0435\u043C\u043D\u0438 \u043A\u043E\u043C\u043F\u043E\u043D\u0435\u043D\u0442\u0438, \u043A\u0430\u0442\u043E \u0430\u0433\u0435\u043D\u0442\u0438\u0442\u0435,\ - \u043A\u043E\u043C\u0430\u043D\u0434\u043D\u0438\u044F \u0440\u0435\u0434 \u0438 \u0434\u0440\u0443\u0433\u0438\u0442\u0435 \u043A\u043B\u0438\u0435\u043D\u0442\u0438 \u043F\u043E\u0434\u0434\u044A\u0440\u0436\u0430\u0442 \u043D\u043E\u0432\u0438\u0442\u0435 \u043F\u0440\u043E\u0442\u043E\u043A\u043E\u043B\u0438, \u0441\u0438\u043B\u043D\u043E \u043F\u0440\u0435\u043F\u043E\u0440\u044A\u0447\u0432\u0430\u043C\u0435\ - \u0434\u0430 \u0438\u0437\u043A\u043B\u044E\u0447\u0438\u0442\u0435 \u043E\u0441\u0442\u0430\u0440\u0435\u043B\u0438\u0442\u0435. -# It may impact stability of the instance. \ -# If newer protocol versions are supported by all system components (agents, CLI and other clients), \ -# it is highly recommended to disable the deprecated protocols. - diff --git a/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message_it.properties b/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message_it.properties deleted file mode 100644 index 78f92b4903..0000000000 --- a/core/src/main/resources/jenkins/slaves/DeprecatedAgentProtocolMonitor/message_it.properties +++ /dev/null @@ -1,28 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributors -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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=Quest''istanza di Jenkins utilizza protocolli deprecati: {0}. \ - Ci\uFFFD potrebbe influenzare la stabilit\uFFFD dell''istanza. \ - Se le nuove versioni dei protocolli sono supportate da tutti i componenti di sistema (agenti, \ - interfaccia da riga di comando e altri client), \uFFFD fortemente raccomandato disabilitare i \ - protocolli deprecati. -See\ Protocol\ Configuration=Vedi Configurazione protocollo. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause.jelly b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause.jelly deleted file mode 100644 index 9704ac6557..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause.jelly +++ /dev/null @@ -1,4 +0,0 @@ - - - ${%message} - diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause.properties deleted file mode 100644 index 714d1f68ea..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause.properties +++ /dev/null @@ -1,2 +0,0 @@ -message=This protocol is an obsolete protocol, which has been replaced by version 4. \ - It is also not encrypted. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause_bg.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause_bg.properties deleted file mode 100644 index 2f66522f0e..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause_bg.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Bulgarian translation: Copyright (c) 2017, 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. - -# This protocol is an obsolete protocol, which has been replaced by JNLP2-connect. \ -# It is also not encrypted. -message=\ - \u0422\u043e\u0437\u0438 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0435 \u043e\u0441\u0442\u0430\u0440\u044f\u043b \u0438 \u0435 \u0431\u0435\u0437 \u0448\u0438\u0444\u0440\u0438\u0440\u0430\u043d\u0435. \u0417\u0430\u043c\u0435\u043d\u0435\u043d \u0435 \u043e\u0442 JNLP2-connect. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause_it.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause_it.properties deleted file mode 100644 index bd2140b934..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/deprecationCause_it.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributors -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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. - -message=Questo protocollo un protocollo obsoleto rimpiazzato da JNLP2-connect. \ - Inoltre, non criptato. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description.jelly b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description.jelly deleted file mode 100644 index 55e2c974b5..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description.jelly +++ /dev/null @@ -1,4 +0,0 @@ - - - ${%summary} - diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description.properties deleted file mode 100644 index f4a0f9073c..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description.properties +++ /dev/null @@ -1,2 +0,0 @@ -summary=Accepts connections from remote clients so that they can be used as additional agents. \ - This protocol is unencrypted. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description_bg.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description_bg.properties deleted file mode 100644 index 4e35de871c..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description_bg.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Bulgarian translation: Copyright (c) 2016, 2017, 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. - -Accepts\ connections\ from\ remote\ clients\ so\ that\ they\ can\ be\ used\ as\ additional\ build\ agents=\ - \u041f\u0440\u0438\u0435\u043c\u0430\u043d\u0435 \u043d\u0430 \u0432\u0440\u044a\u0437\u043a\u0438 \u043e\u0442 \u043e\u0442\u0434\u0430\u043b\u0435\u0447\u0435\u043d\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0438, \u0442\u0430\u043a\u0430 \u0447\u0435 \u0442\u0435 \u0434\u0430 \u0441\u0435 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0442 \u043a\u0430\u0442\u043e\ - \u0434\u043e\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u043d\u0438 \u043c\u0430\u0448\u0438\u043d\u0438 \u0437\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435. -# Accepts connections from remote clients so that they can be used as additional agents. \ -# This protocol is unencrypted. -summary=\ - \u041f\u0440\u0438\u0435\u043c\u0430\u043d\u0435 \u043d\u0430 \u0432\u0440\u044a\u0437\u043a\u0438 \u043e\u0442 \u043e\u0442\u0434\u0430\u043b\u0435\u0447\u0435\u043d\u0438 \u043a\u043b\u0438\u0435\u043d\u0442\u0438, \u0442\u0430\u043a\u0430 \u0447\u0435 \u0442\u0435 \u0434\u0430 \u0441\u0435 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0442 \u043a\u0430\u0442\u043e\ - \u0434\u043e\u043f\u044a\u043b\u043d\u0438\u0442\u0435\u043b\u043d\u0438 \u043c\u0430\u0448\u0438\u043d\u0438 \u0437\u0430 \u0438\u0437\u0433\u0440\u0430\u0436\u0434\u0430\u043d\u0435. \u041f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u044a\u0442 \u043d\u0435 \u0435 \u0437\u0430\u0449\u0438\u0442\u0435\u043d \u0441 \u0448\u0438\u0444\u0440\u0438\u0440\u0430\u043d\u0435. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description_de.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description_de.properties deleted file mode 100644 index 61f21fa183..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description_de.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2017 Daniel Beck and a number of other of contributors -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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. - -summary=Bedient Verbindungen von entfernten Clients, damit diese als Agenten verwendet werden k\u00F6nnen. \ - Dieses Protokoll ist unverschl\u00FCsselt. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description_it.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description_it.properties deleted file mode 100644 index c42ad94e0c..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description_it.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributors -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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. - -summary=Accetta connessioni dai client remoti in modo che questi possano essere utilizzati \ - come agenti di compilazione aggiuntivi. Questo protocollo non criptato. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description_sr.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description_sr.properties deleted file mode 100644 index 3f5c9d27c2..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol/description_sr.properties +++ /dev/null @@ -1,3 +0,0 @@ -# This file is under the MIT License by authors - -summary=\u041f\u0440\u0438\u0445\u0432\u0430\u0442\u0430 \u0432\u0435\u0437\u0435 \u043e\u0434 \u043a\u043b\u0438\u0458\u0435\u043d\u0442\u0438\u043c\u0430 \u0434\u0430 \u0431\u0438 \u043c\u043e\u0433\u043b\u0438 \u0441\u0435 \u0443\u043f\u043e\u0442\u0440\u0435\u0431\u0438\u0442\u0438 \u043a\u0430\u043e \u0434\u043e\u0434\u0430\u0442\u043d\u0435 \u0430\u0433\u0435\u043d\u0442\u0435 \u0437\u0430 \u0438\u0437\u0433\u0440\u0430\u0434\u045a\u0443. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause.jelly b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause.jelly deleted file mode 100644 index 17138fc4fe..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause.jelly +++ /dev/null @@ -1,5 +0,0 @@ - - - ${%message} - ${%TCP Agent Protocol 2 Errata} - diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause.properties deleted file mode 100644 index e84662a073..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause.properties +++ /dev/null @@ -1,3 +0,0 @@ -message=This protocol has known stability issues, and it is replaced by version 4. \ - It is also not encrypted. \ - See more information in the protocol Errata. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause_bg.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause_bg.properties deleted file mode 100644 index 35fdea705a..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause_bg.properties +++ /dev/null @@ -1,30 +0,0 @@ -# The MIT License -# -# Bulgarian translation: Copyright (c) 2017, 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. - -JNLP2\ Protocol\ Errata=\ - \u0413\u0440\u0435\u0448\u043a\u0438 \u0432 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 JNLP2 -# This protocol has known stability issues, and it is replaced by JNLP4. \ -# It is also not encrypted. \ -# See more information in the protocol Errata. -message=\ - \u0422\u043e\u0437\u0438 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u043d\u0435 \u0435 \u0441\u0442\u0430\u0431\u0438\u043b\u0435\u043d \u0438 \u0435 \u0437\u0430\u043c\u0435\u043d\u0435\u043d \u043e\u0442 JNLP4. \u0412 JNLP2 \u043b\u0438\u043f\u0441\u0432\u0430 \u0448\u0438\u0444\u0440\u0438\u0440\u0430\u043d\u0435.\ - \u0417\u0430 \u043f\u043e\u0432\u0435\u0447\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0432\u0438\u0436\u0442\u0435 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\u0442\u0430 \u0437\u0430 \u0433\u0440\u0435\u0448\u043a\u0438\u0442\u0435 \u0432 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause_it.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause_it.properties deleted file mode 100644 index 8ae8437b43..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/deprecationCause_it.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributors -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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. - -message=Questo protocollo ha problemi di stabilit noti ed stato sostituito da JNLP4. \ - Non inoltre criptato. \ - Si vedano ulteriori informazioni nell''Errata corrige del protocollo. -JNLP2\ Protocol\ Errata=Errata corrige protocollo JNLP2 diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description.jelly b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description.jelly deleted file mode 100644 index 55e2c974b5..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description.jelly +++ /dev/null @@ -1,4 +0,0 @@ - - - ${%summary} - diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description.properties deleted file mode 100644 index edb6b96c46..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description.properties +++ /dev/null @@ -1,3 +0,0 @@ -summary=Extends the version 1 protocol by adding a per-client cookie, \ -so that we can detect a reconnection from the agent and take appropriate action. \ -This protocol is unencrypted. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description_bg.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description_bg.properties deleted file mode 100644 index e49efb0715..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description_bg.properties +++ /dev/null @@ -1,33 +0,0 @@ -# The MIT License -# -# Bulgarian translation: Copyright (c) 2016, 2017, 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. - -Extends\ the\ version\ 1\ protocol\ by\ adding\ a\ per-client\ cookie,\ so\ that\ we\ can\ detect\ a\ reconnection\ from\ the\ agent\ and\ take\ appropriate\ action=\ - \u0420\u0430\u0437\u0448\u0438\u0440\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u044f 1 \u043d\u0430 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430, \u043a\u0430\u0442\u043e \u0441\u0435 \u0434\u043e\u0431\u0430\u0432\u044f \u0431\u0438\u0441\u043a\u0432\u0438\u0442\u043a\u0430 \u0437\u0430 \u0432\u0441\u0435\u043a\u0438\ - \u043a\u043b\u0438\u0435\u043d\u0442. \u0422\u043e\u0432\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0432\u0430 \u043e\u0442\u043a\u0440\u0438\u0432\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0432\u044a\u0437\u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0432\u0440\u044a\u0437\u043a\u0438\u0442\u0435 \u043e\u0442\ - \u0430\u0433\u0435\u043d\u0442\u0438\u0442\u0435 \u0438 \u043f\u0440\u0435\u0434\u043f\u0440\u0438\u0435\u043c\u0430\u043d\u0435 \u043d\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u043e\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435. -# Extends the version 1 protocol by adding a per-client cookie, \ -# so that we can detect a reconnection from the agent and take appropriate action. \ -# This protocol is unencrypted. -summary=\ - \u0420\u0430\u0437\u0448\u0438\u0440\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u044f 1 \u043d\u0430 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430, \u043a\u0430\u0442\u043e \u0441\u0435 \u0434\u043e\u0431\u0430\u0432\u044f \u0431\u0438\u0441\u043a\u0432\u0438\u0442\u043a\u0430 \u0437\u0430 \u0432\u0441\u0435\u043a\u0438\ - \u043a\u043b\u0438\u0435\u043d\u0442. \u0422\u043e\u0432\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0432\u0430 \u043e\u0442\u043a\u0440\u0438\u0432\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0432\u044a\u0437\u0441\u0442\u0430\u043d\u043e\u0432\u044f\u0432\u0430\u043d\u0435\u0442\u043e \u043d\u0430 \u0432\u0440\u044a\u0437\u043a\u0438\u0442\u0435 \u043e\u0442\ - \u0430\u0433\u0435\u043d\u0442\u0438\u0442\u0435 \u0438 \u043f\u0440\u0435\u0434\u043f\u0440\u0438\u0435\u043c\u0430\u043d\u0435 \u043d\u0430 \u043f\u043e\u0434\u0445\u043e\u0434\u044f\u0449\u043e\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435. \u0422\u043e\u0437\u0438 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0435 \u043d\u0435\u0437\u0430\u0449\u0438\u0442\u0435\u043d. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description_de.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description_de.properties deleted file mode 100644 index b4b1383d45..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description_de.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2017 Daniel Beck and a number of other of contributors -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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. - -summary=Erweitert das Protokoll Version 1 um Identifikations-Cookies f\u00FCr Clients, so dass erneute Verbindungsversuche desselben Agenten identifiziert und entsprechend behandelt werden k\u00F6nnen. Dieses Protkoll ist unverschl\u00FCsselt. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description_it.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description_it.properties deleted file mode 100644 index 3c298bbc12..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description_it.properties +++ /dev/null @@ -1,25 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributors -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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. - -summary=Estende la versione 1 del protocollo aggiungendo un cookie per ogni client \ - in modo da rilevare una nuova connessione da parte dell''agent e intraprendere le azioni opportune. \ - Questo protocollo non criptato. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description_sr.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description_sr.properties deleted file mode 100644 index f96b74e2e0..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol2/description_sr.properties +++ /dev/null @@ -1,3 +0,0 @@ -# This file is under the MIT License by authors - -summary=\u041d\u0430\u0434\u0433\u0440\u0430\u0452\u0443\u0458\u0435 \u0432\u0435\u0440\u0437\u0438\u0458\u0443 1 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u0434\u043e\u0434\u0430\u0432\u0430\u045b\u0438 cookie \u0441\u0432\u0430\u043a\u043e\u043c \u043a\u043b\u0438\u0458\u0435\u043d\u0442\u0443, \u0448\u0442\u043e \u043e\u043c\u043e\u0433\u0443\u0458\u0443\u045b\u0435 \u043f\u043e\u043d\u043e\u0432\u043e \u043f\u043e\u0432\u0435\u0437\u0438\u0432\u0430\u045a\u0435 \u0441\u0430 \u0430\u0433\u0435\u043d\u0442\u043e\u043c. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause.jelly b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause.jelly deleted file mode 100644 index 780b7239db..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause.jelly +++ /dev/null @@ -1,5 +0,0 @@ - - - ${%This protocol is unstable. See the protocol documentation for more info.} - ${%TCP Agent Protocol 3 Errata} - diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause.properties deleted file mode 100644 index 8b13789179..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause.properties +++ /dev/null @@ -1 +0,0 @@ - diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause_bg.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause_bg.properties deleted file mode 100644 index c0ffc66602..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause_bg.properties +++ /dev/null @@ -1,26 +0,0 @@ -# The MIT License -# -# Bulgarian translation: Copyright (c) 2017, 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. - -JNLP3\ Protocol\ Errata=\ - \u0413\u0440\u0435\u0448\u043a\u0438 \u0432 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 JNLP3 -This\ protocol\ is\ unstable.\ See\ the\ protocol\ documentation\ for\ more\ info.=\ - \u0422\u043e\u0437\u0438 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u0435 \u043d\u0435\u0441\u0442\u0430\u0431\u0438\u043b\u0435\u043d. \u0417\u0430 \u043f\u043e\u0432\u0435\u0447\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u0432\u0438\u0436\u0442\u0435 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f\u0442\u0430 \u043c\u0443. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause_it.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause_it.properties deleted file mode 100644 index 9032ff199c..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/deprecationCause_it.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributors -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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. - -JNLP3\ Protocol\ Errata=Errata corrige protocollo JNLP3 -This\ protocol\ is\ unstable.\ See\ the\ protocol\ documentation\ for\ more\ info.=Questo protocollo non stabile. Si veda la documentazione del protocollo per ulteriori informazioni. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description.jelly b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description.jelly deleted file mode 100644 index 55e2c974b5..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description.jelly +++ /dev/null @@ -1,4 +0,0 @@ - - - ${%summary} - diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description.properties deleted file mode 100644 index ec1f6a2c89..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description.properties +++ /dev/null @@ -1 +0,0 @@ -summary=Extends the version 2 protocol by adding basic encryption but requires a thread per client. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description_bg.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description_bg.properties deleted file mode 100644 index 2a41070810..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description_bg.properties +++ /dev/null @@ -1,35 +0,0 @@ -# The MIT License -# -# Bulgarian translation: Copyright (c) 2016, 2017 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. - -Extends\ the\ version\ 2\ protocol\ by\ adding\ basic\ encryption\ but\ requires\ a\ thread\ per\ client=\ - \u0420\u0430\u0437\u0448\u0438\u0440\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u044f 2 \u043d\u0430 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u043a\u0430\u0442\u043e \u0441\u0435 \u0434\u043e\u0431\u0430\u0432\u044f \u0448\u0438\u0444\u0440\u0438\u0440\u0430\u043d\u0435, \u043d\u043e \u0442\u043e\u0432\u0430\ - \u0438\u0437\u0438\u0441\u043a\u0432\u0430 \u043f\u043e \u0435\u0434\u043d\u0430 \u043d\u0438\u0448\u043a\u0430 \u0437\u0430 \u0432\u0441\u0435\u043a\u0438 \u043a\u043b\u0438\u0435\u043d\u0442 -# Extends the version 2 protocol by adding basic encryption but requires a thread per client. \ -# This protocol falls back to Java Web Start Agent Protocol/2 (unencrypted) when it can't create a secure connection. \ -# This protocol is not recommended. \ -# Use Java Web Start Agent Protocol/4 instead. -summary=\ - \u0420\u0430\u0437\u0448\u0438\u0440\u044f\u0432\u0430\u043d\u0435 \u043d\u0430 \u0432\u0435\u0440\u0441\u0438\u044f 2 \u043d\u0430 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u043a\u0430\u0442\u043e \u0441\u0435 \u0434\u043e\u0431\u0430\u0432\u044f \u0448\u0438\u0444\u0440\u0438\u0440\u0430\u043d\u0435, \u043d\u043e \u0442\u043e\u0432\u0430\ - \u0438\u0437\u0438\u0441\u043a\u0432\u0430 \u043f\u043e \u0435\u0434\u043d\u0430 \u043d\u0438\u0448\u043a\u0430 \u0437\u0430 \u0432\u0441\u0435\u043a\u0438 \u043a\u043b\u0438\u0435\u043d\u0442. \u041a\u043e\u0433\u0430\u0442\u043e \u043d\u0435 \u043c\u043e\u0436\u0435 \u0434\u0430 \u0441\u0435 \u0441\u044a\u0437\u0434\u0430\u0434\u0435 \u0437\u0430\u0449\u0438\u0442\u0435\u043d\u0430\ - \u0432\u0440\u044a\u0437\u043a\u0430, \u0442\u043e\u0437\u0438 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b \u043f\u0440\u0438\u0431\u044f\u0433\u0432\u0430 \u0434\u043e Java Web Start Agent Protocol/2, \u043a\u043e\u0439\u0442\u043e \u043d\u0435 \u0435\ - \u0448\u0438\u0444\u0440\u0438\u0440\u0430\u043d. \u0422\u043e\u0432\u0430 \u043d\u0435 \u0435 \u043f\u0440\u0435\u043f\u043e\u0440\u044a\u0447\u0438\u0442\u0435\u043b\u043d\u043e \u2014 \u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0439\u0442e Java Web Start Agent\ - Protocol/4 \u0432\u043c\u0435\u0441\u0442\u043e \u0442\u043e\u0432\u0430. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description_de.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description_de.properties deleted file mode 100644 index 6280077683..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description_de.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2017 Daniel Beck and a number of other of contributors -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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. - -summary=Erweitert das Protokoll Version 2 um einfache Verschl\u00fcsselung, aber erfordert einen Thread pro Client. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description_it.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description_it.properties deleted file mode 100644 index d62d8a0aea..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description_it.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-, Kohsuke Kawaguchi, Sun Microsystems, Inc., and a number of other of contributors -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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. - -summary=Estende la versione 2 del protocollo aggiungendo crittografia di base ma richiede un thread per client. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description_sr.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description_sr.properties deleted file mode 100644 index 8c185f3e4b..0000000000 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol3/description_sr.properties +++ /dev/null @@ -1,3 +0,0 @@ -# This file is under the MIT License by authors -#TODO: Summary is outdated, needs to be modified -summary=\u041d\u0430\u0434\u0433\u0440\u0430\u0452\u0443\u0458\u0435 \u0432\u0435\u0440\u0437\u0438\u0458\u0443 2 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430 \u0434\u043e\u0434\u0430\u0432\u0430\u0458\u0443\u045b\u0438 \u0448\u0438\u0444\u0440\u043e\u0432\u0430\u045a\u0435 (\u043f\u043e\u0442\u0440\u0435\u0431\u043d\u043e \u0458\u0435\u0434\u0430\u043d \u043d\u0438\u0437 \u0437\u0430 \u0441\u0432\u0430\u043a\u043e\u0433 \u043a\u043b\u0438\u0458\u0435\u043d\u0442\u0430) diff --git a/core/src/main/resources/lib/form/expandableTextbox_pt_BR.properties b/core/src/main/resources/lib/form/expandableTextbox_pt_BR.properties index 5cf246c45b..ddb2ef68b8 100644 --- a/core/src/main/resources/lib/form/expandableTextbox_pt_BR.properties +++ b/core/src/main/resources/lib/form/expandableTextbox_pt_BR.properties @@ -23,5 +23,5 @@ # \ # Click to expand to multiple lineswhere you can use new lines instead of space # To revert back to single line, write everything in one line then submit. -tooltip=Clique para expandir para v\u00E1rias linhas
      onde voc\u00EA pode usar novas linhas em vez de espa\u00E7os.
      Para reverter em uma \u00FAnica linha, escrever tudo em uma \u00FAnica linha, em seguida, submeta. +tooltip=Clique para expandir para v\u00E1rias linhas
      onde voc\u00EA pode usar novas linhas em vez de espa\u00E7os.
      Para reverter em uma \u00FAnica linha, escrever tudo em uma \u00FAnica linha, em seguida, submeta.
      \ Para reverter de volta em uma linha, escreva tudo em uma linha ent\u00e3o envie. diff --git a/core/src/main/resources/lib/form/password.jelly b/core/src/main/resources/lib/form/password.jelly index eae77c32b0..caaf04e0ff 100644 --- a/core/src/main/resources/lib/form/password.jelly +++ b/core/src/main/resources/lib/form/password.jelly @@ -61,12 +61,73 @@ THE SOFTWARE. - - + + + + + + +
      + +
      +
      + + + + + + + + + ${%Concealed} +
      +
      + +
      +
      +
      +
      + + + + +
      +
      + + + +
      diff --git a/core/src/main/resources/lib/form/password/password.css b/core/src/main/resources/lib/form/password/password.css new file mode 100644 index 0000000000..250c55c7de --- /dev/null +++ b/core/src/main/resources/lib/form/password/password.css @@ -0,0 +1,55 @@ +/* + * The MIT License + * + * Copyright (c) 2019 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. + */ + +.hidden-password-placeholder { + display: flex; +} + +.hidden-password-legend { + border: 1px solid #ccc; + border-radius: 3px; + background: #f9f9f9; + flex-grow: 1; + align-items: center; + display: inline-flex; +} + +.hidden-password-legend > svg { + margin-right: 1em; + margin-left: 0.5em; +} + +.hidden-password input[type='button'] { + background: #4b99d0; + color: #fff; + border-radius: 4px; + border: none; + padding: 7px; + margin-left: 5px; +} + +.hidden-password input[type='button']:hover { + background: #5092be; + cursor: pointer; +} diff --git a/core/src/main/resources/lib/form/password/password.js b/core/src/main/resources/lib/form/password/password.js new file mode 100644 index 0000000000..e4f44cceff --- /dev/null +++ b/core/src/main/resources/lib/form/password/password.js @@ -0,0 +1,38 @@ +/* + * The MIT License + * + * Copyright (c) 2019 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. + */ + +Behaviour.specify('.hidden-password', 'hidden-password-button', 0, function (e) { + var secretUpdateBtn = e.querySelector('.hidden-password-update-btn'); + if (secretUpdateBtn === null) return; + + var id = 'hidden-password-' + (iota++); + + secretUpdateBtn.onclick = function () { + e.querySelector('.hidden-password-field').setAttribute('type', 'password'); + e.querySelector('.hidden-password-placeholder').remove(); + secretUpdateBtn.remove(); + // fix UI bug when DOM changes + Event.fire(window, 'jenkins:bottom-sticker-adjust'); + }; +}); diff --git a/core/src/main/resources/lib/form/repeatableProperty.jelly b/core/src/main/resources/lib/form/repeatableProperty.jelly index 125972242e..b5aa38291c 100644 --- a/core/src/main/resources/lib/form/repeatableProperty.jelly +++ b/core/src/main/resources/lib/form/repeatableProperty.jelly @@ -35,6 +35,12 @@ THE SOFTWARE.
      + + Due to a bug in Stapler data binding the model elements are only set if they consist of one or more values. + If all values have been removed in the user interface (i.e. the associated form is empty), then the setter is not + invoked anymore. As a workaround, you need to override the corresponding configure method and clear the model + property manually before invoking the data binding. See warnings-ng-plugin PR#266. + ]]> diff --git a/core/src/main/resources/lib/hudson/buildProgressBar_ko.properties b/core/src/main/resources/lib/hudson/buildProgressBar_ko.properties index d1cc19cd4e..134c24582d 100644 --- a/core/src/main/resources/lib/hudson/buildProgressBar_ko.properties +++ b/core/src/main/resources/lib/hudson/buildProgressBar_ko.properties @@ -20,5 +20,4 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -text="{0} \uC804\uC5D0 \uC2DC\uC791 -\uC608\uC0C1 \uC794\uC5EC \uC2DC\uAC04: {1}" +text="{0} \uC804\uC5D0 \uC2DC\uC791
      \uC608\uC0C1 \uC794\uC5EC \uC2DC\uAC04: {1}" diff --git a/core/src/main/resources/lib/hudson/buildProgressBar_sk.properties b/core/src/main/resources/lib/hudson/buildProgressBar_sk.properties index 20c378adb1..c754fff7ff 100644 --- a/core/src/main/resources/lib/hudson/buildProgressBar_sk.properties +++ b/core/src/main/resources/lib/hudson/buildProgressBar_sk.properties @@ -21,4 +21,3 @@ # THE SOFTWARE. text=Spusten\u00E9 pred {0}
      Predpokladan\u00FD zost\u00E1vaj\u00FAci \u010Das: {1} -Predpokladan\u00FD zost\u00E1vaj\u00FAci \u010Das: {1} diff --git a/core/src/main/resources/lib/hudson/buildProgressBar_sl.properties b/core/src/main/resources/lib/hudson/buildProgressBar_sl.properties index 97e9164f80..bab5dd206e 100644 --- a/core/src/main/resources/lib/hudson/buildProgressBar_sl.properties +++ b/core/src/main/resources/lib/hudson/buildProgressBar_sl.properties @@ -1,4 +1,3 @@ # This file is under the MIT License by authors -text=Startan pred {0}
      -Predviden preostali \u010Das: {1} +text=Startan pred {0}
      Predviden preostali \u010Das: {1} diff --git a/core/src/main/resources/lib/hudson/executors.jelly b/core/src/main/resources/lib/hudson/executors.jelly index 578808d47f..663d7b64e2 100644 --- a/core/src/main/resources/lib/hudson/executors.jelly +++ b/core/src/main/resources/lib/hudson/executors.jelly @@ -35,7 +35,20 @@ THE SOFTWARE. ${title} - (${%offline}) + + + + + ( ${%offline}) + + + (${%launching}) + + + (${%offline}) + + + (${%suspended}) @@ -110,7 +123,7 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/lib/hudson/executors.properties b/core/src/main/resources/lib/hudson/executors.properties index 3d8ebc248e..d21742283c 100644 --- a/core/src/main/resources/lib/hudson/executors.properties +++ b/core/src/main/resources/lib/hudson/executors.properties @@ -1,2 +1,3 @@ Computers=master{0,choice,0#|1# + {0,number} computer ({1} of {2} executors)|1< + {0,number} computers ({1} of {2} executors)} confirm=Are you sure you want to abort {0}? +launching=launching... diff --git a/core/src/main/resources/lib/hudson/scriptConsole_ko.properties b/core/src/main/resources/lib/hudson/scriptConsole_ko.properties index 523c9f7126..31b7f20020 100644 --- a/core/src/main/resources/lib/hudson/scriptConsole_ko.properties +++ b/core/src/main/resources/lib/hudson/scriptConsole_ko.properties @@ -23,8 +23,4 @@ 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.)

      -\uC608\uC81C:
      - -\uC608\uC81C:
      - +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: 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 ef03bcb2ec..4855b5d7f0 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,4 @@ 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. -Eksempel: -println(hudson.model.Hudson.instance.pluginManager.plugins) - +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: diff --git a/core/src/main/resources/lib/hudson/thirdPartyLicenses.jelly b/core/src/main/resources/lib/hudson/thirdPartyLicenses.jelly index 072f859fa9..7d2e816ad7 100644 --- a/core/src/main/resources/lib/hudson/thirdPartyLicenses.jelly +++ b/core/src/main/resources/lib/hudson/thirdPartyLicenses.jelly @@ -39,7 +39,7 @@ THE SOFTWARE. - ${attrs.name} + ${attrs.name} ${attrs.groupId}:${attrs.artifactId}:${attrs.version} @@ -51,7 +51,7 @@ THE SOFTWARE. - ${attrs.name}
      + ${attrs.name}
      diff --git a/core/src/main/resources/lib/layout/task.jelly b/core/src/main/resources/lib/layout/task.jelly index 54d95993ce..a1fa68cc43 100644 --- a/core/src/main/resources/lib/layout/task.jelly +++ b/core/src/main/resources/lib/layout/task.jelly @@ -207,7 +207,7 @@ THE SOFTWARE. - + ${title} diff --git a/core/src/main/resources/windows-service/jenkins-slave.xml b/core/src/main/resources/windows-service/jenkins-slave.xml deleted file mode 100644 index cc18abf4cc..0000000000 --- a/core/src/main/resources/windows-service/jenkins-slave.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - @ID@ - Jenkins agent (@ID@) - This service runs an agent for Jenkins automation server. - - @JAVA@ - -Xrs @VMARGS@ -jar "%BASE%\agent.jar" @ARGS@ - - rotate - - - - - - - - %BASE%\jenkins_agent.pid - 5000 - false - - - - - - diff --git a/core/src/test/java/hudson/EnvVarsTest.java b/core/src/test/java/hudson/EnvVarsTest.java index affe20be07..2021086cf6 100644 --- a/core/src/test/java/hudson/EnvVarsTest.java +++ b/core/src/test/java/hudson/EnvVarsTest.java @@ -23,19 +23,15 @@ */ package hudson; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - import hudson.EnvVars.OverrideOrderCalculator; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; +import java.util.*; import com.google.common.collect.Sets; import org.junit.Test; +import static org.junit.Assert.*; + /** * @author Kohsuke Kawaguchi */ @@ -140,4 +136,25 @@ public void overrideOrderCalculatorCyclic() { assertEquals(Arrays.asList("B", "A", "C"), order.subList(0, 3)); assertEquals(Sets.newHashSet("E", "D"), new HashSet<>(order.subList(3, order.size()))); } + + @Test + public void putIfNotNull() { + EnvVars env = new EnvVars(); + env.putIfNotNull("foo", null); + assertTrue(env.isEmpty()); + env.putIfNotNull("foo", "bar"); + assertFalse(env.isEmpty()); + } + + @Test + public void putAllNonNull() { + EnvVars env = new EnvVars(); + TreeMap map = new TreeMap<>(); + map.put("A", "a"); + map.put("B", null); + TreeMap filteredMap = new TreeMap<>(); + filteredMap.put("A", "a"); + env.putAllNonNull(map); + assertEquals(filteredMap, env); + } } diff --git a/core/src/test/java/hudson/FilePathTest.java b/core/src/test/java/hudson/FilePathTest.java index 70348334f9..79ad7816e8 100644 --- a/core/src/test/java/hudson/FilePathTest.java +++ b/core/src/test/java/hudson/FilePathTest.java @@ -208,13 +208,10 @@ public void close() throws IOException { for (int i = 0; i < 10000; i++) { // TODO is there a simpler way to force the TarOutputStream to be flushed and the reader to start? // Have not found a way to make the failure guaranteed. - OutputStream os = from.child("content" + i).write(); - try { + try (OutputStream os = from.child("content" + i).write()) { for (int j = 0; j < 1024; j++) { os.write('.'); } - } finally { - os.close(); } } FilePath toF = to.child("content0"); diff --git a/core/src/test/java/hudson/PluginWrapperTest.java b/core/src/test/java/hudson/PluginWrapperTest.java index 2bc8f754bb..a10d42d961 100644 --- a/core/src/test/java/hudson/PluginWrapperTest.java +++ b/core/src/test/java/hudson/PluginWrapperTest.java @@ -53,7 +53,7 @@ public void jenkinsCoreTooOld() throws Exception { pw.resolvePluginDependencies(); fail(); } catch (IOException ex) { - assertContains(ex, "fake version 42 failed to load", "update Jenkins from version 2.0 to version 3.0"); + assertContains(ex, "Failed to load: fake (42)", "Jenkins (3.0) or higher required"); } } @@ -64,7 +64,7 @@ public void dependencyNotInstalled() throws Exception { pw.resolvePluginDependencies(); fail(); } catch (IOException ex) { - assertContains(ex, "dependee version 42 failed to load", "dependency version 42 is missing. To fix, install version 42 or later"); + assertContains(ex, "Failed to load: dependee (42)", "Plugin is missing: dependency (42)"); } } @@ -76,7 +76,7 @@ public void dependencyOutdated() throws Exception { pw.resolvePluginDependencies(); fail(); } catch (IOException ex) { - assertContains(ex, "dependee version 42 failed to load", "dependency version 3 is older than required. To fix, install version 5 or later"); + assertContains(ex, "Failed to load: dependee (42)", "Update required: dependency (3) to be updated to 5 or higher"); } } @@ -88,7 +88,7 @@ public void dependencyFailedToLoad() throws Exception { pw.resolvePluginDependencies(); fail(); } catch (IOException ex) { - assertContains(ex, "dependee version 42 failed to load", "dependency version 5 failed to load. Fix this plugin first"); + assertContains(ex, "Failed to load: dependee (42)", "Failed to load: dependency (5)"); } } @@ -161,12 +161,11 @@ private PluginWrapper buildFailed() { } private PluginWrapper build() { - Manifest manifest = mock(Manifest.class); - Attributes attributes = new Attributes(); + Manifest manifest = new Manifest(); + Attributes attributes = manifest.getMainAttributes(); attributes.put(new Attributes.Name("Short-Name"), name); attributes.put(new Attributes.Name("Jenkins-Version"), requiredCoreVersion); attributes.put(new Attributes.Name("Plugin-Version"), version); - when(manifest.getMainAttributes()).thenReturn(attributes); return new PluginWrapper( pm, new File("/tmp/" + name + ".jpi"), diff --git a/core/src/test/java/hudson/cli/ListJobsCommandTest.java b/core/src/test/java/hudson/cli/ListJobsCommandTest.java index 7c4934ac72..a329e4f30a 100644 --- a/core/src/test/java/hudson/cli/ListJobsCommandTest.java +++ b/core/src/test/java/hudson/cli/ListJobsCommandTest.java @@ -50,7 +50,6 @@ public void setUp() { jenkins = mock(Jenkins.class); mockStatic(Jenkins.class); when(Jenkins.get()).thenReturn(jenkins); - when(Jenkins.getActiveInstance()).thenReturn(jenkins); command = mock(ListJobsCommand.class, Mockito.CALLS_REAL_METHODS); command.stdout = new PrintStream(stdout); command.stderr = new PrintStream(stderr); diff --git a/core/src/test/java/hudson/cli/handlers/ViewOptionHandlerTest.java b/core/src/test/java/hudson/cli/handlers/ViewOptionHandlerTest.java index 2fa4ecc732..1ae52440ed 100644 --- a/core/src/test/java/hudson/cli/handlers/ViewOptionHandlerTest.java +++ b/core/src/test/java/hudson/cli/handlers/ViewOptionHandlerTest.java @@ -84,7 +84,6 @@ public class ViewOptionHandlerTest { PowerMockito.mockStatic(Jenkins.class); PowerMockito.when(Jenkins.get()).thenReturn(jenkins); - PowerMockito.when(Jenkins.getActiveInstance()).thenReturn(jenkins); when(jenkins.getView("outer")).thenReturn(outer); when(jenkins.getDisplayName()).thenReturn("Jenkins"); when(jenkins.getACL()).thenReturn(new ACL() { diff --git a/core/src/test/java/hudson/model/AbstractItemTest.java b/core/src/test/java/hudson/model/AbstractItemTest.java index bb5c851ae4..b5dcdf41d2 100644 --- a/core/src/test/java/hudson/model/AbstractItemTest.java +++ b/core/src/test/java/hudson/model/AbstractItemTest.java @@ -30,7 +30,7 @@ public Collection getAllJobs() { } /** - * Override save so that nothig happens when setDisplayName() is called + * Override save so that nothing happens when setDisplayName() is called */ @Override public void save() { diff --git a/core/src/test/java/hudson/model/EnvironmentContributingActionTest.java b/core/src/test/java/hudson/model/EnvironmentContributingActionTest.java index 3794a6bf24..8bf6c69b30 100644 --- a/core/src/test/java/hudson/model/EnvironmentContributingActionTest.java +++ b/core/src/test/java/hudson/model/EnvironmentContributingActionTest.java @@ -39,13 +39,13 @@ boolean wasDeprecatedMethodCalled() { } class OverrideBoth extends InvisibleAction implements EnvironmentContributingAction { - private boolean wasCalledAstractBuild = false; + private boolean wasCalledAbstractBuild = false; private boolean wasCalledRun = false; @SuppressWarnings("deprecation") @Override public void buildEnvVars(AbstractBuild abstractBuild, EnvVars envVars) { - wasCalledAstractBuild = true; + wasCalledAbstractBuild = true; } @Override @@ -54,7 +54,7 @@ public void buildEnvironment(Run run, EnvVars env) { } boolean wasDeprecatedMethodCalled() { - return wasCalledAstractBuild; + return wasCalledAbstractBuild; } boolean wasRunCalled() { @@ -152,4 +152,4 @@ public void testOverrideBothAndCallDeprecatedMethod() throws Exception { assertTrue(overrideRun.wasDeprecatedMethodCalled()); } -} \ No newline at end of file +} diff --git a/core/src/test/java/hudson/model/FingerprintCleanupThreadTest.java b/core/src/test/java/hudson/model/FingerprintCleanupThreadTest.java index ec9b6ad7ce..61a1a72645 100644 --- a/core/src/test/java/hudson/model/FingerprintCleanupThreadTest.java +++ b/core/src/test/java/hudson/model/FingerprintCleanupThreadTest.java @@ -65,7 +65,7 @@ public void testFingerprintFileIsEmpty() throws IOException { } @Test - public void testGetRecurencePeriod() throws IOException { + public void testGetRecurrencePeriod() throws IOException { FingerprintCleanupThread cleanupThread = new TestFingerprintCleanupThread(new TestFingerprint()); assertEquals("Wrong recurrence period.", PeriodicWork.DAY, cleanupThread.getRecurrencePeriod()); } diff --git a/core/src/test/java/hudson/model/QueueTest.java b/core/src/test/java/hudson/model/QueueTest.java new file mode 100644 index 0000000000..15cc6f2dda --- /dev/null +++ b/core/src/test/java/hudson/model/QueueTest.java @@ -0,0 +1,72 @@ +package hudson.model; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.jvnet.hudson.test.Issue; +import org.kohsuke.stapler.HttpResponse; +import org.kohsuke.stapler.StaplerResponse; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class QueueTest { + + @Mock + StaplerResponse resp; + @Mock + Queue.Task task; + @Mock + PrintWriter writer; + + @Before + public void setup() throws IOException { + when(resp.getWriter()).thenReturn(writer); + } + + @Issue("JENKINS-21311") + @Test + public void cancelItemOnaValidItemShouldReturnA204() throws IOException, ServletException { + when(task.hasAbortPermission()).thenReturn(true); + Queue queue = new Queue(LoadBalancer.CONSISTENT_HASH); + queue.schedule(task, 6000); + + HttpResponse httpResponse = queue.doCancelItem(Queue.WaitingItem.getCurrentCounterValue()); + httpResponse.generateResponse(null, resp, null); + + verify(resp).setStatus(HttpServletResponse.SC_NO_CONTENT); + } + + @Issue("JENKINS-21311") + @Test + public void cancelItemOnANonExistingItemShouldReturnA404() throws IOException, ServletException { + Queue queue = new Queue(LoadBalancer.CONSISTENT_HASH); + queue.schedule(task, 6000); + + HttpResponse httpResponse = queue.doCancelItem(Queue.WaitingItem.getCurrentCounterValue() + 1); + httpResponse.generateResponse(null, resp, null); + + verify(resp).setStatus(HttpServletResponse.SC_NOT_FOUND); + } + + @Issue("JENKINS-21311") + @Test + public void cancelItemOnANonCancellableItemShouldReturnA422() throws IOException, ServletException { + when(task.hasAbortPermission()).thenReturn(false); + Queue queue = new Queue(LoadBalancer.CONSISTENT_HASH); + queue.schedule(task, 6000); + + HttpResponse httpResponse = queue.doCancelItem(Queue.WaitingItem.getCurrentCounterValue()); + httpResponse.generateResponse(null, resp, null); + + verify(resp).setStatus(422); + } +} diff --git a/core/src/test/java/hudson/util/ArgumentListBuilderTest.java b/core/src/test/java/hudson/util/ArgumentListBuilderTest.java index 564ad81a5d..2f143b1567 100644 --- a/core/src/test/java/hudson/util/ArgumentListBuilderTest.java +++ b/core/src/test/java/hudson/util/ArgumentListBuilderTest.java @@ -222,11 +222,9 @@ public void numberOfBackslashesInPropertiesShouldBePreservedAfterMacroExpansion( map.put("TWO", "two\\\\backslashes"); map.put("FOUR", "four\\\\\\\\backslashes"); - final String properties = new StringBuilder() - .append("one=$ONE\n") - .append("two=$TWO\n") - .append("four=$FOUR\n") - .toString() + final String properties = "one=$ONE\n" + + "two=$TWO\n" + + "four=$FOUR\n" ; final String args = new ArgumentListBuilder() diff --git a/core/src/test/java/hudson/util/CopyOnWriteListTest.java b/core/src/test/java/hudson/util/CopyOnWriteListTest.java index 0d734c389a..3f4eb9ebc1 100644 --- a/core/src/test/java/hudson/util/CopyOnWriteListTest.java +++ b/core/src/test/java/hudson/util/CopyOnWriteListTest.java @@ -23,10 +23,14 @@ */ package hudson.util; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.xmlunit.matchers.CompareMatcher.isSimilarTo; import org.junit.Test; +import org.xmlunit.diff.DefaultNodeMatcher; +import org.xmlunit.diff.ElementSelectors; import java.util.ArrayList; import java.util.List; @@ -50,21 +54,25 @@ public void serialization() { TestData td = new TestData(); String out = xs.toXML(td); - assertEquals("empty lists", "" - + "", - out.replaceAll("\\s+", "")); - TestData td2 = (TestData)xs.fromXML(out.toString()); + String expected = "" + + ""; + assertThat(out, isSimilarTo(expected).ignoreWhitespace() + .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText))); + + + TestData td2 = (TestData)xs.fromXML(out); assertTrue(td2.list1.isEmpty()); assertTrue(td2.list2.isEmpty()); td.list1.add("foobar1"); td.list2.add("foobar2"); out = xs.toXML(td); - assertEquals("lists", "" + expected = "" + "foobar1foobar2" - + "", - out.replaceAll("\\s+", "")); - td2 = (TestData)xs.fromXML(out.toString()); + + ""; + assertThat(out, isSimilarTo(expected).ignoreWhitespace() + .withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText))); + td2 = (TestData)xs.fromXML(out); assertEquals("foobar1", td2.list1.getView().get(0)); assertEquals("foobar2", td2.list2.get(0)); } diff --git a/core/src/test/java/hudson/util/SecretTest.java b/core/src/test/java/hudson/util/SecretTest.java index 2fec21b6e1..32b8d86ceb 100644 --- a/core/src/test/java/hudson/util/SecretTest.java +++ b/core/src/test/java/hudson/util/SecretTest.java @@ -24,6 +24,7 @@ package hudson.util; +import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.Random; import java.util.regex.Pattern; @@ -124,7 +125,7 @@ public void migrationFromLegacyKeyToConfidentialStore() throws Exception { for (String str : new String[] {"Hello world", "", "\u0000unprintable"}) { Cipher cipher = Secret.getCipher("AES"); cipher.init(Cipher.ENCRYPT_MODE, legacy); - String old = new String(Base64.getEncoder().encode(cipher.doFinal((str + HistoricalSecrets.MAGIC).getBytes("UTF-8")))); + String old = new String(Base64.getEncoder().encode(cipher.doFinal((str + HistoricalSecrets.MAGIC).getBytes(StandardCharsets.UTF_8)))); Secret s = Secret.fromString(old); assertEquals("secret by the old key should decrypt", str, s.getPlainText()); assertNotEquals("but when encrypting, ConfidentialKey should be in use", old, s.getEncryptedValue()); diff --git a/core/src/test/java/hudson/util/XStream2EncodingTest.java b/core/src/test/java/hudson/util/XStream2EncodingTest.java index ea23797dea..d51226b4f3 100644 --- a/core/src/test/java/hudson/util/XStream2EncodingTest.java +++ b/core/src/test/java/hudson/util/XStream2EncodingTest.java @@ -28,6 +28,8 @@ import java.io.ByteArrayOutputStream; import java.lang.reflect.Field; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + import static org.hamcrest.CoreMatchers.*; import org.junit.After; import static org.junit.Assert.*; @@ -70,7 +72,7 @@ private void clearDefaultEncoding() { Thing t = (Thing) xs.fromXML(new ByteArrayInputStream(ambiguousXml)); assertThat(t.field, not(msg)); ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); - baos2.write("\n".getBytes("UTF-8")); + baos2.write("\n".getBytes(StandardCharsets.UTF_8)); baos2.write(ambiguousXml); t = (Thing) xs.fromXML(new ByteArrayInputStream(ambiguousXml)); assertThat(t.field, not(msg)); diff --git a/core/src/test/java/hudson/util/io/ZipArchiverTest.java b/core/src/test/java/hudson/util/io/ZipArchiverTest.java index 59767b16fc..f865016113 100644 --- a/core/src/test/java/hudson/util/io/ZipArchiverTest.java +++ b/core/src/test/java/hudson/util/io/ZipArchiverTest.java @@ -82,21 +82,11 @@ public void backwardsSlashesOnWindows() { // back-slashes ("\") String zipEntryName = null; - ZipFile zipFileVerify = null; - try { - zipFileVerify = new ZipFile(zipFile); + try (ZipFile zipFileVerify = new ZipFile(zipFile)) { zipEntryName = ((ZipEntry) zipFileVerify.entries().nextElement()).getName(); } catch (Exception e) { fail("failure enumerating zip entries", e); - } finally { - if (zipFileVerify != null) { - try { - zipFileVerify.close(); - } catch (IOException e) { - // ignored - } - } } assertEquals("foo/bar/baz/Test.txt", zipEntryName); @@ -144,21 +134,11 @@ public void huge64bitFile() { // examine zip contents and assert that there's an item there... String zipEntryName = null; - ZipFile zipFileVerify = null; - try { - zipFileVerify = new ZipFile(zipFile); + try (ZipFile zipFileVerify = new ZipFile(zipFile)) { zipEntryName = ((ZipEntry) zipFileVerify.entries().nextElement()).getName(); } catch (Exception e) { fail("failure enumerating zip entries", e); - } finally { - if (zipFileVerify != null) { - try { - zipFileVerify.close(); - } catch (IOException e) { - // ignored - } - } } assertEquals("huge64bitFileTest.txt", zipEntryName); diff --git a/core/src/test/java/jenkins/model/lazy/FakeMapBuilder.java b/core/src/test/java/jenkins/model/lazy/FakeMapBuilder.java index 4013736cb8..8a9aeb262f 100644 --- a/core/src/test/java/jenkins/model/lazy/FakeMapBuilder.java +++ b/core/src/test/java/jenkins/model/lazy/FakeMapBuilder.java @@ -54,7 +54,7 @@ public FakeMapBuilder add(int n) throws IOException { } /** - * Adds a build record under the givn ID but make it unloadable, + * Adds a build record under the given ID but make it unloadable, * which will cause a failure when a load is attempted on this build ID. */ public FakeMapBuilder addUnloadable(int n) throws IOException { diff --git a/core/src/test/java/jenkins/security/RSADigitalSignatureConfidentialKeyTest.java b/core/src/test/java/jenkins/security/RSADigitalSignatureConfidentialKeyTest.java index bb8832e349..51b088ab27 100644 --- a/core/src/test/java/jenkins/security/RSADigitalSignatureConfidentialKeyTest.java +++ b/core/src/test/java/jenkins/security/RSADigitalSignatureConfidentialKeyTest.java @@ -23,6 +23,7 @@ */ package jenkins.security; +import java.nio.charset.StandardCharsets; import java.security.Signature; import java.util.Base64; import static org.junit.Assert.assertTrue; @@ -44,7 +45,7 @@ public void dsigSignAndVerify() throws Exception { Signature sig = Signature.getInstance("SHA256withRSA"); sig.initVerify(key.getPublicKey()); - sig.update(plainText.getBytes("UTF-8")); + sig.update(plainText.getBytes(StandardCharsets.UTF_8)); assertTrue(sig.verify(Base64.getDecoder().decode(msg))); } diff --git a/core/src/test/java/jenkins/util/MarkFindingOutputStreamTest.java b/core/src/test/java/jenkins/util/MarkFindingOutputStreamTest.java index 7ab0f48cdb..3de38b3449 100644 --- a/core/src/test/java/jenkins/util/MarkFindingOutputStreamTest.java +++ b/core/src/test/java/jenkins/util/MarkFindingOutputStreamTest.java @@ -5,6 +5,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.nio.charset.StandardCharsets; import org.junit.Test; @@ -75,7 +76,7 @@ private void assertCount(int n) { } private void write(String s) throws IOException { - m.write(s.getBytes("UTF-8")); + m.write(s.getBytes(StandardCharsets.UTF_8)); } private void writeOneByOne(String s) throws IOException { diff --git a/essentials.yml b/essentials.yml index e5eaf42fb8..335cf29ada 100644 --- a/essentials.yml +++ b/essentials.yml @@ -1,7 +1,7 @@ --- ath: useLocalSnapshots: false - athRevision: "5606d3bb3a645311711b74833d5d3a4fdc4d713d" + athRevision: "7bd2cd43e03848d2db1f07be9115a2ebe24e9527" athImage: "jenkins/ath@sha256:284c2fdfaf1a51e95783126367c0a88c07af83ff9234063d12ba3001959628e8" categories: - org.jenkinsci.test.acceptance.junit.SmokeTest diff --git a/pom.xml b/pom.xml index c7dfcae0a1..f29a642ecd 100755 --- a/pom.xml +++ b/pom.xml @@ -52,7 +52,6 @@ THE SOFTWARE. bom core war - test-pom test cli @@ -77,7 +76,7 @@ THE SOFTWARE. - 2.204 + 2.215 -SNAPSHOT - 3.35 + 4.0 3.14 @@ -365,12 +364,6 @@ THE SOFTWARE. org.apache.maven.plugins maven-pmd-plugin - - - org.jenkins-ci.tools - maven-jenkins-dev-plugin - 9.4.12.v20180830-jenkins-2 - org.jvnet.updatecenter2 maven-makepkgs-plugin @@ -503,15 +496,6 @@ THE SOFTWARE. - - - - org.jenkins-ci.tools - maven-jenkins-dev-plugin - @@ -672,14 +656,5 @@ THE SOFTWARE. 11 - - jdk8 - - test-jdk8 - - - 1.8 - - diff --git a/src/findbugs/findbugs-excludes.xml b/src/findbugs/findbugs-excludes.xml index f8e3d3061a..665871ffd1 100644 --- a/src/findbugs/findbugs-excludes.xml +++ b/src/findbugs/findbugs-excludes.xml @@ -6,8 +6,6 @@ - - diff --git a/test-jdk8/pom.xml b/test-jdk8/pom.xml deleted file mode 100644 index 70c4870837..0000000000 --- a/test-jdk8/pom.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - 4.0.0 - - - org.jenkins-ci.main - jenkins-test-parent - ${revision}${changelist} - ../test-pom - - - jenkins-test-jdk8 - - JDK8-only tests for Jenkins core - JDK8-only Functional tests for Jenkins core - - diff --git a/test-pom/pom.xml b/test-pom/pom.xml deleted file mode 100644 index 832cd72e48..0000000000 --- a/test-pom/pom.xml +++ /dev/null @@ -1,402 +0,0 @@ - - - - 4.0.0 - - - org.jenkins-ci.main - jenkins-parent - ${revision}${changelist} - - - jenkins-test-parent - - Jenkins core tests POM - Parent POM for Functional tests for Jenkins core - pom - - - 2 - false - - - - - - - org.jenkins-ci.main - jenkins-bom - ${project.version} - pom - import - - - com.google.code.findbugs - annotations - 3.0.1 - provided - - - - - - ${project.groupId} - jenkins-war - ${project.version} - executable-war - test - - - ${project.groupId} - jenkins-test-harness - 2.55 - test - - - ${project.groupId} - jenkins-war - - - - - ${project.groupId} - jenkins-test-harness-tools - 2.0 - test - - - org.jenkins-ci.plugins - cloudbees-folder - 6.3 - test - - - ${project.groupId} - maven-plugin - 2.14 - - - org.apache.httpcomponents - httpclient - - - org.apache.httpcomponents - httpcore - - - commons-codec - commons-codec - - - com.google.inject - guice - - - org.apache.ant - ant - - - - - - org.jenkins-ci.plugins - mailer - 1.23 - - - org.jenkins-ci.plugins - matrix-auth - ${matrix-auth.version} - - - org.jenkins-ci.plugins - antisamy-markup-formatter - 1.0 - test - - - org.jenkins-ci.plugins - matrix-project - ${matrix-project.version} - - - org.jenkins-ci.plugins - junit - 1.26.1 - test - - - org.jenkins-ci.plugins - structs - 1.7 - test - - - org.jvnet.mock-javamail - mock-javamail - 1.7 - - - javax.mail - mail - - - - - org.hamcrest - hamcrest-core - 1.3 - - - - org.jvnet.hudson - netx - 0.5-hudson-2 - - - org.easymock - easymock - 2.4 - - - org.mockito - mockito-core - test - - - org.reflections - reflections - 0.9.9 - - - com.google.guava - guava - - - com.google.code.findbugs - jsr305 - - - - - org.codehaus.geb - geb-implicit-assertions - 0.7.2 - - - org.javassist - javassist - 3.19.0-GA - test - - - org.apache.commons - commons-collections4 - 4.0 - test - - - org.awaitility - awaitility - 3.0.0 - test - - - org.objenesis - objenesis - test - - - - - - - org.jenkins-ci.tools - maven-hpi-plugin - true - - - org.kohsuke.stapler - maven-stapler-plugin - - true - - - maven-dependency-plugin - - - old-remoting-for-test - generate-test-resources - - - copy - - - - - org.jenkins-ci.main - remoting - ${remoting.minimum.supported.version} - jar - ${project.build.outputDirectory}/old-remoting - remoting-minimal-supported.jar - - - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - ${jacocoSurefireArgs} -Dfile.encoding=UTF-8 -Xmx1g -Djdk.net.URLClassPath.disableClassPathURLCheck=true - - - true - ${mavenDebug} - ${project.build.directory} - - false - ${concurrency} - - - - maven-deploy-plugin - - true - - - - org.apache.maven.plugins - maven-enforcer-plugin - - - - - org.apache.maven:maven-embedder - org.codehaus.plexus:plexus-classworlds - org.apache.maven:maven-core - org.apache.maven:maven-aether-provider - org.codehaus.plexus:plexus-utils - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - true - - - - - - - - - light-test - - true - - - - - smoke-test - - - - maven-surefire-plugin - - org.jvnet.hudson.test.SmokeTest - - - - - - - all-tests - - - !test - - - - true - 4 - 100 - - - - jacoco - - - - org.jacoco - jacoco-maven-plugin - 0.6.3.201306030806 - - - - pre-unit-test - - prepare-agent - - - - ${project.build.directory}/coverage-reports/jacoco-ut.exec - jacocoSurefireArgs - - - - - post-unit-test - test - - report - - - - ${project.build.directory}/coverage-reports/jacoco-ut.exec - - ${project.reporting.outputDirectory}/jacoco-ut - - - - - - - - - diff --git a/test/pom.xml b/test/pom.xml index 4c5abecc6f..1832600737 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -2,7 +2,7 @@ + false + + + + + + + org.jenkins-ci.main + jenkins-bom + ${project.version} + pom + import + + + com.google.code.findbugs + annotations + 3.0.1 + provided + + + + + + ${project.groupId} + jenkins-war + ${project.version} + executable-war + test + + + ${project.groupId} + jenkins-test-harness + 2.59 + test + + + ${project.groupId} + jenkins-war + + + + + ${project.groupId} + jenkins-test-harness-tools + 2.0 + test + + + org.jenkins-ci.plugins + cloudbees-folder + 6.3 + test + + + ${project.groupId} + maven-plugin + 2.14 + + + org.apache.httpcomponents + httpclient + + + org.apache.httpcomponents + httpcore + + + commons-codec + commons-codec + + + com.google.inject + guice + + + org.apache.ant + ant + + + + + + org.jenkins-ci.plugins + mailer + 1.23 + + + org.jenkins-ci.plugins + matrix-auth + ${matrix-auth.version} + + + org.jenkins-ci.plugins + antisamy-markup-formatter + 1.0 + test + + + org.jenkins-ci.plugins + matrix-project + ${matrix-project.version} + + + org.jenkins-ci.plugins + junit + 1.26.1 + test + + + org.jenkins-ci.plugins + structs + 1.7 + test + + + org.jvnet.mock-javamail + mock-javamail + 1.7 + + + javax.mail + mail + + + + + org.hamcrest + hamcrest-core + 2.2 + + + + org.jvnet.hudson + netx + 0.5-hudson-2 + + + org.easymock + easymock + 2.4 + + + org.mockito + mockito-core + test + + + org.reflections + reflections + 0.9.9 + + + com.google.guava + guava + + + com.google.code.findbugs + jsr305 + + + + + org.codehaus.geb + geb-implicit-assertions + 0.7.2 + + + org.javassist + javassist + 3.19.0-GA + test + + + org.apache.commons + commons-collections4 + 4.0 + test + + + org.awaitility + awaitility + 3.0.0 + test + + + org.objenesis + objenesis + test + + + + + + + org.jenkins-ci.tools + maven-hpi-plugin + true + + + org.kohsuke.stapler + maven-stapler-plugin + + true + + + maven-dependency-plugin + + + old-remoting-for-test + generate-test-resources + + + copy + + + + + org.jenkins-ci.main + remoting + ${remoting.minimum.supported.version} + jar + ${project.build.outputDirectory}/old-remoting + remoting-minimal-supported.jar + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + ${jacocoSurefireArgs} -Dfile.encoding=UTF-8 -Xmx1g -Djdk.net.URLClassPath.disableClassPathURLCheck=true + + + true + ${mavenDebug} + ${project.build.directory} + + false + ${concurrency} + + + + maven-deploy-plugin + + true + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + + + org.apache.maven:maven-embedder + org.codehaus.plexus:plexus-classworlds + org.apache.maven:maven-core + org.apache.maven:maven-aether-provider + org.codehaus.plexus:plexus-utils + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + true + + + + + + + + + light-test + + true + + + + + smoke-test + + + + maven-surefire-plugin + + org.jvnet.hudson.test.SmokeTest + + + + + + + all-tests + + + !test + + + + true + 4 + 100 + + + + jacoco + + + + org.jacoco + jacoco-maven-plugin + 0.6.3.201306030806 + + + + pre-unit-test + + prepare-agent + + + + ${project.build.directory}/coverage-reports/jacoco-ut.exec + jacocoSurefireArgs + + + + + post-unit-test + test + + report + + + + ${project.build.directory}/coverage-reports/jacoco-ut.exec + + ${project.reporting.outputDirectory}/jacoco-ut + + + + + + + + diff --git a/test/src/test/java/hudson/ExtensionFinderTest.java b/test/src/test/java/hudson/ExtensionFinderTest.java index df1a809fc7..b323070128 100644 --- a/test/src/test/java/hudson/ExtensionFinderTest.java +++ b/test/src/test/java/hudson/ExtensionFinderTest.java @@ -25,29 +25,36 @@ import com.google.inject.AbstractModule; import hudson.model.PageDecorator; -import org.jvnet.hudson.test.HudsonTestCase; -import org.jvnet.hudson.test.TestEnvironment; -import org.jvnet.hudson.test.TestExtension; - -import javax.inject.Inject; -import javax.inject.Qualifier; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import javax.inject.Inject; +import javax.inject.Qualifier; +import static org.junit.Assert.*; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.TestEnvironment; +import org.jvnet.hudson.test.TestExtension; /** * @author Kohsuke Kawaguchi */ -public class ExtensionFinderTest extends HudsonTestCase { +public class ExtensionFinderTest { + + @Rule + public JenkinsRule r = new JenkinsRule(); + /** * It's OK for some extensions to fail to load. The system needs to tolerate that. */ - public void testFailingInstance() { + @Test + public void failingInstance() { FailingExtension i = PageDecorator.all().get(FailingExtension.class); assertNull("Instantiation should have failed",i); assertTrue("Instantiation should have been attempted", FailingExtension.error); } - @TestExtension("testFailingInstance") + @TestExtension("failingInstance") public static class FailingExtension extends PageDecorator { public FailingExtension() { super(FailingExtension.class); @@ -64,13 +71,14 @@ public FailingExtension() { /** * Extensions are Guice components, so it should support injection. */ - public void testInjection() { + @Test + public void injection() { InjectingExtension i = PageDecorator.all().get(InjectingExtension.class); assertNotNull(i.foo); assertEquals("lion king",i.value); } - @TestExtension("testInjection") + @TestExtension("injection") public static class InjectingExtension extends PageDecorator { @Inject Foo foo; @@ -94,7 +102,7 @@ public static class ModuleImpl extends AbstractModule { protected void configure() { TestEnvironment environment = TestEnvironment.get(); // JMH benchmarks do not initialize TestEnvironment, so check for null - if (environment != null && environment.testCase instanceof ExtensionFinderTest) { + if (environment != null && ExtensionFinderTest.class.getName().equals(environment.description().getClassName()) && "injection".equals(environment.description().getMethodName())) { bind(String.class).annotatedWith(LionKing.class).toInstance("lion king"); } } @@ -106,12 +114,13 @@ protected void configure() { * * One failure in binding definition shouldn't prevent Jenkins from booting. */ - public void testErrorRecovery() { + @Test + public void errorRecovery() { BrokenExtension i = PageDecorator.all().get(BrokenExtension.class); assertNull(i); } - @TestExtension("testErrorRecovery") + @TestExtension("errorRecovery") public static class BrokenExtension extends PageDecorator { public BrokenExtension() { super(InjectingExtension.class); @@ -119,4 +128,21 @@ public BrokenExtension() { throw new Error(); } } + + @Test + public void injectMutualRecursion() { + A a = ExtensionList.lookupSingleton(A.class); + B b = ExtensionList.lookupSingleton(B.class); + assertEquals(b, a.b); + assertEquals(a, b.a); + } + @TestExtension("injectMutualRecursion") + public static final class A { + @Inject B b; + } + @TestExtension("injectMutualRecursion") + public static final class B { + @Inject A a; + } + } diff --git a/test/src/test/java/hudson/PluginManagerTest.java b/test/src/test/java/hudson/PluginManagerTest.java index 535587df86..57cd87d9f9 100644 --- a/test/src/test/java/hudson/PluginManagerTest.java +++ b/test/src/test/java/hudson/PluginManagerTest.java @@ -333,6 +333,11 @@ private String callDependerValue() throws Exception { fail(); } catch( ClassNotFoundException ex ){ } + // Extension extending a dependee class can't be loaded either + try { + r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.depender.DependerExtension"); + fail(); + } catch( NoClassDefFoundError ex ){} // Load dependee. { @@ -342,10 +347,33 @@ private String callDependerValue() throws Exception { // (MUST) Not throws an exception // (SHOULD) depender successfully accesses to dependee. assertEquals("dependee", callDependerValue()); - - // No extensions exist. - // extensions in depender are loaded. - assertFalse(r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.dependee.DependeeExtensionPoint").isEmpty()); + + // Extensions in depender are loaded. + assertEquals(1, r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.depender.DependerExtension").size()); + } + + /** + * Load "optional-depender" and then load "dependee". + * Asserts that "depender" can access to "dependee". + * + * @throws Exception + */ + @Issue("JENKINS-60449") + @WithPlugin("variant.hpi") + @Test public void installDependedOptionalPluginWithoutRestart() throws Exception { + // Load optional-depender. + { + dynamicLoad("optional-depender-0.0.2.hpi"); + } + // Extension depending on dependee class isn't loaded + assertTrue(r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.optionaldepender.OptionalDependerExtension").isEmpty()); + // Load dependee. + { + dynamicLoad("dependee-0.0.2.hpi"); + } + + // Extensions in depender are loaded. + assertEquals(1, r.jenkins.getExtensionList("org.jenkinsci.plugins.dependencytest.optionaldepender.OptionalDependerExtension").size()); } @Issue("JENKINS-21486") diff --git a/test/src/test/java/hudson/PluginTest.java b/test/src/test/java/hudson/PluginTest.java index 7b05f96e8b..b4a2217b27 100644 --- a/test/src/test/java/hudson/PluginTest.java +++ b/test/src/test/java/hudson/PluginTest.java @@ -48,9 +48,11 @@ public class PluginTest { ((TestPluginManager) r.jenkins.pluginManager).installDetachedPlugin("matrix-auth"); r.createWebClient().goTo("plugin/matrix-auth/images/user-disabled.png", "image/png"); r.createWebClient().goTo("plugin/matrix-auth/images/../images/user-disabled.png", "image/png"); // collapsed somewhere before it winds up in restOfPath + /* TODO https://github.com/apache/httpcomponents-client/commit/8c04c6ae5e5ba1432e40684428338ce68431766b#r32873542 r.createWebClient().assertFails("plugin/matrix-auth/images/%2E%2E/images/user-disabled.png", HttpServletResponse.SC_INTERNAL_SERVER_ERROR); // IAE from TokenList. r.createWebClient().assertFails("plugin/matrix-auth/images/%252E%252E/images/user-disabled.png", HttpServletResponse.SC_BAD_REQUEST); // SECURITY-131 r.createWebClient().assertFails("plugin/matrix-auth/images/%25252E%25252E/images/user-disabled.png", HttpServletResponse.SC_BAD_REQUEST); // just checking + */ // SECURITY-705: r.createWebClient().assertFails("plugin/matrix-auth/images/..%2fWEB-INF/licenses.xml", HttpServletResponse.SC_BAD_REQUEST); r.createWebClient().assertFails("plugin/matrix-auth/./matrix-auth.jpi", /* Path collapsed to simply `credentials.jpi` before entering */ HttpServletResponse.SC_NOT_FOUND); diff --git a/test/src/test/java/hudson/cli/CLIActionTest.java b/test/src/test/java/hudson/cli/CLIActionTest.java index 4e7e2a7acc..f3840459b8 100644 --- a/test/src/test/java/hudson/cli/CLIActionTest.java +++ b/test/src/test/java/hudson/cli/CLIActionTest.java @@ -20,7 +20,6 @@ import java.net.HttpURLConnection; import java.util.Arrays; import java.util.List; -import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import jenkins.model.Jenkins; @@ -53,8 +52,6 @@ public class CLIActionTest { @Rule public LoggerRule logging = new LoggerRule(); - private ExecutorService pool; - @Test @PresetData(DataSet.NO_ANONYMOUS_READACCESS) @Issue("SECURITY-192") @@ -87,7 +84,6 @@ public void authentication() throws Exception { // @CLIMethod: assertExitCode(6, false, jar, "disable-job", "p"); // AccessDeniedException from CLIRegisterer? assertExitCode(0, true, jar, "disable-job", "p"); - // If we have anonymous read access, then the situation is simpler. j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy().grant(Jenkins.ADMINISTER).everywhere().to(ADMIN).grant(Jenkins.READ, Item.READ).everywhere().toEveryone()); assertExitCode(6, false, jar, "get-job", "p"); // AccessDeniedException from AbstractItem.writeConfigDotXml assertExitCode(0, true, jar, "get-job", "p"); // works with API tokens @@ -98,7 +94,7 @@ public void authentication() throws Exception { private static final String ADMIN = "admin@mycorp.com"; private void assertExitCode(int code, boolean useApiToken, File jar, String... args) throws IOException, InterruptedException { - List commands = Lists.newArrayList("java", "-jar", jar.getAbsolutePath(), "-s", j.getURL().toString(), /* not covering SSH keys in this test */ "-noKeyAuth"); + List commands = Lists.newArrayList("java", "-jar", jar.getAbsolutePath(), "-s", j.getURL().toString(), /* TODO until it is the default */ "-webSocket"); if (useApiToken) { commands.add("-auth"); commands.add(ADMIN + ":" + User.get(ADMIN).getProperty(ApiTokenProperty.class).getApiToken()); @@ -137,7 +133,8 @@ public void encodingAndLocale() throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); assertEquals(0, new Launcher.LocalLauncher(StreamTaskListener.fromStderr()).launch().cmds( "java", "-Dfile.encoding=ISO-8859-2", "-Duser.language=cs", "-Duser.country=CZ", "-jar", jar.getAbsolutePath(), - "-s", j.getURL().toString()./* just checking */replaceFirst("/$", ""), "-noKeyAuth", "test-diagnostic"). + "-webSocket", // TODO as above + "-s", j.getURL().toString()./* just checking */replaceFirst("/$", ""), "test-diagnostic"). stdout(baos).stderr(System.err).join()); assertEquals("encoding=ISO-8859-2 locale=cs_CZ", baos.toString().trim()); // TODO test that stdout/stderr are in expected encoding (not true of -remoting mode!) @@ -155,7 +152,9 @@ public void interleavedStdio() throws Exception { PipedOutputStream pos = new PipedOutputStream(pis); PrintWriter pw = new PrintWriter(new TeeOutputStream(pos, System.err), true); Proc proc = new Launcher.LocalLauncher(StreamTaskListener.fromStderr()).launch().cmds( - "java", "-jar", jar.getAbsolutePath(), "-s", j.getURL().toString(), "-noKeyAuth", "groovysh"). + "java", "-jar", jar.getAbsolutePath(), "-s", j.getURL().toString(), + "-webSocket", // TODO as above + "groovysh"). stdout(new TeeOutputStream(baos, System.out)).stderr(System.err).stdin(pis).start(); while (!baos.toString().contains("000")) { // cannot just search for, say, "groovy:000> " since there are ANSI escapes there (cf. StringEscapeUtils.escapeJava) Thread.sleep(100); @@ -164,7 +163,6 @@ public void interleavedStdio() throws Exception { while (!baos.toString().contains("121")) { // ditto not "===> 121" Thread.sleep(100); } - Thread.sleep(31_000); // aggravate org.eclipse.jetty.io.IdleTimeout (cf. AbstractConnector._idleTimeout) pw.println("11 * 11 * 11"); while (!baos.toString().contains("1331")) { Thread.sleep(100); diff --git a/test/src/test/java/hudson/cli/CLITest.java b/test/src/test/java/hudson/cli/CLITest.java index 14ff043c68..ca541bc950 100644 --- a/test/src/test/java/hudson/cli/CLITest.java +++ b/test/src/test/java/hudson/cli/CLITest.java @@ -157,6 +157,7 @@ public void interrupt() throws Exception { p.getBuildersList().add(new SleepBuilder(TimeUnit.MINUTES.toMillis(5))); doInterrupt(p, "-ssh", "-user", "admin", "-i", privkey.getAbsolutePath()); doInterrupt(p, "-http", "-auth", "admin:admin"); + doInterrupt(p, "-webSocket", "-auth", "admin:admin"); } private void doInterrupt(FreeStyleProject p, String... modeArgs) throws Exception { ByteArrayOutputStream baos = new ByteArrayOutputStream(); @@ -191,6 +192,7 @@ public void reportNotJenkins() throws Exception { assertThat(baos.toString(), containsString("There's no Jenkins running at")); assertNotEquals(0, ret); } + // TODO -webSocket currently produces a stack trace } @TestExtension("reportNotJenkins") public static final class NoJenkinsAction extends CrumbExclusion implements UnprotectedRootAction, StaplerProxy { @@ -240,11 +242,11 @@ public void redirectToEndpointShouldBeFollowed() throws Exception { WebResponse rsp = wc.goTo("cli-proxy/").getWebResponse(); assertEquals(rsp.getContentAsString(), HttpURLConnection.HTTP_MOVED_TEMP, rsp.getStatusCode()); - assertEquals(rsp.getContentAsString(), null, rsp.getResponseHeaderValue("X-Jenkins")); - assertEquals(rsp.getContentAsString(), null, rsp.getResponseHeaderValue("X-Jenkins-CLI-Port")); - assertEquals(rsp.getContentAsString(), null, rsp.getResponseHeaderValue("X-SSH-Endpoint")); + assertNull(rsp.getContentAsString(), rsp.getResponseHeaderValue("X-Jenkins")); + assertNull(rsp.getContentAsString(), rsp.getResponseHeaderValue("X-Jenkins-CLI-Port")); + assertNull(rsp.getContentAsString(), rsp.getResponseHeaderValue("X-SSH-Endpoint")); - for (String transport: Arrays.asList("-http", "-ssh")) { + for (String transport: Arrays.asList("-http", "-ssh", "-webSocket")) { String url = r.getURL().toString() + "cli-proxy/"; ByteArrayOutputStream baos = new ByteArrayOutputStream(); diff --git a/test/src/test/java/hudson/cli/CancelQuietDownCommandTest.java b/test/src/test/java/hudson/cli/CancelQuietDownCommandTest.java index 8c1a4c7e43..d4c40b9cb3 100644 --- a/test/src/test/java/hudson/cli/CancelQuietDownCommandTest.java +++ b/test/src/test/java/hudson/cli/CancelQuietDownCommandTest.java @@ -79,7 +79,7 @@ public void cancelQuietDownShouldSuccessOnNoQuietDownedJenkins() throws Exceptio @Test public void cancelQuietDownShouldSuccessOnQuietDownedJenkins() throws Exception { - j.jenkins.getActiveInstance().doQuietDown(); + j.jenkins.doQuietDown(); QuietDownCommandTest.assertJenkinsInQuietMode(j); final CLICommandInvoker.Result result = command .authorizedTo(Jenkins.READ, Jenkins.ADMINISTER) @@ -132,7 +132,7 @@ public void cancelQuietDownShouldSuccessOnQuietDownedJenkinsAndRunningExecutor() Future build = OnlineNodeCommandTest.startBlockingAndFinishingBuild(project, finish); assertThat(((FreeStyleProject) j.jenkins.getItem("aProject")).getBuilds(), hasSize(1)); assertThat(project.isBuilding(), equalTo(true)); - j.jenkins.getActiveInstance().doQuietDown(); + j.jenkins.doQuietDown(); QuietDownCommandTest.assertJenkinsInQuietMode(j); final CLICommandInvoker.Result result = command @@ -156,4 +156,4 @@ public void cancelQuietDownShouldSuccessOnQuietDownedJenkinsAndRunningExecutor() j.assertBuildStatusSuccess(build); QuietDownCommandTest.assertJenkinsNotInQuietMode(j); } -} \ No newline at end of file +} diff --git a/test/src/test/java/hudson/cli/ConnectNodeCommandTest.java b/test/src/test/java/hudson/cli/ConnectNodeCommandTest.java index a07755cfa6..0a443ed597 100644 --- a/test/src/test/java/hudson/cli/ConnectNodeCommandTest.java +++ b/test/src/test/java/hudson/cli/ConnectNodeCommandTest.java @@ -173,7 +173,7 @@ public class ConnectNodeCommandTest { } @Test public void connectNodeShouldSucceedOnMaster() throws Exception { - final Computer masterComputer = j.jenkins.getActiveInstance().getComputer(""); + final Computer masterComputer = j.jenkins.getComputer(""); CLICommandInvoker.Result result = command .authorizedTo(Computer.CONNECT, Jenkins.READ) diff --git a/test/src/test/java/hudson/cli/ConsoleCommandTest.java b/test/src/test/java/hudson/cli/ConsoleCommandTest.java index 70a2d9a595..1e8bcebe51 100644 --- a/test/src/test/java/hudson/cli/ConsoleCommandTest.java +++ b/test/src/test/java/hudson/cli/ConsoleCommandTest.java @@ -106,7 +106,7 @@ public class ConsoleCommandTest { assertThat(result.stderr(), containsString("ERROR: No such job 'never_created'")); } - @Test public void consoleShouldFailWhenLastBuildDoesNotdExist() throws Exception { + @Test public void consoleShouldFailWhenLastBuildDoesNotExist() throws Exception { j.createFreeStyleProject("aProject"); diff --git a/test/src/test/java/hudson/cli/DisconnectNodeCommandTest.java b/test/src/test/java/hudson/cli/DisconnectNodeCommandTest.java index a3a6a3ceed..6323e680c2 100644 --- a/test/src/test/java/hudson/cli/DisconnectNodeCommandTest.java +++ b/test/src/test/java/hudson/cli/DisconnectNodeCommandTest.java @@ -265,7 +265,7 @@ public void disconnectNodeManyShouldSucceedEvenANodeIsSpecifiedTwice() throws Ex } public void disconnectNodeShouldSucceedOnMaster() throws Exception { - final Computer masterComputer = j.jenkins.getActiveInstance().getComputer(""); + final Computer masterComputer = j.jenkins.getComputer(""); assertThat(masterComputer.isOnline(), equalTo(true)); assertThat(masterComputer.getOfflineCause(), equalTo(null)); diff --git a/test/src/test/java/hudson/cli/OfflineNodeCommandTest.java b/test/src/test/java/hudson/cli/OfflineNodeCommandTest.java index 07642d147b..6c64a7ba2f 100644 --- a/test/src/test/java/hudson/cli/OfflineNodeCommandTest.java +++ b/test/src/test/java/hudson/cli/OfflineNodeCommandTest.java @@ -453,7 +453,7 @@ public void offlineNodeManyShouldSucceedEvenANodeIsSpecifiedTwiceWithCause() thr @Test public void offlineNodeShouldSucceedOnMaster() throws Exception { - final Computer masterComputer = Jenkins.getActiveInstance().getComputer(""); + final Computer masterComputer = Jenkins.get().getComputer(""); final CLICommandInvoker.Result result = command .authorizedTo(Computer.DISCONNECT, Jenkins.READ) @@ -467,7 +467,7 @@ public void offlineNodeShouldSucceedOnMaster() throws Exception { @Test public void offlineNodeShouldSucceedOnMasterWithCause() throws Exception { - final Computer masterComputer = Jenkins.getActiveInstance().getComputer(""); + final Computer masterComputer = Jenkins.get().getComputer(""); final CLICommandInvoker.Result result = command .authorizedTo(Computer.DISCONNECT, Jenkins.READ) diff --git a/test/src/test/java/hudson/cli/OnlineNodeCommandTest.java b/test/src/test/java/hudson/cli/OnlineNodeCommandTest.java index 5b237af8d8..5712b6cfb1 100644 --- a/test/src/test/java/hudson/cli/OnlineNodeCommandTest.java +++ b/test/src/test/java/hudson/cli/OnlineNodeCommandTest.java @@ -286,7 +286,7 @@ public class OnlineNodeCommandTest { } @Test public void onlineNodeShouldSucceedOnMaster() throws Exception { - final Computer masterComputer = j.jenkins.getActiveInstance().getComputer(""); + final Computer masterComputer = j.jenkins.getComputer(""); CLICommandInvoker.Result result = command .authorizedTo(Computer.CONNECT, Jenkins.READ) diff --git a/test/src/test/java/hudson/cli/QuietDownCommandTest.java b/test/src/test/java/hudson/cli/QuietDownCommandTest.java index ecec6f956d..21e5de8fcc 100644 --- a/test/src/test/java/hudson/cli/QuietDownCommandTest.java +++ b/test/src/test/java/hudson/cli/QuietDownCommandTest.java @@ -128,7 +128,7 @@ public void quietDownShouldFailWithEmptyTimeout() throws Exception { @Test public void quietDownShouldSuccessOnAlreadyQuietDownedJenkins() throws Exception { - j.jenkins.getActiveInstance().doQuietDown(); + j.jenkins.doQuietDown(); assertJenkinsInQuietMode(); final CLICommandInvoker.Result result = command .authorizedTo(Jenkins.READ, Jenkins.ADMINISTER) @@ -139,7 +139,7 @@ public void quietDownShouldSuccessOnAlreadyQuietDownedJenkins() throws Exception @Test public void quietDownShouldSuccessWithBlockOnAlreadyQuietDownedJenkins() throws Exception { - j.jenkins.getActiveInstance().doQuietDown(true, 0); + j.jenkins.doQuietDown(true, 0); assertJenkinsInQuietMode(); final CLICommandInvoker.Result result = command .authorizedTo(Jenkins.READ, Jenkins.ADMINISTER) @@ -150,7 +150,7 @@ public void quietDownShouldSuccessWithBlockOnAlreadyQuietDownedJenkins() throws @Test public void quietDownShouldSuccessWithBlockAndTimeoutOnAlreadyQuietDownedJenkins() throws Exception { - j.jenkins.getActiveInstance().doQuietDown(true, 0); + j.jenkins.doQuietDown(true, 0); assertJenkinsInQuietMode(); final long time_before = System.currentTimeMillis(); final CLICommandInvoker.Result result = command @@ -483,7 +483,7 @@ private final void assertJenkinsNotInQuietMode() { public static final void assertJenkinsInQuietMode(final JenkinsRule j) { await().pollInterval(250, TimeUnit.MILLISECONDS) .atMost(10, TimeUnit.SECONDS) - .until(() -> j.jenkins.getActiveInstance().getQueue().isBlockedByShutdown(task)); + .until(() -> j.jenkins.getQueue().isBlockedByShutdown(task)); } /** @@ -493,6 +493,6 @@ public static final void assertJenkinsInQuietMode(final JenkinsRule j) { public static final void assertJenkinsNotInQuietMode(final JenkinsRule j) { await().pollInterval(250, TimeUnit.MILLISECONDS) .atMost(10, TimeUnit.SECONDS) - .until(() -> !j.jenkins.getActiveInstance().getQueue().isBlockedByShutdown(task)); + .until(() -> !j.jenkins.getQueue().isBlockedByShutdown(task)); } } diff --git a/test/src/test/java/hudson/diagnosis/HudsonHomeDiskUsageMonitorTest.java b/test/src/test/java/hudson/diagnosis/HudsonHomeDiskUsageMonitorTest.java index 975b6ea1bc..1a29a8fa8f 100644 --- a/test/src/test/java/hudson/diagnosis/HudsonHomeDiskUsageMonitorTest.java +++ b/test/src/test/java/hudson/diagnosis/HudsonHomeDiskUsageMonitorTest.java @@ -96,6 +96,8 @@ public void noAccessForNonAdmin() throws Exception { assertEquals(HttpURLConnection.HTTP_FORBIDDEN, p.getWebResponse().getStatusCode()); wc.withBasicApiToken(administrator); + request = new WebRequest(new URL(wc.getContextPath() + "administrativeMonitor/hudsonHomeIsFull/act"), HttpMethod.POST); + request.setRequestParameters(Collections.singletonList(param)); p = wc.getPage(request); assertEquals(HttpURLConnection.HTTP_OK, p.getWebResponse().getStatusCode()); assertFalse(mon.isEnabled()); diff --git a/test/src/test/java/hudson/markup/MarkupFormatterTest.java b/test/src/test/java/hudson/markup/MarkupFormatterTest.java index 7252bf6ca5..daf03665a1 100644 --- a/test/src/test/java/hudson/markup/MarkupFormatterTest.java +++ b/test/src/test/java/hudson/markup/MarkupFormatterTest.java @@ -69,4 +69,12 @@ public void translate(String markup, Writer output) throws IOException { @TestExtension public static class DescriptorImpl extends MarkupFormatterDescriptor {} } + + @Test + public void defaultEscaped() throws Exception { + assertEquals("<your thing here>", j.jenkins.getMarkupFormatter().translate("")); + assertEquals("", j.jenkins.getMarkupFormatter().translate("")); + assertEquals("", j.jenkins.getMarkupFormatter().translate(null)); + } + } diff --git a/test/src/test/java/hudson/model/AbstractBuildTest.java b/test/src/test/java/hudson/model/AbstractBuildTest.java index fad2b3dcb7..2f51b954eb 100644 --- a/test/src/test/java/hudson/model/AbstractBuildTest.java +++ b/test/src/test/java/hudson/model/AbstractBuildTest.java @@ -26,9 +26,12 @@ import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.WebResponse; import hudson.EnvVars; +import hudson.Functions; import hudson.Launcher; import hudson.model.queue.QueueTaskFuture; import hudson.slaves.EnvironmentVariablesNodeProperty; +import hudson.slaves.WorkspaceList; +import hudson.tasks.BatchFile; import hudson.tasks.BuildStepMonitor; import hudson.tasks.Builder; import java.io.IOException; @@ -43,11 +46,14 @@ import hudson.tasks.LogRotatorTest; import hudson.tasks.Recorder; +import hudson.tasks.Shell; import hudson.util.OneShotEvent; import net.sf.json.JSONArray; import net.sf.json.JSONObject; +import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; +import org.jvnet.hudson.test.BuildWatcher; import org.jvnet.hudson.test.CaptureEnvironmentBuilder; import org.jvnet.hudson.test.FailureBuilder; import org.jvnet.hudson.test.FakeChangeLogSCM; @@ -62,6 +68,9 @@ * Unit tests of {@link AbstractBuild}. */ public class AbstractBuildTest { + + @ClassRule + public static BuildWatcher buildWatcher = new BuildWatcher(); @Rule public JenkinsRule j = new JenkinsRule(); @@ -316,4 +325,17 @@ private Object writeReplace() { done.signal(); } + @Test + @Issue("JENKINS-60634") + public void tempDirVariable() throws Exception { + FreeStyleProject p = j.createFreeStyleProject(); + if (Functions.isWindows()) { + p.getBuildersList().add(new BatchFile("mkdir \"%WORKSPACE_TMP%\"\r\necho ok > \"%WORKSPACE_TMP%\\x\"")); + } else { + p.getBuildersList().add(new Shell("set -u && mkdir -p \"$WORKSPACE_TMP\" && touch \"$WORKSPACE_TMP/x\"")); + } + j.buildAndAssertSuccess(p); + assertTrue(WorkspaceList.tempDir(j.jenkins.getWorkspaceFor(p)).child("x").exists()); + } + } diff --git a/test/src/test/java/hudson/model/ApiSecurity1129Test.java b/test/src/test/java/hudson/model/ApiSecurity1129Test.java index 999eacb43e..fb20b279ae 100644 --- a/test/src/test/java/hudson/model/ApiSecurity1129Test.java +++ b/test/src/test/java/hudson/model/ApiSecurity1129Test.java @@ -43,7 +43,7 @@ public void wrapperBadName() throws Exception { } /** - * Test thw erapper parameter with a good name, to ensure the security fix doesn't break anything. + * Test the wrapper parameter with a good name, to ensure the security fix doesn't break anything. * @throws Exception See {@link #checkWrapperParam(String, Integer, String)} */ @Issue("SECURITY-1129") @@ -55,9 +55,9 @@ public void wrapperGoodName() throws Exception { } /** - * Check the response for a XML api with the wrapper param specified. At least the statuCode or the responseMessage + * Check the response for a XML api with the wrapper param specified. At least the statusCode or the responseMessage * should be indicated. - * @param wrapper the wrapper param passed in theurl. + * @param wrapper the wrapper param passed in the url. * @param statusCode the status code expected in the response. If it's null, it's not checked. * @param responseMessage the message expected in the response. If it's null, it's not checked. * @throws IOException See {@link org.jvnet.hudson.test.JenkinsRule.WebClient#goTo(String, String)} diff --git a/test/src/test/java/hudson/model/BuildAuthorizationTokenTest.java b/test/src/test/java/hudson/model/BuildAuthorizationTokenTest.java index cc0fdcfb4f..01ea0f35db 100644 --- a/test/src/test/java/hudson/model/BuildAuthorizationTokenTest.java +++ b/test/src/test/java/hudson/model/BuildAuthorizationTokenTest.java @@ -65,7 +65,7 @@ public void triggerJobsWithoutTokenShouldFail() throws Exception { fail("should not reach here as anonymous does not have Item.BUILD and token is not set"); } catch (FailingHttpStatusCodeException fex) { - assertThat("Should fail with access denined", fex.getStatusCode(), is(403)); + assertThat("Should fail with access denied", fex.getStatusCode(), is(403)); } } diff --git a/test/src/test/java/hudson/model/BuildExecutionTest.java b/test/src/test/java/hudson/model/BuildExecutionTest.java index 71a6fbed0f..1da51025f0 100644 --- a/test/src/test/java/hudson/model/BuildExecutionTest.java +++ b/test/src/test/java/hudson/model/BuildExecutionTest.java @@ -47,11 +47,8 @@ public class BuildExecutionTest { FreeStyleBuild b = r.assertBuildStatus(Result.FAILURE, p.scheduleBuild2(0).get()); r.assertLogContains(Messages.Build_post_build_steps_failed(), b); FilePath ws = r.jenkins.getWorkspaceFor(p); - WorkspaceList.Lease lease = r.jenkins.toComputer().getWorkspaceList().allocate(ws); - try { + try (WorkspaceList.Lease lease = r.jenkins.toComputer().getWorkspaceList().allocate(ws)) { assertEquals(ws, lease.path); - } finally { - lease.close(); } } diff --git a/test/src/test/java/hudson/model/ExecutorTest.java b/test/src/test/java/hudson/model/ExecutorTest.java index 70254456fd..4562093250 100644 --- a/test/src/test/java/hudson/model/ExecutorTest.java +++ b/test/src/test/java/hudson/model/ExecutorTest.java @@ -116,7 +116,7 @@ public void disconnectCause() throws Exception { assertThat(log, containsString("Finished: FAILURE")); assertThat(log, containsString("Build step 'BlockingBuilder' marked build as failure")); assertThat(log, containsString("Agent went offline during the build")); - assertThat(log, containsString("Disconnected by Johnny : Taking offline to break your buil")); + assertThat(log, containsString("Disconnected by Johnny : Taking offline to break your build")); } @Issue("SECURITY-611") diff --git a/test/src/test/java/hudson/model/FreeStyleProjectTest.java b/test/src/test/java/hudson/model/FreeStyleProjectTest.java index 085c86a3e4..78af26927d 100644 --- a/test/src/test/java/hudson/model/FreeStyleProjectTest.java +++ b/test/src/test/java/hudson/model/FreeStyleProjectTest.java @@ -26,6 +26,7 @@ import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; @@ -78,7 +79,7 @@ public void configSubmission() throws Exception { assertEquals(1,builders.size()); assertEquals(Shell.class,builders.get(0).getClass()); assertEquals("echo hello",((Shell)builders.get(0)).getCommand().trim()); - assertTrue(builders.get(0)!=shell); + assertNotSame(builders.get(0), shell); } /** @@ -127,7 +128,7 @@ public void minimalConfigXml() throws Exception { assertEquals(1,builders.size()); assertEquals(Shell.class,builders.get(0).getClass()); assertEquals("echo hello",((Shell)builders.get(0)).getCommand().trim()); - assertTrue(builders.get(0)!=shell); + assertNotSame(builders.get(0), shell); System.out.println(project.getConfigFile().asString()); } diff --git a/test/src/test/java/hudson/model/ManagementLinkTest.java b/test/src/test/java/hudson/model/ManagementLinkTest.java index 239fb15dbf..86cf8d0ed7 100644 --- a/test/src/test/java/hudson/model/ManagementLinkTest.java +++ b/test/src/test/java/hudson/model/ManagementLinkTest.java @@ -24,6 +24,7 @@ package hudson.model; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import com.gargoylesoftware.htmlunit.html.DomNodeUtil; @@ -65,7 +66,7 @@ public void links() throws Exception { @Test @Issue("JENKINS-33683") public void invisibleLinks() throws Exception { - assertEquals(null, j.jenkins.getDynamic("and_fail_trying")); + assertNull(j.jenkins.getDynamic("and_fail_trying")); } @TestExtension // Intentionally hooked in all tests diff --git a/test/src/test/java/hudson/model/NodeTest.java b/test/src/test/java/hudson/model/NodeTest.java index 967d13d6ec..95b831e7dd 100644 --- a/test/src/test/java/hudson/model/NodeTest.java +++ b/test/src/test/java/hudson/model/NodeTest.java @@ -208,8 +208,8 @@ public void testCanTake() throws Exception { assertEquals("Cause of blockage should be reserved label.", message, node.canTake(item2).getShortDescription()); node.getNodeProperties().add(new NodePropertyImpl()); notTake = true; - assertNotNull("Node should not take project because node property not alow it.", node.canTake(item)); - assertTrue("Cause of blockage should be bussy label.", node.canTake(item) instanceof CauseOfBlockage.BecauseLabelIsBusy); + assertNotNull("Node should not take project because node property does not allow it.", node.canTake(item)); + assertTrue("Cause of blockage should be busy label.", node.canTake(item) instanceof CauseOfBlockage.BecauseLabelIsBusy); User user = User.get("John"); GlobalMatrixAuthorizationStrategy auth = new GlobalMatrixAuthorizationStrategy(); j.jenkins.setAuthorizationStrategy(auth); @@ -221,7 +221,7 @@ public void testCanTake() throws Exception { QueueItemAuthenticatorConfiguration.get().getAuthenticators().add(new MockQueueItemAuthenticator(Collections.singletonMap(project.getFullName(), user.impersonate()))); assertNotNull("Node should not take project because user does not have build permission.", node.canTake(item)); message = Messages._Node_LackingBuildPermission(item.authenticate().getName(),node.getNodeName()).toString(); - assertEquals("Cause of blockage should be bussy label.", message, node.canTake(item).getShortDescription()); + assertEquals("Cause of blockage should be build permission label.", message, node.canTake(item).getShortDescription()); } @Test diff --git a/test/src/test/java/hudson/model/ParametersAction2Test.java b/test/src/test/java/hudson/model/ParametersAction2Test.java index 502506f945..48bab88899 100644 --- a/test/src/test/java/hudson/model/ParametersAction2Test.java +++ b/test/src/test/java/hudson/model/ParametersAction2Test.java @@ -98,7 +98,7 @@ public void backwardCompatibility() throws Exception { @Issue("SECURITY-170") public void parametersDefinitionChange() throws Exception { FreeStyleProject p = j.createFreeStyleProject(); - p.addProperty(new ParametersDefinitionProperty(Arrays.asList( + p.addProperty(new ParametersDefinitionProperty(Arrays.asList( new StringParameterDefinition("foo", "foo"), new StringParameterDefinition("bar", "bar")))); @@ -108,28 +108,28 @@ public void parametersDefinitionChange() throws Exception { new StringParameterValue("undef", "undef") ))); - assertTrue("undef parameter is not listed in getParameters", - !hasParameterWithName(build.getAction(ParametersAction.class), "undef")); + assertFalse("undef parameter is not listed in getParameters", + hasParameterWithName(build.getAction(ParametersAction.class), "undef")); p.removeProperty(ParametersDefinitionProperty.class); - p.addProperty(new ParametersDefinitionProperty(Arrays.asList( + p.addProperty(new ParametersDefinitionProperty(Arrays.asList( new StringParameterDefinition("foo", "foo"), new StringParameterDefinition("bar", "bar"), new StringParameterDefinition("undef", "undef")))); // undef is still not listed even after being added to the job parameters definition - assertTrue("undef parameter is not listed in getParameters", - !hasParameterWithName(build.getAction(ParametersAction.class), "undef")); + assertFalse("undef parameter is not listed in getParameters", + hasParameterWithName(build.getAction(ParametersAction.class), "undef")); // remove bar and undef from parameters definition p.removeProperty(ParametersDefinitionProperty.class); - p.addProperty(new ParametersDefinitionProperty(Arrays.asList( + p.addProperty(new ParametersDefinitionProperty(Arrays.asList( new StringParameterDefinition("foo", "foo")))); - assertTrue("the build still have 2 parameters", build.getAction(ParametersAction.class).getParameters().size() == 2); + assertEquals("the build still have 2 parameters", 2, build.getAction(ParametersAction.class).getParameters().size()); p.removeProperty(ParametersDefinitionProperty.class); - assertTrue("the build still have 2 parameters", build.getAction(ParametersAction.class).getParameters().size() == 2); + assertEquals("the build still have 2 parameters", 2, build.getAction(ParametersAction.class).getParameters().size()); } @Test @@ -163,13 +163,13 @@ public void whitelistedParameter() throws Exception { public void whitelistedParameterByOverride() throws Exception { FreeStyleProject p = j.createFreeStyleProject(); String name = p.getFullName(); - p.addProperty(new ParametersDefinitionProperty(Arrays.asList( + p.addProperty(new ParametersDefinitionProperty(Arrays.asList( new StringParameterDefinition("foo", "foo"), new StringParameterDefinition("bar", "bar")))); try { ParametersAction action = new ParametersAction( - Arrays.asList( + Arrays.asList( new StringParameterValue("foo", "baz"), new StringParameterValue("bar", "bar"), new StringParameterValue("whitelisted1", "x"), @@ -185,8 +185,6 @@ public void whitelistedParameterByOverride() throws Exception { hasParameterWithName(build.getAction(ParametersAction.class), "whitelisted2")); assertFalse("whitelisted3 parameter is listed in getParameters", hasParameterWithName(build.getAction(ParametersAction.class), "whitelisted3")); - p = null; - build = null; j.jenkins.reload(); //Test again after reload p = j.jenkins.getItemByFullName(name, FreeStyleProject.class); @@ -207,7 +205,7 @@ public void whitelistedParameterByOverride() throws Exception { public void whitelistedParameterSameAfterChange() throws Exception { FreeStyleProject p = j.createFreeStyleProject(); String name = p.getFullName(); - p.addProperty(new ParametersDefinitionProperty(Arrays.asList( + p.addProperty(new ParametersDefinitionProperty(Arrays.asList( new StringParameterDefinition("foo", "foo"), new StringParameterDefinition("bar", "bar")))); @@ -231,8 +229,6 @@ public void whitelistedParameterSameAfterChange() throws Exception { hasParameterWithName(build.getAction(ParametersAction.class), "whitelisted4")); System.setProperty(ParametersAction.SAFE_PARAMETERS_SYSTEM_PROPERTY_NAME, "whitelisted3,whitelisted4"); - p = null; - build = null; j.jenkins.reload(); p = j.jenkins.getItemByFullName(name, FreeStyleProject.class); build = p.getLastBuild(); @@ -261,10 +257,10 @@ public void nonParameterizedJob() throws Exception { new StringParameterValue("bar", "bar") ))); - assertTrue("foo parameter is not listed in getParameters", - !hasParameterWithName(build.getAction(ParametersAction.class), "foo")); - assertTrue("bar parameter is not listed in getParameters", - !hasParameterWithName(build.getAction(ParametersAction.class), "bar")); + assertFalse("foo parameter is not listed in getParameters", + hasParameterWithName(build.getAction(ParametersAction.class), "foo")); + assertFalse("bar parameter is not listed in getParameters", + hasParameterWithName(build.getAction(ParametersAction.class), "bar")); } @Test @@ -348,13 +344,13 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen if (expectLegacyBehavior) { assertTrue("undef parameter is listed in getParameters", hasParameterWithName(pa.getParameters(), "undef")); assertTrue("undef parameter is listed in iterator", hasParameterWithName(pa, "undef")); - assertTrue("undef in environment", build.getEnvironment(listener).keySet().contains("undef")); - assertTrue("UNDEF in environment", build.getEnvironment(listener).keySet().contains("UNDEF")); + assertTrue("undef in environment", build.getEnvironment(listener).containsKey("undef")); + assertTrue("UNDEF in environment", build.getEnvironment(listener).containsKey("UNDEF")); } else { assertFalse("undef parameter is not listed in getParameters", hasParameterWithName(pa.getParameters(), "undef")); assertFalse("undef parameter is not listed in iterator", hasParameterWithName(pa, "undef")); - assertFalse("undef not in environment", build.getEnvironment(listener).keySet().contains("undef")); - assertFalse("UNDEF not in environment", build.getEnvironment(listener).keySet().contains("UNDEF")); + assertFalse("undef not in environment", build.getEnvironment(listener).containsKey("undef")); + assertFalse("UNDEF not in environment", build.getEnvironment(listener).containsKey("UNDEF")); } assertTrue("undef parameter is listed in getAllParameters", hasParameterWithName(pa.getAllParameters(), "undef")); diff --git a/test/src/test/java/hudson/model/PasswordParameterDefinitionTest.java b/test/src/test/java/hudson/model/PasswordParameterDefinitionTest.java index f67f630958..2d06d402d1 100644 --- a/test/src/test/java/hudson/model/PasswordParameterDefinitionTest.java +++ b/test/src/test/java/hudson/model/PasswordParameterDefinitionTest.java @@ -82,6 +82,7 @@ public class PasswordParameterDefinitionTest { // Another control case: anyone can enter a different value. HtmlForm form = wc.withBasicApiToken(dev).getPage(p, "build?delay=0sec").getFormByName("parameters"); + form.getElementsByAttribute("input", "class", "hidden-password-update-btn").get(0).click(); HtmlPasswordInput input = form.getInputByName("value"); input.setText("rumor"); j.submit(form); @@ -99,6 +100,7 @@ public class PasswordParameterDefinitionTest { // Another control case: blank values. form = wc.withBasicApiToken(dev).getPage(p, "build?delay=0sec").getFormByName("parameters"); + form.getElementsByAttribute("input", "class", "hidden-password-update-btn").get(0).click(); input = form.getInputByName("value"); input.setText(""); j.submit(form); diff --git a/test/src/test/java/hudson/model/QueueTest.java b/test/src/test/java/hudson/model/QueueTest.java index 060bf57e85..35e99971ba 100644 --- a/test/src/test/java/hudson/model/QueueTest.java +++ b/test/src/test/java/hudson/model/QueueTest.java @@ -67,6 +67,7 @@ import hudson.slaves.NodeProperty; import hudson.slaves.NodePropertyDescriptor; import hudson.slaves.NodeProvisionerRule; +import hudson.slaves.OfflineCause; import hudson.tasks.BatchFile; import hudson.tasks.BuildTrigger; import hudson.tasks.Shell; @@ -131,7 +132,10 @@ import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.everyItem; +import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.lessThan; +import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.*; import org.junit.Ignore; @@ -558,6 +562,9 @@ public TestFlyweightTask(AtomicInteger cnt, Label assignedLabel) { @Override public Label getAssignedLabel() { return assignedLabel; } + public Computer getOwner() { + return exec == null ? null : exec.getOwner(); + } } @Test public void taskEquality() throws Exception { @@ -1079,16 +1086,22 @@ public static final class QueueSaveSniffer extends SaveableListener { @Test @Issue("SECURITY-891") public void doCancelItem_PermissionIsChecked() throws Exception { - checkCancelOperationUsingUrl(item -> "queue/cancelItem?id=" + item.getId()); + checkCancelOperationUsingUrl(item -> "queue/cancelItem?id=" + item.getId(), false); } @Test @Issue("SECURITY-891") public void doCancelQueue_PermissionIsChecked() throws Exception { - checkCancelOperationUsingUrl(item -> "queue/item/" + item.getId() + "/cancelQueue"); + checkCancelOperationUsingUrl(item -> "queue/item/" + item.getId() + "/cancelQueue", true); } - private void checkCancelOperationUsingUrl(Function urlProvider) throws Exception { + /** + * + * @param urlProvider the endpoint to query + * @param legacyRedirect whether the endpoint has the legacy behavior (ie makes a redirect no matter the result) + * Or it uses the newer response codes introduced by JENKINS-21311 + */ + private void checkCancelOperationUsingUrl(Function urlProvider, boolean legacyRedirect) throws Exception { Queue q = r.jenkins.getQueue(); r.jenkins.setCrumbIssuer(null); @@ -1117,11 +1130,13 @@ private void checkCancelOperationUsingUrl(Function urlProvid .withRedirectEnabled(false) .withThrowExceptionOnFailingStatusCode(false); wc.login("user"); - Page p = wc.getPage(request); - // currently the endpoint return a redirection to the previously visited page, none in our case - // (so force no redirect to avoid false positive error) - assertThat(p.getWebResponse().getStatusCode(), lessThan(400)); - + if(legacyRedirect) { + Page p = wc.getPage(request); + // the legacy endpoint returns a redirection to the previously visited page, none in our case + // (so force no redirect to avoid false positive error) + // see JENKINS-21311 + assertThat(p.getWebResponse().getStatusCode(), lessThan(400)); + } assertFalse(currentOne.getFuture().isCancelled()); } { // user with right can @@ -1136,6 +1151,43 @@ private void checkCancelOperationUsingUrl(Function urlProvid } } + @Test + public void flyweightsRunOnMasterIfPossible() throws Exception { + r.createOnlineSlave(); + r.jenkins.setNumExecutors(0); + List tasks = new ArrayList<>(); + Queue q = r.jenkins.getQueue(); + + for (int i = 0; i < 100; i++) { + TestFlyweightTask task = new TestFlyweightTask(new AtomicInteger(i), null); + tasks.add(task); + q.schedule2(task, 0); + } + + q.maintain(); + r.waitUntilNoActivityUpTo(10000); + Assert.assertThat(tasks, everyItem(hasProperty("owner", equalTo(Jenkins.get().toComputer())))); + } + + @Test + public void flyweightsRunOnAgentIfNecessary() throws Exception { + r.createOnlineSlave(); + r.jenkins.setNumExecutors(0); + r.jenkins.toComputer().setTemporarilyOffline(true, new OfflineCause.UserCause(null, null)); + List tasks = new ArrayList<>(); + Queue q = r.jenkins.getQueue(); + + for (int i = 0; i < 10; i++) { + TestFlyweightTask task = new TestFlyweightTask(new AtomicInteger(i), null); + tasks.add(task); + q.schedule2(task, 0); + } + + q.maintain(); + r.waitUntilNoActivityUpTo(10000); + Assert.assertThat(tasks, everyItem(hasProperty("owner", not(equalTo(Jenkins.get().toComputer()))))); + } + @Test @Issue("JENKINS-57805") public void brokenAffinityKey() throws Exception { diff --git a/test/src/test/java/hudson/model/UpdateSiteTest.java b/test/src/test/java/hudson/model/UpdateSiteTest.java index 559c75be59..d5c7f824d7 100644 --- a/test/src/test/java/hudson/model/UpdateSiteTest.java +++ b/test/src/test/java/hudson/model/UpdateSiteTest.java @@ -24,6 +24,8 @@ package hudson.model; +import hudson.PluginWrapper; +import hudson.PluginWrapper.Dependency; import hudson.model.UpdateSite.Data; import hudson.util.FormValidation; import hudson.util.PersistedList; @@ -32,9 +34,12 @@ import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; +import java.util.jar.Attributes; +import java.util.jar.Manifest; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -42,6 +47,7 @@ import static org.junit.Assert.*; +import jenkins.model.Jenkins; import jenkins.security.UpdateSiteWarningsConfiguration; import jenkins.security.UpdateSiteWarningsMonitor; import org.apache.commons.io.FileUtils; @@ -107,11 +113,9 @@ public void shutdownWebserver() throws Exception { } @Test public void relativeURLs() throws Exception { - PersistedList sites = j.jenkins.getUpdateCenter().getSites(); - sites.clear(); URL url = new URL(baseUrl, "/plugins/tasks-update-center.json"); UpdateSite site = new UpdateSite(UpdateCenter.ID_DEFAULT, url.toString()); - sites.add(site); + overrideUpdateSite(site); assertEquals(FormValidation.ok(), site.updateDirectly(false).get()); Data data = site.getData(); assertNotNull(data); @@ -124,6 +128,28 @@ public void shutdownWebserver() throws Exception { assertEquals("Wrong name of plugin found", "Task Scanner Plug-in", tasksPlugin.getDisplayName()); } + @Test public void wikiUrlFromSingleSite() throws Exception { + UpdateSite site = getUpdateSite("/plugins/tasks-update-center.json"); + overrideUpdateSite(site); + PluginWrapper wrapper = buildPluginWrapper("dummy", "https://wiki.jenkins.io/display/JENKINS/dummy"); + assertEquals("https://plugins.jenkins.io/dummy", wrapper.getUrl()); + } + + @Test public void wikiUrlFromMoreSites() throws Exception { + UpdateSite site = getUpdateSite("/plugins/tasks-update-center.json"); + UpdateSite alternativeSite = getUpdateSite("/plugins/alternative-update-center.json", "alternative"); + overrideUpdateSite(site, alternativeSite); + // sites use different Wiki URL for dummy -> use URL from manifest + PluginWrapper wrapper = buildPluginWrapper("dummy", "https://wiki.jenkins.io/display/JENKINS/dummy"); + assertEquals("https://wiki.jenkins.io/display/JENKINS/dummy", wrapper.getUrl()); + // sites use the same Wiki URL for tasks -> use it + wrapper = buildPluginWrapper("tasks", "https://wiki.jenkins.io/display/JENKINS/tasks"); + assertEquals("https://plugins.jenkins.io/tasks", wrapper.getUrl()); + // only one site has it + wrapper = buildPluginWrapper("foo", "https://wiki.jenkins.io/display/JENKINS/foo"); + assertEquals("https://plugins.jenkins.io/foo", wrapper.getUrl()); + } + @Test public void updateDirectlyWithJson() throws Exception { UpdateSite us = new UpdateSite("default", new URL(baseUrl, "update-center.json").toExternalForm()); assertNull(us.getPlugin("AdaptivePlugin")); @@ -141,12 +167,8 @@ public void shutdownWebserver() throws Exception { } @Test public void incompleteWarningsJson() throws Exception { - PersistedList sites = j.jenkins.getUpdateCenter().getSites(); - sites.clear(); - URL url = new URL(baseUrl, "/plugins/warnings-update-center-malformed.json"); - UpdateSite site = new UpdateSite(UpdateCenter.ID_DEFAULT, url.toString()); - sites.add(site); - assertEquals(FormValidation.ok(), site.updateDirectly(false).get()); + UpdateSite site = getUpdateSite("/plugins/warnings-update-center-malformed.json"); + overrideUpdateSite(site); assertEquals("number of warnings", 7, site.getData().getWarnings().size()); assertNotEquals("plugin data is present", Collections.emptyMap(), site.getData().plugins); } @@ -190,11 +212,38 @@ public void isPluginUpdateCompatible() throws Exception { assertFalse("isLegacyDefault should be false with null url",new UpdateSite(null,null).isLegacyDefault()); } - private UpdateSite getUpdateSite(String path) throws Exception { + return getUpdateSite(path, UpdateCenter.ID_DEFAULT); + } + + private UpdateSite getUpdateSite(String path, String id) throws Exception { URL url = new URL(baseUrl, path); - UpdateSite site = new UpdateSite(UpdateCenter.ID_DEFAULT, url.toString()); + UpdateSite site = new UpdateSite(id, url.toString()); assertEquals(FormValidation.ok(), site.updateDirectly(false).get()); return site; } + + private void overrideUpdateSite(UpdateSite... overrideSites) { + PersistedList sites = j.jenkins.getUpdateCenter().getSites(); + sites.clear(); + sites.addAll(Arrays.asList(overrideSites)); + } + + private PluginWrapper buildPluginWrapper(String name, String wikiUrl) { + Manifest manifest = new Manifest(); + Attributes attributes = manifest.getMainAttributes(); + attributes.put(new Attributes.Name("Short-Name"), name); + attributes.put(new Attributes.Name("Plugin-Version"), "1.0.0"); + attributes.put(new Attributes.Name("Url"), wikiUrl); + return new PluginWrapper( + Jenkins.get().getPluginManager(), + new File("/tmp/" + name + ".jpi"), + manifest, + null, + null, + new File("/tmp/" + name + ".jpi.disabled"), + null, + new ArrayList() + ); + } } diff --git a/test/src/test/java/hudson/model/UsageStatisticsTest.java b/test/src/test/java/hudson/model/UsageStatisticsTest.java index d53754abda..e1b596b666 100644 --- a/test/src/test/java/hudson/model/UsageStatisticsTest.java +++ b/test/src/test/java/hudson/model/UsageStatisticsTest.java @@ -90,7 +90,7 @@ public void roundtrip() throws Exception { InputStreamReader r = new InputStreamReader(new GZIPInputStream( new CombinedCipherInputStream(new ByteArrayInputStream(cipherText),priv,"AES")), "UTF-8"); JSONObject o = JSONObject.fromObject(IOUtils.toString(r)); - Jenkins jenkins = Jenkins.getActiveInstance(); + Jenkins jenkins = j.jenkins; // A bit intrusive with UsageStatistics internals, but done to prevent undetected changes // that would cause issues with parsing/analyzing uploaded usage statistics assertEquals(1, o.getInt("stat")); @@ -136,13 +136,12 @@ public void roundtrip() throws Exception { * @throws InterruptedException */ private void warmUpNodeMonitorCache() throws InterruptedException { - Jenkins j = Jenkins.getActiveInstance(); - ArchitectureMonitor.DescriptorImpl descriptor = j.getDescriptorByType(ArchitectureMonitor.DescriptorImpl.class); + ArchitectureMonitor.DescriptorImpl descriptor = j.jenkins.getDescriptorByType(ArchitectureMonitor.DescriptorImpl.class); String value = null; int count = 1; while (value == null && count++ <= 5) // If for some reason the cache doesn't get populated, don't loop forever { - final Computer master = j.getComputers()[0]; + final Computer master = j.jenkins.getComputers()[0]; value = descriptor.get(master); Thread.sleep(200); } diff --git a/test/src/test/java/hudson/model/ViewDescriptorTest.java b/test/src/test/java/hudson/model/ViewDescriptorTest.java index 02be6a5f4b..78cc73d4af 100644 --- a/test/src/test/java/hudson/model/ViewDescriptorTest.java +++ b/test/src/test/java/hudson/model/ViewDescriptorTest.java @@ -26,13 +26,23 @@ import java.util.Arrays; import java.util.TreeSet; +import java.util.concurrent.TimeUnit; + +import com.gargoylesoftware.htmlunit.html.HtmlForm; +import com.gargoylesoftware.htmlunit.html.HtmlPage; + import jenkins.model.DirectlyModifiableTopLevelItemGroup; import static org.junit.Assert.*; + +import org.awaitility.Awaitility; import org.junit.Rule; import org.junit.Test; +import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.MockFolder; import org.jvnet.hudson.test.TestExtension; +import org.kohsuke.stapler.StaplerRequest; +import net.sf.json.JSONObject; public class ViewDescriptorTest { @@ -75,4 +85,96 @@ private void assertContains(AutoCompletionCandidates c, String... values) { assertEquals(new TreeSet<>(Arrays.asList(values)), new TreeSet<>(c.getValues())); } + + @Test + @Issue("JENKINS-60579") + public void invisiblePropertiesOnViewShoudBePersisted() throws Exception { + + //GIVEN a listView that have an invisible property + ListView myListView = new ListView("Rock"); + myListView.setRecurse(true); + myListView.setIncludeRegex(".*"); + + CustomInvisibleProperty invisibleProperty = new CustomInvisibleProperty(); + invisibleProperty.setSomeProperty("You cannot see me."); + invisibleProperty.setView(myListView); + myListView.getProperties().add(invisibleProperty); + + r.jenkins.addView(myListView); + + assertEquals(r.jenkins.getView("Rock").getProperties().get(CustomInvisibleProperty.class).getSomeProperty(), + "You cannot see me."); + + //WHEN the users goes with "Edit View" on the configure page + JenkinsRule.WebClient webClient = r.createWebClient(); + HtmlPage editViewPage = webClient.getPage(myListView, "configure"); + + //THEN the invisible property is not displayed on page + assertFalse("CustomInvisibleProperty should not be displayed on the View edition page UI.", + editViewPage.asText().contains("CustomInvisibleProperty")); + + + HtmlForm editViewForm = editViewPage.getFormByName("viewConfig"); + editViewForm.getTextAreaByName("description").type("This list view is awesome !"); + r.submit(editViewForm); + + //Check that the description is updated on view + Awaitility.waitAtMost(3, TimeUnit.SECONDS).until(() -> webClient.getPage(myListView) + .asText() + .contains("This list view is awesome !")); + + + //AND THEN after View save, the invisible property is still persisted with the View. + assertNotNull("The CustomInvisibleProperty should be persisted on the View.", + r.jenkins.getView("Rock").getProperties().get(CustomInvisibleProperty.class)); + assertEquals(r.jenkins.getView("Rock").getProperties().get(CustomInvisibleProperty.class).getSomeProperty(), + "You cannot see me."); + + } + + private static class CustomInvisibleProperty extends ViewProperty { + + private String someProperty; + + public void setSomeProperty(String someProperty) { + this.someProperty = someProperty; + } + + public String getSomeProperty() { + return this.someProperty; + } + + public CustomInvisibleProperty() { + this.someProperty = "undefined"; + } + + @Override + public ViewProperty reconfigure(StaplerRequest req, JSONObject form) { + return this; + } + + @TestExtension + public static final class CustomInvisibleDescriptorImpl extends ViewPropertyDescriptor { + + @Override + public String getId() { + return "CustomInvisibleDescriptorImpl"; + } + + @Override + public boolean isEnabledFor(View view) { + return true; + } + } + + @TestExtension + public static final class CustomInvisibleDescriptorVisibilityFilterImpl extends DescriptorVisibilityFilter { + + @Override + public boolean filter(Object context, Descriptor descriptor) { + return false; + } + } + } + } diff --git a/test/src/test/java/hudson/model/queue/BuildKeepsRunningWhenFaultySubTasksTest.java b/test/src/test/java/hudson/model/queue/BuildKeepsRunningWhenFaultySubTasksTest.java new file mode 100644 index 0000000000..2836d4072f --- /dev/null +++ b/test/src/test/java/hudson/model/queue/BuildKeepsRunningWhenFaultySubTasksTest.java @@ -0,0 +1,97 @@ +package hudson.model.queue; + +import hudson.model.AbstractProject; +import hudson.model.FreeStyleBuild; +import hudson.model.FreeStyleProject; +import hudson.model.Label; +import hudson.model.Node; +import hudson.model.Queue; +import hudson.model.ResourceList; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.TestExtension; + +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.concurrent.TimeUnit; + +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; + +public class BuildKeepsRunningWhenFaultySubTasksTest { + @Rule + public JenkinsRule j = new JenkinsRule(); + + public static final String ERROR_MESSAGE = "My unexpected exception"; + + // When using SubTaskContributor (FailingSubTaskContributor) the build never ends + @Test + @Issue("JENKINS-59793") + public void buildFinishesWhenSubTaskFails() throws Exception { + FreeStyleProject p = j.createProject(FreeStyleProject.class); + QueueTaskFuture future = p.scheduleBuild2(0); + assertThat("Build should be actually scheduled by Jenkins", future, notNullValue()); + + // We don't get stalled waiting the finalization of the job + future.get(5, TimeUnit.SECONDS); + } + + // A SubTask failing with an exception + @TestExtension + public static class FailingSubTaskContributor extends SubTaskContributor { + @Override + public Collection forProject(final AbstractProject p) { + return Collections.singleton(new SubTask() { + private final SubTask outer = this; + + public Queue.Executable createExecutable() throws IOException { + return new Queue.Executable() { + public SubTask getParent() { + return outer; + } + + public void run() { + throw new ArrayIndexOutOfBoundsException(ERROR_MESSAGE); + } + + public long getEstimatedDuration() { + return 0; + } + }; + } + + @Override + public Label getAssignedLabel() { + return null; + } + @Override + public Node getLastBuiltOn() { + return null; + } + @Override + public long getEstimatedDuration() { + return 0; + } + @Override + public Queue.Task getOwnerTask() { + return p; + } + @Override + public Object getSameNodeConstraint() { + return null; + } + @Override + public ResourceList getResourceList() { + return ResourceList.EMPTY; + } + @Override + public String getDisplayName() { + return "Subtask of " + p.getDisplayName(); + } + }); + } + } +} diff --git a/test/src/test/java/hudson/model/queue/MaintainCanTakeStrengtheningTest.java b/test/src/test/java/hudson/model/queue/MaintainCanTakeStrengtheningTest.java new file mode 100644 index 0000000000..4997945da4 --- /dev/null +++ b/test/src/test/java/hudson/model/queue/MaintainCanTakeStrengtheningTest.java @@ -0,0 +1,76 @@ +package hudson.model.queue; + +import hudson.model.FreeStyleProject; +import hudson.model.Messages; +import hudson.model.Node; +import hudson.model.Queue; +import hudson.model.labels.LabelExpression; +import hudson.slaves.DumbSlave; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.LoggerRule; +import org.jvnet.hudson.test.TestExtension; + +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItem; + +public class MaintainCanTakeStrengtheningTest { + @Rule + public JenkinsRule r = new JenkinsRule(); + + @Rule + public LoggerRule logging = new LoggerRule().record(Node.class.getName(), Level.ALL).capture(100); + + private QueueTaskFuture scheduleBuild(String name, String label) throws Exception { + FreeStyleProject project = r.createFreeStyleProject(name); + + project.setAssignedLabel(LabelExpression.get(label)); + return project.scheduleBuild2(0); + } + + @Issue("JENKINS-59886") + @Test + public void testExceptionOnNodeProperty() throws Exception { + // A node throwing the exception because of the canTake method of the attached FaultyNodeProperty + DumbSlave faultyAgent = r.createOnlineSlave(LabelExpression.get("faulty")); + faultyAgent.getNodeProperties().add(new FaultyNodeProperty()); + + // A good agent + r.createOnlineSlave(LabelExpression.get("good")); + + // Only the good ones will be run and the latest doesn't get hung because of the second + QueueTaskFuture[] taskFuture = new QueueTaskFuture[3]; + taskFuture[0] = scheduleBuild("good1", "good"); + taskFuture[1] = scheduleBuild("theFaultyOne", "faulty"); + taskFuture[2] = scheduleBuild("good2", "good"); + + // Wait for a while until the good ones start, no need to wait for their completion to guarantee + // the fix works + taskFuture[0].getStartCondition().get(15, TimeUnit.SECONDS); + taskFuture[2].getStartCondition().get(15, TimeUnit.SECONDS); + + // The faulty one is the only one in the queue + assertThat(r.getInstance().getQueue().getBuildableItems().size(), equalTo(1)); + assertThat(r.getInstance().getQueue().getBuildableItems().get(0).task.getName(), equalTo("theFaultyOne")); + + // The new error is shown in the logs + assertThat(logging.getMessages(), hasItem(String.format("Exception evaluating if the node '%s' can take the task '%s'", new Object[]{faultyAgent.getDisplayName(), "theFaultyOne"}))); + } + + /** + * A node property throwing an exception to cause the canTake method fails. + */ + @TestExtension + public static class FaultyNodeProperty extends hudson.slaves.NodeProperty { + @Override + public CauseOfBlockage canTake(Queue.BuildableItem item) { + throw new ArrayIndexOutOfBoundsException(); + } + } +} diff --git a/test/src/test/java/hudson/scm/ChangeLogSetTest.java b/test/src/test/java/hudson/scm/ChangeLogSetTest.java index 310f28f2b9..4973ba6384 100644 --- a/test/src/test/java/hudson/scm/ChangeLogSetTest.java +++ b/test/src/test/java/hudson/scm/ChangeLogSetTest.java @@ -1,6 +1,7 @@ package hudson.scm; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import hudson.Extension; import hudson.MarkupText; @@ -23,14 +24,12 @@ public class ChangeLogSetTest { public void catchingExceptionDuringAnnotation() { EntryImpl change = new EntryImpl(); change.setParent(ChangeLogSet.createEmpty(null)); // otherwise test would actually test only NPE thrown when accessing parent.build - boolean notCaught = false; try { change.getMsgAnnotated(); } catch (Throwable t) { - notCaught = true; + fail(t.getMessage()); } assertEquals((new EntryImpl()).getMsg(), change.getMsg()); - assertEquals(false, notCaught); } @Extension diff --git a/test/src/test/java/hudson/security/HudsonPrivateSecurityRealmTest.java b/test/src/test/java/hudson/security/HudsonPrivateSecurityRealmTest.java index da7803d5af..d5debcadd5 100644 --- a/test/src/test/java/hudson/security/HudsonPrivateSecurityRealmTest.java +++ b/test/src/test/java/hudson/security/HudsonPrivateSecurityRealmTest.java @@ -101,7 +101,7 @@ public void hashCompatibility() { String secure = PASSWORD_ENCODER.encodePassword("hello world", null); assertTrue(PASSWORD_ENCODER.isPasswordValid(old,"hello world",null)); - assertFalse(secure.equals(old)); + assertNotEquals(secure, old); } @@ -144,7 +144,7 @@ public void fullNameCollisionPassword() throws Exception { // throws FailingHttpStatusCodeException on login failure wc2.login("user2", "password2"); - // belt and braces incase the failed login no longer throws exceptions. + // belt and braces in case the failed login no longer throws exceptions. w1 = (XmlPage) wc1.goTo("whoAmI/api/xml", "application/xml"); assertThat(w1, hasXPath("//name", is("user1"))); @@ -284,14 +284,14 @@ public void selfRegistrationTriggerLoggedIn() throws Exception { assertTrue(spySecurityListener.loggedInUsernames.isEmpty()); createFirstAccount("admin"); - assertTrue(spySecurityListener.loggedInUsernames.get(0).equals("admin")); + assertEquals("admin", spySecurityListener.loggedInUsernames.get(0)); createAccountByAdmin("alice"); // no new event in such case - assertTrue(spySecurityListener.loggedInUsernames.isEmpty()); + assertEquals(true, spySecurityListener.loggedInUsernames.isEmpty()); selfRegistration("bob"); - assertTrue(spySecurityListener.loggedInUsernames.get(0).equals("bob")); + assertEquals("bob", spySecurityListener.loggedInUsernames.get(0)); } @Issue("JENKINS-55307") @@ -306,8 +306,8 @@ public void selfRegistrationTriggerUserCreation() throws Exception { selfRegistration("bob"); selfRegistration("charlie"); - assertTrue(spySecurityListener.createdUsers.get(0).equals("bob")); - assertTrue(spySecurityListener.createdUsers.get(1).equals("charlie")); + assertEquals("bob", spySecurityListener.createdUsers.get(0)); + assertEquals("charlie", spySecurityListener.createdUsers.get(1)); } @Issue("JENKINS-55307") @@ -327,8 +327,8 @@ public void userCreationFromRealm() throws Exception { u2.setFullName("Debbie User"); u2.save(); - assertTrue(spySecurityListener.createdUsers.get(0).equals("alice")); - assertTrue(spySecurityListener.createdUsers.get(1).equals("debbie")); + assertEquals("alice", spySecurityListener.createdUsers.get(0)); + assertEquals("debbie", spySecurityListener.createdUsers.get(1)); } @Issue("JENKINS-55307") @@ -342,7 +342,7 @@ public void userCreationWithHashedPasswords() throws Exception { securityRealm.createAccountWithHashedPassword("charlie_hashed", "#jbcrypt:" + BCrypt.hashpw("charliePassword", BCrypt.gensalt())); - assertTrue(spySecurityListener.createdUsers.get(0).equals("charlie_hashed")); + assertEquals("charlie_hashed", spySecurityListener.createdUsers.get(0)); } private void createFirstAccount(String login) throws Exception { diff --git a/test/src/test/java/hudson/security/SecurityRealmTest.java b/test/src/test/java/hudson/security/SecurityRealmTest.java index 76307e8418..5d4ef3868f 100644 --- a/test/src/test/java/hudson/security/SecurityRealmTest.java +++ b/test/src/test/java/hudson/security/SecurityRealmTest.java @@ -106,7 +106,6 @@ public void many_sessions_logout() throws Exception { calendar.add(Calendar.DAY_OF_YEAR, 1); Date tomorrow = calendar.getTime(); Collections.nCopies(8, 1) - .stream() .forEach(i -> addSessionCookie(manager, LOCALHOST, "/jenkins", tomorrow)); addSessionCookie(manager, LOCALHOST, WILL_NOT_BE_SENT, tomorrow); diff --git a/test/src/test/java/hudson/security/TokenBasedRememberMeServices2Test.java b/test/src/test/java/hudson/security/TokenBasedRememberMeServices2Test.java index c7c4cf0609..7854ca7869 100644 --- a/test/src/test/java/hudson/security/TokenBasedRememberMeServices2Test.java +++ b/test/src/test/java/hudson/security/TokenBasedRememberMeServices2Test.java @@ -135,7 +135,7 @@ public void basicFlow() throws Exception { wc.executeOnServer(() -> { Authentication a = Jenkins.getAuthentication(); assertEquals("bob", a.getName()); - assertEquals(ImmutableList.of("authenticated", "myteam"), Arrays.asList(a.getAuthorities()).stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList())); + assertEquals(ImmutableList.of("authenticated", "myteam"), Arrays.stream(a.getAuthorities()).map(GrantedAuthority::getAuthority).collect(Collectors.toList())); return null; }); } diff --git a/test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerSEC1491Test.java b/test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerSEC1491Test.java index f27bea8eb8..61cff923b9 100644 --- a/test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerSEC1491Test.java +++ b/test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerSEC1491Test.java @@ -4,8 +4,13 @@ import com.gargoylesoftware.htmlunit.HttpMethod; import com.gargoylesoftware.htmlunit.WebRequest; import com.gargoylesoftware.htmlunit.html.HtmlPage; +import java.net.HttpURLConnection; +import java.net.URL; +import javax.servlet.http.HttpServletResponse; import jenkins.model.Jenkins; +import static org.hamcrest.Matchers.*; import org.junit.Assert; +import static org.junit.Assert.*; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -13,15 +18,6 @@ import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.MockAuthorizationStrategy; -import java.net.HttpURLConnection; -import java.net.URL; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - //TODO merge back to DefaultCrumbIssuerTest public class DefaultCrumbIssuerSEC1491Test { @@ -72,7 +68,8 @@ private void sameCrumbUsedOnDifferentAnonymousRequest_tokenAreEqual(boolean areE r.createWebClient().getPage(request1); fail(); } catch (FailingHttpStatusCodeException e) { - assertTrue(e.getMessage().contains("No valid crumb")); + assertEquals(HttpServletResponse.SC_FORBIDDEN, e.getStatusCode()); + assertThat(e.getResponse().getContentAsString(), containsString("No valid crumb")); } // cannot create new job due to missing crumb assertNull(r.jenkins.getItem(jobName1)); diff --git a/test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerSEC626Test.java b/test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerSEC626Test.java index 379dce8e5b..c67cd49fd0 100644 --- a/test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerSEC626Test.java +++ b/test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerSEC626Test.java @@ -10,6 +10,9 @@ import com.gargoylesoftware.htmlunit.html.DomElement; import com.gargoylesoftware.htmlunit.html.HtmlPage; import hudson.model.User; +import javax.servlet.http.HttpServletResponse; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -17,10 +20,6 @@ import org.jvnet.hudson.test.JenkinsRule; import org.jvnet.hudson.test.JenkinsRule.WebClient; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - /** * @author dty */ @@ -74,7 +73,8 @@ private void compareDifferentSessions_tokenAreEqual(boolean areEqual) throws Exc r.submit(p.getFormByName("config")); fail(); } catch (FailingHttpStatusCodeException e) { - assertTrue(e.getMessage().contains("No valid crumb")); + assertEquals(HttpServletResponse.SC_FORBIDDEN, e.getStatusCode()); + assertThat(e.getResponse().getContentAsString(), containsString("No valid crumb")); } } } diff --git a/test/src/test/java/hudson/slaves/JNLPLauncherTest.java b/test/src/test/java/hudson/slaves/JNLPLauncherTest.java index c76303719f..a60c4dc687 100644 --- a/test/src/test/java/hudson/slaves/JNLPLauncherTest.java +++ b/test/src/test/java/hudson/slaves/JNLPLauncherTest.java @@ -56,9 +56,11 @@ import static org.junit.Assert.fail; import java.awt.*; +import java.util.logging.Level; import static org.hamcrest.Matchers.instanceOf; import org.junit.rules.TemporaryFolder; import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.LoggerRule; import org.jvnet.hudson.test.recipes.LocalData; /** @@ -69,7 +71,9 @@ public class JNLPLauncherTest { @Rule public JenkinsRule j = new JenkinsRule(); - @Rule public TemporaryFolder tmpDir = new TemporaryFolder(); + @Rule public TemporaryFolder tmpDir = new TemporaryFolder(); + + @Rule public LoggerRule logging = new LoggerRule().record(Slave.class, Level.FINE); /** * Starts a JNLP agent and makes sure it successfully connects to Jenkins. @@ -98,7 +102,7 @@ public void testLaunchWithWorkDir() throws Exception { /** * Tests the '-headless' option. - * (Although this test doesn't really assert that the agent really is running in a headless mdoe.) + * (Although this test doesn't really assert that the agent really is running in a headless mode.) */ @Test public void testHeadlessLaunch() throws Exception { diff --git a/test/src/test/java/hudson/tasks/FingerprinterTest.java b/test/src/test/java/hudson/tasks/FingerprinterTest.java index 9696e1c5cc..69344b5c8d 100644 --- a/test/src/test/java/hudson/tasks/FingerprinterTest.java +++ b/test/src/test/java/hudson/tasks/FingerprinterTest.java @@ -262,8 +262,8 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen fingerprints = action.getFingerprints().values(); for (Fingerprint f: fingerprints) { assertTrue(f.getOriginal().is(upstream)); - assertTrue(f.getOriginal().getName().equals(renamedProject1)); - assertFalse(f.getOriginal().getName().equals(oldUpstreamName)); + assertEquals(f.getOriginal().getName(), renamedProject1); + assertNotEquals(f.getOriginal().getName(), oldUpstreamName); } // Verify that usage entry in fingerprint record is changed after diff --git a/test/src/test/java/hudson/tasks/MavenTest.java b/test/src/test/java/hudson/tasks/MavenTest.java index ca0f7b71a1..04fa5587ef 100644 --- a/test/src/test/java/hudson/tasks/MavenTest.java +++ b/test/src/test/java/hudson/tasks/MavenTest.java @@ -360,7 +360,7 @@ public void parametersReferencedFromPropertiesShouldRetainBackslashes() throws E MavenInstallation maven = ToolInstallations.configureMaven3(); MavenInstallation maven2 = ToolInstallations.configureMaven3(); assertEquals(maven.hashCode(), maven2.hashCode()); - assertTrue(maven.equals(maven2)); + assertEquals(maven, maven2); } @Issue("JENKINS-34138") @@ -368,6 +368,6 @@ public void parametersReferencedFromPropertiesShouldRetainBackslashes() throws E MavenInstallation maven3 = ToolInstallations.configureMaven3(); MavenInstallation maven2 = ToolInstallations.configureDefaultMaven(); assertNotEquals(maven3.hashCode(), maven2.hashCode()); - assertFalse(maven3.equals(maven2)); + assertNotEquals(maven3, maven2); } } diff --git a/test/src/test/java/hudson/util/HudsonIsLoading.java b/test/src/test/java/hudson/util/HudsonIsLoadingTest.java similarity index 51% rename from test/src/test/java/hudson/util/HudsonIsLoading.java rename to test/src/test/java/hudson/util/HudsonIsLoadingTest.java index 10c11adfbf..f0efc3e269 100644 --- a/test/src/test/java/hudson/util/HudsonIsLoading.java +++ b/test/src/test/java/hudson/util/HudsonIsLoadingTest.java @@ -7,10 +7,12 @@ import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; +import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; -public class HudsonIsLoading { +public class HudsonIsLoadingTest { @Rule public JenkinsRule j = new JenkinsRule(); @@ -18,12 +20,20 @@ public class HudsonIsLoading { @Issue("JENKINS-55062") public void withPrefix() throws Exception { j.jenkins.servletContext.setAttribute("app", new HudsonIsLoading()); - JenkinsRule.WebClient wc = j.createWebClient(); - wc.getOptions().setThrowExceptionOnFailingStatusCode(false); // this is a failure page already - wc.getOptions().setJavaScriptEnabled(false); + JenkinsRule.WebClient wc = j.createWebClient() + // this is a failure page already + .withThrowExceptionOnFailingStatusCode(false) + .withJavaScriptEnabled(false); - Page p = wc.goTo("", "text/html"); - assertTrue( p.isHtmlPage() ); + checkingPage(wc, ""); + checkingPage(wc, "anyRandomString"); + checkingPage(wc, "multiple/layer/ofRelative.xml"); + } + + private void checkingPage(JenkinsRule.WebClient wc, String relativePath) throws Exception { + Page p = wc.goTo(relativePath, "text/html"); + assertTrue(p.isHtmlPage()); + assertEquals(SC_SERVICE_UNAVAILABLE, p.getWebResponse().getStatusCode()); String body = p.getWebResponse().getContentAsString(); assertThat(body, CoreMatchers.containsString("data-resurl=\"")); assertThat(body, CoreMatchers.containsString("data-rooturl=\"")); diff --git a/test/src/test/java/hudson/util/HudsonIsRestarting.java b/test/src/test/java/hudson/util/HudsonIsRestartingTest.java similarity index 51% rename from test/src/test/java/hudson/util/HudsonIsRestarting.java rename to test/src/test/java/hudson/util/HudsonIsRestartingTest.java index 3b0d8f76b2..25ea8bac86 100644 --- a/test/src/test/java/hudson/util/HudsonIsRestarting.java +++ b/test/src/test/java/hudson/util/HudsonIsRestartingTest.java @@ -7,9 +7,10 @@ import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; +import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE; import static org.junit.Assert.*; -public class HudsonIsRestarting { +public class HudsonIsRestartingTest { @Rule public JenkinsRule j = new JenkinsRule(); @@ -18,12 +19,20 @@ public class HudsonIsRestarting { @Issue("JENKINS-55062") public void withPrefix() throws Exception { j.jenkins.servletContext.setAttribute("app", new HudsonIsRestarting()); - JenkinsRule.WebClient wc = j.createWebClient(); - wc.getOptions().setThrowExceptionOnFailingStatusCode(false); // this is a failure page already - wc.getOptions().setJavaScriptEnabled(false); + JenkinsRule.WebClient wc = j.createWebClient() + // this is a failure page already + .withThrowExceptionOnFailingStatusCode(false) + .withJavaScriptEnabled(false); - Page p = wc.goTo("", "text/html"); - assertTrue( p.isHtmlPage() ); + checkingPage(wc, ""); + checkingPage(wc, "anyRandomString"); + checkingPage(wc, "multiple/layer/ofRelative.xml"); + } + + private void checkingPage(JenkinsRule.WebClient wc, String relativePath) throws Exception { + Page p = wc.goTo(relativePath, "text/html"); + assertTrue(p.isHtmlPage()); + assertEquals(SC_SERVICE_UNAVAILABLE, p.getWebResponse().getStatusCode()); String body = p.getWebResponse().getContentAsString(); assertThat(body, CoreMatchers.containsString("data-resurl=\"")); assertThat(body, CoreMatchers.containsString("data-rooturl=\"")); diff --git a/test/src/test/java/jenkins/AgentProtocolTest.java b/test/src/test/java/jenkins/AgentProtocolTest.java index dbd4479c5a..68548c7bfd 100644 --- a/test/src/test/java/jenkins/AgentProtocolTest.java +++ b/test/src/test/java/jenkins/AgentProtocolTest.java @@ -27,18 +27,10 @@ import java.util.List; import java.util.Set; import javax.annotation.CheckForNull; -import jenkins.install.SetupWizardTest; import jenkins.model.Jenkins; -import jenkins.slaves.DeprecatedAgentProtocolMonitor; import org.apache.commons.lang.StringUtils; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.nullValue; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Issue; @@ -55,25 +47,6 @@ public class AgentProtocolTest { @Rule public JenkinsRule j = new JenkinsRule(); - //TODO: Test is unstable on CI due to the race condition, needs to be reworked - /** - * Checks that Jenkins does not disable agent protocols by default after the upgrade. - * - * @throws Exception Test failure - * @see SetupWizardTest#shouldDisableUnencryptedProtocolsByDefault() - */ - @Test - @Ignore - @LocalData - @Issue("JENKINS-45841") - public void testShouldNotDisableProtocolsForMigratedInstances() throws Exception { - assertProtocols(true, "Legacy Non-encrypted JNLP protocols should be enabled", - "JNLP-connect", "JNLP2-connect", "JNLP4-connect"); - assertProtocols(true, "Default encrypted protocols should be enabled", "JNLP4-connect"); - assertProtocols(false, "JNLP3-connect protocol should be disabled by default", "JNLP3-connect"); - assertMonitorTriggered("JNLP-connect", "JNLP2-connect"); - } - @Test @LocalData @Issue("JENKINS-45841") @@ -81,7 +54,6 @@ public void testShouldNotOverrideUserConfiguration() throws Exception { assertEnabled("JNLP-connect", "JNLP3-connect"); assertDisabled("JNLP2-connect", "JNLP4-connect"); assertProtocols(true, "System protocols should be always enabled", "Ping"); - assertMonitorTriggered("JNLP-connect", "JNLP3-connect"); } private void assertEnabled(String ... protocolNames) throws AssertionError { @@ -119,30 +91,4 @@ public static void assertProtocols(Jenkins jenkins, boolean shouldBeEnabled, @Ch } } - public static void assertMonitorNotActive(JenkinsRule j) { - DeprecatedAgentProtocolMonitor monitor = new DeprecatedAgentProtocolMonitor(); - assertFalse("Deprecated Agent Protocol Monitor should not be activated. Current protocols: " - + StringUtils.join(j.jenkins.getAgentProtocols(), ","), monitor.isActivated()); - } - - public static void assertMonitorTriggered(String ... expectedProtocols) { - DeprecatedAgentProtocolMonitor monitor = new DeprecatedAgentProtocolMonitor(); - assertTrue("Deprecated Agent Protocol Monitor should be activated", monitor.isActivated()); - String protocolList = monitor.getDeprecatedProtocols(); - assertThat("List of the protocols should not be null", protocolList, not(nullValue())); - - List failedChecks = new ArrayList<>(); - for(String protocol : expectedProtocols) { - if (!protocolList.contains(protocol)) { - failedChecks.add(protocol); - } - } - - if (!failedChecks.isEmpty()) { - String message = String.format( - "Protocol(s) should in the deprecated protocol list: %s. Current list: %s", - StringUtils.join(expectedProtocols, ','), protocolList); - fail(message); - } - } } diff --git a/test/src/test/java/jenkins/TestJnlpSlaveAgentProtocol.java b/test/src/test/java/jenkins/TestJnlpSlaveAgentProtocol.java new file mode 100644 index 0000000000..b228e111c2 --- /dev/null +++ b/test/src/test/java/jenkins/TestJnlpSlaveAgentProtocol.java @@ -0,0 +1,58 @@ +/* + * The MIT License + * + * Copyright (c) 2020 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; + +import hudson.Extension; +import java.net.Socket; +import org.jenkinsci.Symbol; + +@Extension +@Symbol("jnlp") +public class TestJnlpSlaveAgentProtocol extends AgentProtocol { + + @Override + public boolean isOptIn() { + return true; + } + + @Override + public boolean isDeprecated() { + return true; + } + + @Override + public String getName() { + return "JNLP-connect"; + } + + @Override + public String getDisplayName() { + return "JNLP-connect"; + } + + @Override + public void handle(Socket socket) { + } + +} diff --git a/test/src/test/java/jenkins/TestJnlpSlaveAgentProtocol2.java b/test/src/test/java/jenkins/TestJnlpSlaveAgentProtocol2.java new file mode 100644 index 0000000000..adc936104d --- /dev/null +++ b/test/src/test/java/jenkins/TestJnlpSlaveAgentProtocol2.java @@ -0,0 +1,59 @@ +/* + * The MIT License + * + * Copyright (c) 2020 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; + +import hudson.Extension; +import org.jenkinsci.Symbol; + +import java.net.Socket; + +@Extension +@Symbol("jnlp2") +public class TestJnlpSlaveAgentProtocol2 extends AgentProtocol { + + @Override + public boolean isOptIn() { + return true; + } + + @Override + public boolean isDeprecated() { + return true; + } + + @Override + public String getName() { + return "JNLP2-connect"; + } + + @Override + public String getDisplayName() { + return "JNLP2-connect"; + } + + @Override + public void handle(Socket socket) { + } + +} diff --git a/test/src/test/java/jenkins/TestJnlpSlaveAgentProtocol3.java b/test/src/test/java/jenkins/TestJnlpSlaveAgentProtocol3.java new file mode 100644 index 0000000000..e5a1376c74 --- /dev/null +++ b/test/src/test/java/jenkins/TestJnlpSlaveAgentProtocol3.java @@ -0,0 +1,59 @@ +/* + * The MIT License + * + * Copyright (c) 2020 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; + +import hudson.Extension; +import org.jenkinsci.Symbol; + +import java.net.Socket; + +@Extension +@Symbol("jnlp3") +public class TestJnlpSlaveAgentProtocol3 extends AgentProtocol { + + @Override + public boolean isOptIn() { + return true; + } + + @Override + public boolean isDeprecated() { + return true; + } + + @Override + public String getName() { + return "JNLP3-connect"; + } + + @Override + public String getDisplayName() { + return "JNLP3-connect"; + } + + @Override + public void handle(Socket socket) { + } + +} diff --git a/test/src/test/java/jenkins/agents/WebSocketAgentsTest.java b/test/src/test/java/jenkins/agents/WebSocketAgentsTest.java new file mode 100644 index 0000000000..37c47dcfd3 --- /dev/null +++ b/test/src/test/java/jenkins/agents/WebSocketAgentsTest.java @@ -0,0 +1,125 @@ +/* + * The MIT License + * + * Copyright 2019 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.agents; + +import hudson.Functions; +import hudson.Proc; +import hudson.model.FreeStyleProject; +import hudson.model.Slave; +import hudson.remoting.Engine; +import hudson.slaves.DumbSlave; +import hudson.slaves.JNLPLauncher; +import hudson.slaves.SlaveComputer; +import hudson.tasks.BatchFile; +import hudson.tasks.Shell; +import java.io.File; +import java.util.concurrent.atomic.AtomicReference; +import java.util.logging.Level; +import java.util.logging.Logger; +import jenkins.security.SlaveToMasterCallable; +import org.apache.commons.io.FileUtils; +import org.apache.tools.ant.util.JavaEnvUtils; +import org.junit.ClassRule; +import org.junit.Test; +import static org.junit.Assert.*; +import org.junit.Rule; +import org.junit.rules.TemporaryFolder; +import org.jvnet.hudson.test.BuildWatcher; +import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.LoggerRule; + +@Issue("JEP-222") +public class WebSocketAgentsTest { + + private static final Logger LOGGER = Logger.getLogger(WebSocketAgentsTest.class.getName()); + + @ClassRule + public static BuildWatcher buildWatcher = new BuildWatcher(); + + @Rule + public JenkinsRule r = new JenkinsRule(); + + @Rule + public LoggerRule logging = new LoggerRule(). + record(Slave.class, Level.FINE). + record(SlaveComputer.class, Level.FINEST). + record(WebSocketAgents.class, Level.FINEST). + record(Engine.class, Level.FINEST); + + @Rule + public TemporaryFolder tmp = new TemporaryFolder(); + + /** + * Verify basic functionality of an agent in {@code -webSocket} mode. + * Requires {@code remoting} to have been {@code mvn install}ed. + * Does not show {@code FINE} or lower agent logs ({@link JenkinsRule#showAgentLogs(Slave, LoggerRule)} cannot be used here). + * Unlike {@link hudson.slaves.JNLPLauncherTest} this does not use {@code javaws}; + * closer to {@link hudson.bugs.JnlpAccessWithSecuredHudsonTest}. + * @see hudson.remoting.Launcher + */ + @SuppressWarnings("ResultOfMethodCallIgnored") + @Test + public void smokes() throws Exception { + AtomicReference proc = new AtomicReference<>(); + try { + JNLPLauncher launcher = new JNLPLauncher(true); + launcher.setWebSocket(true); + DumbSlave s = new DumbSlave("remote", tmp.newFolder("agent").getAbsolutePath(), launcher); + r.jenkins.addNode(s); + String secret = ((SlaveComputer) s.toComputer()).getJnlpMac(); + File slaveJar = tmp.newFile(); + FileUtils.copyURLToFile(new Slave.JnlpJar("slave.jar").getURL(), slaveJar); + proc.set(r.createLocalLauncher().launch().cmds( + JavaEnvUtils.getJreExecutable("java"), "-jar", slaveJar.getAbsolutePath(), + "-jnlpUrl", r.getURL() + "computer/remote/slave-agent.jnlp", + "-secret", secret + ).stdout(System.out).start()); + r.waitOnline(s); + assertEquals("response", s.getChannel().call(new DummyTask())); + FreeStyleProject p = r.createFreeStyleProject(); + p.setAssignedNode(s); + p.getBuildersList().add(Functions.isWindows() ? new BatchFile("echo hello") : new Shell("echo hello")); + r.buildAndAssertSuccess(p); + s.toComputer().getLogText().writeLogTo(0, System.out); + } finally { + if (proc.get() != null) { + proc.get().kill(); + while (r.jenkins.getComputer("remote").isOnline()) { + LOGGER.info("waiting for computer to go offline"); + Thread.sleep(250); + } + } + } + } + + private static class DummyTask extends SlaveToMasterCallable { + @Override + public String call() { + return "response"; + } + } + +} diff --git a/test/src/test/java/jenkins/install/InstallStateTest.java b/test/src/test/java/jenkins/install/InstallStateTest.java index 581e19401c..c6debf2c5f 100644 --- a/test/src/test/java/jenkins/install/InstallStateTest.java +++ b/test/src/test/java/jenkins/install/InstallStateTest.java @@ -49,7 +49,7 @@ public class InstallStateTest { public JenkinsRule j = new JenkinsRule(); @Test - public void shouldPefromCorrectConversionForAllNames() { + public void shouldPerformCorrectConversionForAllNames() { ExtensionList states = InstallState.all(); for (InstallState state : states) { InstallState afterRoundtrip = forName(state.name()); diff --git a/test/src/test/java/jenkins/install/SetupWizardTest.java b/test/src/test/java/jenkins/install/SetupWizardTest.java index 6afe562779..fd495e9ea1 100644 --- a/test/src/test/java/jenkins/install/SetupWizardTest.java +++ b/test/src/test/java/jenkins/install/SetupWizardTest.java @@ -32,7 +32,6 @@ import java.io.File; import java.io.IOException; import java.net.MalformedURLException; -import jenkins.AgentProtocolTest; import org.apache.commons.io.FileUtils; import static org.hamcrest.Matchers.*; import org.junit.Before; @@ -115,17 +114,6 @@ public void shouldProhibitAccessToPluginListWithoutAuth() throws Exception { wc.assertFails("setupWizard/completeInstall", 403); } - @Test - @Issue("JENKINS-45841") - public void shouldDisableUnencryptedProtocolsByDefault() throws Exception { - AgentProtocolTest.assertProtocols(j.jenkins, true, - "Encrypted JNLP4-protocols protocol should be enabled", "JNLP4-connect"); - AgentProtocolTest.assertProtocols(j.jenkins, false, - "Non-encrypted JNLP protocols should be disabled by default", - "JNLP-connect", "JNLP2-connect"); - AgentProtocolTest.assertMonitorNotActive(j); - } - private String jsonRequest(JenkinsRule.WebClient wc, String path) throws Exception { // Try to call the actions method to retrieve the data final Page res; diff --git a/test/src/test/java/jenkins/model/ContextMenuTest.java b/test/src/test/java/jenkins/model/ContextMenuTest.java index 18d113c417..a890dac491 100644 --- a/test/src/test/java/jenkins/model/ContextMenuTest.java +++ b/test/src/test/java/jenkins/model/ContextMenuTest.java @@ -35,6 +35,8 @@ import java.util.concurrent.Callable; import static jenkins.model.ModelObjectWithContextMenu.*; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.Issue; @@ -64,7 +66,7 @@ public class ContextMenuTest { f.visible = false; menu = j.executeOnServer(doContextMenu); parsed = parse(menu); - assertEquals(parsed.toString(), null, parsed.get("testing")); + assertNull(parsed.toString(), parsed.get("testing")); } @TestExtension public static class ActionFactory extends TransientProjectActionFactory { diff --git a/test/src/test/java/jenkins/model/JenkinsBuildsAndWorkspacesDirectoriesTest.java b/test/src/test/java/jenkins/model/JenkinsBuildsAndWorkspacesDirectoriesTest.java index f8bc1802b4..cfd65dae9d 100644 --- a/test/src/test/java/jenkins/model/JenkinsBuildsAndWorkspacesDirectoriesTest.java +++ b/test/src/test/java/jenkins/model/JenkinsBuildsAndWorkspacesDirectoriesTest.java @@ -25,7 +25,6 @@ import java.util.List; import java.util.logging.Level; import java.util.stream.Stream; -import java.util.stream.Collectors; import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertEquals; @@ -287,9 +286,8 @@ private boolean logWasFound(String searched) { private boolean logWasFoundAtLevel(String searched, Level level) { return loggerRule.getRecords().stream() - .filter(record -> record.getMessage().contains(searched)) - .filter(record -> record.getLevel().equals(level)) - .collect(Collectors.toList()).size() > 0; + .filter(record -> record.getMessage().contains(searched)) + .filter(record -> record.getLevel().equals(level)).count() > 0; } @Test diff --git a/test/src/test/java/jenkins/model/JenkinsTest.java b/test/src/test/java/jenkins/model/JenkinsTest.java index 781ea44331..6addc51eb3 100644 --- a/test/src/test/java/jenkins/model/JenkinsTest.java +++ b/test/src/test/java/jenkins/model/JenkinsTest.java @@ -383,7 +383,7 @@ public String getUrlName() { } public HttpResponse doDynamic() { - assertTrue(Jenkins.get().getAuthentication().getName().equals("anonymous")); + assertEquals("anonymous", Jenkins.get().getAuthentication().getName()); count++; return HttpResponses.html("OK"); } @@ -411,7 +411,7 @@ public void testErrorPageShouldBeAnonymousAccessible() throws Exception { j.jenkins.setAuthorizationStrategy(auth); // no anonymous read access - assertTrue(!Jenkins.get().hasPermission(Jenkins.ANONYMOUS, Jenkins.READ)); + assertFalse(Jenkins.get().hasPermission(Jenkins.ANONYMOUS, Jenkins.READ)); WebClient wc = j.createWebClient() .withThrowExceptionOnFailingStatusCode(false); diff --git a/test/src/test/java/jenkins/model/MasterBuildConfigurationTest.java b/test/src/test/java/jenkins/model/MasterBuildConfigurationTest.java index e314ee0fe5..5fcad5b221 100644 --- a/test/src/test/java/jenkins/model/MasterBuildConfigurationTest.java +++ b/test/src/test/java/jenkins/model/MasterBuildConfigurationTest.java @@ -1,6 +1,6 @@ package jenkins.model; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; import hudson.model.Node.Mode; @@ -17,8 +17,8 @@ public class MasterBuildConfigurationTest { @Issue("JENKINS-23966") public void retainMasterLabelWhenNoSlaveDefined() throws Exception { Jenkins jenkins = j.getInstance(); - - assertTrue("Test is for master with no slave", jenkins.getComputers().length == 1); + + assertEquals("Test is for master with no slave", 1, jenkins.getComputers().length); // set our own label & mode final String myTestLabel = "TestLabelx0123"; @@ -29,7 +29,7 @@ public void retainMasterLabelWhenNoSlaveDefined() throws Exception { j.configRoundtrip(); // make sure settings were not lost - assertTrue("Master's label is lost", myTestLabel.equals(jenkins.getLabelString())); - assertTrue("Master's mode is lost", Mode.EXCLUSIVE.equals(jenkins.getMode())); + assertEquals("Master's label is lost", myTestLabel, jenkins.getLabelString()); + assertEquals("Master's mode is lost", Mode.EXCLUSIVE, jenkins.getMode()); } } diff --git a/test/src/test/java/jenkins/model/lazy/LazyBuildMixInTest.java b/test/src/test/java/jenkins/model/lazy/LazyBuildMixInTest.java index a08c22d6fc..e57b52d5e2 100644 --- a/test/src/test/java/jenkins/model/lazy/LazyBuildMixInTest.java +++ b/test/src/test/java/jenkins/model/lazy/LazyBuildMixInTest.java @@ -48,8 +48,8 @@ public class LazyBuildMixInTest { FreeStyleBuild b3 = r.buildAndAssertSuccess(p); assertEquals(b2, b1.getNextBuild()); assertEquals(b3, b2.getNextBuild()); - assertEquals(null, b3.getNextBuild()); - assertEquals(null, b1.getPreviousBuild()); + assertNull(b3.getNextBuild()); + assertNull(b1.getPreviousBuild()); assertEquals(b1, b2.getPreviousBuild()); assertEquals(b2, b3.getPreviousBuild()); b1.getRunMixIn().createReference().clear(); @@ -70,8 +70,8 @@ public class LazyBuildMixInTest { FreeStyleBuild b3 = r.buildAndAssertSuccess(p); assertEquals(b2, b1.getNextBuild()); assertEquals(b3, b2.getNextBuild()); - assertEquals(null, b3.getNextBuild()); - assertEquals(null, b1.getPreviousBuild()); + assertNull(b3.getNextBuild()); + assertNull(b1.getPreviousBuild()); assertEquals(b1, b2.getPreviousBuild()); assertEquals(b2, b3.getPreviousBuild()); b2.delete(); diff --git a/test/src/test/java/jenkins/security/FilePathSecureTest.java b/test/src/test/java/jenkins/security/FilePathSecureTest.java index 23996343a1..7e32c232eb 100644 --- a/test/src/test/java/jenkins/security/FilePathSecureTest.java +++ b/test/src/test/java/jenkins/security/FilePathSecureTest.java @@ -63,11 +63,8 @@ public class FilePathSecureTest { dir.mkdirs(); dir.child("stuff").write("hello", null); FilePath tar = root.child("dir.tar"); - OutputStream os = tar.write(); - try { + try (OutputStream os = tar.write()) { dir.tar(os, new DirScanner.Full()); - } finally { - os.close(); } tar.untar(remote, FilePath.TarCompression.NONE); assertEquals("hello", remote.child("dir/stuff").readToString()); @@ -88,11 +85,8 @@ public class FilePathSecureTest { dir.mkdirs(); dir.child("stuff").write("hello", null); FilePath tar = root.child("dir.tar"); - OutputStream os = tar.write(); - try { + try (OutputStream os = tar.write()) { dir.tar(os, new DirScanner.Full()); - } finally { - os.close(); } tar.untar(root, FilePath.TarCompression.NONE); assertEquals("hello", remote.child("dir/stuff").readToString()); diff --git a/test/src/test/java/jenkins/security/RedactSecretJsonInErrorMessageSanitizerHtmlTest.java b/test/src/test/java/jenkins/security/RedactSecretJsonInErrorMessageSanitizerHtmlTest.java index 2ac05c82bf..9fae40fd01 100644 --- a/test/src/test/java/jenkins/security/RedactSecretJsonInErrorMessageSanitizerHtmlTest.java +++ b/test/src/test/java/jenkins/security/RedactSecretJsonInErrorMessageSanitizerHtmlTest.java @@ -82,10 +82,9 @@ public void passwordsAreRedacted_andOtherStayTheSame() throws Exception { String textLevelOne = "plain-2"; String pwdLevelOneA = "secret-2"; - String pwdLevelOneB = "secret-3"; + String pwdLevelOneB = "pre-set secret"; // set in Jelly ((HtmlInput) page.getElementById("text-level-one")).setValueAttribute(textLevelOne); ((HtmlInput) page.getElementById("pwd-level-one-a")).setValueAttribute(pwdLevelOneA); - ((HtmlInput) page.getElementById("pwd-level-one-b")).setValueAttribute(pwdLevelOneB); HtmlForm form = page.getFormByName("config"); Page formSubmitPage = j.submit(form); diff --git a/test/src/test/java/jenkins/security/ResourceDomainTest.java b/test/src/test/java/jenkins/security/ResourceDomainTest.java index 4aca157e6d..5c5c335eb2 100644 --- a/test/src/test/java/jenkins/security/ResourceDomainTest.java +++ b/test/src/test/java/jenkins/security/ResourceDomainTest.java @@ -10,6 +10,7 @@ import hudson.model.UnprotectedRootAction; import jenkins.model.Jenkins; import jenkins.model.JenkinsLocationConfiguration; +import static org.hamcrest.Matchers.*; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -98,7 +99,7 @@ public void secondDomainBasics() throws Exception { { webClient.setThrowExceptionOnFailingStatusCode(false); - Page page = webClient.getPage(resourceRootUrl + "/static-files"); + Page page = webClient.getPage(resourceRootUrl + "/static-files/"); Assert.assertEquals("resource action index page response is 404", 404, page.getWebResponse().getStatusCode()); } @@ -176,7 +177,7 @@ public void secondDomainCannotBeFaked() throws Exception { String modifiedUrl = resourceResponseUrl.replaceAll("static[-]files[/]....", "static-files/aaaa"); Page page = webClient.getPage(modifiedUrl); Assert.assertEquals("resource not found", 404, page.getWebResponse().getStatusCode()); - Assert.assertEquals("resource not found", ResourceDomainFilter.ERROR_RESPONSE, page.getWebResponse().getStatusMessage()); + Assert.assertThat("resource not found", page.getWebResponse().getContentAsString(), containsString(ResourceDomainFilter.ERROR_RESPONSE)); } @@ -219,7 +220,7 @@ public void missingPermissionsCause403() throws Exception { // and we get a 403 response page = webClient.getPage(anonUrl); Assert.assertEquals("page is not found", 403, page.getWebResponse().getStatusCode()); - Assert.assertTrue("Response mentions workspace permission", page.getWebResponse().getStatusMessage().contains("Failed permission check: anonymous is missing the Job/Workspace permission")); + Assert.assertThat("Response mentions workspace permission", page.getWebResponse().getContentAsString(), containsString("Failed permission check: anonymous is missing the Job/Workspace permission")); // now remove Job/Read permission from all users (but grant Discover) a = new MockAuthorizationStrategy(); @@ -230,7 +231,7 @@ public void missingPermissionsCause403() throws Exception { // and we get a 403 response asking to log in (Job/Discover is basically meant to be granted to anonymous only) page = webClient.getPage(anonUrl); Assert.assertEquals("page is not found", 403, page.getWebResponse().getStatusCode()); - Assert.assertTrue("Response mentions workspace permission", page.getWebResponse().getStatusMessage().contains("Failed permission check: Please login to access job")); + Assert.assertThat("Response mentions workspace permission", page.getWebResponse().getContentAsString(), containsString("Failed permission check: Please login to access job")); } @Test diff --git a/test/src/test/java/jenkins/security/Security637Test.java b/test/src/test/java/jenkins/security/Security637Test.java index 7a38df6a6b..ef60250162 100644 --- a/test/src/test/java/jenkins/security/Security637Test.java +++ b/test/src/test/java/jenkins/security/Security637Test.java @@ -51,6 +51,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; +import org.junit.Ignore; public class Security637Test { @@ -88,7 +89,8 @@ public String call() throws Exception { return handler.getClass().getName(); } } - + + @Ignore("TODO these map to different IPs now") @Test @Issue("SECURITY-637") public void urlDnsEquivalence() { @@ -104,6 +106,7 @@ public void evaluate() throws Exception { }); } + @Ignore("TODO these map to different IPs now") @Test @Issue("SECURITY-637") public void urlSafeDeserialization_urlBuiltInAgent_inSameJVMRemotingContext() { @@ -136,6 +139,7 @@ public URL call() throws Exception { } } + @Ignore("TODO these map to different IPs now") @Test @Issue("SECURITY-637") public void urlSafeDeserialization_urlBuiltInMaster_inSameJVMRemotingContext() { diff --git a/test/src/test/java/jenkins/security/seed/UserSeedSecurityListenerTest.java b/test/src/test/java/jenkins/security/seed/UserSeedSecurityListenerTest.java new file mode 100644 index 0000000000..b68187f68a --- /dev/null +++ b/test/src/test/java/jenkins/security/seed/UserSeedSecurityListenerTest.java @@ -0,0 +1,61 @@ +/* + * The MIT License + * + * Copyright (c) 2019 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.seed; + +import org.acegisecurity.AuthenticationManager; +import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.JenkinsRule; +import org.kohsuke.stapler.Stapler; + +import javax.servlet.http.HttpSession; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class UserSeedSecurityListenerTest { + + @Rule + public JenkinsRule j = new JenkinsRule(); + + @Test + @Issue("JENKINS-59107") + public void authenticateSecondaryUserWhileLoggedIn_shouldNotOverwritePrimaryUserSessionSeed() throws Exception { + j.jenkins.setSecurityRealm(j.createDummySecurityRealm()); + AuthenticationManager authenticationManager = j.jenkins.getSecurityRealm().getSecurityComponents().manager; + JenkinsRule.WebClient wc = j.createWebClient(); + wc.login("alice").executeOnServer(() -> { + HttpSession session = Stapler.getCurrentRequest().getSession(); + String existingSeed = (String) session.getAttribute(UserSeedProperty.USER_SESSION_SEED); + assertNotNull(existingSeed); + authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob", "bob")); + String updatedSeed = (String) session.getAttribute(UserSeedProperty.USER_SESSION_SEED); + assertEquals(existingSeed, updatedSeed); + return null; + }); + } +} diff --git a/test/src/test/java/jenkins/security/stapler/Security400Test.java b/test/src/test/java/jenkins/security/stapler/Security400Test.java index afb4db75aa..78382f933f 100644 --- a/test/src/test/java/jenkins/security/stapler/Security400Test.java +++ b/test/src/test/java/jenkins/security/stapler/Security400Test.java @@ -55,6 +55,7 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; +import java.net.URLEncoder; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -261,7 +262,114 @@ public void ensureDoStopStillReachable() throws Exception { assertEquals(3, atomicResult.get()); } } - + + /* + * Similar to ensureDoStopStillReachable()}, but tests Executor.doStopBuild(String) instead of Executor.doStop(). + * Implemented here (instead of ExecutorTest) for convenience (uses SemaphoredBuilder). + */ + @Test + @Issue("JENKINS-59656") + public void ensureDoStopBuildWorks() throws Exception { + j.jenkins.setCrumbIssuer(null); + JenkinsRule.WebClient wc = j.createWebClient(); + wc.getOptions().setThrowExceptionOnFailingStatusCode(false); // we expect 404 + wc.getOptions().setPrintContentOnFailingStatusCode(false); // be less verbose + + // gives access to the build result code + final AtomicInteger atomicResult = new AtomicInteger(0); + // blocks execution of the build step + final Semaphore semaphore = new Semaphore(0); + // the test project with a semaphored build step + FreeStyleProject p = j.createFreeStyleProject(); + p.getBuildersList().add(new SemaphoredBuilder(semaphore, atomicResult)); + + // to be sure to reach the correct one + j.jenkins.setNumExecutors(1); + + { // preliminary test, calling stopBuild without any executor results in 404 + WebRequest request = new WebRequest(new URL(j.getURL() + "computers/0/executors/0/stopBuild"), HttpMethod.POST); + Page page = wc.getPage(request); + assertEquals(404, page.getWebResponse().getStatusCode()); + assertRequestWasNotBlocked(); + } + + { // first try, we let the build finishes normally + // reset semaphore and result code + semaphore.drainPermits(); + atomicResult.set(0); + + QueueTaskFuture futureBuild = p.scheduleBuild2(0); + futureBuild.waitForStart(); + + // let the build finishes + semaphore.release(1); + + j.assertBuildStatus(Result.SUCCESS, futureBuild); + assertEquals(1, atomicResult.get()); + } + + { // second try, calling stopBuild without parameter interrupts the build (same as calling stop) + // reset semaphore and result code + semaphore.drainPermits(); + atomicResult.set(0); + + QueueTaskFuture futureBuild = p.scheduleBuild2(0); + futureBuild.waitForStart(); + + WebRequest request = new WebRequest(new URL(j.getURL() + "computers/0/executors/0/stopBuild"), HttpMethod.POST); + Page page = wc.getPage(request); + assertEquals(404, page.getWebResponse().getStatusCode()); + assertRequestWasNotBlocked(); + + // let the build finish quickly (if not interrupted already) + semaphore.release(1); + + j.assertBuildStatus(Result.FAILURE, futureBuild); + assertEquals(3, atomicResult.get()); // interrupted + } + + { // third try, calling stopBuild with the right parameter interrupts the build + // reset semaphore and result code + semaphore.drainPermits(); + atomicResult.set(0); + + QueueTaskFuture futureBuild = p.scheduleBuild2(0); + FreeStyleBuild build = futureBuild.waitForStart(); + String runExtId = URLEncoder.encode(build.getExternalizableId(), "UTF-8"); + + WebRequest request = new WebRequest(new URL(j.getURL() + "computers/0/executors/0/stopBuild?runExtId=" + runExtId), HttpMethod.POST); + Page page = wc.getPage(request); + assertEquals(404, page.getWebResponse().getStatusCode()); + assertRequestWasNotBlocked(); + + // let the build finish quickly (if not interrupted already) + semaphore.release(1); + + j.assertBuildStatus(Result.FAILURE, futureBuild); + assertEquals(3, atomicResult.get()); // interrupted + } + + { // fourth try, calling stopBuild with a parameter not matching build id doesn't interrupt the build + // reset semaphore and result code + semaphore.drainPermits(); + atomicResult.set(0); + + QueueTaskFuture futureBuild = p.scheduleBuild2(0); + futureBuild.waitForStart(); + + WebRequest request = new WebRequest(new URL(j.getURL() + "computers/0/executors/0/stopBuild?runExtId=whatever"), HttpMethod.POST); + Page page = wc.getPage(request); + assertEquals(404, page.getWebResponse().getStatusCode()); + assertRequestWasNotBlocked(); + + // let the build finishes + semaphore.release(1); + + j.assertBuildStatus(Result.SUCCESS, futureBuild); + assertEquals(1, atomicResult.get()); + } + } + @Test @Issue("SECURITY-404") public void anonCannotReadTextConsole() throws Exception { diff --git a/test/src/test/java/jenkins/util/AntClassLoaderTest.java b/test/src/test/java/jenkins/util/AntClassLoaderTest.java new file mode 100644 index 0000000000..248ba631be --- /dev/null +++ b/test/src/test/java/jenkins/util/AntClassLoaderTest.java @@ -0,0 +1,47 @@ +/* + * The MIT License + * + * Copyright 2020 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.util; + +import org.junit.ClassRule; +import org.junit.Test; +import static org.junit.Assert.*; +import org.junit.Rule; +import org.jvnet.hudson.test.BuildWatcher; +import org.jvnet.hudson.test.Issue; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.recipes.WithPlugin; + +public class AntClassLoaderTest { + + @Rule + public JenkinsRule r = new JenkinsRule(); + + @Issue("JENKINS-60644") + @WithPlugin("loads-resource.jpi") + @Test + public void loadsResource() throws Exception { + assertNotNull(r.jenkins.pluginManager.getPlugin("loads-resource").classLoader.getResourceAsStream("io/jenkins/plugins/loads_resource/stuff")); + } + +} diff --git a/test/src/test/java/lib/form/PasswordTest.java b/test/src/test/java/lib/form/PasswordTest.java index 042f232340..f6449d7bee 100644 --- a/test/src/test/java/lib/form/PasswordTest.java +++ b/test/src/test/java/lib/form/PasswordTest.java @@ -26,7 +26,7 @@ import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.html.HtmlInput; import com.gargoylesoftware.htmlunit.html.HtmlPage; -import com.gargoylesoftware.htmlunit.html.HtmlPasswordInput; +import com.gargoylesoftware.htmlunit.html.HtmlTextInput; import hudson.cli.CopyJobCommand; import hudson.cli.GetJobCommand; import hudson.model.*; @@ -186,8 +186,8 @@ public void testExposedCiphertext() throws Exception { @Issue("SECURITY-616") public void testCheckMethod() throws Exception { FreeStyleProject p = j.createFreeStyleProject("p"); - p.addProperty(new VulnerableProperty(Secret.fromString(""))); - HtmlPasswordInput field = j.createWebClient().getPage(p, "configure").getFormByName("config").getInputByName("_.secret"); + p.addProperty(new VulnerableProperty(null)); + HtmlTextInput field = j.createWebClient().getPage(p, "configure").getFormByName("config").getInputByName("_.secret"); while (VulnerableProperty.DescriptorImpl.incomingURL == null) { // waitForBackgroundJavaScript does not work well Thread.sleep(100); // form validation of saved value } diff --git a/test/src/test/resources/hudson/model/QueueTest/load_queue_xml/config.xml b/test/src/test/resources/hudson/model/QueueTest/load_queue_xml/config.xml index d18cae81c5..011c4941a0 100644 --- a/test/src/test/resources/hudson/model/QueueTest/load_queue_xml/config.xml +++ b/test/src/test/resources/hudson/model/QueueTest/load_queue_xml/config.xml @@ -35,10 +35,6 @@ all -1 - - JNLP-connect - JNLP2-connect - false diff --git a/test/src/test/resources/jenkins/AgentProtocolTest/testShouldNotOverrideUserConfiguration/config.xml b/test/src/test/resources/jenkins/AgentProtocolTest/config.xml similarity index 100% rename from test/src/test/resources/jenkins/AgentProtocolTest/testShouldNotOverrideUserConfiguration/config.xml rename to test/src/test/resources/jenkins/AgentProtocolTest/config.xml diff --git a/test/src/test/resources/jenkins/AgentProtocolTest/testShouldNotDisableProtocolsForMigratedInstances/config.xml b/test/src/test/resources/jenkins/AgentProtocolTest/testShouldNotDisableProtocolsForMigratedInstances/config.xml deleted file mode 100644 index 16c467b807..0000000000 --- a/test/src/test/resources/jenkins/AgentProtocolTest/testShouldNotDisableProtocolsForMigratedInstances/config.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - 1.0 - 2 - NORMAL - true - - - false - - ${ITEM_ROOTDIR}/workspace - ${ITEM_ROOTDIR}/builds - - - - - - 0 - - - - all - false - false - - - - all - 0 - - - - - \ No newline at end of file diff --git a/test/src/test/resources/jenkins/model/JenkinsBuildsAndWorkspacesDirectoriesTest/fromPreviousCustomSetup/config.xml b/test/src/test/resources/jenkins/model/JenkinsBuildsAndWorkspacesDirectoriesTest/fromPreviousCustomSetup/config.xml index 230b8e49f0..415be22b69 100644 --- a/test/src/test/resources/jenkins/model/JenkinsBuildsAndWorkspacesDirectoriesTest/fromPreviousCustomSetup/config.xml +++ b/test/src/test/resources/jenkins/model/JenkinsBuildsAndWorkspacesDirectoriesTest/fromPreviousCustomSetup/config.xml @@ -36,10 +36,6 @@ all -1 - - JNLP-connect - JNLP2-connect - false diff --git a/test/src/test/resources/jenkins/security/RedactSecretJsonInErrorMessageSanitizerHtmlTest/TestPassword/index.jelly b/test/src/test/resources/jenkins/security/RedactSecretJsonInErrorMessageSanitizerHtmlTest/TestPassword/index.jelly index 151e1d9000..3e75324cac 100644 --- a/test/src/test/resources/jenkins/security/RedactSecretJsonInErrorMessageSanitizerHtmlTest/TestPassword/index.jelly +++ b/test/src/test/resources/jenkins/security/RedactSecretJsonInErrorMessageSanitizerHtmlTest/TestPassword/index.jelly @@ -40,7 +40,7 @@ THE SOFTWARE. - + diff --git a/test/src/test/resources/plugins/alternative-update-center.json b/test/src/test/resources/plugins/alternative-update-center.json new file mode 100644 index 0000000000..4277698cb0 --- /dev/null +++ b/test/src/test/resources/plugins/alternative-update-center.json @@ -0,0 +1,47 @@ +updateCenter.post( +{"connectionCheckUrl":"http://www.google.com/", // has to be here because updateDirectly sniffs only very limited formats + "core": { + "buildDate": "Dec 31, 1969", + "name": "core", + "url": "jenkins.war", + "version": "23" + }, + "id": "alternative", + "plugins": { + "tasks": { + "buildDate": "Dec 17, 2008", + "dependencies": [], + "developers": [{"name": "lokadm"}], + "excerpt": " This plug-in scans for open tasks in a specified set of files in the project modules and visualizes the results. ", + "name": "tasks", + "wiki": "https://plugins.jenkins.io/tasks", + "requiredCore": "1.264", + "sha1": "wtzlciUKiMcg90H5CTYkGX6+r8Y=", + "title": "Jenkins Task Scanner Plug-in", + "url": "tasks.jpi", + "version": "2.23" + }, + "dummy": { + "buildDate": "Dec 17, 2008", + "dependencies": [], + "developers": [], + "excerpt": "…", + "name": "dummy", + "wiki": "https://plugins.example.com/dummy", + "requiredCore": "1.100", + "sha1": "wtzlcjUKiMcg90H5CTYkGX6+r8Y=", + "title": "Dummy", + "url": "http://nowhere.net/dummy.hpi", + "version": "1.0" + }, + "foo": { + "dependencies": [], + "name": "foo", + "wiki": "https://plugins.jenkins.io/foo", + "version": "1.0", + "url": "http://nowhere.net/dummy.hpi", + } + }, + "updateCenterVersion": 1 +} +); diff --git a/test/src/test/resources/plugins/loads-resource.jpi b/test/src/test/resources/plugins/loads-resource.jpi new file mode 100644 index 0000000000..45b9a05e98 Binary files /dev/null and b/test/src/test/resources/plugins/loads-resource.jpi differ diff --git a/test/src/test/resources/plugins/optional-depender-0.0.2.hpi b/test/src/test/resources/plugins/optional-depender-0.0.2.hpi new file mode 100644 index 0000000000..6e3031e7cd Binary files /dev/null and b/test/src/test/resources/plugins/optional-depender-0.0.2.hpi differ diff --git a/test/src/test/resources/plugins/tasks-update-center.json b/test/src/test/resources/plugins/tasks-update-center.json index 092d90d382..b70301c797 100644 --- a/test/src/test/resources/plugins/tasks-update-center.json +++ b/test/src/test/resources/plugins/tasks-update-center.json @@ -14,6 +14,7 @@ updateCenter.post( "developers": [{"name": "lokadm"}], "excerpt": " This plug-in scans for open tasks in a specified set of files in the project modules and visualizes the results. ", "name": "tasks", + "wiki": "https://plugins.jenkins.io/tasks", "requiredCore": "1.264", "sha1": "wtzlciUKiMcg90H5CTYkGX6+r8Y=", "title": "Jenkins Task Scanner Plug-in", @@ -26,6 +27,7 @@ updateCenter.post( "developers": [], "excerpt": "…", "name": "dummy", + "wiki": "https://plugins.jenkins.io/dummy", "requiredCore": "1.100", "sha1": "wtzlcjUKiMcg90H5CTYkGX6+r8Y=", "title": "Dummy", diff --git a/test/src/test/resources/plugins/variant.hpi b/test/src/test/resources/plugins/variant.hpi index 999acbcf1b..9f49430df0 100644 Binary files a/test/src/test/resources/plugins/variant.hpi and b/test/src/test/resources/plugins/variant.hpi differ diff --git a/war/nbactions.xml b/war/nbactions.xml index 3461cc3270..04a8d17042 100644 --- a/war/nbactions.xml +++ b/war/nbactions.xml @@ -30,16 +30,16 @@ Ensures that NetBeans knows which goals to run when Run Project is selected. run - hudson-dev:run + jetty:run debug - hudson-dev:run + jetty:run maven - \ No newline at end of file + diff --git a/war/pom.xml b/war/pom.xml index d8b5519fc8..da3705dd92 100644 --- a/war/pom.xml +++ b/war/pom.xml @@ -91,9 +91,7 @@ THE SOFTWARE. ${project.groupId} cli - jar-with-dependencies ${project.version} - provided org.jenkins-ci winstone - 5.3 + 5.6 test @@ -262,13 +260,6 @@ THE SOFTWARE. - - ${project.groupId} - cli - jar-with-dependencies - ${project.build.directory}/${project.build.finalName}/WEB-INF - jenkins-cli.jar - org.jenkins-ci winstone @@ -369,7 +360,7 @@ THE SOFTWARE. org.jenkins-ci.plugins script-security - 1.65 + 1.68 hpi @@ -466,10 +457,9 @@ THE SOFTWARE. - - org.jenkins-ci.tools - maven-jenkins-dev-plugin - + org.eclipse.jetty + jetty-maven-plugin + 9.4.22.v20191022 - ../core/src/main/resources - - - ../core/target/classes - default @@ -544,6 +524,8 @@ THE SOFTWARE. + + ${project.basedir}/../core/src/main/resources,${project.basedir}/../core/target/classes ${contextPath} false NONE diff --git a/war/src/main/webapp/WEB-INF/web.xml b/war/src/main/webapp/WEB-INF/web.xml index 2810415583..6647f00cc2 100644 --- a/war/src/main/webapp/WEB-INF/web.xml +++ b/war/src/main/webapp/WEB-INF/web.xml @@ -188,6 +188,16 @@ THE SOFTWARE. + + + + Disable TRACE + /* + TRACE + + + + other diff --git a/war/src/main/webapp/css/style.css b/war/src/main/webapp/css/style.css index 3c31191c44..b57dfd5dc4 100644 --- a/war/src/main/webapp/css/style.css +++ b/war/src/main/webapp/css/style.css @@ -82,6 +82,10 @@ dt { font-weight: bold; } +dt > .plugin_version { + font-weight: normal; +} + .fixed-width { font-family: monospace; } @@ -457,9 +461,10 @@ td.pane { vertical-align: middle; } -table.stripped tr:nth-child(even) { +table.stripped tr:nth-of-type(even) { background: #fbfbfb; } + table.stripped-even tr:nth-child(even) { background: #fbfbfb; } diff --git a/war/src/main/webapp/help/system-config/master-slave/clock_tr.html b/war/src/main/webapp/help/system-config/master-slave/clock_tr.html index 2d984f32a3..801ba69bfb 100644 --- a/war/src/main/webapp/help/system-config/master-slave/clock_tr.html +++ b/war/src/main/webapp/help/system-config/master-slave/clock_tr.html @@ -1,6 +1,6 @@
      Bir yapılandırma, birçok yönüyle saat konusunda hassastır. - Bu nedenle, eğer Jenkins'ın çalıştığı ana sunucunun saati ile slave'in + Bu nedenle, eğer Jenkins'in çalıştığı ana sunucunun saati ile slave'in saati arasında ciddi bir fark varsa, garip problemler oluşabilir. Makineler arasındaki saat senkronizasyonunu NTP ile sağlayabilirsiniz.
      diff --git a/war/src/main/webapp/help/system-config/master-slave/numExecutors_tr.html b/war/src/main/webapp/help/system-config/master-slave/numExecutors_tr.html index 5a9a8aa25b..93a0d77f0b 100644 --- a/war/src/main/webapp/help/system-config/master-slave/numExecutors_tr.html +++ b/war/src/main/webapp/help/system-config/master-slave/numExecutors_tr.html @@ -1,6 +1,6 @@
      - Jenkins'ın bu slave üzerinde eş zamanlı kaç tane yapılandırma yürütebileceğini kontrol eder. - Yani, buraya girilecek değer, Jenkins'ın ne kadar yüke maruz kalacağını belirler. + Jenkins'in bu slave üzerinde eş zamanlı kaç tane yapılandırma yürütebileceğini kontrol eder. + Yani, buraya girilecek değer, Jenkins'in ne kadar yüke maruz kalacağını belirler. Başlangıç için, işlemci sayısı iyi bir rakam olabilir.

      @@ -9,6 +9,6 @@ ile uğraşmasına yol açacaktır.

      - Bu değeri 0 yapmak, Jenkins'ın, konfigürasyonunu kaybetmeden, devre dışı bırakılmış bir slave'i + Bu değeri 0 yapmak, Jenkins'in, konfigürasyonunu kaybetmeden, devre dışı bırakılmış bir slave'i silmesine olanak tanır.

      \ No newline at end of file diff --git a/war/src/main/webapp/help/system-config/master-slave/usage_tr.html b/war/src/main/webapp/help/system-config/master-slave/usage_tr.html index 0cf87a3633..5a255b7a76 100644 --- a/war/src/main/webapp/help/system-config/master-slave/usage_tr.html +++ b/war/src/main/webapp/help/system-config/master-slave/usage_tr.html @@ -1,5 +1,5 @@
      - Bu makine üzerinde, Jenkins'ın yapılandırmaları nasıl planlayacağını kontrol eder. + Bu makine üzerinde, Jenkins'in yapılandırmaları nasıl planlayacağını kontrol eder.
      diff --git a/war/src/main/webapp/scripts/hudson-behavior.js b/war/src/main/webapp/scripts/hudson-behavior.js index 04270d61a5..667d00bd40 100644 --- a/war/src/main/webapp/scripts/hudson-behavior.js +++ b/war/src/main/webapp/scripts/hudson-behavior.js @@ -2615,6 +2615,9 @@ function buildFormTree(form) { default: p = findParent(e); addProperty(p, e.name, e.value); + if (e.hasClassName("complex-password-field")) { + addProperty(p, "$redact", shortenName(e.name)); + } break; } } @@ -2775,7 +2778,7 @@ function applySafeRedirector(url) { new Ajax.Request(url, { method: "get", onFailure: function(rsp) { - if(rsp.status==503 && rsp.getHeader("X-Jenkins-Interactive")==null) { + if((rsp.status >= 502 && rsp.status <= 504) && rsp.getHeader("X-Jenkins-Interactive")==null) { // redirect as long as we are still loading window.setTimeout(statusChecker,5000); } else { diff --git a/war/src/main/webapp/scripts/loading.js b/war/src/main/webapp/scripts/loading.js index 282f3395e4..ea4851fad5 100644 --- a/war/src/main/webapp/scripts/loading.js +++ b/war/src/main/webapp/scripts/loading.js @@ -47,7 +47,7 @@ function safeRedirector(url) { window.setTimeout(function() { const statusChecker = arguments.callee; Fetch.get(url, function(error, status) { - if(status === 503 || status === 0) { + if((status >= 502 && status <= 504) || status === 0) { window.setTimeout(statusChecker, timeout) } else { window.location.replace(url); diff --git a/war/src/realm.properties b/war/src/realm.properties index e8bfbe17d6..5211348e39 100644 --- a/war/src/realm.properties +++ b/war/src/realm.properties @@ -20,7 +20,9 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -for-the-syntax-of-this-file: see-http://wiki.eclipse.org/Jetty/Tutorial/Realms#HashLoginService +# For the syntax of this file see: +# https://wiki.eclipse.org/Jetty/Tutorial/Realms#HashLoginService + guest: guest admin: admin,admin alice: alice,admin