Merge "Allow to disable the validation of code owner config files per branch"
diff --git a/java/com/google/gerrit/plugins/codeowners/acceptance/AbstractCodeOwnersTest.java b/java/com/google/gerrit/plugins/codeowners/acceptance/AbstractCodeOwnersTest.java
index a06525d..c85c506 100644
--- a/java/com/google/gerrit/plugins/codeowners/acceptance/AbstractCodeOwnersTest.java
+++ b/java/com/google/gerrit/plugins/codeowners/acceptance/AbstractCodeOwnersTest.java
@@ -168,7 +168,7 @@
CodeOwnersPluginConfiguration.SECTION_CODE_OWNERS, subsection, key, values));
}
- private void updateCodeOwnersConfig(Project.NameKey project, Consumer<Config> configUpdater)
+ protected void updateCodeOwnersConfig(Project.NameKey project, Consumer<Config> configUpdater)
throws Exception {
Config codeOwnersConfig = new Config();
configUpdater.accept(codeOwnersConfig);
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigSnapshot.java b/java/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigSnapshot.java
index 72747a6..4595fff 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigSnapshot.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigSnapshot.java
@@ -131,14 +131,44 @@
return generalConfig.getRejectNonResolvableImports(projectName, pluginConfig);
}
- /** Whether code owner configs should be validated when a commit is received. */
- public CodeOwnerConfigValidationPolicy getCodeOwnerConfigValidationPolicyForCommitReceived() {
+ /**
+ * Whether code owner configs should be validated when a commit is received.
+ *
+ * @param branchName the branch for which it should be checked whether code owner configs should
+ * be validated on commit received
+ */
+ public CodeOwnerConfigValidationPolicy getCodeOwnerConfigValidationPolicyForCommitReceived(
+ String branchName) {
+ requireNonNull(branchName, "branchName");
+
+ Optional<CodeOwnerConfigValidationPolicy> branchSpecificPolicy =
+ generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceivedForBranch(
+ BranchNameKey.create(projectName, branchName), pluginConfig);
+ if (branchSpecificPolicy.isPresent()) {
+ return branchSpecificPolicy.get();
+ }
+
return generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceived(
projectName, pluginConfig);
}
- /** Whether code owner configs should be validated when a change is submitted. */
- public CodeOwnerConfigValidationPolicy getCodeOwnerConfigValidationPolicyForSubmit() {
+ /**
+ * Whether code owner configs should be validated when a change is submitted.
+ *
+ * @param branchName the branch for which it should be checked whether code owner configs should
+ * be validated on submit
+ */
+ public CodeOwnerConfigValidationPolicy getCodeOwnerConfigValidationPolicyForSubmit(
+ String branchName) {
+ requireNonNull(branchName, "branchName");
+
+ Optional<CodeOwnerConfigValidationPolicy> branchSpecificPolicy =
+ generalConfig.getCodeOwnerConfigValidationPolicyForSubmitForBranch(
+ BranchNameKey.create(projectName, branchName), pluginConfig);
+ if (branchSpecificPolicy.isPresent()) {
+ return branchSpecificPolicy.get();
+ }
+
return generalConfig.getCodeOwnerConfigValidationPolicyForSubmit(projectName, pluginConfig);
}
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/config/GeneralConfig.java b/java/com/google/gerrit/plugins/codeowners/backend/config/GeneralConfig.java
index 3558582..e0f38cb 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/config/GeneralConfig.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/config/GeneralConfig.java
@@ -22,6 +22,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.annotations.PluginName;
import com.google.gerrit.plugins.codeowners.backend.CodeOwnerReference;
@@ -33,12 +34,14 @@
import com.google.gerrit.server.config.PluginConfigFactory;
import com.google.gerrit.server.git.validators.CommitValidationMessage;
import com.google.gerrit.server.git.validators.ValidationMessage;
+import com.google.gerrit.server.project.RefPatternMatcher;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
+import java.util.regex.PatternSyntaxException;
import org.eclipse.jgit.lib.Config;
/**
@@ -56,6 +59,8 @@
public class GeneralConfig {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+ public static final String SECTION_VALIDATION = "validation";
+
public static final String KEY_FILE_EXTENSION = "fileExtension";
public static final String KEY_READ_ONLY = "readOnly";
public static final String KEY_EXEMPT_PURE_REVERTS = "exemptPureReverts";
@@ -388,14 +393,16 @@
}
/**
- * Gets the enable validation on commit received configuration from the given plugin config with
- * fallback to {@code gerrit.config} and default to {@code true}.
+ * Gets the enable validation on commit received configuration from the given plugin config for
+ * the specified project with fallback to {@code gerrit.config} and default to {@code true}.
*
* <p>The enable validation on commit received controls whether code owner config files should be
* validated when a commit is received.
*
+ * @param project the project for which the enable validation on commit received configuration
+ * should be read
* @param pluginConfig the plugin config from which the enable validation on commit received
- * configuration should be read.
+ * configuration should be read
* @return whether code owner config files should be validated when a commit is received
*/
CodeOwnerConfigValidationPolicy getCodeOwnerConfigValidationPolicyForCommitReceived(
@@ -405,14 +412,40 @@
}
/**
- * Gets the enable validation on submit configuration from the given plugin config with fallback
- * to {@code gerrit.config} and default to {@code true}.
+ * Gets the enable validation on commit received configuration from the given plugin config for
+ * the specified branch.
+ *
+ * <p>If multiple branch-specific configurations match the specified branch, it is undefined which
+ * of the matching branch configurations takes precedence.
+ *
+ * <p>The enable validation on commit received controls whether code owner config files should be
+ * validated when a commit is received.
+ *
+ * @param branchNameKey the branch and project for which the enable validation on commit received
+ * configuration should be read
+ * @param pluginConfig the plugin config from which the enable validation on commit received
+ * configuration should be read
+ * @return the enable validation on commit received configuration that is configured for the
+ * branch, {@link Optional#empty()} if no branch specific configuration exists
+ */
+ Optional<CodeOwnerConfigValidationPolicy>
+ getCodeOwnerConfigValidationPolicyForCommitReceivedForBranch(
+ BranchNameKey branchNameKey, Config pluginConfig) {
+ return getCodeOwnerConfigValidationPolicyForBranch(
+ KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED, branchNameKey, pluginConfig);
+ }
+
+ /**
+ * Gets the enable validation on submit configuration from the given plugin config for the
+ * specified project with fallback to {@code gerrit.config} and default to {@code true}.
*
* <p>The enable validation on submit controls whether code owner config files should be validated
* when a change is submitted.
*
+ * @param project the project for which the enable validation on submit configuration should be
+ * read
* @param pluginConfig the plugin config from which the enable validation on submit configuration
- * should be read.
+ * should be read
* @return whether code owner config files should be validated when a change is submitted
*/
CodeOwnerConfigValidationPolicy getCodeOwnerConfigValidationPolicyForSubmit(
@@ -421,6 +454,45 @@
KEY_ENABLE_VALIDATION_ON_SUBMIT, project, pluginConfig);
}
+ /**
+ * Gets the enable validation on submit configuration from the given plugin config for the
+ * specified branch.
+ *
+ * <p>If multiple branch-specific configurations match the specified branch, it is undefined which
+ * of the matching branch configurations takes precedence.
+ *
+ * <p>The enable validation on submit controls whether code owner config files should be validated
+ * when a change is submitted.
+ *
+ * @param branchNameKey the branch and project for which the enable validation on submit
+ * configuration should be read
+ * @param pluginConfig the plugin config from which the enable validation on submit configuration
+ * should be read
+ * @return the enable validation on submit configuration that is configured for the branch, {@link
+ * Optional#empty()} if no branch specific configuration exists
+ */
+ Optional<CodeOwnerConfigValidationPolicy> getCodeOwnerConfigValidationPolicyForSubmitForBranch(
+ BranchNameKey branchNameKey, Config pluginConfig) {
+ return getCodeOwnerConfigValidationPolicyForBranch(
+ KEY_ENABLE_VALIDATION_ON_SUBMIT, branchNameKey, pluginConfig);
+ }
+
+ private Optional<CodeOwnerConfigValidationPolicy> getCodeOwnerConfigValidationPolicyForBranch(
+ String key, BranchNameKey branchNameKey, Config pluginConfig) {
+ requireNonNull(key, "key");
+ requireNonNull(branchNameKey, "branchNameKey");
+ requireNonNull(pluginConfig, "pluginConfig");
+
+ Optional<String> validationSectionForBranch =
+ getValidationSectionForBranch(branchNameKey, pluginConfig);
+ if (!validationSectionForBranch.isPresent()) {
+ return Optional.empty();
+ }
+
+ return getCodeOwnerConfigValidationPolicyForBranch(
+ validationSectionForBranch.get(), key, branchNameKey.project(), pluginConfig);
+ }
+
private CodeOwnerConfigValidationPolicy getCodeOwnerConfigValidationPolicy(
String key, Project.NameKey project, Config pluginConfig) {
requireNonNull(key, "key");
@@ -459,6 +531,76 @@
}
}
+ private Optional<String> getValidationSectionForBranch(
+ BranchNameKey branchNameKey, Config pluginConfig) {
+ ImmutableSet<String> matchingValidationSubsections =
+ pluginConfig.getSubsections(SECTION_VALIDATION).stream()
+ .filter(
+ refPattern -> {
+ try {
+ return RefPatternMatcher.getMatcher(refPattern)
+ .match(branchNameKey.branch(), /* user= */ null);
+ } catch (PatternSyntaxException e) {
+ logger.atWarning().withCause(e).log(
+ "invalid ref pattern %s for subsection %s.%s in %s.config of project %s",
+ refPattern,
+ SECTION_VALIDATION,
+ refPattern,
+ pluginName,
+ branchNameKey.project());
+ return false;
+ }
+ })
+ .collect(toImmutableSet());
+
+ if (matchingValidationSubsections.isEmpty()) {
+ return Optional.empty();
+ }
+
+ String matchingValidationSubsection = matchingValidationSubsections.asList().get(0);
+ if (matchingValidationSubsections.size() > 1) {
+ logger.atWarning().log(
+ "branch %s matches multiple %s subsections in %.config of project %s: %s,"
+ + " subsection %s takes precedence",
+ branchNameKey.branch(),
+ SECTION_VALIDATION,
+ pluginName,
+ branchNameKey.project(),
+ matchingValidationSubsections,
+ matchingValidationSubsection);
+ }
+ return Optional.of(matchingValidationSubsection);
+ }
+
+ private Optional<CodeOwnerConfigValidationPolicy> getCodeOwnerConfigValidationPolicyForBranch(
+ String branchSubsection, String key, Project.NameKey project, Config pluginConfig) {
+ requireNonNull(branchSubsection, "branchSubsection");
+ requireNonNull(key, "key");
+ requireNonNull(project, "project");
+ requireNonNull(pluginConfig, "pluginConfig");
+
+ String codeOwnerConfigValidationPolicyString =
+ pluginConfig.getString(SECTION_VALIDATION, branchSubsection, key);
+ if (codeOwnerConfigValidationPolicyString != null) {
+ try {
+ return Optional.of(
+ pluginConfig.getEnum(
+ SECTION_VALIDATION, branchSubsection, key, CodeOwnerConfigValidationPolicy.TRUE));
+ } catch (IllegalArgumentException e) {
+ logger.atWarning().withCause(e).log(
+ "Ignoring invalid value %s for the code owner config validation policy in '%s.config'"
+ + " of project %s (parameter %s.%s.%s). Falling back to project-level setting.",
+ codeOwnerConfigValidationPolicyString,
+ pluginName,
+ project.get(),
+ SECTION_VALIDATION,
+ branchSubsection,
+ key);
+ }
+ }
+ return Optional.empty();
+ }
+
/**
* Gets the merge commit strategy from the given plugin config with fallback to {@code
* gerrit.config}.
diff --git a/java/com/google/gerrit/plugins/codeowners/validation/CodeOwnerConfigValidator.java b/java/com/google/gerrit/plugins/codeowners/validation/CodeOwnerConfigValidator.java
index 3f79135..4f03274 100644
--- a/java/com/google/gerrit/plugins/codeowners/validation/CodeOwnerConfigValidator.java
+++ b/java/com/google/gerrit/plugins/codeowners/validation/CodeOwnerConfigValidator.java
@@ -177,7 +177,7 @@
CodeOwnerConfigValidationPolicy codeOwnerConfigValidationPolicy =
codeOwnersPluginConfiguration
.getProjectConfig(receiveEvent.getProjectNameKey())
- .getCodeOwnerConfigValidationPolicyForCommitReceived();
+ .getCodeOwnerConfigValidationPolicyForCommitReceived(receiveEvent.refName);
logger.atFine().log("codeOwnerConfigValidationPolicy = %s", codeOwnerConfigValidationPolicy);
Optional<ValidationResult> validationResult;
if (!codeOwnerConfigValidationPolicy.runValidation()) {
@@ -247,7 +247,7 @@
CodeOwnerConfigValidationPolicy codeOwnerConfigValidationPolicy =
codeOwnersPluginConfiguration
.getProjectConfig(branchNameKey.project())
- .getCodeOwnerConfigValidationPolicyForSubmit();
+ .getCodeOwnerConfigValidationPolicyForSubmit(branchNameKey.branch());
logger.atFine().log("codeOwnerConfigValidationPolicy = %s", codeOwnerConfigValidationPolicy);
Optional<ValidationResult> validationResult;
if (!codeOwnerConfigValidationPolicy.runValidation()) {
diff --git a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnerConfigValidatorIT.java b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnerConfigValidatorIT.java
index 3465717..b501277 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnerConfigValidatorIT.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnerConfigValidatorIT.java
@@ -53,10 +53,12 @@
import com.google.gerrit.plugins.codeowners.backend.CodeOwnerSet;
import com.google.gerrit.plugins.codeowners.backend.PathExpressionMatcher;
import com.google.gerrit.plugins.codeowners.backend.config.BackendConfig;
+import com.google.gerrit.plugins.codeowners.backend.config.GeneralConfig;
import com.google.gerrit.plugins.codeowners.backend.findowners.FindOwnersBackend;
import com.google.gerrit.plugins.codeowners.backend.findowners.FindOwnersCodeOwnerConfigParser;
import com.google.gerrit.plugins.codeowners.backend.proto.ProtoBackend;
import com.google.gerrit.plugins.codeowners.backend.proto.ProtoCodeOwnerConfigParser;
+import com.google.gerrit.plugins.codeowners.common.CodeOwnerConfigValidationPolicy;
import com.google.gerrit.server.IdentifiedUser;
import com.google.inject.Inject;
import com.google.inject.Key;
@@ -1968,6 +1970,43 @@
}
}
+ @Test
+ public void disableValidationForBranch() throws Exception {
+ setAsDefaultCodeOwners(admin);
+
+ // Disable the validation for the master branch.
+ updateCodeOwnersConfig(
+ project,
+ codeOwnersConfig -> {
+ codeOwnersConfig.setString(
+ GeneralConfig.SECTION_VALIDATION,
+ "refs/heads/master",
+ GeneralConfig.KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED,
+ CodeOwnerConfigValidationPolicy.FALSE.name());
+ codeOwnersConfig.setString(
+ GeneralConfig.SECTION_VALIDATION,
+ "refs/heads/master",
+ GeneralConfig.KEY_ENABLE_VALIDATION_ON_SUBMIT,
+ CodeOwnerConfigValidationPolicy.FALSE.name());
+ });
+
+ PushOneCommit.Result r =
+ createChange(
+ "Add code owners",
+ codeOwnerConfigOperations
+ .codeOwnerConfig(createCodeOwnerConfigKey("/"))
+ .getJGitFilePath(),
+ "INVALID");
+ assertOkWithHints(
+ r,
+ "skipping validation of code owner config files",
+ "code owners config validation is disabled");
+
+ approve(r.getChangeId());
+ gApi.changes().id(r.getChangeId()).current().submit();
+ assertThat(gApi.changes().id(r.getChangeId()).get().status).isEqualTo(ChangeStatus.MERGED);
+ }
+
private CodeOwnerConfig createCodeOwnerConfigWithImport(
CodeOwnerConfig.Key keyOfImportingCodeOwnerConfig,
CodeOwnerConfigImportType importType,
diff --git a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/PutCodeOwnerProjectConfigIT.java b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/PutCodeOwnerProjectConfigIT.java
index 655b45e..50114fe 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/PutCodeOwnerProjectConfigIT.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/PutCodeOwnerProjectConfigIT.java
@@ -467,7 +467,7 @@
assertThat(
codeOwnersPluginConfiguration
.getProjectConfig(project)
- .getCodeOwnerConfigValidationPolicyForCommitReceived())
+ .getCodeOwnerConfigValidationPolicyForCommitReceived("master"))
.isEqualTo(CodeOwnerConfigValidationPolicy.TRUE);
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
@@ -476,7 +476,7 @@
assertThat(
codeOwnersPluginConfiguration
.getProjectConfig(project)
- .getCodeOwnerConfigValidationPolicyForCommitReceived())
+ .getCodeOwnerConfigValidationPolicyForCommitReceived("master"))
.isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
input.enableValidationOnCommitReceived = CodeOwnerConfigValidationPolicy.TRUE;
@@ -484,7 +484,7 @@
assertThat(
codeOwnersPluginConfiguration
.getProjectConfig(project)
- .getCodeOwnerConfigValidationPolicyForCommitReceived())
+ .getCodeOwnerConfigValidationPolicyForCommitReceived("master"))
.isEqualTo(CodeOwnerConfigValidationPolicy.TRUE);
}
@@ -493,7 +493,7 @@
assertThat(
codeOwnersPluginConfiguration
.getProjectConfig(project)
- .getCodeOwnerConfigValidationPolicyForSubmit())
+ .getCodeOwnerConfigValidationPolicyForSubmit("master"))
.isEqualTo(CodeOwnerConfigValidationPolicy.TRUE);
CodeOwnerProjectConfigInput input = new CodeOwnerProjectConfigInput();
@@ -502,7 +502,7 @@
assertThat(
codeOwnersPluginConfiguration
.getProjectConfig(project)
- .getCodeOwnerConfigValidationPolicyForSubmit())
+ .getCodeOwnerConfigValidationPolicyForSubmit("master"))
.isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
input.enableValidationOnSubmit = CodeOwnerConfigValidationPolicy.TRUE;
@@ -510,7 +510,7 @@
assertThat(
codeOwnersPluginConfiguration
.getProjectConfig(project)
- .getCodeOwnerConfigValidationPolicyForSubmit())
+ .getCodeOwnerConfigValidationPolicyForSubmit("master"))
.isEqualTo(CodeOwnerConfigValidationPolicy.TRUE);
}
diff --git a/javatests/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigSnapshotTest.java b/javatests/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigSnapshotTest.java
index 529cbd4..eff2303 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigSnapshotTest.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigSnapshotTest.java
@@ -40,6 +40,7 @@
import com.google.gerrit.plugins.codeowners.backend.FallbackCodeOwners;
import com.google.gerrit.plugins.codeowners.backend.PathExpressionMatcher;
import com.google.gerrit.plugins.codeowners.backend.findowners.FindOwnersBackend;
+import com.google.gerrit.plugins.codeowners.common.CodeOwnerConfigValidationPolicy;
import com.google.gerrit.plugins.codeowners.common.MergeCommitStrategy;
import com.google.gerrit.server.IdentifiedUser;
import com.google.inject.Inject;
@@ -910,6 +911,196 @@
assertThat(cfgSnapshot().areImplicitApprovalsEnabled()).isFalse();
}
+ @Test
+ public void cannotGetCodeOwnerConfigValidationPolicyForCommitReceivedForNullBranch()
+ throws Exception {
+ NullPointerException npe =
+ assertThrows(
+ NullPointerException.class,
+ () ->
+ cfgSnapshot()
+ .getCodeOwnerConfigValidationPolicyForCommitReceived(/* branchName= */ null));
+ assertThat(npe).hasMessageThat().isEqualTo("branchName");
+ }
+
+ @Test
+ public void getCodeOwnerConfigValidationPolicyForCommitReceived_notConfigured() throws Exception {
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForCommitReceived("master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.TRUE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForCommitReceived("non-existing"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.TRUE);
+ }
+
+ @Test
+ public void getCodeOwnerConfigValidationPolicyForCommitReceived_configuredOnProjectLevel()
+ throws Exception {
+ configureEnableValidationOnCommitReceived(project, CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForCommitReceived("master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForCommitReceived("non-existing"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ }
+
+ @Test
+ public void getCodeOwnerConfigValidationPolicyForCommitReceived_configuredOnBranchLevel()
+ throws Exception {
+ configureEnableValidationOnCommitReceivedForBranch(
+ project, "refs/heads/master", CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForCommitReceived("master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(
+ cfgSnapshot().getCodeOwnerConfigValidationPolicyForCommitReceived("refs/heads/master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForCommitReceived("foo"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.TRUE);
+ }
+
+ @Test
+ public void getCodeOwnerConfigValidationPolicyForCommitReceived_branchLevelConfigTakesPrecedence()
+ throws Exception {
+ updateCodeOwnersConfig(
+ project,
+ codeOwnersConfig -> {
+ codeOwnersConfig.setEnum(
+ CodeOwnersPluginConfiguration.SECTION_CODE_OWNERS,
+ /* subsection= */ null,
+ GeneralConfig.KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED,
+ CodeOwnerConfigValidationPolicy.DRY_RUN);
+ codeOwnersConfig.setEnum(
+ GeneralConfig.SECTION_VALIDATION,
+ "refs/heads/master",
+ GeneralConfig.KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED,
+ CodeOwnerConfigValidationPolicy.FALSE);
+ });
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForCommitReceived("master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(
+ cfgSnapshot().getCodeOwnerConfigValidationPolicyForCommitReceived("refs/heads/master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForCommitReceived("foo"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.DRY_RUN);
+ }
+
+ @Test
+ public void
+ getCodeOwnerConfigValidationPolicyForCommitReceived_inheritedBranchLevelConfigTakesPrecedence()
+ throws Exception {
+ configureEnableValidationOnCommitReceivedForBranch(
+ allProjects, "refs/heads/master", CodeOwnerConfigValidationPolicy.FALSE);
+ configureEnableValidationOnCommitReceived(project, CodeOwnerConfigValidationPolicy.DRY_RUN);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForCommitReceived("master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(
+ cfgSnapshot().getCodeOwnerConfigValidationPolicyForCommitReceived("refs/heads/master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForCommitReceived("foo"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.DRY_RUN);
+ }
+
+ @Test
+ public void
+ getCodeOwnerConfigValidationPolicyForCommitReceived_inheritedBranchLevelCanBeOverridden()
+ throws Exception {
+ configureEnableValidationOnCommitReceivedForBranch(
+ allProjects, "refs/heads/master", CodeOwnerConfigValidationPolicy.FALSE);
+ configureEnableValidationOnCommitReceivedForBranch(
+ project, "refs/heads/master", CodeOwnerConfigValidationPolicy.DRY_RUN);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForCommitReceived("master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.DRY_RUN);
+ }
+
+ @Test
+ public void cannotGetCodeOwnerConfigValidationPolicyForSubmitForNullBranch() throws Exception {
+ NullPointerException npe =
+ assertThrows(
+ NullPointerException.class,
+ () ->
+ cfgSnapshot().getCodeOwnerConfigValidationPolicyForSubmit(/* branchName= */ null));
+ assertThat(npe).hasMessageThat().isEqualTo("branchName");
+ }
+
+ @Test
+ public void getCodeOwnerConfigValidationPolicyForSubmitd_notConfigured() throws Exception {
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForSubmit("master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.TRUE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForSubmit("non-existing"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.TRUE);
+ }
+
+ @Test
+ public void getCodeOwnerConfigValidationPolicyForSubmit_configuredOnProjectLevel()
+ throws Exception {
+ configureEnableValidationOnSubmit(project, CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForSubmit("master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForSubmit("non-existing"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ }
+
+ @Test
+ public void getCodeOwnerConfigValidationPolicyForSubmit_configuredOnBranchLevel()
+ throws Exception {
+ configureEnableValidationOnSubmitForBranch(
+ project, "refs/heads/master", CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForSubmit("master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForSubmit("refs/heads/master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForSubmit("foo"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.TRUE);
+ }
+
+ @Test
+ public void getCodeOwnerConfigValidationPolicyForSubmit_branchLevelConfigTakesPrecedence()
+ throws Exception {
+ updateCodeOwnersConfig(
+ project,
+ codeOwnersConfig -> {
+ codeOwnersConfig.setEnum(
+ CodeOwnersPluginConfiguration.SECTION_CODE_OWNERS,
+ /* subsection= */ null,
+ GeneralConfig.KEY_ENABLE_VALIDATION_ON_SUBMIT,
+ CodeOwnerConfigValidationPolicy.DRY_RUN);
+ codeOwnersConfig.setEnum(
+ GeneralConfig.SECTION_VALIDATION,
+ "refs/heads/master",
+ GeneralConfig.KEY_ENABLE_VALIDATION_ON_SUBMIT,
+ CodeOwnerConfigValidationPolicy.FALSE);
+ });
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForSubmit("master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForSubmit("refs/heads/master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForSubmit("foo"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.DRY_RUN);
+ }
+
+ @Test
+ public void
+ getCodeOwnerConfigValidationPolicyForSubmit_inheritedBranchLevelConfigTakesPrecedence()
+ throws Exception {
+ configureEnableValidationOnSubmitForBranch(
+ allProjects, "refs/heads/master", CodeOwnerConfigValidationPolicy.FALSE);
+ configureEnableValidationOnSubmit(project, CodeOwnerConfigValidationPolicy.DRY_RUN);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForSubmit("master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForSubmit("refs/heads/master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForSubmit("foo"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.DRY_RUN);
+ }
+
+ @Test
+ public void getCodeOwnerConfigValidationPolicyForSubmit_inheritedBranchLevelCanBeOverridden()
+ throws Exception {
+ configureEnableValidationOnSubmitForBranch(
+ allProjects, "refs/heads/master", CodeOwnerConfigValidationPolicy.FALSE);
+ configureEnableValidationOnSubmitForBranch(
+ project, "refs/heads/master", CodeOwnerConfigValidationPolicy.DRY_RUN);
+ assertThat(cfgSnapshot().getCodeOwnerConfigValidationPolicyForSubmit("master"))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.DRY_RUN);
+ }
+
private CodeOwnersPluginConfigSnapshot cfgSnapshot() {
return codeOwnersPluginConfigSnapshotFactory.create(project);
}
@@ -997,6 +1188,56 @@
requiredApproval);
}
+ private void configureEnableValidationOnCommitReceived(
+ Project.NameKey project, CodeOwnerConfigValidationPolicy codeOwnerConfigValidationPolicy)
+ throws Exception {
+ setCodeOwnersConfig(
+ project,
+ /* subsection= */ null,
+ GeneralConfig.KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED,
+ codeOwnerConfigValidationPolicy.name());
+ }
+
+ private void configureEnableValidationOnCommitReceivedForBranch(
+ Project.NameKey project,
+ String branchSubsection,
+ CodeOwnerConfigValidationPolicy codeOwnerConfigValidationPolicy)
+ throws Exception {
+ updateCodeOwnersConfig(
+ project,
+ codeOwnersConfig ->
+ codeOwnersConfig.setString(
+ GeneralConfig.SECTION_VALIDATION,
+ branchSubsection,
+ GeneralConfig.KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED,
+ codeOwnerConfigValidationPolicy.name()));
+ }
+
+ private void configureEnableValidationOnSubmit(
+ Project.NameKey project, CodeOwnerConfigValidationPolicy codeOwnerConfigValidationPolicy)
+ throws Exception {
+ setCodeOwnersConfig(
+ project,
+ /* subsection= */ null,
+ GeneralConfig.KEY_ENABLE_VALIDATION_ON_SUBMIT,
+ codeOwnerConfigValidationPolicy.name());
+ }
+
+ private void configureEnableValidationOnSubmitForBranch(
+ Project.NameKey project,
+ String branchSubsection,
+ CodeOwnerConfigValidationPolicy codeOwnerConfigValidationPolicy)
+ throws Exception {
+ updateCodeOwnersConfig(
+ project,
+ codeOwnersConfig ->
+ codeOwnersConfig.setString(
+ GeneralConfig.SECTION_VALIDATION,
+ branchSubsection,
+ GeneralConfig.KEY_ENABLE_VALIDATION_ON_SUBMIT,
+ codeOwnerConfigValidationPolicy.name()));
+ }
+
private AutoCloseable registerTestBackend() {
RegistrationHandle registrationHandle =
((PrivateInternals_DynamicMapImpl<CodeOwnerBackend>) codeOwnerBackends)
diff --git a/javatests/com/google/gerrit/plugins/codeowners/backend/config/GeneralConfigTest.java b/javatests/com/google/gerrit/plugins/codeowners/backend/config/GeneralConfigTest.java
index 456deb5..3c9fc09 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/backend/config/GeneralConfigTest.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/backend/config/GeneralConfigTest.java
@@ -31,12 +31,14 @@
import static com.google.gerrit.plugins.codeowners.backend.config.GeneralConfig.KEY_READ_ONLY;
import static com.google.gerrit.plugins.codeowners.backend.config.GeneralConfig.KEY_REJECT_NON_RESOLVABLE_CODE_OWNERS;
import static com.google.gerrit.plugins.codeowners.backend.config.GeneralConfig.KEY_REJECT_NON_RESOLVABLE_IMPORTS;
+import static com.google.gerrit.plugins.codeowners.backend.config.GeneralConfig.SECTION_VALIDATION;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import static com.google.gerrit.truth.OptionalSubject.assertThat;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.gerrit.acceptance.config.GerritConfig;
+import com.google.gerrit.entities.BranchNameKey;
import com.google.gerrit.plugins.codeowners.acceptance.AbstractCodeOwnersTest;
import com.google.gerrit.plugins.codeowners.backend.CodeOwnerReference;
import com.google.gerrit.plugins.codeowners.backend.EnableImplicitApprovals;
@@ -417,6 +419,165 @@
}
@Test
+ public void cannotGetEnableValidationOnCommitReceivedForBranchForNullBranch() throws Exception {
+ NullPointerException npe =
+ assertThrows(
+ NullPointerException.class,
+ () ->
+ generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceivedForBranch(
+ /* branchNameKey= */ null, new Config()));
+ assertThat(npe).hasMessageThat().isEqualTo("branchNameKey");
+ }
+
+ @Test
+ public void cannotGetEnableValidationOnCommitReceivedForBranchForNullPluginConfig()
+ throws Exception {
+ NullPointerException npe =
+ assertThrows(
+ NullPointerException.class,
+ () ->
+ generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceivedForBranch(
+ BranchNameKey.create(project, "master"), /* pluginConfig= */ null));
+ assertThat(npe).hasMessageThat().isEqualTo("pluginConfig");
+ }
+
+ @Test
+ public void noBranchSpecificEnableValidationOnCommitReceivedConfiguration() throws Exception {
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceivedForBranch(
+ BranchNameKey.create(project, "master"), new Config()))
+ .isEmpty();
+ }
+
+ @Test
+ public void noMatchingBranchSpecificEnableValidationOnCommitReceivedConfiguration_exact()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(
+ SECTION_VALIDATION, "refs/heads/foo", KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED, "false");
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceivedForBranch(
+ BranchNameKey.create(project, "master"), cfg))
+ .isEmpty();
+ }
+
+ @Test
+ public void noMatchingBranchSpecificEnableValidationOnCommitReceivedConfiguration_refPattern()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(
+ SECTION_VALIDATION, "refs/heads/foo/*", KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED, "false");
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceivedForBranch(
+ BranchNameKey.create(project, "master"), cfg))
+ .isEmpty();
+ }
+
+ @Test
+ public void noMatchingBranchSpecificEnableValidationOnCommitReceivedConfiguration_regEx()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(
+ SECTION_VALIDATION,
+ "^refs/heads/.*foo.*",
+ KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED,
+ "false");
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceivedForBranch(
+ BranchNameKey.create(project, "master"), cfg))
+ .isEmpty();
+ }
+
+ @Test
+ public void noMatchingBranchSpecificEnableValidationOnCommitReceivedConfiguration_invalidRegEx()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(
+ SECTION_VALIDATION, "^refs/heads/[", KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED, "false");
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceivedForBranch(
+ BranchNameKey.create(project, "master"), cfg))
+ .isEmpty();
+ }
+
+ @Test
+ public void matchingBranchSpecificEnableValidationOnCommitReceivedConfiguration_exact()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(
+ SECTION_VALIDATION, "refs/heads/master", KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED, "false");
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceivedForBranch(
+ BranchNameKey.create(project, "master"), cfg))
+ .value()
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ }
+
+ @Test
+ public void matchingBranchSpecificEnableValidationOnCommitReceivedConfiguration_refPattern()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(
+ SECTION_VALIDATION, "refs/heads/*", KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED, "false");
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceivedForBranch(
+ BranchNameKey.create(project, "master"), cfg))
+ .value()
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ }
+
+ @Test
+ public void matchingBranchSpecificEnableValidationOnCommitReceivedConfiguration_regEx()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(
+ SECTION_VALIDATION,
+ "^refs/heads/.*bar.*",
+ KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED,
+ "false");
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceivedForBranch(
+ BranchNameKey.create(project, "foobarbaz"), cfg))
+ .value()
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ }
+
+ @Test
+ public void branchSpecificEnableValidationOnCommitReceivedConfigurationIsIgnoredIfValueIsInvalid()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(
+ SECTION_VALIDATION,
+ "refs/heads/master",
+ KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED,
+ "INVALID");
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceivedForBranch(
+ BranchNameKey.create(project, "master"), cfg))
+ .isEmpty();
+ }
+
+ @Test
+ public void multipleMatchingBranchSpecificEnableValidationOnCommitReceivedConfiguration()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(
+ SECTION_VALIDATION, "refs/heads/master", KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED, "false");
+ cfg.setString(
+ SECTION_VALIDATION, "refs/heads/*", KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED, "false");
+ cfg.setString(
+ SECTION_VALIDATION, "^refs/heads/.*", KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED, "false");
+
+ // it is non-deterministic which of the branch-specific configurations takes precedence, but
+ // since they all configure the same value it's not important for this assertion
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceivedForBranch(
+ BranchNameKey.create(project, "master"), cfg))
+ .value()
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ }
+
+ @Test
public void cannotGetEnableValidationOnSubmitForNullProject() throws Exception {
NullPointerException npe =
assertThrows(
@@ -485,6 +646,147 @@
}
@Test
+ public void cannotGetEnableValidationOnSubmitForBranchForNullBranch() throws Exception {
+ NullPointerException npe =
+ assertThrows(
+ NullPointerException.class,
+ () ->
+ generalConfig.getCodeOwnerConfigValidationPolicyForSubmitForBranch(
+ /* branchNameKey= */ null, new Config()));
+ assertThat(npe).hasMessageThat().isEqualTo("branchNameKey");
+ }
+
+ @Test
+ public void cannotGetEnableValidationOnSubmitForBranchForNullPluginConfig() throws Exception {
+ NullPointerException npe =
+ assertThrows(
+ NullPointerException.class,
+ () ->
+ generalConfig.getCodeOwnerConfigValidationPolicyForSubmitForBranch(
+ BranchNameKey.create(project, "master"), /* pluginConfig= */ null));
+ assertThat(npe).hasMessageThat().isEqualTo("pluginConfig");
+ }
+
+ @Test
+ public void noBranchSpecificEnableValidationOnSubmitConfiguration() throws Exception {
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForSubmitForBranch(
+ BranchNameKey.create(project, "master"), new Config()))
+ .isEmpty();
+ }
+
+ @Test
+ public void noMatchingBranchSpecificEnableValidationOnSubmitConfiguration_exact()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(SECTION_VALIDATION, "refs/heads/foo", KEY_ENABLE_VALIDATION_ON_SUBMIT, "false");
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForSubmitForBranch(
+ BranchNameKey.create(project, "master"), cfg))
+ .isEmpty();
+ }
+
+ @Test
+ public void noMatchingBranchSpecificEnableValidationOnSubmitConfiguration_refPattern()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(SECTION_VALIDATION, "refs/heads/foo/*", KEY_ENABLE_VALIDATION_ON_SUBMIT, "false");
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForSubmitForBranch(
+ BranchNameKey.create(project, "master"), cfg))
+ .isEmpty();
+ }
+
+ @Test
+ public void noMatchingBranchSpecificEnableValidationOnSubmitConfiguration_regEx()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(
+ SECTION_VALIDATION, "^refs/heads/.*foo.*", KEY_ENABLE_VALIDATION_ON_SUBMIT, "false");
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForCommitReceivedForBranch(
+ BranchNameKey.create(project, "master"), cfg))
+ .isEmpty();
+ }
+
+ @Test
+ public void noMatchingBranchSpecificEnableValidationOnSubmitConfiguration_invalidRegEx()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(SECTION_VALIDATION, "^refs/heads/[", KEY_ENABLE_VALIDATION_ON_SUBMIT, "false");
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForSubmitForBranch(
+ BranchNameKey.create(project, "master"), cfg))
+ .isEmpty();
+ }
+
+ @Test
+ public void matchingBranchSpecificEnableValidationOnSubmitConfiguration_exact() throws Exception {
+ Config cfg = new Config();
+ cfg.setString(
+ SECTION_VALIDATION, "refs/heads/master", KEY_ENABLE_VALIDATION_ON_SUBMIT, "false");
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForSubmitForBranch(
+ BranchNameKey.create(project, "master"), cfg))
+ .value()
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ }
+
+ @Test
+ public void matchingBranchSpecificEnableValidationOnSubmitConfiguration_refPattern()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(SECTION_VALIDATION, "refs/heads/*", KEY_ENABLE_VALIDATION_ON_SUBMIT, "false");
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForSubmitForBranch(
+ BranchNameKey.create(project, "master"), cfg))
+ .value()
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ }
+
+ @Test
+ public void matchingBranchSpecificEnableValidationOnSubmitConfiguration_regEx() throws Exception {
+ Config cfg = new Config();
+ cfg.setString(
+ SECTION_VALIDATION, "^refs/heads/.*bar.*", KEY_ENABLE_VALIDATION_ON_SUBMIT, "false");
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForSubmitForBranch(
+ BranchNameKey.create(project, "foobarbaz"), cfg))
+ .value()
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ }
+
+ @Test
+ public void branchSpecificEnableValidationOnSubmitConfigurationIsIgnoredIfValueIsInvalid()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(
+ SECTION_VALIDATION, "refs/heads/master", KEY_ENABLE_VALIDATION_ON_SUBMIT, "INVALID");
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForSubmitForBranch(
+ BranchNameKey.create(project, "master"), cfg))
+ .isEmpty();
+ }
+
+ @Test
+ public void multipleMatchingBranchSpecificEnableValidationOnSubmitConfiguration()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(
+ SECTION_VALIDATION, "refs/heads/master", KEY_ENABLE_VALIDATION_ON_SUBMIT, "false");
+ cfg.setString(SECTION_VALIDATION, "refs/heads/*", KEY_ENABLE_VALIDATION_ON_SUBMIT, "false");
+ cfg.setString(SECTION_VALIDATION, "^refs/heads/.*", KEY_ENABLE_VALIDATION_ON_SUBMIT, "false");
+
+ // it is non-deterministic which of the branch-specific configurations takes precedence, but
+ // since they all configure the same value it's not important for this assertion
+ assertThat(
+ generalConfig.getCodeOwnerConfigValidationPolicyForSubmitForBranch(
+ BranchNameKey.create(project, "master"), cfg))
+ .value()
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ }
+
+ @Test
public void cannotGetMergeCommitStrategyForNullPluginConfig() throws Exception {
NullPointerException npe =
assertThrows(
diff --git a/resources/Documentation/config.md b/resources/Documentation/config.md
index ffa4018..70e5630 100644
--- a/resources/Documentation/config.md
+++ b/resources/Documentation/config.md
@@ -605,10 +605,26 @@
[plugin.@PLUGIN@.enableValidationOnCommitReceived](#pluginCodeOwnersEnableValidationOnCommitReceived)
in `gerrit.config` and the `codeOwners.enableValidationOnCommitReceived`
setting from parent projects.\
+ Can be overriden on branch-level by setting
+ [validation.\<branch\>.enableValidationOnCommitReceived](#validationBranchEnableValidationOnCommitReceived).\
If not set, the global setting
[plugin.@PLUGIN@.enableValidationOnCommitReceived](#pluginCodeOwnersEnableValidationOnCommitReceived)
in `gerrit.config` is used.
+<a id="validationBranchEnableValidationOnCommitReceived">validation.\<branch\>.enableValidationOnCommitReceived</a>
+: Branch-level policy for validating code owner config files when a commit
+ is received.\
+ Applies to all branches that are matched by `<branch>`, which can be
+ an exact ref name (e.g. `refs/heads/master`), a ref pattern (e.g.
+ `refs/heads/*`) or a regular expression (e.g. `^refs/heads/stable-.*`).\
+ If a branches matches multiple validation subsections it is undefined
+ which of the subsections takes precedence.\
+ Overrides the project-level configuration for validating code owner
+ config files when a commit is received that is configured by
+ [codeOwners.enableValidationOnCommitReceived](#codeOwnersEnableValidationOnCommitReceived).\
+ For further details see the description of
+ [codeOwners.enableValidationOnCommitReceived](#codeOwnersEnableValidationOnCommitReceived).
+
<a id="codeOwnersEnableValidationOnSubmit">codeOwners.enableValidationOnSubmit</a>
: Policy for validating code owner config files when a change is
submitted. Allowed values are `true` (the code owner config file
@@ -622,10 +638,26 @@
[plugin.@PLUGIN@.enableValidationOnSubmit](#pluginCodeOwnersEnableValidationOnSubmit)
in `gerrit.config` and the `codeOwners.enableValidationOnSubmit` setting
from parent projects.\
+ Can be overriden on branch-level by setting
+ [validation.\<branch\>.enableValidationOnSubmit](#validationBranchEnableValidationOnSubmit).\
If not set, the global setting
[plugin.@PLUGIN@.enableValidationOnSubmit](#pluginCodeOwnersEnableValidationOnSubmit)
in `gerrit.config` is used.
+<a id="validationBranchEnableValidationOnSubmit">validation.\<branch\>.enableValidationOnSubmit</a>
+: Branch-level policy for validating code owner config files when a change
+ is submitted.\
+ Applies to all branches that are matched by `<branch>`, which can be
+ an exact ref name (e.g. `refs/heads/master`), a ref pattern (e.g.
+ `refs/heads/*`) or a regular expression (e.g. `^refs/heads/stable-.*`).\
+ If a branches matches multiple validation subsections it is undefined
+ which of the subsections takes precedence.\
+ Overrides the project-level configuration for validating code owner
+ config files when a change is submitted that is configured by
+ [codeOwners.enableValidationOnSubmit](#codeOwnersEnableValidationOnSubmit).\
+ For further details see the description of
+ [codeOwners.enableValidationOnSubmit](#codeOwnersEnableValidationOnSubmit).
+
<a id="codeOwnersRejectNonResolvableCodeOwners">codeOwners.rejectNonResolvableCodeOwners</a>
: Whether modifications of code owner config files that newly add
non-resolvable code owners should be rejected on commit received and