diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 20d33f3a6b..9013d1a824 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -6,9 +6,8 @@ name-template: $NEXT_MINOR_VERSION tag-template: jenkins-$NEXT_MINOR_VERSION template: | - **Disclaimer**: This is an automatically generated changelog draft for Jenkins weekly releases. - See https://www.jenkins.io/changelog/ for the official changelogs. - For `changelog.yaml` drafts see GitHub action artifacts attached to release commits. + _This is an automatically generated changelog draft for Jenkins weekly releases. + See https://www.jenkins.io/changelog/ for the official changelogs._ $CHANGES diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml index 351260d3c2..92ab774cb0 100644 --- a/.github/workflows/changelog.yml +++ b/.github/workflows/changelog.yml @@ -3,6 +3,7 @@ name: Changelog Drafter on: + workflow_dispatch: push: # branches to consider in the event; optional, defaults to all branches: @@ -10,6 +11,7 @@ on: jobs: update_draft_release: + if: github.repository_owner == 'jenkinsci' runs-on: ubuntu-latest steps: # Drafts your next Release notes as Pull Requests are merged into "master" @@ -19,6 +21,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Generates a YAML changelog file using https://github.com/jenkinsci/jenkins-core-changelog-generator + # used by Oleg N in open graph generator experiment for now - name: Generate YAML changelog draft id: jenkins-core-changelog-generator uses: jenkinsci/jenkins-core-changelog-generator@master @@ -29,15 +32,29 @@ jobs: 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 + + jenkins_io_draft: + runs-on: ubuntu-latest + if: github.repository_owner == 'jenkinsci' + steps: + - uses: tibdex/github-app-token@v1 + id: generate-token + with: + app_id: ${{ secrets.JENKINS_CHANGELOG_UPDATER_APP_ID }} + private_key: ${{ secrets.JENKINS_CHANGELOG_UPDATER_PRIVATE_KEY }} + repository: jenkins-infra/jenkins.io + - name: Check out + uses: actions/checkout@v2.3.4 + with: + fetch-depth: 0 + - name: Publish jenkins.io changelog draft + env: + GITHUB_TOKEN: ${{ steps.generate-token.outputs.token }} + GITHUB_AUTH: "nobody:${{ steps.generate-token.outputs.token }}" + GIT_AUTHOR_NAME: jenkins-infra-changelog-generator + GIT_AUTHOR_EMAIL: <86592549+jenkins-infra-changelog-generator[bot]@users.noreply.github.com> + GIT_COMMITTER_NAME: jenkins-infra-changelog-generator + GIT_COMMITTER_EMAIL: <86592549+jenkins-infra-changelog-generator[bot]@users.noreply.github.com> + run: | + wget --quiet https://raw.githubusercontent.com/jenkinsci/core-changelog-generator/master/generate-weekly-changelog.sh + bash generate-weekly-changelog.sh diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml index a2d496cc2b..43d6281619 100644 --- a/.mvn/extensions.xml +++ b/.mvn/extensions.xml @@ -2,6 +2,6 @@ io.jenkins.tools.incrementals git-changelist-maven-extension - 1.0-beta-4 + 1.2 diff --git a/Jenkinsfile b/Jenkinsfile index 7d28d339c9..b378353018 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -36,7 +36,7 @@ for(j = 0; j < jdks.size(); j++) { // Now run the actual build. stage("${buildType} Build / Test") { - timeout(time: 180, unit: 'MINUTES') { + timeout(time: 300, unit: 'MINUTES') { // See below for what this method does - we're passing an arbitrary environment // variable to it so that JAVA_OPTS and MAVEN_OPTS are set correctly. withMavenEnv(["JAVA_OPTS=-Xmx1536m -Xms512m", diff --git a/bom/pom.xml b/bom/pom.xml index beaca71fad..ea6f7ce430 100644 --- a/bom/pom.xml +++ b/bom/pom.xml @@ -39,7 +39,7 @@ THE SOFTWARE. - 1.7.31 + 1.7.32 1563.v3da2d02f9572 2.4.12 @@ -49,7 +49,7 @@ THE SOFTWARE. org.springframework.security spring-security-bom - 5.5.0 + 5.5.2 pom import @@ -66,12 +66,12 @@ THE SOFTWARE. org.apache.ant ant - 1.10.10 + 1.10.11 commons-io commons-io - 2.10.0 + 2.11.0 commons-lang @@ -140,7 +140,7 @@ THE SOFTWARE. org.kohsuke access-modifier-annotation - ${access-modifier-annotation.version} + ${access-modifier.version} @@ -170,7 +170,7 @@ THE SOFTWARE. org.jenkins-ci annotation-indexer - 1.14 + 1.15 @@ -193,11 +193,6 @@ THE SOFTWARE. jnr-posix 3.1.7 - - org.ow2.asm - asm - 9.1 - org.kohsuke windows-package-checker @@ -236,7 +231,7 @@ THE SOFTWARE. org.apache.commons commons-compress - 1.20 + 1.21 commons-collections @@ -263,15 +258,10 @@ THE SOFTWARE. memory-monitor 1.9 - - org.codehaus.woodstox - wstx-asl - 3.2.9 - net.java.dev.jna jna - 5.8.0 + 5.9.0 org.kohsuke diff --git a/cli/pom.xml b/cli/pom.xml index 259689191e..746123378f 100644 --- a/cli/pom.xml +++ b/cli/pom.xml @@ -12,6 +12,7 @@ Jenkins cli Command line interface for Jenkins + https://github.com/jenkinsci/jenkins diff --git a/core/pom.xml b/core/pom.xml index c5fcbb51b2..a617d48cd9 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -36,6 +36,7 @@ THE SOFTWARE. Jenkins core Jenkins core code and view files to render HTML. + https://github.com/jenkinsci/jenkins true @@ -107,10 +108,6 @@ THE SOFTWARE. com.github.jnr jnr-posix - - org.ow2.asm - asm - - org.codehaus.woodstox - wstx-asl - - - - stax - stax-api - - - net.java.dev.jna jna diff --git a/core/src/main/java/hudson/ClassicPluginStrategy.java b/core/src/main/java/hudson/ClassicPluginStrategy.java index 34cc9e246a..098e5661ba 100644 --- a/core/src/main/java/hudson/ClassicPluginStrategy.java +++ b/core/src/main/java/hudson/ClassicPluginStrategy.java @@ -36,7 +36,6 @@ import jenkins.ClassLoaderReflectionToolkit; import jenkins.ExtensionFilter; import jenkins.plugins.DetachedPluginsUtil; import jenkins.util.AntClassLoader; -import jenkins.util.AntWithFindResourceClassLoader; import jenkins.util.SystemProperties; import org.apache.commons.io.output.NullOutputStream; import org.apache.tools.ant.BuildException; @@ -297,7 +296,7 @@ public class ClassicPluginStrategy implements PluginStrategy { } } - AntWithFindResourceClassLoader classLoader = new AntWithFindResourceClassLoader(parent, true); + AntClassLoader classLoader = new AntClassLoader(parent, true); classLoader.addPathFiles(paths); return classLoader; } @@ -616,15 +615,6 @@ public class ClassicPluginStrategy implements PluginStrategy { return transientDependencies; } -// public List getDependencyPluginWrappers() { -// List r = new ArrayList(); -// for (Dependency d : dependencies) { -// PluginWrapper w = pluginManager.getPlugin(d.shortName); -// if (w!=null) r.add(w); -// } -// return r; -// } - @Override protected Class findClass(String name) throws ClassNotFoundException { if (PluginManager.FAST_LOOKUP) { diff --git a/core/src/main/java/hudson/EnvVars.java b/core/src/main/java/hudson/EnvVars.java index f0e42183e2..4ecd522978 100644 --- a/core/src/main/java/hudson/EnvVars.java +++ b/core/src/main/java/hudson/EnvVars.java @@ -24,7 +24,6 @@ package hudson; import hudson.remoting.VirtualChannel; -import hudson.util.CaseInsensitiveComparator; import hudson.util.CyclicGraphDetector; import hudson.util.CyclicGraphDetector.CycleDetectedException; import hudson.util.VariableResolver; @@ -105,7 +104,7 @@ public class EnvVars extends TreeMap { this.platform = platform; } public EnvVars() { - super(CaseInsensitiveComparator.INSTANCE); + super(String.CASE_INSENSITIVE_ORDER); } public EnvVars(@NonNull Map m) { diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java index c2f612f18e..fdc0df530d 100644 --- a/core/src/main/java/hudson/FilePath.java +++ b/core/src/main/java/hudson/FilePath.java @@ -35,7 +35,6 @@ import hudson.model.AbstractProject; import hudson.model.Computer; import hudson.model.Item; import hudson.model.TaskListener; -import hudson.os.PosixAPI; import hudson.os.PosixException; import hudson.remoting.Callable; import hudson.remoting.Channel; @@ -697,7 +696,7 @@ public final class FilePath implements SerializableOnlyOverRemoting { while (entries.hasMoreElements()) { ZipEntry e = entries.nextElement(); File f = new File(dir, e.getName()); - if (!f.getCanonicalPath().startsWith(dir.getCanonicalPath())) { + if (!f.getCanonicalFile().toPath().startsWith(dir.getCanonicalPath())) { throw new IOException( "Zip " + zipFile.getPath() + " contains illegal file name that breaks out of the target directory: " + e.getName()); } @@ -1013,7 +1012,7 @@ public final class FilePath implements SerializableOnlyOverRemoting { timestamp.touch(sourceTimestamp); return true; } catch (IOException x) { - Functions.printStackTrace(x, listener.error("Failed to download " + archive + " from agent; will retry from master")); + Functions.printStackTrace(x, listener.error("Failed to download " + archive + " from agent; will retry from controller")); } } @@ -1895,11 +1894,7 @@ public final class FilePath implements SerializableOnlyOverRemoting { // Anyway the existing calls already skip this method if on Windows. if (File.pathSeparatorChar==';') return; // noop - if (Util.NATIVE_CHMOD_MODE) { - PosixAPI.jnr().chmod(f.getAbsolutePath(), mask); - } else { - Files.setPosixFilePermissions(fileToPath(f), Util.modeToPermissions(mask)); - } + Files.setPosixFilePermissions(fileToPath(f), Util.modeToPermissions(mask)); } private static boolean CHMOD_WARNED = false; diff --git a/core/src/main/java/hudson/Functions.java b/core/src/main/java/hudson/Functions.java index 6756715726..d49e49a358 100644 --- a/core/src/main/java/hudson/Functions.java +++ b/core/src/main/java/hudson/Functions.java @@ -1685,7 +1685,7 @@ public class Functions { if (Util.isOverridden(Throwable.class, t.getClass(), "printStackTrace", PrintWriter.class)) { StringWriter sw = new StringWriter(); t.printStackTrace(new PrintWriter(sw)); - s.append(sw.toString()); + s.append(sw); return; } Throwable lower = t.getCause(); diff --git a/core/src/main/java/hudson/Launcher.java b/core/src/main/java/hudson/Launcher.java index 9baa3992fa..3bc5f5ca51 100644 --- a/core/src/main/java/hudson/Launcher.java +++ b/core/src/main/java/hudson/Launcher.java @@ -813,7 +813,7 @@ public abstract class Launcher { } else buf.append(c); } - listener.getLogger().println(buf.toString()); + listener.getLogger().println(buf); listener.getLogger().flush(); } diff --git a/core/src/main/java/hudson/PluginFirstClassLoader.java b/core/src/main/java/hudson/PluginFirstClassLoader.java index ee398f7b9b..fda97b672d 100644 --- a/core/src/main/java/hudson/PluginFirstClassLoader.java +++ b/core/src/main/java/hudson/PluginFirstClassLoader.java @@ -23,17 +23,16 @@ */ package hudson; -import java.io.Closeable; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; -import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; -import jenkins.util.AntWithFindResourceClassLoader; +import jenkins.util.AntClassLoader; /** * classLoader which use first /WEB-INF/lib/*.jar and /WEB-INF/classes before core classLoader @@ -42,15 +41,17 @@ import jenkins.util.AntWithFindResourceClassLoader; * @since 1.371 */ public class PluginFirstClassLoader - extends AntWithFindResourceClassLoader - implements Closeable + extends AntClassLoader { + static { + registerAsParallelCapable(); + } public PluginFirstClassLoader() { super(null, false); } - private List urls = new ArrayList<>(); + private List urls = new CopyOnWriteArrayList<>(); @Override public void addPathFiles( Collection paths ) @@ -70,13 +71,6 @@ public class PluginFirstClassLoader { return urls; } - - @Override - public void close() - throws IOException - { - cleanup(); - } @Override protected Enumeration findResources( String arg0, boolean arg1 ) diff --git a/core/src/main/java/hudson/PluginManager.java b/core/src/main/java/hudson/PluginManager.java index 5a5b613965..dd246de8d9 100644 --- a/core/src/main/java/hudson/PluginManager.java +++ b/core/src/main/java/hudson/PluginManager.java @@ -63,7 +63,6 @@ import jenkins.install.InstallUtil; import jenkins.model.Jenkins; import jenkins.plugins.DetachedPluginsUtil; import jenkins.security.CustomClassFilter; -import jenkins.telemetry.impl.java11.MissingClassTelemetry; import jenkins.util.SystemProperties; import jenkins.util.io.OnMaster; import jenkins.util.xml.RestrictiveEntityResolver; @@ -2172,9 +2171,7 @@ public abstract class PluginManager extends AbstractModelObject implements OnMas loaded.put(name, null); } // not found in any of the classloader. delegate. - ClassNotFoundException cnfe = new ClassNotFoundException(name); - MissingClassTelemetry.reportException(name, cnfe); - throw cnfe; + throw new ClassNotFoundException(name); } @Override diff --git a/core/src/main/java/hudson/PluginWrapper.java b/core/src/main/java/hudson/PluginWrapper.java index 4f02ac6e54..77435c688e 100644 --- a/core/src/main/java/hudson/PluginWrapper.java +++ b/core/src/main/java/hudson/PluginWrapper.java @@ -1071,7 +1071,7 @@ public class PluginWrapper implements Comparable, ModelObject { /** * Get list of implied dependencies. - * @since TODO + * @since 2.296 */ @Restricted(NoExternalUse.class) public @NonNull Set getImpliedDependents() { diff --git a/core/src/main/java/hudson/Util.java b/core/src/main/java/hudson/Util.java index bde1562250..8a7269bfb1 100644 --- a/core/src/main/java/hudson/Util.java +++ b/core/src/main/java/hudson/Util.java @@ -890,6 +890,20 @@ public class Util { // queryMap[38] = queryMap[43] = queryMap[61] = true; } + private static final boolean[] fullUriMap = new boolean[123]; + static { + String raw = " 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz"; + // !"#$%&'()*+,-./0123456789:;<=>?@ [\]^_` {|}~ + // ^--so these are encoded + int i; + // Encode control chars and space + for (i = 0; i < 33; i++) fullUriMap[i] = true; + for (int j = 0; j < raw.length(); i++, j++) + fullUriMap[i] = raw.charAt(j) == ' '; + // If we add encodeQuery() just add a 2nd map to encode &+= + // queryMap[38] = queryMap[43] = queryMap[61] = true; + } + /** * Encode a single path component for use in an HTTP URL. * Escapes all non-ASCII, general unsafe (space and {@code "#%<>[\]^`{|}~}) @@ -901,6 +915,23 @@ public class Util { */ @NonNull public static String rawEncode(@NonNull String s) { + return encode(s, uriMap); + } + + /** + * Encode a single path component for use in an HTTP URL. + * Escapes all special characters including those outside + * of the characters specified in RFC1738. + * All characters outside numbers and letters without diacritic are encoded. + * Note that slash ({@code /}) is encoded, so the given string should be a + * single path component used in constructing a URL. + */ + @NonNull + public static String fullEncode(@NonNull String s){ + return encode(s, fullUriMap); + } + + private static String encode(String s, boolean[] map){ boolean escaped = false; StringBuilder out = null; CharsetEncoder enc = null; @@ -910,7 +941,7 @@ public class Util { int codePoint = Character.codePointAt(s, i); if((codePoint&0xffffff80)==0) { // 1 byte c = s.charAt(i); - if (c > 122 || uriMap[c]) { + if (c > 122 || map[c]) { if (!escaped) { out = new StringBuilder(i + (m - i) * 3); out.append(s, 0, i); @@ -1805,16 +1836,4 @@ public class Util { private static PathRemover newPathRemover(@NonNull PathRemover.PathChecker pathChecker) { return PathRemover.newFilteredRobustRemover(pathChecker, DELETION_RETRIES, GC_AFTER_FAILED_DELETE, WAIT_BETWEEN_DELETION_RETRIES); } - - /** - * If this flag is true, native implementations of {@link FilePath#chmod} - * and {@link hudson.util.IOUtils#mode} are used instead of NIO. - *

- * This should only be enabled if the setgid/setuid/sticky bits are - * intentionally set on the Jenkins installation and they are being - * overwritten by Jenkins erroneously. - */ - @Restricted(value = NoExternalUse.class) - @SuppressFBWarnings("MS_SHOULD_BE_FINAL") - public static boolean NATIVE_CHMOD_MODE = SystemProperties.getBoolean(Util.class.getName() + ".useNativeChmodAndMode"); } diff --git a/core/src/main/java/hudson/WebAppMain.java b/core/src/main/java/hudson/WebAppMain.java index 6eab71e566..1f88bae7cb 100644 --- a/core/src/main/java/hudson/WebAppMain.java +++ b/core/src/main/java/hudson/WebAppMain.java @@ -341,7 +341,7 @@ public class WebAppMain implements ServletContextListener { */ private void recordBootAttempt(File home) { try (OutputStream o=Files.newOutputStream(BootFailure.getBootFailureFile(home).toPath(), StandardOpenOption.CREATE, StandardOpenOption.APPEND)) { - o.write((new Date().toString() + System.getProperty("line.separator", "\n")).getBytes()); + o.write((new Date() + System.getProperty("line.separator", "\n")).getBytes()); } catch (IOException | InvalidPathException e) { LOGGER.log(WARNING, "Failed to record boot attempts",e); } diff --git a/core/src/main/java/hudson/XmlFile.java b/core/src/main/java/hudson/XmlFile.java index d203806906..3e53cd5d19 100644 --- a/core/src/main/java/hudson/XmlFile.java +++ b/core/src/main/java/hudson/XmlFile.java @@ -33,6 +33,8 @@ import hudson.diagnosis.OldDataMonitor; import hudson.model.Descriptor; import hudson.util.AtomicFileWriter; import hudson.util.XStream2; +import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.InvalidPathException; import org.xml.sax.Attributes; @@ -118,6 +120,7 @@ import org.apache.commons.io.IOUtils; public final class XmlFile { private final XStream xs; private final File file; + private final boolean force; private static final Map beingWritten = Collections.synchronizedMap(new IdentityHashMap<>()); private static final ThreadLocal writing = new ThreadLocal<>(); @@ -126,8 +129,19 @@ public final class XmlFile { } public XmlFile(XStream xs, File file) { + this(xs, file, true); + } + + /** + * @param force Whether or not to flush the page cache to the storage device with {@link + * FileChannel#force} (i.e., {@code fsync}} or {@code FlushFileBuffers}) before this method + * returns. If you set this to {@code false}, you will lose data integrity. + * @since 2.304 + */ + public XmlFile(XStream xs, File file, boolean force) { this.xs = xs; this.file = file; + this.force = force; } public File getFile() { @@ -186,7 +200,9 @@ public final class XmlFile { public void write( Object o ) throws IOException { mkdirs(); - AtomicFileWriter w = new AtomicFileWriter(file); + AtomicFileWriter w = force + ? new AtomicFileWriter(file) + : new AtomicFileWriter(file.toPath(), StandardCharsets.UTF_8, false, false); try { w.write("\n"); beingWritten.put(o, null); diff --git a/core/src/main/java/hudson/cli/ConnectNodeCommand.java b/core/src/main/java/hudson/cli/ConnectNodeCommand.java index 0a9a152e22..670550ac76 100644 --- a/core/src/main/java/hudson/cli/ConnectNodeCommand.java +++ b/core/src/main/java/hudson/cli/ConnectNodeCommand.java @@ -42,7 +42,7 @@ import java.util.logging.Logger; public class ConnectNodeCommand extends CLICommand { @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") - @Argument(metaVar="NAME", usage="Slave name, or empty string for master; comma-separated list is supported", required=true, multiValued=true) + @Argument(metaVar="NAME", usage="Agent name, or empty string for built-in node; comma-separated list is supported", required=true, multiValued=true) private List nodes; @Option(name="-f", usage="Cancel any currently pending connect operation and retry from scratch") diff --git a/core/src/main/java/hudson/cli/DisconnectNodeCommand.java b/core/src/main/java/hudson/cli/DisconnectNodeCommand.java index 5a0a25c954..1a2e9c5570 100644 --- a/core/src/main/java/hudson/cli/DisconnectNodeCommand.java +++ b/core/src/main/java/hudson/cli/DisconnectNodeCommand.java @@ -43,7 +43,7 @@ import java.util.logging.Logger; */ @Extension public class DisconnectNodeCommand extends CLICommand { - @Argument(metaVar = "NAME", usage = "Slave name, or empty string for master; comma-separated list is supported", required = true, multiValued = true) + @Argument(metaVar = "NAME", usage = "Agent name, or empty string for built-in node; comma-separated list is supported", required = true, multiValued = true) private List nodes; @Option(name = "-m", usage = "Record the reason about why you are disconnecting this node") diff --git a/core/src/main/java/hudson/cli/OfflineNodeCommand.java b/core/src/main/java/hudson/cli/OfflineNodeCommand.java index 39270918dc..fca028627e 100644 --- a/core/src/main/java/hudson/cli/OfflineNodeCommand.java +++ b/core/src/main/java/hudson/cli/OfflineNodeCommand.java @@ -45,7 +45,7 @@ import java.util.List; @Extension public class OfflineNodeCommand extends CLICommand { - @Argument(metaVar = "NAME", usage = "Agent name, or empty string for master", required = true, multiValued = true) + @Argument(metaVar = "NAME", usage = "Agent name, or empty string for built-in node", required = true, multiValued = true) private List nodes; @Option(name = "-m", usage = "Record the reason about why you are disconnecting this node") diff --git a/core/src/main/java/hudson/cli/OnlineNodeCommand.java b/core/src/main/java/hudson/cli/OnlineNodeCommand.java index e4a56ef8ed..91fcc894dd 100644 --- a/core/src/main/java/hudson/cli/OnlineNodeCommand.java +++ b/core/src/main/java/hudson/cli/OnlineNodeCommand.java @@ -41,7 +41,7 @@ import java.util.List; @Extension public class OnlineNodeCommand extends CLICommand { - @Argument(metaVar = "NAME", usage = "Agent name, or empty string for master", required = true, multiValued = true) + @Argument(metaVar = "NAME", usage = "Agent name, or empty string for built-in node", required = true, multiValued = true) private List nodes; @Override diff --git a/core/src/main/java/hudson/console/ModelHyperlinkNote.java b/core/src/main/java/hudson/console/ModelHyperlinkNote.java index 233cac2f25..334aa56e84 100644 --- a/core/src/main/java/hudson/console/ModelHyperlinkNote.java +++ b/core/src/main/java/hudson/console/ModelHyperlinkNote.java @@ -56,7 +56,7 @@ public class ModelHyperlinkNote extends HyperlinkNote { if (c != null) { return encodeTo("/" + c.getUrl(), node.getDisplayName()); } - String nodePath = node == Jenkins.get() ? "(master)" : node.getNodeName(); + String nodePath = node == Jenkins.get() ? "(built-in)" : node.getNodeName(); return encodeTo("/computer/" + nodePath, node.getDisplayName()); } diff --git a/core/src/main/java/hudson/diagnosis/MemoryUsageMonitor.java b/core/src/main/java/hudson/diagnosis/MemoryUsageMonitor.java index c3499035a7..aa8d781032 100644 --- a/core/src/main/java/hudson/diagnosis/MemoryUsageMonitor.java +++ b/core/src/main/java/hudson/diagnosis/MemoryUsageMonitor.java @@ -76,27 +76,19 @@ public final class MemoryUsageMonitor extends PeriodicWork { private void update() { long used = 0; long max = 0; -// long cur = 0; for (MemoryPoolMXBean pool : pools) { MemoryUsage usage = pool.getCollectionUsage(); if(usage==null) continue; // not available used += usage.getUsed(); max += usage.getMax(); - -// usage = pool.getUsage(); -// if(usage==null) continue; // not available -// cur += usage.getUsed(); } // B -> KB used /= 1024; max /= 1024; -// cur /= 1024; this.used.update(used); this.max.update(max); -// -// return String.format("%d/%d/%d (%d%%)",used,cur,max,used*100/max); } /** diff --git a/core/src/main/java/hudson/diagnosis/OldDataMonitor.java b/core/src/main/java/hudson/diagnosis/OldDataMonitor.java index 6345dff0c5..fa43d35890 100644 --- a/core/src/main/java/hudson/diagnosis/OldDataMonitor.java +++ b/core/src/main/java/hudson/diagnosis/OldDataMonitor.java @@ -274,7 +274,7 @@ public class OldDataMonitor extends AdministrativeMonitor { @Override public String toString() { - return min==null ? "" : min.toString() + (single ? "" : " - " + max.toString()); + return min==null ? "" : min + (single ? "" : " - " + max.toString()); } /** diff --git a/core/src/main/java/hudson/init/TaskMethodFinder.java b/core/src/main/java/hudson/init/TaskMethodFinder.java index c23aa88f76..06702e4ea8 100644 --- a/core/src/main/java/hudson/init/TaskMethodFinder.java +++ b/core/src/main/java/hudson/init/TaskMethodFinder.java @@ -84,7 +84,7 @@ abstract class TaskMethodFinder extends TaskBuilder { c.getClassLoader().loadClass(c.getPackage().getName() + ".Messages")); return rb.format(key); } catch (ClassNotFoundException x) { - LOGGER.log(WARNING, "Failed to load "+x.getMessage()+" for "+e.toString(),x); + LOGGER.log(WARNING, "Failed to load "+x.getMessage()+" for "+ e,x); return key; } catch (MissingResourceException x) { LOGGER.log(WARNING, "Could not find key '" + key + "' in " + c.getPackage().getName() + ".Messages", x); diff --git a/core/src/main/java/hudson/init/impl/InstallUncaughtExceptionHandler.java b/core/src/main/java/hudson/init/impl/InstallUncaughtExceptionHandler.java index 2eaec5326f..36fb58addb 100644 --- a/core/src/main/java/hudson/init/impl/InstallUncaughtExceptionHandler.java +++ b/core/src/main/java/hudson/init/impl/InstallUncaughtExceptionHandler.java @@ -2,7 +2,6 @@ package hudson.init.impl; import hudson.init.Initializer; import jenkins.model.Jenkins; -import jenkins.telemetry.impl.java11.MissingClassTelemetry; import org.kohsuke.MetaInfServices; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -32,9 +31,7 @@ public class InstallUncaughtExceptionHandler { @Initializer public static void init(final Jenkins j) throws IOException { - CompressionFilter.setUncaughtExceptionHandler(j.servletContext, (e, context, req, rsp) -> { - handleException(j, e, req, rsp, 500); - }); + CompressionFilter.setUncaughtExceptionHandler(j.servletContext, (e, context, req, rsp) -> handleException(j, e, req, rsp, 500)); try { Thread.setDefaultUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler()); LOGGER.log(Level.FINE, "Successfully installed a global UncaughtExceptionHandler."); @@ -60,10 +57,6 @@ public class InstallUncaughtExceptionHandler { req.setAttribute("javax.servlet.error.exception",e); rsp.setStatus(code); try { - // If we have an exception, let's see if it's related with missing classes on Java 11. We reach - // here with a ClassNotFoundException in an action, for example. Setting the report here is the only - // way to catch the missing classes when the plugin uses Thread.currentThread().getContextClassLoader().loadClass - MissingClassTelemetry.reportExceptionInside(e); WebApp.get(j.servletContext).getSomeStapler().invoke(req, rsp, j, "/oops"); } catch (ServletException | IOException x) { if (!Stapler.isSocketException(x)) { @@ -110,11 +103,6 @@ public class InstallUncaughtExceptionHandler { "A thread (" + t.getName() + '/' + t.getId() + ") died unexpectedly due to an uncaught exception, this may leave your Jenkins in a bad way and is usually indicative of a bug in the code.", ex); - - // If we have an exception, let's see if it's related with missing classes on Java 11. We reach - // here with a ClassNotFoundException in an action, for example. Setting the report here is the only - // way to catch the missing classes when the plugin uses Thread.currentThread().getContextClassLoader().loadClass - MissingClassTelemetry.reportExceptionInside(ex); } } diff --git a/core/src/main/java/hudson/model/AbstractItem.java b/core/src/main/java/hudson/model/AbstractItem.java index b562f91ed8..2f0b64ef69 100644 --- a/core/src/main/java/hudson/model/AbstractItem.java +++ b/core/src/main/java/hudson/model/AbstractItem.java @@ -960,10 +960,10 @@ public abstract class AbstractItem extends Actionable implements Item, HttpDelet @Restricted(NoExternalUse.class) public Object getTarget() { if (!SKIP_PERMISSION_CHECK) { - if (!getACL().hasPermission(Item.DISCOVER)) { + if (!hasPermission(Item.DISCOVER)) { return null; } - getACL().checkPermission(Item.READ); + checkPermission(Item.READ); } return this; } diff --git a/core/src/main/java/hudson/model/BuildTimelineWidget.java b/core/src/main/java/hudson/model/BuildTimelineWidget.java index 717052e5bf..66b5f3c1d9 100644 --- a/core/src/main/java/hudson/model/BuildTimelineWidget.java +++ b/core/src/main/java/hudson/model/BuildTimelineWidget.java @@ -61,16 +61,13 @@ public class BuildTimelineWidget { public TimelineEventList doData(StaplerRequest req, @QueryParameter long min, @QueryParameter long max) throws IOException { TimelineEventList result = new TimelineEventList(); - for (Run r : builds.byTimestamp(min,max)) { + for (Run r : builds.byTimestamp(min,max)) { Event e = new Event(); e.start = new Date(r.getStartTimeInMillis()); e.end = new Date(r.getStartTimeInMillis()+r.getDuration()); // due to SimileAjax.HTML.deEntify (in simile-ajax-bundle.js), "<" are transformed back to "<", but not the "<"; // to protect against XSS e.title = Util.escape(r.getFullDisplayName()).replace("<", "<"); - // what to put in the description? - // e.description = "Longish description of event "+r.getFullDisplayName(); - // e.durationEvent = true; e.link = req.getContextPath()+'/'+r.getUrl(); BallColor c = r.getIconColor(); e.color = String.format("#%06X",c.getBaseColor().darker().getRGB()&0xFFFFFF); diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index 9780d77ceb..232d0c4c86 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -785,7 +785,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces } public String getUrl() { - return "computer/" + Util.rawEncode(getName()) + "/"; + return "computer/" + Util.fullEncode(getName()) + "/"; } @Exported @@ -1448,11 +1448,11 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces try (PrintWriter w = new PrintWriter(rsp.getCompressedWriter(req))) { VirtualChannel vc = getChannel(); if (vc instanceof Channel) { - w.println("Master to slave"); + w.println("Controller to agent"); ((Channel) vc).dumpExportTable(w); w.flush(); // flush here once so that even if the dump from the agent fails, the client gets some useful info - w.println("\n\n\nSlave to master"); + w.println("\n\n\nAgent to controller"); w.print(vc.call(new DumpExportTableTask())); } else { w.println(Messages.Computer_BadChannel()); @@ -1656,7 +1656,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces */ @CLIResolver public static Computer resolveForCLI( - @Argument(required=true,metaVar="NAME",usage="Agent name, or empty string for master") String name) throws CmdLineException { + @Argument(required=true,metaVar="NAME",usage="Agent name, or empty string for built-in node") String name) throws CmdLineException { Jenkins h = Jenkins.get(); Computer item = h.getComputer(name); if (item==null) { @@ -1677,6 +1677,7 @@ public /*transient*/ abstract class Computer extends Actionable implements Acces * * @see #getLogFile() */ + // TODO(terminology) migrate from slaves/ to agents/ @Initializer public static void relocateOldLogs() { relocateOldLogs(Jenkins.get().getRootDir()); diff --git a/core/src/main/java/hudson/model/Executor.java b/core/src/main/java/hudson/model/Executor.java index ae53118c02..dc43184026 100644 --- a/core/src/main/java/hudson/model/Executor.java +++ b/core/src/main/java/hudson/model/Executor.java @@ -417,7 +417,7 @@ public class Executor extends Thread implements ModelObject { } } - setName(getName() + " : executing " + executable.toString()); + setName(getName() + " : executing " + executable); Authentication auth = workUnit.context.item.authenticate2(); LOGGER.log(FINE, "{0} is now executing {1} as {2}", new Object[] {getName(), executable, auth}); if (LOGGER.isLoggable(FINE) && auth.equals(ACL.SYSTEM2)) { // i.e., unspecified diff --git a/core/src/main/java/hudson/model/Fingerprint.java b/core/src/main/java/hudson/model/Fingerprint.java index e31483e070..357232edf2 100644 --- a/core/src/main/java/hudson/model/Fingerprint.java +++ b/core/src/main/java/hudson/model/Fingerprint.java @@ -374,25 +374,6 @@ public class Fingerprint implements ModelObject, Saveable { }; } -// /** -// * List up builds. -// */ -// public ,R extends Run> Iterable listBuilds(final J job) { -// return new Iterable() { -// public Iterator iterator() { -// return new Iterators.FilterIterator(new AdaptedIterator(listNumbers().iterator()) { -// protected R adapt(Integer n) { -// return job.getBuildByNumber(n); -// } -// }) { -// protected boolean filter(R r) { -// return r!=null; -// } -// }; -// } -// }; -// } - /** * List all numbers in this range set in the descending order. */ diff --git a/core/src/main/java/hudson/model/Hudson.java b/core/src/main/java/hudson/model/Hudson.java index adea4375cd..b07c8fd0ec 100644 --- a/core/src/main/java/hudson/model/Hudson.java +++ b/core/src/main/java/hudson/model/Hudson.java @@ -306,7 +306,7 @@ public class Hudson extends Jenkins { */ @Deprecated public static boolean isAdmin() { - return Jenkins.get().getACL().hasPermission(ADMINISTER); + return Jenkins.get().hasPermission(ADMINISTER); } /** diff --git a/core/src/main/java/hudson/model/Job.java b/core/src/main/java/hudson/model/Job.java index 4c038af5cd..04efbb5f7d 100644 --- a/core/src/main/java/hudson/model/Job.java +++ b/core/src/main/java/hudson/model/Job.java @@ -1499,8 +1499,6 @@ public abstract class Job, RunT extends Run jobNames = new TreeSet<>(CaseInsensitiveComparator.INSTANCE); + /*package*/ /*almost-final*/ SortedSet jobNames = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); private DescribableList> jobFilters; @@ -151,7 +150,7 @@ public class ListView extends View implements DirectlyModifiableView { } synchronized(this) { if (jobNames == null) { - jobNames = new TreeSet<>(CaseInsensitiveComparator.INSTANCE); + jobNames = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); } } initColumns(); diff --git a/core/src/main/java/hudson/model/ManageJenkinsAction.java b/core/src/main/java/hudson/model/ManageJenkinsAction.java index ce0795c3b0..564b6c4d56 100644 --- a/core/src/main/java/hudson/model/ManageJenkinsAction.java +++ b/core/src/main/java/hudson/model/ManageJenkinsAction.java @@ -37,7 +37,7 @@ public class ManageJenkinsAction implements RootAction { @Override public String getIconFileName() { if (Jenkins.get().hasAnyPermission(Jenkins.MANAGE, Jenkins.SYSTEM_READ)) - return "gear2.png"; + return "gear.png"; else return null; } diff --git a/core/src/main/java/hudson/model/PageDecorator.java b/core/src/main/java/hudson/model/PageDecorator.java index c2be155ee0..f345fb8d21 100644 --- a/core/src/main/java/hudson/model/PageDecorator.java +++ b/core/src/main/java/hudson/model/PageDecorator.java @@ -83,9 +83,6 @@ public abstract class PageDecorator extends Descriptor implements super(self()); } - // this will never work because Descriptor and Describable are the same thing. -// protected PageDecorator() { -// } @Override public final Descriptor getDescriptor() { diff --git a/core/src/main/java/hudson/model/ParametersDefinitionProperty.java b/core/src/main/java/hudson/model/ParametersDefinitionProperty.java index 716183e70c..dfc5575491 100644 --- a/core/src/main/java/hudson/model/ParametersDefinitionProperty.java +++ b/core/src/main/java/hudson/model/ParametersDefinitionProperty.java @@ -27,6 +27,7 @@ package hudson.model; import hudson.Extension; import hudson.Util; import hudson.model.Queue.WaitingItem; +import hudson.model.queue.ScheduleResult; import java.io.IOException; import java.util.AbstractList; import java.util.ArrayList; @@ -39,6 +40,7 @@ import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; import javax.servlet.ServletException; import static javax.servlet.http.HttpServletResponse.SC_CREATED; +import static javax.servlet.http.HttpServletResponse.SC_SEE_OTHER; import jenkins.model.Jenkins; import jenkins.model.OptionalJobProperty; import jenkins.model.ParameterizedJobMixIn; @@ -187,14 +189,19 @@ public class ParametersDefinitionProperty extends OptionalJobProperty> if (delay==null) delay=new TimeDuration(TimeUnit.MILLISECONDS.convert(getJob().getQuietPeriod(), TimeUnit.SECONDS)); - Queue.Item item = Jenkins.get().getQueue().schedule2( - getJob(), delay.getTimeInSeconds(), new ParametersAction(values), ParameterizedJobMixIn.getBuildCause(getJob(), req)).getItem(); - + ScheduleResult scheduleResult = Jenkins.get().getQueue().schedule2( + getJob(), delay.getTimeInSeconds(), new ParametersAction(values), ParameterizedJobMixIn.getBuildCause(getJob(), req)); + Queue.Item item = scheduleResult.getItem(); + + if (item != null && !scheduleResult.isCreated()) { + rsp.sendRedirect(SC_SEE_OTHER, req.getContextPath() + '/' + item.getUrl()); + return; + } if (item != null) { rsp.sendRedirect(SC_CREATED, req.getContextPath() + '/' + item.getUrl()); - } else { - rsp.sendRedirect("."); + return; } + rsp.sendRedirect("."); } /** diff --git a/core/src/main/java/hudson/model/Run.java b/core/src/main/java/hudson/model/Run.java index 8a1f743402..58c842dd8f 100644 --- a/core/src/main/java/hudson/model/Run.java +++ b/core/src/main/java/hudson/model/Run.java @@ -1331,28 +1331,6 @@ public abstract class Run ,RunT extends Run names = new HashSet(); -// for (String[] token : tokens) { -// if(!names.add(combineLast(token,n))) -// continue OUTER; // collision. Increase n and try again -// } -// -// // this n successfully disambiguates -// for (int i = 0; i < tokens.length; i++) { -// String[] token = tokens[i]; -// get(i).displayPath = combineLast(token,n); -// } -// return; -// } - -// // it's impossible to get here, as that means -// // we have the same artifacts archived twice, but be defensive -// for (Artifact a : this) -// a.displayPath = a.relativePath; } /** diff --git a/core/src/main/java/hudson/model/Slave.java b/core/src/main/java/hudson/model/Slave.java index 17079a9f2c..7818fa7af3 100644 --- a/core/src/main/java/hudson/model/Slave.java +++ b/core/src/main/java/hudson/model/Slave.java @@ -206,9 +206,6 @@ public abstract class Slave extends Node implements Serializable { if (name.equals("")) throw new FormException(Messages.Slave_InvalidConfig_NoName(), null); -// if (remoteFS.equals("")) -// throw new FormException(Messages.Slave_InvalidConfig_NoRemoteDir(name), null); - if (this.numExecutors<=0) throw new FormException(Messages.Slave_InvalidConfig_Executors(name), null); } diff --git a/core/src/main/java/hudson/model/StockStatusIcon.java b/core/src/main/java/hudson/model/StockStatusIcon.java index 458c88d1b6..00ce50b045 100644 --- a/core/src/main/java/hudson/model/StockStatusIcon.java +++ b/core/src/main/java/hudson/model/StockStatusIcon.java @@ -28,7 +28,12 @@ public final class StockStatusIcon extends AbstractStatusIcon { @Override public String getImageOf(String size) { - return Stapler.getCurrentRequest().getContextPath()+ Jenkins.RESOURCE_PATH+"/images/"+size+'/'+image; + if (image.endsWith(".svg")) { + return Stapler.getCurrentRequest().getContextPath() + Jenkins.RESOURCE_PATH + "/images/svgs/" + image; + } else { + return Stapler.getCurrentRequest().getContextPath() + Jenkins.RESOURCE_PATH + + "/images/" + size + "/" + image; + } } @Override diff --git a/core/src/main/java/hudson/model/TreeView.java b/core/src/main/java/hudson/model/TreeView.java deleted file mode 100644 index 00191fc97a..0000000000 --- a/core/src/main/java/hudson/model/TreeView.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package hudson.model; - -import hudson.model.Descriptor.FormException; -import hudson.util.CaseInsensitiveComparator; -import hudson.Indenter; -import hudson.Extension; -import jenkins.util.SystemProperties; -import hudson.views.ViewsTabBar; -import jenkins.model.Jenkins; -import org.kohsuke.stapler.DataBoundConstructor; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; - -import javax.servlet.ServletException; -import java.io.IOException; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.CopyOnWriteArrayList; -import org.kohsuke.stapler.interceptor.RequirePOST; -import org.kohsuke.stapler.verb.POST; - -/** - * - *

EXPERIMENTAL

- *

- * The intention is to eventually merge this with the {@link ListView}. - * This class is here for experimentation. - * - *

- * Until this class is sufficiently stable, there's no need for l10n. - * TODO: use ViewGroupMixIn - * - * @author Kohsuke Kawaguchi - */ -public class TreeView extends View implements ViewGroup { - /** - * List of job names. This is what gets serialized. - */ - private final Set jobNames - = new TreeSet<>(CaseInsensitiveComparator.INSTANCE); - - /** - * Nested views. - */ - private final CopyOnWriteArrayList views = new CopyOnWriteArrayList<>(); - - @DataBoundConstructor - public TreeView(String name) { - super(name); - } - - /** - * Returns {@link Indenter} that has the fixed indentation width. - * Used for assisting view rendering. - */ - public Indenter createFixedIndenter(String d) { - final int depth = Integer.parseInt(d); - return new Indenter() { - @Override - protected int getNestLevel(Job job) { return depth; } - }; - } - - /** - * Returns a read-only view of all {@link Job}s in this view. - * - *

- * This method returns a separate copy each time to avoid - * concurrent modification issue. - */ - @Override - public synchronized List getItems() { - return Jenkins.get().getItems(); -// List items = new ArrayList(jobNames.size()); -// for (String name : jobNames) { -// TopLevelItem item = Hudson.getInstance().getItem(name); -// if(item!=null) -// items.add(item); -// } -// return items; - } - - @Override - public boolean contains(TopLevelItem item) { - return true; -// return jobNames.contains(item.getName()); - } - - @Override - @POST - public TopLevelItem doCreateItem(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException { - ItemGroup ig = getOwner().getItemGroup(); - if (ig instanceof ModifiableItemGroup) { - TopLevelItem item = ((ModifiableItemGroup)ig).doCreateItem(req, rsp); - if(item!=null) { - jobNames.add(item.getName()); - owner.save(); - } - return item; - } - return null; - } - - // TODO listen for changes that might affect jobNames - - @Override - protected void submit(StaplerRequest req) throws IOException, ServletException, FormException { - } - - @Override - public boolean canDelete(View view) { - return true; - } - - @Override - public void deleteView(View view) throws IOException { - views.remove(view); - } - - @Override - public Collection getViews() { - return Collections.unmodifiableList(views); - } - - @Override - public View getView(String name) { - //Top level views returned first if match - for (View v : views) { - if (v.getViewName().equals(name)) { - return v; - } - } - for (View v : views) { - if (v instanceof ViewGroup) { - View nestedView = ((ViewGroup) v).getView(name); - if (nestedView != null) { - return nestedView; - } - } - } - return null; - } - - @Override - public void onViewRenamed(View view, String oldName, String newName) { - // noop - } - - @RequirePOST - public void doCreateView( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException, FormException { - checkPermission(View.CREATE); - views.add(View.create(req,rsp,this)); - save(); - } - - // this feature is not public yet - @Extension - public static ViewDescriptor register() { - if(SystemProperties.getBoolean("hudson.TreeView")) - return new DescriptorImpl(); - else - return null; - } - - public static final class DescriptorImpl extends ViewDescriptor { - @Override - public String getDisplayName() { - return "Tree View"; - } - } - - @Override - public ViewsTabBar getViewsTabBar() { - return Jenkins.get().getViewsTabBar(); - } - - @Override - public ItemGroup getItemGroup() { - return getOwner().getItemGroup(); - } - - @Override - public List getViewActions() { - return owner.getViewActions(); - } - -} diff --git a/core/src/main/java/hudson/model/UsageStatistics.java b/core/src/main/java/hudson/model/UsageStatistics.java index 0e2bf9ea72..59f177910b 100644 --- a/core/src/main/java/hudson/model/UsageStatistics.java +++ b/core/src/main/java/hudson/model/UsageStatistics.java @@ -63,6 +63,9 @@ import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.Base64; import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + import com.jcraft.jzlib.GZIPOutputStream; import jenkins.util.SystemProperties; @@ -71,6 +74,8 @@ import jenkins.util.SystemProperties; */ @Extension public class UsageStatistics extends PageDecorator implements PersistentDescriptor { + private static final Logger LOG = Logger.getLogger(UsageStatistics.class.getName()); + private final String keyImage; /** @@ -122,7 +127,8 @@ public class UsageStatistics extends PageDecorator implements PersistentDescript } /** - * Gets the encrypted usage stat data to be sent to the Hudson server. + * Gets the encrypted usage stat data to be sent to the Hudson server. + * Used exclusively by jelly: resources/hudson/model/UsageStatistics/footer.jelly */ public String getStatData() throws IOException { Jenkins j = Jenkins.get(); @@ -190,8 +196,10 @@ public class UsageStatistics extends PageDecorator implements PersistentDescript } return new String(Base64.getEncoder().encode(baos.toByteArray())); - } catch (GeneralSecurityException e) { - throw new Error(e); // impossible + } catch (Throwable e) { // the exception could be GeneralSecurityException, InvalidParameterException or any other depending on the security provider you have installed + LOG.log(Level.INFO, "Usage statistics could not be sent ({0})", e.getMessage()); + LOG.log(Level.FINE, "Error sending usage statistics", e); + return null; } } diff --git a/core/src/main/java/hudson/model/View.java b/core/src/main/java/hudson/model/View.java index 6e13fcd577..25c80b5089 100644 --- a/core/src/main/java/hudson/model/View.java +++ b/core/src/main/java/hudson/model/View.java @@ -921,7 +921,7 @@ public abstract class View extends AbstractModelObject implements AccessControll accumulate("id", u.getId()). accumulate("fullName", u.getFullName()). accumulate("url", u.getUrl()). - accumulate("avatar", i.avatar != null ? i.avatar : Stapler.getCurrentRequest().getContextPath() + Functions.getResourcePath() + "/images/" + iconSize + "/user.png"). + accumulate("avatar", i.avatar != null ? i.avatar : Stapler.getCurrentRequest().getContextPath() + Functions.getResourcePath() + "/images/svgs/person.svg"). accumulate("timeSortKey", i.getTimeSortKey()). accumulate("lastChangeTimeString", i.getLastChangeTimeString()); Job p = i.getJob(); diff --git a/core/src/main/java/hudson/model/labels/LabelExpression.java b/core/src/main/java/hudson/model/labels/LabelExpression.java index 688167fa4b..8443174fdb 100644 --- a/core/src/main/java/hudson/model/labels/LabelExpression.java +++ b/core/src/main/java/hudson/model/labels/LabelExpression.java @@ -286,6 +286,12 @@ public abstract class LabelExpression extends Label { final Jenkins j = Jenkins.get(); Label l = j.getLabel(expression); if (l.isEmpty()) { + final LabelAtom masterLabel = LabelAtom.get("master"); + if (!masterLabel.equals(Jenkins.get().getSelfLabel()) && l.listAtoms().contains(masterLabel) && masterLabel.isEmpty()) { + // Show a warning if this expression's lack of nodes and clouds is likely caused by the built-in node name migration. + // This can probably be done better (e.g. also when `!l.isEmpty()`), but it's a start. + return FormValidation.warningWithMarkup(Messages.LabelExpression_ObsoleteMasterLabel()); + } for (LabelAtom a : l.listAtoms()) { if (a.isEmpty()) { LabelAtom nearest = LabelAtom.findNearest(a.getName()); diff --git a/core/src/main/java/hudson/model/queue/MappingWorksheet.java b/core/src/main/java/hudson/model/queue/MappingWorksheet.java index cced8c0ac8..d60809b2d0 100644 --- a/core/src/main/java/hudson/model/queue/MappingWorksheet.java +++ b/core/src/main/java/hudson/model/queue/MappingWorksheet.java @@ -173,12 +173,6 @@ public class MappingWorksheet { public class WorkChunk extends ReadOnlyList { public final int index; - // the main should be always at position 0 -// /** -// * This chunk includes {@linkplain WorkUnit#isMainWork() the main work unit}. -// */ -// public final boolean isMain; - /** * If this task needs to be run on a node with a particular label, * return that {@link Label}. Otherwise null, indicating diff --git a/core/src/main/java/hudson/node_monitors/AbstractNodeMonitorDescriptor.java b/core/src/main/java/hudson/node_monitors/AbstractNodeMonitorDescriptor.java index 3861bfca21..e773688839 100644 --- a/core/src/main/java/hudson/node_monitors/AbstractNodeMonitorDescriptor.java +++ b/core/src/main/java/hudson/node_monitors/AbstractNodeMonitorDescriptor.java @@ -194,8 +194,6 @@ public abstract class AbstractNodeMonitorDescriptor extends Descriptor0) buf.append(','); -// buf.append(l); -// } -// return buf.toString(); int fc = failureCount(); if(fc>0) return Messages.ResponseTimeMonitor_TimeOut(fc); diff --git a/core/src/main/java/hudson/scm/ChangeLogSet.java b/core/src/main/java/hudson/scm/ChangeLogSet.java index 135869989b..c78edcba8d 100644 --- a/core/src/main/java/hudson/scm/ChangeLogSet.java +++ b/core/src/main/java/hudson/scm/ChangeLogSet.java @@ -253,7 +253,7 @@ public abstract class ChangeLogSet implements Iter } catch(Exception e) { LOGGER.info("ChangeLogAnnotator " + a.toString() + " failed to annotate message '" + getMsg() + "'; " + e.getMessage()); } catch(Error e) { - LOGGER.severe("ChangeLogAnnotator " + a.toString() + " failed to annotate message '" + getMsg() + "'; " + e.getMessage()); + LOGGER.severe("ChangeLogAnnotator " + a + " failed to annotate message '" + getMsg() + "'; " + e.getMessage()); } return markup.toString(false); diff --git a/core/src/main/java/hudson/security/ACL.java b/core/src/main/java/hudson/security/ACL.java index cf4260035c..47ff187077 100644 --- a/core/src/main/java/hudson/security/ACL.java +++ b/core/src/main/java/hudson/security/ACL.java @@ -69,7 +69,7 @@ public abstract class ACL { */ public final void checkPermission(@NonNull Permission p) { Authentication a = Jenkins.getAuthentication2(); - if (a.equals(SYSTEM2)) { + if (a.equals(SYSTEM2)) { // perhaps redundant given check in AccessControlled return; } if (!hasPermission2(a,p)) { @@ -131,7 +131,7 @@ public abstract class ACL { */ public final boolean hasPermission(@NonNull Permission p) { Authentication a = Jenkins.getAuthentication2(); - if (a.equals(SYSTEM2)) { + if (a.equals(SYSTEM2)) { // perhaps redundant given check in AccessControlled return true; } return hasPermission2(a, p); diff --git a/core/src/main/java/hudson/security/AccessControlled.java b/core/src/main/java/hudson/security/AccessControlled.java index 2de2ae904b..a8c8a93a8b 100644 --- a/core/src/main/java/hudson/security/AccessControlled.java +++ b/core/src/main/java/hudson/security/AccessControlled.java @@ -24,6 +24,7 @@ package hudson.security; import edu.umd.cs.findbugs.annotations.NonNull; +import jenkins.model.Jenkins; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.core.Authentication; @@ -44,6 +45,9 @@ public interface AccessControlled { * Convenient short-cut for {@code getACL().checkPermission(permission)} */ default void checkPermission(@NonNull Permission permission) throws AccessDeniedException { + if (Jenkins.getAuthentication2().equals(ACL.SYSTEM2)) { + return; + } getACL().checkPermission(permission); } @@ -61,6 +65,9 @@ public interface AccessControlled { * Convenient short-cut for {@code getACL().hasPermission(permission)} */ default boolean hasPermission(@NonNull Permission permission) { + if (Jenkins.getAuthentication2().equals(ACL.SYSTEM2)) { + return true; + } return getACL().hasPermission(permission); } diff --git a/core/src/main/java/hudson/security/AuthenticationProcessingFilter2.java b/core/src/main/java/hudson/security/AuthenticationProcessingFilter2.java index 1f028b047f..55f3358adf 100644 --- a/core/src/main/java/hudson/security/AuthenticationProcessingFilter2.java +++ b/core/src/main/java/hudson/security/AuthenticationProcessingFilter2.java @@ -62,10 +62,9 @@ public final class AuthenticationProcessingFilter2 extends UsernamePasswordAuthe @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { if (SystemProperties.getInteger(SecurityRealm.class.getName() + ".sessionFixationProtectionMode", 1) == 2) { - // This is the default session fixation prevention fix. - // While use of SessionFixationProtectionStrategy would be the canonical Spring Security approach, it seems less compatible with some security realms. + // While use of SessionFixationProtectionStrategy is the canonical Spring Security approach, it may not be compatible with some security realms, so offer this alternative request.getSession().invalidate(); - HttpSession newSession = request.getSession(true); + request.getSession(true); } super.successfulAuthentication(request, response, chain, authResult); HttpSession newSession = request.getSession(); diff --git a/core/src/main/java/hudson/security/BasicAuthenticationFilter.java b/core/src/main/java/hudson/security/BasicAuthenticationFilter.java index 836ddd5f1d..d481260c3a 100644 --- a/core/src/main/java/hudson/security/BasicAuthenticationFilter.java +++ b/core/src/main/java/hudson/security/BasicAuthenticationFilter.java @@ -178,20 +178,6 @@ public class BasicAuthenticationFilter implements Filter { rsp.setHeader("Location",path); } - //public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - // HttpServletRequest req = (HttpServletRequest) request; - // String authorization = req.getHeader("Authorization"); - // - // String path = req.getServletPath(); - // if(authorization==null || req.getUserPrincipal()!=null || path.startsWith("/secured/")) { - // chain.doFilter(request,response); - // } else { - // if(req.getQueryString()!=null) - // path += req.getQueryString(); - // ((HttpServletResponse)response).sendRedirect(req.getContextPath()+"/secured"+path); - // } - //} - @Override public void destroy() { } diff --git a/core/src/main/java/hudson/security/SecurityRealm.java b/core/src/main/java/hudson/security/SecurityRealm.java index 0f9214da55..b31679911c 100644 --- a/core/src/main/java/hudson/security/SecurityRealm.java +++ b/core/src/main/java/hudson/security/SecurityRealm.java @@ -596,7 +596,7 @@ public abstract class SecurityRealm extends AbstractDescribableImpl, Serializable { public static final Comparator INSTANCE = new CaseInsensitiveComparator(); diff --git a/core/src/main/java/hudson/util/ChunkedInputStream.java b/core/src/main/java/hudson/util/ChunkedInputStream.java index 491e8885fa..b934fd7af9 100644 --- a/core/src/main/java/hudson/util/ChunkedInputStream.java +++ b/core/src/main/java/hudson/util/ChunkedInputStream.java @@ -284,25 +284,6 @@ public class ChunkedInputStream extends InputStream { private void parseTrailerHeaders() throws IOException { // I feel lazy. No trailing header support readCRLF(); - -// Header[] footers = null; -// try { -// String charset = "US-ASCII"; -// if (this.method != null) { -// charset = this.method.getParams().getHttpElementCharset(); -// } -// footers = HttpParser.parseHeaders(in, charset); -// } catch(HttpException e) { -// LOG.error("Error parsing trailer headers", e); -// IOException ioe = new IOException(e.getMessage()); -// ExceptionUtil.initCause(ioe, e); -// throw ioe; -// } -// if (this.method != null) { -// for (int i = 0; i < footers.length; i++) { -// this.method.addResponseFooter(footers[i]); -// } -// } } /** diff --git a/core/src/main/java/hudson/util/FormFieldValidator.java b/core/src/main/java/hudson/util/FormFieldValidator.java index f3e78b1292..29ae0eb8d4 100644 --- a/core/src/main/java/hudson/util/FormFieldValidator.java +++ b/core/src/main/java/hudson/util/FormFieldValidator.java @@ -567,10 +567,8 @@ public abstract class FormFieldValidator { public void validate(File fexe) { try { self.checkExecutable(fexe); - } catch (IOException ioe) { - exceptions[0] = ioe; - } catch (ServletException se) { - exceptions[0] = se; + } catch (IOException | ServletException ex) { + exceptions[0] = ex; } } }); diff --git a/core/src/main/java/hudson/util/IOUtils.java b/core/src/main/java/hudson/util/IOUtils.java index b51435b49c..0b77adba41 100644 --- a/core/src/main/java/hudson/util/IOUtils.java +++ b/core/src/main/java/hudson/util/IOUtils.java @@ -2,7 +2,6 @@ package hudson.util; import hudson.Functions; import hudson.Util; -import hudson.os.PosixAPI; import hudson.os.PosixException; import java.nio.file.Files; import java.nio.file.InvalidPathException; @@ -135,11 +134,7 @@ public class IOUtils { public static int mode(File f) throws PosixException { if(Functions.isWindows()) return -1; try { - if (Util.NATIVE_CHMOD_MODE) { - return PosixAPI.jnr().stat(f.getPath()).mode(); - } else { - return Util.permissionsToMode(Files.getPosixFilePermissions(fileToPath(f))); - } + return Util.permissionsToMode(Files.getPosixFilePermissions(fileToPath(f))); } catch (IOException cause) { throw new PosixException("Unable to get file permissions", cause); } diff --git a/core/src/main/java/hudson/util/Iterators.java b/core/src/main/java/hudson/util/Iterators.java index a596de1d66..a09c1dcae0 100644 --- a/core/src/main/java/hudson/util/Iterators.java +++ b/core/src/main/java/hudson/util/Iterators.java @@ -23,7 +23,6 @@ */ package hudson.util; -import com.google.common.annotations.Beta; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; @@ -419,7 +418,9 @@ public class Iterators { } /** - * Similar to {@link com.google.common.collect.Iterators#skip} except not {@link Beta}. + * Calls {@code next()} on {@code iterator}, either {@code count} times + * or until {@code hasNext()} returns {@code false}, whichever comes first. + * * @param iterator some iterator * @param count a nonnegative count */ diff --git a/core/src/main/java/hudson/util/MaskingClassLoader.java b/core/src/main/java/hudson/util/MaskingClassLoader.java index e143a47784..e8bf134217 100644 --- a/core/src/main/java/hudson/util/MaskingClassLoader.java +++ b/core/src/main/java/hudson/util/MaskingClassLoader.java @@ -49,6 +49,10 @@ public class MaskingClassLoader extends ClassLoader { private final List masksResources = new CopyOnWriteArrayList<>(); + static { + registerAsParallelCapable(); + } + public MaskingClassLoader(ClassLoader parent, String... masks) { this(parent, Arrays.asList(masks)); } diff --git a/core/src/main/java/hudson/util/ProcessTree.java b/core/src/main/java/hudson/util/ProcessTree.java index 8bcaf49a5f..367c700023 100644 --- a/core/src/main/java/hudson/util/ProcessTree.java +++ b/core/src/main/java/hudson/util/ProcessTree.java @@ -195,9 +195,9 @@ public abstract class ProcessTree implements Iterable, IProcessTree, /*package*/ final List getKillers() throws InterruptedException { if (killers==null) try { - VirtualChannel channelToMaster = AgentComputerUtil.getChannelToMaster(); - if (channelToMaster!=null) { - killers = channelToMaster.call(new ListAll()); + VirtualChannel channelToController = AgentComputerUtil.getChannelToController(); + if (channelToController!=null) { + killers = channelToController.call(new ListAll()); } else { // used in an environment that doesn't support talk-back to the master. // let's do with what we have. @@ -294,10 +294,10 @@ public abstract class ProcessTree implements Iterable, IProcessTree, // Quick check, does anything exist to check against if (!skipVetoes) { try { - VirtualChannel channelToMaster = AgentComputerUtil.getChannelToMaster(); - if (channelToMaster!=null) { + VirtualChannel channelToController = AgentComputerUtil.getChannelToController(); + if (channelToController!=null) { CheckVetoes vetoCheck = new CheckVetoes(this); - causeMessage = channelToMaster.call(vetoCheck); + causeMessage = channelToController.call(vetoCheck); } } catch (IOException e) { LOGGER.log(Level.WARNING, "I/O Exception while checking for vetoes", e); @@ -438,9 +438,9 @@ public abstract class ProcessTree implements Iterable, IProcessTree, // Check for the existance of vetoers if I don't know already if (vetoersExist == null) { try { - VirtualChannel channelToMaster = AgentComputerUtil.getChannelToMaster(); - if (channelToMaster != null) { - vetoersExist = channelToMaster.call(new DoVetoersExist()); + VirtualChannel channelToController = AgentComputerUtil.getChannelToController(); + if (channelToController != null) { + vetoersExist = channelToController.call(new DoVetoersExist()); } } catch (InterruptedException ie) { @@ -1691,9 +1691,6 @@ public abstract class ProcessTree implements Iterable, IProcessTree, for( int base=0; base, IProcessTree, return new Remote(this, getChannelForSerialization()); } -// public static void main(String[] args) { -// // dump everything -// LOGGER.setLevel(Level.ALL); -// ConsoleHandler h = new ConsoleHandler(); -// h.setLevel(Level.ALL); -// LOGGER.addHandler(h); -// -// Solaris killer = (Solaris)get(); -// Solaris.SolarisSystem s = killer.createSystem(); -// Solaris.SolarisProcess p = s.get(Integer.parseInt(args[0])); -// System.out.println(p.getEnvVars()); -// -// if(args.length==2) -// p.kill(); -// } - /* On MacOS X, there's no procfs instead you'd do it with the sysctl diff --git a/core/src/main/java/hudson/util/SecretRewriter.java b/core/src/main/java/hudson/util/SecretRewriter.java index ffb417a781..9a98477067 100644 --- a/core/src/main/java/hudson/util/SecretRewriter.java +++ b/core/src/main/java/hudson/util/SecretRewriter.java @@ -54,7 +54,7 @@ public class SecretRewriter { this(); } - private String tryRewrite(String s) throws IOException, InvalidKeyException { + private String tryRewrite(String s) throws InvalidKeyException { if (s.length()<24) return s; // Encrypting "" in Secret produces 24-letter characters, so this must be the minimum length if (!isBase64(s)) @@ -82,7 +82,7 @@ public class SecretRewriter { public boolean rewrite(File f) throws InvalidKeyException, IOException { - AtomicFileWriter w = new AtomicFileWriter(f, "UTF-8"); + AtomicFileWriter w = new AtomicFileWriter(f.toPath(), StandardCharsets.UTF_8); try { boolean modified = false; // did we actually change anything? try (PrintWriter out = new PrintWriter(new BufferedWriter(w)); @@ -110,7 +110,7 @@ public class SecretRewriter { copied = eidx; } buf.append(line.substring(copied)); - out.println(buf.toString()); + out.println(buf); } } diff --git a/core/src/main/java/hudson/util/SubClassGenerator.java b/core/src/main/java/hudson/util/SubClassGenerator.java deleted file mode 100644 index 1f15e3ba8f..0000000000 --- a/core/src/main/java/hudson/util/SubClassGenerator.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2010, InfraDNA, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package hudson.util; - -import hudson.PluginManager.UberClassLoader; -import jenkins.model.Jenkins; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Type; - -import java.lang.reflect.Constructor; - -import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -import static org.objectweb.asm.Opcodes.ALOAD; -import static org.objectweb.asm.Opcodes.ILOAD; -import static org.objectweb.asm.Opcodes.INVOKESPECIAL; -import static org.objectweb.asm.Opcodes.RETURN; - -/** - * Generates a new class that just defines constructors into the super types. - * - * @author Kohsuke Kawaguchi - */ -@Deprecated -public class SubClassGenerator extends ClassLoader { - public SubClassGenerator(ClassLoader parent) { - super(parent); - } - - public Class generate(Class base, String name) { - ClassWriter cw = new ClassWriter(0);//? - cw.visit(49, ACC_PUBLIC, name.replace('.', '/'), null, - Type.getInternalName(base),null); - - for (Constructor c : base.getDeclaredConstructors()) { - Class[] et = c.getExceptionTypes(); - String[] exceptions = new String[et.length]; - for (int i = 0; i < et.length; i++) - exceptions[i] = Type.getInternalName(et[i]); - - String methodDescriptor = getMethodDescriptor(c); - MethodVisitor m = cw.visitMethod(c.getModifiers(), "", methodDescriptor, null, exceptions); - m.visitCode(); - - int index=1; - m.visitVarInsn(ALOAD,0); - for (Class param : c.getParameterTypes()) { - Type t = Type.getType(param); - m.visitVarInsn(t.getOpcode(ILOAD), index); - index += t.getSize(); - } - m.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(base), "", methodDescriptor); - m.visitInsn(RETURN); - m.visitMaxs(index,index); - m.visitEnd(); - } - - cw.visitEnd(); - byte[] image = cw.toByteArray(); - - Class c = defineClass(name, image, 0, image.length).asSubclass(base); - - Jenkins h = Jenkins.getInstanceOrNull(); - if (h!=null) // null only during tests. - ((UberClassLoader)h.pluginManager.uberClassLoader).addNamedClass(name,c); // can't change the field type as it breaks binary compatibility - - return c; - } - - private String getMethodDescriptor(Constructor c) { - StringBuilder buf = new StringBuilder(); - buf.append('('); - for (Class p : c.getParameterTypes()) - buf.append(Type.getDescriptor(p)); - - buf.append(")V"); - return buf.toString(); - } -} diff --git a/core/src/main/java/jenkins/ClassLoaderReflectionToolkit.java b/core/src/main/java/jenkins/ClassLoaderReflectionToolkit.java index 5dc7859f13..141ed7b28a 100644 --- a/core/src/main/java/jenkins/ClassLoaderReflectionToolkit.java +++ b/core/src/main/java/jenkins/ClassLoaderReflectionToolkit.java @@ -9,7 +9,6 @@ import java.util.Enumeration; import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; import jenkins.util.AntClassLoader; -import jenkins.util.AntWithFindResourceClassLoader; /** * Reflective access to various {@link ClassLoader} methods which are otherwise {@code protected}. @@ -47,8 +46,8 @@ public class ClassLoaderReflectionToolkit { } private static Object getClassLoadingLock(ClassLoader cl, String name) { - if (cl instanceof AntWithFindResourceClassLoader) { - return ((AntWithFindResourceClassLoader) cl).getClassLoadingLock(name); + if (cl instanceof AntClassLoader) { + return ((AntClassLoader) cl).getClassLoadingLock(name); } return invoke(GetClassLoadingLock.GET_CLASS_LOADING_LOCK, RuntimeException.class, cl, name); } @@ -75,8 +74,8 @@ public class ClassLoaderReflectionToolkit { public static @CheckForNull Class _findLoadedClass(ClassLoader cl, String name) { synchronized (getClassLoadingLock(cl, name)) { Class c; - if (cl instanceof AntWithFindResourceClassLoader) { - c = ((AntWithFindResourceClassLoader) cl).findLoadedClass2(name); + if (cl instanceof AntClassLoader) { + c = ((AntClassLoader) cl).findLoadedClass2(name); } else { c = (Class) invoke(FindLoadedClass.FIND_LOADED_CLASS, RuntimeException.class, cl, name); } @@ -132,8 +131,8 @@ public class ClassLoaderReflectionToolkit { */ public static @CheckForNull URL _findResource(ClassLoader cl, String name) { URL url; - if (cl instanceof AntWithFindResourceClassLoader) { - url = ((AntWithFindResourceClassLoader) cl).findResource(name); + if (cl instanceof AntClassLoader) { + url = ((AntClassLoader) cl).findResource(name); } else if (cl instanceof URLClassLoader) { url = ((URLClassLoader) cl).findResource(name); } else { @@ -162,8 +161,8 @@ public class ClassLoaderReflectionToolkit { */ public static @NonNull Enumeration _findResources(ClassLoader cl, String name) throws IOException { Enumeration urls; - if (cl instanceof AntWithFindResourceClassLoader) { - urls = ((AntWithFindResourceClassLoader) cl).findResources(name); + if (cl instanceof AntClassLoader) { + urls = ((AntClassLoader) cl).findResources(name); } else { urls = (Enumeration) invoke(FindResources.FIND_RESOURCES, IOException.class, cl, name); } diff --git a/core/src/main/java/jenkins/agents/AgentComputerUtil.java b/core/src/main/java/jenkins/agents/AgentComputerUtil.java index 021b236c53..c987768b86 100644 --- a/core/src/main/java/jenkins/agents/AgentComputerUtil.java +++ b/core/src/main/java/jenkins/agents/AgentComputerUtil.java @@ -35,26 +35,36 @@ public final class AgentComputerUtil { } /** - * Obtains a {@link VirtualChannel} that allows some computation to be performed on the master. - * This method can be called from any thread on the master, or from agent (more precisely, + * Obtains a {@link VirtualChannel} that allows some computation to be performed on the controller. + * This method can be called from any thread on the controller, or from agent (more precisely, * it only works from the remoting request-handling thread in agents, which means if you've started * separate thread on agents, that'll fail.) * - * @return null if the calling thread doesn't have any trace of where its master is. - * @since 2.235 + * @return null if the calling thread doesn't have any trace of where its controller is. + * @since 2.307 */ @CheckForNull - public static VirtualChannel getChannelToMaster() { + public static VirtualChannel getChannelToController() { if (JenkinsJVM.isJenkinsJVM()) { return FilePath.localChannel; } // if this method is called from within the agent computation thread, this should work Channel c = Channel.current(); - if (c != null && Boolean.TRUE.equals(c.getProperty("slave"))) { + if (c != null && Boolean.TRUE.equals(c.getProperty("agent"))) { return c; } return null; } + + /** + * @deprecated Use {{@link #getChannelToController()}}. + * @since 2.235 + */ + @Deprecated + @CheckForNull + public static VirtualChannel getChannelToMaster() { + return getChannelToController(); + } } diff --git a/core/src/main/java/jenkins/diagnostics/ControllerExecutorsAgents.java b/core/src/main/java/jenkins/diagnostics/ControllerExecutorsAgents.java index f13df36018..31711ccbff 100644 --- a/core/src/main/java/jenkins/diagnostics/ControllerExecutorsAgents.java +++ b/core/src/main/java/jenkins/diagnostics/ControllerExecutorsAgents.java @@ -37,7 +37,7 @@ import org.kohsuke.stapler.interceptor.RequirePOST; import java.io.IOException; @Extension -@Symbol("controllerExecutorsWithAgents") +@Symbol({"executorsOnBuiltInNodeWithAgents", "controllerExecutorsWithAgents"}) @Restricted(NoExternalUse.class) public class ControllerExecutorsAgents extends AdministrativeMonitor { @@ -63,7 +63,7 @@ public class ControllerExecutorsAgents extends AdministrativeMonitor { disable(true); rsp.sendRedirect(req.getContextPath() + "/manage"); } else if (req.hasParameter("yes")) { - rsp.sendRedirect(req.getContextPath() + "/computer/(master)/configure"); + rsp.sendRedirect(req.getContextPath() + "/computer/(built-in)/configure"); } } diff --git a/core/src/main/java/jenkins/diagnostics/ControllerExecutorsNoAgents.java b/core/src/main/java/jenkins/diagnostics/ControllerExecutorsNoAgents.java index 52f5ae5517..bf036ba2b0 100644 --- a/core/src/main/java/jenkins/diagnostics/ControllerExecutorsNoAgents.java +++ b/core/src/main/java/jenkins/diagnostics/ControllerExecutorsNoAgents.java @@ -37,7 +37,7 @@ import org.kohsuke.stapler.interceptor.RequirePOST; import java.io.IOException; @Extension -@Symbol("controllerExecutorsWithoutAgents") +@Symbol({"executorsOnBuiltInNodeWithoutAgents", "controllerExecutorsWithoutAgents"}) @Restricted(NoExternalUse.class) public class ControllerExecutorsNoAgents extends AdministrativeMonitor { diff --git a/core/src/main/java/jenkins/fingerprints/FingerprintStorage.java b/core/src/main/java/jenkins/fingerprints/FingerprintStorage.java index d92bbf4c22..f447ed378e 100644 --- a/core/src/main/java/jenkins/fingerprints/FingerprintStorage.java +++ b/core/src/main/java/jenkins/fingerprints/FingerprintStorage.java @@ -114,7 +114,7 @@ public abstract class FingerprintStorage extends AbstractDescribableImpl items = new CopyOnWriteMap.Tree<>(CaseInsensitiveComparator.INSTANCE); + /*package*/ final transient Map items = new CopyOnWriteMap.Tree<>(String.CASE_INSENSITIVE_ORDER); /** * The sole instance. @@ -673,10 +670,13 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve private transient Set agentProtocols; /** - * Whitespace-separated labels assigned to the master as a {@link Node}. + * Whitespace-separated labels assigned to the built-in node as a {@link Node}. */ private String label=""; + //@SuppressFBWarnings("MS_SHOULD_BE_FINAL") + private static /* non-final for Groovy */ String nodeNameAndSelfLabelOverride = SystemProperties.getString(Jenkins.class.getName() + ".nodeNameAndSelfLabelOverride"); + /** * {@link hudson.security.csrf.CrumbIssuer} */ @@ -860,6 +860,14 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve */ private Boolean noUsageStatistics; + /** + * If this is false, no migration is needed to reconfigure the built-in node (formerly 'master', now 'built-in'). + * Otherwise, {@link BuiltInNodeMigration} will show up. + */ + // See #readResolve for null -> true transition and #save for null -> false transition + @Restricted(NoExternalUse.class) + /* package-private */ Boolean nodeRenameMigrationNeeded; + /** * HTTP proxy configuration. */ @@ -905,12 +913,6 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } // doing this early allows InitStrategy to set environment upfront - //Telemetry: add interceptor classloader - //These lines allow the catcher to be present on Thread.currentThread().getContextClassLoader() in every plugin which - //allow us to detect failures in every plugin loading classes by this way. - if (MissingClassTelemetry.enabled() && !(Thread.currentThread().getContextClassLoader() instanceof CatcherClassLoader)) { - Thread.currentThread().setContextClassLoader(new CatcherClassLoader(Thread.currentThread().getContextClassLoader())); - } final InitStrategy is = InitStrategy.get(Thread.currentThread().getContextClassLoader()); Trigger.timer = new java.util.Timer("Jenkins cron thread"); @@ -951,20 +953,8 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve pluginManager = PluginManager.createDefault(this); this.pluginManager = pluginManager; WebApp webApp = WebApp.get(servletContext); - - //Telemetry: add interceptor classloader - //These lines allows the catcher to be present on Thread.currentThread().getContextClassLoader() in every plugin which - //allow us to detect failures in every plugin loading classes by this way. // JSON binding needs to be able to see all the classes from all the plugins - - ClassLoader classLoaderToAssign; - if (MissingClassTelemetry.enabled() && !(pluginManager.uberClassLoader instanceof CatcherClassLoader)) { - classLoaderToAssign = new CatcherClassLoader(pluginManager.uberClassLoader); - } else { - classLoaderToAssign = pluginManager.uberClassLoader; - } - webApp.setClassLoader(classLoaderToAssign); - + webApp.setClassLoader(pluginManager.uberClassLoader); webApp.setJsonInErrorMessageSanitizer(RedactSecretJsonInErrorMessageSanitizer.INSTANCE); TypedFilter typedFilter = new TypedFilter(); @@ -980,10 +970,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve webApp.setDispatchValidator(new StaplerDispatchValidator()); webApp.setFilteredDispatchTriggerListener(actionListener); - //Telemetry: add interceptor classloader - //These lines allows the catcher to be present on Thread.currentThread().getContextClassLoader() in every plugin which - //allow us to detect failures in every plugin loading classes at this way. - adjuncts = new AdjunctManager(servletContext, classLoaderToAssign, "adjuncts/" + SESSION_HASH, TimeUnit.DAYS.toMillis(365)); + adjuncts = new AdjunctManager(servletContext, pluginManager.uberClassLoader, "adjuncts/" + SESSION_HASH, TimeUnit.DAYS.toMillis(365)); ClassFilterImpl.register(); @@ -1031,7 +1018,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } catch (Exception e) { // Per Javadoc log exceptions but still go online. // NOTE: this does not include Errors, which indicate a fatal problem - LOGGER.log(WARNING, String.format("Exception in onOnline() for the computer listener %s on the Jenkins master node", + LOGGER.log(WARNING, String.format("Exception in onOnline() for the computer listener %s on the built-in node", cl.getClass()), e); } } @@ -1082,6 +1069,12 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve // no longer persisted installStateName = null; + + if (nodeRenameMigrationNeeded == null) { + /* deserializing without a value set means we need to migrate */ + nodeRenameMigrationNeeded = true; + } + return this; } @@ -2037,7 +2030,8 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve @CLIResolver public @CheckForNull Computer getComputer(@Argument(required=true,metaVar="NAME",usage="Node name") @NonNull String name) { - if(name.equals("(master)")) + if(name.equals("(built-in)") + || name.equals("(master)")) // backwards compatibility for URLs name = ""; for (Computer c : computers.values()) { @@ -2180,7 +2174,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve /** * Returns all {@link Node}s in the system, excluding {@link Jenkins} instance itself which - * represents the master. + * represents the built-in node (in other words, this only returns agents). */ @Override @NonNull @@ -3213,9 +3207,29 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve @Override public LabelAtom getSelfLabel() { + if (nodeNameAndSelfLabelOverride != null) { + return getLabelAtom(nodeNameAndSelfLabelOverride); + } + if (getRenameMigrationDone()) { + return getLabelAtom("built-in"); + } return getLabelAtom("master"); } + /* package */ boolean getRenameMigrationDone() { + if (nodeRenameMigrationNeeded == null) { + /* This is exceptionally unlikely to occur since we replace 'null' with 'true' on save */ + return true; + } + return !nodeRenameMigrationNeeded; + } + + /* package */ void performRenameMigration() throws IOException { + this.nodeRenameMigrationNeeded = false; + this.save(); + this.trimLabels(); + } + @Override @NonNull public Computer createComputer() { @@ -3471,6 +3485,14 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve LOGGER.log(FINE, "refusing to set version {0} to {1} during {2}", new Object[] {version, VERSION, currentMilestone}); } + if (nodeRenameMigrationNeeded == null) { + /* + If we initialized this object bypassing #readResolve, i.e. a new instance, + we need to persist this value, otherwise on restart we'd flag this as migration needed. + */ + nodeRenameMigrationNeeded = false; + } + getConfigFile().write(this); SaveableListener.fireOnChange(this, getConfigFile()); } @@ -4066,7 +4088,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve } } if (toComputer() == null) { - future.put("master", RemotingDiagnostics.getThreadDumpAsync(FilePath.localChannel)); + future.put("master", RemotingDiagnostics.getThreadDumpAsync(FilePath.localChannel)); // TODO(terminology) Built-in node? Controller? How is this used? } // if the result isn't available in 5 sec, ignore that. @@ -4412,7 +4434,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve private static Lifecycle restartableLifecycle() throws RestartNotSupportedException { if (Main.isUnitTest) { - throw new RestartNotSupportedException("Restarting the master JVM is not supported in JenkinsRule-based tests"); + throw new RestartNotSupportedException("Restarting the controller JVM is not supported in JenkinsRule-based tests"); } Lifecycle lifecycle = Lifecycle.get(); lifecycle.verifyRestartable(); @@ -5089,7 +5111,7 @@ public class Jenkins extends AbstractCIBase implements DirectlyModifiableTopLeve @Override public String getUrl() { - return "computer/(master)/"; + return "computer/(built-in)/"; } @Override diff --git a/core/src/main/java/jenkins/model/MasterBuildConfiguration.java b/core/src/main/java/jenkins/model/MasterBuildConfiguration.java index 0916394043..b7a5c66b8c 100644 --- a/core/src/main/java/jenkins/model/MasterBuildConfiguration.java +++ b/core/src/main/java/jenkins/model/MasterBuildConfiguration.java @@ -36,7 +36,7 @@ import java.io.IOException; * * @author Kohsuke Kawaguchi */ -@Extension(ordinal=500) @Symbol("masterBuild") +@Extension(ordinal=500) @Symbol({"builtInNode", "masterBuild"}) public class MasterBuildConfiguration extends GlobalConfiguration { public int getNumExecutors() { return Jenkins.get().getNumExecutors(); @@ -57,8 +57,8 @@ public class MasterBuildConfiguration extends GlobalConfiguration { } j.setNumExecutors(json.getInt("numExecutors")); - if (req.hasParameter("master.mode")) - j.setMode(Mode.valueOf(req.getParameter("master.mode"))); + if (req.hasParameter("builtin.mode")) + j.setMode(Mode.valueOf(req.getParameter("builtin.mode"))); else j.setMode(Mode.NORMAL); diff --git a/core/src/main/java/jenkins/model/identity/IdentityRootAction.java b/core/src/main/java/jenkins/model/identity/IdentityRootAction.java index 50a0862548..fdfee1cc79 100644 --- a/core/src/main/java/jenkins/model/identity/IdentityRootAction.java +++ b/core/src/main/java/jenkins/model/identity/IdentityRootAction.java @@ -52,7 +52,7 @@ public class IdentityRootAction implements UnprotectedRootAction { buf.append(new String(encoded, index, len, StandardCharsets.UTF_8)); index += len; } - return String.format("-----BEGIN PUBLIC KEY-----%n%s%n-----END PUBLIC KEY-----%n", buf.toString()); + return String.format("-----BEGIN PUBLIC KEY-----%n%s%n-----END PUBLIC KEY-----%n", buf); } /** diff --git a/core/src/main/java/jenkins/monitor/JavaVersionRecommendationAdminMonitor.java b/core/src/main/java/jenkins/monitor/JavaVersionRecommendationAdminMonitor.java index 33adc87e55..c328705386 100644 --- a/core/src/main/java/jenkins/monitor/JavaVersionRecommendationAdminMonitor.java +++ b/core/src/main/java/jenkins/monitor/JavaVersionRecommendationAdminMonitor.java @@ -28,6 +28,7 @@ import hudson.Extension; import hudson.model.AdministrativeMonitor; import hudson.security.Permission; import jenkins.model.Jenkins; +import jenkins.util.SystemProperties; import jenkins.util.java.JavaUtils; import org.jenkinsci.Symbol; import org.kohsuke.accmod.Restricted; @@ -46,9 +47,11 @@ import java.io.IOException; @Symbol("javaVersionRecommendation") public class JavaVersionRecommendationAdminMonitor extends AdministrativeMonitor { + private static Boolean disabled = SystemProperties.getBoolean(JavaVersionRecommendationAdminMonitor.class.getName() + ".disabled", false); + @Override public boolean isActivated() { - return JavaUtils.isRunningWithJava8OrBelow(); + return !disabled && JavaUtils.isRunningWithJava8OrBelow(); } @Override diff --git a/core/src/main/java/jenkins/security/ResourceDomainRecommendation.java b/core/src/main/java/jenkins/security/ResourceDomainRecommendation.java index 30b2c2467d..1826a77c4b 100644 --- a/core/src/main/java/jenkins/security/ResourceDomainRecommendation.java +++ b/core/src/main/java/jenkins/security/ResourceDomainRecommendation.java @@ -80,4 +80,9 @@ public class ResourceDomainRecommendation extends AdministrativeMonitor { public Permission getRequiredPermission() { return Jenkins.SYSTEM_READ; } + + @Override + public boolean isSecurity() { + return true; + } } diff --git a/core/src/main/java/jenkins/security/s2m/AdminCallableMonitor.java b/core/src/main/java/jenkins/security/s2m/AdminCallableMonitor.java index 921ffa0db5..c0d3db7f7d 100644 --- a/core/src/main/java/jenkins/security/s2m/AdminCallableMonitor.java +++ b/core/src/main/java/jenkins/security/s2m/AdminCallableMonitor.java @@ -21,7 +21,7 @@ import java.io.IOException; * @since 1.587 / 1.580.1 * @author Kohsuke Kawaguchi */ -@Extension @Symbol("slaveToMasterAccessControl") +@Extension @Symbol({"agentToControllerAccessControl", "slaveToMasterAccessControl"}) public class AdminCallableMonitor extends AdministrativeMonitor { @Inject Jenkins jenkins; @@ -30,7 +30,7 @@ public class AdminCallableMonitor extends AdministrativeMonitor { AdminWhitelistRule rule; public AdminCallableMonitor() { - super("slaveToMasterAccessControl"); + super("slaveToMasterAccessControl"); // TODO Can we change this while retaining compatibility? } @Override diff --git a/core/src/main/java/jenkins/security/s2m/CallableDirectionChecker.java b/core/src/main/java/jenkins/security/s2m/CallableDirectionChecker.java index 546f398e69..8712737308 100644 --- a/core/src/main/java/jenkins/security/s2m/CallableDirectionChecker.java +++ b/core/src/main/java/jenkins/security/s2m/CallableDirectionChecker.java @@ -52,17 +52,17 @@ public class CallableDirectionChecker extends RoleChecker { final String name = subject.getClass().getName(); if (expected.contains(Roles.MASTER)) { - LOGGER.log(Level.FINE, "Executing {0} is allowed since it is targeted for the master role", name); + LOGGER.log(Level.FINE, "Executing {0} is allowed since it is targeted for the controller role", name); return; // known to be safe } if (isWhitelisted(subject,expected)) { // this subject is dubious, but we are letting it through as per whitelisting - LOGGER.log(Level.FINE, "Explicitly allowing {0} to be sent from agent to master", name); + LOGGER.log(Level.FINE, "Explicitly allowing {0} to be sent from agent to controller", name); return; } - throw new SecurityException("Sending " + name + " from agent to master is prohibited.\nSee https://www.jenkins.io/redirect/security-144 for more details"); + throw new SecurityException("Sending " + name + " from agent to controller is prohibited.\nSee https://www.jenkins.io/redirect/security-144 for more details"); } /** diff --git a/core/src/main/java/jenkins/security/s2m/MasterKillSwitchConfiguration.java b/core/src/main/java/jenkins/security/s2m/MasterKillSwitchConfiguration.java index 3e69570589..ddfb774226 100644 --- a/core/src/main/java/jenkins/security/s2m/MasterKillSwitchConfiguration.java +++ b/core/src/main/java/jenkins/security/s2m/MasterKillSwitchConfiguration.java @@ -11,7 +11,7 @@ import net.sf.json.JSONObject; import org.kohsuke.stapler.StaplerRequest; /** - * Exposes {@link AdminWhitelistRule#masterKillSwitch} to the admin. + * Exposes {@code AdminWhitelistRule#masterKillSwitch} to the admin. * * @author Kohsuke Kawaguchi * @since 1.587 / 1.580.1 @@ -38,7 +38,7 @@ public class MasterKillSwitchConfiguration extends GlobalConfiguration { if (isRelevant()) { // don't record on/off unless this becomes relevant, so that we can differentiate // those who have disabled vs those who haven't cared. - rule.setMasterKillSwitch(!json.has("masterToSlaveAccessControl")); + rule.setMasterKillSwitch(!json.has("agentToControllerAccessControl")); } return true; } diff --git a/core/src/main/java/jenkins/slaves/DefaultJnlpSlaveReceiver.java b/core/src/main/java/jenkins/slaves/DefaultJnlpSlaveReceiver.java index 0da6efa0e6..7b22dc27aa 100644 --- a/core/src/main/java/jenkins/slaves/DefaultJnlpSlaveReceiver.java +++ b/core/src/main/java/jenkins/slaves/DefaultJnlpSlaveReceiver.java @@ -137,7 +137,7 @@ public class DefaultJnlpSlaveReceiver extends JnlpAgentReceiver { } } else { event.reject(new ConnectionRefusalException(String.format( - "%s is already connected to this master. Rejecting this connection.", clientName))); + "%s is already connected to this controller. Rejecting this connection.", clientName))); return; } } diff --git a/core/src/main/java/jenkins/telemetry/impl/java11/CatcherClassLoader.java b/core/src/main/java/jenkins/telemetry/impl/java11/CatcherClassLoader.java deleted file mode 100644 index 8a1c962f79..0000000000 --- a/core/src/main/java/jenkins/telemetry/impl/java11/CatcherClassLoader.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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.telemetry.impl.java11; - -import org.kohsuke.accmod.Restricted; -import org.kohsuke.accmod.restrictions.NoExternalUse; - -@Restricted(NoExternalUse.class) -public class CatcherClassLoader extends ClassLoader { - - public CatcherClassLoader(ClassLoader parent) { - super(parent); - } - - - /** - * Usually, the {@link ClassLoader} calls its parent and finally this method. So if we are here, it's the last - * element of the chain. It doesn't happen in {@link jenkins.util.AntClassLoader} so it has an special management - * on {@link hudson.ClassicPluginStrategy} - * - * - */ - @Override - protected Class findClass(String name) throws ClassNotFoundException { - ClassNotFoundException e = new ClassNotFoundException(name); - MissingClassTelemetry.reportException(name, e); - throw e; - } -} diff --git a/core/src/main/java/jenkins/telemetry/impl/java11/MissingClassEvent.java b/core/src/main/java/jenkins/telemetry/impl/java11/MissingClassEvent.java deleted file mode 100644 index ab13224f97..0000000000 --- a/core/src/main/java/jenkins/telemetry/impl/java11/MissingClassEvent.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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.telemetry.impl.java11; - -import edu.umd.cs.findbugs.annotations.NonNull; -import java.io.PrintWriter; -import java.io.StringWriter; - -/** - * Store an event regarding missing classes. We can already catch ClassNotFoundException and NoClassDefFoundError - */ -class MissingClassEvent { - private String time; - private long occurrences; - private String stackTrace; - private String className; - - String getStackTrace() { - return stackTrace; - } - - void setStackTrace(String stackTrace) { - this.stackTrace = stackTrace; - } - - String getClassName() { - return className; - } - - void setClassName(String className) { - this.className = className; - } - - MissingClassEvent(@NonNull String name, @NonNull Throwable t) { - this.className = name; - - StringWriter stackTrace = new StringWriter(); - t.printStackTrace(new PrintWriter(stackTrace)); - this.stackTrace = stackTrace.toString(); - - this.time = MissingClassTelemetry.clientDateString(); - this.occurrences = 1; - } - - String getTime() { - return time; - } - - long getOccurrences() { - return occurrences; - } - - void setOccurrences(long occurrences) { - this.occurrences = occurrences; - } - - void setTime(String time) { - this.time = time; - } - - @Override - public String toString() { - return "MissingClassEvent{" + - "time='" + time + '\'' + - ", occurrences=" + occurrences + - ", stackTrace='" + stackTrace + '\'' + - ", className='" + className + '\'' + - '}'; - } -} diff --git a/core/src/main/java/jenkins/telemetry/impl/java11/MissingClassEvents.java b/core/src/main/java/jenkins/telemetry/impl/java11/MissingClassEvents.java deleted file mode 100644 index 59d7ba6e47..0000000000 --- a/core/src/main/java/jenkins/telemetry/impl/java11/MissingClassEvents.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * 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.telemetry.impl.java11; - -import com.google.common.annotations.VisibleForTesting; - -import edu.umd.cs.findbugs.annotations.NonNull; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicLong; - -public class MissingClassEvents { - - /** - * Only 100 exceptions a day (period of telemetry) - */ - @VisibleForTesting - /* package */ static /* final */ int MAX_EVENTS_PER_SEND = 100; - - /** - * List of events, one per stack trace, to send to Telemetry. Only the first {@code #MAX_EVENTS_PER_SEND} are sent. - */ - private ConcurrentHashMap, MissingClassEvent> events = new ConcurrentHashMap<>(MAX_EVENTS_PER_SEND); - - /** - * List of all events registered on this execution, to avoid printing an event more than once in the log. This map - * is not limited. On every Jenkins restart is cleaned because it's not persisted, so the CNFE is printed again. The - * key is the class name not found to quickly look for it on every CNFE thrown. - */ - private ConcurrentHashMap eventsOnThisExecution = new ConcurrentHashMap<>(MAX_EVENTS_PER_SEND); - /** - * Add a new exception to the store. If the same exception already exists, it increases the occurrences. If we - * already get the maximum number of exceptions, it doesn't add any value. - * @param name name of the class not found - * @param t the exception to store - * @return the occurrences stored for this throwable. 1 the fist time it's stored. > 1 for successive stores of the - * same stack trace. 0 if we already stored MAX_EVENTS_PER_SEND (100) events for a single send. - */ - public long put(String name, @NonNull Throwable t) { - // A final object to pass it to the function - final AtomicLong occurrences = new AtomicLong(); - - // We need the key (the stack trace) to be a list and unmodifiable - List key = Collections.unmodifiableList(Arrays.asList(t.getStackTrace())); - - final MissingClassEvent newEvent = new MissingClassEvent(name, t); - events.compute(key, (stackTraceElements, missingClassEvent) -> { - - if (missingClassEvent == null) { - // It's a new element, the size will increase - if (events.size() < MAX_EVENTS_PER_SEND) { - // Create the new value - occurrences.set(1); - return newEvent; - } else { - return null; - } - } else { - // We update the occurrences and the last time it happened - occurrences.set(missingClassEvent.getOccurrences()); - missingClassEvent.setOccurrences(occurrences.incrementAndGet()); - missingClassEvent.setTime(MissingClassTelemetry.clientDateString()); - return missingClassEvent; - } - }); - - // We add the event to the list of already printed events. We used the name of the missing class instead of the - // full stack trace as a key to avoid filling the log with CNFE talking about the same class even though the - // stack traces are different. Worse scenario, if we don't put the exception on the IGNORED_PLACES correctly, - // the administrator will see the message again and we will be able to add the new one to the IGNORED_PLACES. - // In addition, the event is also sent to telemetry. - eventsOnThisExecution.putIfAbsent(name, newEvent); - return occurrences.get(); - } - - /** - * Reinitialize the events happened and return the number of events stored since last execution of this method. - * Used to send via telemetry the events and restart the events store. - * @return the number of events stored since previous call to this method. - */ - - @VisibleForTesting - /* package */ synchronized @NonNull ConcurrentHashMap, MissingClassEvent> getEventsAndClean() { - ConcurrentHashMap, MissingClassEvent> currentEvents = events; - events = new ConcurrentHashMap<>(MAX_EVENTS_PER_SEND); - return currentEvents; - } - - /** - * Returns true if the class name was already registered previously, during the current execution of this Jenkins - * instance. - * @param className the class name to check - * @return true if it was already registered - */ - public boolean alreadyRegistered(@NonNull String className) { - return eventsOnThisExecution.containsKey(className); - } - - // To clean on every test execution - void clearEventsOnThisExecution() { - eventsOnThisExecution.clear(); - } - - @Override - public String toString() { - return "MissingClassEvents{" + - "events=" + events + - '}'; - } -} diff --git a/core/src/main/java/jenkins/telemetry/impl/java11/MissingClassTelemetry.java b/core/src/main/java/jenkins/telemetry/impl/java11/MissingClassTelemetry.java deleted file mode 100644 index 4b66804793..0000000000 --- a/core/src/main/java/jenkins/telemetry/impl/java11/MissingClassTelemetry.java +++ /dev/null @@ -1,382 +0,0 @@ -/* - * 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.telemetry.impl.java11; - -import com.google.common.annotations.VisibleForTesting; -import hudson.Extension; -import hudson.util.VersionNumber; -import io.jenkins.lib.versionnumber.JavaSpecificationVersion; -import jenkins.model.Jenkins; -import jenkins.telemetry.Telemetry; -import jenkins.util.java.JavaUtils; -import net.sf.json.JSONArray; -import net.sf.json.JSONObject; -import org.kohsuke.accmod.Restricted; -import org.kohsuke.accmod.restrictions.NoExternalUse; - -import edu.umd.cs.findbugs.annotations.CheckForNull; -import edu.umd.cs.findbugs.annotations.NonNull; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.time.LocalDate; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Set; -import java.util.TimeZone; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Telemetry class to gather information about missing classes when running on java 11. This class sends classes not - * found and in packages related with Java changes from Java 8 to Java 11. See {@link #MOVED_PACKAGES}. - **/ - -@Extension -@Restricted(NoExternalUse.class) -public class MissingClassTelemetry extends Telemetry { - private static final Logger LOGGER = Logger.getLogger(MissingClassTelemetry.class.getName()); - - // Store 100 events today - private static MissingClassEvents events = new MissingClassEvents(); - - // When we begin to gather these data - private static final LocalDate START = LocalDate.of(2019, 4, 1); - // Gather for 2 years (who knows how long people will need to migrate to Java 11) - private static final LocalDate END = START.plusMonths(24); - - // The types of exceptions which can be reported - private static final Set reportableExceptions = - new HashSet(Arrays.asList(ClassNotFoundException.class, NoClassDefFoundError.class)); - - @VisibleForTesting - /* package */ static final String CIRCULAR_REFERENCE = "Circular reference found on the exception we are analysing to report via telemetry"; - - /** - * Packages removed from java8 up to java11 - * https://blog.codefx.org/java/java-11-migration-guide/ - */ - private static final String[] MOVED_PACKAGES = new String[] {"javax.activation", "javax.annotation", "javax.jws", - "javax.rmi", "javax.transaction", "javax.xml.bind", "javax.xml.soap", "javax.xml.ws", "org.omg", - "javax.activity", "com.sun", "sun"}; - - /** - * Places where a ClassNotFoundException is going to be thrown but it's ignored later in the code, so we - * don't have to send this exception, even though it might be related with java classes of moved packages - */ - private static String[][] IGNORED_PLACES = { - {"hudson.util.XStream2$AssociatedConverterImpl", "findConverter"}, - {"org.jenkinsci.plugins.workflow.cps.global.GrapeHack", "hack"}, - {"org.codehaus.groovy.runtime.callsite.CallSiteArray", "createCallStaticSite"}, - {"groovy.lang.MetaClassImpl", "addProperties"}, - // We set the reportException call directly in this method when it's appropriated - {"hudson.PluginManager.UberClassLoader", "findClass"}, - {"hudson.ExtensionFinder$GuiceFinder$FaultTolerantScope$1", "get"}, - {"hudson.ExtensionFinder$GuiceFinder$SezpozModule", "resolve"}, - {"java.beans.Introspector", "findCustomizerClass"}, - {"com.sun.beans.finder.InstanceFinder", "instantiate"}, - {"com.sun.beans.finder.ClassFinder", "findClass"}, - {"java.util.ResourceBundle$Control", "newBundle"}, - //hundreds when a job is created - {"org.codehaus.groovy.control.ClassNodeResolver", "tryAsLoaderClassOrScript"}, - {"org.kohsuke.stapler.RequestImpl$TypePair", "convertJSON"}, - {"net.bull.javamelody.FilterContext", "isMojarraAvailable"}, // JENKINS-60725 - {"hudson.remoting.RemoteClassLoader$ClassLoaderProxy", "fetch3"}, // JENKINS-61521 - //Don't add "java.base/" before sun.reflect.generics.factory.CoreReflectionFactory - {"sun.reflect.generics.factory.CoreReflectionFactory", "makeNamedType"}, // JENKINS-61920 - - }; - - @NonNull - @Override - public String getDisplayName() { - return "Missing classes related with Java updates"; - } - - @NonNull - @Override - public LocalDate getStart() { - return START; - } - - @NonNull - @Override - public LocalDate getEnd() { - return END; - } - - /** - * To allow asserting this info in tests. - * @return the events gathered. - */ - @VisibleForTesting - /* package */ static MissingClassEvents getEvents() { - return events; - } - - /** - * This telemetry is only enabled when running on Java versions newer than Java 8. - * @return true if running on a newer Java version than Java 8 - */ - public static boolean enabled() { - return JavaUtils.getCurrentJavaRuntimeVersionNumber().isNewerThan(JavaSpecificationVersion.JAVA_8); - } - - @CheckForNull - @Override - public JSONObject createContent() { - // If we are on the time window of this telemetry (checked by the Telemetry class) but we are not running on - // Java > 1.8 (checked here), we don't send anything - if (!enabled()) { - return null; - } - - // To avoid sending empty events - JSONArray events = formatEventsAndInitialize(); - if (events.size() == 0) { - return null; - } - - JSONObject info = new JSONObject(); - VersionNumber jenkinsVersion = Jenkins.getVersion(); - info.put("core", jenkinsVersion != null ? jenkinsVersion.toString() : "UNKNOWN"); - info.put("clientDate", clientDateString()); - info.put("classMissingEvents", events); - - return JSONObject.fromObject(info); - } - - /** - * Returns the events gathered as a Map ready to use in a Json object to send via telemetry and clean the map to - * gather another window of events. - * @return the map of missed classes events gathered along this window of telemetry - */ - @NonNull - private JSONArray formatEventsAndInitialize() { - // Save the current events and clean for next (not this one) telemetry send - ConcurrentHashMap, MissingClassEvent> toReport = MissingClassTelemetry.events.getEventsAndClean(); - if (LOGGER.isLoggable(Level.FINE)) { - LOGGER.fine("Cleaned events for missing classes"); - } - - return formatEvents(toReport); - } - - /** - * Format the events gathered in a map used to create the json object to send via telemetry. The events are named by - * the class not found. But a class could be repeated if it was thrown from several places. The interesting - * pieces of information we want to gather are the places where the {@link ClassNotFoundException} or the - * {@link NoClassDefFoundError} errors happens, rather than the class itself. - * @param events events collected in this telemetry window. - * @return the events formatted in a map. - */ - @NonNull - private JSONArray formatEvents(@NonNull ConcurrentHashMap, MissingClassEvent> events) { - JSONArray jsonEvents = new JSONArray(); - - events.forEach((stackTrace, event) -> { - JSONObject eventObject = new JSONObject(); - eventObject.put("className", event.getClassName()); - eventObject.put("class", event.getClassName()); - eventObject.put("time", event.getTime()); - eventObject.put("occurrences", Long.toString(event.getOccurrences())); - eventObject.put("stacktrace", event.getStackTrace()); - - jsonEvents.add(eventObject); - }); - - return jsonEvents; - } - - /** - * The current time in the same way as other telemetry implementations. - * @return the UTC time formatted with the pattern yyyy-MM-dd'T'HH:mm'Z' - */ - @NonNull - static String clientDateString() { - TimeZone tz = TimeZone.getTimeZone("UTC"); - DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'"); - df.setTimeZone(tz); // strip timezone - return df.format(new Date()); - } - - /** - * Store the exception if it's from a split package of Java. This method report this exception directly, it doesn't - * look into the causes or suppressed exceptions of the exception specified. This method tends to be used in the - * ClassLoader directly. Outside the class loaders is best to use {@link #reportExceptionInside(Throwable)} - * @param name the name of the class - * @param e the throwable to report if needed - */ - public static void reportException(@NonNull String name, @NonNull Throwable e) { - if (enabled()) { - //ClassDefFoundError uses / instead of . - name = name.replace('/', '.').trim(); - - // We call the methods in this order because if the missing class is not java related, we don't loop over the - // stack trace to look if it's not thrown from an ignored place avoiding an impact on performance. - if (isFromMovedPackage(name) && !calledFromIgnoredPlace(e)) { - if (LOGGER.isLoggable(Level.WARNING) && !wasAlreadyReported(name)) { - LOGGER.log(Level.WARNING, "Added a missed class for missing class telemetry. Class: " + name, e); - } - events.put(name, e); - } - } - } - - private static boolean wasAlreadyReported(@NonNull String className) { - return events.alreadyRegistered(className); - } - - /** - * Determine if the exception specified was thrown from an ignored place - * @param throwable The exception thrown - * @return true if in the stack trace there is an ignored method / class. - */ - private static boolean calledFromIgnoredPlace(@NonNull Throwable throwable) { - for(String[] ignoredPlace : IGNORED_PLACES) { - if (calledFrom(throwable, ignoredPlace[0], ignoredPlace[1])) { - return true; - } - } - return false; - } - - /** - * Check if the throwable was thrown by the class and the method specified. - * @param throwable stack trace to look at - * @param clazz class to look for in the stack trace - * @param method method where the throwable was thrown in the clazz - * @return true if the method of the clazz has thrown the throwable - */ - private static boolean calledFrom (@NonNull Throwable throwable, @NonNull String clazz, @NonNull String method){ - StackTraceElement[] trace = throwable.getStackTrace(); - for (StackTraceElement el : trace) { - //If the exception has the class and method searched, it's called from there - if (clazz.equals(el.getClassName()) && el.getMethodName().equals(method)) { - return true; - } - } - return false; - } - - /** - * Store the exception extracting the class name from the message of the throwable specified. This method report - * this exception directly, it doesn't look into the causes or suppressed exceptions of the exception specified. - * This method tends to be used in the ClassLoader directly. Outside the class loaders is best to use - * {@link #reportExceptionInside(Throwable)} - * @param e the exception to report if needed - */ - private static void reportException(@NonNull Throwable e) { - if (enabled()) { - String name = e.getMessage(); - - if (name == null || name.trim().isEmpty()) { - LOGGER.log(Level.INFO, "No class name could be extracted from the throwable to determine if it's reportable", e); - } else { - reportException(name, e); - } - } - } - - private static boolean isFromMovedPackage(@NonNull String clazz) { - for (String movedPackage : MOVED_PACKAGES) { - if (clazz.startsWith(movedPackage)) { - return true; - } - } - return false; - } - - /** - * Report the class not found if this exception or any of its causes or suppressed exceptions is related to missed - * classes. - * @param e the exception to look into - */ - public static void reportExceptionInside(@NonNull Throwable e) { - if (enabled()) { - // Use a Set with equity based on == instead of equal to find cycles - Set exceptionsReviewed = Collections.newSetFromMap(new IdentityHashMap<>()); - reportExceptionInside(e, exceptionsReviewed); - } - } - - /** - * Find the exception to report among the exception passed and its causes and suppressed exceptions. It does a - * recursion and uses a Set to avoid circular references. - * @param e the exception - * @param exceptionsReviewed the set of already reviewed exceptions - * @return true if a exception was reported - */ - private static boolean reportExceptionInside(@NonNull Throwable e, @NonNull Set exceptionsReviewed) { - if (exceptionsReviewed.contains(e)) { - LOGGER.log(Level.WARNING, CIRCULAR_REFERENCE, e); - // Don't go deeper, we already did - return false; - } - - // Add this exception to the list of already reviewed exceptions before going deeper in its causes or suppressed - // exceptions - exceptionsReviewed.add(e); - - // It this exception is the one searched - if (isMissedClassRelatedException(e)) { - MissingClassTelemetry.reportException(e); - return true; - } - - // We search in its cause exception - if (e.getCause() != null) { - if (reportExceptionInside(e.getCause(), exceptionsReviewed)) { - return true; - } - } - - // We search in its suppressed exceptions - for (Throwable suppressed: e.getSuppressed()) { - if (suppressed != null) { - if (reportExceptionInside(suppressed, exceptionsReviewed)) { - return true; - } - } - } - - // If this exception or its ancestors are not related with missed classes - return false; - } - - /** - * Check if the exception specified is related with a missed class, that is, defined in the - * {@link #reportableExceptions} method. - * @param e the exception to look into - * @return true if the class is related with missed classes. - */ - private static boolean isMissedClassRelatedException(Throwable e) { - return reportableExceptions.contains(e.getClass()); - } -} diff --git a/core/src/main/java/jenkins/util/AntClassLoader.java b/core/src/main/java/jenkins/util/AntClassLoader.java index db8ef62436..5f144f1e87 100644 --- a/core/src/main/java/jenkins/util/AntClassLoader.java +++ b/core/src/main/java/jenkins/util/AntClassLoader.java @@ -6,7 +6,7 @@ * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -17,24 +17,25 @@ */ package jenkins.util; -import jenkins.telemetry.impl.java11.MissingClassTelemetry; import org.apache.tools.ant.BuildEvent; import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.MagicNames; import org.apache.tools.ant.Project; import org.apache.tools.ant.SubBuildListener; import org.apache.tools.ant.launch.Locator; import org.apache.tools.ant.types.Path; -import org.apache.tools.ant.util.CollectionUtils; import org.apache.tools.ant.util.FileUtils; 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.StringUtils; +import org.apache.tools.ant.util.VectorSet; +import org.apache.tools.zip.ZipLong; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; -import edu.umd.cs.findbugs.annotations.CheckForNull; -import edu.umd.cs.findbugs.annotations.NonNull; import java.io.ByteArrayOutputStream; +import java.io.Closeable; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -45,13 +46,14 @@ import java.nio.file.Files; import java.security.CodeSource; import java.security.ProtectionDomain; import java.security.cert.Certificate; -import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.StringTokenizer; import java.util.Vector; import java.util.jar.Attributes; @@ -59,6 +61,9 @@ import java.util.jar.Attributes.Name; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.jar.Manifest; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.ZipFile; /** * Used to load classes within ant with a different classpath from @@ -78,10 +83,35 @@ import java.util.jar.Manifest; * */ @Restricted(NoExternalUse.class) -public class AntClassLoader extends ClassLoader implements SubBuildListener { +public class AntClassLoader extends ClassLoader implements SubBuildListener, Closeable { private static final FileUtils FILE_UTILS = FileUtils.getFileUtils(); + private static final boolean IS_ATLEAST_JAVA9 = JavaEnvUtils.isAtLeastJavaVersion(JavaEnvUtils.JAVA_9); + // constructs needed to create (via reflection) a java.util.jar.JarFile instance when Java runtime version is >= 9 + private static final Class[] MR_JARFILE_CTOR_ARGS; + private static final Object MR_JARFILE_CTOR_RUNTIME_VERSION_VAL; + + static { + registerAsParallelCapable(); + if (IS_ATLEAST_JAVA9) { + Class[] ctorArgs = null; + Object runtimeVersionVal = null; + try { + final Class runtimeVersionClass = Class.forName("java.lang.Runtime$Version"); + ctorArgs = new Class[] {File.class, boolean.class, int.class, runtimeVersionClass}; + runtimeVersionVal = Runtime.class.getDeclaredMethod("version").invoke(null); + } catch (Exception e) { + // ignore - we consider this as multi-release jar unsupported + } + MR_JARFILE_CTOR_ARGS = ctorArgs; + MR_JARFILE_CTOR_RUNTIME_VERSION_VAL = runtimeVersionVal; + } else { + MR_JARFILE_CTOR_ARGS = null; + MR_JARFILE_CTOR_RUNTIME_VERSION_VAL = null; + } + } + /** * An enumeration of all resources of a given name found within the * classpath of this class loader. This enumeration is used by the @@ -91,11 +121,11 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @see AntClassLoader#findResources(String) * @see java.lang.ClassLoader#getResources(String) */ - private class ResourceEnumeration implements Enumeration { + private class ResourceEnumeration implements Enumeration { /** * The name of the resource being searched for. */ - private String resourceName; + private final String resourceName; /** * The index of the next classpath element to search. @@ -115,7 +145,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * * @param name the name of the resource to search for. */ - ResourceEnumeration(String name) { + ResourceEnumeration(final String name) { this.resourceName = name; this.pathElementsIndex = 0; findNextResource(); @@ -139,8 +169,8 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @return the next resource in the enumeration */ @Override - public Object nextElement() { - URL ret = this.nextResource; + public URL nextElement() { + final URL ret = this.nextResource; if (ret == null) { throw new NoSuchElementException(); } @@ -158,10 +188,10 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { URL url = null; while (pathElementsIndex < pathComponents.size() && url == null) { try { - File pathComponent = pathComponents.get(pathElementsIndex); + final File pathComponent = pathComponents.elementAt(pathElementsIndex); url = getResourceURL(pathComponent, this.resourceName); pathElementsIndex++; - } catch (BuildException e) { + } catch (final BuildException e) { // ignore path elements which are not valid relative to the // project } @@ -184,7 +214,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * The components of the classpath that the classloader searches * for classes. */ - private ArrayList pathComponents = new ArrayList<>(); + private final Vector pathComponents = new VectorSet<>(); /** * The project to which this class loader belongs. @@ -202,14 +232,14 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * loader regardless of whether the parent class loader is being searched * first or not. */ - private Vector systemPackages = new Vector(); + private final Vector systemPackages = new Vector<>(); /** * These are the package roots that are to be loaded by this class loader * regardless of whether the parent class loader is being searched first * or not. */ - private Vector loaderPackages = new Vector(); + private final Vector loaderPackages = new Vector<>(); /** * Whether or not this classloader will ignore the base @@ -227,10 +257,11 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { /** * A hashtable of zip files opened by the classloader (File to JarFile). */ - private Hashtable jarFiles = new Hashtable(); + private Hashtable jarFiles = new Hashtable<>(); /** Static map of jar file/time to manifest class-path entries */ - private static Map/**/ pathMap = Collections.synchronizedMap(new HashMap()); + private static Map pathMap = + Collections.synchronizedMap(new HashMap<>()); /** * The context loader saved when setting the thread's current @@ -252,8 +283,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * belong. * @param classpath The classpath to use to load classes. */ - public AntClassLoader(ClassLoader parent, Project project, Path classpath) { - super(parent); // KK patch for JENKINS-21579 + public AntClassLoader(final ClassLoader parent, final Project project, final Path classpath) { setParent(parent); setClassPath(classpath); setProject(project); @@ -277,7 +307,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * May be {@code null}, in which case no path * elements are set up to start with. */ - public AntClassLoader(Project project, Path classpath) { + public AntClassLoader(final Project project, final Path classpath) { setParent(null); setProject(project); setClassPath(classpath); @@ -299,8 +329,8 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * classloader should be consulted before trying to * load the a class through this loader. */ - public AntClassLoader( - ClassLoader parent, Project project, Path classpath, boolean parentFirst) { + public AntClassLoader(final ClassLoader parent, final Project project, + final Path classpath, final boolean parentFirst) { this(project, classpath); if (parent != null) { setParent(parent); @@ -321,7 +351,8 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * classloader should be consulted before trying to * load the a class through this loader. */ - public AntClassLoader(Project project, Path classpath, boolean parentFirst) { + public AntClassLoader(final Project project, final Path classpath, + final boolean parentFirst) { this(null, project, classpath, parentFirst); } @@ -338,8 +369,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * classloader should be consulted before trying to * load the a class through this loader. */ - public AntClassLoader(ClassLoader parent, boolean parentFirst) { - super(parent); // KK patch for JENKINS-21579 + public AntClassLoader(final ClassLoader parent, final boolean parentFirst) { setParent(parent); project = null; this.parentFirst = parentFirst; @@ -350,7 +380,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * * @param project the project instance */ - public void setProject(Project project) { + public void setProject(final Project project) { this.project = project; if (project != null) { project.addBuildListener(this); @@ -364,17 +394,17 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @param classpath the search classpath consisting of directories and * jar/zip files. */ - public void setClassPath(Path classpath) { - pathComponents.clear(); + public void setClassPath(final Path classpath) { + pathComponents.removeAllElements(); if (classpath != null) { - Path actualClasspath = classpath.concatSystemClasspath("ignore"); - String[] pathElements = actualClasspath.list(); - for (String pathElement : pathElements) { + for (String pathElement : classpath.concatSystemClasspath("ignore").list()) { try { addPathElement(pathElement); - } catch (BuildException e) { + } catch (final BuildException e) { // ignore path elements which are invalid // relative to the project + log("Ignoring path element " + pathElement + " from " + + "classpath due to exception " + e, Project.MSG_DEBUG); } } } @@ -386,7 +416,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * * @param parent the parent class loader. */ - public void setParent(ClassLoader parent) { + public void setParent(final ClassLoader parent) { this.parent = parent == null ? AntClassLoader.class.getClassLoader() : parent; } @@ -398,7 +428,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @param parentFirst if true, delegate initial class search to the parent * classloader. */ - public void setParentFirst(boolean parentFirst) { + public void setParentFirst(final boolean parentFirst) { this.parentFirst = parentFirst; } @@ -410,9 +440,11 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * * @param priority The logging priority of the message. */ - protected void log(String message, int priority) { + protected void log(final String message, final int priority) { if (project != null) { project.log(message, priority); + } else if (priority < Project.MSG_INFO) { + System.err.println(message); } } @@ -427,7 +459,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { if (LoaderUtils.isContextLoaderAvailable()) { savedContextLoader = LoaderUtils.getContextClassLoader(); ClassLoader loader = this; - if (project != null && "only".equals(project.getProperty("build.sysclasspath"))) { + if (project != null && "only".equals(project.getProperty(MagicNames.BUILD_SYSCLASSPATH))) { loader = this.getClass().getClassLoader(); } LoaderUtils.setContextClassLoader(loader); @@ -456,12 +488,12 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @exception BuildException if the given path element cannot be resolved * against the project. */ - public void addPathElement(String pathElement) throws BuildException { - File pathComponent = project != null ? project.resolveFile(pathElement) : new File( + public void addPathElement(final String pathElement) throws BuildException { + final File pathComponent = project != null ? project.resolveFile(pathElement) : new File( pathElement); try { addPathFile(pathComponent); - } catch (IOException e) { + } catch (final IOException e) { throw new BuildException(e); } } @@ -473,11 +505,17 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * their CLASSPATH entry in the manifest file. * @param file the jar file or directory to add. */ - public void addPathComponent(File file) { + public void addPathComponent(final File file) { if (pathComponents.contains(file)) { return; } - pathComponents.add(file); + pathComponents.addElement(file); + } + + public void addPathFiles(Collection paths) throws IOException { + for (File f : paths) { + addPathFile(f); + } } /** @@ -490,20 +528,20 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * * @throws IOException if data needed from the file cannot be read. */ - protected void addPathFile(File pathComponent) throws IOException { + protected void addPathFile(final File pathComponent) throws IOException { if (!pathComponents.contains(pathComponent)) { - pathComponents.add(pathComponent); + pathComponents.addElement(pathComponent); } if (pathComponent.isDirectory()) { return; } - String absPathPlusTimeAndLength = pathComponent.getAbsolutePath() + final String absPathPlusTimeAndLength = pathComponent.getAbsolutePath() + pathComponent.lastModified() + "-" + pathComponent.length(); - String classpath = (String) pathMap.get(absPathPlusTimeAndLength); + String classpath = pathMap.get(absPathPlusTimeAndLength); if (classpath == null) { - try (JarFile jarFile = new JarFile(pathComponent)) { - Manifest manifest = jarFile.getManifest(); + try (JarFile jarFile = newJarFile(pathComponent)) { + final Manifest manifest = jarFile.getManifest(); if (manifest == null) { return; } @@ -516,20 +554,20 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { pathMap.put(absPathPlusTimeAndLength, classpath); } - if (!"".equals(classpath)) { - URL baseURL = FILE_UTILS.getFileURL(pathComponent); - StringTokenizer st = new StringTokenizer(classpath); + if (!classpath.isEmpty()) { + final URL baseURL = FILE_UTILS.getFileURL(pathComponent); + final StringTokenizer st = new StringTokenizer(classpath); while (st.hasMoreTokens()) { - String classpathElement = st.nextToken(); - URL libraryURL = new URL(baseURL, classpathElement); + final String classpathElement = st.nextToken(); + final URL libraryURL = new URL(baseURL, classpathElement); if (!libraryURL.getProtocol().equals("file")) { log("Skipping jar library " + classpathElement + " since only relative URLs are supported by this" + " loader", Project.MSG_VERBOSE); continue; } - String decodedPath = Locator.decodeUri(libraryURL.getFile()); - File libraryFile = new File(decodedPath); + final String decodedPath = Locator.decodeUri(libraryURL.getFile()); + final File libraryFile = new File(decodedPath); if (libraryFile.exists() && !isInPath(libraryFile)) { addPathFile(libraryFile); } @@ -544,15 +582,12 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * separated by the path separator for the system. */ public String getClasspath() { - StringBuilder sb = new StringBuilder(); - boolean firstPass = true; - for (File pathComponent : pathComponents) { - if (!firstPass) { - sb.append(System.getProperty("path.separator")); - } else { - firstPass = false; + final StringBuilder sb = new StringBuilder(); + for (final File component : pathComponents) { + if (sb.length() > 0) { + sb.append(File.pathSeparator); } - sb.append(pathComponent.getAbsolutePath()); + sb.append(component.getAbsolutePath()); } return sb.toString(); } @@ -566,7 +601,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @param isolated Whether or not this classloader should run in * isolated mode. */ - public synchronized void setIsolated(boolean isolated) { + public synchronized void setIsolated(final boolean isolated) { ignoreBase = isolated; } @@ -581,13 +616,13 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * Use Class.forName with initialize=true instead. */ @Deprecated - public static void initializeClass(Class theClass) { + public static void initializeClass(final Class theClass) { // ***HACK*** We ask the VM to create an instance // by voluntarily providing illegal arguments to force // the VM to run the class' static initializer, while // at the same time not running a valid constructor. - final Constructor[] cons = theClass.getDeclaredConstructors(); + final Constructor[] cons = theClass.getDeclaredConstructors(); //At least one constructor is guaranteed to be there, but check anyway. if (cons != null) { if (cons.length > 0 && cons[0] != null) { @@ -596,7 +631,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { cons[0].newInstance((Object[]) strs); // Expecting an exception to be thrown by this call: // IllegalArgumentException: wrong number of Arguments - } catch (Exception e) { + } catch (final Exception e) { // Ignore - we are interested only in the side // effect - that of getting the static initializers // invoked. As we do not want to call a valid @@ -623,7 +658,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @param packageRoot The root of all packages to be included. * Should not be {@code null}. */ - public void addSystemPackageRoot(String packageRoot) { + public void addSystemPackageRoot(final String packageRoot) { systemPackages.addElement(packageRoot + (packageRoot.endsWith(".") ? "" : ".")); } @@ -636,7 +671,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @param packageRoot The root of all packages to be included. * Should not be {@code null}. */ - public void addLoaderPackageRoot(String packageRoot) { + public void addLoaderPackageRoot(final String packageRoot) { loaderPackages.addElement(packageRoot + (packageRoot.endsWith(".") ? "" : ".")); } @@ -655,10 +690,10 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @exception ClassNotFoundException if the requested class does not exist * on this loader's classpath. */ - public Class forceLoadClass(String classname) throws ClassNotFoundException { + public Class forceLoadClass(final String classname) throws ClassNotFoundException { log("force loading " + classname, Project.MSG_DEBUG); - Class theClass = findLoadedClass(classname); + Class theClass = findLoadedClass(classname); if (theClass == null) { theClass = findClass(classname); @@ -682,10 +717,10 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @exception ClassNotFoundException if the requested class does not exist * on this loader's classpath. */ - public Class forceLoadSystemClass(String classname) throws ClassNotFoundException { + public Class forceLoadSystemClass(final String classname) throws ClassNotFoundException { log("force system loading " + classname, Project.MSG_DEBUG); - Class theClass = findLoadedClass(classname); + Class theClass = findLoadedClass(classname); if (theClass == null) { theClass = findBaseClass(classname); @@ -703,7 +738,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * resource cannot be found on the loader's classpath. */ @Override - public InputStream getResourceAsStream(String name) { + public InputStream getResourceAsStream(final String name) { InputStream resourceStream = null; if (isParentFirst(name)) { resourceStream = loadBaseResource(name); @@ -720,7 +755,9 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { } if (resourceStream == null && !isParentFirst(name)) { if (ignoreBase) { - resourceStream = getRootLoader() == null ? null : getRootLoader().getResourceAsStream(name); + resourceStream = getRootLoader() == null + ? null + : getRootLoader().getResourceAsStream(name); } else { resourceStream = loadBaseResource(name); } @@ -744,16 +781,11 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @return a stream to the required resource or {@code null} if * the resource cannot be found on the loader's classpath. */ - private InputStream loadResource(String name) { + private InputStream loadResource(final String name) { // we need to search the components of the path to see if we can // find the class we want. - for (File pathComponent : pathComponents) { - InputStream stream = getResourceStream(pathComponent, name); - if (stream != null) { - return stream; - } - } - return null; + return pathComponents.stream().map(path -> getResourceStream(path, name)) + .filter(Objects::nonNull).findFirst().orElse(null); } /** @@ -766,34 +798,10 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @return a stream to the named resource, or {@code null} if * the resource cannot be found. */ - private InputStream loadBaseResource(String name) { + private InputStream loadBaseResource(final String name) { return parent == null ? super.getResourceAsStream(name) : parent.getResourceAsStream(name); } - @FunctionalInterface - private interface Converter { - T convert(@NonNull JarFile jarFile, @NonNull JarEntry entry) throws IOException; - } - - @CheckForNull - private T storeAndConvert(JarFile jarFile, File file, String resourceName, Converter converter) throws IOException { - if (jarFile == null) { - if (file.exists()) { - jarFile = new JarFile(file); - jarFiles.put(file, jarFile); - } else { - return null; - } - //to eliminate a race condition, retrieve the entry - //that is in the hash table under that filename - jarFile = (JarFile) jarFiles.get(file); - } - JarEntry entry = jarFile.getJarEntry(resourceName); - if (entry == null) - return null; - return converter.convert(jarFile, entry); - } - /** * Returns an inputstream to a given resource in the given file which may * either be a directory or a zip file. @@ -806,18 +814,32 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @return a stream to the required resource or {@code null} if * the resource cannot be found in the given file. */ - private InputStream getResourceStream(File file, String resourceName) { + private InputStream getResourceStream(final File file, final String resourceName) { try { - JarFile jarFile = (JarFile) jarFiles.get(file); + JarFile jarFile = jarFiles.get(file); if (jarFile == null && file.isDirectory()) { - File resource = new File(file, resourceName); + final File resource = new File(file, resourceName); if (resource.exists()) { return Files.newInputStream(resource.toPath()); } } else { - return storeAndConvert(jarFile, file, resourceName, JarFile::getInputStream); + if (jarFile == null) { + if (file.exists()) { + jarFile = newJarFile(file); + jarFiles.put(file, jarFile); + } else { + return null; + } + //to eliminate a race condition, retrieve the entry + //that is in the hash table under that filename + jarFile = jarFiles.get(file); + } + final JarEntry entry = jarFile.getJarEntry(resourceName); + if (entry != null) { + return jarFile.getInputStream(entry); + } } - } catch (Exception e) { + } catch (final Exception e) { log("Ignoring Exception " + e.getClass().getName() + ": " + e.getMessage() + " reading resource " + resourceName + " from " + file, Project.MSG_VERBOSE); } @@ -837,31 +859,16 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @return whether or not the parent classloader should be checked for a * resource before this one is. */ - private boolean isParentFirst(String resourceName) { + private boolean isParentFirst(final String resourceName) { // default to the global setting and then see // if this class belongs to a package which has been // designated to use a specific loader first // (this one or the parent one) - // TODO shouldn't this always return false in isolated mode? + // TODO - shouldn't this always return false in isolated mode? - boolean useParentFirst = parentFirst; - - for (Enumeration e = systemPackages.elements(); e.hasMoreElements();) { - String packageName = (String) e.nextElement(); - if (resourceName.startsWith(packageName)) { - useParentFirst = true; - break; - } - } - for (Enumeration e = loaderPackages.elements(); e.hasMoreElements();) { - String packageName = (String) e.nextElement(); - if (resourceName.startsWith(packageName)) { - useParentFirst = false; - break; - } - } - return useParentFirst; + return loaderPackages.stream().noneMatch(resourceName::startsWith) + && (systemPackages.stream().anyMatch(resourceName::startsWith) || parentFirst); } /** @@ -889,7 +896,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * adequate privileges to get the resource. */ @Override - public URL getResource(String name) { + public URL getResource(final String name) { // we need to search the components of the path to see if // we can find the class we want. URL url = null; @@ -899,9 +906,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { if (url != null) { log("Resource " + name + " loaded from parent loader", Project.MSG_DEBUG); } else { - // try and load from this loader if the parent either didn't find - // it or wasn't consulted. - url = getUrl(pathComponents, name); + url = getUrl(name); } if (url == null && !isParentFirst(name)) { // this loader was first but it didn't find it - try the parent @@ -921,22 +926,25 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { } /** - * Finds a matching file by iterating pathComponents. + * Finds a matching file by iterating through path components. * - * @param pathComponents Path to a folder, split into the individual folder names * @param name File to find - * @return Url to found object + * @return A {@code URL} object for reading the resource, or {@code null} if the + * resource could not be found */ - @CheckForNull - protected URL getUrl(Iterable pathComponents, String name) { + private URL getUrl(String name) { URL url = null; - for (File pathComponent : pathComponents) { + + // try and load from this loader if the parent either didn't find + // it or wasn't consulted. + for (final File pathComponent : pathComponents) { url = getResourceURL(pathComponent, name); if (url != null) { log("Resource " + name + " loaded from ant loader", Project.MSG_DEBUG); break; } } + return url; } @@ -945,16 +953,29 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * data (images, audio, text, etc) that can be accessed by class * code in a way that is independent of the location of the code. * - *

Would override getResources if that wasn't final in Java - * 1.4.

- * + * @param name name of the resource + * @return possible URLs as enumeration + * @throws IOException if something goes wrong + * @see #findResources(String, boolean) * @since Ant 1.8.0 */ - public Enumeration/**/ getNamedResources(String name) + public Enumeration getNamedResources(final String name) throws IOException { return findResources(name, false); } + /** + * Finds the resource with the given name. + * + * @param name The resource name + * @return A {@code URL} object for reading the resource, or {@code null} if the + * resource could not be found + */ + @Override + public URL findResource(final String name) { + return getUrl(name); + } + /** * Returns an enumeration of URLs representing all the resources with the * given name by searching the class loader's classpath. @@ -965,7 +986,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @exception IOException if I/O errors occurs (can't happen) */ @Override - public Enumeration/**/ findResources(String name) throws IOException { + public Enumeration findResources(final String name) throws IOException { return findResources(name, true); } @@ -975,38 +996,38 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * * @param name The resource name to search for. * Must not be {@code null}. - * @param parentHasBeenSearched whether ClassLoader.this.parent - * has been searched - will be true if the method is (indirectly) - * called from ClassLoader.getResources + * @param skipParent whether to skip searching the parent first - will be false if the method is + * invoked from {@link #getResources(String)} or {@link #getNamedResources(String)} and true + * if the method is invoked from {@link #findResources(String)}. * @return an enumeration of URLs for the resources * @exception IOException if I/O errors occurs (can't happen) */ - protected Enumeration/**/ findResources(String name, - boolean parentHasBeenSearched) + protected Enumeration findResources(final String name, + final boolean skipParent) throws IOException { - Enumeration/**/ mine = new ResourceEnumeration(name); - Enumeration/**/ base; - if (parent != null && (!parentHasBeenSearched || parent != getParent())) { + final Enumeration mine = new ResourceEnumeration(name); + Enumeration base; + if (parent != null && !skipParent) { // Delegate to the parent: base = parent.getResources(name); - // Note: could cause overlaps in case - // ClassLoader.this.parent has matches and - // parentHasBeenSearched is true } else { - // ClassLoader.this.parent is already delegated to for example from - // ClassLoader.getResources, no need: - base = new CollectionUtils.EmptyEnumeration(); + base = Collections.emptyEnumeration(); } if (isParentFirst(name)) { // Normal case. - return CollectionUtils.append(base, mine); + return append(base, mine); } if (ignoreBase) { - return getRootLoader() == null ? mine : CollectionUtils.append(mine, getRootLoader() - .getResources(name)); + return getRootLoader() == null ? mine + : append(mine, getRootLoader().getResources(name)); } // parent last: - return CollectionUtils.append(mine, base); + return append(mine, base); + } + + private static Enumeration append(Enumeration one, Enumeration two) { + return Stream.concat(Collections.list(one).stream(), Collections.list(two).stream()) + .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::enumeration)); } /** @@ -1021,33 +1042,49 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @return a stream to the required resource or {@code null} if the * resource cannot be found in the given file object. */ - protected URL getResourceURL(File file, String resourceName) { + protected URL getResourceURL(final File file, final String resourceName) { try { - JarFile jarFile = (JarFile) jarFiles.get(file); + JarFile jarFile = jarFiles.get(file); if (jarFile == null && file.isDirectory()) { - File resource = new File(file, resourceName); + final File resource = new File(file, resourceName); if (resource.exists()) { try { return FILE_UTILS.getFileURL(resource); - } catch (MalformedURLException ex) { + } catch (final MalformedURLException ex) { return null; } } } else { - return storeAndConvert(jarFile, file, resourceName, (jar, entry) -> { - try { - return new URL("jar:" + FILE_UTILS.getFileURL(file) + "!/" + entry); - } catch (MalformedURLException ex) { + if (jarFile == null) { + if (file.exists()) { + if (!isZip(file)) { + final String msg = "CLASSPATH element " + file + + " is not a JAR."; + log(msg, Project.MSG_WARN); + return null; + } + jarFile = newJarFile(file); + jarFiles.put(file, jarFile); + } else { return null; } - }); + // potential race-condition + jarFile = jarFiles.get(file); + } + final JarEntry entry = jarFile.getJarEntry(resourceName); + if (entry != null) { + try { + return new URL("jar:" + FILE_UTILS.getFileURL(file) + "!/" + entry); + } catch (final MalformedURLException ex) { + return null; + } + } } - } catch (Exception e) { - String msg = "Unable to obtain resource from " + file + ": "; + } catch (final Exception e) { + final String msg = "Unable to obtain resource from " + file + ": "; log(msg + e, Project.MSG_WARN); - System.err.println(msg); - e.printStackTrace(); + log(StringUtils.getStackTrace(e), Project.MSG_WARN); } return null; } @@ -1073,46 +1110,37 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * classpath. */ @Override - protected synchronized Class loadClass(String classname, boolean resolve) - throws ClassNotFoundException { + protected synchronized Class loadClass(final String classname, final boolean resolve) + throws ClassNotFoundException { // 'sync' is needed - otherwise 2 threads can load the same class // twice, resulting in LinkageError: duplicated class definition. // findLoadedClass avoids that, but without sync it won't work. - Class theClass = findLoadedClass(classname); + Class theClass = findLoadedClass(classname); if (theClass != null) { return theClass; } - - //Surround the former logic with a try-catch to report missing class exceptions via Java11 telemetry - try { - if (isParentFirst(classname)) { - try { - theClass = findBaseClass(classname); - log("Class " + classname + " loaded from parent loader " + "(parentFirst)", - Project.MSG_DEBUG); - } catch (ClassNotFoundException cnfe) { - theClass = findClass(classname); - log("Class " + classname + " loaded from ant loader " + "(parentFirst)", - Project.MSG_DEBUG); - } - } else { - try { - theClass = findClass(classname); - log("Class " + classname + " loaded from ant loader", Project.MSG_DEBUG); - } catch (ClassNotFoundException cnfe) { - if (ignoreBase) { - throw cnfe; - } - theClass = findBaseClass(classname); - log("Class " + classname + " loaded from parent loader", Project.MSG_DEBUG); - } + if (isParentFirst(classname)) { + try { + theClass = findBaseClass(classname); + log("Class " + classname + " loaded from parent loader " + "(parentFirst)", + Project.MSG_DEBUG); + } catch (final ClassNotFoundException cnfe) { + theClass = findClass(classname); + log("Class " + classname + " loaded from ant loader " + "(parentFirst)", + Project.MSG_DEBUG); + } + } else { + try { + theClass = findClass(classname); + log("Class " + classname + " loaded from ant loader", Project.MSG_DEBUG); + } catch (final ClassNotFoundException cnfe) { + if (ignoreBase) { + throw cnfe; + } + theClass = findBaseClass(classname); + log("Class " + classname + " loaded from parent loader", Project.MSG_DEBUG); } - } catch (ClassNotFoundException cnfe) { - //To catch CNFE thrown from this.getClass().getClassLoader().loadClass(classToLoad); from a plugin step or - //a plugin page - MissingClassTelemetry.reportException(classname, cnfe); - throw cnfe; } if (resolve) { resolveClass(theClass); @@ -1129,7 +1157,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * * @return the classname in filesystem format (eg java/lang/Integer.class) */ - private String getClassFilename(String classname) { + private String getClassFilename(final String classname) { return classname.replace('.', '/') + ".class"; } @@ -1146,15 +1174,15 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * * @throws IOException if the class data cannot be read. */ - protected Class defineClassFromData(File container, byte[] classData, String classname) - throws IOException { + protected Class defineClassFromData(final File container, final byte[] classData, final String classname) + throws IOException { definePackage(container, classname); - ProtectionDomain currentPd = Project.class.getProtectionDomain(); - String classResource = getClassFilename(classname); - CodeSource src = new CodeSource(FILE_UTILS.getFileURL(container), - getCertificates(container, - classResource)); - ProtectionDomain classesPd = + final ProtectionDomain currentPd = Project.class.getProtectionDomain(); + final String classResource = getClassFilename(classname); + final CodeSource src = new CodeSource(FILE_UTILS.getFileURL(container), + getCertificates(container, + classResource)); + final ProtectionDomain classesPd = new ProtectionDomain(src, currentPd.getPermissions(), this, currentPd.getPrincipals()); @@ -1172,18 +1200,18 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @exception IOException if the package information cannot be read from the * container. */ - protected void definePackage(File container, String className) throws IOException { - int classIndex = className.lastIndexOf('.'); + protected void definePackage(final File container, final String className) throws IOException { + final int classIndex = className.lastIndexOf('.'); if (classIndex == -1) { return; } - String packageName = className.substring(0, classIndex); + final String packageName = className.substring(0, classIndex); if (getPackage(packageName) != null) { // already defined return; } // define the package now - Manifest manifest = getJarManifest(container); + final Manifest manifest = getJarManifest(container); if (manifest == null) { definePackage(packageName, null, null, null, null, null, null, null); @@ -1203,11 +1231,11 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * * @exception IOException if the manifest cannot be read. */ - private Manifest getJarManifest(File container) throws IOException { + private Manifest getJarManifest(final File container) throws IOException { if (container.isDirectory()) { return null; } - JarFile jarFile = (JarFile) jarFiles.get(container); + final JarFile jarFile = jarFiles.get(container); if (jarFile == null) { return null; } @@ -1222,19 +1250,16 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * * @return the entry's certificates or null is the container is * not a jar or it has no certificates. - * - * @exception IOException if the manifest cannot be read. */ - private Certificate[] getCertificates(File container, String entry) - throws IOException { + private Certificate[] getCertificates(final File container, final String entry) { if (container.isDirectory()) { return null; } - JarFile jarFile = (JarFile) jarFiles.get(container); + final JarFile jarFile = jarFiles.get(container); if (jarFile == null) { return null; } - JarEntry ent = jarFile.getJarEntry(entry); + final JarEntry ent = jarFile.getJarEntry(entry); return ent == null ? null : ent.getCertificates(); } @@ -1246,8 +1271,8 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @param packageName the name of the package being defined. * @param manifest the jar's manifest */ - protected void definePackage(File container, String packageName, Manifest manifest) { - String sectionName = packageName.replace('.', '/') + "/"; + protected void definePackage(final File container, final String packageName, final Manifest manifest) { + final String sectionName = packageName.replace('.', '/') + "/"; String specificationTitle = null; String specificationVendor = null; @@ -1258,7 +1283,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { String sealedString = null; URL sealBase = null; - Attributes sectionAttributes = manifest.getAttributes(sectionName); + final Attributes sectionAttributes = manifest.getAttributes(sectionName); if (sectionAttributes != null) { specificationTitle = sectionAttributes.getValue(Name.SPECIFICATION_TITLE); specificationVendor = sectionAttributes.getValue(Name.SPECIFICATION_VENDOR); @@ -1268,7 +1293,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { implementationVersion = sectionAttributes.getValue(Name.IMPLEMENTATION_VERSION); sealedString = sectionAttributes.getValue(Name.SEALED); } - Attributes mainAttributes = manifest.getMainAttributes(); + final Attributes mainAttributes = manifest.getMainAttributes(); if (mainAttributes != null) { if (specificationTitle == null) { specificationTitle = mainAttributes.getValue(Name.SPECIFICATION_TITLE); @@ -1295,12 +1320,12 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { if (sealedString != null && sealedString.equalsIgnoreCase("true")) { try { sealBase = new URL(FileUtils.getFileUtils().toURI(container.getAbsolutePath())); - } catch (MalformedURLException e) { + } catch (final MalformedURLException e) { // ignore } } definePackage(packageName, specificationTitle, specificationVersion, specificationVendor, - implementationTitle, implementationVersion, implementationVendor, sealBase); + implementationTitle, implementationVersion, implementationVendor, sealBase); } /** @@ -1319,16 +1344,16 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @exception SecurityException if there is a security problem while * reading the class from the stream. */ - private Class getClassFromStream(InputStream stream, String classname, File container) - throws IOException, SecurityException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); + private Class getClassFromStream(final InputStream stream, final String classname, final File container) + throws IOException, SecurityException { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); int bytesRead = -1; - byte[] buffer = new byte[BUFFER_SIZE]; + final byte[] buffer = new byte[BUFFER_SIZE]; while ((bytesRead = stream.read(buffer, 0, BUFFER_SIZE)) != -1) { baos.write(buffer, 0, bytesRead); } - byte[] classData = baos.toByteArray(); + final byte[] classData = baos.toByteArray(); return defineClassFromData(container, classData, classname); } @@ -1344,7 +1369,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * on this loader's classpath. */ @Override - public Class findClass(String name) throws ClassNotFoundException { + public Class findClass(final String name) throws ClassNotFoundException { log("Finding class " + name, Project.MSG_DEBUG); return findClassInComponents(name); } @@ -1356,7 +1381,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * * @return true if the file is in the class path */ - protected boolean isInPath(File component) { + protected boolean isInPath(final File component) { return pathComponents.contains(component); } @@ -1371,24 +1396,24 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @exception ClassNotFoundException if the requested class does not exist * on this loader's classpath. */ - private Class findClassInComponents(String name) + private Class findClassInComponents(final String name) throws ClassNotFoundException { // we need to search the components of the path to see if // we can find the class we want. - String classFilename = getClassFilename(name); - for (File pathComponent : pathComponents) { + final String classFilename = getClassFilename(name); + for (final File pathComponent : pathComponents) { try (InputStream stream = getResourceStream(pathComponent, classFilename)) { if (stream != null) { log("Loaded from " + pathComponent + " " + classFilename, Project.MSG_DEBUG); return getClassFromStream(stream, name, pathComponent); } - } catch (SecurityException se) { + } catch (final SecurityException se) { throw se; - } catch (IOException ioe) { + } catch (final IOException ioe) { // ioe.printStackTrace(); log("Exception reading component " + pathComponent + " (reason: " - + ioe.getMessage() + ")", Project.MSG_VERBOSE); + + ioe.getMessage() + ")", Project.MSG_VERBOSE); } } throw new ClassNotFoundException(name); @@ -1409,7 +1434,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @exception ClassNotFoundException if the requested class does not exist * on this loader's classpath. */ - private Class findBaseClass(String name) throws ClassNotFoundException { + private Class findBaseClass(final String name) throws ClassNotFoundException { return parent == null ? findSystemClass(name) : parent.loadClass(name); } @@ -1418,15 +1443,10 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * files are closed. */ public synchronized void cleanup() { - for (Enumeration e = jarFiles.elements(); e.hasMoreElements();) { - JarFile jarFile = (JarFile) e.nextElement(); - try { - jarFile.close(); - } catch (IOException ioe) { - // ignore - } + for (final JarFile jarFile : jarFiles.values()) { + FileUtils.close(jarFile); } - jarFiles = new Hashtable(); + jarFiles = new Hashtable<>(); if (project != null) { project.removeBuildListener(this); } @@ -1437,6 +1457,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * Gets the parent as has been specified in the constructor or via * setParent. * + * @return classloader * @since Ant 1.8.0 */ public ClassLoader getConfiguredParent() { @@ -1449,7 +1470,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @param event the buildStarted event */ @Override - public void buildStarted(BuildEvent event) { + public void buildStarted(final BuildEvent event) { // Not significant for the class loader. } @@ -1460,7 +1481,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @param event the buildFinished event */ @Override - public void buildFinished(BuildEvent event) { + public void buildFinished(final BuildEvent event) { cleanup(); } @@ -1474,7 +1495,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @since Ant 1.6.2 */ @Override - public void subBuildFinished(BuildEvent event) { + public void subBuildFinished(final BuildEvent event) { if (event.getProject() == project) { cleanup(); } @@ -1488,7 +1509,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @since Ant 1.6.2 */ @Override - public void subBuildStarted(BuildEvent event) { + public void subBuildStarted(final BuildEvent event) { // Not significant for the class loader. } @@ -1498,7 +1519,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @param event the targetStarted event */ @Override - public void targetStarted(BuildEvent event) { + public void targetStarted(final BuildEvent event) { // Not significant for the class loader. } @@ -1508,7 +1529,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @param event the targetFinished event */ @Override - public void targetFinished(BuildEvent event) { + public void targetFinished(final BuildEvent event) { // Not significant for the class loader. } @@ -1518,7 +1539,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @param event the taskStarted event */ @Override - public void taskStarted(BuildEvent event) { + public void taskStarted(final BuildEvent event) { // Not significant for the class loader. } @@ -1528,7 +1549,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @param event the taskFinished event */ @Override - public void taskFinished(BuildEvent event) { + public void taskFinished(final BuildEvent event) { // Not significant for the class loader. } @@ -1538,7 +1559,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * @param event the messageLogged event */ @Override - public void messageLogged(BuildEvent event) { + public void messageLogged(final BuildEvent event) { // Not significant for the class loader. } @@ -1547,12 +1568,7 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { * here */ public void addJavaLibraries() { - Vector packages = JavaEnvUtils.getJrePackages(); - Enumeration e = packages.elements(); - while (e.hasMoreElements()) { - String packageName = (String) e.nextElement(); - addSystemPackageRoot(packageName); - } + JavaEnvUtils.getJrePackages().forEach(this::addSystemPackageRoot); } /** @@ -1564,38 +1580,93 @@ public class AntClassLoader extends ClassLoader implements SubBuildListener { return "AntClassLoader[" + getClasspath() + "]"; } - private static Class subClassToLoad = null; - private static final Class[] CONSTRUCTOR_ARGS = new Class[] { - ClassLoader.class, Project.class, Path.class, Boolean.TYPE - }; + /** + * Public version of {@link ClassLoader#findLoadedClass(String)} + */ + public Class findLoadedClass2(String name) { + return findLoadedClass(name); + } - static { - if (JavaEnvUtils.isAtLeastJavaVersion(JavaEnvUtils.JAVA_1_5)) { - try { - subClassToLoad = - Class.forName("org.apache.tools.ant.loader.AntClassLoader5"); - } catch (ClassNotFoundException e) { - // this is Java5 but the installation is lacking our subclass - } - } + /** + * Public version of {@link ClassLoader#getClassLoadingLock(String)} + */ + @Override + public Object getClassLoadingLock(String className) { + return super.getClassLoadingLock(className); + } + + /** {@inheritDoc} */ + @Override + public Enumeration getResources(String name) throws IOException { + return getNamedResources(name); + } + + /** {@inheritDoc} */ + @Override + public void close() { + cleanup(); } /** * Factory method + * + * @param parent ClassLoader + * @param project Project + * @param path Path + * @param parentFirst boolean + * @return AntClassLoader */ - public static AntClassLoader newAntClassLoader(ClassLoader parent, - Project project, - Path path, - boolean parentFirst) { - if (subClassToLoad != null) { - return (AntClassLoader) - ReflectUtil.newInstance(subClassToLoad, - CONSTRUCTOR_ARGS, - new Object[] { - parent, project, path, parentFirst - }); - } + public static AntClassLoader newAntClassLoader(final ClassLoader parent, + final Project project, + final Path path, + final boolean parentFirst) { return new AntClassLoader(parent, project, path, parentFirst); } + private static final ZipLong EOCD_SIG = new ZipLong(0X06054B50L); + private static final ZipLong SINGLE_SEGMENT_SPLIT_MARKER = + new ZipLong(0X30304B50L); + + private static boolean isZip(final File file) throws IOException { + final byte[] sig = new byte[4]; + if (readFully(file, sig)) { + final ZipLong start = new ZipLong(sig); + return ZipLong.LFH_SIG.equals(start) // normal file + || EOCD_SIG.equals(start) // empty zip + || ZipLong.DD_SIG.equals(start) // split zip + || SINGLE_SEGMENT_SPLIT_MARKER.equals(start); + } + return false; + } + + private static boolean readFully(final File f, final byte[] b) throws IOException { + try (InputStream fis = Files.newInputStream(f.toPath())) { + final int len = b.length; + int count = 0, x = 0; + while (count != len) { + x = fis.read(b, count, len - count); + if (x == -1) { + break; + } + count += x; + } + return count == len; + } + } + + /** + * + * @param file The file representing the jar + * @return Returns a {@link JarFile} instance, which is constructed based upon the Java runtime version. + * Depending on the Java runtime version, the returned instance may or may not be {@code multi-release} + * aware (a feature introduced in Java 9) + * @throws IOException + */ + private static JarFile newJarFile(final File file) throws IOException { + if (!IS_ATLEAST_JAVA9 || MR_JARFILE_CTOR_ARGS == null || MR_JARFILE_CTOR_RUNTIME_VERSION_VAL == null) { + return new JarFile(file); + } + return ReflectUtil.newInstance(JarFile.class, MR_JARFILE_CTOR_ARGS, + new Object[] {file, true, ZipFile.OPEN_READ, MR_JARFILE_CTOR_RUNTIME_VERSION_VAL}); + } } diff --git a/core/src/main/java/jenkins/util/AntWithFindResourceClassLoader.java b/core/src/main/java/jenkins/util/AntWithFindResourceClassLoader.java deleted file mode 100644 index 4c03d41242..0000000000 --- a/core/src/main/java/jenkins/util/AntWithFindResourceClassLoader.java +++ /dev/null @@ -1,62 +0,0 @@ -package jenkins.util; - -import java.io.Closeable; -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Field; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; - -/** - * 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 ArrayList pathComponents; - - public AntWithFindResourceClassLoader(ClassLoader parent, boolean parentFirst) { - super(parent, parentFirst); - - try { - Field $pathComponents = AntClassLoader.class.getDeclaredField("pathComponents"); - $pathComponents.setAccessible(true); - pathComponents = (ArrayList)$pathComponents.get(this); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new LinkageError(e.getMessage(), e); - } - } - - public void addPathFiles(Collection paths) throws IOException { - for (File f : paths) - addPathFile(f); - } - - @Override - public void close() throws IOException { - cleanup(); - } - - @Override - public URL findResource(String name) { - // try and load from this loader if the parent either didn't find - // it or wasn't consulted. - return getUrl(pathComponents, name); - } - - /** - * Public version of {@link ClassLoader#findLoadedClass(String)} - */ - public Class findLoadedClass2(String name) { - return findLoadedClass(name); - } - - /** - * Public version of {@link ClassLoader#getClassLoadingLock(String)} - */ - @Override - public Object getClassLoadingLock(String className) { - return super.getClassLoadingLock(className); - } - -} diff --git a/core/src/main/java/jenkins/util/JSONSignatureValidator.java b/core/src/main/java/jenkins/util/JSONSignatureValidator.java index b696a3f3af..1dcd433f42 100644 --- a/core/src/main/java/jenkins/util/JSONSignatureValidator.java +++ b/core/src/main/java/jenkins/util/JSONSignatureValidator.java @@ -73,9 +73,9 @@ public class JSONSignatureValidator { try { c.checkValidity(); } catch (CertificateExpiredException e) { // even if the certificate isn't valid yet, we'll proceed it anyway - warning = FormValidation.warning(e, String.format("Certificate %s has expired in %s", cert.toString(), name)); + warning = FormValidation.warning(e, String.format("Certificate %s has expired in %s", cert, name)); } catch (CertificateNotYetValidException e) { - warning = FormValidation.warning(e, String.format("Certificate %s is not yet valid in %s", cert.toString(), name)); + warning = FormValidation.warning(e, String.format("Certificate %s is not yet valid in %s", cert, name)); } LOGGER.log(Level.FINE, "Add certificate found in JSON document:\n\tsubjectDN: {0}\n\tissuer: {1}\n\tnotBefore: {2}\n\tnotAfter: {3}", new Object[] { c.getSubjectDN(), c.getIssuerDN(), c.getNotBefore(), c.getNotAfter() }); diff --git a/core/src/main/java/jenkins/util/JenkinsJVM.java b/core/src/main/java/jenkins/util/JenkinsJVM.java index f8e37a79a1..fafe1223a3 100644 --- a/core/src/main/java/jenkins/util/JenkinsJVM.java +++ b/core/src/main/java/jenkins/util/JenkinsJVM.java @@ -43,7 +43,7 @@ public class JenkinsJVM { */ public static void checkJenkinsJVM() { if (!isJenkinsJVM()) { - throw new IllegalStateException("Not running on the Jenkins master JVM"); + throw new IllegalStateException("Not running on the Jenkins controller JVM"); } } @@ -55,7 +55,7 @@ public class JenkinsJVM { */ public static void checkNotJenkinsJVM() { if (isJenkinsJVM()) { - throw new IllegalStateException("Running on the Jenkins master JVM"); + throw new IllegalStateException("Running on the Jenkins controller JVM"); } } diff --git a/core/src/main/java/jenkins/util/ResourceBundleUtil.java b/core/src/main/java/jenkins/util/ResourceBundleUtil.java index 7a53b54785..60b71ae696 100644 --- a/core/src/main/java/jenkins/util/ResourceBundleUtil.java +++ b/core/src/main/java/jenkins/util/ResourceBundleUtil.java @@ -70,7 +70,7 @@ public class ResourceBundleUtil { * @throws MissingResourceException Missing resource bundle. */ public static @NonNull JSONObject getBundle(@NonNull String baseName, @NonNull Locale locale) throws MissingResourceException { - String bundleKey = baseName + ":" + locale.toString(); + String bundleKey = baseName + ":" + locale; JSONObject bundleJSON = bundles.get(bundleKey); if (bundleJSON != null) { diff --git a/core/src/main/java/org/jenkins/ui/icon/Icon.java b/core/src/main/java/org/jenkins/ui/icon/Icon.java index 00d57fbccc..1de8642974 100644 --- a/core/src/main/java/org/jenkins/ui/icon/Icon.java +++ b/core/src/main/java/org/jenkins/ui/icon/Icon.java @@ -24,6 +24,7 @@ package org.jenkins.ui.icon; import org.apache.commons.jelly.JellyContext; +import org.apache.commons.lang.StringUtils; import org.kohsuke.accmod.Restricted; import org.kohsuke.accmod.restrictions.NoExternalUse; @@ -47,6 +48,7 @@ public class Icon { public static final String ICON_LARGE_STYLE = "width: 32px; height: 32px;"; public static final String ICON_XLARGE_STYLE = "width: 48px; height: 48px;"; + private static final String[] SUPPORTED_FORMATS = new String[] {".svg", ".png", ".gif"}; private static final Map iconDims = new HashMap<>(); static { @@ -216,7 +218,7 @@ public class Icon { if (string == null) { return null; } - if (string.endsWith(".png") || string.endsWith(".gif")) { + if (StringUtils.endsWithAny(string, SUPPORTED_FORMATS)) { string = string.substring(0, string.length() - 4); } return string.replace('_', '-'); diff --git a/core/src/main/java/org/jenkins/ui/icon/IconSet.java b/core/src/main/java/org/jenkins/ui/icon/IconSet.java index 5acd1f231d..15d4abbb85 100644 --- a/core/src/main/java/org/jenkins/ui/icon/IconSet.java +++ b/core/src/main/java/org/jenkins/ui/icon/IconSet.java @@ -25,6 +25,9 @@ package org.jenkins.ui.icon; import org.apache.commons.jelly.JellyContext; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -254,21 +257,18 @@ public class IconSet { return Icon.toNormalizedIconUrl(url); } - // Initialize the core Jenkins icons. We need all this stuff so as to maintain - // backward compatibility. + // Initialize the core Jenkins icons. + // We need all this stuff to maintain backward compatibility. + // SVG will override PNG, PNG will override GIF + // Only time a gif should be returned by name is when it's an animated status icon ("-anime-") static { - // Small icons. - // .png versions will override .gif versions => only time a gif should be returned by - // name is when it's an animated status icon ("-anime-") + // Small icons icons.addIcon(new BuildStatusIcon("icon-aborted icon-sm", "build-status/build-status-sprite.svg#last-aborted", Icon.ICON_SMALL_STYLE)); icons.addIcon(new BuildStatusIcon("icon-aborted-anime icon-sm", "build-status/build-status-sprite.svg#last-aborted", Icon.ICON_SMALL_STYLE, true)); icons.addIcon(new BuildStatusIcon("icon-blue icon-sm", "build-status/build-status-sprite.svg#last-successful", Icon.ICON_SMALL_STYLE)); icons.addIcon(new BuildStatusIcon("icon-blue-anime icon-sm", "build-status/build-status-sprite.svg#last-successful", Icon.ICON_SMALL_STYLE, true)); - icons.addIcon(new Icon("icon-clock icon-sm", "16x16/clock.gif", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-clock-anime icon-sm", "16x16/clock_anime.gif", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-computer-flash icon-sm", "16x16/computer-flash.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-computer-x icon-sm", "16x16/computer-x.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-computer icon-sm", "16x16/computer.gif", Icon.ICON_SMALL_STYLE)); icons.addIcon(new BuildStatusIcon("icon-disabled icon-sm", "build-status/build-status-sprite.svg#last-disabled", Icon.ICON_SMALL_STYLE)); icons.addIcon(new BuildStatusIcon("icon-disabled-anime icon-sm", "build-status/build-status-sprite.svg#last-disabled", Icon.ICON_SMALL_STYLE, true)); icons.addIcon(new Icon("icon-document-add icon-sm", "16x16/document_add.gif", Icon.ICON_SMALL_STYLE)); @@ -277,13 +277,8 @@ public class IconSet { icons.addIcon(new Icon("icon-edit-delete icon-sm", "16x16/edit-delete.gif", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-edit-select-all icon-sm", "16x16/edit-select-all.gif", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-empty icon-sm", "16x16/empty.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-error icon-sm", "16x16/error.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-fingerprint icon-sm", "16x16/fingerprint.gif", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-folder-error icon-sm", "16x16/folder-error.gif", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-folder-open icon-sm", "16x16/folder-open.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-folder icon-sm", "16x16/folder.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-gear2 icon-sm", "16x16/gear2.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-go-next icon-sm", "16x16/go-next.gif", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-green icon-sm", "16x16/green.gif", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-green-anime icon-sm", "16x16/green_anime.gif", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-grey icon-sm", "16x16/grey.gif", Icon.ICON_SMALL_STYLE)); @@ -293,100 +288,39 @@ public class IconSet { icons.addIcon(new WeatherIcon("icon-health-40to59 icon-sm", Icon.ICON_SMALL_STYLE, WeatherIcon.Status.CLOUDY)); icons.addIcon(new WeatherIcon("icon-health-60to79 icon-sm", Icon.ICON_SMALL_STYLE, WeatherIcon.Status.PARTLY_CLOUDY)); icons.addIcon(new WeatherIcon("icon-health-80plus icon-sm", Icon.ICON_SMALL_STYLE, WeatherIcon.Status.SUNNY)); - icons.addIcon(new Icon("icon-help icon-sm", "16x16/help.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-hourglass icon-sm", "16x16/hourglass.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-lock icon-sm", "16x16/lock.gif", Icon.ICON_SMALL_STYLE)); icons.addIcon(new BuildStatusIcon("icon-nobuilt icon-sm", "build-status/build-status-sprite.svg#never-built", Icon.ICON_SMALL_STYLE)); icons.addIcon(new BuildStatusIcon("icon-nobuilt-anime icon-sm", "build-status/build-status-sprite.svg#never-built", Icon.ICON_SMALL_STYLE, true)); - icons.addIcon(new Icon("icon-notepad icon-sm", "16x16/notepad.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-package icon-sm", "16x16/package.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-person icon-sm", "16x16/person.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-plugin icon-sm", "16x16/plugin.gif", Icon.ICON_SMALL_STYLE)); icons.addIcon(new BuildStatusIcon("icon-red icon-sm", "build-status/build-status-sprite.svg#last-failed", Icon.ICON_SMALL_STYLE)); icons.addIcon(new BuildStatusIcon("icon-red-anime icon-sm", "build-status/build-status-sprite.svg#last-failed", Icon.ICON_SMALL_STYLE, true)); - icons.addIcon(new Icon("icon-redo icon-sm", "16x16/redo.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-save icon-sm", "16x16/save.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-search icon-sm", "16x16/search.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-star-gold icon-sm", "16x16/star-gold.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-star icon-sm", "16x16/star.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-stop icon-sm", "16x16/stop.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-terminal icon-sm", "16x16/terminal.gif", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-text-error icon-sm", "16x16/text-error.gif", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-text icon-sm", "16x16/text.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-user icon-sm", "16x16/user.gif", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-warning icon-sm", "16x16/warning.gif", Icon.ICON_SMALL_STYLE)); icons.addIcon(new BuildStatusIcon("icon-yellow icon-sm", "build-status/build-status-sprite.svg#last-unstable", Icon.ICON_SMALL_STYLE)); icons.addIcon(new BuildStatusIcon("icon-yellow-anime icon-sm", "build-status/build-status-sprite.svg#last-unstable", Icon.ICON_SMALL_STYLE, true)); - - icons.addIcon(new Icon("icon-accept icon-sm", "16x16/accept.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-attribute icon-sm", "16x16/attribute.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-clock icon-sm", "16x16/clock.png", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-collapse icon-sm", "16x16/collapse.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-computer-x icon-sm", "16x16/computer-x.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-computer icon-sm", "16x16/computer.png", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-document-add icon-sm", "16x16/document_add.png", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-document-delete icon-sm", "16x16/document_delete.png", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-document-edit icon-sm", "16x16/document_edit.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-edit-delete icon-sm", "16x16/edit-delete.png", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-edit-select-all icon-sm", "16x16/edit-select-all.png", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-empty icon-sm", "16x16/empty.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-error icon-sm", "16x16/error.png", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-expand icon-sm", "16x16/expand.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-fingerprint icon-sm", "16x16/fingerprint.png", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-folder-error icon-sm", "16x16/folder-error.png", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-folder-open icon-sm", "16x16/folder-open.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-folder icon-sm", "16x16/folder.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-gear2 icon-sm", "16x16/gear2.png", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-go-next icon-sm", "16x16/go-next.png", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-grey icon-sm", "16x16/grey.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-help icon-sm", "material-icons/svg-sprite-action-symbol.svg#ic_help_24px", Icon.ICON_SMALL_STYLE, IconFormat.EXTERNAL_SVG_SPRITE)); - icons.addIcon(new Icon("icon-hourglass icon-sm", "16x16/hourglass.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-lock icon-sm", "16x16/lock.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-notepad icon-sm", "16x16/notepad.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-orange-square icon-sm", "16x16/orange-square.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-package icon-sm", "16x16/package.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-person icon-sm", "16x16/person.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-plugin icon-sm", "16x16/plugin.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-redo icon-sm", "16x16/redo.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-save icon-sm", "16x16/save.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-search icon-sm", "16x16/search.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-secure icon-sm", "16x16/secure.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-setting icon-sm", "16x16/setting.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-star-gold icon-sm", "16x16/star-gold.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-star icon-sm", "16x16/star.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-stop icon-sm", "16x16/stop.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-terminal icon-sm", "16x16/terminal.png", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-text-error icon-sm", "16x16/text-error.png", Icon.ICON_SMALL_STYLE)); icons.addIcon(new Icon("icon-text icon-sm", "16x16/text.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-user icon-sm", "16x16/user.png", Icon.ICON_SMALL_STYLE)); - icons.addIcon(new Icon("icon-warning icon-sm", "16x16/warning.png", Icon.ICON_SMALL_STYLE)); - // Medium icons. - // .png versions will override .gif versions => only time a gif should be returned by - // name is when it's an animated status icon ("-anime-") + // Medium icons icons.addIcon(new BuildStatusIcon("icon-aborted icon-md", "build-status/build-status-sprite.svg#last-aborted", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new BuildStatusIcon("icon-aborted-anime icon-md", "build-status/build-status-sprite.svg#last-aborted", Icon.ICON_MEDIUM_STYLE, true)); icons.addIcon(new BuildStatusIcon("icon-blue icon-md", "build-status/build-status-sprite.svg#last-successful", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new BuildStatusIcon("icon-blue-anime icon-md", "build-status/build-status-sprite.svg#last-successful", Icon.ICON_MEDIUM_STYLE, true)); - icons.addIcon(new Icon("icon-clipboard icon-md", "24x24/clipboard.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-clock icon-md", "24x24/clock.gif", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new Icon("icon-clock-anime icon-md", "24x24/clock_anime.gif", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new Icon("icon-computer-flash icon-md", "24x24/computer-flash.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-computer-x icon-md", "24x24/computer-x.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-computer icon-md", "24x24/computer.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-delete-document icon-md", "24x24/delete-document.gif", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new BuildStatusIcon("icon-disabled icon-md", "build-status/build-status-sprite.svg#last-disabled", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new BuildStatusIcon("icon-disabled-anime icon-md", "build-status/build-status-sprite.svg#last-disabled", Icon.ICON_MEDIUM_STYLE, true)); icons.addIcon(new Icon("icon-document-properties icon-md", "24x24/document-properties.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-document icon-md", "24x24/document.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-edit-delete icon-md", "24x24/edit-delete.gif", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new Icon("icon-empty icon-md", "24x24/empty.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-fingerprint icon-md", "24x24/fingerprint.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-folder-delete icon-md", "24x24/folder-delete.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-folder icon-md", "24x24/folder.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-gear icon-md", "24x24/gear.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-gear2 icon-md", "24x24/gear2.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-graph icon-md", "24x24/graph.gif", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new Icon("icon-green icon-md", "24x24/green.gif", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new Icon("icon-green-anime icon-md", "24x24/green_anime.gif", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new Icon("icon-grey icon-md", "24x24/grey.gif", Icon.ICON_MEDIUM_STYLE)); @@ -396,102 +330,31 @@ public class IconSet { icons.addIcon(new WeatherIcon("icon-health-40to59 icon-md", Icon.ICON_MEDIUM_STYLE, WeatherIcon.Status.CLOUDY)); icons.addIcon(new WeatherIcon("icon-health-60to79 icon-md", Icon.ICON_MEDIUM_STYLE, WeatherIcon.Status.PARTLY_CLOUDY)); icons.addIcon(new WeatherIcon("icon-health-80plus icon-md", Icon.ICON_MEDIUM_STYLE, WeatherIcon.Status.SUNNY)); - icons.addIcon(new Icon("icon-help icon-md", "24x24/help.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-installer icon-md", "24x24/installer.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-monitor icon-md", "24x24/monitor.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-new-computer icon-md", "24x24/new-computer.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-new-document icon-md", "24x24/new-document.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-new-package icon-md", "24x24/new-package.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-new-user icon-md", "24x24/new-user.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-next icon-md", "24x24/next.gif", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new BuildStatusIcon("icon-nobuilt icon-md", "build-status/build-status-sprite.svg#never-built", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new BuildStatusIcon("icon-nobuilt-anime icon-md", "build-status/build-status-sprite.svg#never-built", Icon.ICON_MEDIUM_STYLE, true)); - icons.addIcon(new Icon("icon-notepad icon-md", "24x24/notepad.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-orange-square icon-md", "24x24/orange-square.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-package icon-md", "24x24/package.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-previous icon-md", "24x24/previous.gif", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new BuildStatusIcon("icon-red icon-md", "build-status/build-status-sprite.svg#last-failed", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new BuildStatusIcon("icon-red-anime icon-md", "build-status/build-status-sprite.svg#last-failed", Icon.ICON_MEDIUM_STYLE, true)); - icons.addIcon(new Icon("icon-redo icon-md", "24x24/redo.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-refresh icon-md", "24x24/refresh.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-save icon-md", "24x24/save.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-search icon-md", "24x24/search.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-setting icon-md", "24x24/setting.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-star-gold icon-md", "24x24/star-gold.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-star icon-md", "24x24/star.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-terminal icon-md", "24x24/terminal.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-up icon-md", "24x24/up.gif", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-user icon-md", "24x24/user.gif", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new BuildStatusIcon("icon-yellow icon-md", "build-status/build-status-sprite.svg#last-unstable", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new BuildStatusIcon("icon-yellow-anime icon-md", "build-status/build-status-sprite.svg#last-unstable", Icon.ICON_MEDIUM_STYLE, true)); - - icons.addIcon(new Icon("icon-accept icon-md", "24x24/accept.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-attribute icon-md", "24x24/attribute.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-clipboard icon-md", "24x24/clipboard.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-clock icon-md", "24x24/clock.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-computer-x icon-md", "24x24/computer-x.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-computer icon-md", "24x24/computer.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-delete-document icon-md", "24x24/delete-document.png", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new Icon("icon-document-properties icon-md", "24x24/document-properties.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-document icon-md", "24x24/document.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-edit-delete icon-md", "24x24/edit-delete.png", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new Icon("icon-empty icon-md", "24x24/empty.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-fingerprint icon-md", "24x24/fingerprint.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-folder-delete icon-md", "24x24/folder-delete.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-folder icon-md", "24x24/folder.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-gear icon-md", "24x24/gear.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-gear2 icon-md", "24x24/gear2.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-graph icon-md", "24x24/graph.png", Icon.ICON_MEDIUM_STYLE)); icons.addIcon(new Icon("icon-grey icon-md", "24x24/grey.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-help icon-md", "material-icons/svg-sprite-action-symbol.svg#ic_help_24px", Icon.ICON_MEDIUM_STYLE, IconFormat.EXTERNAL_SVG_SPRITE)); - icons.addIcon(new Icon("icon-installer icon-md", "24x24/installer.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-lock icon-md", "24x24/lock.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-monitor icon-md", "24x24/monitor.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-new-computer icon-md", "24x24/new-computer.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-new-document icon-md", "24x24/new-document.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-new-package icon-md", "24x24/new-package.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-new-user icon-md", "24x24/new-user.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-next icon-md", "24x24/next.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-notepad icon-md", "24x24/notepad.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-orange-square icon-md", "24x24/orange-square.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-package icon-md", "24x24/package.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-plugin icon-md", "24x24/plugin.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-previous icon-md", "24x24/previous.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-redo icon-md", "24x24/redo.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-refresh icon-md", "24x24/refresh.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-save icon-md", "24x24/save.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-search icon-md", "24x24/search.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-secure icon-md", "24x24/secure.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-setting icon-md", "24x24/setting.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-star-gold icon-md", "24x24/star-gold.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-star icon-md", "24x24/star.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-terminal icon-md", "24x24/terminal.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-up icon-md", "24x24/up.png", Icon.ICON_MEDIUM_STYLE)); - icons.addIcon(new Icon("icon-user icon-md", "24x24/user.png", Icon.ICON_MEDIUM_STYLE)); - // Large icons. - // .png versions will override .gif versions => only time a gif should be returned by - // name is when it's an animated status icon ("-anime") + // Large icons icons.addIcon(new BuildStatusIcon("icon-aborted icon-lg", "build-status/build-status-sprite.svg#last-aborted", Icon.ICON_LARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-aborted-anime icon-lg", "build-status/build-status-sprite.svg#last-aborted", Icon.ICON_LARGE_STYLE, true)); icons.addIcon(new BuildStatusIcon("icon-blue icon-lg", "build-status/build-status-sprite.svg#last-successful", Icon.ICON_LARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-blue-anime icon-lg", "build-status/build-status-sprite.svg#last-successful", Icon.ICON_LARGE_STYLE, true)); - icons.addIcon(new Icon("icon-clipboard icon-lg", "32x32/clipboard.gif", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-clock icon-lg", "32x32/clock.gif", Icon.ICON_LARGE_STYLE)); icons.addIcon(new Icon("icon-clock-anime icon-lg", "32x32/clock_anime.gif", Icon.ICON_LARGE_STYLE)); icons.addIcon(new Icon("icon-computer-flash icon-lg", "32x32/computer-flash.gif", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-computer-x icon-lg", "32x32/computer-x.gif", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-computer icon-lg", "32x32/computer.gif", Icon.ICON_LARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-disabled icon-lg", "build-status/build-status-sprite.svg#last-disabled", Icon.ICON_LARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-disabled-anime icon-lg", "build-status/build-status-sprite.svg#last-disabled", Icon.ICON_LARGE_STYLE, true)); icons.addIcon(new Icon("icon-empty icon-lg", "32x32/empty.gif", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-error icon-lg", "32x32/error.gif", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-folder icon-lg", "32x32/folder.gif", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-graph icon-lg", "32x32/graph.gif", Icon.ICON_LARGE_STYLE)); icons.addIcon(new Icon("icon-green icon-lg", "32x32/green.gif", Icon.ICON_LARGE_STYLE)); icons.addIcon(new Icon("icon-green-anime icon-lg", "32x32/green_anime.gif", Icon.ICON_LARGE_STYLE)); icons.addIcon(new Icon("icon-grey icon-lg", "32x32/grey.gif", Icon.ICON_LARGE_STYLE)); icons.addIcon(new Icon("icon-grey-anime icon-lg", "32x32/grey_anime.gif", Icon.ICON_LARGE_STYLE)); + icons.addIcon(new Icon("icon-empty icon-lg", "32x32/empty.png", Icon.ICON_LARGE_STYLE)); icons.addIcon(new WeatherIcon("icon-health-00to19 icon-lg", Icon.ICON_LARGE_STYLE, WeatherIcon.Status.POURING)); icons.addIcon(new WeatherIcon("icon-health-20to39 icon-lg", Icon.ICON_LARGE_STYLE, WeatherIcon.Status.RAINY)); icons.addIcon(new WeatherIcon("icon-health-40to59 icon-lg", Icon.ICON_LARGE_STYLE, WeatherIcon.Status.CLOUDY)); @@ -499,59 +362,20 @@ public class IconSet { icons.addIcon(new WeatherIcon("icon-health-80plus icon-lg", Icon.ICON_LARGE_STYLE, WeatherIcon.Status.SUNNY)); icons.addIcon(new BuildStatusIcon("icon-nobuilt icon-lg", "build-status/build-status-sprite.svg#never-built", Icon.ICON_LARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-nobuilt-anime icon-lg", "build-status/build-status-sprite.svg#never-built", Icon.ICON_LARGE_STYLE, true)); - icons.addIcon(new Icon("icon-plugin icon-lg", "32x32/plugin.gif", Icon.ICON_LARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-red icon-lg", "build-status/build-status-sprite.svg#last-failed", Icon.ICON_LARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-red-anime icon-lg", "build-status/build-status-sprite.svg#last-failed", Icon.ICON_LARGE_STYLE, true)); - icons.addIcon(new Icon("icon-setting icon-lg", "32x32/setting.gif", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-star-gold icon-lg", "32x32/star-gold.gif", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-star icon-lg", "32x32/star.gif", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-user icon-lg", "32x32/user.png", Icon.ICON_LARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-yellow icon-lg", "build-status/build-status-sprite.svg#last-unstable", Icon.ICON_LARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-yellow-anime icon-lg", "build-status/build-status-sprite.svg#last-unstable", Icon.ICON_LARGE_STYLE, true)); - - icons.addIcon(new Icon("icon-accept icon-lg", "32x32/accept.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-attribute icon-lg", "32x32/attribute.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-clipboard icon-lg", "32x32/clipboard.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-clock icon-lg", "32x32/clock.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-computer-x icon-lg", "32x32/computer-x.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-computer icon-lg", "32x32/computer.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-empty icon-lg", "32x32/empty.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-error icon-lg", "32x32/error.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-folder icon-lg", "32x32/folder.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-gear2 icon-lg", "32x32/gear2.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-graph icon-lg", "32x32/graph.png", Icon.ICON_LARGE_STYLE)); icons.addIcon(new Icon("icon-grey icon-lg", "32x32/grey.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-lock icon-lg", "32x32/lock.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-orange-square icon-lg", "32x32/orange-square.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-package icon-lg", "32x32/package.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-plugin icon-lg", "32x32/plugin.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-secure icon-lg", "32x32/secure.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-setting icon-lg", "32x32/setting.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-star-gold icon-lg", "32x32/star-gold.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-star icon-lg", "32x32/star.png", Icon.ICON_LARGE_STYLE)); - icons.addIcon(new Icon("icon-user icon-lg", "32x32/user.gif", Icon.ICON_LARGE_STYLE)); - // X icon-lg icons. - // .png versions will override .gif versions => only time a gif should be returned by - // name is when it's an animated status icon ("-anime-") + // Extra-large icons icons.addIcon(new BuildStatusIcon("icon-aborted icon-xlg", "build-status/build-status-sprite.svg#last-aborted", Icon.ICON_XLARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-aborted-anime icon-xlg", "build-status/build-status-sprite.svg#last-aborted", Icon.ICON_XLARGE_STYLE, true)); icons.addIcon(new BuildStatusIcon("icon-blue icon-xlg", "build-status/build-status-sprite.svg#last-successful", Icon.ICON_XLARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-blue-anime icon-xlg", "build-status/build-status-sprite.svg#last-successful", Icon.ICON_XLARGE_STYLE, true)); - icons.addIcon(new Icon("icon-clipboard icon-xlg", "48x48/clipboard.gif", Icon.ICON_XLARGE_STYLE)); icons.addIcon(new Icon("icon-computer-flash icon-xlg", "48x48/computer-flash.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-computer-x icon-xlg", "48x48/computer-x.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-computer icon-xlg", "48x48/computer.gif", Icon.ICON_XLARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-disabled icon-xlg", "build-status/build-status-sprite.svg#last-disabled", Icon.ICON_XLARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-disabled-anime icon-xlg", "build-status/build-status-sprite.svg#last-disabled", Icon.ICON_XLARGE_STYLE, true)); - icons.addIcon(new Icon("icon-document icon-xlg", "48x48/document.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-empty icon-xlg", "48x48/empty.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-error icon-xlg", "48x48/error.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-fingerprint icon-xlg", "48x48/fingerprint.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-folder-delete icon-xlg", "48x48/folder-delete.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-folder icon-xlg", "48x48/folder.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-gear2 icon-xlg", "48x48/gear2.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-graph icon-xlg", "48x48/graph.gif", Icon.ICON_XLARGE_STYLE)); icons.addIcon(new Icon("icon-green icon-xlg", "48x48/green.gif", Icon.ICON_XLARGE_STYLE)); icons.addIcon(new Icon("icon-green-anime icon-xlg", "48x48/green_anime.gif", Icon.ICON_XLARGE_STYLE)); icons.addIcon(new Icon("icon-grey icon-xlg", "48x48/grey.gif", Icon.ICON_XLARGE_STYLE)); @@ -561,68 +385,113 @@ public class IconSet { icons.addIcon(new WeatherIcon("icon-health-40to59 icon-xlg", Icon.ICON_XLARGE_STYLE, WeatherIcon.Status.CLOUDY)); icons.addIcon(new WeatherIcon("icon-health-60to79 icon-xlg", Icon.ICON_XLARGE_STYLE, WeatherIcon.Status.PARTLY_CLOUDY)); icons.addIcon(new WeatherIcon("icon-health-80plus icon-xlg", Icon.ICON_XLARGE_STYLE, WeatherIcon.Status.SUNNY)); - icons.addIcon(new Icon("icon-help icon-xlg", "48x48/help.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-installer icon-xlg", "48x48/installer.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-monitor icon-xlg", "48x48/monitor.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-network icon-xlg", "48x48/network.gif", Icon.ICON_XLARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-nobuilt icon-xlg", "build-status/build-status-sprite.svg#never-built", Icon.ICON_XLARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-nobuilt-anime icon-xlg", "build-status/build-status-sprite.svg#never-built", Icon.ICON_XLARGE_STYLE, true)); - icons.addIcon(new Icon("icon-notepad icon-xlg", "48x48/notepad.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-orange-square icon-xlg", "48x48/orange-square.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-package icon-xlg", "48x48/package.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-plugin icon-xlg", "48x48/plugin.gif", Icon.ICON_XLARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-red icon-xlg", "build-status/build-status-sprite.svg#last-failed", Icon.ICON_XLARGE_STYLE )); icons.addIcon(new BuildStatusIcon("icon-red-anime icon-xlg", "build-status/build-status-sprite.svg#last-failed", Icon.ICON_XLARGE_STYLE, true)); - icons.addIcon(new Icon("icon-redo icon-xlg", "48x48/redo.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-refresh icon-xlg", "48x48/refresh.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-search icon-xlg", "48x48/search.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-secure icon-xlg", "48x48/secure.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-setting icon-xlg", "48x48/setting.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-star-gold icon-xlg", "48x48/star-gold.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-star icon-xlg", "48x48/star.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-system-log-out icon-xlg", "48x48/system-log-out.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-terminal icon-xlg", "48x48/terminal.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-user icon-xlg", "48x48/user.gif", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-warning icon-xlg", "48x48/warning.gif", Icon.ICON_XLARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-yellow icon-xlg", "build-status/build-status-sprite.svg#last-unstable", Icon.ICON_XLARGE_STYLE)); icons.addIcon(new BuildStatusIcon("icon-yellow-anime icon-xlg", "build-status/build-status-sprite.svg#last-unstable", Icon.ICON_XLARGE_STYLE, true)); - - icons.addIcon(new Icon("icon-accept icon-xlg", "48x48/accept.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-attribute icon-xlg", "48x48/attribute.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-clipboard icon-xlg", "48x48/clipboard.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-computer-x icon-xlg", "48x48/computer-x.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-computer icon-xlg", "48x48/computer.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-document icon-xlg", "48x48/document.png", Icon.ICON_XLARGE_STYLE)); icons.addIcon(new Icon("icon-empty icon-xlg", "48x48/empty.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-error icon-xlg", "48x48/error.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-fingerprint icon-xlg", "48x48/fingerprint.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-folder-delete icon-xlg", "48x48/folder-delete.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-folder icon-xlg", "48x48/folder.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-gear2 icon-xlg", "48x48/gear2.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-graph icon-xlg", "48x48/graph.png", Icon.ICON_XLARGE_STYLE)); icons.addIcon(new Icon("icon-grey icon-xlg", "48x48/grey.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-help icon-xlg", "material-icons/svg-sprite-action-symbol.svg#ic_help_24px", Icon.ICON_XLARGE_STYLE, IconFormat.EXTERNAL_SVG_SPRITE)); - icons.addIcon(new Icon("icon-installer icon-xlg", "48x48/installer.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-lock icon-xlg", "48x48/lock.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-monitor icon-xlg", "48x48/monitor.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-network icon-xlg", "48x48/network.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-notepad icon-xlg", "48x48/notepad.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-orange-square icon-xlg", "48x48/orange-square.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-package icon-xlg", "48x48/package.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-plugin icon-xlg", "48x48/plugin.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-redo icon-xlg", "48x48/redo.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-refresh icon-xlg", "48x48/refresh.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-search icon-xlg", "48x48/search.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-secure icon-xlg", "48x48/secure.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-setting icon-xlg", "48x48/setting.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-star-gold icon-xlg", "48x48/star-gold.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-star icon-xlg", "48x48/star.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-system-log-out icon-xlg", "48x48/system-log-out.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-terminal icon-xlg", "48x48/terminal.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-user icon-xlg", "48x48/user.png", Icon.ICON_XLARGE_STYLE)); - icons.addIcon(new Icon("icon-warning icon-xlg", "48x48/warning.png", Icon.ICON_XLARGE_STYLE)); + + initializeSVGs(); // Capture a list of the core icons. icons.coreIcons.putAll(icons.iconsByCSSSelector); } + + private static void initializeSVGs() { + Map sizes = new HashMap<>(); + sizes.put("icon-sm", Icon.ICON_SMALL_STYLE); + sizes.put("icon-md", Icon.ICON_MEDIUM_STYLE); + sizes.put("icon-lg", Icon.ICON_LARGE_STYLE); + sizes.put("icon-xlg", Icon.ICON_XLARGE_STYLE); + + List images = new ArrayList<>(); + images.add("computer"); + images.add("delete-document"); + images.add("accept"); + images.add("application-certificate"); + images.add("attribute"); + images.add("bookmark-new"); + images.add("certificate"); + images.add("clipboard-list-solid"); + images.add("clipboard"); + images.add("clock"); + images.add("computer-user-offline"); + images.add("computer-x"); + images.add("document"); + images.add("edit-delete"); + images.add("emblem-urgent"); + images.add("error"); + images.add("fingerprint"); + images.add("folder-delete"); + images.add("folder"); + images.add("gear"); + images.add("gear2"); + images.add("go-down"); + images.add("go-top"); + images.add("go-up"); + images.add("graph"); + images.add("headless"); + images.add("headshot"); + images.add("hourglass"); + images.add("installer"); + images.add("keys"); + images.add("lock"); + images.add("logo"); + images.add("monitor"); + images.add("network"); + images.add("new-computer"); + images.add("new-document"); + images.add("new-package"); + images.add("new-user"); + images.add("next"); + images.add("notepad"); + images.add("orange-square"); + images.add("package"); + images.add("person"); + images.add("plugin"); + images.add("previous"); + images.add("redo"); + images.add("refresh"); + images.add("save-new"); + images.add("save"); + images.add("search"); + images.add("secure"); + images.add("setting"); + images.add("shield"); + images.add("star-gold"); + images.add("star-large-gold"); + images.add("star-large"); + images.add("star"); + images.add("stop"); + images.add("system-log-out"); + images.add("terminal"); + images.add("undo"); + images.add("up"); + images.add("user"); + images.add("video"); + images.add("warning"); + + Map materialIcons = new HashMap<>(); + materialIcons.put("help", "svg-sprite-action-symbol.svg#ic_help_24px"); + + for (Map.Entry size : sizes.entrySet()) { + for (String image : images) { + icons.addIcon(new Icon("icon-" + image + " " + size.getKey(), + "svgs/" + image + ".svg", size.getValue())); + } + + for (String image : materialIcons.keySet()) { + icons.addIcon(new Icon( + "icon-" + image + " " + size.getKey(), + "material-icons/" + materialIcons.get(image), + size.getValue(), + IconFormat.EXTERNAL_SVG_SPRITE + ) + ); + } + } + } } diff --git a/core/src/main/resources/dsld/IntelliJ.gdsl b/core/src/main/resources/dsld/IntelliJ.gdsl index 6babd92f23..0be510b16f 100644 --- a/core/src/main/resources/dsld/IntelliJ.gdsl +++ b/core/src/main/resources/dsld/IntelliJ.gdsl @@ -25,7 +25,7 @@ contributor(ctx) { for (def f=ct.containingFile.virtualFile; f!=null && !roots.contains(f); f=f.parent) { contentPaths << f.name } - if (contentPaths.size()>0) { + if (contentPaths.size()>1) { // directory portion matches the FQCN def fqcn = contentPaths.reverse()[0.. - + diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/feeds.jelly b/core/src/main/resources/hudson/logging/LogRecorderManager/feeds.jelly index e64510514e..c9841b5b5b 100644 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/feeds.jelly +++ b/core/src/main/resources/hudson/logging/LogRecorderManager/feeds.jelly @@ -28,22 +28,22 @@ THE SOFTWARE.
- + ${%All} - + ${%SEVERE} - + ${%WARNING} diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/index.jelly b/core/src/main/resources/hudson/logging/LogRecorderManager/index.jelly index fcdc2542be..6546379ab5 100644 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/index.jelly +++ b/core/src/main/resources/hudson/logging/LogRecorderManager/index.jelly @@ -60,7 +60,7 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel.jelly b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel.jelly index 1e6e7850f6..3343b76f17 100644 --- a/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel.jelly +++ b/core/src/main/resources/hudson/logging/LogRecorderManager/sidepanel.jelly @@ -31,7 +31,7 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/hudson/model/AbstractBuild/index.jelly b/core/src/main/resources/hudson/model/AbstractBuild/index.jelly index e259553075..3f1774061c 100644 --- a/core/src/main/resources/hudson/model/AbstractBuild/index.jelly +++ b/core/src/main/resources/hudson/model/AbstractBuild/index.jelly @@ -47,10 +47,7 @@ THE SOFTWARE.
- - ${%Build} ${it.displayName} - () - + ${%Build} ${it.displayName} ()
diff --git a/core/src/main/resources/hudson/model/AbstractModelObject/descriptionForm.jelly b/core/src/main/resources/hudson/model/AbstractModelObject/descriptionForm.jelly index 8bb30e90ce..2d793ab4b9 100644 --- a/core/src/main/resources/hudson/model/AbstractModelObject/descriptionForm.jelly +++ b/core/src/main/resources/hudson/model/AbstractModelObject/descriptionForm.jelly @@ -39,7 +39,7 @@ THE SOFTWARE.
- +
diff --git a/core/src/main/resources/hudson/model/AbstractModelObject/editDescription.jelly b/core/src/main/resources/hudson/model/AbstractModelObject/editDescription.jelly index 5ee89972ff..9d715ab6f3 100644 --- a/core/src/main/resources/hudson/model/AbstractModelObject/editDescription.jelly +++ b/core/src/main/resources/hudson/model/AbstractModelObject/editDescription.jelly @@ -39,7 +39,7 @@ THE SOFTWARE. codemirror-mode="${app.markupFormatter.codeMirrorMode}" codemirror-config="${app.markupFormatter.codeMirrorConfig}" previewEndpoint="/markupFormatter/previewDescription"/> - + diff --git a/core/src/main/resources/hudson/model/AbstractProject/help-label.html b/core/src/main/resources/hudson/model/AbstractProject/help-label.html index df1b6a104a..24034668e2 100644 --- a/core/src/main/resources/hudson/model/AbstractProject/help-label.html +++ b/core/src/main/resources/hudson/model/AbstractProject/help-label.html @@ -5,8 +5,8 @@ expression evaluates to true, then that agent will be allowed to execute builds of this project.

- If this project should always be built on a specific agent, or on the Jenkins - master, then you can just enter the agent's name, or master, + If this project should always be built on a specific agent, or on the built-in + node, then you can just enter the agent's name, or built-in, respectively.

However, you should generally avoid using the Name of an agent here, @@ -98,8 +98,8 @@

Examples

-
master
-
Builds of this project may be executed only on the Jenkins master
+
built-in
+
Builds of this project may be executed only on the built-in node
linux-machine-42
diff --git a/core/src/main/resources/hudson/model/AbstractProject/help-label_bg.html b/core/src/main/resources/hudson/model/AbstractProject/help-label_bg.html index 194bd86cb9..1cae56db1a 100644 --- a/core/src/main/resources/hudson/model/AbstractProject/help-label_bg.html +++ b/core/src/main/resources/hudson/model/AbstractProject/help-label_bg.html @@ -6,7 +6,7 @@

Ако проектът трябва задължително да се изгражда на определен подчинен компютър или на основния, въведете съответно името на компютъра или - master. + built-in.

Като цяло трябва да избягвате употребата на името на подчинения компютър като вместо това използвате етикетите на компютрите. Както е @@ -96,7 +96,7 @@

Примери

-
master
+
built-in
Изгражданията на този проект може да са само на основния компютър на Jenkins.
diff --git a/core/src/main/resources/hudson/model/AbstractProject/help-label_it.html b/core/src/main/resources/hudson/model/AbstractProject/help-label_it.html index 1cf1afb930..8014cef95a 100644 --- a/core/src/main/resources/hudson/model/AbstractProject/help-label_it.html +++ b/core/src/main/resources/hudson/model/AbstractProject/help-label_it.html @@ -104,7 +104,7 @@

Esempi

-
master
+
built-in
Le compilazioni di questo progetto possono eseguite solo sul nodo master di Jenkins diff --git a/core/src/main/resources/hudson/model/AbstractProject/sidepanel.jelly b/core/src/main/resources/hudson/model/AbstractProject/sidepanel.jelly index 3a40490166..b3259668e1 100644 --- a/core/src/main/resources/hudson/model/AbstractProject/sidepanel.jelly +++ b/core/src/main/resources/hudson/model/AbstractProject/sidepanel.jelly @@ -47,7 +47,7 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/hudson/model/ComputerSet/index.jelly b/core/src/main/resources/hudson/model/ComputerSet/index.jelly index 64b3bc5337..60b5ca18f5 100644 --- a/core/src/main/resources/hudson/model/ComputerSet/index.jelly +++ b/core/src/main/resources/hudson/model/ComputerSet/index.jelly @@ -61,7 +61,7 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly b/core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly index 6940dd6714..d26786989f 100644 --- a/core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly +++ b/core/src/main/resources/hudson/model/ComputerSet/sidepanel.jelly @@ -32,11 +32,11 @@ THE SOFTWARE. - + - + diff --git a/core/src/main/resources/hudson/model/Job/buildTimeTrend.jelly b/core/src/main/resources/hudson/model/Job/buildTimeTrend.jelly index 41ae8ec5bf..1a689c5a0a 100644 --- a/core/src/main/resources/hudson/model/Job/buildTimeTrend.jelly +++ b/core/src/main/resources/hudson/model/Job/buildTimeTrend.jelly @@ -39,18 +39,18 @@ THE SOFTWARE. [${%Build time graph}]
- +
${handler.setBuilds(it.builds)} + data-is-distributed-build-enabled="${isDistributedBuildEnabled}"> - + diff --git a/core/src/main/resources/hudson/model/Job/buildTimeTrend_resources.js b/core/src/main/resources/hudson/model/Job/buildTimeTrend_resources.js index efeb5489d3..791c123a3a 100644 --- a/core/src/main/resources/hudson/model/Job/buildTimeTrend_resources.js +++ b/core/src/main/resources/hudson/model/Job/buildTimeTrend_resources.js @@ -3,7 +3,7 @@ */ function buildTimeTrend_displayBuilds(data) { var p = document.getElementById('trend'); - var isMasterSlaveEnabled = 'true' === p.getAttribute("data-is-master-slave-enabled"); + var isDistributedBuildsEnabled = 'true' === p.getAttribute("data-is-distributed-build-enabled"); var imagesURL = document.head.getAttribute('data-imagesurl'); var rootURL = document.head.getAttribute('data-rooturl'); @@ -18,7 +18,7 @@ function buildTimeTrend_displayBuilds(data) { update(e.displayName.escapeHTML()))); tr.insert(new Element('td', {data: e.duration}). update(e.durationString.escapeHTML())); - if (isMasterSlaveEnabled) { + if (isDistributedBuildsEnabled) { var buildInfo = null; var buildInfoStr = (e.builtOnStr || '').escapeHTML(); if(e.builtOn) { diff --git a/core/src/main/resources/hudson/model/Label/sidepanel.jelly b/core/src/main/resources/hudson/model/Label/sidepanel.jelly index 7d662a0a45..5b4608c846 100644 --- a/core/src/main/resources/hudson/model/Label/sidepanel.jelly +++ b/core/src/main/resources/hudson/model/Label/sidepanel.jelly @@ -34,7 +34,7 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/hudson/model/Messages.properties b/core/src/main/resources/hudson/model/Messages.properties index 1b38799541..6981bc4b3a 100644 --- a/core/src/main/resources/hudson/model/Messages.properties +++ b/core/src/main/resources/hudson/model/Messages.properties @@ -23,7 +23,7 @@ # THE SOFTWARE. AbstractBuild.BuildingRemotely=Building remotely on {0} -AbstractBuild.BuildingOnMaster=Building on master +AbstractBuild.BuildingOnMaster=Building on the built-in node AbstractBuild_Building=Building AbstractBuild.BuildingInWorkspace=\ in workspace {0} AbstractBuild.KeptBecause=This build is kept because of {0}. @@ -106,7 +106,7 @@ Computer.CreatePermission.Description=This permission allows users to create age Computer.ConnectPermission.Description=This permission allows users to connect agents or mark agents as online. Computer.DisconnectPermission.Description=This permission allows users to disconnect agents or mark agents as temporarily offline. Computer.BuildPermission.Description=This permission allows users to run jobs as them on agents. -Computer.BadChannel=Agent node offline or not a remote channel (such as master node). +Computer.BadChannel=Agent node offline or not a remote channel (such as the built-in node). ComputerSet.NoSuchSlave=No such agent: {0} ComputerSet.SlaveAlreadyExists=Agent called \u2018{0}\u2019 already exists @@ -125,8 +125,8 @@ FreeStyleProject.Description=\ HealthReport.EmptyString= Hudson.BadPortNumber=Bad port number {0} -Hudson.Computer.Caption=Master -Hudson.Computer.DisplayName=master +Hudson.Computer.Caption=Built-In Node +Hudson.Computer.DisplayName=Built-In Node Hudson.ControlCodeNotAllowed=No control code is allowed: {0} Hudson.DisplayName=Jenkins Hudson.JobAlreadyExists=A job already exists with the name \u2018{0}\u2019 @@ -168,7 +168,7 @@ Hudson.ReadPermission.Description=\ add "authenticated" pseudo-user and grant the read access. Hudson.RunScriptsPermission.Description=\ Deprecated - please use the Overall/Administer permission instead -Hudson.NodeDescription=the master Jenkins node +Hudson.NodeDescription=the Jenkins controller''s built-in node Item.Permissions.Title=Job Item.CREATE.description=Create a new job. @@ -189,6 +189,8 @@ Label.GroupOf=group of {0} Label.InvalidLabel=invalid label Label.ProvisionedFrom=Provisioned from {0} LabelExpression.InvalidBooleanExpression=Invalid boolean expression: {0} +LabelExpression_ObsoleteMasterLabel=This expression includes the label master that is no longer used for the built-in node. Use built-in instead. \ + Learn more. LabelExpression.LabelLink=Label {1} matches {3,choice,0#no nodes|1#1 node|1<{3} nodes}{4,choice,0#|1# and 1 cloud|1< and {4} clouds}. \ Permissions or other restrictions provided by plugins may further reduce that list. LabelExpression.NoMatch=No agent/cloud matches this label expression. @@ -253,7 +255,7 @@ Run.Summary.Unknown=? Slave.InvalidConfig.Executors=Invalid agent configuration for {0}. Invalid number of executors. Slave.InvalidConfig.NoName=Invalid agent configuration. Name is empty -Slave.Network.Mounted.File.System.Warning=Are you sure you want to use network mounted file system for FS root? Note that this directory does not need to be visible to the master. +Slave.Network.Mounted.File.System.Warning=Are you sure you want to use network mounted file system for FS root? Note that this directory does not need to be visible to the controller. Slave.Remote.Director.Mandatory=Remote directory is mandatory Slave.Terminated={0} agent was terminated Slave.Remote.Relative.Path.Warning=Are you sure you want to use a relative path for the FS root? Note that relative \ @@ -296,7 +298,7 @@ UpdateCenter.PluginCategory.builder=Build Tools UpdateCenter.PluginCategory.buildwrapper=Build Wrappers UpdateCenter.PluginCategory.cli=Command Line Interface UpdateCenter.PluginCategory.cloud=Cloud Providers -UpdateCenter.PluginCategory.cluster=Cluster Management and Distributed Build +UpdateCenter.PluginCategory.cluster=Cluster Management UpdateCenter.PluginCategory.database=Database UpdateCenter.PluginCategory.deployment=Deployment UpdateCenter.PluginCategory.devops=DevOps @@ -322,7 +324,7 @@ UpdateCenter.PluginCategory.scala=Scala Development UpdateCenter.PluginCategory.scm=Source Code Management UpdateCenter.PluginCategory.scm-related=Source Code Management related UpdateCenter.PluginCategory.security=Security -UpdateCenter.PluginCategory.slaves=Agent Launchers and Controllers +UpdateCenter.PluginCategory.slaves=Agent Management UpdateCenter.PluginCategory.test=Testing UpdateCenter.PluginCategory.theme=UI Themes UpdateCenter.PluginCategory.trigger=Build Triggers diff --git a/core/src/main/resources/hudson/model/Node/help-numExecutors.html b/core/src/main/resources/hudson/model/Node/help-numExecutors.html index 62ee113d35..89d1af5179 100644 --- a/core/src/main/resources/hudson/model/Node/help-numExecutors.html +++ b/core/src/main/resources/hudson/model/Node/help-numExecutors.html @@ -9,12 +9,12 @@ the second build could take advantage of the spare I/O capacity at that moment.

- Agents (nodes that are not the master) must have at least one executor. + Agents (nodes that are not the built-in node) must have at least one executor. To temporarily prevent any builds from being executed on an agent, use the Mark this node temporarily offline button on the agent's page.

- For the master, set the number of executors to zero to prevent it from - executing builds locally. - Note: master will always be able to run flyweight tasks including + For the built-in node, set the number of executors to zero to prevent it from + executing builds locally on the controller. + Note: The built-in node will always be able to run flyweight tasks including Pipeline's top-level task. diff --git a/core/src/main/resources/hudson/model/PasswordParameterDefinition/help.html b/core/src/main/resources/hudson/model/PasswordParameterDefinition/help.html index 0b9e3662e5..e78469f695 100644 --- a/core/src/main/resources/hudson/model/PasswordParameterDefinition/help.html +++ b/core/src/main/resources/hudson/model/PasswordParameterDefinition/help.html @@ -1,5 +1,5 @@

Pass a password to your build. The password entered here is made available to the build in plain text as an environment variable like a string parameter would be. - The value will be stored encrypted on the Jenkins master, similar to passwords in Jenkins configuration. + The value will be stored encrypted on the Jenkins controller, similar to passwords in Jenkins configuration.
\ No newline at end of file diff --git a/core/src/main/resources/hudson/model/Run/artifacts-index.jelly b/core/src/main/resources/hudson/model/Run/artifacts-index.jelly index b954198257..67a057e8ea 100644 --- a/core/src/main/resources/hudson/model/Run/artifacts-index.jelly +++ b/core/src/main/resources/hudson/model/Run/artifacts-index.jelly @@ -28,9 +28,7 @@ THE SOFTWARE. - - ${%Build Artifacts} - + ${%Build Artifacts}
${%Build} ${%Duration}${%Agent}
@@ -49,4 +47,4 @@ THE SOFTWARE. - \ No newline at end of file + diff --git a/core/src/main/resources/hudson/model/Run/console.jelly b/core/src/main/resources/hudson/model/Run/console.jelly index 132ed4747b..a8e6e99573 100644 --- a/core/src/main/resources/hudson/model/Run/console.jelly +++ b/core/src/main/resources/hudson/model/Run/console.jelly @@ -32,9 +32,7 @@ THE SOFTWARE. - - ${%Console Output} - + ${%Console Output} @@ -54,7 +52,7 @@ THE SOFTWARE.
             
- +
diff --git a/core/src/main/resources/hudson/model/Slave/help-remoteFS.html b/core/src/main/resources/hudson/model/Slave/help-remoteFS.html index 9b74e2e95c..38c0b42e27 100644 --- a/core/src/main/resources/hudson/model/Slave/help-remoteFS.html +++ b/core/src/main/resources/hudson/model/Slave/help-remoteFS.html @@ -4,10 +4,10 @@ the path to this directory on the agent. It is best to use an absolute path, such as /var/jenkins or c:\jenkins. This should be a path local to the agent machine. There is no need for - this path to be visible from the master. + this path to be visible from the controller.

Agents do not maintain important data; all job configurations, build logs and - artifacts are stored on the master, so it would be possible to use a temporary + artifacts are stored on the controller, so it would be possible to use a temporary directory as the agent root directory.
However, by giving an agent a directory that is not deleted after a machine diff --git a/core/src/main/resources/hudson/model/TreeView/ajaxRows.jelly b/core/src/main/resources/hudson/model/TreeView/ajaxRows.jelly deleted file mode 100644 index a6812a20cd..0000000000 --- a/core/src/main/resources/hudson/model/TreeView/ajaxRows.jelly +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - -

- - - - - - - - - -
- - diff --git a/core/src/main/resources/hudson/model/TreeView/main.jelly b/core/src/main/resources/hudson/model/TreeView/main.jelly deleted file mode 100644 index 0f14902005..0000000000 --- a/core/src/main/resources/hudson/model/TreeView/main.jelly +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/core/src/main/resources/hudson/model/TreeView/newView.jelly b/core/src/main/resources/hudson/model/TreeView/newView.jelly deleted file mode 100644 index 9f22b566ac..0000000000 --- a/core/src/main/resources/hudson/model/TreeView/newView.jelly +++ /dev/null @@ -1,26 +0,0 @@ - - - - \ No newline at end of file diff --git a/core/src/main/resources/hudson/model/TreeView/newViewDetail.jelly b/core/src/main/resources/hudson/model/TreeView/newViewDetail.jelly deleted file mode 100644 index b7c7ea1666..0000000000 --- a/core/src/main/resources/hudson/model/TreeView/newViewDetail.jelly +++ /dev/null @@ -1,28 +0,0 @@ - - - -
- Experimental: show hierarchical views -
\ No newline at end of file diff --git a/core/src/main/resources/hudson/model/TreeView/sidepanel2.jelly b/core/src/main/resources/hudson/model/TreeView/sidepanel2.jelly deleted file mode 100644 index dc3d0e7938..0000000000 --- a/core/src/main/resources/hudson/model/TreeView/sidepanel2.jelly +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - diff --git a/core/src/main/resources/hudson/model/TreeView/sidepanel2_bg.properties b/core/src/main/resources/hudson/model/TreeView/sidepanel2_bg.properties deleted file mode 100644 index 6c612eb9e6..0000000000 --- a/core/src/main/resources/hudson/model/TreeView/sidepanel2_bg.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Bulgarian translation: Copyright (c) 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. - -New\ View=\ - \u041d\u043e\u0432 \u0438\u0437\u0433\u043b\u0435\u0434 diff --git a/core/src/main/resources/hudson/model/TreeView/sidepanel2_da.properties b/core/src/main/resources/hudson/model/TreeView/sidepanel2_da.properties deleted file mode 100644 index 448476e662..0000000000 --- a/core/src/main/resources/hudson/model/TreeView/sidepanel2_da.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. Kohsuke Kawaguchi. Knud Poulsen. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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. - -New\ View=Ny visning diff --git a/core/src/main/resources/hudson/model/TreeView/sidepanel2_de.properties b/core/src/main/resources/hudson/model/TreeView/sidepanel2_de.properties deleted file mode 100644 index ce2c2658a4..0000000000 --- a/core/src/main/resources/hudson/model/TreeView/sidepanel2_de.properties +++ /dev/null @@ -1 +0,0 @@ -New\ View=Neue Ansicht diff --git a/core/src/main/resources/hudson/model/TreeView/sidepanel2_es.properties b/core/src/main/resources/hudson/model/TreeView/sidepanel2_es.properties deleted file mode 100644 index 4df3f2f531..0000000000 --- a/core/src/main/resources/hudson/model/TreeView/sidepanel2_es.properties +++ /dev/null @@ -1,23 +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. - -New\ View=Nueva vista diff --git a/core/src/main/resources/hudson/model/TreeView/sidepanel2_fr.properties b/core/src/main/resources/hudson/model/TreeView/sidepanel2_fr.properties deleted file mode 100644 index f4253389b6..0000000000 --- a/core/src/main/resources/hudson/model/TreeView/sidepanel2_fr.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Eric Lefevre-Ardant -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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. - -New\ View=Nouvelle vue diff --git a/core/src/main/resources/hudson/model/TreeView/sidepanel2_it.properties b/core/src/main/resources/hudson/model/TreeView/sidepanel2_it.properties deleted file mode 100644 index 260b76d71e..0000000000 --- a/core/src/main/resources/hudson/model/TreeView/sidepanel2_it.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Italian localization plugin for Jenkins -# Copyright © 2020 Alessandro Menti -# -# 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. - -New\ View=Nuova vista diff --git a/core/src/main/resources/hudson/model/TreeView/sidepanel2_ja.properties b/core/src/main/resources/hudson/model/TreeView/sidepanel2_ja.properties deleted file mode 100644 index 78f5e6bb32..0000000000 --- a/core/src/main/resources/hudson/model/TreeView/sidepanel2_ja.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -New\ View=\u65B0\u898F\u30D3\u30E5\u30FC diff --git a/core/src/main/resources/hudson/model/TreeView/sidepanel2_sr.properties b/core/src/main/resources/hudson/model/TreeView/sidepanel2_sr.properties deleted file mode 100644 index f8ec299e02..0000000000 --- a/core/src/main/resources/hudson/model/TreeView/sidepanel2_sr.properties +++ /dev/null @@ -1,3 +0,0 @@ -# This file is under the MIT License by authors - -New\ View=\u041D\u043E\u0432\u0438 \u043F\u0440\u0435\u0433\u043B\u0435\u0434 diff --git a/core/src/main/resources/hudson/model/TreeView/sidepanel2_zh_TW.properties b/core/src/main/resources/hudson/model/TreeView/sidepanel2_zh_TW.properties deleted file mode 100644 index 4d5595a242..0000000000 --- a/core/src/main/resources/hudson/model/TreeView/sidepanel2_zh_TW.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2013, Chunghwa Telecom Co., Ltd., Pei-Tang Huang -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -New\ View=\u65b0\u589e\u8996\u666f diff --git a/core/src/main/resources/hudson/model/UpdateCenter/sidepanel.jelly b/core/src/main/resources/hudson/model/UpdateCenter/sidepanel.jelly index d9625aa282..5f62d34583 100644 --- a/core/src/main/resources/hudson/model/UpdateCenter/sidepanel.jelly +++ b/core/src/main/resources/hudson/model/UpdateCenter/sidepanel.jelly @@ -31,7 +31,7 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/hudson/model/UsageStatistics/footer.jelly b/core/src/main/resources/hudson/model/UsageStatistics/footer.jelly index b532b3d746..1b0771b539 100644 --- a/core/src/main/resources/hudson/model/UsageStatistics/footer.jelly +++ b/core/src/main/resources/hudson/model/UsageStatistics/footer.jelly @@ -32,10 +32,13 @@ THE SOFTWARE. - + + + + diff --git a/core/src/main/resources/hudson/model/User/sidepanel.jelly b/core/src/main/resources/hudson/model/User/sidepanel.jelly index 46bad7a605..40d91da48b 100644 --- a/core/src/main/resources/hudson/model/User/sidepanel.jelly +++ b/core/src/main/resources/hudson/model/User/sidepanel.jelly @@ -34,7 +34,7 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/hudson/node_monitors/ClockMonitor/help.html b/core/src/main/resources/hudson/node_monitors/ClockMonitor/help.html index 31c27afba0..4311cc9b4f 100644 --- a/core/src/main/resources/hudson/node_monitors/ClockMonitor/help.html +++ b/core/src/main/resources/hudson/node_monitors/ClockMonitor/help.html @@ -1,5 +1,5 @@
- This monitors the clock difference between the master and nodes. + This monitors the clock difference between the controller and nodes. While Jenkins itself is generally capable of tolerating clock differences between systems, version control activities and distributed file access (such as NFS, Windows file shares) tend to have strange problems when systems involved have different clocks. diff --git a/core/src/main/resources/hudson/node_monitors/ResponseTimeMonitor/help.html b/core/src/main/resources/hudson/node_monitors/ResponseTimeMonitor/help.html index 5a6f27a412..977072ab4b 100644 --- a/core/src/main/resources/hudson/node_monitors/ResponseTimeMonitor/help.html +++ b/core/src/main/resources/hudson/node_monitors/ResponseTimeMonitor/help.html @@ -1,9 +1,9 @@
- This monitors the round trip network response time from the master to the agent, and if it + This monitors the round trip network response time from the controller to the agent, and if it goes above a threshold repeatedly, it marks the agent offline.

This is useful for detecting unresponsive agents, or other network problems that clog the - communication channel. More specifically, the master sends a no-op command to the agent, + communication channel. More specifically, the controller sends a no-op command to the agent, and checks the time it takes to get back the result of this no-op command.

\ No newline at end of file diff --git a/core/src/main/resources/hudson/node_monitors/TemporarySpaceMonitor/help.html b/core/src/main/resources/hudson/node_monitors/TemporarySpaceMonitor/help.html index d285370f91..a6626679f9 100644 --- a/core/src/main/resources/hudson/node_monitors/TemporarySpaceMonitor/help.html +++ b/core/src/main/resources/hudson/node_monitors/TemporarySpaceMonitor/help.html @@ -9,5 +9,5 @@

More specifically, it checks the available disk space of a partition that includes directory designated by the java.io.tmpdir system property. - To check where this directory is on a given agent, go to ${rootURL}/computer/SLAVENAME/systemInfo. + To check where this directory is on a given agent, go to ${rootURL}/computer/AGENTNAME/systemInfo.

\ No newline at end of file diff --git a/core/src/main/resources/hudson/node_monitors/TemporarySpaceMonitor/help_bg.html b/core/src/main/resources/hudson/node_monitors/TemporarySpaceMonitor/help_bg.html index 861a5d3e98..c2f38e2985 100644 --- a/core/src/main/resources/hudson/node_monitors/TemporarySpaceMonitor/help_bg.html +++ b/core/src/main/resources/hudson/node_monitors/TemporarySpaceMonitor/help_bg.html @@ -12,5 +12,5 @@ По-специално, проверката се извършва на файловата система, която съдържа директорията указвана от системното свойство „java.io.tmpdir“. За да проверите къде тя се намира на определена машина, прегледайте файла - „${rootURL}/computer/SLAVENAME/systemInfo“. + „${rootURL}/computer/AGENTNAME/systemInfo“.
diff --git a/core/src/main/resources/hudson/node_monitors/TemporarySpaceMonitor/help_ja.html b/core/src/main/resources/hudson/node_monitors/TemporarySpaceMonitor/help_ja.html index 9654d171ef..3a553569d7 100644 --- a/core/src/main/resources/hudson/node_monitors/TemporarySpaceMonitor/help_ja.html +++ b/core/src/main/resources/hudson/node_monitors/TemporarySpaceMonitor/help_ja.html @@ -7,5 +7,5 @@

もっと具体的に言うと、システムプロパティjava.io.tmpdirで指定されたディレクトリを含むパーティションの利用可能なディスク容量をチェックします。 - エージェントでのこのディレクトリが何であるかチェックするには、${rootURL}/computer/SLAVENAME/systemInfoを参照してください。 + エージェントでのこのディレクトリが何であるかチェックするには、${rootURL}/computer/AGENTNAME/systemInfoを参照してください。 \ No newline at end of file diff --git a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/index.jelly b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/index.jelly index 8a5fde08fe..9f1ab4374e 100644 --- a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/index.jelly +++ b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/index.jelly @@ -43,7 +43,7 @@ THE SOFTWARE. ${user.id} ${user} - + diff --git a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/sidepanel.jelly b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/sidepanel.jelly index 8e3c84edcc..eeb89b3e88 100644 --- a/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/sidepanel.jelly +++ b/core/src/main/resources/hudson/security/HudsonPrivateSecurityRealm/sidepanel.jelly @@ -28,7 +28,7 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/hudson/slaves/JNLPLauncher/help.properties b/core/src/main/resources/hudson/slaves/JNLPLauncher/help.properties index a14577f0f2..d49d20b0ed 100644 --- a/core/src/main/resources/hudson/slaves/JNLPLauncher/help.properties +++ b/core/src/main/resources/hudson/slaves/JNLPLauncher/help.properties @@ -21,14 +21,14 @@ # THE SOFTWARE. blurb=\ - Allows an agent to be connected to the Jenkins master whenever it is ready.
\ + Allows an agent to be connected to the Jenkins controller whenever it is ready.
\ In one mode, Java Web Start is used. \ In this case, a JNLP file must be opened on the agent machine, \ - which will establish a TCP connection to the Jenkins master. \ + which will establish a TCP connection to the Jenkins controller. \ (Other launch methods use a JNLP file but not Java Web Start, or do not use a JNLP file at all.)
\ - This means that the agent need not be reachable from the master; \ - the agent just needs to be able to reach the master. \ + This means that the agent need not be reachable from the controller; \ + the agent just needs to be able to reach the controller. \ If you have enabled security via the Configure Global Security page, \ - you can customize the port on which the Jenkins master will listen for incoming agent connections.
\ + you can customize the port on which the Jenkins controller will listen for incoming agent connections.
\ By default, the agent will launch a GUI, but it is also possible to run \ an agent without a GUI, for example as a Windows service. diff --git a/core/src/main/resources/hudson/slaves/Messages.properties b/core/src/main/resources/hudson/slaves/Messages.properties index e767585075..bf2dd8dc8f 100644 --- a/core/src/main/resources/hudson/slaves/Messages.properties +++ b/core/src/main/resources/hudson/slaves/Messages.properties @@ -23,7 +23,7 @@ RetentionStrategy.Always.displayName=Keep this agent online as much as possible RetentionStrategy.Demand.displayName=Bring this agent online when in demand, and take offline when idle RetentionStrategy.Demand.OfflineIdle=Offline because computer was idle; it will be relaunched when needed. -JNLPLauncher.displayName=Launch agent by connecting it to the master +JNLPLauncher.displayName=Launch agent by connecting it to the controller ComputerLauncher.unexpectedError=Unexpected error in launching an agent. This is probably a bug in Jenkins ComputerLauncher.abortedLaunch=Launching agent process aborted. ConnectionActivityMonitor.OfflineCause=Repeated ping attempts failed diff --git a/core/src/main/resources/hudson/tools/Messages.properties b/core/src/main/resources/hudson/tools/Messages.properties index 5eeb9f12f0..ab80fbb894 100644 --- a/core/src/main/resources/hudson/tools/Messages.properties +++ b/core/src/main/resources/hudson/tools/Messages.properties @@ -30,5 +30,5 @@ ZipExtractionInstaller.bad_connection=Server rejected connection. ZipExtractionInstaller.malformed_url=Malformed URL. ZipExtractionInstaller.could_not_connect=Could not connect to URL. InstallSourceProperty.DescriptorImpl.displayName=Install automatically -ToolDescriptor.NotADirectory={0} is not a directory on the Jenkins master (but perhaps it exists on some agents) +ToolDescriptor.NotADirectory={0} is not a directory on the Jenkins controller (but perhaps it exists on some agents) CannotBeInstalled=Installer "{0}" cannot be used to install "{1}" on the node "{2}" diff --git a/core/src/main/resources/hudson/tools/ZipExtractionInstaller/help-url.html b/core/src/main/resources/hudson/tools/ZipExtractionInstaller/help-url.html index 9637265029..f22666f219 100644 --- a/core/src/main/resources/hudson/tools/ZipExtractionInstaller/help-url.html +++ b/core/src/main/resources/hudson/tools/ZipExtractionInstaller/help-url.html @@ -3,5 +3,5 @@ Should be either a ZIP or a GZip-compressed TAR file. The timestamp on the server will be compared to the local version (if any) so you can publish updates easily. - The URL must be accessible from the Jenkins master but need not be accessible from agents. + The URL must be accessible from the Jenkins controller but need not be accessible from agents. diff --git a/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly b/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly index ad4d05280f..7b56363123 100644 --- a/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly +++ b/core/src/main/resources/hudson/widgets/HistoryWidget/index.jelly @@ -42,11 +42,11 @@ THE SOFTWARE. --> - + Atom feed ${%for all} - + Atom feed ${%for failures} diff --git a/core/src/main/resources/jenkins/diagnostics/ControllerExecutorsAgents/message.properties b/core/src/main/resources/jenkins/diagnostics/ControllerExecutorsAgents/message.properties index 0cbc65ecc0..b1dbea82dc 100644 --- a/core/src/main/resources/jenkins/diagnostics/ControllerExecutorsAgents/message.properties +++ b/core/src/main/resources/jenkins/diagnostics/ControllerExecutorsAgents/message.properties @@ -20,6 +20,7 @@ #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN #THE SOFTWARE. -ExecutorsWarning=Building on the controller node can be a security issue. \ - You should set the number of executors on the controller to 0. \ +ExecutorsWarning=Building on the built-in node can be a security issue. \ + You should set the number of executors on the built-in node to 0. \ See the documentation. +# TODO(terminology) rename redirect URL diff --git a/core/src/main/resources/jenkins/diagnostics/ControllerExecutorsNoAgents/message.properties b/core/src/main/resources/jenkins/diagnostics/ControllerExecutorsNoAgents/message.properties index eb387c79f4..7f981c08d6 100644 --- a/core/src/main/resources/jenkins/diagnostics/ControllerExecutorsNoAgents/message.properties +++ b/core/src/main/resources/jenkins/diagnostics/ControllerExecutorsNoAgents/message.properties @@ -20,6 +20,7 @@ #OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN #THE SOFTWARE. -ExecutorsWarning=Building on the controller node can be a security issue. \ +ExecutorsWarning=Building on the built-in node can be a security issue. \ You should set up distributed builds. \ See the documentation. +# TODO(terminology) rename redirect URL diff --git a/core/src/main/resources/jenkins/diagnostics/Messages.properties b/core/src/main/resources/jenkins/diagnostics/Messages.properties index 16097ded39..f6ccd27507 100644 --- a/core/src/main/resources/jenkins/diagnostics/Messages.properties +++ b/core/src/main/resources/jenkins/diagnostics/Messages.properties @@ -2,5 +2,5 @@ CompletedInitializationMonitor.DisplayName=Jenkins Initialization Monitor SecurityIsOffMonitor.DisplayName=Disabled Security URICheckEncodingMonitor.DisplayName=Check URI Encoding RootUrlNotSetMonitor.DisplayName=Root URL not configured Monitor -ControllerExecutorsNoAgents.DisplayName=Controller Without Agents Executors Configured Monitor -ControllerExecutorsAgents.DisplayName=Controller With Agents Executors Configured Monitor +ControllerExecutorsNoAgents.DisplayName=Built-in Node Without Agents Executors Configured Monitor +ControllerExecutorsAgents.DisplayName=Built-in Node With Agents Executors Configured Monitor diff --git a/core/src/main/resources/jenkins/management/ShutdownLink/index.groovy b/core/src/main/resources/jenkins/management/ShutdownLink/index.groovy index 252dbae1f4..8e06378860 100644 --- a/core/src/main/resources/jenkins/management/ShutdownLink/index.groovy +++ b/core/src/main/resources/jenkins/management/ShutdownLink/index.groovy @@ -10,7 +10,7 @@ l.layout(norefresh: true, permission: app.MANAGE, 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}/manage", title: _("Manage Jenkins")) + l.task(icon: "icon-gear icon-md", href: "${rootURL}/manage", title: _("Manage Jenkins")) } } l.main_panel { diff --git a/core/src/main/resources/jenkins/model/BuiltInNodeMigration/message.jelly b/core/src/main/resources/jenkins/model/BuiltInNodeMigration/message.jelly new file mode 100644 index 0000000000..82037ac2e4 --- /dev/null +++ b/core/src/main/resources/jenkins/model/BuiltInNodeMigration/message.jelly @@ -0,0 +1,10 @@ + + +

+
+ + + + ${%blurb} +
+ diff --git a/core/src/main/resources/jenkins/model/BuiltInNodeMigration/message.properties b/core/src/main/resources/jenkins/model/BuiltInNodeMigration/message.properties new file mode 100644 index 0000000000..10f3afcf7b --- /dev/null +++ b/core/src/main/resources/jenkins/model/BuiltInNodeMigration/message.properties @@ -0,0 +1,40 @@ +# The MIT License +# +# Copyright (c) 2021 Daniel Beck +# +# 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 = The word "master" is being retired as the term for the main Jenkins process and the built-in node. \ + The main process is now called "controller" and the built-in node is called just "built-in node". \ + The UI has been updated with these changes. \ + The following features are also affected: \ +
    \ +
  • The implicit label of the built-in node changes from master to built-in.
  • \ +
  • The built-in node''s NODE_NAME environment variable also changes from master to built-in.
  • \ +
\ + These changes could affect build behavior, so are not applied automatically. \ + Before you apply these changes, you should do the following: \ +
    \ +
  • Review label assignments in job configurations and tool installers for uses of master label. \ + Any such label assignments will not match the built-in node after migration. \ + Besides updating these assignments, you could also explicitly add the master label to the built-in node. \ +
  • \ +
  • Review use of the NODE_NAME environment variable in build scripts.
  • \ +
\ + Learn more. diff --git a/core/src/main/resources/jenkins/model/CoreEnvironmentContributor/buildEnv.properties b/core/src/main/resources/jenkins/model/CoreEnvironmentContributor/buildEnv.properties index 11c7828ddb..8373df3368 100644 --- a/core/src/main/resources/jenkins/model/CoreEnvironmentContributor/buildEnv.properties +++ b/core/src/main/resources/jenkins/model/CoreEnvironmentContributor/buildEnv.properties @@ -10,14 +10,14 @@ EXECUTOR_NUMBER.blurb=\ (among executors of the same machine) that\u2019s \ carrying out this build. This is the number you see in \ the "build executor status", except that the number starts from 0, not 1. -NODE_NAME.blurb=Name of the agent if the build is on an agent, or "master" if run on master. +NODE_NAME.blurb=Name of the agent if the build is on an agent, or "built-in" if run on the built-in node (or "master" until Jenkins 2.306). 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). \ Not defined when the regular workspace is a drive root. -JENKINS_HOME.blurb=The absolute path of the directory assigned on the master node for Jenkins to store data. +JENKINS_HOME.blurb=The absolute path of the directory assigned on the controller file system 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). JOB_URL.blurb=Full URL of this job, like http://server:port/jenkins/job/foo/ (Jenkins URL must be set). diff --git a/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index.groovy b/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index.groovy index 691fbe5bba..1e1a1249fa 100644 --- a/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index.groovy +++ b/core/src/main/resources/jenkins/model/GlobalCloudConfiguration/index.groovy @@ -13,7 +13,7 @@ l.layout(norefresh:true, permission:app.SYSTEM_READ, 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.task(icon:"icon-gear icon-md", href:"${rootURL}/computer/", title:_("Manage Nodes")) } } l.main_panel { diff --git a/core/src/main/resources/jenkins/model/Jenkins/MasterComputer/configure.jelly b/core/src/main/resources/jenkins/model/Jenkins/MasterComputer/configure.jelly index 883b6b6a3e..e40af4263a 100644 --- a/core/src/main/resources/jenkins/model/Jenkins/MasterComputer/configure.jelly +++ b/core/src/main/resources/jenkins/model/Jenkins/MasterComputer/configure.jelly @@ -50,7 +50,7 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/jenkins/model/MasterBuildConfiguration/config.groovy b/core/src/main/resources/jenkins/model/MasterBuildConfiguration/config.groovy index 9ad0aaa0c5..e0e2224df7 100644 --- a/core/src/main/resources/jenkins/model/MasterBuildConfiguration/config.groovy +++ b/core/src/main/resources/jenkins/model/MasterBuildConfiguration/config.groovy @@ -8,4 +8,4 @@ f.entry(title:_("# of executors"), field:"numExecutors") { f.entry(title:_("Labels"),field:"labelString") { f.textbox() } -f.slave_mode(name:"master.mode",node:app) +f.slave_mode(name:"builtin.mode",node:app) diff --git a/core/src/main/resources/jenkins/model/Messages.properties b/core/src/main/resources/jenkins/model/Messages.properties index c7c1d079c7..d5afb130ac 100644 --- a/core/src/main/resources/jenkins/model/Messages.properties +++ b/core/src/main/resources/jenkins/model/Messages.properties @@ -24,8 +24,8 @@ # THE SOFTWARE. Hudson.BadPortNumber=Bad port number {0} -Hudson.Computer.Caption=Master -Hudson.Computer.DisplayName=master +Hudson.Computer.Caption=Built-in Node +Hudson.Computer.DisplayName=Built-in Hudson.Computer.IncorrectNumberOfExecutors=Incorrect field "Number of executors". It should be a non-negative number. Hudson.ControlCodeNotAllowed=No control code is allowed: {0} Hudson.DisplayName=Jenkins @@ -41,7 +41,7 @@ Hudson.NotUsesUTF8ToDecodeURL=\ Your container doesn\u2019t use UTF-8 to decode URLs. If you use non-ASCII characters as a job name etc, \ this will cause problems. \ See Tomcat i18n for more details. -Hudson.NodeDescription=the master Jenkins node +Hudson.NodeDescription=the Jenkins controller''s built-in node CLI.restart.shortDescription=Restart Jenkins. CLI.safe-restart.shortDescription=Safely restart Jenkins. @@ -77,5 +77,7 @@ CLI.enable-job.shortDescription=Enables a job. GlobalCloudConfiguration.DisplayName=Configure Clouds +BuiltInNodeMigration.DisplayName=Built-In Node Name and Label Migration + SimpleGlobalBuildDiscarderStrategy.displayName=Specific Build Discarder JobGlobalBuildDiscarderStrategy.displayName=Project Build Discarder diff --git a/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchConfiguration/config.groovy b/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchConfiguration/config.groovy index ae486437d3..40d93c8fd9 100644 --- a/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchConfiguration/config.groovy +++ b/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchConfiguration/config.groovy @@ -4,7 +4,7 @@ def f=namespace(lib.FormTagLib) if (instance.isRelevant()) { f.section(title: _('Agent \u2192 Controller Security')) { - f.optionalBlock(field: "masterToSlaveAccessControl", title: _("Enable Agent \u2192 Controller Access Control")) { + f.optionalBlock(field: "agentToControllerAccessControl", title: _("Enable Agent \u2192 Controller Access Control")) { f.nested() { raw _("Rules can be tweaked here") } diff --git a/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchConfiguration/help-masterToSlaveAccessControl.html b/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchConfiguration/help-agentToControllerAccessControl.html similarity index 100% rename from core/src/main/resources/jenkins/security/s2m/MasterKillSwitchConfiguration/help-masterToSlaveAccessControl.html rename to core/src/main/resources/jenkins/security/s2m/MasterKillSwitchConfiguration/help-agentToControllerAccessControl.html diff --git a/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchConfiguration/help-masterToSlaveAccessControl_bg.html b/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchConfiguration/help-agentToControllerAccessControl_bg.html similarity index 100% rename from core/src/main/resources/jenkins/security/s2m/MasterKillSwitchConfiguration/help-masterToSlaveAccessControl_bg.html rename to core/src/main/resources/jenkins/security/s2m/MasterKillSwitchConfiguration/help-agentToControllerAccessControl_bg.html diff --git a/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchConfiguration/help-masterToSlaveAccessControl_it.html b/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchConfiguration/help-agentToControllerAccessControl_it.html similarity index 100% rename from core/src/main/resources/jenkins/security/s2m/MasterKillSwitchConfiguration/help-masterToSlaveAccessControl_it.html rename to core/src/main/resources/jenkins/security/s2m/MasterKillSwitchConfiguration/help-agentToControllerAccessControl_it.html diff --git a/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchWarning/message.properties b/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchWarning/message.properties index 0470434922..04be9aaf93 100644 --- a/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchWarning/message.properties +++ b/core/src/main/resources/jenkins/security/s2m/MasterKillSwitchWarning/message.properties @@ -1,2 +1,2 @@ -blurb=Agent to master security subsystem is currently off. \ +blurb=Agent to controller security subsystem is currently off. \ Please read the documentation and consider turning it on. diff --git a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol4/description.properties b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol4/description.properties index 9cf2b4b2f8..4ecb60357f 100644 --- a/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol4/description.properties +++ b/core/src/main/resources/jenkins/slaves/JnlpSlaveAgentProtocol4/description.properties @@ -1 +1 @@ -summary=A TLS secured connection between the master and the agent performed by TLS upgrade of the socket. +summary=A TLS secured connection between the controller and the agent performed by TLS upgrade of the socket. diff --git a/core/src/main/resources/jenkins/tools/GlobalToolConfiguration/index.groovy b/core/src/main/resources/jenkins/tools/GlobalToolConfiguration/index.groovy index 3223e22562..ab82331bda 100644 --- a/core/src/main/resources/jenkins/tools/GlobalToolConfiguration/index.groovy +++ b/core/src/main/resources/jenkins/tools/GlobalToolConfiguration/index.groovy @@ -11,7 +11,7 @@ l.layout(permission:app.SYSTEM_READ, 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}/manage", title:_("Manage Jenkins")) + l.task(icon:"icon-gear icon-md", href:"${rootURL}/manage", title:_("Manage Jenkins")) } } set("readOnlyMode", !app.hasPermission(app.ADMINISTER)) diff --git a/core/src/main/resources/jenkins/triggers/ReverseBuildTrigger/config.jelly b/core/src/main/resources/jenkins/triggers/ReverseBuildTrigger/config.jelly index 3a3ddd8e62..7b048f8350 100644 --- a/core/src/main/resources/jenkins/triggers/ReverseBuildTrigger/config.jelly +++ b/core/src/main/resources/jenkins/triggers/ReverseBuildTrigger/config.jelly @@ -40,4 +40,8 @@ THE SOFTWARE. + + + diff --git a/core/src/main/resources/lib/hudson/buildCaption.jelly b/core/src/main/resources/lib/hudson/buildCaption.jelly index 4193d4a169..feb3c13934 100644 --- a/core/src/main/resources/lib/hudson/buildCaption.jelly +++ b/core/src/main/resources/lib/hudson/buildCaption.jelly @@ -43,7 +43,7 @@ THE SOFTWARE. - + - - + + + + diff --git a/core/src/main/resources/lib/hudson/editableDescription.jelly b/core/src/main/resources/lib/hudson/editableDescription.jelly index 585b844c2b..7517833b57 100644 --- a/core/src/main/resources/lib/hudson/editableDescription.jelly +++ b/core/src/main/resources/lib/hudson/editableDescription.jelly @@ -40,17 +40,21 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/hudson/model/TreeView/sidepanel2_pt_BR.properties b/core/src/main/resources/lib/hudson/editableDescription.properties similarity index 90% rename from core/src/main/resources/hudson/model/TreeView/sidepanel2_pt_BR.properties rename to core/src/main/resources/lib/hudson/editableDescription.properties index 6054ccefe2..0d5b672a9b 100644 --- a/core/src/main/resources/hudson/model/TreeView/sidepanel2_pt_BR.properties +++ b/core/src/main/resources/lib/hudson/editableDescription.properties @@ -1,6 +1,6 @@ # The MIT License # -# Copyright (c) 2004-2010, Sun Microsystems, Inc., Cleiber Silva +# Copyright (c) 2021, Jenkins 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 @@ -20,4 +20,5 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -New\ View=Nova view +add\ description=Add description +edit\ description=Edit description diff --git a/core/src/main/resources/lib/hudson/executors.properties b/core/src/main/resources/lib/hudson/executors.properties index d21742283c..951d07ec26 100644 --- a/core/src/main/resources/lib/hudson/executors.properties +++ b/core/src/main/resources/lib/hudson/executors.properties @@ -1,3 +1,4 @@ -Computers=master{0,choice,0#|1# + {0,number} computer ({1} of {2} executors)|1< + {0,number} computers ({1} of {2} executors)} +# TODO This label should distinguish between having and not having executors on the built-in node +Computers=built-in node{0,choice,0# ({1} of {2} executors busy)|1# + {0,number} agent ({1} of {2} executors busy)|1< + {0,number} agents ({1} of {2} executors busy)} confirm=Are you sure you want to abort {0}? launching=launching... diff --git a/core/src/main/resources/lib/hudson/iconSize.jelly b/core/src/main/resources/lib/hudson/iconSize.jelly index 4dd5fbeff1..1fbb33d8c9 100644 --- a/core/src/main/resources/lib/hudson/iconSize.jelly +++ b/core/src/main/resources/lib/hudson/iconSize.jelly @@ -23,30 +23,40 @@ THE SOFTWARE. --> - - - - - - - - - ${title} - - - ${title} - - - - + +
+ + + + + +
  • + ${title.charAt(0)}${title.substring(1)} +
  • +
    + +
  • + + ${title.charAt(0)}${title.substring(1)} + +
  • +
    +
    +
    +
    -
    - -
    ${%Icon}: +
    + ${%Icon}: +
      -
    - -
    + + + +
    + +
    +
    diff --git a/core/src/main/resources/lib/hudson/iconSize.properties b/core/src/main/resources/lib/hudson/iconSize.properties index d4292959f9..517fa42843 100644 --- a/core/src/main/resources/lib/hudson/iconSize.properties +++ b/core/src/main/resources/lib/hudson/iconSize.properties @@ -21,6 +21,6 @@ # THE SOFTWARE. Icon=Icon -S=S -M=M -L=L +S=Small +M=Medium +L=Large diff --git a/core/src/main/resources/lib/hudson/node.jelly b/core/src/main/resources/lib/hudson/node.jelly index d6a74ede8b..db88102acb 100644 --- a/core/src/main/resources/lib/hudson/node.jelly +++ b/core/src/main/resources/lib/hudson/node.jelly @@ -37,7 +37,7 @@ THE SOFTWARE. ${valueStr} - ${%master} + ${%builtin} \ No newline at end of file diff --git a/core/src/main/resources/lib/hudson/node_bg.properties b/core/src/main/resources/lib/hudson/node_bg.properties deleted file mode 100644 index 1b8e9a626e..0000000000 --- a/core/src/main/resources/lib/hudson/node_bg.properties +++ /dev/null @@ -1,24 +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. - -master=\ - \u0423\u043f\u0440\u0430\u0432\u043b\u044f\u0432\u0430\u0449 \u043a\u043e\u043c\u043f\u044e\u0442\u044a\u0440 diff --git a/core/src/main/resources/lib/hudson/node_da.properties b/core/src/main/resources/lib/hudson/node_da.properties deleted file mode 100644 index 199e3db8bc..0000000000 --- a/core/src/main/resources/lib/hudson/node_da.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2010, Sun Microsystems, Inc. Kohsuke Kawaguchi. Knud Poulsen. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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. - -master=master diff --git a/core/src/main/resources/lib/hudson/node_de.properties b/core/src/main/resources/lib/hudson/node_de.properties deleted file mode 100644 index 7871885968..0000000000 --- a/core/src/main/resources/lib/hudson/node_de.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Simon Wiest -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -master=Master diff --git a/core/src/main/resources/lib/hudson/node_es.properties b/core/src/main/resources/lib/hudson/node_es.properties deleted file mode 100644 index 9269e6a688..0000000000 --- a/core/src/main/resources/lib/hudson/node_es.properties +++ /dev/null @@ -1,23 +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. - -master=principal diff --git a/core/src/main/resources/lib/hudson/node_fr.properties b/core/src/main/resources/lib/hudson/node_fr.properties deleted file mode 100644 index 8d98360c00..0000000000 --- a/core/src/main/resources/lib/hudson/node_fr.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Eric Lefevre-Ardant -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# 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. - -master=maître diff --git a/core/src/main/resources/lib/hudson/node_he.properties b/core/src/main/resources/lib/hudson/node_he.properties deleted file mode 100644 index 9af9d68d6e..0000000000 --- a/core/src/main/resources/lib/hudson/node_he.properties +++ /dev/null @@ -1,3 +0,0 @@ -# This file is under the MIT License by authors - -master=\u05E8\u05D0\u05E9\u05D9 diff --git a/core/src/main/resources/lib/hudson/node_it.properties b/core/src/main/resources/lib/hudson/node_it.properties deleted file mode 100644 index 27f0451747..0000000000 --- a/core/src/main/resources/lib/hudson/node_it.properties +++ /dev/null @@ -1,24 +0,0 @@ -# The MIT License -# -# Italian localization plugin for Jenkins -# Copyright © 2020 Alessandro Menti -# -# 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. - -master=master diff --git a/core/src/main/resources/lib/hudson/node_ja.properties b/core/src/main/resources/lib/hudson/node_ja.properties deleted file mode 100644 index 9fe631574c..0000000000 --- a/core/src/main/resources/lib/hudson/node_ja.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2011, Sun Microsystems, Inc., Kohsuke Kawaguchi, Seiji Sogabe -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -master=master diff --git a/core/src/main/resources/lib/hudson/node_ko.properties b/core/src/main/resources/lib/hudson/node_ko.properties deleted file mode 100644 index 4754bdb4f5..0000000000 --- a/core/src/main/resources/lib/hudson/node_ko.properties +++ /dev/null @@ -1,3 +0,0 @@ -# This file is under the MIT License by authors - -master=\uB9C8\uC2A4\uD130 diff --git a/core/src/main/resources/lib/hudson/node_lv.properties b/core/src/main/resources/lib/hudson/node_lv.properties deleted file mode 100644 index f17c6857dc..0000000000 --- a/core/src/main/resources/lib/hudson/node_lv.properties +++ /dev/null @@ -1,23 +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. - -master=master diff --git a/core/src/main/resources/lib/hudson/node_nb_NO.properties b/core/src/main/resources/lib/hudson/node_nb_NO.properties deleted file mode 100644 index f17c6857dc..0000000000 --- a/core/src/main/resources/lib/hudson/node_nb_NO.properties +++ /dev/null @@ -1,23 +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. - -master=master diff --git a/core/src/main/resources/lib/hudson/node_nl.properties b/core/src/main/resources/lib/hudson/node_nl.properties deleted file mode 100644 index 0b6e6f9046..0000000000 --- a/core/src/main/resources/lib/hudson/node_nl.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, id:sorokh -# -# 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. - -master=hoofdnode diff --git a/core/src/main/resources/lib/hudson/node_pl.properties b/core/src/main/resources/lib/hudson/node_pl.properties deleted file mode 100644 index c71caf50dc..0000000000 --- a/core/src/main/resources/lib/hudson/node_pl.properties +++ /dev/null @@ -1,23 +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. - -master= diff --git a/core/src/main/resources/lib/hudson/node_pt_BR.properties b/core/src/main/resources/lib/hudson/node_pt_BR.properties deleted file mode 100644 index c9b0c63452..0000000000 --- a/core/src/main/resources/lib/hudson/node_pt_BR.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Reginaldo L. Russinholi, Cleiber Silva, Fernando Boaglio -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -master=master diff --git a/core/src/main/resources/lib/hudson/node_ru.properties b/core/src/main/resources/lib/hudson/node_ru.properties deleted file mode 100644 index d16173a4b5..0000000000 --- a/core/src/main/resources/lib/hudson/node_ru.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Mike Salnikov -# -# 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. - -master=\u0413\u043b\u0430\u0432\u043d\u044b\u0439 diff --git a/core/src/main/resources/lib/hudson/node_sk.properties b/core/src/main/resources/lib/hudson/node_sk.properties deleted file mode 100644 index 0c7115d8f5..0000000000 --- a/core/src/main/resources/lib/hudson/node_sk.properties +++ /dev/null @@ -1,3 +0,0 @@ -# This file is under the MIT License by authors - -master=velite\u013E diff --git a/core/src/main/resources/lib/hudson/node_sr.properties b/core/src/main/resources/lib/hudson/node_sr.properties deleted file mode 100644 index e2aa681592..0000000000 --- a/core/src/main/resources/lib/hudson/node_sr.properties +++ /dev/null @@ -1,3 +0,0 @@ -# This file is under the MIT License by authors - -master=\u043C\u0430\u0441\u0442\u0435\u0440 diff --git a/core/src/main/resources/lib/hudson/node_tr.properties b/core/src/main/resources/lib/hudson/node_tr.properties deleted file mode 100644 index 9cdc1f395f..0000000000 --- a/core/src/main/resources/lib/hudson/node_tr.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi, Oguz Dag -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -master= diff --git a/core/src/main/resources/lib/hudson/node_uk.properties b/core/src/main/resources/lib/hudson/node_uk.properties deleted file mode 100644 index a77f2faefb..0000000000 --- a/core/src/main/resources/lib/hudson/node_uk.properties +++ /dev/null @@ -1,23 +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. - -master=\u0433\u043E\u043B\u043E\u0432\u043D\u043E\u043C\u0443 diff --git a/core/src/main/resources/lib/hudson/node_zh_TW.properties b/core/src/main/resources/lib/hudson/node_zh_TW.properties deleted file mode 100644 index 565e2cb800..0000000000 --- a/core/src/main/resources/lib/hudson/node_zh_TW.properties +++ /dev/null @@ -1,23 +0,0 @@ -# The MIT License -# -# Copyright (c) 2013, Chunghwa Telecom Co., Ltd., Pei-Tang Huang -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -master=master diff --git a/core/src/main/resources/lib/hudson/project/configurable.jelly b/core/src/main/resources/lib/hudson/project/configurable.jelly index 91569d4f82..eacf85006e 100644 --- a/core/src/main/resources/lib/hudson/project/configurable.jelly +++ b/core/src/main/resources/lib/hudson/project/configurable.jelly @@ -38,10 +38,10 @@ THE SOFTWARE. - + - + diff --git a/core/src/main/resources/lib/hudson/project/console-link.jelly b/core/src/main/resources/lib/hudson/project/console-link.jelly index 646313aad3..97ddb9d9aa 100644 --- a/core/src/main/resources/lib/hudson/project/console-link.jelly +++ b/core/src/main/resources/lib/hudson/project/console-link.jelly @@ -32,7 +32,7 @@ THE SOFTWARE. - + diff --git a/core/src/main/resources/lib/hudson/rssBar.jelly b/core/src/main/resources/lib/hudson/rssBar.jelly index dcd9842c86..734cc36f5d 100644 --- a/core/src/main/resources/lib/hudson/rssBar.jelly +++ b/core/src/main/resources/lib/hudson/rssBar.jelly @@ -25,39 +25,31 @@ THE SOFTWARE. - diff --git a/core/src/main/resources/lib/hudson/rssBar.properties b/core/src/main/resources/lib/hudson/rssBar.properties new file mode 100644 index 0000000000..b48bf0b490 --- /dev/null +++ b/core/src/main/resources/lib/hudson/rssBar.properties @@ -0,0 +1 @@ +Legend=Icon legend diff --git a/core/src/main/resources/lib/layout/breadcrumbs.css b/core/src/main/resources/lib/layout/breadcrumbs.css index b9d0840a5c..f808e93864 100644 --- a/core/src/main/resources/lib/layout/breadcrumbs.css +++ b/core/src/main/resources/lib/layout/breadcrumbs.css @@ -18,7 +18,7 @@ min-height: 2.5rem; font-size: 1rem; line-height: 1.5; - padding: 0 1.25rem; + padding: 0 0.7rem; background-color: #F8F8F8; background-color: var(--breadcrumbs-bg); } @@ -100,7 +100,7 @@ #breadcrumbs LI.children:after, #breadcrumbs LI.separator:after { /* Right arrow */ content: ""; - border-left: 0.25em solid #bcbcbc; + border-left: 0.25em solid currentColor; border-top: 0.25em solid transparent; border-bottom: 0.25em solid transparent; border-right: 0; diff --git a/core/src/main/resources/lib/layout/icon.jelly b/core/src/main/resources/lib/layout/icon.jelly index 1f6eec8a42..e4b4c47b2e 100644 --- a/core/src/main/resources/lib/layout/icon.jelly +++ b/core/src/main/resources/lib/layout/icon.jelly @@ -70,9 +70,9 @@ THE SOFTWARE. - + - + diff --git a/core/src/main/resources/lib/layout/layout.properties b/core/src/main/resources/lib/layout/layout.properties index 84295a04e9..35e647a0c0 100644 --- a/core/src/main/resources/lib/layout/layout.properties +++ b/core/src/main/resources/lib/layout/layout.properties @@ -25,3 +25,4 @@ searchBox.url=https://www.jenkins.io/redirect/search-box logout=log out title=Jenkins jenkinshead.alt=Jenkins +search=Search \ No newline at end of file diff --git a/core/src/main/resources/lib/layout/pageHeader.jelly b/core/src/main/resources/lib/layout/pageHeader.jelly index 6b4933f399..987142bb62 100644 --- a/core/src/main/resources/lib/layout/pageHeader.jelly +++ b/core/src/main/resources/lib/layout/pageHeader.jelly @@ -31,7 +31,7 @@ diff --git a/core/src/test/java/hudson/FilePathTest.java b/core/src/test/java/hudson/FilePathTest.java index 146198acd1..aa09e2f204 100644 --- a/core/src/test/java/hudson/FilePathTest.java +++ b/core/src/test/java/hudson/FilePathTest.java @@ -82,7 +82,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import static org.junit.Assume.assumeTrue; import static org.mockito.Mockito.mock; @@ -164,49 +163,44 @@ public class FilePathTest { private List> whenFileIsCopied100TimesConcurrently(final File file) throws InterruptedException { List> r = new ArrayList<>(); for (int i=0; i<100; i++) { - r.add(new Callable() { - @Override - public Integer call() throws Exception { - class Sink extends OutputStream { - private Exception closed; - private final AtomicInteger count = new AtomicInteger(); + r.add(() -> { + class Sink extends OutputStream { + private Exception closed; + private final AtomicInteger count = new AtomicInteger(); - private void checkNotClosed() throws IOException { - if (closed != null) - throw new IOException(closed); - } - - @Override - public void write(int b) throws IOException { - count.incrementAndGet(); - checkNotClosed(); - } - - @Override - public void write(byte[] b) throws IOException { - count.addAndGet(b.length); - checkNotClosed(); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - count.addAndGet(len); - checkNotClosed(); - } - - @Override - public void close() throws IOException { - closed = new Exception(); - //if (size!=count) - // fail(); - } + private void checkNotClosed() throws IOException { + if (closed != null) + throw new IOException(closed); } - FilePath f = new FilePath(channels.french, file.getPath()); - Sink sink = new Sink(); - f.copyTo(sink); - return sink.count.get(); + @Override + public void write(int b) throws IOException { + count.incrementAndGet(); + checkNotClosed(); + } + + @Override + public void write(byte[] b) throws IOException { + count.addAndGet(b.length); + checkNotClosed(); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + count.addAndGet(len); + checkNotClosed(); + } + + @Override + public void close() throws IOException { + closed = new Exception(); + } } + + FilePath f = new FilePath(channels.french, file.getPath()); + Sink sink = new Sink(); + f.copyTo(sink); + return sink.count.get(); }); } @@ -571,12 +565,7 @@ public class FilePathTest { assertNull(d.validateAntFileMask("d1/d2/**/f.txt")); assertNull(d.validateAntFileMask("d1/d2/**/f.txt", 10)); assertEquals(Messages.FilePath_validateAntFileMask_portionMatchButPreviousNotMatchAndSuggest("**/*.js", "**", "**/*.js"), d.validateAntFileMask("**/*.js", 1000)); - try { - d.validateAntFileMask("**/*.js", 10); - fail(); - } catch (InterruptedException x) { - // good - } + assertThrows(InterruptedException.class, () -> d.validateAntFileMask("**/*.js", 10)); } @Issue("JENKINS-5253") @@ -789,12 +778,8 @@ public class FilePathTest { File f = temp.newFolder("folder"); FilePath fp = new FilePath(f); int invalidMode = 01770; // Full permissions for owner and group plus sticky bit. - try { - chmodAndMode(fp, invalidMode); - fail("Setting sticky bit should fail"); - } catch (IOException e) { - assertEquals("Invalid mode: " + invalidMode, e.getMessage()); - } + final IOException e = assertThrows("Setting sticky bit should fail", IOException.class, () -> chmodAndMode(fp, invalidMode)); + assertEquals("Invalid mode: " + invalidMode, e.getMessage()); } private int chmodAndMode(FilePath path, int mode) throws Exception { diff --git a/core/src/test/java/hudson/PluginManagerTest.java b/core/src/test/java/hudson/PluginManagerTest.java index d4080da9af..5d460ae7f0 100644 --- a/core/src/test/java/hudson/PluginManagerTest.java +++ b/core/src/test/java/hudson/PluginManagerTest.java @@ -48,7 +48,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsInstanceOf.instanceOf; import static org.hamcrest.core.StringContains.containsString; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * Tests of {@link PluginManager}. @@ -81,14 +81,11 @@ public class PluginManagerTest { "\n"; PluginManager pluginManager = new LocalPluginManager(Util.createTempDir()); - try { - pluginManager.parseRequestedPlugins(new StringInputStream(evilXML)); - fail("XML contains an external entity, but no exception was thrown."); - } - catch (IOException ex) { - assertThat(ex.getCause(), instanceOf(SAXException.class)); - assertThat(ex.getCause().getMessage(), containsString("Refusing to resolve entity with publicId(null) and systemId (file:///)")); - } + final IOException ex = assertThrows(IOException.class, + () -> pluginManager.parseRequestedPlugins(new StringInputStream(evilXML)), + "XML contains an external entity, but no exception was thrown."); + assertThat(ex.getCause(), instanceOf(SAXException.class)); + assertThat(ex.getCause().getMessage(), containsString("Refusing to resolve entity with publicId(null) and systemId (file:///)")); } @Test diff --git a/core/src/test/java/hudson/PluginWrapperTest.java b/core/src/test/java/hudson/PluginWrapperTest.java index 5fc7795de4..58e896cfcf 100644 --- a/core/src/test/java/hudson/PluginWrapperTest.java +++ b/core/src/test/java/hudson/PluginWrapperTest.java @@ -13,7 +13,6 @@ import jenkins.model.Jenkins; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.jvnet.hudson.test.Issue; @@ -22,8 +21,8 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -65,47 +64,35 @@ public class PluginWrapperTest { @Test public void jenkinsCoreTooOld() { PluginWrapper pw = pluginWrapper("fake").requiredCoreVersion("3.0").buildLoaded(); - try { - pw.resolvePluginDependencies(); - fail(); - } catch (IOException ex) { - assertContains(ex, "Failed to load: fake (42)", "Jenkins (3.0) or higher required"); - } + + final IOException ex = assertThrows(IOException.class, pw::resolvePluginDependencies); + assertContains(ex, "Failed to load: fake (42)", "Jenkins (3.0) or higher required"); } @Test public void dependencyNotInstalled() { PluginWrapper pw = pluginWrapper("dependee").deps("dependency:42").buildLoaded(); - try { - pw.resolvePluginDependencies(); - fail(); - } catch (IOException ex) { - assertContains(ex, "Failed to load: dependee (42)", "Plugin is missing: dependency (42)"); - } + + final IOException ex = assertThrows(IOException.class, pw::resolvePluginDependencies); + assertContains(ex, "Failed to load: dependee (42)", "Plugin is missing: dependency (42)"); } @Test public void dependencyOutdated() { pluginWrapper("dependency").version("3").buildLoaded(); PluginWrapper pw = pluginWrapper("dependee").deps("dependency:5").buildLoaded(); - try { - pw.resolvePluginDependencies(); - fail(); - } catch (IOException ex) { - assertContains(ex, "Failed to load: dependee (42)", "Update required: dependency (3) to be updated to 5 or higher"); - } + + final IOException ex = assertThrows(IOException.class, pw::resolvePluginDependencies); + assertContains(ex, "Failed to load: dependee (42)", "Update required: dependency (3) to be updated to 5 or higher"); } @Test public void dependencyFailedToLoad() { pluginWrapper("dependency").version("5").buildFailed(); PluginWrapper pw = pluginWrapper("dependee").deps("dependency:3").buildLoaded(); - try { - pw.resolvePluginDependencies(); - fail(); - } catch (IOException ex) { - assertContains(ex, "Failed to load: dependee (42)", "Failed to load: dependency (5)"); - } + + final IOException ex = assertThrows(IOException.class, pw::resolvePluginDependencies); + assertContains(ex, "Failed to load: dependee (42)", "Failed to load: dependency (5)"); } private void assertContains(Throwable ex, String... patterns) { @@ -123,18 +110,15 @@ public class PluginWrapperTest { private final HashMap plugins = new HashMap<>(); private final PluginManager pm = mock(PluginManager.class); { - when(pm.getPlugin(any(String.class))).thenAnswer(new Answer() { - @Override public PluginWrapper answer(InvocationOnMock invocation) throws Throwable { - return plugins.get(invocation.getArguments()[0]); - } - }); + when(pm.getPlugin(any(String.class))).thenAnswer((Answer) invocation -> plugins.get(invocation.getArguments()[0])); } + private final class PluginWrapperBuilder { - private String name; + private final String name; private String version = "42"; private String requiredCoreVersion = "1.0"; - private List deps = new ArrayList<>(); - private List optDeps = new ArrayList<>(); + private final List deps = new ArrayList<>(); + private final List optDeps = new ArrayList<>(); private PluginWrapperBuilder(String name) { this.name = name; @@ -157,13 +141,6 @@ public class PluginWrapperTest { return this; } - public PluginWrapperBuilder optDeps(String... optDeps) { - for (String dep: optDeps) { - this.optDeps.add(new PluginWrapper.Dependency(dep)); - } - return this; - } - private PluginWrapper buildLoaded() { PluginWrapper pw = build(); plugins.put(name, pw); diff --git a/core/src/test/java/hudson/UtilTest.java b/core/src/test/java/hudson/UtilTest.java index 2222543c0f..e01f735275 100644 --- a/core/src/test/java/hudson/UtilTest.java +++ b/core/src/test/java/hudson/UtilTest.java @@ -175,6 +175,26 @@ public class UtilTest { } } + /** + * Test the fullEncode() method. + */ + @Test + public void testFullEncode(){ + String[] data = { + "abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", + "01234567890!@$&*()-_=+',.", "01234567890%21%40%24%26%2A%28%29%2D%5F%3D%2B%27%2C%2E", + " \"#%/:;<>?", "%20%22%23%25%2F%3A%3B%3C%3E%3F", + "[\\]^`{|}~", "%5B%5C%5D%5E%60%7B%7C%7D%7E", + "d\u00E9velopp\u00E9s", "d%C3%A9velopp%C3%A9s", + "Foo \uD800\uDF98 Foo", "Foo%20%F0%90%8E%98%20Foo", + "\u00E9 ", "%C3%A9%20" + }; + for (int i = 0; i < data.length; i += 2) { + assertEquals("test " + i, data[i + 1], Util.fullEncode(data[i])); + } + } + /** * Test the tryParseNumber() method. */ @@ -599,9 +619,7 @@ public class UtilTest { @Test public void ifOverriddenFailure() { - AbstractMethodError error = Assert.assertThrows(AbstractMethodError.class, () -> { - Util.ifOverridden(() -> true, BaseClass.class, DerivedClassFailure.class, "method"); - }); + AbstractMethodError error = Assert.assertThrows(AbstractMethodError.class, () -> Util.ifOverridden(() -> true, BaseClass.class, DerivedClassFailure.class, "method")); assertEquals("The class " + DerivedClassFailure.class.getName() + " must override at least one of the BaseClass.method methods", error.getMessage()); } diff --git a/core/src/test/java/hudson/XmlFileTest.java b/core/src/test/java/hudson/XmlFileTest.java index c8d8b9f3c1..e208c48440 100644 --- a/core/src/test/java/hudson/XmlFileTest.java +++ b/core/src/test/java/hudson/XmlFileTest.java @@ -42,7 +42,7 @@ public class XmlFileTest { XmlFile xmlFile = new XmlFile(xs, new File(configUrl.getFile())); if (xmlFile.exists()) { - assertThrows(SAXParseException.class, () -> xmlFile.read()); + assertThrows(SAXParseException.class, xmlFile::read); } } diff --git a/core/src/test/java/hudson/cli/ListJobsCommandTest.java b/core/src/test/java/hudson/cli/ListJobsCommandTest.java index fff904545e..ba90445345 100644 --- a/core/src/test/java/hudson/cli/ListJobsCommandTest.java +++ b/core/src/test/java/hudson/cli/ListJobsCommandTest.java @@ -4,7 +4,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertThrows; import static org.powermock.api.mockito.PowerMockito.mock; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.when; @@ -20,7 +20,6 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; - import jenkins.model.Jenkins; import org.hamcrest.Description; @@ -57,17 +56,13 @@ public class ListJobsCommandTest { } @Test - public void failForNonexistingName() throws Exception { + public void failForNonexistentName() { when(jenkins.getView("NoSuchViewOrItemGroup")).thenReturn(null); when(jenkins.getItemByFullName("NoSuchViewOrItemGroup")).thenReturn(null); - try { - runWith("NoSuchViewOrItemGroup"); - fail("Exception should be thrown in the previous call."); - } catch (IllegalArgumentException e) { // Expected - assertThat(e.getMessage(), containsString("No view or item group with the given name 'NoSuchViewOrItemGroup' found.")); - } + final IllegalArgumentException e = assertThrows(IllegalArgumentException.class, () -> runWith("NoSuchViewOrItemGroup")); + assertThat(e.getMessage(), containsString("No view or item group with the given name 'NoSuchViewOrItemGroup' found.")); assertThat(stdout, is(empty())); } diff --git a/core/src/test/java/hudson/cli/handlers/ViewOptionHandlerTest.java b/core/src/test/java/hudson/cli/handlers/ViewOptionHandlerTest.java index 474444da1a..a27716b0cb 100644 --- a/core/src/test/java/hudson/cli/handlers/ViewOptionHandlerTest.java +++ b/core/src/test/java/hudson/cli/handlers/ViewOptionHandlerTest.java @@ -25,6 +25,7 @@ package hudson.cli.handlers; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.fail; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.verify; @@ -179,22 +180,15 @@ public class ViewOptionHandlerTest { } @Test public void reportViewSpaceNameRequestAsIAE() { - try { - assertNull(handler.getView(" ")); - fail("No exception thrown. Expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - assertEquals("No view named inside view Jenkins", e.getMessage()); - verifyNoInteractions(setter); - } + final IllegalArgumentException e = assertThrows("No exception thrown. Expected IllegalArgumentException", + IllegalArgumentException.class, () -> assertNull(handler.getView(" "))); + assertEquals("No view named inside view Jenkins", e.getMessage()); + verifyNoInteractions(setter); } @Test public void reportNullViewAsNPE() { - try { - handler.getView(null); - fail("No exception thrown. Expected NullPointerException"); - } catch (NullPointerException e) { - verifyNoInteractions(setter); - } + assertThrows(NullPointerException.class, () -> handler.getView(null)); + verifyNoInteractions(setter); } @Test public void refuseToReadOuterView() throws Exception { diff --git a/core/src/test/java/hudson/model/AbstractItemTest.java b/core/src/test/java/hudson/model/AbstractItemTest.java index 09894a1732..f6d4cab179 100644 --- a/core/src/test/java/hudson/model/AbstractItemTest.java +++ b/core/src/test/java/hudson/model/AbstractItemTest.java @@ -2,7 +2,7 @@ package hudson.model; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertThrows; import java.io.IOException; import java.util.Collection; @@ -115,15 +115,11 @@ public class AbstractItemTest { NameNotEditableItem item = new NameNotEditableItem(null,"NameNotEditableItem"); //WHEN - try { - item.renameTo("NewName"); - fail("An item with isNameEditable false must throw exception when trying to rename it."); - } catch (IOException e) { + final IOException e = assertThrows("An item with isNameEditable false must throw exception when trying to rename it.", + IOException.class, () -> item.renameTo("NewName")); - //THEN - assertEquals("Trying to rename an item that does not support this operation.", e.getMessage()); - assertEquals("NameNotEditableItem",item.getName()); - } + assertEquals("Trying to rename an item that does not support this operation.", e.getMessage()); + assertEquals("NameNotEditableItem", item.getName()); } @Test @@ -134,15 +130,10 @@ public class AbstractItemTest { NameNotEditableItem item = new NameNotEditableItem(null,"NameNotEditableItem"); //WHEN - try { - item.doConfirmRename("MyNewName"); - fail("An item with isNameEditable false must throw exception when trying to call doConfirmRename."); - } catch (Failure f) { - - //THEN - assertEquals("Trying to rename an item that does not support this operation.", f.getMessage()); - assertEquals("NameNotEditableItem",item.getName()); - } + final Failure f = assertThrows("An item with isNameEditable false must throw exception when trying to call doConfirmRename.", + Failure.class, () -> item.doConfirmRename("MyNewName")); + assertEquals("Trying to rename an item that does not support this operation.", f.getMessage()); + assertEquals("NameNotEditableItem", item.getName()); } } diff --git a/core/src/test/java/hudson/model/ItemsTest.java b/core/src/test/java/hudson/model/ItemsTest.java index 2a7cef9f5d..3bdedd259c 100644 --- a/core/src/test/java/hudson/model/ItemsTest.java +++ b/core/src/test/java/hudson/model/ItemsTest.java @@ -5,7 +5,7 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertThrows; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -14,9 +14,9 @@ import static org.mockito.Mockito.when; */ public class ItemsTest { - private static ItemGroup root; - private static ItemGroup foo; - private static ItemGroup foo_bar; + private static ItemGroup root; + private static ItemGroup foo; + private static ItemGroup foo_bar; @BeforeClass public static void itemGroups() { @@ -28,7 +28,6 @@ public class ItemsTest { foo_bar = mock(ItemGroup.class); when(foo_bar.getFullName()).thenReturn("foo/bar"); - } @Test @@ -43,26 +42,14 @@ public class ItemsTest { assertEquals("foo/bar/baz/qux", Items.getCanonicalName(foo_bar, "baz/qux")); assertEquals("foo/baz/qux", Items.getCanonicalName(foo_bar, "../baz/qux")); - try { - Items.getCanonicalName(root, ".."); - fail(); - } catch (IllegalArgumentException ex) { - assertEquals("Illegal relative path '..' within context ''", ex.getMessage()); - } + final IllegalArgumentException ex0 = assertThrows(IllegalArgumentException.class, () -> Items.getCanonicalName(root, "..")); + assertEquals("Illegal relative path '..' within context ''", ex0.getMessage()); - try { - Items.getCanonicalName(foo, "../.."); - fail(); - } catch (IllegalArgumentException ex) { - assertEquals("Illegal relative path '../..' within context 'foo'", ex.getMessage()); - } + final IllegalArgumentException ex1 = assertThrows(IllegalArgumentException.class, () -> Items.getCanonicalName(foo, "../..")); + assertEquals("Illegal relative path '../..' within context 'foo'", ex1.getMessage()); - try { - Items.getCanonicalName(root, "foo/../.."); - fail(); - } catch (IllegalArgumentException ex) { - assertEquals("Illegal relative path 'foo/../..' within context ''", ex.getMessage()); - } + final IllegalArgumentException ex2 = assertThrows(IllegalArgumentException.class, () -> Items.getCanonicalName(root, "foo/../..")); + assertEquals("Illegal relative path 'foo/../..' within context ''", ex2.getMessage()); } @Test diff --git a/core/src/test/java/hudson/model/RunParameterValueTest.java b/core/src/test/java/hudson/model/RunParameterValueTest.java index ce34590540..4374808c13 100644 --- a/core/src/test/java/hudson/model/RunParameterValueTest.java +++ b/core/src/test/java/hudson/model/RunParameterValueTest.java @@ -27,7 +27,7 @@ package hudson.model; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertThrows; public class RunParameterValueTest { @@ -37,24 +37,11 @@ public class RunParameterValueTest { assertEquals("whatever", rpv.getName()); assertEquals("folder/job", rpv.getJobName()); assertEquals("57", rpv.getNumber()); - try { - new RunParameterValue("whatever", null); - fail(); - } catch (IllegalArgumentException x) { - // good - } - try { - new RunParameterValue("whatever", "invalid"); - fail(); - } catch (IllegalArgumentException x) { - // good - } - try { - new RunParameterValue("whatever", "invalid", "desc"); - fail(); - } catch (IllegalArgumentException x) { - // good - } + + assertThrows(IllegalArgumentException.class, () -> new RunParameterValue("whatever", null)); + assertThrows(IllegalArgumentException.class, () -> new RunParameterValue("whatever", "invalid")); + assertThrows(IllegalArgumentException.class, () -> new RunParameterValue("whatever", "invalid", "desc")); + rpv = (RunParameterValue) Run.XSTREAM2.fromXML("whateverbogus"); assertEquals("whatever", rpv.getName()); assertNull(rpv.getJobName()); diff --git a/core/src/test/java/hudson/model/UpdateCenterTest.java b/core/src/test/java/hudson/model/UpdateCenterTest.java index 2a84fab8d5..8d4ff97f67 100644 --- a/core/src/test/java/hudson/model/UpdateCenterTest.java +++ b/core/src/test/java/hudson/model/UpdateCenterTest.java @@ -10,8 +10,8 @@ import java.util.Locale; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertEquals; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; public class UpdateCenterTest { @@ -52,12 +52,10 @@ public class UpdateCenterTest { @Test public void noChecksums() { - try { - UpdateCenter.verifyChecksums(new MockDownloadJob(null, null, null), buildEntryWithExpectedChecksums(null, null, null), new File("example")); - fail(); - } catch (IOException ex) { - assertEquals("Unable to confirm integrity of downloaded file, refusing installation", ex.getMessage()); - } + final IOException ex = assertThrows(IOException.class, + () -> UpdateCenter.verifyChecksums(new MockDownloadJob(null, null, null), + buildEntryWithExpectedChecksums(null, null, null), new File("example"))); + assertEquals("Unable to confirm integrity of downloaded file, refusing installation", ex.getMessage()); } @Test @@ -69,14 +67,10 @@ public class UpdateCenterTest { @Test public void sha1Mismatch() { - try { - UpdateCenter.verifyChecksums( - new MockDownloadJob(EMPTY_SHA1.replace('k', 'f'), null, null), - buildEntryWithExpectedChecksums(EMPTY_SHA1, null, null), new File("example")); - fail(); - } catch (IOException ex) { - assertTrue(ex.getMessage().contains("does not match expected SHA-1, expected '2jmj7l5rSw0yVb/vlWAYkK/YBwk=', actual '2jmj7l5rSw0yVb/vlWAYfK/YBwf='")); - } + final IOException ex = assertThrows(IOException.class, () -> UpdateCenter.verifyChecksums( + new MockDownloadJob(EMPTY_SHA1.replace('k', 'f'), null, null), + buildEntryWithExpectedChecksums(EMPTY_SHA1, null, null), new File("example"))); + assertTrue(ex.getMessage().contains("does not match expected SHA-1, expected '2jmj7l5rSw0yVb/vlWAYkK/YBwk=', actual '2jmj7l5rSw0yVb/vlWAYfK/YBwf='")); } @Test @@ -95,45 +89,32 @@ public class UpdateCenterTest { @Test public void sha1DoesNotIgnoreCase() { - try { - UpdateCenter.verifyChecksums( - new MockDownloadJob(EMPTY_SHA1, EMPTY_SHA256, EMPTY_SHA512), - buildEntryWithExpectedChecksums(EMPTY_SHA1.toUpperCase(Locale.US), null, null), new File("example")); - fail(); - } catch (Exception e) { - assertTrue(e.getMessage().contains("does not match expected SHA-1, expected '2JMJ7L5RSW0YVB/VLWAYKK/YBWK=', actual '2jmj7l5rSw0yVb/vlWAYkK/YBwk='")); - } - + final Exception ex = assertThrows(Exception.class, () -> UpdateCenter.verifyChecksums( + new MockDownloadJob(EMPTY_SHA1, EMPTY_SHA256, EMPTY_SHA512), + buildEntryWithExpectedChecksums(EMPTY_SHA1.toUpperCase(Locale.US), null, null), new File("example"))); + assertTrue(ex.getMessage().contains("does not match expected SHA-1, expected '2JMJ7L5RSW0YVB/VLWAYKK/YBWK=', actual '2jmj7l5rSw0yVb/vlWAYkK/YBwk='")); } @Test public void noOverlapForComputedAndProvidedChecksums() { - try { - UpdateCenter.verifyChecksums( - new MockDownloadJob(EMPTY_SHA1, EMPTY_SHA256, null), - buildEntryWithExpectedChecksums(null, null, EMPTY_SHA512), new File("example")); - fail(); - } catch (Exception e) { - assertEquals("Unable to confirm integrity of downloaded file, refusing installation", e.getMessage()); - } + final Exception ex = assertThrows(Exception.class, () -> UpdateCenter.verifyChecksums( + new MockDownloadJob(EMPTY_SHA1, EMPTY_SHA256, null), + buildEntryWithExpectedChecksums(null, null, EMPTY_SHA512), new File("example"))); + assertEquals("Unable to confirm integrity of downloaded file, refusing installation", ex.getMessage()); } @Test public void noOverlapForComputedAndProvidedChecksumsForSpecIncompliantJVM() { - try { - UpdateCenter.verifyChecksums( - new MockDownloadJob(EMPTY_SHA1, null, null), - buildEntryWithExpectedChecksums(null, EMPTY_SHA256, EMPTY_SHA512), new File("example")); - fail(); - } catch (Exception e) { - assertEquals("Unable to confirm integrity of downloaded file, refusing installation", e.getMessage()); - } + final Exception ex = assertThrows(Exception.class, () -> UpdateCenter.verifyChecksums( + new MockDownloadJob(EMPTY_SHA1, null, null), + buildEntryWithExpectedChecksums(null, EMPTY_SHA256, EMPTY_SHA512), new File("example"))); + assertEquals("Unable to confirm integrity of downloaded file, refusing installation", ex.getMessage()); } - private static String EMPTY_SHA1 = "2jmj7l5rSw0yVb/vlWAYkK/YBwk="; - private static String EMPTY_SHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; - private static String EMPTY_SHA512 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"; + private static final String EMPTY_SHA1 = "2jmj7l5rSw0yVb/vlWAYkK/YBwk="; + private static final String EMPTY_SHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; + private static final String EMPTY_SHA512 = "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"; private static UpdateSite.Entry buildEntryWithExpectedChecksums(String expectedSHA1, String expectedSHA256, String expectedSHA512) { JSONObject o = new JSONObject(); diff --git a/core/src/test/java/hudson/scheduler/CronTabTest.java b/core/src/test/java/hudson/scheduler/CronTabTest.java index c812b4c651..958b9807ad 100644 --- a/core/src/test/java/hudson/scheduler/CronTabTest.java +++ b/core/src/test/java/hudson/scheduler/CronTabTest.java @@ -33,7 +33,7 @@ import java.util.TimeZone; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertThrows; import org.junit.Test; import org.jvnet.hudson.test.Issue; @@ -265,12 +265,8 @@ public class CronTabTest { compare(new GregorianCalendar(2013, 2, 21, 0, 2), new CronTab("H(0-15)/3 * * * *", Hash.from("junk")).ceil(new GregorianCalendar(2013, 2, 21, 0, 0))); compare(new GregorianCalendar(2013, 2, 21, 0, 2), new CronTab("H(0-3)/4 * * * *", Hash.from("junk")).ceil(new GregorianCalendar(2013, 2, 21, 0, 0))); compare(new GregorianCalendar(2013, 2, 21, 1, 2), new CronTab("H(0-3)/4 * * * *", Hash.from("junk")).ceil(new GregorianCalendar(2013, 2, 21, 0, 5))); - try { - compare(new GregorianCalendar(2013, 2, 21, 0, 0), new CronTab("H(0-3)/15 * * * *", Hash.from("junk")).ceil(new GregorianCalendar(2013, 2, 21, 0, 0))); - fail(); - } catch (ANTLRException x) { - // good - } + + assertThrows(ANTLRException.class, () -> compare(new GregorianCalendar(2013, 2, 21, 0, 0), new CronTab("H(0-3)/15 * * * *", Hash.from("junk")).ceil(new GregorianCalendar(2013, 2, 21, 0, 0)))); } @Test public void repeatedHash() throws Exception { @@ -289,21 +285,11 @@ public class CronTabTest { } @Test public void rangeBoundsCheckFailHour() { - try { - new CronTab("H H(12-24) * * *"); - fail(); - } catch (ANTLRException e) { - // ok - } + assertThrows(ANTLRException.class, () -> new CronTab("H H(12-24) * * *")); } @Test public void rangeBoundsCheckFailMinute() { - try { - new CronTab("H(33-66) * * * *"); - fail(); - } catch (ANTLRException e) { - // ok - } + assertThrows(ANTLRException.class, () -> new CronTab("H(33-66) * * * *")); } @Issue("JENKINS-9283") diff --git a/core/src/test/java/hudson/util/AtomicFileWriterTest.java b/core/src/test/java/hudson/util/AtomicFileWriterTest.java index 72e64746a1..c498bbbdee 100644 --- a/core/src/test/java/hudson/util/AtomicFileWriterTest.java +++ b/core/src/test/java/hudson/util/AtomicFileWriterTest.java @@ -25,8 +25,8 @@ import static org.hamcrest.core.StringContains.containsString; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import static org.junit.Assume.assumeThat; public class AtomicFileWriterTest { @@ -136,12 +136,7 @@ public class AtomicFileWriterTest { @Test public void indexOutOfBoundsLeavesOriginalUntouched() throws Exception { // Given - try { - afw.write(expectedContent, 0, expectedContent.length() + 10); - fail("exception expected"); - } catch (IndexOutOfBoundsException e) { - } - + assertThrows(IndexOutOfBoundsException.class, () -> afw.write(expectedContent, 0, expectedContent.length() + 10)); assertEquals(PREVIOUS, FileUtils.readFileToString(af, Charset.defaultCharset())); } @Test @@ -152,13 +147,10 @@ public class AtomicFileWriterTest { assertTrue(newFile.exists()); assertFalse(parentExistsAndIsAFile.exists()); - try { - new AtomicFileWriter(parentExistsAndIsAFile.toPath(), StandardCharsets.UTF_8); - fail("Expected a failure"); - } catch (IOException e) { - assertThat(e.getMessage(), - containsString("exists and is neither a directory nor a symlink to a directory")); - } + final IOException e = assertThrows(IOException.class, + () -> new AtomicFileWriter(parentExistsAndIsAFile.toPath(), StandardCharsets.UTF_8)); + assertThat(e.getMessage(), + containsString("exists and is neither a directory nor a symlink to a directory")); } @Issue("JENKINS-48407") diff --git a/core/src/test/java/hudson/util/ConsistentHashTest.java b/core/src/test/java/hudson/util/ConsistentHashTest.java index 1fb54174c1..0b6efd3c44 100644 --- a/core/src/test/java/hudson/util/ConsistentHashTest.java +++ b/core/src/test/java/hudson/util/ConsistentHashTest.java @@ -27,8 +27,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import org.junit.Ignore; import org.junit.Test; @@ -170,13 +170,11 @@ public class ConsistentHashTest { throw exception; }; - try { + final RuntimeException e = assertThrows(RuntimeException.class, () -> { ConsistentHash hash = new ConsistentHash<>(hashFunction); hash.add("foo"); - fail("Didn't use custom hash function"); - } catch (RuntimeException e) { - assertSame(exception, e); - } + }); + assertSame(exception, e); } /** diff --git a/core/src/test/java/hudson/util/CyclicGraphDetectorTest.java b/core/src/test/java/hudson/util/CyclicGraphDetectorTest.java index bc0a818632..b02613e029 100644 --- a/core/src/test/java/hudson/util/CyclicGraphDetectorTest.java +++ b/core/src/test/java/hudson/util/CyclicGraphDetectorTest.java @@ -1,7 +1,7 @@ package hudson.util; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import hudson.util.CyclicGraphDetector.CycleDetectedException; import org.junit.Test; @@ -61,20 +61,19 @@ public class CyclicGraphDetectorTest { }.run(nodes()); } - void mustContainCycle(String... members) throws Exception { - try { - check(); - fail("Cycle expected"); - } catch (CycleDetectedException e) { - String msg = "Expected cycle of " + Arrays.asList(members) + " but found " + e.cycle; - for (String s : members) - assertTrue(msg, e.cycle.contains(s)); + void mustContainCycle(String... members) { + final CycleDetectedException e = assertThrows("Cycle expected", + CycleDetectedException.class, this::check); + + final String msg = "Expected cycle of " + Arrays.asList(members) + " but found " + e.cycle; + for (String s : members) { + assertTrue(msg, e.cycle.contains(s)); } } } @Test - public void cycle1() throws Exception { + public void cycle1() { new Graph().e("A","B").e("B","C").e("C","A").mustContainCycle("A","B","C"); } @@ -84,7 +83,7 @@ public class CyclicGraphDetectorTest { } @Test - public void cycle3() throws Exception { + public void cycle3() { new Graph().e("A","B").e("B","C").e("C","D").e("B","E").e("E","D").e("E","A").mustContainCycle("A","B","E"); } } diff --git a/core/src/test/java/hudson/util/RetrierTest.java b/core/src/test/java/hudson/util/RetrierTest.java index a13519e1e7..158c8111b3 100644 --- a/core/src/test/java/hudson/util/RetrierTest.java +++ b/core/src/test/java/hudson/util/RetrierTest.java @@ -10,11 +10,11 @@ import java.util.concurrent.Callable; import java.util.logging.Level; import java.util.logging.Logger; -import static junit.framework.TestCase.fail; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; public class RetrierTest { - private static Logger LOG = Logger.getLogger(RetrierTest.class.getName()); + private static final Logger LOG = Logger.getLogger(RetrierTest.class.getName()); @Test public void performedAtThirdAttemptTest() throws Exception { @@ -306,14 +306,8 @@ public class RetrierTest { .build(); // Begin the process that raises an unexpected exception - try { - r.start(); - fail("The process should be exited with an unexpected exception"); - } catch (IOException e) { - String testFailure = Messages.Retrier_ExceptionThrown(ATTEMPTS, ACTION); - assertTrue(String.format("The log should contain '%s'", testFailure), handler.getView().stream().anyMatch(m -> m.getMessage().contains(testFailure))); - } catch (Exception e) { - fail(String.format("Unexpected exception: %s", e)); - } + assertThrows("The process should be exited with an unexpected exception", IOException.class, r::start); + String testFailure = Messages.Retrier_ExceptionThrown(ATTEMPTS, ACTION); + assertTrue(String.format("The log should contain '%s'", testFailure), handler.getView().stream().anyMatch(m -> m.getMessage().contains(testFailure))); } } diff --git a/core/src/test/java/hudson/util/RobustReflectionConverterTest.java b/core/src/test/java/hudson/util/RobustReflectionConverterTest.java index 022eb820f2..18f0c5a981 100644 --- a/core/src/test/java/hudson/util/RobustReflectionConverterTest.java +++ b/core/src/test/java/hudson/util/RobustReflectionConverterTest.java @@ -23,9 +23,10 @@ */ package hudson.util; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertThrows; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.ConversionException; @@ -60,22 +61,15 @@ public class RobustReflectionConverterTest { @Test public void ifWorkaroundNeeded() { - try { - read(new XStream()); - fail(); - } catch (ConversionException e) { - // expected - assertTrue(e.getMessage().contains("z")); - } + final ConversionException e = assertThrows(ConversionException.class, () -> read(new XStream())); + assertThat(e.getMessage(), containsString("z")); } @Test public void classOwnership() { - XStream xs = new XStream2(new XStream2.ClassOwnership() { - @Override public String ownerOf(Class clazz) { - Owner o = clazz.getAnnotation(Owner.class); - return o != null ? o.value() : null; - } + XStream xs = new XStream2(clazz -> { + Owner o = clazz.getAnnotation(Owner.class); + return o != null ? o.value() : null; }); String prefix1 = RobustReflectionConverterTest.class.getName() + "_-"; String prefix2 = RobustReflectionConverterTest.class.getName() + "$"; diff --git a/core/src/test/java/hudson/util/SubClassGeneratorTest.java b/core/src/test/java/hudson/util/SubClassGeneratorTest.java deleted file mode 100644 index 1cc590bb6d..0000000000 --- a/core/src/test/java/hudson/util/SubClassGeneratorTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * The MIT License - * - * Copyright (c) 2010, InfraDNA, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package hudson.util; - -import static org.junit.Assert.assertEquals; - -import org.junit.Test; - -/** - * @author Kohsuke Kawaguchi - */ -public class SubClassGeneratorTest { - - public static class Foo { - String s; - double x; - int y; - public Foo() {} - public Foo(String s) {this.s=s;} - public Foo(double x, int y) { - this.x = x; - this.y = y; - } - } - - @Test - public void foo() throws Exception { - Class c = new SubClassGenerator(getClass().getClassLoader()).generate(Foo.class, "12345"); - assertEquals("12345",c.getName()); - - c.getDeclaredConstructor().newInstance(); - - Foo f = c.getConstructor(String.class).newInstance("aaa"); - assertEquals("aaa",f.s); - - f = c.getConstructor(double.class,int.class).newInstance(1.0,3); - assertEquals(1.0,f.x,0); - assertEquals(3,f.y); - } -} diff --git a/core/src/test/java/hudson/util/XStream2Test.java b/core/src/test/java/hudson/util/XStream2Test.java index 4d12691e1d..f5f4d64c16 100644 --- a/core/src/test/java/hudson/util/XStream2Test.java +++ b/core/src/test/java/hudson/util/XStream2Test.java @@ -28,8 +28,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -284,11 +284,7 @@ public class XStream2Test { @Issue("SECURITY-105") @Test public void dynamicProxyBlocked() { - try { - ((Runnable) new XStream2().fromXML("java.lang.Runnableoops")).run(); - } catch (XStreamException x) { - // good - } + assertThrows(XStreamException.class, () -> ((Runnable) new XStream2().fromXML("java.lang.Runnableoops")).run()); assertFalse("should never have run that", Hacked.tripped); } @@ -529,13 +525,8 @@ public class XStream2Test { @Issue("SECURITY-503") @Test - public void crashXstream() throws Exception { - try { - new XStream2().fromXML(""); - fail("expected to throw ConversionException, but why are we still alive?"); - } catch (XStreamException ex) { - // pass - } + public void crashXstream() { + assertThrows(XStreamException.class, () -> new XStream2().fromXML("")); } @Test @@ -543,12 +534,8 @@ public class XStream2Test { assertEquals("not registered, so sorry", "", Jenkins.XSTREAM2.toXML(new C1())); assertEquals("manually registered", "", Jenkins.XSTREAM2.toXML(new C2())); assertEquals("manually processed", "", Jenkins.XSTREAM2.toXML(new C3())); - try { - Jenkins.XSTREAM2.fromXML(""); - fail("this could never have worked anyway"); - } catch (CannotResolveClassException x) { - // OK - } + assertThrows(CannotResolveClassException.class, () -> Jenkins.XSTREAM2.fromXML("")); + Jenkins.XSTREAM2.processAnnotations(C5.class); assertThat("can deserialize from annotations so long as the processing happened at some point", Jenkins.XSTREAM2.fromXML(""), instanceOf(C5.class)); } diff --git a/core/src/test/java/jenkins/RemotingJarSignatureTest.java b/core/src/test/java/jenkins/RemotingJarSignatureTest.java index 7bf5ac7264..f6103ec165 100644 --- a/core/src/test/java/jenkins/RemotingJarSignatureTest.java +++ b/core/src/test/java/jenkins/RemotingJarSignatureTest.java @@ -1,6 +1,6 @@ package jenkins; -import static org.junit.Assert.fail; +import static org.junit.Assert.assertNotNull; import hudson.remoting.Channel; import hudson.remoting.Which; @@ -23,8 +23,6 @@ public class RemotingJarSignatureTest { @Test public void testSignature() throws Exception { File jar = Which.jarFile(Channel.class); -// File jar = new File("/home/kohsuke/.m2/repository/org/jenkins-ci/main/remoting/1.421/remoting-1.421.jar"); -// File jar = new File("/home/kohsuke/.m2/repository/org/jenkins-ci/main/remoting/2.0/remoting-2.0.jar"); System.out.println("Verifying "+jar); JarFile myJar = new JarFile(jar,true); @@ -43,9 +41,7 @@ public class RemotingJarSignatureTest { // make sure bits are signed IOUtils.copy(myJar.getInputStream(entry), NullOutputStream.NULL_OUTPUT_STREAM); - if (entry.getCodeSigners()==null) { - fail("No signature for " + name); - } + assertNotNull("No signature for " + name, entry.getCodeSigners()); } } } diff --git a/core/src/test/java/jenkins/model/RunIdMigratorTest.java b/core/src/test/java/jenkins/model/RunIdMigratorTest.java index 02378ef6e6..c702a4e113 100644 --- a/core/src/test/java/jenkins/model/RunIdMigratorTest.java +++ b/core/src/test/java/jenkins/model/RunIdMigratorTest.java @@ -41,8 +41,8 @@ import org.junit.AfterClass; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import org.junit.Before; @@ -207,12 +207,7 @@ public class RunIdMigratorTest { File dest = new File(tmp.getRoot(), "dest"); RunIdMigrator.move(src, dest); File dest2 = tmp.newFile(); - try { - RunIdMigrator.move(dest, dest2); - fail(); - } catch (IOException x) { - System.err.println("Got expected move exception: " + x); - } + assertThrows(IOException.class, () -> RunIdMigrator.move(dest, dest2)); } } diff --git a/core/src/test/java/jenkins/model/lazy/AbstractLazyLoadRunMapTest.java b/core/src/test/java/jenkins/model/lazy/AbstractLazyLoadRunMapTest.java index 40d5d4342a..01c7b3bcd1 100644 --- a/core/src/test/java/jenkins/model/lazy/AbstractLazyLoadRunMapTest.java +++ b/core/src/test/java/jenkins/model/lazy/AbstractLazyLoadRunMapTest.java @@ -29,6 +29,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -157,13 +158,7 @@ public class AbstractLazyLoadRunMapTest { @Test public void firstKey() { assertEquals(5, a.firstKey().intValue()); - - try { - b.firstKey(); - fail(); - } catch (NoSuchElementException e) { - // as expected - } + assertThrows(NoSuchElementException.class, () -> b.firstKey()); } @Issue("JENKINS-26690") diff --git a/core/src/test/java/jenkins/util/JenkinsJVMTest.java b/core/src/test/java/jenkins/util/JenkinsJVMTest.java index 206ca39fe2..888c592739 100644 --- a/core/src/test/java/jenkins/util/JenkinsJVMTest.java +++ b/core/src/test/java/jenkins/util/JenkinsJVMTest.java @@ -13,14 +13,14 @@ public class JenkinsJVMTest { @Test public void checkJenkinsJVM_WhenNotInAJenkinsJVM() { - assertThrows(IllegalStateException.class, () -> JenkinsJVM.checkJenkinsJVM()); + assertThrows(IllegalStateException.class, JenkinsJVM::checkJenkinsJVM); } @Test public void checkNotJenkinsJVM_WhenInAJenkinsJVM() { JenkinsJVM.setJenkinsJVM(true); try { - assertThrows(IllegalStateException.class, () -> JenkinsJVM.checkNotJenkinsJVM()); + assertThrows(IllegalStateException.class, JenkinsJVM::checkNotJenkinsJVM); } finally { JenkinsJVM.setJenkinsJVM(false); } diff --git a/core/src/test/java/jenkins/util/TimerTest.java b/core/src/test/java/jenkins/util/TimerTest.java index dde07b3cae..197c440f20 100644 --- a/core/src/test/java/jenkins/util/TimerTest.java +++ b/core/src/test/java/jenkins/util/TimerTest.java @@ -78,7 +78,7 @@ public class TimerTest { startLatch.countDown(); contextClassloaders[j] = Thread.currentThread().getContextClassLoader(); } catch (Exception ex) { - throw new RuntimeException(ex); + throw new RuntimeException(ex); } } }, 0, TimeUnit.SECONDS); diff --git a/core/src/test/java/jenkins/util/VirtualFileTest.java b/core/src/test/java/jenkins/util/VirtualFileTest.java index e2f4d81a45..c28a213b1b 100644 --- a/core/src/test/java/jenkins/util/VirtualFileTest.java +++ b/core/src/test/java/jenkins/util/VirtualFileTest.java @@ -100,7 +100,7 @@ public class VirtualFileTest { VirtualFile hack = root.child("hack"); assertFalse(hack.isFile()); assertFalse(hack.exists()); - assertThrows(FileNotFoundException.class, () -> hack.open()); + assertThrows(FileNotFoundException.class, hack::open); } @Issue("JENKINS-26810") diff --git a/core/src/test/java/jenkins/util/io/PathRemoverTest.java b/core/src/test/java/jenkins/util/io/PathRemoverTest.java index 3e4bd1f4cd..f95aa1e55f 100644 --- a/core/src/test/java/jenkins/util/io/PathRemoverTest.java +++ b/core/src/test/java/jenkins/util/io/PathRemoverTest.java @@ -61,7 +61,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import static org.junit.Assume.assumeTrue; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; @@ -104,14 +103,9 @@ public class PathRemoverTest { given(attributes.isDirectory()).willReturn(false); PathRemover remover = PathRemover.newSimpleRemover(); - try { - remover.forceRemoveFile(file.toPath()); - fail("Should not have been deleted: " + file); - } catch (IOException e) { - assertThat(calcExceptionHierarchy(e), hasItem(FileSystemException.class)); - assertThat(e.getMessage(), containsString(filename)); - } - + final IOException e = assertThrows(IOException.class, () -> remover.forceRemoveFile(file.toPath())); + assertThat(calcExceptionHierarchy(e), hasItem(FileSystemException.class)); + assertThat(e.getMessage(), containsString(filename)); } private static List> calcExceptionHierarchy(Throwable t) { @@ -437,13 +431,12 @@ public class PathRemoverTest { for (int i = 0; i < lockedFiles; i++) { locker.acquireLock(files[i]); } - try { - PathRemover.newSimpleRemover().forceRemoveRecursive(dir.toPath()); - fail("Deletion should have failed"); - } catch (CompositeIOException e) { - assertThat(e.getSuppressed(), arrayWithSize(maxExceptions)); - assertThat(e.getMessage(), endsWith("(Discarded " + (lockedFiles + 1 - maxExceptions) + " additional exceptions)")); - } + + final CompositeIOException e = assertThrows(CompositeIOException.class, + () -> PathRemover.newSimpleRemover().forceRemoveRecursive(dir.toPath())); + assertThat(e.getSuppressed(), arrayWithSize(maxExceptions)); + assertThat(e.getMessage(), endsWith("(Discarded " + (lockedFiles + 1 - maxExceptions) + " additional exceptions)")); + assertTrue(dir.exists()); assertThat(dir.listFiles().length, equalTo(lockedFiles)); } diff --git a/core/src/test/java/jenkins/xml/XMLUtilsTest.java b/core/src/test/java/jenkins/xml/XMLUtilsTest.java index 3f0b131198..58ed437267 100644 --- a/core/src/test/java/jenkins/xml/XMLUtilsTest.java +++ b/core/src/test/java/jenkins/xml/XMLUtilsTest.java @@ -41,6 +41,8 @@ import javax.xml.xpath.XPathExpressionException; import static org.hamcrest.core.StringContains.containsString; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertThrows; + import org.jvnet.hudson.test.Issue; import org.xml.sax.SAXException; @@ -117,19 +119,15 @@ public class XMLUtilsTest { } @Test - public void testParse_with_XXE() throws IOException { - try { - final String xml = "\n" + - "\n" + - " ]> " + - "&xxe;"; + public void testParse_with_XXE() { + final String xml = "\n" + + "\n" + + " ]> " + + "&xxe;"; - StringReader stringReader = new StringReader(xml); - XMLUtils.parse(stringReader); - Assert.fail("Expecting SAXException for XXE."); - } catch (SAXException e) { - assertThat(e.getMessage(), containsString("\"http://apache.org/xml/features/disallow-doctype-decl\"")); - } + StringReader stringReader = new StringReader(xml); + final SAXException e = assertThrows(SAXException.class, () -> XMLUtils.parse(stringReader)); + assertThat(e.getMessage(), containsString("\"http://apache.org/xml/features/disallow-doctype-decl\"")); } } diff --git a/pom.xml b/pom.xml index 6212db894d..23ad304ddc 100644 --- a/pom.xml +++ b/pom.xml @@ -28,7 +28,7 @@ THE SOFTWARE. org.jenkins-ci jenkins - 1.64 + 1.65 @@ -39,6 +39,7 @@ THE SOFTWARE. Jenkins main module The module that constitutes the main jenkins.war + https://github.com/jenkinsci/jenkins @@ -69,7 +70,7 @@ THE SOFTWARE. - 2.301 + 2.309 -SNAPSHOT - 4.9 + 4.10 3.14 @@ -99,12 +100,10 @@ THE SOFTWARE. High ${project.basedir}/../src/findbugs/findbugs-excludes.xml - - 1.21 - 1.21 + 1.24 5.7.2 2.0.9 - 2.12.1 + 2.12.3 diff --git a/test/pom.xml b/test/pom.xml index f51c55c12b..4264e3531f 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -56,11 +56,17 @@ THE SOFTWARE. ant 1.11
    + + + org.jenkins-ci.plugins + display-url-api + 2.3.5 + org.jenkins-ci.plugins script-security - 1.77 + 1.78 @@ -93,7 +99,7 @@ THE SOFTWARE. org.jenkins-ci.plugins cloudbees-folder - 6.15 + 6.16 test @@ -105,7 +111,7 @@ THE SOFTWARE. org.jenkins-ci.plugins matrix-auth - 2.6.7 + 2.6.8 test @@ -129,7 +135,7 @@ THE SOFTWARE. org.jenkins-ci.plugins junit - 1.50 + 1.52 test @@ -211,8 +217,6 @@ THE SOFTWARE. ${jacocoSurefireArgs} -Dfile.encoding=UTF-8 -Xmx1g -Djdk.net.URLClassPath.disableClassPathURLCheck=true - - true ${mavenDebug} ${project.build.directory} diff --git a/test/src/test/java/hudson/FilePathTest.java b/test/src/test/java/hudson/FilePathTest.java index b6294400d7..6b70b4e725 100644 --- a/test/src/test/java/hudson/FilePathTest.java +++ b/test/src/test/java/hudson/FilePathTest.java @@ -222,4 +222,63 @@ public class FilePathTest { assertThat(simple1.exists(), is(true)); assertThat(simple2.exists(), is(true)); } + + @Test + @Issue("JENKINS-66094") + @LocalData("ZipSlipSamePathPrefix") + public void zipSlipSamePathPrefix() throws Exception { + assumeFalse(Functions.isWindows()); + + // > unzip -l evil.zip + // good.txt + // ../foo_evil.txt + FilePath zipFile = r.jenkins.getRootPath().child("evil.zip"); + + // foo_evil.txt will be extracted to unzip-target/foo_evil.txt + // which has the same path prefix as unzip-target/foo + FilePath targetLocationParent = r.jenkins.getRootPath().child("unzip-target"); + FilePath targetLocationFoo = targetLocationParent.child("foo"); + FilePath evilEntry = targetLocationParent.child("foo_evil.txt"); + + assertThat(evilEntry.exists(), is(false)); + + try { + zipFile.unzip(targetLocationFoo); + fail("The ../foo_evil.txt should have triggered an exception"); + } catch(IOException e){ + e.printStackTrace(); + assertThat(e.getMessage(), containsString("contains illegal file name that breaks out of the target directory")); + } + + assertThat(evilEntry.exists(), is(false)); + } + + @Test + @Issue("JENKINS-66094") + @LocalData("ZipSlipSamePathPrefix") + public void zipSlipSamePathPrefixWin() throws Exception { + assumeTrue(Functions.isWindows()); + + // > unzip -l evil-win.zip + // good.txt + // ..\foo_evil.txt + FilePath zipFile = r.jenkins.getRootPath().child("evil-win.zip"); + + // foo_evil.txt will be extracted to unzip-target\foo_evil.txt + // which has the same path prefix as unzip-target\foo + FilePath targetLocationParent = r.jenkins.getRootPath().child("unzip-target"); + FilePath targetLocationFoo = targetLocationParent.child("foo"); + FilePath evilEntry = targetLocationParent.child("foo_evil.txt"); + + assertThat(evilEntry.exists(), is(false)); + + try { + zipFile.unzip(targetLocationFoo); + fail("The ../foo_evil.txt should have triggered an exception"); + } catch(IOException e){ + assertThat(e.getMessage(), containsString("contains illegal file name that breaks out of the target directory")); + } + + assertThat(evilEntry.exists(), is(false)); + } } diff --git a/test/src/test/java/hudson/cli/GetNodeCommandTest.java b/test/src/test/java/hudson/cli/GetNodeCommandTest.java index 45adbac47a..20c667f48c 100644 --- a/test/src/test/java/hudson/cli/GetNodeCommandTest.java +++ b/test/src/test/java/hudson/cli/GetNodeCommandTest.java @@ -102,10 +102,18 @@ public class GetNodeCommandTest { assertThat(result.stderr(), containsString("No such node ''")); assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); + + // old name result = command.authorizedTo(Computer.EXTENDED_READ, Jenkins.READ).invokeWithArgs("(master)"); assertThat(result.stderr(), containsString("No such node '(master)'")); assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); + + // new name + result = command.authorizedTo(Computer.EXTENDED_READ, Jenkins.READ).invokeWithArgs("(built-in)"); + assertThat(result.stderr(), containsString("No such node '(built-in)'")); + assertThat(result, failedWith(3)); + assertThat(result, hasNoStandardOutput()); } } diff --git a/test/src/test/java/hudson/cli/HelpCommandTest.java b/test/src/test/java/hudson/cli/HelpCommandTest.java index 95ea8baa15..abc6c96db5 100644 --- a/test/src/test/java/hudson/cli/HelpCommandTest.java +++ b/test/src/test/java/hudson/cli/HelpCommandTest.java @@ -102,7 +102,7 @@ public class HelpCommandTest { private void assertContainsUsageOfMethodCommand(String text) { assertThat(text, containsString("offline-node NAME ... [-m VAL]")); - assertThat(text, containsStrings("NAME", "Agent name, or empty string for master")); + assertThat(text, containsStrings("NAME", "Agent name, or empty string for built-in node")); assertThat(text, containsStrings("-m VAL", "Record the reason about why you are disconnecting this node")); } diff --git a/test/src/test/java/hudson/cli/UpdateNodeCommandTest.java b/test/src/test/java/hudson/cli/UpdateNodeCommandTest.java index bfd956a500..f4fcfc400c 100644 --- a/test/src/test/java/hudson/cli/UpdateNodeCommandTest.java +++ b/test/src/test/java/hudson/cli/UpdateNodeCommandTest.java @@ -109,10 +109,18 @@ public class UpdateNodeCommandTest { assertThat(result.stderr(), containsString("No such node ''")); assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); + + // old name result = command.authorizedTo(Computer.EXTENDED_READ, Jenkins.READ).withStdin(Computer.class.getResourceAsStream("node.xml")).invokeWithArgs("(master)"); assertThat(result.stderr(), containsString("No such node '(master)'")); assertThat(result, failedWith(3)); assertThat(result, hasNoStandardOutput()); + + // new name + result = command.authorizedTo(Computer.EXTENDED_READ, Jenkins.READ).withStdin(Computer.class.getResourceAsStream("node.xml")).invokeWithArgs("(built-in)"); + assertThat(result.stderr(), containsString("No such node '(built-in)'")); + assertThat(result, failedWith(3)); + assertThat(result, hasNoStandardOutput()); } @Test diff --git a/test/src/test/java/hudson/cli/UpdateViewCommandTest.java b/test/src/test/java/hudson/cli/UpdateViewCommandTest.java index 857b67f352..1d9c72ff1a 100644 --- a/test/src/test/java/hudson/cli/UpdateViewCommandTest.java +++ b/test/src/test/java/hudson/cli/UpdateViewCommandTest.java @@ -33,7 +33,7 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.nullValue; import hudson.model.ListView; -import hudson.model.TreeView; +import hudson.model.MyView; import hudson.model.View; import jenkins.model.Jenkins; @@ -85,8 +85,8 @@ public class UpdateViewCommandTest { } @Test public void updateViewWithWrongViewTypeShouldFail() throws Exception { - TreeView tv = new TreeView("aView"); - j.jenkins.addView(tv); + MyView myView = new MyView("aView"); + j.jenkins.addView(myView); final CLICommandInvoker.Result result = command .authorizedTo(View.READ, View.CONFIGURE, Jenkins.READ) .withStdin(this.getClass().getResourceAsStream("/hudson/cli/view.xml")) @@ -94,7 +94,7 @@ public class UpdateViewCommandTest { ; assertThat(result, failedWith(1)); - assertThat(result.stderr(), containsString("Expecting view type: "+ tv.getClass() + assertThat(result.stderr(), containsString("Expecting view type: "+ myView.getClass() + " but got: class hudson.model.ListView instead.")); } diff --git a/test/src/test/java/hudson/cli/WaitNodeOnlineCommandTest.java b/test/src/test/java/hudson/cli/WaitNodeOnlineCommandTest.java index 8e92a30f82..403714cd49 100644 --- a/test/src/test/java/hudson/cli/WaitNodeOnlineCommandTest.java +++ b/test/src/test/java/hudson/cli/WaitNodeOnlineCommandTest.java @@ -31,7 +31,6 @@ import org.junit.Rule; import org.junit.Test; import org.jvnet.hudson.test.JenkinsRule; -import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -86,15 +85,12 @@ public class WaitNodeOnlineCommandTest { slave.toComputer().setTemporarilyOffline(true); boolean timeoutOccurred = false; - FutureTask task = new FutureTask(new Callable() { - @Override - public Object call() { - final CLICommandInvoker.Result result = command - .authorizedTo(Jenkins.READ) - .invokeWithArgs("aNode"); - fail("Never should return from previous CLI call!"); - return null; - } + FutureTask task = new FutureTask(() -> { + final CLICommandInvoker.Result result = command + .authorizedTo(Jenkins.READ) + .invokeWithArgs("aNode"); + fail("Never should return from previous CLI call!"); + return null; }); try { task.get(30, TimeUnit.SECONDS); @@ -115,15 +111,12 @@ public class WaitNodeOnlineCommandTest { slave.toComputer().waitUntilOffline(); boolean timeoutOccurred = false; - FutureTask task = new FutureTask(new Callable() { - @Override - public Object call() { - final CLICommandInvoker.Result result = command - .authorizedTo(Jenkins.READ) - .invokeWithArgs("aNode"); - fail("Never should return from previous CLI call!"); - return null; - } + FutureTask task = new FutureTask(() -> { + final CLICommandInvoker.Result result = command + .authorizedTo(Jenkins.READ) + .invokeWithArgs("aNode"); + fail("Never should return from previous CLI call!"); + return null; }); try { task.get(30, TimeUnit.SECONDS); @@ -143,15 +136,12 @@ public class WaitNodeOnlineCommandTest { slave.toComputer().disconnect(); boolean timeoutOccurred = false; - FutureTask task = new FutureTask(new Callable() { - @Override - public Object call() { - final CLICommandInvoker.Result result = command - .authorizedTo(Jenkins.READ) - .invokeWithArgs("aNode"); - fail("Never should return from previous CLI call!"); - return null; - } + FutureTask task = new FutureTask(() -> { + final CLICommandInvoker.Result result = command + .authorizedTo(Jenkins.READ) + .invokeWithArgs("aNode"); + fail("Never should return from previous CLI call!"); + return null; }); try { task.get(30, TimeUnit.SECONDS); diff --git a/test/src/test/java/hudson/diagnosis/OldDataMonitorTest.java b/test/src/test/java/hudson/diagnosis/OldDataMonitorTest.java index afb198fe04..11586b9918 100644 --- a/test/src/test/java/hudson/diagnosis/OldDataMonitorTest.java +++ b/test/src/test/java/hudson/diagnosis/OldDataMonitorTest.java @@ -67,14 +67,6 @@ public class OldDataMonitorTest { OldDataMonitor odm = OldDataMonitor.get(r.jenkins); FreeStyleProject p = r.jenkins.getItemByFullName("busted", FreeStyleProject.class); assertNotNull(p); - /* - System.err.println(p.getActions()); - for (Map.Entry entry : odm.getData().entrySet()) { - System.err.println(entry.getKey()); - System.err.println(entry.getValue()); - System.err.println(entry.getValue().extra); - } - */ assertEquals(Collections.singleton(p), odm.getData().keySet()); odm.doDiscard(null, null); assertEquals(Collections.emptySet(), odm.getData().keySet()); diff --git a/test/src/test/java/hudson/model/AbstractProjectTest.java b/test/src/test/java/hudson/model/AbstractProjectTest.java index e532feae16..a2e65992ec 100644 --- a/test/src/test/java/hudson/model/AbstractProjectTest.java +++ b/test/src/test/java/hudson/model/AbstractProjectTest.java @@ -566,8 +566,8 @@ public class AbstractProjectTest { */ assertThat(responseContent, allOf( containsString("warning"), - // as there is only master that is currently used, it's de facto the nearest to whatever - containsString("master"), + // as there is only the built-in node that is currently used, it's de facto the nearest to whatever + containsString("built-in"), containsString("whatever") )); } diff --git a/test/src/test/java/hudson/model/DependencyGraphTest.java b/test/src/test/java/hudson/model/DependencyGraphTest.java index 66a3c2be32..a00bfc40be 100644 --- a/test/src/test/java/hudson/model/DependencyGraphTest.java +++ b/test/src/test/java/hudson/model/DependencyGraphTest.java @@ -69,7 +69,7 @@ public class DependencyGraphTest { j.jenkins.rebuildDependencyGraph(); // First build won't trigger down1 (Unstable doesn't meet threshold) // but will trigger down2 (build #1 is odd). - Build b = (Build)p.scheduleBuild2(0, new Cause.UserCause()).get(); + Build b = (Build)p.scheduleBuild2(0, new Cause.UserIdCause()).get(); String log = j.getLog(b); Queue.Item q = j.jenkins.getQueue().getItem(down1); assertNull("down1 should not be triggered: " + log, q); @@ -85,7 +85,7 @@ public class DependencyGraphTest { j.jenkins.rebuildDependencyGraph(); // ..and next build will trigger down1 (Success meets threshold), // but not down2 (build #2 is even) - b = (Build)p.scheduleBuild2(0, new Cause.UserCause()).get(); + b = (Build)p.scheduleBuild2(0, new Cause.UserIdCause()).get(); log = j.getLog(b); q = j.jenkins.getQueue().getItem(down2); assertNull("down2 should not be triggered: " + log, q); diff --git a/test/src/test/java/hudson/model/DirectoryBrowserSupportTest.java b/test/src/test/java/hudson/model/DirectoryBrowserSupportTest.java index 1a4332a836..628f2d069a 100644 --- a/test/src/test/java/hudson/model/DirectoryBrowserSupportTest.java +++ b/test/src/test/java/hudson/model/DirectoryBrowserSupportTest.java @@ -27,6 +27,7 @@ import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.UnexpectedPage; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.util.NameValuePair; +import com.sun.management.UnixOperatingSystemMXBean; import edu.umd.cs.findbugs.annotations.NonNull; import hudson.ExtensionList; import hudson.FilePath; @@ -62,6 +63,8 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.management.ManagementFactory; +import java.lang.management.OperatingSystemMXBean; import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; @@ -73,6 +76,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.TreeMap; import java.util.stream.Collectors; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -210,6 +214,85 @@ public class DirectoryBrowserSupportTest { zipfile.delete(); } + @Test + public void zipDownloadFileLeakMx_hypothesis() throws Exception { + // this test is meant to just ensure zipDownloadFileLeakMx hypothesis about the UI work fine + + String content = "Hello world!"; + FreeStyleProject p = j.createFreeStyleProject(); + p.setScm(new SingleFileSCM("artifact.out", content)); + p.getPublishersList().add(new ArtifactArchiver("*", "", true)); + assertEquals(Result.SUCCESS, p.scheduleBuild2(0).get().getResult()); + + HtmlPage page = j.createWebClient().goTo("job/" + p.getName() + "/lastSuccessfulBuild/artifact/"); + Page downloadPage = page.getAnchorByHref("artifact.out").click(); + assertEquals(content, downloadPage.getWebResponse().getContentAsString()); + } + + @Test + @Issue({"JENKINS-64632", "JENKINS-61121"}) + public void zipDownloadFileLeakMx() throws Exception { + Assume.assumeFalse(Functions.isWindows()); + + int numOfClicks = 10; + int totalRuns = 10; + boolean freeFromLeak = false; + long[][] openFds = new long[totalRuns][2]; + for (int runs = 0; runs < totalRuns && !freeFromLeak; runs++) { + long initialOpenFds = getOpenFdCount(); + FreeStyleProject p = j.createFreeStyleProject(); + + // add randomness just to prevent any potential caching issue + p.setScm(new SingleFileSCM("artifact.out", "Hello world! " + Math.random())); + p.getPublishersList().add(new ArtifactArchiver("*", "", true)); + assertEquals(Result.SUCCESS, p.scheduleBuild2(0).get().getResult()); + + HtmlPage page = j.createWebClient().goTo("job/" + p.getName() + "/lastSuccessfulBuild/artifact/"); + for (int clicks = 0; clicks < numOfClicks; clicks++) { + page.getAnchorByHref("artifact.out").click(); + } + long finalOpenFds = getOpenFdCount(); + + if (finalOpenFds < initialOpenFds + numOfClicks) { + // when there was a file leak, the number of open file handle was always + // greater or equal to the number of download + // in reverse, since the correction, the likelihood to overpass the limit was less than 1% + freeFromLeak = true; + } + + openFds[runs][0] = initialOpenFds; + openFds[runs][1] = finalOpenFds; + } + + List messages = new ArrayList<>(); + Map differences = new TreeMap<>(); + for (int runs = 0; runs < totalRuns; runs++) { + long difference = openFds[runs][1] - openFds[runs][0]; + Long storedDifference = differences.get(difference); + if (storedDifference == null) { + differences.put(difference, 1L); + } else { + differences.put(difference, ++storedDifference); + } + messages.add("Initial=" + openFds[runs][0] + ", Final=" + openFds[runs][1] + ", difference=" + difference); + } + for (Long difference : differences.keySet()) { + messages.add("Difference=" + difference + " occurs " + differences.get(difference) + " times"); + } + + String summary = String.join("\n", messages); + System.out.println("Summary of the test: \n"+ summary); + assertTrue("There should be no difference greater than "+numOfClicks+", but the output was: \n"+ summary, freeFromLeak); + } + + private long getOpenFdCount() { + OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean(); + if(os instanceof UnixOperatingSystemMXBean){ + return ((UnixOperatingSystemMXBean) os).getOpenFileDescriptorCount(); + } + return -1; + } + @Issue("SECURITY-95") @Test public void contentSecurityPolicy() throws Exception { diff --git a/test/src/test/java/hudson/model/EnvironmentContributorTest.java b/test/src/test/java/hudson/model/EnvironmentContributorTest.java index c426647dea..40946e4c26 100644 --- a/test/src/test/java/hudson/model/EnvironmentContributorTest.java +++ b/test/src/test/java/hudson/model/EnvironmentContributorTest.java @@ -26,7 +26,7 @@ public class EnvironmentContributorTest { j.assertBuildStatusSuccess(p.scheduleBuild2(0)); assertEquals("Issac Newton", c.getEnvVars().get("ABC")); - assertEquals("master", c.getEnvVars().get("NODE_NAME")); + assertEquals("built-in", c.getEnvVars().get("NODE_NAME")); } @TestExtension("projectScoped") diff --git a/test/src/test/java/hudson/model/HudsonTest.java b/test/src/test/java/hudson/model/HudsonTest.java index 33dfdf6c92..cf88609533 100644 --- a/test/src/test/java/hudson/model/HudsonTest.java +++ b/test/src/test/java/hudson/model/HudsonTest.java @@ -155,35 +155,35 @@ public class HudsonTest { } /** - * Configure link from "/computer/(master)/" should work. + * Configure link from "/computer/(built-in)/" should work. */ @Test @Email("http://www.nabble.com/Master-slave-refactor-td21361880.html") public void computerConfigureLink() throws Exception { - HtmlPage page = j.createWebClient().goTo("computer/(master)/configure"); + HtmlPage page = j.createWebClient().goTo("computer/(built-in)/configure"); j.submit(page.getFormByName("config")); } /** - * Configure link from "/computer/(master)/" should work. + * Configure link from "/computer/(built-in)/" should work. */ @Test @Email("http://www.nabble.com/Master-slave-refactor-td21361880.html") public void deleteHudsonComputer() throws Exception { WebClient wc = j.createWebClient(); - HtmlPage page = wc.goTo("computer/(master)/"); + HtmlPage page = wc.goTo("computer/(built-in)/"); for (HtmlAnchor a : page.getAnchors()) { assertFalse(a.getHrefAttribute(), a.getHrefAttribute().endsWith("delete")); } wc.setThrowExceptionOnFailingStatusCode(false); // try to delete it by hitting the final URL directly - WebRequest req = new WebRequest(new URL(wc.getContextPath()+"computer/(master)/doDelete"), HttpMethod.POST); + WebRequest req = new WebRequest(new URL(wc.getContextPath()+"computer/(built-in)/doDelete"), HttpMethod.POST); page = wc.getPage(wc.addCrumb(req)); assertEquals(HttpURLConnection.HTTP_BAD_REQUEST, page.getWebResponse().getStatusCode()); - // the master computer object should be still here - page = wc.goTo("computer/(master)/"); + // the built-in computer object should be still here + page = wc.goTo("computer/(built-in)/"); assertEquals(HttpURLConnection.HTTP_OK, page.getWebResponse().getStatusCode()); } diff --git a/test/src/test/java/hudson/model/MyViewTest.java b/test/src/test/java/hudson/model/MyViewTest.java index d464897d9a..839dafede2 100644 --- a/test/src/test/java/hudson/model/MyViewTest.java +++ b/test/src/test/java/hudson/model/MyViewTest.java @@ -61,7 +61,7 @@ public class MyViewTest { } @Test - public void testContains() throws IOException, Exception{ + public void testContains() throws Exception{ GlobalMatrixAuthorizationStrategy auth = new GlobalMatrixAuthorizationStrategy(); rule.jenkins.setAuthorizationStrategy(auth); @@ -77,7 +77,7 @@ public class MyViewTest { } @Test - public void testDoCreateItem() throws IOException, Exception{ + public void testDoCreateItem() throws Exception{ logs.record(AbstractItem.class, Level.ALL); MyView view = new MyView("My", rule.jenkins); rule.jenkins.addView(view); diff --git a/test/src/test/java/hudson/model/MyViewsPropertyTest.java b/test/src/test/java/hudson/model/MyViewsPropertyTest.java index 7106f352de..e5970ff654 100644 --- a/test/src/test/java/hudson/model/MyViewsPropertyTest.java +++ b/test/src/test/java/hudson/model/MyViewsPropertyTest.java @@ -234,7 +234,7 @@ public class MyViewsPropertyTest { property.setUser(user); user.addProperty(property); for(Permission p : Permission.getAll()){ - assertEquals("Property should have the same ACL as its user", property.getACL().hasPermission(p), user.getACL().hasPermission(p)); + assertEquals("Property should have the same ACL as its user", property.hasPermission(p), user.hasPermission(p)); } } diff --git a/test/src/test/java/hudson/model/NodeTest.java b/test/src/test/java/hudson/model/NodeTest.java index bfa11836b4..852795cc6c 100644 --- a/test/src/test/java/hudson/model/NodeTest.java +++ b/test/src/test/java/hudson/model/NodeTest.java @@ -379,8 +379,8 @@ public class NodeTest { @Test public void builtInComputerConfigDotXml() throws Exception { JenkinsRule.WebClient wc = j.createWebClient(); - wc.assertFails("computer/(master)/config.xml", HttpURLConnection.HTTP_BAD_REQUEST); - WebRequest settings = new WebRequest(wc.createCrumbedUrl("computer/(master)/config.xml")); + wc.assertFails("computer/(built-in)/config.xml", HttpURLConnection.HTTP_BAD_REQUEST); + WebRequest settings = new WebRequest(wc.createCrumbedUrl("computer/(built-in)/config.xml")); settings.setHttpMethod(HttpMethod.POST); settings.setRequestBody(""); @@ -408,13 +408,11 @@ public class NodeTest { } // Gather information for failure message just in case. - containsFailureMessage.append("{").append(entry.item.toString()).append(", ").append(entry.weight).append("}"); + containsFailureMessage.append("{").append(entry.item).append(", ").append(entry.weight).append("}"); } // If a label should be part of the cloud label then fail. - if (contains) { - fail(containsFailureMessage.toString() + "]"); - } + assertFalse(containsFailureMessage + "]", contains); } /** diff --git a/test/src/test/java/hudson/model/RSSTest.java b/test/src/test/java/hudson/model/RSSTest.java index 2053fd6475..0fc35a1322 100644 --- a/test/src/test/java/hudson/model/RSSTest.java +++ b/test/src/test/java/hudson/model/RSSTest.java @@ -183,8 +183,8 @@ public class RSSTest { public void checkWithSingleBuild_Rss_All_Computer() throws Exception { runSuccessfulBuild(); - String pathPrefix = "computer/(master)/"; - String displayName = "master"; + String pathPrefix = "computer/(built-in)/"; + String displayName = Messages.Hudson_Computer_DisplayName(); String buildType = ALL_BUILD_TYPE; String buildTitle = STABLE_BUILD_TITLE; XmlPage page = getRssAllPage(pathPrefix); @@ -195,8 +195,8 @@ public class RSSTest { public void checkWithSingleBuild_Rss_Failed_Computer() throws Exception { runFailingBuild(); - String pathPrefix = "computer/(master)/"; - String displayName = "master"; + String pathPrefix = "computer/(built-in)/"; + String displayName = Messages.Hudson_Computer_DisplayName(); String buildType = FAILED_BUILD_TYPE; String buildTitle = FAILED_BUILD_TITLE; XmlPage page = getRssFailedPage(pathPrefix); @@ -205,8 +205,8 @@ public class RSSTest { @Test public void latestBuilds_Computer() throws Exception { - String pathPrefix = "computer/(master)/"; - String displayName = "master"; + String pathPrefix = "computer/(built-in)/"; + String displayName = Messages.Hudson_Computer_DisplayName(); String buildType = LATEST_BUILD_TYPE; int expectedLinks = 3; int expectedAllLinks = 6; diff --git a/test/src/test/java/hudson/model/ViewTest.java b/test/src/test/java/hudson/model/ViewTest.java index 936471d32b..60b8ab410f 100644 --- a/test/src/test/java/hudson/model/ViewTest.java +++ b/test/src/test/java/hudson/model/ViewTest.java @@ -313,7 +313,7 @@ public class ViewTest { } @Test - public void testGetQueueItems() throws IOException, Exception{ + public void testGetQueueItems() throws Exception{ ListView view1 = listView("view1"); view1.filterQueue = true; ListView view2 = listView("view2"); @@ -367,7 +367,7 @@ public class ViewTest { } @Test - public void testGetComputers() throws IOException, Exception{ + public void testGetComputers() throws Exception{ ListView view1 = listView("view1"); ListView view2 = listView("view2"); ListView view3 = listView("view3"); diff --git a/test/src/test/java/hudson/model/labels/LabelExpressionTest.java b/test/src/test/java/hudson/model/labels/LabelExpressionTest.java index eeb39e4821..c82672a470 100644 --- a/test/src/test/java/hudson/model/labels/LabelExpressionTest.java +++ b/test/src/test/java/hudson/model/labels/LabelExpressionTest.java @@ -262,7 +262,7 @@ public class LabelExpressionTest { assertTrue(msg.contains("foo")); assertTrue(msg.contains("goo")); - msg = LabelExpression.validate("master && goo").renderHtml(); + msg = LabelExpression.validate("built-in && goo").renderHtml(); assertTrue(msg.contains("foo")); assertTrue(msg.contains("goo")); return null; diff --git a/test/src/test/java/hudson/security/ACLTest.java b/test/src/test/java/hudson/security/ACLTest.java index c04cc134c3..554e59f0e3 100644 --- a/test/src/test/java/hudson/security/ACLTest.java +++ b/test/src/test/java/hudson/security/ACLTest.java @@ -46,6 +46,7 @@ import org.jvnet.hudson.test.MockAuthorizationStrategy; import org.jvnet.hudson.test.TestExtension; import edu.umd.cs.findbugs.annotations.CheckForNull; +import hudson.model.Job; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.core.Authentication; @@ -195,6 +196,11 @@ public class ACLTest { }; } + @Override + public ACL getACL(Job project) { + throw new AssertionError("should not have even needed to call getACL"); + } + @NonNull @Override public Collection getGroups() { diff --git a/test/src/test/java/hudson/security/SecurityRealmTest.java b/test/src/test/java/hudson/security/SecurityRealmTest.java index e4b5b41e31..e2f95d9093 100644 --- a/test/src/test/java/hudson/security/SecurityRealmTest.java +++ b/test/src/test/java/hudson/security/SecurityRealmTest.java @@ -143,7 +143,7 @@ public class SecurityRealmTest { } } } - System.err.println(builder.toString()); + System.err.println(builder); assertThat(unexpectedSessionCookies, is(0)); } diff --git a/test/src/test/java/hudson/tasks/FingerprinterTest.java b/test/src/test/java/hudson/tasks/FingerprinterTest.java index 2043aa2c0b..701c01e9e9 100644 --- a/test/src/test/java/hudson/tasks/FingerprinterTest.java +++ b/test/src/test/java/hudson/tasks/FingerprinterTest.java @@ -383,7 +383,7 @@ public class FingerprinterTest { } - private FreeStyleProject createFreeStyleProjectWithFingerprints(String[] contents, String[] files) throws IOException, Exception { + private FreeStyleProject createFreeStyleProjectWithFingerprints(String[] contents, String[] files) throws Exception { FreeStyleProject project = j.createFreeStyleProject(); addFingerprinterToProject(project, contents, files); @@ -391,7 +391,7 @@ public class FingerprinterTest { return project; } - private void addFingerprinterToProject(AbstractProject project, String[] contents, String[] files) throws Exception { + private void addFingerprinterToProject(AbstractProject project, String[] contents, String[] files) { StringBuilder targets = new StringBuilder(); for (int i = 0; i < contents.length; i++) { if (project instanceof MatrixProject) { diff --git a/test/src/test/java/hudson/tasks/UserAvatarResolverTest.java b/test/src/test/java/hudson/tasks/UserAvatarResolverTest.java index ef3e4b1e94..53b1e37c1e 100644 --- a/test/src/test/java/hudson/tasks/UserAvatarResolverTest.java +++ b/test/src/test/java/hudson/tasks/UserAvatarResolverTest.java @@ -23,6 +23,8 @@ */ package hudson.tasks; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.endsWith; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -45,21 +47,21 @@ public class UserAvatarResolverTest { @Test public void defaultImageIsReturnedIfRegexFails() { - String avatar = UserAvatarResolver.resolve(User.get("USER"), "meh"); - assertTrue(avatar.endsWith("/images/meh/user.png")); + String avatar = UserAvatarResolver.resolve(User.getOrCreateByIdOrFullName("USER"), "meh"); + assertThat(avatar, endsWith("/images/svgs/person.svg")); } @Test public void resolverIsUsed() { - expUser = User.get("unique-user-not-used-in-anyother-test", true); + expUser = User.getOrCreateByIdOrFullName("unique-user-not-used-in-anyother-test"); String avatar = UserAvatarResolver.resolve(expUser, "20x20"); assertEquals("http://myown.image", avatar); } @Test public void noResolverCanFindAvatar() { - String avatar = UserAvatarResolver.resolve(User.get("USER"), "20x20"); - assertTrue(avatar.endsWith("/images/20x20/user.png")); + String avatar = UserAvatarResolver.resolve(User.getOrCreateByIdOrFullName("USER"), "20x20"); + assertThat(avatar, endsWith("/images/svgs/person.svg")); } @Test @@ -73,7 +75,6 @@ public class UserAvatarResolverTest { @Extension public static final class UserAvatarResolverImpl extends UserAvatarResolver { - @Override public String findAvatarFor(User u, int width, int height) { if (u != null && u == expUser) { diff --git a/test/src/test/java/hudson/tools/InstallerTranslatorTest.java b/test/src/test/java/hudson/tools/InstallerTranslatorTest.java index 25cbef83f9..d4d5f09c74 100644 --- a/test/src/test/java/hudson/tools/InstallerTranslatorTest.java +++ b/test/src/test/java/hudson/tools/InstallerTranslatorTest.java @@ -128,8 +128,8 @@ public class InstallerTranslatorTest { ? new BatchCommandInstaller("wrong1", "echo hello", "C:\\jdk") : new CommandInstaller("wrong1", "echo hello", "/opt/jdk"); final AbstractCommandInstaller ci2 = Functions.isWindows() - ? new BatchCommandInstaller("master", "echo hello", "C:\\jdk2") - : new CommandInstaller("master", "echo hello", "/opt/jdk2"); + ? new BatchCommandInstaller("built-in", "echo hello", "C:\\jdk2") + : new CommandInstaller("built-in", "echo hello", "/opt/jdk2"); InstallSourceProperty isp = new InstallSourceProperty(Arrays.asList(ci, ci2)); JDK jdk = new JDK("jdk", null, Collections.singletonList(isp)); diff --git a/test/src/test/java/hudson/util/BootFailureTest.java b/test/src/test/java/hudson/util/BootFailureTest.java index 4a2a0f292a..f519e372fc 100644 --- a/test/src/test/java/hudson/util/BootFailureTest.java +++ b/test/src/test/java/hudson/util/BootFailureTest.java @@ -71,7 +71,7 @@ public class BootFailureTest { ServletContext ws = createWebServer((context, server) -> { NoListenerConfiguration noListenerConfiguration = context.getBean(NoListenerConfiguration.class); // future-proof - Assert.notNull(noListenerConfiguration); + Assert.notNull(noListenerConfiguration, "Value must not be null"); if (noListenerConfiguration != null) { context.removeBean(noListenerConfiguration); context.addBean(new AbstractLifeCycle() { diff --git a/test/src/test/java/jenkins/install/SetupWizardTest.java b/test/src/test/java/jenkins/install/SetupWizardTest.java index bfa3534d81..7f34c82fe6 100644 --- a/test/src/test/java/jenkins/install/SetupWizardTest.java +++ b/test/src/test/java/jenkins/install/SetupWizardTest.java @@ -179,7 +179,7 @@ public class SetupWizardTest { private final File tmpdir; CustomLocalUpdateSite(File tmpdir) throws MalformedURLException { - super("custom-uc", tmpdir.toURI().toURL().toString() + "update-center.json"); + super("custom-uc", tmpdir.toURI().toURL() + "update-center.json"); this.tmpdir = tmpdir; } @@ -197,7 +197,7 @@ public class SetupWizardTest { private final File tmpdir; CustomLocalUpdateSiteWithWrapperJSON(File tmpdir) throws MalformedURLException { - super("custom-uc2", tmpdir.toURI().toURL().toString() + "update-center.json"); + super("custom-uc2", tmpdir.toURI().toURL() + "update-center.json"); this.tmpdir = tmpdir; } diff --git a/test/src/test/java/jenkins/model/BuiltInNodeMigrationPropertyTest.java b/test/src/test/java/jenkins/model/BuiltInNodeMigrationPropertyTest.java new file mode 100644 index 0000000000..07dfa44310 --- /dev/null +++ b/test/src/test/java/jenkins/model/BuiltInNodeMigrationPropertyTest.java @@ -0,0 +1,67 @@ +/* + * The MIT License + * + * Copyright (c) 2021 Daniel Beck + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package jenkins.model; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.recipes.LocalData; + +public class BuiltInNodeMigrationPropertyTest { + public static final String KEY = Jenkins.class.getName() + ".nodeNameAndSelfLabelOverride"; + public static final String OVERRIDE_VALUE = "foo"; + @Rule + public JenkinsRule j = new JenkinsRule(); + + @BeforeClass + public static void setProperty() { + System.setProperty(KEY, OVERRIDE_VALUE); + } + + @AfterClass + public static void clearProperty() { + System.clearProperty(KEY); + } + + @Test + public void overrideAppliesToNewInstance() throws Exception { + BuiltInNodeMigrationTest.assertStatus(j, true, false, OVERRIDE_VALUE, OVERRIDE_VALUE); + } + + @Test + @LocalData + public void overrideAppliesToUnmigratedInstance() throws Exception { + BuiltInNodeMigrationTest.assertStatus(j, false, true, OVERRIDE_VALUE, OVERRIDE_VALUE); + j.jenkins.performRenameMigration(); + BuiltInNodeMigrationTest.assertStatus(j, true, false, OVERRIDE_VALUE, OVERRIDE_VALUE); + } + + @Test + @LocalData + public void overrideAppliesToMigratedInstance() throws Exception { + BuiltInNodeMigrationTest.assertStatus(j, true, false, OVERRIDE_VALUE, OVERRIDE_VALUE); + } +} diff --git a/test/src/test/java/jenkins/model/BuiltInNodeMigrationRestartTest.java b/test/src/test/java/jenkins/model/BuiltInNodeMigrationRestartTest.java new file mode 100644 index 0000000000..585141ad8e --- /dev/null +++ b/test/src/test/java/jenkins/model/BuiltInNodeMigrationRestartTest.java @@ -0,0 +1,114 @@ +package jenkins.model; + +import org.apache.commons.io.FileUtils; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.Description; +import org.jvnet.hudson.test.HudsonHomeLoader; +import org.jvnet.hudson.test.JenkinsRecipe; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.JenkinsSessionRule; +import org.jvnet.hudson.test.recipes.LocalData; + +import java.io.File; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import java.lang.reflect.Method; +import java.util.Objects; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +public class BuiltInNodeMigrationRestartTest { + @Rule + public JenkinsSessionRule r = new JenkinsSessionRule(); + + @Test + public void testNewInstanceWithoutConfiguration() throws Throwable { + r.then(j -> { + Assert.assertTrue(j.jenkins.getRenameMigrationDone()); + Assert.assertFalse(j.jenkins.nodeRenameMigrationNeeded); + Assert.assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated()); + }); + r.then(j -> { + Assert.assertTrue(j.jenkins.getRenameMigrationDone()); + Assert.assertFalse(j.jenkins.nodeRenameMigrationNeeded); + Assert.assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated()); + }); + } + + @Test + @LocalDataOnce + public void migratedInstanceStartsWithNewTerminology() throws Throwable { + r.then(j -> { + Assert.assertTrue(j.jenkins.getRenameMigrationDone()); + Assert.assertFalse(j.jenkins.nodeRenameMigrationNeeded); + Assert.assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated()); + }); + r.then(j -> { + Assert.assertTrue(j.jenkins.getRenameMigrationDone()); + Assert.assertFalse(j.jenkins.nodeRenameMigrationNeeded); + Assert.assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated()); + }); + } + + @Test + @LocalDataOnce + public void oldDataStartsWithOldTerminology() throws Throwable { + r.then(j -> { + Assert.assertFalse(j.jenkins.getRenameMigrationDone()); + Assert.assertTrue(j.jenkins.nodeRenameMigrationNeeded); + Assert.assertTrue(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated()); + }); + r.then(j -> { + Assert.assertFalse(j.jenkins.getRenameMigrationDone()); + Assert.assertTrue(j.jenkins.nodeRenameMigrationNeeded); + Assert.assertTrue(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated()); + + j.jenkins.performRenameMigration(); + + Assert.assertTrue(j.jenkins.getRenameMigrationDone()); + Assert.assertFalse(j.jenkins.nodeRenameMigrationNeeded); + Assert.assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated()); + }); + r.then(j -> { + Assert.assertTrue(j.jenkins.getRenameMigrationDone()); + Assert.assertFalse(j.jenkins.nodeRenameMigrationNeeded); + Assert.assertFalse(Objects.requireNonNull(j.jenkins.getAdministrativeMonitor(BuiltInNodeMigration.class.getName())).isActivated()); + }); + } + + /** + * Like {@link LocalData} except it only provides the JENKINS_HOME content if the directory is currently empty. + */ + @JenkinsRecipe(LocalDataOnce.RuleRunnerImpl.class) + @Target(METHOD) + @Retention(RUNTIME) + private @interface LocalDataOnce { + class RuleRunnerImpl extends JenkinsRecipe.Runner { + public static final Logger LOGGER = Logger.getLogger(RuleRunnerImpl.class.getName()); + private Method method; + + public void setup(JenkinsRule jenkinsRule, LocalDataOnce recipe) throws Exception { + Description desc = jenkinsRule.getTestDescription(); + method = desc.getTestClass().getMethod((desc.getMethodName())); + } + + @Override + public void decorateHome(JenkinsRule jenkinsRule, File home) throws Exception { + // Only copy the home directory if it doesn't have content yet + final File[] files = home.listFiles(); + if (!home.exists() || !home.isDirectory() || files == null || files.length == 0) { + LOGGER.log(Level.INFO, () -> "Copying JENKINS_HOME from test resources to " + home); + File source = new HudsonHomeLoader.Local(method, "").allocate(); + FileUtils.copyDirectory(source, home); + } else { + LOGGER.log(Level.INFO, () -> "JENKINS_HOME " + home + " is not empty, skipping copy from test resources"); + } + } + } + } +} diff --git a/test/src/test/java/jenkins/model/BuiltInNodeMigrationTest.java b/test/src/test/java/jenkins/model/BuiltInNodeMigrationTest.java new file mode 100644 index 0000000000..080a717bfc --- /dev/null +++ b/test/src/test/java/jenkins/model/BuiltInNodeMigrationTest.java @@ -0,0 +1,79 @@ +/* + * The MIT License + * + * Copyright (c) 2021 Daniel Beck + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package jenkins.model; + +import hudson.ExtensionList; +import hudson.model.FreeStyleProject; +import hudson.model.labels.LabelAtom; +import org.junit.Rule; +import org.junit.Test; +import org.jvnet.hudson.test.CaptureEnvironmentBuilder; +import org.jvnet.hudson.test.JenkinsRule; +import org.jvnet.hudson.test.recipes.LocalData; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class BuiltInNodeMigrationTest { + @Rule + public JenkinsRule j = new JenkinsRule(); + + @Test + public void newInstanceHasNewTerminology() throws Exception { + assertStatus(j, true, false, "built-in", "built-in"); + assertFalse(ExtensionList.lookupSingleton(BuiltInNodeMigration.class).isActivated()); + } + + @Test + @LocalData + public void oldDataStartsWithOldTerminology() throws Exception { + assertStatus(j, false, true, "master", "master"); + final BuiltInNodeMigration builtInNodeMigration = ExtensionList.lookupSingleton(BuiltInNodeMigration.class); + assertTrue(builtInNodeMigration.isActivated()); + + // Now perform rename and confirm it's done + j.jenkins.performRenameMigration(); + assertStatus(j, true, false, "built-in", "built-in"); + assertFalse(builtInNodeMigration.isActivated()); + } + + @Test + @LocalData + public void migratedInstanceStartsWithNewTerminology() throws Exception { + assertStatus(j, true, false, "built-in", "built-in"); + assertFalse(ExtensionList.lookupSingleton(BuiltInNodeMigration.class).isActivated()); + } + + public static void assertStatus(JenkinsRule j, boolean migrationDoneGetterValue, Boolean migrationNeededFieldValue, String label, String nodeName) throws Exception { + assertEquals(migrationDoneGetterValue, j.jenkins.getRenameMigrationDone()); + assertEquals(migrationNeededFieldValue, j.jenkins.nodeRenameMigrationNeeded); + assertEquals(new LabelAtom(label), j.jenkins.getSelfLabel()); + final FreeStyleProject freeStyleProject = j.createFreeStyleProject(); + final CaptureEnvironmentBuilder environmentBuilder = new CaptureEnvironmentBuilder(); + freeStyleProject.getBuildersList().add(environmentBuilder); + j.buildAndAssertSuccess(freeStyleProject); + assertEquals(nodeName, environmentBuilder.getEnvVars().get("NODE_NAME")); + } +} diff --git a/test/src/test/java/jenkins/model/JenkinsManagePermissionTest.java b/test/src/test/java/jenkins/model/JenkinsManagePermissionTest.java index cf6b175ef9..890bb37391 100644 --- a/test/src/test/java/jenkins/model/JenkinsManagePermissionTest.java +++ b/test/src/test/java/jenkins/model/JenkinsManagePermissionTest.java @@ -113,8 +113,8 @@ public class JenkinsManagePermissionTest { .grant(Jenkins.MANAGE).everywhere().to(MANAGER) .grant(Jenkins.READ).everywhere().to(MANAGER) ); - j.createWebClient().login(READER).assertFails("computer/(master)/dumpExportTable", HttpURLConnection.HTTP_FORBIDDEN); - j.createWebClient().login(MANAGER).assertFails("computer/(master)/dumpExportTable", HttpURLConnection.HTTP_FORBIDDEN); + j.createWebClient().login(READER).assertFails("computer/(built-in)/dumpExportTable", HttpURLConnection.HTTP_FORBIDDEN); + j.createWebClient().login(MANAGER).assertFails("computer/(built-in)/dumpExportTable", HttpURLConnection.HTTP_FORBIDDEN); } // End of ComputerTest diff --git a/test/src/test/java/jenkins/telemetry/MissingClassTelemetryTest.java b/test/src/test/java/jenkins/telemetry/MissingClassTelemetryTest.java deleted file mode 100644 index 5f60f5de34..0000000000 --- a/test/src/test/java/jenkins/telemetry/MissingClassTelemetryTest.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * 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.telemetry; - -import edu.umd.cs.findbugs.annotations.CheckForNull; -import hudson.ExtensionList; -import hudson.model.UnprotectedRootAction; -import hudson.security.csrf.CrumbExclusion; -import jenkins.telemetry.impl.java11.CatcherClassLoader; -import jenkins.telemetry.impl.java11.MissingClassTelemetry; -import net.sf.json.JSONArray; -import net.sf.json.JSONObject; -import org.apache.commons.io.IOUtils; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.jvnet.hudson.test.JenkinsRule; -import org.jvnet.hudson.test.TestExtension; -import org.kohsuke.stapler.StaplerRequest; -import org.kohsuke.stapler.StaplerResponse; - -import javax.servlet.FilterChain; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; -import java.time.LocalDate; - -import static org.junit.Assert.assertEquals; - -/** - * This test needs to be here to be able to modify the {@link Telemetry#ENDPOINT} as it's package protected. - */ -public class MissingClassTelemetryTest { - private static final String TELEMETRY_ENDPOINT = "uplink"; - private CatcherClassLoader cl; - - @Rule - public JenkinsRule j = new JenkinsRule(); - - private static JSONObject received = null; - - @Before - public void prepare() throws Exception { - received = null; - cl = new CatcherClassLoader(this.getClass().getClassLoader()); - Telemetry.ENDPOINT = j.getURL().toString() + TELEMETRY_ENDPOINT + "/events"; - j.jenkins.setNoUsageStatistics(false); // tests usually don't submit this, but we need this - } - - /** - * Test if the telemetry sent works and the received data is the expected for a specific case (5 occurrences of the - * same stack trace). - * @throws InterruptedException if the thread is interrupted while sleeping - */ - @Test - public void telemetrySentWorks() throws InterruptedException { - Assume.assumeTrue("The telemetry should be enabled", MissingClassTelemetry.enabled()); - Assume.assumeTrue("The telemetry shouldn't be ended", Telemetry.all().get(MissingClassTelemetry.class).getEnd().isAfter(LocalDate.now())); - // Generate 5 events - for(int i = 0; i < 5; i++) { - try { - cl.loadClass("sun.java.MyNonExistentClass"); - } catch (ClassNotFoundException ignored) { - } - } - - // Run the telemetry sent - ExtensionList.lookupSingleton(Telemetry.TelemetryReporter.class).doRun(); - do { - - Thread.sleep(250); - } while (received == null); // this might end up being flaky due to 1 to many active telemetry trials - - - // The telemetry stuff sent is the class expected, the number of events is 1, the class not found is the - // expected and the number of occurrences is the expected - assertEquals(MissingClassTelemetry.class.getName(), received.getString("type")); - JSONArray events = received.getJSONObject("payload").getJSONArray("classMissingEvents"); - assertEquals(1, events.size()); - assertEquals("sun.java.MyNonExistentClass", ((JSONObject) events.get(0)).get("className")); - assertEquals(5, Integer.parseInt( (String) ((JSONObject) events.get(0)).get("occurrences"))); - } - - /** - * Avoid crumb checking (CSRF) - */ - @TestExtension - public static class NoCrumb extends CrumbExclusion { - @Override - public boolean process(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { - String pathInfo = request.getPathInfo(); - if (pathInfo != null && pathInfo.startsWith("/uplink")) { - chain.doFilter(request, response); - return true; - } - return false; - } - } - - @TestExtension - public static class TelemetryReceiver implements UnprotectedRootAction { - public void doEvents(StaplerRequest request, StaplerResponse response) throws IOException { - StringWriter sw = new StringWriter(); - IOUtils.copy(request.getInputStream(), sw, StandardCharsets.UTF_8); - received = JSONObject.fromObject(sw.toString()); - } - - @CheckForNull - @Override - public String getIconFileName() { - return null; - } - - @CheckForNull - @Override - public String getDisplayName() { - return null; - } - - @CheckForNull - @Override - public String getUrlName() { - return TELEMETRY_ENDPOINT; - } - } -} diff --git a/test/src/test/java/jenkins/telemetry/impl/java11/MissingClassTelemetryFasterTest.java b/test/src/test/java/jenkins/telemetry/impl/java11/MissingClassTelemetryFasterTest.java deleted file mode 100644 index 7862aa7185..0000000000 --- a/test/src/test/java/jenkins/telemetry/impl/java11/MissingClassTelemetryFasterTest.java +++ /dev/null @@ -1,388 +0,0 @@ -/* - * 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.telemetry.impl.java11; - -import org.junit.Assume; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.jvnet.hudson.test.LoggerRule; - -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Logger; - -import static org.hamcrest.Matchers.not; -import static org.hamcrest.core.StringContains.containsString; -import static org.junit.Assert.assertEquals; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Tests without a running Jenkins for Java11 Telemetry of ClassNotFoundException. - */ -public class MissingClassTelemetryFasterTest { - final String NON_EXISTING_CLASS = "sun.java.MyNonExistentJavaClass"; - - private CatcherClassLoader cl; - - @Rule - public LoggerRule logging = new LoggerRule().record(MissingClassTelemetry.class, Logger.getLogger(MissingClassTelemetry.class.getName()).getLevel()).capture(5); - - @Before - public void cleanEvents() { - cl = new CatcherClassLoader(this.getClass().getClassLoader()); - MissingClassTelemetry.getEvents().getEventsAndClean(); - MissingClassTelemetry.getEvents().clearEventsOnThisExecution(); - } - - @Test - public void maxNumberEvents() { - Assume.assumeTrue("The telemetry should be enabled", MissingClassTelemetry.enabled()); - - // Backup to restore at the end of the test - int maxEventsBefore = MissingClassEvents.MAX_EVENTS_PER_SEND; - - try { - MissingClassEvents.MAX_EVENTS_PER_SEND = 1; - - try { - cl.loadClass(NON_EXISTING_CLASS); - } catch (ClassNotFoundException ignored) { - } - - try { - cl.loadClass("sun.java.MySecondNonExistentJavaClass"); - } catch (ClassNotFoundException ignored) { - } - - - ConcurrentHashMap, MissingClassEvent> eventsGathered = MissingClassTelemetry.getEvents().getEventsAndClean(); - - // Only one class miss gathered - assertEquals(1, eventsGathered.size()); - - // 2 log entries - assertEquals("Two missing class should be printed out in the log", 2, logging.getRecords().stream().filter(r -> r.getMessage().contains(NON_EXISTING_CLASS) || - r.getMessage().contains("sun.java.MySecondNonExistentJavaClass")).count()); - } finally { - MissingClassEvents.MAX_EVENTS_PER_SEND = maxEventsBefore; - } - } - - /** - * The same class failed to be loaded in different places ends up in two records of telemetry with one occurrence - * each. - */ - @Test - public void differentEventsAlthoughSameClass() { - Assume.assumeTrue("The telemetry should be enabled", MissingClassTelemetry.enabled()); - - try { - cl.loadClass(NON_EXISTING_CLASS); - } catch (ClassNotFoundException ignored) { - } - - try { - cl.loadClass(NON_EXISTING_CLASS); - } catch (ClassNotFoundException ignored) { - } - - // Get the events gathered - MissingClassEvents events = MissingClassTelemetry.getEvents(); - ConcurrentHashMap, MissingClassEvent> eventsGathered = events.getEventsAndClean(); - - // Only one class miss gathered with two occurrences - assertEquals(2, eventsGathered.size()); - assertEquals(1, eventsGathered.values().iterator().next().getOccurrences()); - assertEquals(1, eventsGathered.values().iterator().next().getOccurrences()); - - // The stack trace of these CNFE are different but we only look at class names when printing on logs, so - // just one log entry - assertEquals("Single missing class should be printed out in the log", 1, logging.getRecords().stream().filter(r -> r.getMessage().contains(NON_EXISTING_CLASS)).count()); - } - - /** - * The same class thrown in the same line ends up in a single event with two occurrences. - */ - @Test - public void addOccurrenceIfSameStackTrace() { - Assume.assumeTrue("The telemetry should be enabled", MissingClassTelemetry.enabled()); - - for (int i = 0; i < 2; i++) { - try { - //Exceptions thrown at the same line, with the same stack trace become occurrences of just one event - cl.loadClass(NON_EXISTING_CLASS); - } catch (ClassNotFoundException ignored) { - } - } - - // Get the events gathered - MissingClassEvents events = MissingClassTelemetry.getEvents(); - ConcurrentHashMap, MissingClassEvent> eventsGathered = events.getEventsAndClean(); - - // Only one class miss gathered with two occurrences - assertEquals(1, eventsGathered.size()); - assertEquals(2, eventsGathered.values().iterator().next().getOccurrences()); - - // The class name and also the stack trace of these CNFEs are the same, so 1 log event - assertEquals("Just one missing class should be printed out in the log", 1, logging.getRecords().stream().filter(r -> r.getMessage().contains(NON_EXISTING_CLASS)).count()); - } - - /** - * A class not from the split packages is not gathered. - */ - @Test - public void nonJavaClassesNotGathered() { - Assume.assumeTrue("The telemetry should be enabled", MissingClassTelemetry.enabled()); - - try { - cl.loadClass("jenkins.MyNonExistentClass"); - } catch (ClassNotFoundException ignored) { - } - - // Get the events gathered - MissingClassEvents events = MissingClassTelemetry.getEvents(); - ConcurrentHashMap, MissingClassEvent> eventsGathered = events.getEventsAndClean(); - - // No events gathered - assertEquals(0, eventsGathered.size()); - - // No log - assertEquals("No log if the class is not a java one", 0, logging.getRecords().stream().filter(r -> r.getMessage().contains(NON_EXISTING_CLASS)).count()); - } - - /** - * Only a max number of events is gathered. In this test, just one with two occurrences - */ - @Test - public void maxEventsLimitedSameStackTrace() { - Assume.assumeTrue("The telemetry should be enabled", MissingClassTelemetry.enabled()); - - // Backup to restore at the end of the test - int maxEventsBefore = MissingClassEvents.MAX_EVENTS_PER_SEND; - MissingClassEvents.MAX_EVENTS_PER_SEND = 1; - try { - for (int i = 0; i < 2; i++) { - try { - //Exceptions thrown at the same line, with the same stack trace become occurrences of just one event - cl.loadClass(NON_EXISTING_CLASS); - } catch (ClassNotFoundException ignored) { - } - } - - // Get the events gathered - MissingClassEvents events = MissingClassTelemetry.getEvents(); - ConcurrentHashMap, MissingClassEvent> eventsGathered = events.getEventsAndClean(); - - // Only one event gathered - assertEquals(1, eventsGathered.size()); - assertEquals(2, eventsGathered.values().iterator().next().getOccurrences()); - - assertEquals("One event should be logged", 1, logging.getRecords().stream().filter(r -> r.getMessage().contains(NON_EXISTING_CLASS)).count()); - } finally { - MissingClassEvents.MAX_EVENTS_PER_SEND = maxEventsBefore; - } - } - - /** - * Only a max number of events is gathered. In this test, just one wit one occurrence. The second one is discarded - */ - @Test - public void maxEventsLimitedDifferentStackTrace() { - Assume.assumeTrue("The telemetry should be enabled", MissingClassTelemetry.enabled()); - - // Backup to restore at the end of the test - int maxEventsBefore = MissingClassEvents.MAX_EVENTS_PER_SEND; - MissingClassEvents.MAX_EVENTS_PER_SEND = 1; - - try { - try { - cl.loadClass("sun.java.MyNonExistentClassGathered"); - } catch (ClassNotFoundException ignored) { - } - - try { - cl.loadClass("sun.java.MyNonExistentJavaClassNotGathered"); - } catch (ClassNotFoundException ignored) { - } - - // Get the events gathered - MissingClassEvents events = MissingClassTelemetry.getEvents(); - ConcurrentHashMap, MissingClassEvent> eventsGathered = events.getEventsAndClean(); - - // Only one event gathered - assertEquals(1, eventsGathered.size()); - assertEquals(1, eventsGathered.values().iterator().next().getOccurrences()); - assertThat(eventsGathered.values().iterator().next().getStackTrace(), containsString("MyNonExistentClassGathered")); - assertThat(eventsGathered.values().iterator().next().getStackTrace(), not(containsString("MyNonExistentJavaClassNotGathered"))); - - // Log has nothing to do with the limit for the sending. We print both because they have different class names - assertEquals("Two CNFE should be logged", 2, logging.getRecords().stream().filter(r -> r.getMessage().contains("MyNonExistentClassGathered") || - r.getMessage().contains("MyNonExistentJavaClassNotGathered")).count()); - } finally { - MissingClassEvents.MAX_EVENTS_PER_SEND = maxEventsBefore; - } - } - - /** - * Test the cycles in the exceptions. This specific tests shows that we first look for reportable exceptions in the - * causes and when found a reportable exception, we stop searching. So the warning because a cycle is not logged. - */ - @Test - public void cyclesNotReachedBecauseCNFEReported() { - Assume.assumeTrue("The telemetry should be enabled", MissingClassTelemetry.enabled()); - - try { - /* - parent -> child -> cnfe - \ - parent - We first look into the causes exceptions. When found, we don't look into the suppressed, so the cycle is not - found here - */ - - ClassNotFoundException cnfe = new ClassNotFoundException(NON_EXISTING_CLASS); - Exception child = new Exception("child", cnfe); - Exception parent = new Exception("parent", child); // parent -> caused by -> child - child.addSuppressed(parent); - - // Some extra wrapping - throw new Exception(new Exception (new Exception (parent))); - - } catch (Exception e) { - // Look for anything to report - MissingClassTelemetry.reportExceptionInside(e); - - // Get the events gathered - MissingClassEvents events = MissingClassTelemetry.getEvents(); - ConcurrentHashMap, MissingClassEvent> eventsGathered = events.getEventsAndClean(); - - // One event gathered - assertEquals(1, eventsGathered.size()); - - // the circular reference has not been recorded in the log because we reached a CNFE previously - assertEquals("No circular message was printed in logs", 0, logging.getRecords().stream().filter(r -> r.getMessage().contains(MissingClassTelemetry.CIRCULAR_REFERENCE)).count()); - } - } - - /** - * Test the cycles in the exceptions. This specific tests shows that we first look for reportable exceptions deep - * in the causes and suppressed exceptions in this order. We report the cycle but also the CNFE. - */ - @Test - public void cnfeFoundAfterCycle() { - Assume.assumeTrue("The telemetry should be enabled", MissingClassTelemetry.enabled()); - - try { - ClassNotFoundException cnfe = new ClassNotFoundException(NON_EXISTING_CLASS); - - /* - parent -> child - \ \ - cnfe parent - */ - Exception child = new Exception("child"); - Exception parent = new Exception("parent", child); // parent -> caused by -> child - child.addSuppressed(parent); // Boooomm!!!! The parent is a child suppressed exception -> cycle - parent.addSuppressed(cnfe); - - // Some extra wrapping - throw new Exception(new Exception (new Exception (parent))); - - } catch (Exception e) { - // Look for anything to report - MissingClassTelemetry.reportExceptionInside(e); - - // Get the events gathered - MissingClassEvents events = MissingClassTelemetry.getEvents(); - ConcurrentHashMap, MissingClassEvent> eventsGathered = events.getEventsAndClean(); - - // One event gathered - assertEquals(1, eventsGathered.size()); - - // the circular reference has been recorded in the log - assertThat(logging, LoggerRule.recorded(containsString(MissingClassTelemetry.CIRCULAR_REFERENCE))); - } - } - - /** - * Test the cycles in the exceptions. This specific tests shows that we first look for reportable exceptions deep - * in the causes and suppressed exceptions in this order. We report the cycle but also the CNFE in the parent. - */ - @Test - public void cnfeAfterCNFENotJava11AndCycle() { - Assume.assumeTrue("The telemetry should be enabled", MissingClassTelemetry.enabled()); - - try { - ClassNotFoundException cnfe = new ClassNotFoundException("sun.java.MyNonExistentClassGathered"); - ClassNotFoundException cnfeNonJava11 = new ClassNotFoundException("MyNonExistentClassGathered"); - - /* - parent -> child -> grandchild - \ \ \ - cnfe parent cnfe (non java11) - */ - Exception grandchild = new Exception("grandchild"); - Exception child = new Exception("child"); - Exception parent = new Exception("parent", child); // parent -> caused by -> child - child.addSuppressed(parent); // Boooomm!!!! The parent is a child suppressed exception -> cycle - grandchild.addSuppressed(cnfeNonJava11); - parent.addSuppressed(cnfe); - - // Some extra wrapping - throw new Exception(new Exception (new Exception (parent))); - - } catch (Exception e) { - // Look for anything to report - MissingClassTelemetry.reportExceptionInside(e); - - // Get the events gathered - MissingClassEvents events = MissingClassTelemetry.getEvents(); - ConcurrentHashMap, MissingClassEvent> eventsGathered = events.getEventsAndClean(); - - // One event gathered - assertEquals(1, eventsGathered.size()); - - // the circular reference has been recorded in the log - assertThat(logging, LoggerRule.recorded(containsString(MissingClassTelemetry.CIRCULAR_REFERENCE))); - } - } - - @Test - public void nothingGatheredWhenTelemetryDisabled() { - Assume.assumeFalse("The telemetry should not be enabled", MissingClassTelemetry.enabled()); - - try { - cl.loadClass("sun.java.MyNonExistentClass"); - } catch (ClassNotFoundException ignored) { - } - - ConcurrentHashMap, MissingClassEvent> eventsGathered = MissingClassTelemetry.getEvents().getEventsAndClean(); - - // No events gathered - assertEquals(0, eventsGathered.size()); - - assertEquals("No log if telemetry disabled", 0, logging.getRecords().size()); - } -} diff --git a/test/src/test/java/jenkins/widgets/BuildTimeTrendTest.java b/test/src/test/java/jenkins/widgets/BuildTimeTrendTest.java index af21fb5660..461344003c 100644 --- a/test/src/test/java/jenkins/widgets/BuildTimeTrendTest.java +++ b/test/src/test/java/jenkins/widgets/BuildTimeTrendTest.java @@ -71,7 +71,7 @@ public class BuildTimeTrendTest { wc.withThrowExceptionOnFailingStatusCode(false); HtmlPage page = wc.getPage(p, "buildTimeTrend"); - HtmlTable table = page.getDocumentElement().querySelector("table[data-is-master-slave-enabled=false]"); + HtmlTable table = page.getDocumentElement().querySelector("table[data-is-distributed-build-enabled=false]"); assertNotNull(table); } @@ -87,7 +87,7 @@ public class BuildTimeTrendTest { wc.withThrowExceptionOnFailingStatusCode(false); HtmlPage page = wc.getPage(p, "buildTimeTrend"); - DomNodeList anchors = page.getDocumentElement().querySelectorAll("table[data-is-master-slave-enabled=true] td a"); + DomNodeList anchors = page.getDocumentElement().querySelectorAll("table[data-is-distributed-build-enabled=true] td a"); Optional anchor = anchors.stream() .filter(a -> a.getTextContent().equals(agent.getNodeName())) .findFirst(); @@ -110,17 +110,17 @@ public class BuildTimeTrendTest { wc.withThrowExceptionOnFailingStatusCode(false); HtmlPage page = wc.getPage(p, "buildTimeTrend"); - DomNodeList anchors = page.getDocumentElement().querySelectorAll("table[data-is-master-slave-enabled=true] td a"); + DomNodeList anchors = page.getDocumentElement().querySelectorAll("table[data-is-distributed-build-enabled=true] td a"); Optional anchor = anchors.stream() .filter(a -> a.getTextContent().equals(agent.getNodeName())) .findFirst(); // for the build on agent assertTrue(anchor.isPresent()); - String masterName = hudson.model.Messages.Hudson_Computer_DisplayName(); - DomNodeList tds = page.getDocumentElement().querySelectorAll("table[data-is-master-slave-enabled=true] td"); + String builtInNode = hudson.model.Messages.Hudson_Computer_DisplayName(); + DomNodeList tds = page.getDocumentElement().querySelectorAll("table[data-is-distributed-build-enabled=true] td"); Optional td = tds.stream() - .filter(t -> t.getTextContent().equals(masterName)) + .filter(t -> t.getTextContent().equals(builtInNode)) .findFirst(); // for the build on built-in node assertTrue(td.isPresent()); @@ -136,7 +136,7 @@ public class BuildTimeTrendTest { wc.withThrowExceptionOnFailingStatusCode(false); HtmlPage page = wc.getPage(p, "buildTimeTrend"); - DomNodeList tds = page.getDocumentElement().querySelectorAll("table[data-is-master-slave-enabled=false] td"); + DomNodeList tds = page.getDocumentElement().querySelectorAll("table[data-is-distributed-build-enabled=false] td"); Optional td = tds.stream() .filter(t -> t.getTextContent().equals("#1")) .findFirst(); @@ -148,7 +148,7 @@ public class BuildTimeTrendTest { @LocalData("localDataNonAbstractJob") @Issue("JENKINS-63232") public void withNonAbstractJob_withAgents() throws Exception { - // just to trigger data-is-master-slave-enabled = true + // just to trigger data-is-distributed-build-enabled = true j.createSlave(); // Before the correction, if there was an agent and the build was not inheriting from AbstractBuild, we got @@ -161,7 +161,7 @@ public class BuildTimeTrendTest { wc.withThrowExceptionOnFailingStatusCode(false); HtmlPage page = wc.getPage(p, "buildTimeTrend"); - DomNodeList tds = page.getDocumentElement().querySelectorAll("table[data-is-master-slave-enabled=true] td"); + DomNodeList tds = page.getDocumentElement().querySelectorAll("table[data-is-distributed-build-enabled=true] td"); Optional td = tds.stream() .filter(t -> t.getTextContent().equals("#1")) .findFirst(); diff --git a/test/src/test/java/lib/form/PasswordTest.java b/test/src/test/java/lib/form/PasswordTest.java index 2dcad3763c..885baea78c 100644 --- a/test/src/test/java/lib/form/PasswordTest.java +++ b/test/src/test/java/lib/form/PasswordTest.java @@ -715,7 +715,7 @@ public class PasswordTest { { wc.login(READONLY); - HtmlPage page = wc.goTo("computer/(master)/secured/"); + HtmlPage page = wc.goTo("computer/(built-in)/secured/"); String value = ((HtmlInput)page.getElementById("password")).getValueAttribute(); assertThat(value, is("********")); @@ -723,7 +723,7 @@ public class PasswordTest { { wc.login(ADMIN); - HtmlPage page = wc.goTo("computer/(master)/secured/"); + HtmlPage page = wc.goTo("computer/(built-in)/secured/"); String value = ((HtmlInput)page.getElementById("password")).getValueAttribute(); assertThat(Secret.fromString(value).getPlainText(), is("abcdefgh")); diff --git a/test/src/test/java/lib/layout/IconTest.java b/test/src/test/java/lib/layout/IconTest.java index 7671ec3446..5139ccdc38 100644 --- a/test/src/test/java/lib/layout/IconTest.java +++ b/test/src/test/java/lib/layout/IconTest.java @@ -63,7 +63,9 @@ public class IconTest { public void testIcons() throws Exception { HtmlPage p = j.createWebClient().goTo("testIcons"); DomElement iconsBlock = p.getElementById("iconsBlock"); - List icons = StreamSupport.stream(iconsBlock.getChildElements().spliterator(), false).collect(Collectors.toList()); + List icons = StreamSupport + .stream(iconsBlock.getChildElements().spliterator(), false) + .collect(Collectors.toList()); assertIconToImageOkay(icons.get(0), "/images/16x16/empty.png", "icon-empty icon-sm"); assertIconToImageOkay(icons.get(1), "/images/24x24/empty.png", "icon-empty icon-md"); @@ -96,7 +98,8 @@ public class IconTest { DomElement statusIcons = p.getElementById("statusIcons"); List statusIconsList = StreamSupport.stream(statusIcons.getChildElements().spliterator(), false).collect(Collectors.toList()); - assertIconToImageOkay(statusIconsList.get(0), "/images/32x32/folder.png", "icon-folder icon-lg"); + + assertIconToImageOkay(statusIconsList.get(0), "/images/svgs/user.svg", "icon-user icon-xlg"); assertIconToImageOkay(statusIconsList.get(1), "/plugin/12345/icons/s2.png"); } @@ -112,9 +115,8 @@ public class IconTest { return BallColor.ABORTED; } - public StatusIcon getStatusIcon1() { - return new StockStatusIcon("folder.png", new NonLocalizable("A Folder")); + return new StockStatusIcon("user.svg", new NonLocalizable("A User")); } public StatusIcon getStatusIcon2() { @@ -138,11 +140,13 @@ public class IconTest { DomElement tasksDiv = p.getElementById("tasks"); List taskDivs = StreamSupport.stream(tasksDiv.getChildElements().spliterator(), false).collect(Collectors.toList()); - assertIconToImageOkay(taskDivs.get(0).getElementsByTagName("img").get(0), "/images/24x24/up.png", "icon-up icon-md"); + assertIconToImageOkay(taskDivs.get(0).getElementsByTagName("img").get(0), "/images/svgs/up.svg", "icon-up icon-md"); + // this is loading the png from cloudbees-folder plugin + // when this is swapped to an SVG and the dep updated this test will need to change assertIconToImageOkay(taskDivs.get(1).getElementsByTagName("img").get(0), "/images/24x24/folder.png", "icon-folder icon-md"); - assertIconToImageOkay(taskDivs.get(2).getElementsByTagName("img").get(0), "/images/16x16/package.png", "icon-package icon-sm"); - assertIconToImageOkay(taskDivs.get(3).getElementsByTagName("img").get(0), "/images/16x16/package.png", "icon-package icon-sm"); - assertIconToImageOkay(taskDivs.get(4).getElementsByTagName("img").get(0), "/images/16x16/package.png", "icon-package icon-sm"); + assertIconToImageOkay(taskDivs.get(2).getElementsByTagName("img").get(0), "/images/svgs/package.svg", "icon-package icon-xlg"); + assertIconToImageOkay(taskDivs.get(3).getElementsByTagName("img").get(0), "/images/svgs/package.svg", "icon-package icon-xlg"); + assertIconToImageOkay(taskDivs.get(4).getElementsByTagName("img").get(0), "/images/svgs/package.svg", "icon-package icon-xlg"); assertIconToImageOkay(taskDivs.get(5).getElementsByTagName("img").get(0), "/plugin/xxx/icon.png"); assertIconToImageOkay(taskDivs.get(6).getElementsByTagName("img").get(0), "/plugin/xxx/icon.png"); @@ -164,7 +168,7 @@ public class IconTest { assertThat("img", is(icon.getTagName())); assertThat(icon.getAttribute("src"), endsWith(imgPath)); if (classSpec != null) { - assertThat(classSpec, is(icon.getAttribute("class"))); + assertThat(icon.getAttribute("class"), is(classSpec)); } } diff --git a/test/src/test/java/org/kohsuke/stapler/beanutils/BasicTagWithObjectProperty.java b/test/src/test/java/org/kohsuke/stapler/beanutils/BasicTagWithObjectProperty.java index 98d2a221f7..9c12391224 100644 --- a/test/src/test/java/org/kohsuke/stapler/beanutils/BasicTagWithObjectProperty.java +++ b/test/src/test/java/org/kohsuke/stapler/beanutils/BasicTagWithObjectProperty.java @@ -1,7 +1,6 @@ package org.kohsuke.stapler.beanutils; import org.apache.commons.jelly.JellyTagException; -import org.apache.commons.jelly.MissingAttributeException; import org.apache.commons.jelly.TagSupport; import org.apache.commons.jelly.XMLOutput; import org.xml.sax.SAXException; @@ -14,7 +13,7 @@ public class BasicTagWithObjectProperty extends TagSupport { } @Override - public void doTag(XMLOutput output) throws MissingAttributeException, JellyTagException { + public void doTag(XMLOutput output) throws JellyTagException { try { output.writeComment("Tag with object property\n"); output.writeCDATA(getClass().getName() + ":" + clazz); diff --git a/test/src/test/java/org/kohsuke/stapler/beanutils/DynaTagWithStringProperty.java b/test/src/test/java/org/kohsuke/stapler/beanutils/DynaTagWithStringProperty.java index b22de9b477..7b723c1d82 100644 --- a/test/src/test/java/org/kohsuke/stapler/beanutils/DynaTagWithStringProperty.java +++ b/test/src/test/java/org/kohsuke/stapler/beanutils/DynaTagWithStringProperty.java @@ -2,7 +2,6 @@ package org.kohsuke.stapler.beanutils; import org.apache.commons.jelly.DynaTag; import org.apache.commons.jelly.JellyTagException; -import org.apache.commons.jelly.MissingAttributeException; import org.apache.commons.jelly.TagSupport; import org.apache.commons.jelly.XMLOutput; import org.xml.sax.SAXException; @@ -15,7 +14,7 @@ public class DynaTagWithStringProperty extends TagSupport implements DynaTag { } @Override - public void doTag(XMLOutput output) throws MissingAttributeException, JellyTagException { + public void doTag(XMLOutput output) throws JellyTagException { try { output.writeComment("Tag with string property\n"); output.writeCDATA(getClass().getName() + ":" + clazz); diff --git a/test/src/test/resources/hudson/FilePathTest/ZipSlipSamePathPrefix/evil-win.zip b/test/src/test/resources/hudson/FilePathTest/ZipSlipSamePathPrefix/evil-win.zip new file mode 100644 index 0000000000..0cc0d9bedf Binary files /dev/null and b/test/src/test/resources/hudson/FilePathTest/ZipSlipSamePathPrefix/evil-win.zip differ diff --git a/test/src/test/resources/hudson/FilePathTest/ZipSlipSamePathPrefix/evil.zip b/test/src/test/resources/hudson/FilePathTest/ZipSlipSamePathPrefix/evil.zip new file mode 100644 index 0000000000..dfc24cbbfe Binary files /dev/null and b/test/src/test/resources/hudson/FilePathTest/ZipSlipSamePathPrefix/evil.zip differ diff --git a/test/src/test/resources/hudson/model/UsageStatisticsTest/jobs.json b/test/src/test/resources/hudson/model/UsageStatisticsTest/jobs.json index 1e2cebac29..c86a459197 100644 --- a/test/src/test/resources/hudson/model/UsageStatisticsTest/jobs.json +++ b/test/src/test/resources/hudson/model/UsageStatisticsTest/jobs.json @@ -1 +1 @@ -{"com-cloudbees-hudson-plugins-folder-Folder":0,"hudson-matrix-MatrixProject":0,"hudson-model-FreeStyleProject":0,"org-jenkinsci-plugins-workflow-job-WorkflowJob":0,"org-jvnet-hudson-test-MockFolder":0,"org-jvnet-hudson-test-SecuredMockFolder":0} \ No newline at end of file +{"com-cloudbees-hudson-plugins-folder-Folder":0,"hudson-matrix-MatrixProject":0,"hudson-model-FreeStyleProject":0,"org-jvnet-hudson-test-MockFolder":0,"org-jvnet-hudson-test-SecuredMockFolder":0} \ No newline at end of file diff --git a/test/src/test/resources/jenkins/model/BuiltInNodeMigrationPropertyTest/overrideAppliesToMigratedInstance/config.xml b/test/src/test/resources/jenkins/model/BuiltInNodeMigrationPropertyTest/overrideAppliesToMigratedInstance/config.xml new file mode 100644 index 0000000000..5625041604 --- /dev/null +++ b/test/src/test/resources/jenkins/model/BuiltInNodeMigrationPropertyTest/overrideAppliesToMigratedInstance/config.xml @@ -0,0 +1,37 @@ + + + + 2 + NORMAL + true + + + false + + ${JENKINS_HOME}/workspace/${ITEM_FULL_NAME} + ${ITEM_ROOTDIR}/builds + + + + + 5 + 0 + + + + all + false + false + + + + all + 0 + + + false + + + + false + \ No newline at end of file diff --git a/test/src/test/resources/jenkins/model/BuiltInNodeMigrationPropertyTest/overrideAppliesToUnmigratedInstance/config.xml b/test/src/test/resources/jenkins/model/BuiltInNodeMigrationPropertyTest/overrideAppliesToUnmigratedInstance/config.xml new file mode 100644 index 0000000000..f1626a8892 --- /dev/null +++ b/test/src/test/resources/jenkins/model/BuiltInNodeMigrationPropertyTest/overrideAppliesToUnmigratedInstance/config.xml @@ -0,0 +1,36 @@ + + + + 2 + NORMAL + true + + + false + + ${JENKINS_HOME}/workspace/${ITEM_FULL_NAME} + ${ITEM_ROOTDIR}/builds + + + + + 5 + 0 + + + + all + false + false + + + + all + 0 + + + false + + + + \ No newline at end of file diff --git a/test/src/test/resources/jenkins/model/BuiltInNodeMigrationRestartTest/migratedInstanceStartsWithNewTerminology/config.xml b/test/src/test/resources/jenkins/model/BuiltInNodeMigrationRestartTest/migratedInstanceStartsWithNewTerminology/config.xml new file mode 100644 index 0000000000..5625041604 --- /dev/null +++ b/test/src/test/resources/jenkins/model/BuiltInNodeMigrationRestartTest/migratedInstanceStartsWithNewTerminology/config.xml @@ -0,0 +1,37 @@ + + + + 2 + NORMAL + true + + + false + + ${JENKINS_HOME}/workspace/${ITEM_FULL_NAME} + ${ITEM_ROOTDIR}/builds + + + + + 5 + 0 + + + + all + false + false + + + + all + 0 + + + false + + + + false + \ No newline at end of file diff --git a/test/src/test/resources/jenkins/model/BuiltInNodeMigrationRestartTest/oldDataStartsWithOldTerminology/config.xml b/test/src/test/resources/jenkins/model/BuiltInNodeMigrationRestartTest/oldDataStartsWithOldTerminology/config.xml new file mode 100644 index 0000000000..f1626a8892 --- /dev/null +++ b/test/src/test/resources/jenkins/model/BuiltInNodeMigrationRestartTest/oldDataStartsWithOldTerminology/config.xml @@ -0,0 +1,36 @@ + + + + 2 + NORMAL + true + + + false + + ${JENKINS_HOME}/workspace/${ITEM_FULL_NAME} + ${ITEM_ROOTDIR}/builds + + + + + 5 + 0 + + + + all + false + false + + + + all + 0 + + + false + + + + \ No newline at end of file diff --git a/test/src/test/resources/jenkins/model/BuiltInNodeMigrationTest/migratedInstanceStartsWithNewTerminology/config.xml b/test/src/test/resources/jenkins/model/BuiltInNodeMigrationTest/migratedInstanceStartsWithNewTerminology/config.xml new file mode 100644 index 0000000000..5625041604 --- /dev/null +++ b/test/src/test/resources/jenkins/model/BuiltInNodeMigrationTest/migratedInstanceStartsWithNewTerminology/config.xml @@ -0,0 +1,37 @@ + + + + 2 + NORMAL + true + + + false + + ${JENKINS_HOME}/workspace/${ITEM_FULL_NAME} + ${ITEM_ROOTDIR}/builds + + + + + 5 + 0 + + + + all + false + false + + + + all + 0 + + + false + + + + false + \ No newline at end of file diff --git a/test/src/test/resources/jenkins/model/BuiltInNodeMigrationTest/oldDataStartsWithOldTerminology/config.xml b/test/src/test/resources/jenkins/model/BuiltInNodeMigrationTest/oldDataStartsWithOldTerminology/config.xml new file mode 100644 index 0000000000..f1626a8892 --- /dev/null +++ b/test/src/test/resources/jenkins/model/BuiltInNodeMigrationTest/oldDataStartsWithOldTerminology/config.xml @@ -0,0 +1,36 @@ + + + + 2 + NORMAL + true + + + false + + ${JENKINS_HOME}/workspace/${ITEM_FULL_NAME} + ${ITEM_ROOTDIR}/builds + + + + + 5 + 0 + + + + all + false + false + + + + all + 0 + + + false + + + + \ No newline at end of file diff --git a/test/src/test/resources/lib/layout/IconTest/TestTasks/index.jelly b/test/src/test/resources/lib/layout/IconTest/TestTasks/index.jelly index 0678eaba41..d03d2daab2 100644 --- a/test/src/test/resources/lib/layout/IconTest/TestTasks/index.jelly +++ b/test/src/test/resources/lib/layout/IconTest/TestTasks/index.jelly @@ -32,9 +32,9 @@ THE SOFTWARE. - - - + + + diff --git a/war/images/Tango-Palette.png b/war/images/Tango-Palette.png deleted file mode 100644 index 63b8eef6a1..0000000000 Binary files a/war/images/Tango-Palette.png and /dev/null differ diff --git a/war/images/accept-24x24.svg b/war/images/accept-24x24.svg deleted file mode 100644 index c828e5dd2a..0000000000 --- a/war/images/accept-24x24.svg +++ /dev/null @@ -1,601 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Rodney Dawes - - - - - Jakub Steiner, Garrett LeSage - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/war/images/blue.svg b/war/images/blue.svg deleted file mode 100644 index cd73d4b61f..0000000000 --- a/war/images/blue.svg +++ /dev/null @@ -1,266 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Face - Plain - - - emoticon - emote - face - plain - :| - :-| - - - - - - Steven Garrity - - - http://www.tango-project.org - - - Based on face-smile by jimmac - - - - - - - - - - - - - - - - - - - diff --git a/war/images/compress_png.sh b/war/images/compress_png.sh deleted file mode 100755 index 7d1c37a30c..0000000000 --- a/war/images/compress_png.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -function compress { - echo "Crushing $1" - pngcrush -rem gAMA -rem cHRM -rem iCCP -rem sRGB $1 $1.tmp - mv $1.tmp $1 - echo "Compressing $1" - optipng -o9 $1 > /dev/null -} - -if [ -z "$*" ] -then - echo 'Please pass a list of pngs to compress.'; -fi - -for image in "$@" # Doesn't work properly if "$*" isn't quoted. -do - compress $image -done - diff --git a/war/images/dark-grey.svg b/war/images/dark-grey.svg deleted file mode 100644 index 72f8d199aa..0000000000 --- a/war/images/dark-grey.svg +++ /dev/null @@ -1,178 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - emoticon - emote - face - plain - :| - :-| - - - - - - Steven Garrity - - - http://www.tango-project.org - - - Based on face-smile by jimmac - - - - - - - - - - - - - - - - - - - diff --git a/war/images/gear.svg b/war/images/gear.svg deleted file mode 100644 index f5b116006a..0000000000 --- a/war/images/gear.svg +++ /dev/null @@ -1,181 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - Jakub Steiner - - - http://jimmac.musichall.cz - - Emblem System - - - emblem - system - library - crucial - base - - - - - - - - - - - - - - - - - - - - diff --git a/war/images/green.svg b/war/images/green.svg deleted file mode 100644 index 9fd8c88e20..0000000000 --- a/war/images/green.svg +++ /dev/null @@ -1,273 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Face - Plain - - - emoticon - emote - face - plain - :| - :-| - - - - - - Steven Garrity - - - http://www.tango-project.org - - - Based on face-smile by jimmac - - - - - - - - - - - - - - - - - - - diff --git a/war/images/health-00to19.svg b/war/images/health-00to19.svg deleted file mode 100644 index 8fb48bdecc..0000000000 --- a/war/images/health-00to19.svg +++ /dev/null @@ -1,5206 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - weather-storm - January 2006 - - - Ryan Collier - - - - - http://www.tango-project.org - - - http://www.pseudocode.org - - - weather - applet - notify - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/war/images/health-20to39.svg b/war/images/health-20to39.svg deleted file mode 100644 index 162d09a403..0000000000 --- a/war/images/health-20to39.svg +++ /dev/null @@ -1,6507 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - weather-scattered-showers - January 2006 - - - Ryan collier (pseudo) - - - - - http://www.tango-project.org - - - http://www.pseudocode.org - - - weather - appplet - notify - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/war/images/health-40to59.svg b/war/images/health-40to59.svg deleted file mode 100644 index 442e7d0f49..0000000000 --- a/war/images/health-40to59.svg +++ /dev/null @@ -1,3034 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - weather-overcast - January 2006 - - - Ryan Collier (pseudo) - - - - - http://www.tango-project.org - - - http://www.pseudocode.org - - - weather - applet - notify - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/war/images/health-60to79.svg b/war/images/health-60to79.svg deleted file mode 100644 index 2d32ab096b..0000000000 --- a/war/images/health-60to79.svg +++ /dev/null @@ -1,736 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - weather-clear - January 2006 - - - Ryan Collier (pseudo) - - - - - http://www.tango-project.org - - - http://www.pseudocode.org - - - weather - applet - notification - - - - - - Garrett LeSage - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/war/images/health-80plus.svg b/war/images/health-80plus.svg deleted file mode 100644 index 7cd1ce6ac7..0000000000 --- a/war/images/health-80plus.svg +++ /dev/null @@ -1,1322 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - weather-clear - January 2006 - - - Ryan Collier (pseudo) - - - - - http://www.tango-project.org - - - http://www.pseudocode.org - - - weather - applet - notification - - - - - - Garrett LeSage - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/war/images/hudson-logo.vsd b/war/images/hudson-logo.vsd deleted file mode 100644 index 80b02dc4e6..0000000000 Binary files a/war/images/hudson-logo.vsd and /dev/null differ diff --git a/war/images/light-grey.svg b/war/images/light-grey.svg deleted file mode 100644 index 0d481ac309..0000000000 --- a/war/images/light-grey.svg +++ /dev/null @@ -1,178 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - emoticon - emote - face - plain - :| - :-| - - - - - - Steven Garrity - - - http://www.tango-project.org - - - Based on face-smile by jimmac - - - - - - - - - - - - - - - - - - - diff --git a/war/images/make.sh b/war/images/make.sh deleted file mode 100755 index 3f3c16a24b..0000000000 --- a/war/images/make.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh -e -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -# this script requires these tools to be installed: -# * ImageMagick (http://www.imagemagick.org/) -# * inkscape (http://inkscape.org/) - -for src in *.svg -do - echo processing $src - e=$(echo $src | sed -e s/.svg/.png/ ) - for sz in 16 24 32 48 - do - dst=${sz}x${sz}/$e - if [ ! -e $dst -o $src -nt $dst ]; - then - mkdir ${sz}x${sz} > /dev/null 2>&1 || true - ./svg2png -w $sz -h $sz < $src > $dst - ./compress_png.sh $dst - #convert t.png \( +clone -fill white -draw 'color 0,0 reset' \) \ - # -compose Dst_Over $dst - # composite -compose Dst_Over -tile xc:white t.png $dst - # rm t.png - fi - - gif=$(echo $dst | sed -e s/.png/.gif/) - if [ ! -e $gif -o $dst -nt $gif ]; - then - convert $dst -background white -flatten -transparent white $gif - fi - done -done diff --git a/war/images/makeBalls.sh b/war/images/makeBalls.sh deleted file mode 100755 index 26b49cc441..0000000000 --- a/war/images/makeBalls.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh -ex -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - - -# build flashing balls - -for sz in 16x16 24x24 32x32 48x48 -do - for color in light-grey dark-grey grey blue yellow red green - do - cp $sz/$color.gif ../src/main/webapp/images/$sz/$color.gif - ./makeFlash.sh $sz/$color.gif ../src/main/webapp/images/$sz/${color}_anime.gif - done -done diff --git a/war/images/makeFlash.sh b/war/images/makeFlash.sh deleted file mode 100755 index 6d7e29575b..0000000000 --- a/war/images/makeFlash.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh -ex -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - - -# build a flashing animation image from a still picture -# Usage -t=/tmp/flash$$ - -src=$1 -dst=$2 -for p in 20 40 60 80 100 -do - convert $src -fill white -colorize ${p}% $t.$p.gif -done -convert -delay 10 $src $t.20.gif $t.40.gif $t.60.gif $t.80.gif $t.100.gif $t.80.gif $t.60.gif $t.40.gif $t.20.gif -loop 0 $dst - -rm $t.*.gif diff --git a/war/images/nothing.svg b/war/images/nothing.svg deleted file mode 100644 index c9fca93c9e..0000000000 --- a/war/images/nothing.svg +++ /dev/null @@ -1,157 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Delete - 2005-12-28 - - - Andreas Nilsson - - - http://tango-project.org - - - delete - remove - - - - - - - - - - - - - - - diff --git a/war/images/png2gifanime.sh b/war/images/png2gifanime.sh deleted file mode 100755 index 4db700a855..0000000000 --- a/war/images/png2gifanime.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -e -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - - -# take multiple PNG files in the command line, and convert them to animation gif in the white background -# then send it to stdout -i=0 -tmpbase=/tmp/png2gifanime$$ - -for f in "$@" -do - convert $f \( +clone -fill white -draw 'color 0,0 reset' \) \ - -compose Dst_Over $tmpbase$i.gif - fileList[$i]=$tmpbase$i.gif - i=$((i+1)) -done - -convert -delay 10 ${fileList[@]} -loop 0 "${tmpbase}final.gif" -cat ${tmpbase}final.gif -rm ${fileList[@]} ${tmpbase}final.gif \ No newline at end of file diff --git a/war/images/readme.txt b/war/images/readme.txt deleted file mode 100644 index b009c973fd..0000000000 --- a/war/images/readme.txt +++ /dev/null @@ -1,2 +0,0 @@ -This is the workshop to tweak with images. -These images are generated into PNGs and then copied manually over to the resources/image directory diff --git a/war/images/red.svg b/war/images/red.svg deleted file mode 100644 index 6ac0c77b27..0000000000 --- a/war/images/red.svg +++ /dev/null @@ -1,265 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Face - Plain - - - emoticon - emote - face - plain - :| - :-| - - - - - - Steven Garrity - - - http://www.tango-project.org - - - Based on face-smile by jimmac - - - - - - - - - - - - - - - - - - - diff --git a/war/images/scrollbar/make.rb b/war/images/scrollbar/make.rb deleted file mode 100755 index cc9d5dfe4a..0000000000 --- a/war/images/scrollbar/make.rb +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/ruby -# The MIT License -# -# Copyright (c) 2004-2009, Sun Microsystems, Inc., Kohsuke Kawaguchi -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - - - -# width of the band -$u=20 -$uu=$u*2 - -def make(step,color) - system "convert -size #{$uu}x8 xc:white -fill '#{color}' -stroke '#{color}' -draw \"polyline 0,#{$u-1} #{$u-1},0 #{$uu-1},0 #{$u},#{$u-1}\" -roll +#{step}+0 screen.#{step}.gif" or fail -end - -colors = { "red" => "#cc0000", "blue" => "#3465a4" } -colors.keys.each do |name| - list = [] - color = colors[name]; - - (0...$uu).each do |i| - make(i,color) - list << "screen.#{i}.gif" - end - - system "convert -delay 10 #{list.join(" ")} -loop 0 progress-unknown-#{name}.gif" or fail - - list.each do |file| - File.delete(file) - end -end \ No newline at end of file diff --git a/war/images/scrollbar/test.html b/war/images/scrollbar/test.html deleted file mode 100644 index 7a71f76788..0000000000 --- a/war/images/scrollbar/test.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - -
    -   -
    \ No newline at end of file diff --git a/war/images/svg2png b/war/images/svg2png deleted file mode 100755 index 52bb6d7a41..0000000000 --- a/war/images/svg2png +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -e -# convert an svg file to a png file -# Usage: cat some.svg | svg2png ...options... > some.png -# -# option: -w width -h height - -tmpA=/tmp/svg2pngA$$ -tmpB=/tmp/svg2pngB$$ - -cat > $tmpA -inkscape -z -e "$tmpB" "$@" "$tmpA" 1>&2 -cat $tmpB -rm $tmpA $tmpB diff --git a/war/images/yellow.svg b/war/images/yellow.svg deleted file mode 100644 index de06f91888..0000000000 --- a/war/images/yellow.svg +++ /dev/null @@ -1,265 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - Face - Plain - - - emoticon - emote - face - plain - :| - :-| - - - - - - Steven Garrity - - - http://www.tango-project.org - - - Based on face-smile by jimmac - - - - - - - - - - - - - - - - - - - diff --git a/war/pom.xml b/war/pom.xml index 2fbcbb61bf..a6bc9e2fa1 100644 --- a/war/pom.xml +++ b/war/pom.xml @@ -36,6 +36,7 @@ THE SOFTWARE. Jenkins war Creates a war file. Also includes additional static web resources, such as images, CSS, JavaScript, and some HTML files. + https://github.com/jenkinsci/jenkins ${basedir}/work @@ -105,7 +106,7 @@ THE SOFTWARE. org.jenkins-ci winstone - 5.19 + 5.21 test
    @@ -416,7 +417,7 @@ THE SOFTWARE. org.eclipse.jetty jetty-maven-plugin - 9.4.42.v20210604 + 9.4.43.v20210629 + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + System Applications + + + Jakub Steiner + + + http://jimmac.musichall.cz/ + + + system + applications + group + category + admin + root + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/war/images/go-down.svg b/war/src/main/webapp/images/svgs/go-down.svg similarity index 100% rename from war/images/go-down.svg rename to war/src/main/webapp/images/svgs/go-down.svg diff --git a/war/images/go-top.svg b/war/src/main/webapp/images/svgs/go-top.svg similarity index 100% rename from war/images/go-top.svg rename to war/src/main/webapp/images/svgs/go-top.svg diff --git a/war/images/go-up.svg b/war/src/main/webapp/images/svgs/go-up.svg similarity index 100% rename from war/images/go-up.svg rename to war/src/main/webapp/images/svgs/go-up.svg diff --git a/war/images/graph.svg b/war/src/main/webapp/images/svgs/graph.svg similarity index 100% rename from war/images/graph.svg rename to war/src/main/webapp/images/svgs/graph.svg diff --git a/war/images/grey.svg b/war/src/main/webapp/images/svgs/grey.svg similarity index 100% rename from war/images/grey.svg rename to war/src/main/webapp/images/svgs/grey.svg diff --git a/war/images/headless.svg b/war/src/main/webapp/images/svgs/headless.svg similarity index 100% rename from war/images/headless.svg rename to war/src/main/webapp/images/svgs/headless.svg diff --git a/war/images/headshot.svg b/war/src/main/webapp/images/svgs/headshot.svg similarity index 100% rename from war/images/headshot.svg rename to war/src/main/webapp/images/svgs/headshot.svg diff --git a/war/images/help.svg b/war/src/main/webapp/images/svgs/help.svg similarity index 100% rename from war/images/help.svg rename to war/src/main/webapp/images/svgs/help.svg diff --git a/war/images/hourglass.svg b/war/src/main/webapp/images/svgs/hourglass.svg similarity index 100% rename from war/images/hourglass.svg rename to war/src/main/webapp/images/svgs/hourglass.svg diff --git a/war/images/installer.svg b/war/src/main/webapp/images/svgs/installer.svg similarity index 100% rename from war/images/installer.svg rename to war/src/main/webapp/images/svgs/installer.svg diff --git a/war/images/keys.svg b/war/src/main/webapp/images/svgs/keys.svg similarity index 100% rename from war/images/keys.svg rename to war/src/main/webapp/images/svgs/keys.svg diff --git a/war/images/lock.svg b/war/src/main/webapp/images/svgs/lock.svg similarity index 100% rename from war/images/lock.svg rename to war/src/main/webapp/images/svgs/lock.svg diff --git a/war/images/logo.svg b/war/src/main/webapp/images/svgs/logo.svg similarity index 100% rename from war/images/logo.svg rename to war/src/main/webapp/images/svgs/logo.svg diff --git a/war/images/monitor.svg b/war/src/main/webapp/images/svgs/monitor.svg similarity index 100% rename from war/images/monitor.svg rename to war/src/main/webapp/images/svgs/monitor.svg diff --git a/war/images/network.svg b/war/src/main/webapp/images/svgs/network.svg similarity index 100% rename from war/images/network.svg rename to war/src/main/webapp/images/svgs/network.svg diff --git a/war/images/new-computer.svg b/war/src/main/webapp/images/svgs/new-computer.svg similarity index 100% rename from war/images/new-computer.svg rename to war/src/main/webapp/images/svgs/new-computer.svg diff --git a/war/images/new-document.svg b/war/src/main/webapp/images/svgs/new-document.svg similarity index 100% rename from war/images/new-document.svg rename to war/src/main/webapp/images/svgs/new-document.svg diff --git a/war/images/new-package.svg b/war/src/main/webapp/images/svgs/new-package.svg similarity index 100% rename from war/images/new-package.svg rename to war/src/main/webapp/images/svgs/new-package.svg diff --git a/war/images/new-user.svg b/war/src/main/webapp/images/svgs/new-user.svg similarity index 100% rename from war/images/new-user.svg rename to war/src/main/webapp/images/svgs/new-user.svg diff --git a/war/images/next.svg b/war/src/main/webapp/images/svgs/next.svg similarity index 100% rename from war/images/next.svg rename to war/src/main/webapp/images/svgs/next.svg diff --git a/war/images/notepad.svg b/war/src/main/webapp/images/svgs/notepad.svg similarity index 100% rename from war/images/notepad.svg rename to war/src/main/webapp/images/svgs/notepad.svg diff --git a/war/images/orange-square.svg b/war/src/main/webapp/images/svgs/orange-square.svg similarity index 100% rename from war/images/orange-square.svg rename to war/src/main/webapp/images/svgs/orange-square.svg diff --git a/war/images/package.svg b/war/src/main/webapp/images/svgs/package.svg similarity index 100% rename from war/images/package.svg rename to war/src/main/webapp/images/svgs/package.svg diff --git a/war/images/person.svg b/war/src/main/webapp/images/svgs/person.svg similarity index 100% rename from war/images/person.svg rename to war/src/main/webapp/images/svgs/person.svg diff --git a/war/images/plugin.svg b/war/src/main/webapp/images/svgs/plugin.svg similarity index 100% rename from war/images/plugin.svg rename to war/src/main/webapp/images/svgs/plugin.svg diff --git a/war/images/previous.svg b/war/src/main/webapp/images/svgs/previous.svg similarity index 100% rename from war/images/previous.svg rename to war/src/main/webapp/images/svgs/previous.svg diff --git a/war/images/redo.svg b/war/src/main/webapp/images/svgs/redo.svg similarity index 100% rename from war/images/redo.svg rename to war/src/main/webapp/images/svgs/redo.svg diff --git a/war/images/refresh.svg b/war/src/main/webapp/images/svgs/refresh.svg similarity index 100% rename from war/images/refresh.svg rename to war/src/main/webapp/images/svgs/refresh.svg diff --git a/war/images/save-new.svg b/war/src/main/webapp/images/svgs/save-new.svg similarity index 100% rename from war/images/save-new.svg rename to war/src/main/webapp/images/svgs/save-new.svg diff --git a/war/images/save.svg b/war/src/main/webapp/images/svgs/save.svg similarity index 100% rename from war/images/save.svg rename to war/src/main/webapp/images/svgs/save.svg diff --git a/war/images/search.svg b/war/src/main/webapp/images/svgs/search.svg similarity index 100% rename from war/images/search.svg rename to war/src/main/webapp/images/svgs/search.svg diff --git a/war/images/secure.svg b/war/src/main/webapp/images/svgs/secure.svg similarity index 100% rename from war/images/secure.svg rename to war/src/main/webapp/images/svgs/secure.svg diff --git a/war/images/setting.svg b/war/src/main/webapp/images/svgs/setting.svg similarity index 100% rename from war/images/setting.svg rename to war/src/main/webapp/images/svgs/setting.svg diff --git a/war/images/shield.svg b/war/src/main/webapp/images/svgs/shield.svg similarity index 100% rename from war/images/shield.svg rename to war/src/main/webapp/images/svgs/shield.svg diff --git a/war/images/star-gold.svg b/war/src/main/webapp/images/svgs/star-gold.svg similarity index 100% rename from war/images/star-gold.svg rename to war/src/main/webapp/images/svgs/star-gold.svg diff --git a/war/images/star-large-gold.svg b/war/src/main/webapp/images/svgs/star-large-gold.svg similarity index 100% rename from war/images/star-large-gold.svg rename to war/src/main/webapp/images/svgs/star-large-gold.svg diff --git a/war/images/star-large.svg b/war/src/main/webapp/images/svgs/star-large.svg similarity index 100% rename from war/images/star-large.svg rename to war/src/main/webapp/images/svgs/star-large.svg diff --git a/war/images/star.svg b/war/src/main/webapp/images/svgs/star.svg similarity index 100% rename from war/images/star.svg rename to war/src/main/webapp/images/svgs/star.svg diff --git a/war/images/stop.svg b/war/src/main/webapp/images/svgs/stop.svg similarity index 100% rename from war/images/stop.svg rename to war/src/main/webapp/images/svgs/stop.svg diff --git a/war/images/system-log-out.svg b/war/src/main/webapp/images/svgs/system-log-out.svg similarity index 100% rename from war/images/system-log-out.svg rename to war/src/main/webapp/images/svgs/system-log-out.svg diff --git a/war/images/terminal.svg b/war/src/main/webapp/images/svgs/terminal.svg similarity index 100% rename from war/images/terminal.svg rename to war/src/main/webapp/images/svgs/terminal.svg diff --git a/war/images/undo.svg b/war/src/main/webapp/images/svgs/undo.svg similarity index 100% rename from war/images/undo.svg rename to war/src/main/webapp/images/svgs/undo.svg diff --git a/war/images/up.svg b/war/src/main/webapp/images/svgs/up.svg similarity index 100% rename from war/images/up.svg rename to war/src/main/webapp/images/svgs/up.svg diff --git a/war/images/user.svg b/war/src/main/webapp/images/svgs/user.svg similarity index 100% rename from war/images/user.svg rename to war/src/main/webapp/images/svgs/user.svg diff --git a/war/images/video.svg b/war/src/main/webapp/images/svgs/video.svg similarity index 100% rename from war/images/video.svg rename to war/src/main/webapp/images/svgs/video.svg diff --git a/war/images/warning.svg b/war/src/main/webapp/images/svgs/warning.svg similarity index 100% rename from war/images/warning.svg rename to war/src/main/webapp/images/svgs/warning.svg diff --git a/war/src/main/webapp/images/title.png b/war/src/main/webapp/images/title.png deleted file mode 100644 index db3623b9f5..0000000000 Binary files a/war/src/main/webapp/images/title.png and /dev/null differ diff --git a/war/src/main/webapp/scripts/yui/connection/connection-debug.js b/war/src/main/webapp/scripts/yui/connection/connection-debug.js index dde2842ca4..4eac5ba9b4 100644 --- a/war/src/main/webapp/scripts/yui/connection/connection-debug.js +++ b/war/src/main/webapp/scripts/yui/connection/connection-debug.js @@ -424,7 +424,7 @@ YAHOO.util.Connect = } else{ - // Intialize any transaction-specific custom events, if provided. + // Initialize any transaction-specific custom events, if provided. if(callback && callback.customevents){ this.initCustomEvents(o, callback); }