Merge remote-tracking branch stable-2.13'
* stable-2.13:
Get commentLink w/ association from project.config
Move the association policy to the plugin's config
Restore enforcement constraint by parent projects
Change-Id: I7073bdca41473cfe57f7dc253b8a952bcb016fc5
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfig.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfig.java
index 581ef99..17d31a1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/its/ItsConfig.java
@@ -14,9 +14,14 @@
package com.googlesource.gerrit.plugins.its.base.its;
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
import com.google.gerrit.common.data.RefConfigSection;
import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.extensions.api.projects.CommentLinkInfo;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.reviewdb.client.Project.NameKey;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.PluginConfig;
import com.google.gerrit.server.config.PluginConfigFactory;
@@ -28,6 +33,7 @@
import com.google.gerrit.server.events.Event;
import com.google.gerrit.server.events.PatchSetCreatedEvent;
import com.google.gerrit.server.events.RefUpdatedEvent;
+import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.project.RefPatternMatcher;
@@ -39,10 +45,14 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Collections;
+import java.util.List;
import java.util.regex.Pattern;
public class ItsConfig {
+ private static final String PLUGIN = "plugin";
+
private static final Logger log = LoggerFactory.getLogger(ItsConfig.class);
private final String pluginName;
@@ -50,6 +60,18 @@
private final PluginConfigFactory pluginCfgFactory;
private final Config gerritConfig;
+ private static final ThreadLocal<Project.NameKey> currentProjectName =
+ new ThreadLocal<Project.NameKey>() {
+ @Override
+ protected Project.NameKey initialValue() {
+ return null;
+ }
+ };
+
+ public static void setCurrentProjectName(Project.NameKey projectName) {
+ currentProjectName.set(projectName);
+ }
+
@Inject
public ItsConfig(@PluginName String pluginName, ProjectCache projectCache,
PluginConfigFactory pluginCfgFactory, @GerritServerConfig Config gerritConfig) {
@@ -97,13 +119,8 @@
return false;
}
- for (ProjectState parentState : projectState.treeInOrder()) {
- PluginConfig parentCfg =
- pluginCfgFactory.getFromProjectConfig(parentState, pluginName);
- if (!"false".equals(parentCfg.getString("enabled"))
- && isEnabledForBranch(parentState, refName)) {
- return true;
- }
+ if(isEnforcedByAnyParentProject(refName, projectState)) {
+ return true;
}
return !"false".equals(pluginCfgFactory.getFromProjectConfigWithInheritance(
@@ -111,6 +128,19 @@
&& isEnabledForBranch(projectState, refName);
}
+ private boolean isEnforcedByAnyParentProject(String refName,
+ ProjectState projectState) {
+ for (ProjectState parentState : projectState.treeInOrder()) {
+ PluginConfig parentCfg =
+ pluginCfgFactory.getFromProjectConfig(parentState, pluginName);
+ if ("enforced".equals(parentCfg.getString("enabled", "false"))
+ && isEnabledForBranch(parentState, refName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private boolean isEnabledForBranch(ProjectState project, String refName) {
String[] refPatterns =
pluginCfgFactory.getFromProjectConfigWithInheritance(project,
@@ -140,7 +170,7 @@
public String getCommentLinkName() {
String ret;
- ret = gerritConfig.getString(pluginName, null, "commentlink");
+ ret = getPluginConfigString("commentlink");
if (ret == null) {
ret = pluginName;
}
@@ -158,9 +188,26 @@
* to match issue ids.
*/
public Pattern getIssuePattern() {
+ String match =
+ FluentIterable
+ .from(getCommitLinkInfo(getCommentLinkName()))
+ .filter(new Predicate<CommentLinkInfo>() {
+ @Override
+ public boolean apply(CommentLinkInfo input) {
+ return input.match != null && !input.match.trim().isEmpty();
+ }
+ })
+ .transform(new Function<CommentLinkInfo, String>() {
+ @Override
+ public String apply(CommentLinkInfo input) {
+ return input.match;
+ }
+ })
+ .last()
+ .or(gerritConfig.getString("commentlink", getCommentLinkName(),
+ "match"));
Pattern ret = null;
- String match = gerritConfig.getString("commentlink",
- getCommentLinkName(), "match");
+
if (match != null) {
ret = Pattern.compile(match);
}
@@ -178,7 +225,7 @@
public int getIssuePatternGroupIndex() {
Pattern pattern = getIssuePattern();
int groupCount = pattern.matcher("").groupCount();
- int index = gerritConfig.getInt(pluginName, "commentlinkGroupIndex", 1);
+ int index = getPluginConfigInt("commentlinkGroupIndex", 1);
if (index < 0 || index > groupCount) {
index = (groupCount == 0 ? 0 : 1);
}
@@ -187,10 +234,59 @@
/**
* Gets how necessary it is to associate commits with issues
+ *
* @return policy on how necessary association with issues is
*/
public ItsAssociationPolicy getItsAssociationPolicy() {
- return gerritConfig.getEnum("commentlink", getCommentLinkName(),
- "association", ItsAssociationPolicy.OPTIONAL);
+ ItsAssociationPolicy legacyItsAssociationPolicy =
+ gerritConfig.getEnum("commentLink", getCommentLinkName(),
+ "association", ItsAssociationPolicy.OPTIONAL);
+
+ return getPluginConfigEnum("association", legacyItsAssociationPolicy);
+ }
+
+ private String getPluginConfigString(String key) {
+ return getCurrentPluginConfig().getString(key,
+ gerritConfig.getString(PLUGIN, pluginName, key));
+ }
+
+ private int getPluginConfigInt(String key, int defaultValue) {
+ return getCurrentPluginConfig().getInt(key,
+ gerritConfig.getInt(PLUGIN, pluginName, key, defaultValue));
+ }
+
+ private <T extends Enum<?>> T getPluginConfigEnum(String key, T defaultValue) {
+ return getCurrentPluginConfig().getEnum(key,
+ gerritConfig.getEnum(PLUGIN, pluginName, key, defaultValue));
+ }
+
+ private PluginConfig getCurrentPluginConfig() {
+ NameKey projectName = currentProjectName.get();
+ if (projectName != null) {
+ try {
+ return pluginCfgFactory.getFromProjectConfigWithInheritance(
+ projectName, pluginName);
+ } catch (NoSuchProjectException e) {
+ log.error("Cannot access " + projectName + " configuration for plugin "
+ + pluginName, e);
+ }
+ }
+ return new PluginConfig(pluginName, new Config());
+ }
+
+ private List<CommentLinkInfo> getCommitLinkInfo(final String commentLinkName) {
+ NameKey projectName = currentProjectName.get();
+ if (projectName != null) {
+ List<CommentLinkInfo> commentLinks =
+ projectCache.get(projectName).getCommentLinks();
+ return FluentIterable.from(commentLinks)
+ .filter(new Predicate<CommentLinkInfo>() {
+ @Override
+ public boolean apply(CommentLinkInfo input) {
+ return input.name.equals(commentLinkName);
+ }
+ }).toList();
+ }
+ return Collections.emptyList();
}
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/its/base/validation/ItsValidateComment.java b/src/main/java/com/googlesource/gerrit/plugins/its/base/validation/ItsValidateComment.java
index 07ae258..3d8816f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/its/base/validation/ItsValidateComment.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/its/base/validation/ItsValidateComment.java
@@ -143,6 +143,8 @@
@Override
public List<CommitValidationMessage> onCommitReceived(
CommitReceivedEvent receiveEvent) throws CommitValidationException {
+ ItsConfig.setCurrentProjectName(receiveEvent.getProjectNameKey());
+
if (itsConfig.isEnabled(receiveEvent.getProjectNameKey(), receiveEvent.getRefName())) {
return validCommit(receiveEvent.commit);
}
diff --git a/src/main/resources/Documentation/config-common.md b/src/main/resources/Documentation/config-common.md
index 02565e3..d53b0c6 100644
--- a/src/main/resources/Documentation/config-common.md
+++ b/src/main/resources/Documentation/config-common.md
@@ -26,7 +26,6 @@
[commentlink "@PLUGIN@"]
match = [Bb][Uu][Gg][ ]*([1-9][0-9]*)
html = "<a href=\"http://my.issure.tracker.example.org/show_bug.cgi?id=$1\">(bug $1)</a>"
- association = SUGGESTED
```
in `etc/gerrit.config` would allow to match the issues `4711`, `167`
@@ -36,7 +35,9 @@
Sample commit message relating to bug 4711, and bug 167.
```
-By setting a `commentlink`'s `association` (see above's example), it
+[upstream-comment-link-doc]: ../../../Documentation/config-gerrit.html#commentlink
+
+By setting a `commentlink`'s `association` on the plugin's @PLUGIN@ configuration, it
is possible to require commits to carry ITS references; the following
values are supported (default is `OPTIONAL`):
@@ -52,9 +53,24 @@
: Bug-ids are liked when found in the git commit message, no warning is
displayed otherwise.
-[upstream-comment-link-doc]: ../../../Documentation/config-gerrit.html#commentlink
+Example:
+```
+[plugin "@PLUGIN@"]
+ association = MANDATORY
+```
+in `etc/gerrit.config` would accept only commits that contain a valid issue id
+in the comment, matching the commentLink defined previously.
+
+NOTE: Historically the association has been defined in the Gerrit's commentLink
+section. That setting is deprecated but still supported for the current release.
+You are encouraged to move the association policy to the plugin section, the
+commentLink.association will be discontinued in the next major release.
+
+The association can be overridden at project level in the project.config
+using the same syntax used in the gerrit.config. Project's hierarchy will be respected
+when evaluating the links configuration and association policy.
[enabling-its-integration]: #enabling-its-integration
<a name="enabling-its-integration">Enabling ITS integration</a>