Allow to define per project if plugin config parameter is editable
It is now possible to decide for a project specific plugin configuration parameter whether for a specific project it is editable in the UI. Change-Id: I29f55ca80d0c304ec61e5f7be10128629c7945cf Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
@@ -1301,6 +1301,8 @@ The type of the configuration parameter, can be `STRING`, `INT`,
|
||||
The value of the configuration parameter as string. If the parameter
|
||||
is inheritable this is the effective value which is deduced from
|
||||
`configured_value` and `inherited_value`.
|
||||
`editable` |`false` if not set|
|
||||
Whether the value is editable.
|
||||
|`permitted_values`|optional|
|
||||
The list of permitted values, only set if the `type` is `LIST`.
|
||||
|`inheritable` |`false` if not set|
|
||||
|
||||
@@ -377,7 +377,11 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (param.editable()) {
|
||||
widgetMap.put(param.name(), w);
|
||||
} else {
|
||||
w.setEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,8 +445,30 @@ public class ProjectInfoScreen extends ProjectScreen {
|
||||
}
|
||||
}
|
||||
|
||||
g.add(getDisplayName(param), listBox);
|
||||
if (param.editable()) {
|
||||
saveEnabler.listenTo(listBox);
|
||||
g.add(getDisplayName(param), listBox);
|
||||
} else {
|
||||
listBox.setEnabled(false);
|
||||
|
||||
if (param.inheritable() && listBox.getSelectedIndex() != 0) {
|
||||
// the inherited value is not selected,
|
||||
// since the listBox is disabled the inherited value cannot be
|
||||
// seen and we have to display it explicitly
|
||||
Label inheritedLabel =
|
||||
new Label(Util.M.pluginProjectInheritedValue(param
|
||||
.inheritedValue()));
|
||||
inheritedLabel.setStyleName(Gerrit.RESOURCES.css()
|
||||
.pluginProjectConfigInheritedValue());
|
||||
HorizontalPanel p = new HorizontalPanel();
|
||||
p.add(listBox);
|
||||
p.add(inheritedLabel);
|
||||
g.add(getDisplayName(param), p);
|
||||
} else {
|
||||
g.add(getDisplayName(param), listBox);
|
||||
}
|
||||
}
|
||||
|
||||
return listBox;
|
||||
}
|
||||
|
||||
|
||||
@@ -151,6 +151,7 @@ public class ConfigInfo extends JavaScriptObject {
|
||||
public final native String displayName() /*-{ return this.display_name; }-*/;
|
||||
public final native String type() /*-{ return this.type; }-*/;
|
||||
public final native String value() /*-{ return this.value; }-*/;
|
||||
public final native boolean editable() /*-{ return this.editable ? true : false; }-*/;
|
||||
public final native boolean inheritable() /*-{ return this.inheritable ? true : false; }-*/;
|
||||
public final native String configuredValue() /*-{ return this.configured_value; }-*/;
|
||||
public final native String inheritedValue() /*-{ return this.inherited_value; }-*/;
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.google.gerrit.server.config;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gerrit.extensions.annotations.ExtensionPoint;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@@ -121,4 +122,8 @@ public class ProjectConfigEntry {
|
||||
public List<String> getPermittedValues() {
|
||||
return permittedValues;
|
||||
}
|
||||
|
||||
public boolean isEditable(ProjectState project) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +72,11 @@ public enum CommitMergeStatus {
|
||||
"Change contains an invalid project configuration:\n"
|
||||
+ "One of the plugin configuration parameters has a value that is not permitted."),
|
||||
|
||||
/** */
|
||||
INVALID_PROJECT_CONFIGURATION_PLUGIN_VALUE_NOT_EDITABLE(
|
||||
"Change contains an invalid project configuration:\n"
|
||||
+ "One of the plugin configuration parameters is not editable."),
|
||||
|
||||
/** */
|
||||
INVALID_PROJECT_CONFIGURATION_PARENT_PROJECT_NOT_FOUND(
|
||||
"Change contains an invalid project configuration:\n"
|
||||
|
||||
@@ -687,6 +687,7 @@ public class MergeOp {
|
||||
case NOT_FAST_FORWARD:
|
||||
case INVALID_PROJECT_CONFIGURATION:
|
||||
case INVALID_PROJECT_CONFIGURATION_PLUGIN_VALUE_NOT_PERMITTED:
|
||||
case INVALID_PROJECT_CONFIGURATION_PLUGIN_VALUE_NOT_EDITABLE:
|
||||
case INVALID_PROJECT_CONFIGURATION_PARENT_PROJECT_NOT_FOUND:
|
||||
case INVALID_PROJECT_CONFIGURATION_ROOT_PROJECT_CANNOT_HAVE_PARENT:
|
||||
case SETTING_PARENT_PROJECT_ONLY_ALLOWED_BY_ADMIN:
|
||||
|
||||
@@ -880,18 +880,31 @@ public class ReceiveCommits {
|
||||
}
|
||||
|
||||
for (Entry<ProjectConfigEntry> e : pluginConfigEntries) {
|
||||
ProjectConfigEntry configEntry = e.getProvider().get();
|
||||
if (ProjectConfigEntry.Type.LIST.equals(configEntry.getType())) {
|
||||
PluginConfig pluginCfg = cfg.getPluginConfig(e.getPluginName());
|
||||
ProjectConfigEntry configEntry = e.getProvider().get();
|
||||
String value = pluginCfg.getString(e.getExportName());
|
||||
if (value != null && !configEntry.getPermittedValues().contains(value)) {
|
||||
String oldValue =
|
||||
projectControl.getProjectState().getConfig()
|
||||
.getPluginConfig(e.getPluginName())
|
||||
.getString(e.getExportName());
|
||||
|
||||
if ((value == null ? oldValue != null : !value.equals(oldValue)) &&
|
||||
!configEntry.isEditable(projectControl.getProjectState())) {
|
||||
reject(cmd, String.format(
|
||||
"invalid project configuration: Not allowed to set parameter"
|
||||
+ " '%s' of plugin '%s' on project '%s'.",
|
||||
e.getExportName(), e.getPluginName(), project.getName()));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ProjectConfigEntry.Type.LIST.equals(configEntry.getType())
|
||||
&& value != null && !configEntry.getPermittedValues().contains(value)) {
|
||||
reject(cmd, String.format(
|
||||
"invalid project configuration: The value '%s' is "
|
||||
+ "not permitted for parameter '%s' of plugin '%s'.",
|
||||
value, e.getExportName(), e.getPluginName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
reject(cmd, "invalid project configuration");
|
||||
log.error("User " + currentUser.getUserName()
|
||||
|
||||
@@ -145,16 +145,26 @@ public class MergeValidators {
|
||||
}
|
||||
|
||||
for (Entry<ProjectConfigEntry> e : pluginConfigEntries) {
|
||||
ProjectConfigEntry configEntry = e.getProvider().get();
|
||||
if (ProjectConfigEntry.Type.LIST.equals(configEntry.getType())) {
|
||||
PluginConfig pluginCfg = cfg.getPluginConfig(e.getPluginName());
|
||||
ProjectConfigEntry configEntry = e.getProvider().get();
|
||||
|
||||
String value = pluginCfg.getString(e.getExportName());
|
||||
if (value != null && !configEntry.getPermittedValues().contains(value)) {
|
||||
String oldValue = destProject.getConfig()
|
||||
.getPluginConfig(e.getPluginName())
|
||||
.getString(e.getExportName());
|
||||
|
||||
if ((value == null ? oldValue != null : !value.equals(oldValue)) &&
|
||||
!configEntry.isEditable(destProject)) {
|
||||
throw new MergeValidationException(CommitMergeStatus.
|
||||
INVALID_PROJECT_CONFIGURATION_PLUGIN_VALUE_NOT_EDITABLE);
|
||||
}
|
||||
|
||||
if (ProjectConfigEntry.Type.LIST.equals(configEntry.getType())
|
||||
&& value != null && !configEntry.getPermittedValues().contains(value)) {
|
||||
throw new MergeValidationException(CommitMergeStatus.
|
||||
INVALID_PROJECT_CONFIGURATION_PLUGIN_VALUE_NOT_PERMITTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ConfigInvalidException | IOException e) {
|
||||
throw new MergeValidationException(CommitMergeStatus.
|
||||
INVALID_PROJECT_CONFIGURATION);
|
||||
|
||||
@@ -132,14 +132,15 @@ public class ConfigInfo {
|
||||
PluginConfigFactory cfgFactory, AllProjectsNameProvider allProjects) {
|
||||
TreeMap<String, Map<String, ConfigParameterInfo>> pluginConfig = new TreeMap<>();
|
||||
for (Entry<ProjectConfigEntry> e : pluginConfigEntries) {
|
||||
ProjectConfigEntry configEntry = e.getProvider().get();
|
||||
PluginConfig cfg =
|
||||
cfgFactory.getFromProjectConfig(project, e.getPluginName());
|
||||
ProjectConfigEntry configEntry = e.getProvider().get();
|
||||
String configuredValue = cfg.getString(e.getExportName());
|
||||
ConfigParameterInfo p = new ConfigParameterInfo();
|
||||
p.displayName = configEntry.getDisplayName();
|
||||
p.type = configEntry.getType();
|
||||
p.permittedValues = configEntry.getPermittedValues();
|
||||
p.editable = configEntry.isEditable(project) ? true : null;
|
||||
if (configEntry.isInheritable()
|
||||
&& !allProjects.get().equals(project.getProject().getNameKey())) {
|
||||
PluginConfig cfgWithInheritance =
|
||||
@@ -194,6 +195,7 @@ public class ConfigInfo {
|
||||
public String displayName;
|
||||
public ProjectConfigEntry.Type type;
|
||||
public String value;
|
||||
public Boolean editable;
|
||||
public Boolean inheritable;
|
||||
public String configuredValue;
|
||||
public String inheritedValue;
|
||||
|
||||
@@ -148,7 +148,8 @@ public class PutConfig implements RestModifyView<ProjectResource, Input> {
|
||||
}
|
||||
|
||||
if (input.pluginConfigValues != null) {
|
||||
setPluginConfigValues(projectConfig, input.pluginConfigValues);
|
||||
setPluginConfigValues(rsrc.getControl().getProjectState(),
|
||||
projectConfig, input.pluginConfigValues);
|
||||
}
|
||||
|
||||
md.setMessage("Modified project settings\n");
|
||||
@@ -177,8 +178,8 @@ public class PutConfig implements RestModifyView<ProjectResource, Input> {
|
||||
}
|
||||
}
|
||||
|
||||
private void setPluginConfigValues(ProjectConfig projectConfig,
|
||||
Map<String, Map<String, String>> pluginConfigValues)
|
||||
private void setPluginConfigValues(ProjectState projectState,
|
||||
ProjectConfig projectConfig, Map<String, Map<String, String>> pluginConfigValues)
|
||||
throws BadRequestException {
|
||||
for (Entry<String, Map<String, String>> e : pluginConfigValues.entrySet()) {
|
||||
String pluginName = e.getKey();
|
||||
@@ -192,21 +193,27 @@ public class PutConfig implements RestModifyView<ProjectResource, Input> {
|
||||
"Parameter name '%s' must match '^[a-zA-Z0-9]+[a-zA-Z0-9-]*$'", v.getKey()));
|
||||
continue;
|
||||
}
|
||||
String oldValue = cfg.getString(v.getKey());
|
||||
if (v.getValue() != null) {
|
||||
if (!v.getValue().equals(oldValue)) {
|
||||
validateProjectConfigEntryIsEditable(projectConfigEntry,
|
||||
projectState, e.getKey(), pluginName);
|
||||
try {
|
||||
switch (projectConfigEntry.getType()) {
|
||||
case BOOLEAN:
|
||||
cfg.setBoolean(v.getKey(), Boolean.parseBoolean(v.getValue()));
|
||||
boolean newBooleanValue = Boolean.parseBoolean(v.getValue());
|
||||
cfg.setBoolean(v.getKey(), newBooleanValue);
|
||||
break;
|
||||
case INT:
|
||||
cfg.setInt(v.getKey(), Integer.parseInt(v.getValue()));
|
||||
int newIntValue = Integer.parseInt(v.getValue());
|
||||
cfg.setInt(v.getKey(), newIntValue);
|
||||
break;
|
||||
case LONG:
|
||||
cfg.setLong(v.getKey(), Long.parseLong(v.getValue()));
|
||||
long newLongValue = Long.parseLong(v.getValue());
|
||||
cfg.setLong(v.getKey(), newLongValue);
|
||||
break;
|
||||
case LIST:
|
||||
if (!projectConfigEntry.getPermittedValues()
|
||||
.contains(v.getValue())) {
|
||||
if (!projectConfigEntry.getPermittedValues().contains(v.getValue())) {
|
||||
throw new BadRequestException(String.format(
|
||||
"The value '%s' is not permitted for parameter '%s' of plugin '"
|
||||
+ pluginName + "'", v.getValue(), v.getKey()));
|
||||
@@ -224,9 +231,14 @@ public class PutConfig implements RestModifyView<ProjectResource, Input> {
|
||||
"The value '%s' of config parameter '%s' of plugin '%s' is invalid: %s",
|
||||
v.getValue(), v.getKey(), pluginName, ex.getMessage()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (oldValue != null) {
|
||||
validateProjectConfigEntryIsEditable(projectConfigEntry,
|
||||
projectState, e.getKey(), pluginName);
|
||||
cfg.unset(v.getKey());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new BadRequestException(String.format(
|
||||
"The config parameter '%s' of plugin '%s' does not exist.",
|
||||
@@ -236,6 +248,16 @@ public class PutConfig implements RestModifyView<ProjectResource, Input> {
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateProjectConfigEntryIsEditable(
|
||||
ProjectConfigEntry projectConfigEntry, ProjectState projectState,
|
||||
String parameterName, String pluginName) throws BadRequestException {
|
||||
if (!projectConfigEntry.isEditable(projectState)) {
|
||||
throw new BadRequestException(String.format(
|
||||
"Not allowed to set parameter '%s' of plugin '%s' on project '%s'.",
|
||||
parameterName, pluginName, projectState.getProject().getName()));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isValidParameterName(String name) {
|
||||
return CharMatcher.JAVA_LETTER_OR_DIGIT
|
||||
.or(CharMatcher.is('-'))
|
||||
|
||||
Reference in New Issue
Block a user