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>