Warn if code-owners plugin configuration is added in project.config
The configuration of the code-owners plugin is read from
* gerrit.config (section 'plugin.code-owners')
* code-owners.config in refs/meta/config (mostly section 'codeOwners')
Sometimes it happens that users wrongly add code-owners plugin
configuration in project.config and then don't understand why the
configuration doesn't work.
Print out a warning if code-owners plugin configuration is added in
project.config so that users get to know that this is the wrong place to
configure the code-owners plugin.
Signed-off-by: Edwin Kempin <ekempin@google.com>
Change-Id: Ice385139c41cae421297f12895cdd1a6efff8b93
diff --git a/java/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigValidator.java b/java/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigValidator.java
index 651ce61..df8003f 100644
--- a/java/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigValidator.java
+++ b/java/com/google/gerrit/plugins/codeowners/backend/config/CodeOwnersPluginConfigValidator.java
@@ -14,6 +14,8 @@
package com.google.gerrit.plugins.codeowners.backend.config;
+import static com.google.gerrit.plugins.codeowners.backend.config.CodeOwnersPluginConfiguration.SECTION_CODE_OWNERS;
+
import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.entities.RefNames;
@@ -77,30 +79,40 @@
@Override
public ImmutableList<CommitValidationMessage> onCommitReceived(CommitReceivedEvent receiveEvent)
throws CommitValidationException {
- String fileName = pluginName + ".config";
+ if (!receiveEvent.refName.equals(RefNames.REFS_CONFIG)) {
+ // The code-owners.config file is stored in refs/meta/config, if refs/meta/config was not
+ // modified we do not need to do any validation and can return early.
+ return ImmutableList.of();
+ }
+ ImmutableList.Builder<CommitValidationMessage> validationMessageBuilder =
+ ImmutableList.builder();
+ validationMessageBuilder.addAll(
+ getWarningsForIgnoredCodeOwnerConfigurationInProjectConfig(receiveEvent));
+ String codeOwnersConfigFileName = pluginName + ".config";
try {
- if (!receiveEvent.refName.equals(RefNames.REFS_CONFIG)
- || !isFileChanged(receiveEvent, fileName)) {
+ if (!isFileChanged(receiveEvent, codeOwnersConfigFileName)) {
// the code-owners.config file in refs/meta/config was not modified, hence we do not need to
// validate it
- return ImmutableList.of();
+ return validationMessageBuilder.build();
}
ProjectState projectState = getProjectState(receiveEvent);
- ProjectLevelConfig.Bare cfg = loadConfig(receiveEvent, fileName);
- ImmutableList<CommitValidationMessage> validationMessages =
- validateConfig(projectState, fileName, cfg.getConfig());
+ ProjectLevelConfig.Bare cfg = loadConfig(receiveEvent, codeOwnersConfigFileName);
+ validationMessageBuilder.addAll(
+ validateConfig(projectState, codeOwnersConfigFileName, cfg.getConfig()));
+
+ ImmutableList<CommitValidationMessage> validationMessages = validationMessageBuilder.build();
if (!validationMessages.isEmpty()) {
throw new CommitValidationException(
- exceptionMessage(fileName, cfg.getRevision()), validationMessages);
+ exceptionMessage(codeOwnersConfigFileName, cfg.getRevision()), validationMessages);
}
return ImmutableList.of();
} catch (IOException | DiffNotAvailableException | ConfigInvalidException e) {
String errorMessage =
String.format(
"failed to validate file %s for revision %s in ref %s of project %s",
- fileName,
+ codeOwnersConfigFileName,
receiveEvent.commit.getName(),
RefNames.REFS_CONFIG,
receiveEvent.project.getNameKey());
@@ -109,6 +121,53 @@
}
}
+ private ImmutableList<CommitValidationMessage>
+ getWarningsForIgnoredCodeOwnerConfigurationInProjectConfig(CommitReceivedEvent receiveEvent) {
+ try {
+ if (!isFileChanged(receiveEvent, ProjectConfig.PROJECT_CONFIG)) {
+ return ImmutableList.of();
+ }
+
+ ImmutableList.Builder<CommitValidationMessage> validationMessageBuilder =
+ ImmutableList.builder();
+ ProjectLevelConfig.Bare cfg = loadConfig(receiveEvent, ProjectConfig.PROJECT_CONFIG);
+
+ if (cfg.getConfig().getSubsections("plugin").contains(pluginName)) {
+ // The plugin.code-owners section is only read from gerrit.config, but not from
+ // project.config. Warn that this configuration is ignored and has no effect.
+ validationMessageBuilder.add(
+ new CommitValidationMessage(
+ String.format(
+ "Section 'plugin.code-owners' in %s is ignored and has no effect."
+ + " The configuration for the %s plugin must be done in %s.config.",
+ ProjectConfig.PROJECT_CONFIG, pluginName, pluginName),
+ ValidationMessage.Type.HINT));
+ }
+
+ if (cfg.getConfig().getSections().contains(SECTION_CODE_OWNERS)) {
+ // The codeOwners section is only read from code-owners.config, but not from
+ // project.config. Warn that this configuration is ignored and has no effect.
+ validationMessageBuilder.add(
+ new CommitValidationMessage(
+ String.format(
+ "Section 'codeOwners' in %s is ignored and has no effect."
+ + " The configuration for the %s plugin must be done in %s.config.",
+ ProjectConfig.PROJECT_CONFIG, pluginName, pluginName),
+ ValidationMessage.Type.HINT));
+ }
+
+ return validationMessageBuilder.build();
+ } catch (IOException | DiffNotAvailableException | CommitValidationException e) {
+ logger.atSevere().withCause(e).log(
+ "failed to inspect file %s for revision %s in ref %s of project %s",
+ ProjectConfig.PROJECT_CONFIG,
+ receiveEvent.commit.getName(),
+ RefNames.REFS_CONFIG,
+ receiveEvent.project.getNameKey());
+ return ImmutableList.of();
+ }
+ }
+
private ProjectState getProjectState(CommitReceivedEvent receiveEvent)
throws IOException, ConfigInvalidException {
ProjectConfig projectConfig = projectConfigFactory.create(receiveEvent.project.getNameKey());
diff --git a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnersPluginConfigValidatorIT.java b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnersPluginConfigValidatorIT.java
index f7f94be..b2a6630 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnersPluginConfigValidatorIT.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnersPluginConfigValidatorIT.java
@@ -803,6 +803,63 @@
ObjectIds.abbreviateName(r.getCommit(), testRepo.getRevWalk().getObjectReader())));
}
+ @Test
+ public void warnIfCodeOwnersConfigurationIsDoneInProjectConfig_configWithPluginCodeOwnersSection()
+ throws Exception {
+ fetchRefsMetaConfig();
+ Config cfg = new Config();
+ cfg.setEnum(
+ /* section= */ "plugin",
+ /* subsection= */ "code-owners",
+ GeneralConfig.KEY_FALLBACK_CODE_OWNERS,
+ FallbackCodeOwners.ALL_USERS);
+ PushOneCommit push =
+ pushFactory.create(admin.newIdent(), testRepo, "Change", "project.config", cfg.toText());
+ PushOneCommit.Result r = push.to("refs/for/" + RefNames.REFS_CONFIG);
+ r.assertOkStatus();
+ r.assertMessage(
+ String.format(
+ "hint: commit %s: Section 'plugin.code-owners' in project.config is ignored and has no"
+ + " effect. The configuration for the code-owners plugin must be done in"
+ + " code-owners.config.",
+ ObjectIds.abbreviateName(r.getCommit(), testRepo.getRevWalk().getObjectReader())));
+ }
+
+ @Test
+ public void warnIfCodeOwnersConfigurationIsDoneInProjectConfig_configWithCodeOwnersSection()
+ throws Exception {
+ fetchRefsMetaConfig();
+ Config cfg = new Config();
+ cfg.setEnum(
+ CodeOwnersPluginConfiguration.SECTION_CODE_OWNERS,
+ /* subsection= */ null,
+ GeneralConfig.KEY_FALLBACK_CODE_OWNERS,
+ FallbackCodeOwners.ALL_USERS);
+ PushOneCommit push =
+ pushFactory.create(admin.newIdent(), testRepo, "Change", "project.config", cfg.toText());
+ PushOneCommit.Result r = push.to("refs/for/" + RefNames.REFS_CONFIG);
+ r.assertOkStatus();
+ r.assertMessage(
+ String.format(
+ "hint: commit %s: Section 'codeOwners' in project.config is ignored and has no effect."
+ + " The configuration for the code-owners plugin must be done in code-owners.config.",
+ ObjectIds.abbreviateName(r.getCommit(), testRepo.getRevWalk().getObjectReader())));
+ }
+
+ @Test
+ public void noWarningIfProjectConfigIsUpdatedWithoutCodeOwnerSettings() throws Exception {
+ fetchRefsMetaConfig();
+ Config cfg = new Config();
+ cfg.setString(
+ /* section= */ "foo", /* subsection= */ null, /* name= */ "bar", /* value= */ "baz");
+ PushOneCommit push =
+ pushFactory.create(admin.newIdent(), testRepo, "Change", "project.config", cfg.toText());
+ PushOneCommit.Result r = push.to("refs/for/" + RefNames.REFS_CONFIG);
+ r.assertOkStatus();
+ r.assertNotMessage(
+ "The configuration for the code-owners plugin must be done in code-owners.config.");
+ }
+
private void fetchRefsMetaConfig() throws Exception {
fetch(testRepo, RefNames.REFS_CONFIG + ":" + RefNames.REFS_CONFIG);
testRepo.reset(RefNames.REFS_CONFIG);