From 6b5e3d11700c086d9b3b6e14132240691a6bebbd Mon Sep 17 00:00:00 2001 From: Zbynek Konecny Date: Thu, 13 Jan 2022 08:46:54 +0100 Subject: [PATCH] Unify labels in plugin manager (#6151) * Map outdated labels to canonical ones * Fix checkstyle issue (missing space) --- .../main/java/hudson/model/UpdateSite.java | 5 +- .../jenkins/plugins/DetachedPluginsUtil.java | 2 +- .../java/jenkins/util/PluginLabelUtil.java | 68 +++++++++++++++++++ .../hudson/model/Messages.properties | 4 +- .../hudson/model/Messages_bg.properties | 4 +- .../hudson/model/Messages_de.properties | 4 +- .../hudson/model/Messages_es.properties | 2 +- .../hudson/model/Messages_it.properties | 4 +- .../hudson/model/Messages_lt.properties | 4 +- .../hudson/model/Messages_sr.properties | 4 +- .../resources/jenkins/canonical-labels.txt | 5 ++ .../jenkins/util/PluginLabelUtilTest.java | 19 ++++++ 12 files changed, 108 insertions(+), 17 deletions(-) create mode 100644 core/src/main/java/jenkins/util/PluginLabelUtil.java create mode 100644 core/src/main/resources/jenkins/canonical-labels.txt create mode 100644 core/src/test/java/jenkins/util/PluginLabelUtilTest.java diff --git a/core/src/main/java/hudson/model/UpdateSite.java b/core/src/main/java/hudson/model/UpdateSite.java index e5b7bb3f1228..1b7e3ef89c16 100644 --- a/core/src/main/java/hudson/model/UpdateSite.java +++ b/core/src/main/java/hudson/model/UpdateSite.java @@ -28,9 +28,7 @@ import static java.util.concurrent.TimeUnit.DAYS; import static java.util.concurrent.TimeUnit.HOURS; import static java.util.concurrent.TimeUnit.SECONDS; -import static jenkins.util.MemoryReductionUtil.EMPTY_STRING_ARRAY; import static jenkins.util.MemoryReductionUtil.getPresizedMutableMap; -import static jenkins.util.MemoryReductionUtil.internInPlace; import edu.umd.cs.findbugs.annotations.CheckForNull; import edu.umd.cs.findbugs.annotations.NonNull; @@ -80,6 +78,7 @@ import jenkins.security.UpdateSiteWarningsConfiguration; import jenkins.security.UpdateSiteWarningsMonitor; import jenkins.util.JSONSignatureValidator; +import jenkins.util.PluginLabelUtil; import jenkins.util.SystemProperties; import jenkins.util.java.JavaUtils; import net.sf.json.JSONArray; @@ -1238,7 +1237,7 @@ public Plugin(String sourceId, JSONObject o) { } this.popularity = popularity; this.releaseTimestamp = date; - this.categories = o.has("labels") ? internInPlace((String[]) o.getJSONArray("labels").toArray(EMPTY_STRING_ARRAY)) : null; + this.categories = o.has("labels") ? PluginLabelUtil.canonicalLabels(o.getJSONArray("labels")) : null; this.issueTrackers = o.has("issueTrackers") ? o.getJSONArray("issueTrackers").stream().map(IssueTracker::createFromJSONObject).filter(Objects::nonNull).toArray(IssueTracker[]::new) : null; JSONArray ja = o.getJSONArray("dependencies"); diff --git a/core/src/main/java/jenkins/plugins/DetachedPluginsUtil.java b/core/src/main/java/jenkins/plugins/DetachedPluginsUtil.java index 92c10b25d7ae..9a0bd3d4ed22 100644 --- a/core/src/main/java/jenkins/plugins/DetachedPluginsUtil.java +++ b/core/src/main/java/jenkins/plugins/DetachedPluginsUtil.java @@ -144,7 +144,7 @@ public static boolean isDetachedPlugin(@NonNull String pluginId) { return false; } - private static Stream configLines(InputStream is) throws IOException { + public static Stream configLines(InputStream is) throws IOException { return IOUtils.readLines(is, StandardCharsets.UTF_8).stream().filter(line -> !line.matches("#.*|\\s*")); } diff --git a/core/src/main/java/jenkins/util/PluginLabelUtil.java b/core/src/main/java/jenkins/util/PluginLabelUtil.java new file mode 100644 index 000000000000..b50c111cc8fa --- /dev/null +++ b/core/src/main/java/jenkins/util/PluginLabelUtil.java @@ -0,0 +1,68 @@ +/* + * The MIT License + * + * Copyright (c) 2022 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 + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package jenkins.util; + +import static jenkins.util.MemoryReductionUtil.EMPTY_STRING_ARRAY; + +import hudson.Util; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.HashSet; +import jenkins.plugins.DetachedPluginsUtil; +import net.sf.json.JSONArray; + +public class PluginLabelUtil { + private static HashMap renamedLabels; + + private static String canonicalLabel(String label) { + if (renamedLabels == null) { + renamedLabels = new HashMap<>(); + try (InputStream is = PluginLabelUtil.class.getResourceAsStream("/jenkins/canonical-labels.txt")) { + DetachedPluginsUtil.configLines(is).forEach(line -> { + String[] pieces = line.split(" "); + renamedLabels.put(pieces[0], pieces[1]); + }); + } catch (IOException x) { + throw new ExceptionInInitializerError(x); + } + } + return renamedLabels.getOrDefault(label, label); + } + + /** + * Replaces labels with their canonical form and removes duplicates + * @param labels labels array + * @return unique canonical labels + */ + public static String[] canonicalLabels(JSONArray labels) { + HashSet uniqueLabels = new HashSet<>(); + for (Object label : labels) { + uniqueLabels.add(Util.intern(canonicalLabel(label.toString()))); + } + return uniqueLabels.toArray(EMPTY_STRING_ARRAY); + } + +} diff --git a/core/src/main/resources/hudson/model/Messages.properties b/core/src/main/resources/hudson/model/Messages.properties index e06fc0fb2648..33e069d4bb73 100644 --- a/core/src/main/resources/hudson/model/Messages.properties +++ b/core/src/main/resources/hudson/model/Messages.properties @@ -309,7 +309,7 @@ UpdateCenter.PluginCategory.dotnet=.NET Development UpdateCenter.PluginCategory.external=External Site/Tool Integrations UpdateCenter.PluginCategory.groovy-related=Groovy-related UpdateCenter.PluginCategory.ios=iOS Development -UpdateCenter.PluginCategory.library=Library plugins (for use by other plugins) +UpdateCenter.PluginCategory.api-plugin=Library plugins (for use by other plugins) UpdateCenter.PluginCategory.listview-column=List view columns UpdateCenter.PluginCategory.maven=Maven UpdateCenter.PluginCategory.misc=Miscellaneous @@ -326,7 +326,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 Management +UpdateCenter.PluginCategory.agent=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/Messages_bg.properties b/core/src/main/resources/hudson/model/Messages_bg.properties index 1c80a23398b1..66e2a4ecad58 100644 --- a/core/src/main/resources/hudson/model/Messages_bg.properties +++ b/core/src/main/resources/hudson/model/Messages_bg.properties @@ -433,7 +433,7 @@ UpdateCenter.PluginCategory.groovy-related=\ \u0421\u0432\u044a\u0440\u0437\u0430\u043d\u0438 \u0441 Groovy UpdateCenter.PluginCategory.ios=\ \u041f\u0440\u043e\u0433\u0440\u0430\u043c\u0438\u0440\u0430\u043d\u0435 \u0437\u0430 iOS -UpdateCenter.PluginCategory.library=\ +UpdateCenter.PluginCategory.api-plugin=\ \u041f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0438-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 (\u0438\u0437\u043f\u043e\u043b\u0437\u0432\u0430\u0442 \u0441\u0435 \u043e\u0442 \u0434\u0440\u0443\u0433\u0438 \u043f\u0440\u0438\u0441\u0442\u0430\u0432\u043a\u0438) UpdateCenter.PluginCategory.listview-column=\ \u041a\u043e\u043b\u043e\u043d\u0438 \u0432 \u0441\u043f\u0438\u0441\u044a\u0447\u043d\u0438\u044f \u0438\u0437\u0433\u043b\u0435\u0434 @@ -637,7 +637,7 @@ ComputerSet.SpecifySlaveToCopy=\ Slave.WindowsSlave=\ \u0422\u043e\u0432\u0430 \u0435 \u0430\u0433\u0435\u043d\u0442 \u0437\u0430 Windows # Agent Launchers and Controllers -UpdateCenter.PluginCategory.slaves=\ +UpdateCenter.PluginCategory.agent=\ \u0421\u0442\u0430\u0440\u0442\u0438\u0440\u0430\u043d\u0435 \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u043d\u0430 \u0430\u0433\u0435\u043d\u0442\u0438 MultiStageTimeSeries.EMPTY_STRING=\ diff --git a/core/src/main/resources/hudson/model/Messages_de.properties b/core/src/main/resources/hudson/model/Messages_de.properties index 620e5088f892..9de8c93e009d 100644 --- a/core/src/main/resources/hudson/model/Messages_de.properties +++ b/core/src/main/resources/hudson/model/Messages_de.properties @@ -311,7 +311,7 @@ UpdateCenter.PluginCategory.dotnet=.NET-Entwicklung UpdateCenter.PluginCategory.external=Integration externer Sites und Werkzeuge UpdateCenter.PluginCategory.groovy-related=Groovy (weiteres Umfeld) UpdateCenter.PluginCategory.ios=iOS-Entwicklung -UpdateCenter.PluginCategory.library=Programmbibliotheken (von anderen Plugins verwendet) +UpdateCenter.PluginCategory.api-plugin=Programmbibliotheken (von anderen Plugins verwendet) UpdateCenter.PluginCategory.listview-column=Spalten f\u00FCr Listenansichten UpdateCenter.PluginCategory.maven=Maven bzw. Plugins mit besonderer Maven-Unterst\u00FCtzung UpdateCenter.PluginCategory.misc=Verschiedenes @@ -326,7 +326,7 @@ UpdateCenter.PluginCategory.scala=Scala-Entwicklung UpdateCenter.PluginCategory.scm=Versionsverwaltung UpdateCenter.PluginCategory.scm-related=Versionsverwaltung (weiteres Umfeld) UpdateCenter.PluginCategory.security=Sicherheit -UpdateCenter.PluginCategory.slaves=Agenten-Start und -Steuerung +UpdateCenter.PluginCategory.agent=Agenten-Start und -Steuerung UpdateCenter.PluginCategory.test=Testen UpdateCenter.PluginCategory.trigger=Build-Ausl\u00F6ser UpdateCenter.PluginCategory.ui=Benutzeroberfl\u00E4che diff --git a/core/src/main/resources/hudson/model/Messages_es.properties b/core/src/main/resources/hudson/model/Messages_es.properties index 4fa6ccd05f77..a40a0cb3d3ce 100644 --- a/core/src/main/resources/hudson/model/Messages_es.properties +++ b/core/src/main/resources/hudson/model/Messages_es.properties @@ -194,7 +194,7 @@ UpdateCenter.PluginCategory.post-build=Plugins que a\u00f1aden acciones de post- UpdateCenter.PluginCategory.report=Plugins para generar informes UpdateCenter.PluginCategory.scm=Plugins de repositorios de software UpdateCenter.PluginCategory.scm-related=Plugins relacionados con la gesti\u00f3n repositorios -UpdateCenter.PluginCategory.slaves=Plugins para el control de nodos +UpdateCenter.PluginCategory.agent=Plugins para el control de nodos UpdateCenter.PluginCategory.trigger=Plugins lanzadores de tareas diff --git a/core/src/main/resources/hudson/model/Messages_it.properties b/core/src/main/resources/hudson/model/Messages_it.properties index 695944168aca..498514bcf843 100644 --- a/core/src/main/resources/hudson/model/Messages_it.properties +++ b/core/src/main/resources/hudson/model/Messages_it.properties @@ -403,7 +403,7 @@ UpdateCenter.PluginCategory.dotnet=Sviluppo .NET UpdateCenter.PluginCategory.external=Integrazioni siti/strumenti esterni UpdateCenter.PluginCategory.groovy-related=Componenti legati a Groovy UpdateCenter.PluginCategory.ios=Sviluppo iOS -UpdateCenter.PluginCategory.library=Componenti libreria (per l''utilizzo da \ +UpdateCenter.PluginCategory.api-plugin=Componenti libreria (per l''utilizzo da \ parte di altri componenti aggiuntivi) UpdateCenter.PluginCategory.listview-column=Colonne visualizzazione elenco UpdateCenter.PluginCategory.maven=Maven @@ -423,7 +423,7 @@ UpdateCenter.PluginCategory.scm=Gestione del codice sorgente UpdateCenter.PluginCategory.scm-related=Componenti legati alla gestione del \ codice sorgente UpdateCenter.PluginCategory.security=Sicurezza -UpdateCenter.PluginCategory.slaves=Avvio e controllo agenti +UpdateCenter.PluginCategory.agent=Avvio e controllo agenti UpdateCenter.PluginCategory.test=Test UpdateCenter.PluginCategory.theme=Temi interfaccia utente UpdateCenter.PluginCategory.trigger=Trigger compilazione diff --git a/core/src/main/resources/hudson/model/Messages_lt.properties b/core/src/main/resources/hudson/model/Messages_lt.properties index 22eb9d968088..5d2571900abd 100644 --- a/core/src/main/resources/hudson/model/Messages_lt.properties +++ b/core/src/main/resources/hudson/model/Messages_lt.properties @@ -252,7 +252,7 @@ UpdateCenter.PluginCategory.dotnet=.NET k\u016brimas UpdateCenter.PluginCategory.external=I\u0161orin\u0117 svetain\u0117/\u012franki\u0173 integracija UpdateCenter.PluginCategory.groovy-related=Groovy-susij\u0119s UpdateCenter.PluginCategory.ios=iOS k\u016brimas -UpdateCenter.PluginCategory.library=Bibliotek\u0173 priedai (naudojami kit\u0173 pried\u0173) +UpdateCenter.PluginCategory.api-plugin=Bibliotek\u0173 priedai (naudojami kit\u0173 pried\u0173) UpdateCenter.PluginCategory.listview-column=Rodinio s\u0105ra\u0161o stulpeliai UpdateCenter.PluginCategory.maven=Maven UpdateCenter.PluginCategory.misc=\u012evair\u016bs @@ -268,7 +268,7 @@ UpdateCenter.PluginCategory.scala=Scala k\u016brimas UpdateCenter.PluginCategory.scm=I\u0161eities kodo valdymas UpdateCenter.PluginCategory.scm-related=Susij\u0119 su i\u0161eities kodo valdymu UpdateCenter.PluginCategory.security=Saugumas -UpdateCenter.PluginCategory.slaves=Agent\u0173 paleid\u0117jai ir valdytojai +UpdateCenter.PluginCategory.agent=Agent\u0173 paleid\u0117jai ir valdytojai UpdateCenter.PluginCategory.test=Testavimas UpdateCenter.PluginCategory.trigger=Vykdymo trigeriai UpdateCenter.PluginCategory.ui=Naudotojo s\u0105saja diff --git a/core/src/main/resources/hudson/model/Messages_sr.properties b/core/src/main/resources/hudson/model/Messages_sr.properties index f75aca4c4ee1..ec285a88bbe3 100644 --- a/core/src/main/resources/hudson/model/Messages_sr.properties +++ b/core/src/main/resources/hudson/model/Messages_sr.properties @@ -27,7 +27,7 @@ UpdateCenter.PluginCategory.deployment=\u0418\u043D\u0441\u0442\u0430\u043B\u043 UpdateCenter.PluginCategory.external=\u0418\u043D\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0458\u0430 \u0435\u043A\u0441\u0442\u0435\u0440\u043D\u0438\u043C \u0441\u0435\u0440\u0432\u0438\u0441\u0438\u043C\u0430 \u0438 \u0430\u043B\u0430\u0442\u0438\u043C\u0430 UpdateCenter.PluginCategory.groovy-related=\u0423 \u0432\u0435\u0437\u0438 \u0441\u0430 Groovy UpdateCenter.PluginCategory.ios=iOS \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u0438\u0440\u0430\u045A\u0435 -UpdateCenter.PluginCategory.library=\u0411\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0435 \u0437\u0430 \u043C\u043E\u0434\u0443\u043B\u0435 (\u0443 \u043A\u043E\u0440\u0438\u0441\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u043C\u043E\u0434\u0443\u043B\u0430) +UpdateCenter.PluginCategory.api-plugin=\u0411\u0438\u0431\u043B\u0438\u043E\u0442\u0435\u043A\u0435 \u0437\u0430 \u043C\u043E\u0434\u0443\u043B\u0435 (\u0443 \u043A\u043E\u0440\u0438\u0441\u0442 \u0434\u0440\u0443\u0433\u0438\u0445 \u043C\u043E\u0434\u0443\u043B\u0430) UpdateCenter.PluginCategory.maven=Maven UpdateCenter.PluginCategory.cluster=\u0423\u043F\u0440\u0430\u0432\u0459\u0430\u045A\u0435 \u043A\u043B\u0430\u0441\u0442\u0435\u0440\u0430 \u0438 \u0440\u0430\u0441\u043F\u043E\u0434\u0435\u0459\u0435\u043D\u043E \u0438\u0437\u0433\u0440\u0430\u0434\u045A\u0435 UpdateCenter.PluginCategory.android=Android \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u0438\u0440\u0430\u045A\u0435 @@ -38,7 +38,7 @@ UpdateCenter.PluginCategory.scm=\u0421\u0438\u0441\u0442\u0435\u043C \u0437\u043 UpdateCenter.PluginCategory.scala=Scala \u043F\u0440\u043E\u0433\u0440\u0430\u043C\u0438\u0440\u0430\u045A\u0435 UpdateCenter.PluginCategory.scm-related=\u0412\u0435\u0437\u0430\u043D\u043E \u0441\u0430 \u0441\u0438\u0441\u0442\u0435\u043C\u043E\u043C \u0437\u0430 \u0443\u043F\u0440\u0430\u0432\u0459\u0430\u045A\u0435 \u0438\u0437\u0432\u043E\u0440\u043D\u043E\u0433 \u043A\u043E\u0434\u0430 UpdateCenter.PluginCategory.security=\u0411\u0435\u0437\u0431\u0435\u0434\u043D\u043E\u0441\u0442 -UpdateCenter.PluginCategory.slaves=\u041F\u043E\u043A\u0440\u0435\u0442\u0430\u045A\u0435 \u0438 \u0443\u043F\u0440\u0430\u0432\u0459\u0430\u045A\u0435 \u0430\u0433\u0435\u043D\u0430\u0442\u0430 +UpdateCenter.PluginCategory.agent=\u041F\u043E\u043A\u0440\u0435\u0442\u0430\u045A\u0435 \u0438 \u0443\u043F\u0440\u0430\u0432\u0459\u0430\u045A\u0435 \u0430\u0433\u0435\u043D\u0430\u0442\u0430 UpdateCenter.PluginCategory.test=\u0422\u0435\u0441\u0442\u0438\u0440\u0430\u045A\u0435 UpdateCenter.PluginCategory.trigger=\u0410\u0443\u0442\u043E\u043C\u0430\u0442\u0441\u043A\u0438 \u0441\u0442\u0430\u0440\u0442 \u0438\u0437\u0433\u0440\u0430\u0434\u045A\u0435 \u043D\u0430\u043F\u0430\u0441\u0432\u0430= diff --git a/core/src/main/resources/jenkins/canonical-labels.txt b/core/src/main/resources/jenkins/canonical-labels.txt new file mode 100644 index 000000000000..80da6345deac --- /dev/null +++ b/core/src/main/resources/jenkins/canonical-labels.txt @@ -0,0 +1,5 @@ +# This file lists plugin labels pairs that should be unified in the future. +# If these labels were changed in plugins now, they would not show localized strings in old core versions. +# See https://github.com/jenkinsci/jenkins/pull/6151 +library api-plugin +slaves agent \ No newline at end of file diff --git a/core/src/test/java/jenkins/util/PluginLabelUtilTest.java b/core/src/test/java/jenkins/util/PluginLabelUtilTest.java new file mode 100644 index 000000000000..312aa61ac32b --- /dev/null +++ b/core/src/test/java/jenkins/util/PluginLabelUtilTest.java @@ -0,0 +1,19 @@ +package jenkins.util; + +import static org.junit.Assert.assertArrayEquals; + +import net.sf.json.JSONArray; +import org.junit.Test; + +public class PluginLabelUtilTest { + + @Test + public void testCanonicalLabels() { + JSONArray labels = new JSONArray(); + labels.add("slaves"); + labels.add("api-plugin"); + labels.add("library"); + assertArrayEquals(new String[]{"agent", "api-plugin"}, + PluginLabelUtil.canonicalLabels(labels)); + } +}