mirror of https://github.com/jenkinsci/jenkins.git
`AdministrativeMonitorsDecorator` cleanup; `ManageJenkinsAction.getBadge` optimization (#10855)
This commit is contained in:
parent
3bf037ca07
commit
00c6707c45
|
@ -66,6 +66,11 @@ public class ReverseProxySetupMonitor extends AdministrativeMonitor {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isActivationFake() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Restricted(DoNotUse.class) // WebOnly
|
@Restricted(DoNotUse.class) // WebOnly
|
||||||
@RestrictedSince("2.235")
|
@RestrictedSince("2.235")
|
||||||
public HttpResponse doTest(StaplerRequest2 request, @QueryParameter boolean testWithContext) {
|
public HttpResponse doTest(StaplerRequest2 request, @QueryParameter boolean testWithContext) {
|
||||||
|
|
|
@ -160,6 +160,11 @@ public abstract class AdministrativeMonitor extends AbstractModelObject implemen
|
||||||
*/
|
*/
|
||||||
public abstract boolean isActivated();
|
public abstract boolean isActivated();
|
||||||
|
|
||||||
|
@Restricted(NoExternalUse.class)
|
||||||
|
public boolean isActivationFake() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this monitor is security related.
|
* Returns true if this monitor is security related.
|
||||||
*
|
*
|
||||||
|
@ -186,8 +191,7 @@ public abstract class AdministrativeMonitor extends AbstractModelObject implemen
|
||||||
* By default {@link Jenkins#ADMINISTER}, but {@link Jenkins#SYSTEM_READ} or {@link Jenkins#MANAGE} are also supported.
|
* By default {@link Jenkins#ADMINISTER}, but {@link Jenkins#SYSTEM_READ} or {@link Jenkins#MANAGE} are also supported.
|
||||||
* <p>
|
* <p>
|
||||||
* Changing this permission check to return {@link Jenkins#SYSTEM_READ} will make the active
|
* Changing this permission check to return {@link Jenkins#SYSTEM_READ} will make the active
|
||||||
* administrative monitor appear on {@code manage.jelly} and on the globally visible
|
* administrative monitor appear on {@link ManageJenkinsAction} to users without Administer permission.
|
||||||
* {@link jenkins.management.AdministrativeMonitorsDecorator} to users without Administer permission.
|
|
||||||
* {@link #doDisable(StaplerRequest2, StaplerResponse2)} will still always require Administer permission.
|
* {@link #doDisable(StaplerRequest2, StaplerResponse2)} will still always require Administer permission.
|
||||||
* </p>
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
|
|
|
@ -26,11 +26,11 @@ package hudson.model;
|
||||||
|
|
||||||
import hudson.Extension;
|
import hudson.Extension;
|
||||||
import hudson.Util;
|
import hudson.Util;
|
||||||
|
import hudson.util.HudsonIsLoading;
|
||||||
|
import hudson.util.HudsonIsRestarting;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.logging.Level;
|
||||||
import java.util.Collections;
|
import java.util.logging.Logger;
|
||||||
import java.util.Optional;
|
|
||||||
import jenkins.management.AdministrativeMonitorsDecorator;
|
|
||||||
import jenkins.management.Badge;
|
import jenkins.management.Badge;
|
||||||
import jenkins.model.Jenkins;
|
import jenkins.model.Jenkins;
|
||||||
import jenkins.model.ModelObjectWithContextMenu;
|
import jenkins.model.ModelObjectWithContextMenu;
|
||||||
|
@ -50,6 +50,9 @@ import org.kohsuke.stapler.StaplerResponse2;
|
||||||
*/
|
*/
|
||||||
@Extension(ordinal = 998) @Symbol("manageJenkins")
|
@Extension(ordinal = 998) @Symbol("manageJenkins")
|
||||||
public class ManageJenkinsAction implements RootAction, StaplerFallback, ModelObjectWithContextMenu {
|
public class ManageJenkinsAction implements RootAction, StaplerFallback, ModelObjectWithContextMenu {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(ManageJenkinsAction.class.getName());
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getIconFileName() {
|
public String getIconFileName() {
|
||||||
if (Jenkins.get().hasAnyPermission(Jenkins.MANAGE, Jenkins.SYSTEM_READ))
|
if (Jenkins.get().hasAnyPermission(Jenkins.MANAGE, Jenkins.SYSTEM_READ))
|
||||||
|
@ -98,28 +101,36 @@ public class ManageJenkinsAction implements RootAction, StaplerFallback, ModelOb
|
||||||
menu.add("manage/" + url, icon, iconXml, text, post, requiresConfirmation, badge, message);
|
menu.add("manage/" + url, icon, iconXml, text, post, requiresConfirmation, badge, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Unlike {@link Jenkins#getActiveAdministrativeMonitors} this checks for activation lazily. */
|
||||||
@Override
|
@Override
|
||||||
public Badge getBadge() {
|
public Badge getBadge() {
|
||||||
Jenkins jenkins = Jenkins.get();
|
if (!(AdministrativeMonitor.hasPermissionToDisplay())) {
|
||||||
AdministrativeMonitorsDecorator decorator = jenkins.getExtensionList(PageDecorator.class)
|
|
||||||
.get(AdministrativeMonitorsDecorator.class);
|
|
||||||
|
|
||||||
if (decorator == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<AdministrativeMonitor> activeAdministrativeMonitors = Optional.ofNullable(decorator.getMonitorsToDisplay()).orElse(Collections.emptyList());
|
var app = Jenkins.get().getServletContext().getAttribute("app");
|
||||||
boolean anySecurity = activeAdministrativeMonitors.stream().anyMatch(AdministrativeMonitor::isSecurity);
|
if (app instanceof HudsonIsLoading || app instanceof HudsonIsRestarting) {
|
||||||
|
|
||||||
if (activeAdministrativeMonitors.isEmpty()) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
int size = activeAdministrativeMonitors.size();
|
if (Jenkins.get().administrativeMonitors.stream().anyMatch(m -> m.isSecurity() && isActive(m))) {
|
||||||
String tooltip = size > 1 ? Messages.ManageJenkinsAction_notifications(size) : Messages.ManageJenkinsAction_notification(size);
|
return new Badge("1+", Messages.ManageJenkinsAction_notifications(),
|
||||||
|
Badge.Severity.DANGER);
|
||||||
return new Badge(String.valueOf(size),
|
} else if (Jenkins.get().administrativeMonitors.stream().anyMatch(m -> !m.isSecurity() && isActive(m))) {
|
||||||
tooltip,
|
return new Badge("1+", Messages.ManageJenkinsAction_notifications(),
|
||||||
anySecurity ? Badge.Severity.DANGER : Badge.Severity.WARNING);
|
Badge.Severity.WARNING);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isActive(AdministrativeMonitor m) {
|
||||||
|
try {
|
||||||
|
return !m.isActivationFake() && m.hasRequiredPermission() && m.isEnabled() && m.isActivated();
|
||||||
|
} catch (Throwable x) {
|
||||||
|
LOGGER.log(Level.WARNING, null, x);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,11 @@ public class URICheckEncodingMonitor extends AdministrativeMonitor {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isActivationFake() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDisplayName() {
|
public String getDisplayName() {
|
||||||
return Messages.URICheckEncodingMonitor_DisplayName();
|
return Messages.URICheckEncodingMonitor_DisplayName();
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
package jenkins.management;
|
|
||||||
|
|
||||||
import hudson.Extension;
|
|
||||||
import hudson.model.PageDecorator;
|
|
||||||
import hudson.model.RootAction;
|
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import jenkins.model.Jenkins;
|
|
||||||
import org.kohsuke.accmod.Restricted;
|
|
||||||
import org.kohsuke.accmod.restrictions.NoExternalUse;
|
|
||||||
import org.kohsuke.stapler.StaplerRequest2;
|
|
||||||
import org.kohsuke.stapler.StaplerResponse2;
|
|
||||||
import org.kohsuke.stapler.verb.GET;
|
|
||||||
|
|
||||||
@Extension
|
|
||||||
@Restricted(NoExternalUse.class)
|
|
||||||
public class AdministrativeMonitorsApi implements RootAction {
|
|
||||||
@GET
|
|
||||||
public void doNonSecurityPopupContent(StaplerRequest2 req, StaplerResponse2 resp) throws IOException, ServletException {
|
|
||||||
AdministrativeMonitorsApiData viewData = new AdministrativeMonitorsApiData(getDecorator().getNonSecurityAdministrativeMonitors());
|
|
||||||
req.getView(viewData, "monitorsList.jelly").forward(req, resp);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GET
|
|
||||||
public void doSecurityPopupContent(StaplerRequest2 req, StaplerResponse2 resp) throws IOException, ServletException {
|
|
||||||
AdministrativeMonitorsApiData viewData = new AdministrativeMonitorsApiData(getDecorator().getSecurityAdministrativeMonitors());
|
|
||||||
req.getView(viewData, "monitorsList.jelly").forward(req, resp);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getIconFileName() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDisplayName() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getUrlName() {
|
|
||||||
return "administrativeMonitorsApi";
|
|
||||||
}
|
|
||||||
|
|
||||||
private AdministrativeMonitorsDecorator getDecorator() {
|
|
||||||
return Jenkins.get()
|
|
||||||
.getExtensionList(PageDecorator.class)
|
|
||||||
.get(AdministrativeMonitorsDecorator.class);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
package jenkins.management;
|
|
||||||
|
|
||||||
import hudson.model.AdministrativeMonitor;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import org.kohsuke.accmod.Restricted;
|
|
||||||
import org.kohsuke.accmod.restrictions.NoExternalUse;
|
|
||||||
|
|
||||||
@Restricted(NoExternalUse.class)
|
|
||||||
public class AdministrativeMonitorsApiData {
|
|
||||||
private final List<AdministrativeMonitor> monitorsList = new ArrayList<>();
|
|
||||||
|
|
||||||
AdministrativeMonitorsApiData(List<AdministrativeMonitor> monitors) {
|
|
||||||
monitorsList.addAll(monitors);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<AdministrativeMonitor> getMonitorsList() {
|
|
||||||
return this.monitorsList;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasActiveMonitors() {
|
|
||||||
return !this.monitorsList.isEmpty();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,173 +0,0 @@
|
||||||
/*
|
|
||||||
* The MIT License
|
|
||||||
*
|
|
||||||
* Copyright (c) 2016, Daniel Beck, 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.management;
|
|
||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.NonNull;
|
|
||||||
import hudson.Extension;
|
|
||||||
import hudson.diagnosis.ReverseProxySetupMonitor;
|
|
||||||
import hudson.model.AdministrativeMonitor;
|
|
||||||
import hudson.model.PageDecorator;
|
|
||||||
import hudson.util.HudsonIsLoading;
|
|
||||||
import hudson.util.HudsonIsRestarting;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import jenkins.diagnostics.URICheckEncodingMonitor;
|
|
||||||
import jenkins.model.Jenkins;
|
|
||||||
import org.kohsuke.accmod.Restricted;
|
|
||||||
import org.kohsuke.accmod.restrictions.NoExternalUse;
|
|
||||||
import org.kohsuke.stapler.Ancestor;
|
|
||||||
import org.kohsuke.stapler.Stapler;
|
|
||||||
import org.kohsuke.stapler.StaplerRequest2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show notifications and popups for active administrative monitors on all pages.
|
|
||||||
*/
|
|
||||||
@Extension
|
|
||||||
@Restricted(NoExternalUse.class)
|
|
||||||
public class AdministrativeMonitorsDecorator extends PageDecorator {
|
|
||||||
private final Collection<String> ignoredJenkinsRestOfUrls = new ArrayList<>();
|
|
||||||
|
|
||||||
public AdministrativeMonitorsDecorator() {
|
|
||||||
// otherwise this would be added to every internal context menu building request
|
|
||||||
ignoredJenkinsRestOfUrls.add("contextMenu");
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public String getDisplayName() {
|
|
||||||
return Messages.AdministrativeMonitorsDecorator_DisplayName();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by Jelly
|
|
||||||
public Collection<AdministrativeMonitor> filterNonSecurityAdministrativeMonitors(Collection<AdministrativeMonitor> activeMonitors) {
|
|
||||||
return this.filterActiveAdministrativeMonitors(activeMonitors, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by Jelly
|
|
||||||
public Collection<AdministrativeMonitor> filterSecurityAdministrativeMonitors(Collection<AdministrativeMonitor> activeMonitors) {
|
|
||||||
return this.filterActiveAdministrativeMonitors(activeMonitors, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prevent us to compute multiple times the {@link AdministrativeMonitor#isActivated()} by re-using the same list
|
|
||||||
*/
|
|
||||||
private Collection<AdministrativeMonitor> filterActiveAdministrativeMonitors(Collection<AdministrativeMonitor> activeMonitors, boolean isSecurity) {
|
|
||||||
Collection<AdministrativeMonitor> active = new ArrayList<>();
|
|
||||||
for (AdministrativeMonitor am : activeMonitors) {
|
|
||||||
if (am.isSecurity() == isSecurity) {
|
|
||||||
active.add(am);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return active;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by API
|
|
||||||
public List<AdministrativeMonitor> getNonSecurityAdministrativeMonitors() {
|
|
||||||
Collection<AdministrativeMonitor> allowedMonitors = getMonitorsToDisplay();
|
|
||||||
|
|
||||||
if (allowedMonitors == null) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return allowedMonitors.stream()
|
|
||||||
.filter(administrativeMonitor -> !administrativeMonitor.isSecurity())
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used by API
|
|
||||||
public List<AdministrativeMonitor> getSecurityAdministrativeMonitors() {
|
|
||||||
Collection<AdministrativeMonitor> allowedMonitors = getMonitorsToDisplay();
|
|
||||||
|
|
||||||
if (allowedMonitors == null) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
return allowedMonitors.stream()
|
|
||||||
.filter(AdministrativeMonitor::isSecurity)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Collection<AdministrativeMonitor> getAllActiveAdministrativeMonitors() {
|
|
||||||
Collection<AdministrativeMonitor> active = new ArrayList<>();
|
|
||||||
for (AdministrativeMonitor am : Jenkins.get().getActiveAdministrativeMonitors()) {
|
|
||||||
if (am instanceof ReverseProxySetupMonitor) {
|
|
||||||
// TODO make reverse proxy monitor work when shown on any URL
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (am instanceof URICheckEncodingMonitor) {
|
|
||||||
// TODO make URI encoding monitor work when shown on any URL
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
active.add(am);
|
|
||||||
}
|
|
||||||
return active;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compute the administrative monitors that are active and should be shown.
|
|
||||||
* This is done only when the instance is currently running and the user has the permission to read them.
|
|
||||||
*
|
|
||||||
* @return the list of active monitors if we should display them, otherwise null.
|
|
||||||
*/
|
|
||||||
public Collection<AdministrativeMonitor> getMonitorsToDisplay() {
|
|
||||||
if (!(AdministrativeMonitor.hasPermissionToDisplay())) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
StaplerRequest2 req = Stapler.getCurrentRequest2();
|
|
||||||
|
|
||||||
if (req == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
List<Ancestor> ancestors = req.getAncestors();
|
|
||||||
|
|
||||||
if (ancestors == null || ancestors.isEmpty()) {
|
|
||||||
// ???
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ancestor a = ancestors.get(ancestors.size() - 1);
|
|
||||||
Object o = a.getObject();
|
|
||||||
|
|
||||||
// don't show while Jenkins is loading
|
|
||||||
if (o instanceof HudsonIsLoading || o instanceof HudsonIsRestarting) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// don't show for some URLs served directly by Jenkins
|
|
||||||
if (o instanceof Jenkins) {
|
|
||||||
String url = a.getRestOfUrl();
|
|
||||||
|
|
||||||
if (ignoredJenkinsRestOfUrls.contains(url)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return getAllActiveAdministrativeMonitors();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -66,7 +66,6 @@ public class Badge {
|
||||||
*
|
*
|
||||||
* @param text The text to be shown in the badge.
|
* @param text The text to be shown in the badge.
|
||||||
* Keep it short, ideally just a number. More than 6 or 7 characters do not look good. Avoid spaces as they will lead to line breaks.
|
* Keep it short, ideally just a number. More than 6 or 7 characters do not look good. Avoid spaces as they will lead to line breaks.
|
||||||
* as this might lead to line breaks.
|
|
||||||
* @param tooltip The tooltip to show for the badge.
|
* @param tooltip The tooltip to show for the badge.
|
||||||
* Do not include html tags.
|
* Do not include html tags.
|
||||||
* @param severity The severity of the badge (danger, warning, info)
|
* @param severity The severity of the badge (danger, warning, info)
|
||||||
|
|
|
@ -199,8 +199,7 @@ LabelExpression.LabelLink=<a href="{0}{2}">Label {1}</a> matches {3,choice,0#no
|
||||||
LabelExpression.NoMatch=No agent/cloud matches this label expression.
|
LabelExpression.NoMatch=No agent/cloud matches this label expression.
|
||||||
LabelExpression.NoMatch_DidYouMean=No agent/cloud matches this label expression. Did you mean ‘{1}’ instead of ‘{0}’?
|
LabelExpression.NoMatch_DidYouMean=No agent/cloud matches this label expression. Did you mean ‘{1}’ instead of ‘{0}’?
|
||||||
ManageJenkinsAction.DisplayName=Manage Jenkins
|
ManageJenkinsAction.DisplayName=Manage Jenkins
|
||||||
ManageJenkinsAction.notification={0} notification
|
ManageJenkinsAction.notifications=One or more notifications
|
||||||
ManageJenkinsAction.notifications={0} notifications
|
|
||||||
MultiStageTimeSeries.EMPTY_STRING=
|
MultiStageTimeSeries.EMPTY_STRING=
|
||||||
ParametersDefinitionProperty.BuildButtonText=Build
|
ParametersDefinitionProperty.BuildButtonText=Build
|
||||||
Queue.AllNodesOffline=All nodes of label ‘{0}’ are offline
|
Queue.AllNodesOffline=All nodes of label ‘{0}’ are offline
|
||||||
|
|
|
@ -66,5 +66,3 @@ ShutdownLink.Description=Stops executing new builds, so that the system can be e
|
||||||
ShutdownLink.ShuttingDownInProgressDescription=Jenkins is currently shutting down. New builds are not executing.
|
ShutdownLink.ShuttingDownInProgressDescription=Jenkins is currently shutting down. New builds are not executing.
|
||||||
ShutdownLink.ShutDownReason_title=Reason
|
ShutdownLink.ShutDownReason_title=Reason
|
||||||
ShutdownLink.ShutDownReason_update=Update reason
|
ShutdownLink.ShutDownReason_update=Update reason
|
||||||
|
|
||||||
AdministrativeMonitorsDecorator.DisplayName=Administrative Monitors Notifier
|
|
||||||
|
|
|
@ -74,6 +74,3 @@ ShutdownLink.Description=\
|
||||||
# Configure tools, their locations and automatic installers.
|
# Configure tools, their locations and automatic installers.
|
||||||
ConfigureTools.Description=\
|
ConfigureTools.Description=\
|
||||||
Настройване на инструментите, местоположенията и автоматичното инсталиране.
|
Настройване на инструментите, местоположенията и автоматичното инсталиране.
|
||||||
# Administrative Monitors Notifier
|
|
||||||
AdministrativeMonitorsDecorator.DisplayName=\
|
|
||||||
Известия за предупреждения
|
|
||||||
|
|
|
@ -49,5 +49,4 @@ NodesLink.Description=Knoten hinzufügen, entfernen, steuern und überwachen, au
|
||||||
CliLink.Description=Jenkins aus der Kommandozeile oder skriptgesteuert nutzen und verwalten.
|
CliLink.Description=Jenkins aus der Kommandozeile oder skriptgesteuert nutzen und verwalten.
|
||||||
CliLink.DisplayName=Jenkins CLI
|
CliLink.DisplayName=Jenkins CLI
|
||||||
SystemLogLink.DisplayName=Systemlog
|
SystemLogLink.DisplayName=Systemlog
|
||||||
AdministrativeMonitorsDecorator.DisplayName=Anzeige aktiver Administrator-Warnungen
|
|
||||||
ConfigureTools.Description=Hilfsprogramme, ihre Installationsverzeichnisse und Installationsverfahren konfigurieren
|
ConfigureTools.Description=Hilfsprogramme, ihre Installationsverzeichnisse und Installationsverfahren konfigurieren
|
||||||
|
|
|
@ -21,8 +21,6 @@
|
||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
# THE SOFTWARE.
|
# THE SOFTWARE.
|
||||||
|
|
||||||
AdministrativeMonitorsDecorator.DisplayName=Componente di notifica monitor \
|
|
||||||
amministrativi
|
|
||||||
CliLink.Description=Accedi/gestisci Jenkins dal terminale o da uno script.
|
CliLink.Description=Accedi/gestisci Jenkins dal terminale o da uno script.
|
||||||
CliLink.DisplayName=Interfaccia a riga di comando di Jenkins
|
CliLink.DisplayName=Interfaccia a riga di comando di Jenkins
|
||||||
ConfigureLink.Description=Configura le impostazioni e i percorsi globali.
|
ConfigureLink.Description=Configura le impostazioni e i percorsi globali.
|
||||||
|
|
|
@ -45,7 +45,6 @@ NodesLink.Description=Adiciona, remove, controla e monitora o vários nós
|
||||||
CliLink.DisplayName=Interface de Linha de Commando do Jenkins (CLI)
|
CliLink.DisplayName=Interface de Linha de Commando do Jenkins (CLI)
|
||||||
ShutdownLink.DisplayName_update=Atualizar preparação de desligamento
|
ShutdownLink.DisplayName_update=Atualizar preparação de desligamento
|
||||||
ShutdownLink.ShutDownReason_update=Atualizar razão
|
ShutdownLink.ShutDownReason_update=Atualizar razão
|
||||||
AdministrativeMonitorsDecorator.DisplayName=Notificador de monitorações administrativas
|
|
||||||
ConfigureTools.Description=Configurar ferramentas, suas localizações e instaladores automáticos.
|
ConfigureTools.Description=Configurar ferramentas, suas localizações e instaladores automáticos.
|
||||||
ShutdownLink.ShuttingDownInProgressDescription=O Jenkins está sendo desligado no momento. Novas construções não serão executadas.
|
ShutdownLink.ShuttingDownInProgressDescription=O Jenkins está sendo desligado no momento. Novas construções não serão executadas.
|
||||||
ShutdownLink.ShutDownReason_title=Razão
|
ShutdownLink.ShutDownReason_title=Razão
|
||||||
|
|
|
@ -41,4 +41,3 @@ NodesLink.Description=Позволяет добавлять, удалять, к
|
||||||
PluginsLink.Description=Добавить, удалить, отключить или включить плагины, расширяющие функционональные возможности Jenkins.
|
PluginsLink.Description=Добавить, удалить, отключить или включить плагины, расширяющие функционональные возможности Jenkins.
|
||||||
ConfigureTools.Description=Конфигурация инструментов, их расположение и автоматическая инсталяция.
|
ConfigureTools.Description=Конфигурация инструментов, их расположение и автоматическая инсталяция.
|
||||||
SystemLogLink.DisplayName=Системный журнал
|
SystemLogLink.DisplayName=Системный журнал
|
||||||
AdministrativeMonitorsDecorator.DisplayName=Системные уведомления
|
|
||||||
|
|
|
@ -66,5 +66,3 @@ ShutdownLink.Description=Slutar köra nya byggen så att systemet eventuellt kan
|
||||||
ShutdownLink.ShuttingDownInProgressDescription=Jenkins stängs ned för tillfället. Nya byggen körs inte.
|
ShutdownLink.ShuttingDownInProgressDescription=Jenkins stängs ned för tillfället. Nya byggen körs inte.
|
||||||
ShutdownLink.ShutDownReason_title=Anledning
|
ShutdownLink.ShutDownReason_title=Anledning
|
||||||
ShutdownLink.ShutDownReason_update=Uppdatera anledning
|
ShutdownLink.ShutDownReason_update=Uppdatera anledning
|
||||||
|
|
||||||
AdministrativeMonitorsDecorator.DisplayName=Avisering om administrativ övervakning
|
|
||||||
|
|
|
@ -58,5 +58,3 @@ ShutdownLink.Description=不再執行新的建置作業,讓系統可以安全
|
||||||
ShutdownLink.ShuttingDownInProgressDescription=Jenkins 正在停機,不會執行新的建置作業。
|
ShutdownLink.ShuttingDownInProgressDescription=Jenkins 正在停機,不會執行新的建置作業。
|
||||||
ShutdownLink.ShutDownReason_title=原因
|
ShutdownLink.ShutDownReason_title=原因
|
||||||
ShutdownLink.ShutDownReason_update=更新原因
|
ShutdownLink.ShutDownReason_update=更新原因
|
||||||
|
|
||||||
AdministrativeMonitorsDecorator.DisplayName=管理監視器通知
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
import hudson.ExtensionList;
|
import hudson.ExtensionList;
|
||||||
import hudson.model.AdministrativeMonitor;
|
import hudson.model.AdministrativeMonitor;
|
||||||
|
import hudson.model.ManageJenkinsAction;
|
||||||
import hudson.model.User;
|
import hudson.model.User;
|
||||||
import hudson.security.ACL;
|
import hudson.security.ACL;
|
||||||
import hudson.security.Permission;
|
import hudson.security.Permission;
|
||||||
|
@ -40,6 +41,7 @@ import org.jenkinsci.Symbol;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.jvnet.hudson.test.For;
|
||||||
import org.jvnet.hudson.test.Issue;
|
import org.jvnet.hudson.test.Issue;
|
||||||
import org.jvnet.hudson.test.JenkinsRule;
|
import org.jvnet.hudson.test.JenkinsRule;
|
||||||
import org.jvnet.hudson.test.MockAuthorizationStrategy;
|
import org.jvnet.hudson.test.MockAuthorizationStrategy;
|
||||||
|
@ -47,6 +49,7 @@ import org.jvnet.hudson.test.TestExtension;
|
||||||
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
|
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
|
||||||
|
|
||||||
@WithJenkins
|
@WithJenkins
|
||||||
|
@For(ManageJenkinsAction.class) // the name is historical
|
||||||
class AdministrativeMonitorsDecoratorTest {
|
class AdministrativeMonitorsDecoratorTest {
|
||||||
|
|
||||||
private String managePermission;
|
private String managePermission;
|
||||||
|
@ -68,8 +71,15 @@ class AdministrativeMonitorsDecoratorTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void deleteOtherImpls(ExtensionList<AdministrativeMonitor> extensionList) {
|
||||||
|
extensionList.removeAll(extensionList.stream().filter(m -> m.getClass().getEnclosingClass() != AdministrativeMonitorsDecoratorTest.class).toList());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void ensureAdminMonitorsAreNotRunPerNonAdminPage() throws Exception {
|
void ensureAdminMonitorsAreNotRunPerNonAdminPage() throws Exception {
|
||||||
|
ExtensionList<AdministrativeMonitor> extensionList = j.jenkins.getExtensionList(AdministrativeMonitor.class);
|
||||||
|
deleteOtherImpls(extensionList);
|
||||||
|
|
||||||
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
|
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
|
||||||
String nonAdminLogin = "nonAdmin";
|
String nonAdminLogin = "nonAdmin";
|
||||||
User.getById(nonAdminLogin, true);
|
User.getById(nonAdminLogin, true);
|
||||||
|
@ -81,7 +91,6 @@ class AdministrativeMonitorsDecoratorTest {
|
||||||
JenkinsRule.WebClient wc = j.createWebClient();
|
JenkinsRule.WebClient wc = j.createWebClient();
|
||||||
wc.login(nonAdminLogin);
|
wc.login(nonAdminLogin);
|
||||||
|
|
||||||
ExtensionList<AdministrativeMonitor> extensionList = j.jenkins.getExtensionList(AdministrativeMonitor.class);
|
|
||||||
ExecutionCounterNonSecAdministrativeMonitor nonSecCounter = extensionList.get(ExecutionCounterNonSecAdministrativeMonitor.class);
|
ExecutionCounterNonSecAdministrativeMonitor nonSecCounter = extensionList.get(ExecutionCounterNonSecAdministrativeMonitor.class);
|
||||||
ExecutionCounterSecAdministrativeMonitor secCounter = extensionList.get(ExecutionCounterSecAdministrativeMonitor.class);
|
ExecutionCounterSecAdministrativeMonitor secCounter = extensionList.get(ExecutionCounterSecAdministrativeMonitor.class);
|
||||||
|
|
||||||
|
@ -92,6 +101,9 @@ class AdministrativeMonitorsDecoratorTest {
|
||||||
@Test
|
@Test
|
||||||
@Issue("JENKINS-63977")
|
@Issue("JENKINS-63977")
|
||||||
void ensureAdminMonitorsAreRunOnlyOncePerAdminPage() throws Exception {
|
void ensureAdminMonitorsAreRunOnlyOncePerAdminPage() throws Exception {
|
||||||
|
ExtensionList<AdministrativeMonitor> extensionList = j.jenkins.getExtensionList(AdministrativeMonitor.class);
|
||||||
|
deleteOtherImpls(extensionList);
|
||||||
|
|
||||||
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
|
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
|
||||||
String adminLogin = "admin";
|
String adminLogin = "admin";
|
||||||
User.getById(adminLogin, true);
|
User.getById(adminLogin, true);
|
||||||
|
@ -103,15 +115,40 @@ class AdministrativeMonitorsDecoratorTest {
|
||||||
JenkinsRule.WebClient wc = j.createWebClient();
|
JenkinsRule.WebClient wc = j.createWebClient();
|
||||||
wc.login(adminLogin);
|
wc.login(adminLogin);
|
||||||
|
|
||||||
ExtensionList<AdministrativeMonitor> extensionList = j.jenkins.getExtensionList(AdministrativeMonitor.class);
|
|
||||||
ExecutionCounterNonSecAdministrativeMonitor nonSecCounter = extensionList.get(ExecutionCounterNonSecAdministrativeMonitor.class);
|
ExecutionCounterNonSecAdministrativeMonitor nonSecCounter = extensionList.get(ExecutionCounterNonSecAdministrativeMonitor.class);
|
||||||
ExecutionCounterSecAdministrativeMonitor secCounter = extensionList.get(ExecutionCounterSecAdministrativeMonitor.class);
|
ExecutionCounterSecAdministrativeMonitor secCounter = extensionList.get(ExecutionCounterSecAdministrativeMonitor.class);
|
||||||
|
|
||||||
assertEquals(1, nonSecCounter.count);
|
assertEquals(0, nonSecCounter.count);
|
||||||
assertEquals(1, secCounter.count);
|
assertEquals(1, secCounter.count);
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestExtension({"ensureAdminMonitorsAreNotRunPerNonAdminPage", "ensureAdminMonitorsAreRunOnlyOncePerAdminPage"})
|
@Test
|
||||||
|
void ensureOnlyOneAdminMonitorPerTypeIsRunPerAdminPage() throws Exception {
|
||||||
|
ExtensionList<AdministrativeMonitor> extensionList = j.jenkins.getExtensionList(AdministrativeMonitor.class);
|
||||||
|
deleteOtherImpls(extensionList);
|
||||||
|
|
||||||
|
j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
|
||||||
|
String adminLogin = "admin";
|
||||||
|
User.getById(adminLogin, true);
|
||||||
|
|
||||||
|
j.jenkins.setAuthorizationStrategy(new MockAuthorizationStrategy()
|
||||||
|
.grant(Jenkins.ADMINISTER).everywhere().to(adminLogin)
|
||||||
|
);
|
||||||
|
|
||||||
|
JenkinsRule.WebClient wc = j.createWebClient();
|
||||||
|
wc.login(adminLogin);
|
||||||
|
|
||||||
|
ExecutionCounterNonSecAdministrativeMonitor nonSecCounter = extensionList.get(ExecutionCounterNonSecAdministrativeMonitor.class);
|
||||||
|
ExecutionCounterNonSecAdministrativeMonitor2 nonSecCounter2 = extensionList.get(ExecutionCounterNonSecAdministrativeMonitor2.class);
|
||||||
|
ExecutionCounterSecAdministrativeMonitor secCounter = extensionList.get(ExecutionCounterSecAdministrativeMonitor.class);
|
||||||
|
|
||||||
|
assertEquals(0, nonSecCounter.count);
|
||||||
|
assertEquals(0, nonSecCounter2.count);
|
||||||
|
assertEquals(1, secCounter.count);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@TestExtension({"ensureAdminMonitorsAreNotRunPerNonAdminPage", "ensureAdminMonitorsAreRunOnlyOncePerAdminPage", "ensureOnlyOneAdminMonitorPerTypeIsRunPerAdminPage"})
|
||||||
@Symbol("non_sec_counting")
|
@Symbol("non_sec_counting")
|
||||||
public static class ExecutionCounterNonSecAdministrativeMonitor extends AdministrativeMonitor {
|
public static class ExecutionCounterNonSecAdministrativeMonitor extends AdministrativeMonitor {
|
||||||
|
|
||||||
|
@ -134,7 +171,30 @@ class AdministrativeMonitorsDecoratorTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestExtension({"ensureAdminMonitorsAreNotRunPerNonAdminPage", "ensureAdminMonitorsAreRunOnlyOncePerAdminPage"})
|
@TestExtension("ensureOnlyOneAdminMonitorPerTypeIsRunPerAdminPage")
|
||||||
|
@Symbol("non_sec_counting_2")
|
||||||
|
public static class ExecutionCounterNonSecAdministrativeMonitor2 extends AdministrativeMonitor {
|
||||||
|
|
||||||
|
public int count = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDisplayName() {
|
||||||
|
return "NonSecCounter2";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isActivated() {
|
||||||
|
count++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSecurity() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestExtension({"ensureAdminMonitorsAreNotRunPerNonAdminPage", "ensureAdminMonitorsAreRunOnlyOncePerAdminPage", "ensureOnlyOneAdminMonitorPerTypeIsRunPerAdminPage"})
|
||||||
@Symbol("sec_counting")
|
@Symbol("sec_counting")
|
||||||
public static class ExecutionCounterSecAdministrativeMonitor extends AdministrativeMonitor {
|
public static class ExecutionCounterSecAdministrativeMonitor extends AdministrativeMonitor {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue