Merge changes I1f101173,I32b0d8b9,Ic191c620
* changes:
Fix a heading in the validation documentation
Validation: Do not reject imports that are added in the same commit
Add config option to disable validation of code owner configs on submit
diff --git a/java/com/google/gerrit/plugins/codeowners/config/CodeOwnersPluginConfiguration.java b/java/com/google/gerrit/plugins/codeowners/config/CodeOwnersPluginConfiguration.java
index 60c14d2..1a7985d 100644
--- a/java/com/google/gerrit/plugins/codeowners/config/CodeOwnersPluginConfiguration.java
+++ b/java/com/google/gerrit/plugins/codeowners/config/CodeOwnersPluginConfiguration.java
@@ -130,6 +130,20 @@
}
/**
+ * Whether code owner configs should be validated when a change is submitted.
+ *
+ * @param project the project for it should be checked whether code owner configs should be
+ * validated when a change is submitted
+ * @return whether code owner configs should be validated when a change is submitted
+ */
+ public CodeOwnerConfigValidationPolicy getCodeOwnerConfigValidationPolicyForSubmit(
+ Project.NameKey project) {
+ requireNonNull(project, "project");
+ return generalConfig.getCodeOwnerConfigValidationPolicyForSubmit(
+ project, getPluginConfig(project));
+ }
+
+ /**
* Gets the merge commit strategy for the given project.
*
* @param project the project for which the merge commit strategy should be retrieved
diff --git a/java/com/google/gerrit/plugins/codeowners/config/GeneralConfig.java b/java/com/google/gerrit/plugins/codeowners/config/GeneralConfig.java
index 8a15dcb..85fd19a 100644
--- a/java/com/google/gerrit/plugins/codeowners/config/GeneralConfig.java
+++ b/java/com/google/gerrit/plugins/codeowners/config/GeneralConfig.java
@@ -66,6 +66,9 @@
public static final String KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED =
"enableValidationOnCommitReceived";
+ @VisibleForTesting
+ public static final String KEY_ENABLE_VALIDATION_ON_SUBMIT = "enableValidationOnSubmit";
+
@VisibleForTesting public static final String KEY_MERGE_COMMIT_STRATEGY = "mergeCommitStrategy";
@VisibleForTesting public static final String KEY_GLOBAL_CODE_OWNER = "globalCodeOwner";
@@ -240,23 +243,45 @@
* <p>The enable validation on commit received controls whether code owner config files should be
* validated when a commit is received.
*
- * @param pluginConfig the plugin config from which the read-only configuration should be read.
+ * @param pluginConfig the plugin config from which the enable validation on commit received
+ * configuration should be read.
* @return whether code owner config files should be validated when a commit is received
*/
CodeOwnerConfigValidationPolicy getCodeOwnerConfigValidationPolicyForCommitReceived(
Project.NameKey project, Config pluginConfig) {
+ return getCodeOwnerConfigValidationPolicy(
+ KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED, project, pluginConfig);
+ }
+
+ /**
+ * Gets the enable validation on submit configuration from the given plugin config 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 pluginConfig the plugin config from which the enable validation on submit configuration
+ * should be read.
+ * @return whether code owner config files should be validated when a change is submitted
+ */
+ CodeOwnerConfigValidationPolicy getCodeOwnerConfigValidationPolicyForSubmit(
+ Project.NameKey project, Config pluginConfig) {
+ return getCodeOwnerConfigValidationPolicy(
+ KEY_ENABLE_VALIDATION_ON_SUBMIT, project, pluginConfig);
+ }
+
+ private CodeOwnerConfigValidationPolicy getCodeOwnerConfigValidationPolicy(
+ String key, Project.NameKey project, Config pluginConfig) {
+ requireNonNull(key, "key");
requireNonNull(project, "project");
requireNonNull(pluginConfig, "pluginConfig");
String codeOwnerConfigValidationPolicyString =
- pluginConfig.getString(SECTION_CODE_OWNERS, null, KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED);
+ pluginConfig.getString(SECTION_CODE_OWNERS, null, key);
if (codeOwnerConfigValidationPolicyString != null) {
try {
return pluginConfig.getEnum(
- SECTION_CODE_OWNERS,
- null,
- KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED,
- CodeOwnerConfigValidationPolicy.TRUE);
+ SECTION_CODE_OWNERS, null, key, CodeOwnerConfigValidationPolicy.TRUE);
} catch (IllegalArgumentException e) {
logger.atWarning().log(
"Ignoring invalid value %s for the code owner config validation policy in '%s.config'"
@@ -266,15 +291,14 @@
}
try {
- return pluginConfigFromGerritConfig.getEnum(
- KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED, CodeOwnerConfigValidationPolicy.TRUE);
+ return pluginConfigFromGerritConfig.getEnum(key, CodeOwnerConfigValidationPolicy.TRUE);
} catch (IllegalArgumentException e) {
logger.atWarning().log(
"Ignoring invalid value %s for the code owner config validation policy in gerrit.config"
+ " (parameter plugin.%s.%s). Falling back to default value %s.",
- pluginConfigFromGerritConfig.getString(KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED),
+ pluginConfigFromGerritConfig.getString(key),
pluginName,
- KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED,
+ key,
CodeOwnerConfigValidationPolicy.TRUE);
return CodeOwnerConfigValidationPolicy.TRUE;
}
diff --git a/java/com/google/gerrit/plugins/codeowners/validation/CodeOwnerConfigValidator.java b/java/com/google/gerrit/plugins/codeowners/validation/CodeOwnerConfigValidator.java
index 85cfca4..e659580 100644
--- a/java/com/google/gerrit/plugins/codeowners/validation/CodeOwnerConfigValidator.java
+++ b/java/com/google/gerrit/plugins/codeowners/validation/CodeOwnerConfigValidator.java
@@ -237,16 +237,44 @@
.username(caller.getLoggableName())
.patchSetId(patchSetId.get())
.build())) {
- ChangeNotes changeNotes =
- changeNotesFactory.create(projectState.getNameKey(), commit.change().getId());
- PatchSet patchSet = patchSetUtil.get(changeNotes, patchSetId);
- IdentifiedUser patchSetUploader = userFactory.create(patchSet.uploader());
- Optional<ValidationResult> validationResult =
- validateCodeOwnerConfig(
- branchNameKey, repository.getConfig(), revWalk, commit, patchSetUploader);
+ CodeOwnerConfigValidationPolicy codeOwnerConfigValidationPolicy =
+ codeOwnersPluginConfiguration.getCodeOwnerConfigValidationPolicyForSubmit(
+ branchNameKey.project());
+ logger.atFine().log("codeOwnerConfigValidationPolicy = %s", codeOwnerConfigValidationPolicy);
+ Optional<ValidationResult> validationResult;
+ if (!codeOwnerConfigValidationPolicy.runValidation()) {
+ validationResult =
+ Optional.of(
+ ValidationResult.create(
+ "skipping validation of code owner config files",
+ new CommitValidationMessage(
+ "code owners config validation is disabled", ValidationMessage.Type.HINT)));
+ } else {
+ try {
+ ChangeNotes changeNotes =
+ changeNotesFactory.create(projectState.getNameKey(), commit.change().getId());
+ PatchSet patchSet = patchSetUtil.get(changeNotes, patchSetId);
+ IdentifiedUser patchSetUploader = userFactory.create(patchSet.uploader());
+ validationResult =
+ validateCodeOwnerConfig(
+ branchNameKey, repository.getConfig(), revWalk, commit, patchSetUploader);
+ } catch (RuntimeException e) {
+ if (!codeOwnerConfigValidationPolicy.isDryRun()) {
+ throw e;
+ }
+
+ // The validation was executed as dry-run and failures during the validation should not
+ // cause an error. Hence we swallow the exception here.
+ logger.atFine().withCause(e).log(
+ "ignoring failure during validation of code owner config files in revision %s"
+ + " (project = %s, branch = %s) because the validation was performed as dry-run",
+ commit.name(), branchNameKey.project(), branchNameKey.branch());
+ validationResult = Optional.empty();
+ }
+ }
if (validationResult.isPresent()) {
logger.atFine().log("validation result = %s", validationResult.get());
- validationResult.get().processForOnPreMerge();
+ validationResult.get().processForOnPreMerge(codeOwnerConfigValidationPolicy.isDryRun());
}
}
}
@@ -748,6 +776,7 @@
validateCodeOwnerConfigReference(
codeOwnerConfigFilePath,
codeOwnerConfig.key(),
+ codeOwnerConfig.revision(),
CodeOwnerConfigImportType.GLOBAL,
codeOwnerConfigReference)),
codeOwnerConfig.codeOwnerSets().stream()
@@ -757,6 +786,7 @@
validateCodeOwnerConfigReference(
codeOwnerConfigFilePath,
codeOwnerConfig.key(),
+ codeOwnerConfig.revision(),
CodeOwnerConfigImportType.PER_FILE,
codeOwnerConfigReference)))
.filter(Optional::isPresent)
@@ -769,6 +799,8 @@
* @param codeOwnerConfigFilePath the path of the code owner config file which contains the code
* owner config reference
* @param keyOfImportingCodeOwnerConfig key of the importing code owner config
+ * @param codeOwnerConfigRevision the commit from which the code owner config which contains the
+ * code owner config reference was loaded
* @param importType the type of the import
* @param codeOwnerConfigReference the code owner config reference that should be validated.
* @return a validation message describing the issue with the code owner config reference, {@link
@@ -777,6 +809,7 @@
private Optional<CommitValidationMessage> validateCodeOwnerConfigReference(
Path codeOwnerConfigFilePath,
CodeOwnerConfig.Key keyOfImportingCodeOwnerConfig,
+ ObjectId codeOwnerConfigRevision,
CodeOwnerConfigImportType importType,
CodeOwnerConfigReference codeOwnerConfigReference) {
CodeOwnerConfig.Key keyOfImportedCodeOwnerConfig =
@@ -804,7 +837,9 @@
projectState.get().getProject().getState().name()));
}
- Optional<ObjectId> revision = getRevision(keyOfImportedCodeOwnerConfig);
+ Optional<ObjectId> revision =
+ getRevision(
+ keyOfImportingCodeOwnerConfig, codeOwnerConfigRevision, keyOfImportedCodeOwnerConfig);
if (!revision.isPresent() || !isBranchReadable(keyOfImportedCodeOwnerConfig)) {
// we intentionally use the same error message for non-existing and non-readable branches so
// that uploaders cannot probe for the existence of branches (e.g. deduce from the error
@@ -888,7 +923,18 @@
}
}
- private Optional<ObjectId> getRevision(CodeOwnerConfig.Key keyOfImportedCodeOwnerConfig) {
+ private Optional<ObjectId> getRevision(
+ CodeOwnerConfig.Key keyOfImportingCodeOwnerConfig,
+ ObjectId codeOwnerConfigRevision,
+ CodeOwnerConfig.Key keyOfImportedCodeOwnerConfig) {
+ if (keyOfImportingCodeOwnerConfig
+ .branchNameKey()
+ .equals(keyOfImportedCodeOwnerConfig.branchNameKey())) {
+ // load the imported code owner config from the same revision from which the importing code
+ // owner config was loaded
+ return Optional.of(codeOwnerConfigRevision);
+ }
+
try (Repository repo = repoManager.openRepository(keyOfImportedCodeOwnerConfig.project())) {
return Optional.ofNullable(repo.exactRef(keyOfImportedCodeOwnerConfig.ref()))
.map(Ref::getObjectId);
@@ -959,8 +1005,8 @@
* <p>If there are no errors the validation messages are logged on fine level so that they show
* up in a trace. Returning the message to the user without failing the submit is not possible.
*/
- void processForOnPreMerge() throws MergeValidationException {
- if (hasError()) {
+ void processForOnPreMerge(boolean dryRun) throws MergeValidationException {
+ if (!dryRun && hasError()) {
throw new MergeValidationException(getMessage(validationMessages()));
}
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 bc42987..2e5e73b 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnerConfigValidatorIT.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnerConfigValidatorIT.java
@@ -22,6 +22,7 @@
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import com.google.common.collect.ImmutableMap;
+import com.google.gerrit.acceptance.GitUtil;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.TestAccount;
import com.google.gerrit.acceptance.config.GerritConfig;
@@ -166,6 +167,12 @@
.addCodeOwnerEmail(user.email())
.create();
+ // Fetch the commit that created the imported code owner config into the local repository so
+ // that the commit that creates the importing code owner config becomes a successor of this
+ // commit.
+ GitUtil.fetch(testRepo, "refs/*:refs/*");
+ testRepo.reset(projectOperations.project(project).getHead("master"));
+
CodeOwnerConfigReference codeOwnerConfigReference =
CodeOwnerConfigReference.create(
CodeOwnerConfigImportMode.GLOBAL_CODE_OWNER_SETS_ONLY,
@@ -282,6 +289,47 @@
}
@Test
+ public void canUploadConfigWithoutIssues_withImportOfConfigThatIsAddedInSameCommit()
+ throws Exception {
+ // imports are not supported for the proto backend
+ assume().that(backendConfig.getDefaultBackend()).isNotInstanceOf(ProtoBackend.class);
+
+ CodeOwnerConfig.Key codeOwnerConfigKey = createCodeOwnerConfigKey("/");
+ CodeOwnerConfig.Key keyOfImportedCodeOwnerConfig = createCodeOwnerConfigKey("/foo/");
+
+ CodeOwnerConfigReference codeOwnerConfigReference =
+ CodeOwnerConfigReference.create(
+ CodeOwnerConfigImportMode.GLOBAL_CODE_OWNER_SETS_ONLY,
+ codeOwnerConfigOperations.codeOwnerConfig(keyOfImportedCodeOwnerConfig).getFilePath());
+
+ // Create a code owner config with import and without issues.
+ PushOneCommit.Result r =
+ createChange(
+ "Add code owners",
+ ImmutableMap.of(
+ codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
+ format(
+ CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
+ .addImport(codeOwnerConfigReference)
+ .addCodeOwnerSet(
+ CodeOwnerSet.builder()
+ .addCodeOwnerEmail(admin.email())
+ .addPathExpression("foo")
+ .addImport(codeOwnerConfigReference)
+ .build())
+ .build()),
+ codeOwnerConfigOperations
+ .codeOwnerConfig(keyOfImportedCodeOwnerConfig)
+ .getJGitFilePath(),
+ format(
+ CodeOwnerConfig.builder(keyOfImportedCodeOwnerConfig, TEST_REVISION)
+ .addCodeOwnerSet(
+ CodeOwnerSet.builder().addCodeOwnerEmail(user.email()).build())
+ .build())));
+ assertOkWithHints(r, "code owner config files validated, no issues found");
+ }
+
+ @Test
@GerritConfig(name = "plugin.code-owners.backend", value = "non-existing-backend")
public void canUploadNonParseableConfigIfCodeOwnersPluginConfigurationIsInvalid()
throws Exception {
@@ -1428,6 +1476,81 @@
gApi.changes().create(changeInput);
}
+ @Test
+ @GerritConfig(name = "plugin.code-owners.enableValidationOnSubmit", value = "false")
+ public void canSubmitNonParseableConfigIfValidationIsDisabled() throws Exception {
+ testCanSubmitNonParseableConfig();
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.enableValidationOnSubmit", value = "dry_run")
+ public void canSubmitNonParseableConfigIfValidationIsDoneAsDryRun() throws Exception {
+ testCanSubmitNonParseableConfig();
+ }
+
+ private void testCanSubmitNonParseableConfig() throws Exception {
+ CodeOwnerConfig.Key codeOwnerConfigKey = createCodeOwnerConfigKey("/");
+
+ // disable the code owners functionality so that we can upload a non-parseable code owner config
+ // that we then try to submit
+ disableCodeOwnersForProject(project);
+
+ PushOneCommit.Result r =
+ createChange(
+ "Add code owners",
+ codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
+ "INVALID");
+ r.assertOkStatus();
+
+ // re-enable the code owners functionality for the project
+ enableCodeOwnersForProject(project);
+
+ // submit the change
+ approve(r.getChangeId());
+ gApi.changes().id(r.getChangeId()).current().submit();
+ assertThat(gApi.changes().id(r.getChangeId()).get().status).isEqualTo(ChangeStatus.MERGED);
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.enableValidationOnSubmit", value = "false")
+ public void canSubmitConfigWithIssuesIfValidationIsDisabled() throws Exception {
+ testCanSubmitConfigWithIssues();
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.enableValidationOnSubmit", value = "dry_run")
+ public void canSubmitConfigWithIssuesIfValidationIsDoneAsDryRun() throws Exception {
+ testCanSubmitConfigWithIssues();
+ }
+
+ private void testCanSubmitConfigWithIssues() throws Exception {
+ CodeOwnerConfig.Key codeOwnerConfigKey = createCodeOwnerConfigKey("/");
+
+ // disable the code owners functionality so that we can upload a code owner config with issues
+ // that we then try to submit
+ disableCodeOwnersForProject(project);
+
+ // upload a code owner config that has issues (non-resolvable code owners)
+ String unknownEmail1 = "non-existing-email@example.com";
+ PushOneCommit.Result r =
+ createChange(
+ "Add code owners",
+ codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getJGitFilePath(),
+ format(
+ CodeOwnerConfig.builder(codeOwnerConfigKey, TEST_REVISION)
+ .addCodeOwnerSet(CodeOwnerSet.createWithoutPathExpressions(unknownEmail1))
+ .build()));
+ r.assertOkStatus();
+
+ // re-enable the code owners functionality for the project
+ enableCodeOwnersForProject(project);
+
+ // submit the change
+ 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/config/GeneralConfigTest.java b/javatests/com/google/gerrit/plugins/codeowners/config/GeneralConfigTest.java
index 2a92d16..6bc8ac5 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/config/GeneralConfigTest.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/config/GeneralConfigTest.java
@@ -18,6 +18,7 @@
import static com.google.gerrit.plugins.codeowners.config.CodeOwnersPluginConfiguration.SECTION_CODE_OWNERS;
import static com.google.gerrit.plugins.codeowners.config.GeneralConfig.KEY_ENABLE_IMPLICIT_APPROVALS;
import static com.google.gerrit.plugins.codeowners.config.GeneralConfig.KEY_ENABLE_VALIDATION_ON_COMMIT_RECEIVED;
+import static com.google.gerrit.plugins.codeowners.config.GeneralConfig.KEY_ENABLE_VALIDATION_ON_SUBMIT;
import static com.google.gerrit.plugins.codeowners.config.GeneralConfig.KEY_FALLBACK_CODE_OWNERS;
import static com.google.gerrit.plugins.codeowners.config.GeneralConfig.KEY_FILE_EXTENSION;
import static com.google.gerrit.plugins.codeowners.config.GeneralConfig.KEY_GLOBAL_CODE_OWNER;
@@ -177,6 +178,50 @@
}
@Test
+ public void cannotGetEnableValidationOnSubmitForNullProject() throws Exception {
+ NullPointerException npe =
+ assertThrows(
+ NullPointerException.class,
+ () -> generalConfig.getCodeOwnerConfigValidationPolicyForSubmit(null, new Config()));
+ assertThat(npe).hasMessageThat().isEqualTo("project");
+ }
+
+ @Test
+ public void cannotGetEnableValidationOnSubmitForNullPluginConfig() throws Exception {
+ NullPointerException npe =
+ assertThrows(
+ NullPointerException.class,
+ () -> generalConfig.getCodeOwnerConfigValidationPolicyForSubmit(project, null));
+ assertThat(npe).hasMessageThat().isEqualTo("pluginConfig");
+ }
+
+ @Test
+ public void noEnableValidationOnSubmitConfiguration() throws Exception {
+ assertThat(generalConfig.getCodeOwnerConfigValidationPolicyForSubmit(project, new Config()))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.TRUE);
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.enableValidationOnSubmit", value = "false")
+ public void
+ enableValidationOnSubmitConfigurationIsRetrievedFromGerritConfigIfNotSpecifiedOnProjectLevel()
+ throws Exception {
+ assertThat(generalConfig.getCodeOwnerConfigValidationPolicyForSubmit(project, new Config()))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.FALSE);
+ }
+
+ @Test
+ @GerritConfig(name = "plugin.code-owners.enableValidationOnSubmit", value = "false")
+ public void
+ enableValidationOnSubmitConfigurationInPluginConfigOverridesEnableValidationOnSubmitConfigurationInGerritConfig()
+ throws Exception {
+ Config cfg = new Config();
+ cfg.setString(SECTION_CODE_OWNERS, null, KEY_ENABLE_VALIDATION_ON_SUBMIT, "true");
+ assertThat(generalConfig.getCodeOwnerConfigValidationPolicyForSubmit(project, cfg))
+ .isEqualTo(CodeOwnerConfigValidationPolicy.TRUE);
+ }
+
+ @Test
public void cannotGetMergeCommitStrategyForNullPluginConfig() throws Exception {
NullPointerException npe =
assertThrows(
diff --git a/resources/Documentation/config.md b/resources/Documentation/config.md
index 32d3ae9..28c65b9 100644
--- a/resources/Documentation/config.md
+++ b/resources/Documentation/config.md
@@ -133,6 +133,20 @@
in `@PLUGIN@.config`.\
By default `true`.
+<a id="pluginCodeOwnersEnableValidationOnSubmit">plugin.@PLUGIN@.enableValidationOnSubmit</a>
+: Policy for validating code owner config files when a change is
+ submitted. Allowed values are `true` (the code owner config file
+ validation is enabled and the submit of invalid code owner config files
+ is rejected), `false` (the code owner config file validation is
+ disabled, invalid code owner config files are not rejected) and
+ `dry_run` (code owner config files are validated, but invalid code owner
+ config files are not rejected).\
+ Disabling the submit validation is not recommended.\
+ Can be overridden per project by setting
+ [codeOwners.enableValidationOnSubmit](#codeOwnersEnableValidationOnSubmit)
+ in `@PLUGIN@.config`.\
+ By default `true`.
+
<a id="pluginCodeOwnersAllowedEmailDomain">plugin.@PLUGIN@.allowedEmailDomain</a>
: Email domain that allows to assign code ownerships to emails with this
domain.\
@@ -420,6 +434,22 @@
[plugin.@PLUGIN@.enableValidationOnCommitReceived](#pluginCodeOwnersEnableValidationOnCommitReceived)
in `gerrit.config` is used.
+<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
+ validation is enabled and the submit of invalid code owner config files
+ is rejected), `false` (the code owner config file validation is
+ disabled, invalid code owner config files are not rejected) and
+ `dry_run` (code owner config files are validated, but invalid code owner
+ config files are not rejected).\
+ Disabling the submit validation is not recommended.\
+ Overrides the global setting
+ [plugin.@PLUGIN@.enableValidationOnSubmit](#pluginCodeOwnersEnableValidationOnSubmit)
+ in `gerrit.config`.\
+ If not set, the global setting
+ [plugin.@PLUGIN@.enableValidationOnSubmit](#pluginCodeOwnersEnableValidationOnSubmit)
+ in `gerrit.config` is used.
+
<a id="codeOwnersRequiredApproval">codeOwners.requiredApproval</a>
: Approval that is required from code owners to approve the files in a
change.\
diff --git a/resources/Documentation/validation.md b/resources/Documentation/validation.md
index b3b6405..ef1b4ce 100644
--- a/resources/Documentation/validation.md
+++ b/resources/Documentation/validation.md
@@ -37,8 +37,10 @@
plugin gets installed/enabled, it is possible that invalid configuration files
already exist in the repository)
* updates happen behind Gerrit's back (e.g. pushes that bypass Gerrit)
-* the validation is disabled in the
- [plugin configuration](config.html#codeOwnersEnableValidationOnCommitReceived).
+* the validation is disabled via the
+ [enableValidationOnCommitReceived](config.html#codeOwnersEnableValidationOnCommitReceived)
+ or [enableValidationOnSubmit](config.html#codeOwnersEnableValidationOnSubmit)
+ config options
In addition for [code owner config files](user-guide.html#codeOwnerConfigFiles)
no validation is done when:
@@ -129,7 +131,7 @@
[code owner override](user-guide.html#codeOwnerOverride).
-### <a id="codeOwnerConfigFileChecks">Validation checks for code owner config files
+### <a id="codeOwnersConfigFileChecks">Validation checks for code-owners.config files
For the [code-owner.config](config.html#projectLevelConfigFile) in the
`refs/meta/config` branch the following checks are performed: