Merge "Support project level plugin configuration"

This commit is contained in:
Saša Živkov
2013-09-20 13:23:43 +00:00
committed by Gerrit Code Review
3 changed files with 99 additions and 1 deletions

View File

@@ -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
-------------------------

View File

@@ -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);
}
}

View File

@@ -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);