Merge "Support project level plugin configuration"
This commit is contained in:
@@ -366,6 +366,45 @@ plugin to parse the `gerrit.config` file on its own:
|
||||
.getString("language", "English");
|
||||
----
|
||||
|
||||
[[project-specific-configuration]]
|
||||
Project Specific Configuration
|
||||
------------------------------
|
||||
|
||||
In Gerrit, project specific configuration is stored in the project's
|
||||
`project.config` file on the `refs/meta/config` branch. If a plugin
|
||||
needs configuration on project level (e.g. to enable its functionality
|
||||
only for certain projects), this configuration should be stored in a
|
||||
`plugin` subsection in the project's `project.config` file.
|
||||
|
||||
To avoid conflicts with other plugins, it is recommended that plugins
|
||||
only use the `plugin` subsection with their own name. For example the
|
||||
`helloworld` plugin should store its configuration in the
|
||||
`plugin.helloworld` subsection:
|
||||
|
||||
----
|
||||
[plugin "helloworld"]
|
||||
enabled = true
|
||||
----
|
||||
|
||||
Via the `com.google.gerrit.server.config.PluginConfigFactory` class a
|
||||
plugin can easily access its project specific configuration and there
|
||||
is no need for a plugin to parse the `project.config` file on its own:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Inject
|
||||
private com.google.gerrit.server.config.PluginConfigFactory cfg;
|
||||
|
||||
...
|
||||
|
||||
boolean enabled = cfg.get(project, "helloworld")
|
||||
.getBoolean("enabled", false);
|
||||
----
|
||||
|
||||
Project owners can edit the project configuration by fetching the
|
||||
`refs/meta/config` branch, editing the `project.config` file and
|
||||
pushing the commit back.
|
||||
|
||||
[[capabilities]]
|
||||
Plugin Owned Capabilities
|
||||
-------------------------
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
|
||||
package com.google.gerrit.server.config;
|
||||
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.server.project.NoSuchProjectException;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.project.ProjectState;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
@@ -22,13 +26,24 @@ import org.eclipse.jgit.lib.Config;
|
||||
@Singleton
|
||||
public class PluginConfigFactory {
|
||||
private final Config cfg;
|
||||
private final ProjectCache projectCache;
|
||||
|
||||
@Inject
|
||||
PluginConfigFactory(@GerritServerConfig Config cfg) {
|
||||
PluginConfigFactory(@GerritServerConfig Config cfg, ProjectCache projectCache) {
|
||||
this.cfg = cfg;
|
||||
this.projectCache = projectCache;
|
||||
}
|
||||
|
||||
public PluginConfig get(String pluginName) {
|
||||
return new PluginConfig(pluginName, cfg);
|
||||
}
|
||||
|
||||
public PluginConfig get(Project.NameKey projectName, String pluginName)
|
||||
throws NoSuchProjectException {
|
||||
ProjectState projectState = projectCache.get(projectName);
|
||||
if (projectState == null) {
|
||||
throw new NoSuchProjectException(projectName);
|
||||
}
|
||||
return projectState.getConfig().getPluginConfig(pluginName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.google.gerrit.reviewdb.client.Project.State;
|
||||
import com.google.gerrit.reviewdb.client.Project.SubmitType;
|
||||
import com.google.gerrit.server.account.GroupBackend;
|
||||
import com.google.gerrit.server.config.ConfigUtil;
|
||||
import com.google.gerrit.server.config.PluginConfig;
|
||||
import com.google.gerrit.server.mail.Address;
|
||||
import com.google.gerrit.server.project.CommentLinkInfo;
|
||||
|
||||
@@ -67,6 +68,7 @@ import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
@@ -132,6 +134,8 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
private static final Set<String> LABEL_FUNCTIONS = ImmutableSet.of(
|
||||
"MaxWithBlock", "AnyWithBlock", "MaxNoBlock", "NoBlock", "NoOp");
|
||||
|
||||
private static final String PLUGIN = "plugin";
|
||||
|
||||
private static final SubmitType defaultSubmitAction =
|
||||
SubmitType.MERGE_IF_NECESSARY;
|
||||
private static final State defaultStateValue =
|
||||
@@ -149,6 +153,7 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
private List<ValidationError> validationErrors;
|
||||
private ObjectId rulesId;
|
||||
private long maxObjectSizeLimit;
|
||||
private Map<String, Config> pluginConfigs;
|
||||
|
||||
public static ProjectConfig read(MetaDataUpdate update) throws IOException,
|
||||
ConfigInvalidException {
|
||||
@@ -399,6 +404,7 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
loadNotifySections(rc, groupsByName);
|
||||
loadLabelSections(rc);
|
||||
loadCommentLinkSections(rc);
|
||||
loadPluginSections(rc);
|
||||
|
||||
maxObjectSizeLimit = rc.getLong(RECEIVE, null, KEY_MAX_OBJECT_SIZE_LIMIT, 0);
|
||||
}
|
||||
@@ -683,6 +689,27 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
commentLinkSections = ImmutableList.copyOf(commentLinkSections);
|
||||
}
|
||||
|
||||
private void loadPluginSections(Config rc) {
|
||||
pluginConfigs = Maps.newHashMap();
|
||||
for (String plugin : rc.getSubsections(PLUGIN)) {
|
||||
Config pluginConfig = new Config();
|
||||
pluginConfigs.put(plugin, pluginConfig);
|
||||
for (String name : rc.getNames(PLUGIN, plugin)) {
|
||||
pluginConfig.setStringList(PLUGIN, plugin, name,
|
||||
Arrays.asList(rc.getStringList(PLUGIN, plugin, name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PluginConfig getPluginConfig(String pluginName) {
|
||||
Config pluginConfig = pluginConfigs.get(pluginName);
|
||||
if (pluginConfig == null) {
|
||||
pluginConfig = new Config();
|
||||
pluginConfigs.put(pluginName, pluginConfig);
|
||||
}
|
||||
return new PluginConfig(pluginName, pluginConfig);
|
||||
}
|
||||
|
||||
private Map<String, GroupReference> readGroupList() throws IOException {
|
||||
groupsByUUID = new HashMap<AccountGroup.UUID, GroupReference>();
|
||||
Map<String, GroupReference> groupsByName =
|
||||
@@ -748,6 +775,7 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
saveNotifySections(rc, keepGroups);
|
||||
groupsByUUID.keySet().retainAll(keepGroups);
|
||||
saveLabelSections(rc);
|
||||
savePluginSections(rc);
|
||||
|
||||
saveConfig(PROJECT_CONFIG, rc);
|
||||
saveGroupList();
|
||||
@@ -997,6 +1025,22 @@ public class ProjectConfig extends VersionedMetaData {
|
||||
}
|
||||
}
|
||||
|
||||
private void savePluginSections(Config rc) {
|
||||
List<String> existing = Lists.newArrayList(rc.getSubsections(PLUGIN));
|
||||
for (String name : existing) {
|
||||
rc.unsetSection(PLUGIN, name);
|
||||
}
|
||||
|
||||
for (Entry<String, Config> e : pluginConfigs.entrySet()) {
|
||||
String plugin = e.getKey();
|
||||
Config pluginConfig = e.getValue();
|
||||
for (String name : pluginConfig.getNames(PLUGIN, plugin)) {
|
||||
rc.setStringList(PLUGIN, plugin, name,
|
||||
Arrays.asList(pluginConfig.getStringList(PLUGIN, plugin, name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveGroupList() throws IOException {
|
||||
if (groupsByUUID.isEmpty()) {
|
||||
saveFile(GROUP_LIST, null);
|
||||
|
||||
Reference in New Issue
Block a user