Merge "Include link to validation documentation when issues in OWNERS files are found"
diff --git a/java/com/google/gerrit/plugins/codeowners/validation/CodeOwnerConfigValidator.java b/java/com/google/gerrit/plugins/codeowners/validation/CodeOwnerConfigValidator.java
index f763a2c..0083497 100644
--- a/java/com/google/gerrit/plugins/codeowners/validation/CodeOwnerConfigValidator.java
+++ b/java/com/google/gerrit/plugins/codeowners/validation/CodeOwnerConfigValidator.java
@@ -31,6 +31,7 @@
import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.plugins.codeowners.backend.ChangedFiles;
import com.google.gerrit.plugins.codeowners.backend.CodeOwnerBackend;
@@ -53,6 +54,7 @@
import com.google.gerrit.plugins.codeowners.util.JgitPath;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.PatchSetUtil;
+import com.google.gerrit.server.config.UrlFormatter;
import com.google.gerrit.server.events.CommitReceivedEvent;
import com.google.gerrit.server.events.RefReceivedEvent;
import com.google.gerrit.server.git.CodeReviewCommit;
@@ -151,6 +153,7 @@
private final IdentifiedUser.GenericFactory userFactory;
private final SkipCodeOwnerConfigValidationPushOption skipCodeOwnerConfigValidationPushOption;
private final CodeOwnerMetrics codeOwnerMetrics;
+ private final DynamicItem<UrlFormatter> urlFormatter;
@Inject
CodeOwnerConfigValidator(
@@ -165,7 +168,8 @@
PatchSetUtil patchSetUtil,
IdentifiedUser.GenericFactory userFactory,
SkipCodeOwnerConfigValidationPushOption skipCodeOwnerConfigValidationPushOption,
- CodeOwnerMetrics codeOwnerMetrics) {
+ CodeOwnerMetrics codeOwnerMetrics,
+ DynamicItem<UrlFormatter> urlFormatter) {
this.pluginName = pluginName;
this.codeOwnersPluginConfiguration = codeOwnersPluginConfiguration;
this.repoManager = repoManager;
@@ -178,6 +182,7 @@
this.userFactory = userFactory;
this.skipCodeOwnerConfigValidationPushOption = skipCodeOwnerConfigValidationPushOption;
this.codeOwnerMetrics = codeOwnerMetrics;
+ this.urlFormatter = urlFormatter;
}
@Override
@@ -521,6 +526,7 @@
// validate the code owner config files
return Optional.of(
ValidationResult.create(
+ urlFormatter,
pluginName,
codeOwnerConfigFilesToValidate.stream()
.flatMap(
@@ -1326,12 +1332,23 @@
}
static ValidationResult create(
- String pluginName, Stream<CommitValidationMessage> validationMessagesStream) {
+ DynamicItem<UrlFormatter> urlFormatter,
+ String pluginName,
+ Stream<CommitValidationMessage> validationMessagesStream) {
ImmutableList<CommitValidationMessage> validationMessages =
validationMessagesStream.collect(toImmutableList());
+ Optional<String> helpPage =
+ urlFormatter
+ .get()
+ .getPluginDocUrl(
+ pluginName, "validation.html", "validation-checks-for-code-owner-config-files");
return new AutoValue_CodeOwnerConfigValidator_ValidationResult(
pluginName,
- validationMessages.isEmpty() ? NO_ISSUES_MSG : INVALID_MSG,
+ validationMessages.isEmpty()
+ ? NO_ISSUES_MSG
+ : (helpPage.isPresent()
+ ? String.format("%s (see %s for help)", INVALID_MSG, helpPage.get())
+ : INVALID_MSG),
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 0800de1..51b52da 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnerConfigValidatorIT.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnerConfigValidatorIT.java
@@ -48,6 +48,7 @@
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.ChangeInput;
import com.google.gerrit.extensions.common.MergeInput;
+import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.restapi.MergeConflictException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.git.ObjectIds;
@@ -68,6 +69,7 @@
import com.google.gerrit.plugins.codeowners.common.CodeOwnerConfigValidationPolicy;
import com.google.gerrit.plugins.codeowners.validation.SkipCodeOwnerConfigValidationCapability;
import com.google.gerrit.plugins.codeowners.validation.SkipCodeOwnerConfigValidationPushOption;
+import com.google.gerrit.server.config.UrlFormatter;
import com.google.gerrit.server.submit.IntegrationConflictException;
import com.google.inject.Inject;
import java.nio.file.Path;
@@ -92,6 +94,7 @@
@Inject private RequestScopeOperations requestScopeOperations;
@Inject private ProjectOperations projectOperations;
+ @Inject private DynamicItem<UrlFormatter> urlFormatter;
private FindOwnersCodeOwnerConfigParser findOwnersCodeOwnerConfigParser;
private ProtoCodeOwnerConfigParser protoCodeOwnerConfigParser;
@@ -731,9 +734,11 @@
.isEqualTo(
String.format(
"Failed to submit 1 change due to the following problems:\n"
- + "Change %d: [code-owners] invalid code owner config files:\n"
+ + "Change %d: [code-owners] invalid code owner config files"
+ + " (see %s for help):\n"
+ " ERROR: code owner email '%s' in '%s' cannot be resolved for %s",
r.getChange().getId().get(),
+ getHelpPage(),
unknownEmail,
codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
identifiedUserFactory.create(admin.id()).getLoggableName()));
@@ -2521,8 +2526,9 @@
.hasMessageThat()
.isEqualTo(
String.format(
- "[code-owners] invalid code owner config files:\n"
+ "[code-owners] invalid code owner config files (see %s for help):\n"
+ " [code-owners] code owner email '%s' in '%s' cannot be resolved for %s",
+ getHelpPage(),
unknownEmail,
codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
admin.username()));
@@ -2613,10 +2619,11 @@
.isEqualTo(
String.format(
"Validation for creation of ref 'refs/heads/new' in project %s failed:\n"
- + "[code-owners] invalid code owner config files:\n"
+ + "[code-owners] invalid code owner config files (see %s for help):\n"
+ " ERROR: code owner email '%s' in '%s' cannot be resolved for %s\n"
+ " ERROR: code owner email '%s' in '%s' cannot be resolved for %s",
project,
+ getHelpPage(),
unknownEmail,
codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey1).getFilePath(),
identifiedUserFactory.create(admin.id()).getLoggableName(),
@@ -2648,7 +2655,9 @@
() -> gApi.projects().name(project.get()).branch(input.ref).create(input));
assertThat(exception)
.hasMessageThat()
- .contains("[code-owners] invalid code owner config files:");
+ .contains(
+ String.format(
+ "[code-owners] invalid code owner config files (see %s for help):", getHelpPage()));
input.validationOptions =
ImmutableMap.of(
@@ -2743,10 +2752,11 @@
"refs/heads/new",
String.format(
"Validation for creation of ref 'refs/heads/new' in project %s failed:\n"
- + "[code-owners] invalid code owner config files:\n"
+ + "[code-owners] invalid code owner config files (see %s for help):\n"
+ " ERROR: code owner email '%s' in '%s' cannot be resolved for %s\n"
+ " ERROR: code owner email '%s' in '%s' cannot be resolved for %s",
project,
+ getHelpPage(),
unknownEmail,
codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey1).getFilePath(),
identifiedUserFactory.create(admin.id()).getLoggableName(),
@@ -2785,9 +2795,10 @@
"refs/heads/new",
String.format(
"Validation for creation of ref 'refs/heads/new' in project %s failed:\n"
- + "[code-owners] invalid code owner config files:\n"
+ + "[code-owners] invalid code owner config files (see %s for help):\n"
+ " ERROR: code owner email '%s' in '%s' cannot be resolved for %s",
project,
+ getHelpPage(),
unknownEmail,
codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
identifiedUserFactory.create(admin.id()).getLoggableName()));
@@ -2905,9 +2916,10 @@
assertThat(r.getMessages())
.contains(
String.format(
- "ERROR: [code-owners] invalid code owner config files\n"
+ "ERROR: [code-owners] invalid code owner config files (see %s for help)\n"
+ "ERROR: [code-owners] code owner email '%s' in '%s' cannot be resolved for"
+ " %s",
+ getHelpPage(),
unknownEmail,
codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
identifiedUserFactory.create(admin.id()).getLoggableName()));
@@ -3316,4 +3328,10 @@
pushResult.assertNotMessage("warning");
pushResult.assertNotMessage("hint");
}
+
+ private String getHelpPage() {
+ return urlFormatter.get().getWebUrl().get()
+ + "plugins/code-owners/Documentation/validation.html"
+ + "#validation-checks-for-code-owner-config-files";
+ }
}
diff --git a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnerConfigValidatorOnSubmitIT.java b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnerConfigValidatorOnSubmitIT.java
index b92d0e0..75843f3 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnerConfigValidatorOnSubmitIT.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnerConfigValidatorOnSubmitIT.java
@@ -26,6 +26,7 @@
import com.google.gerrit.acceptance.testsuite.request.RequestScopeOperations;
import com.google.gerrit.entities.Permission;
import com.google.gerrit.extensions.client.ChangeStatus;
+import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.plugins.codeowners.acceptance.AbstractCodeOwnersIT;
import com.google.gerrit.plugins.codeowners.backend.CodeOwnerConfig;
@@ -35,6 +36,7 @@
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.server.config.UrlFormatter;
import com.google.inject.Inject;
import org.eclipse.jgit.lib.ObjectId;
import org.junit.Before;
@@ -50,6 +52,7 @@
@Inject private RequestScopeOperations requestScopeOperations;
@Inject private ProjectOperations projectOperations;
+ @Inject private DynamicItem<UrlFormatter> urlFormatter;
private FindOwnersCodeOwnerConfigParser findOwnersCodeOwnerConfigParser;
private ProtoCodeOwnerConfigParser protoCodeOwnerConfigParser;
@@ -126,9 +129,11 @@
.isEqualTo(
String.format(
"Failed to submit 1 change due to the following problems:\n"
- + "Change %d: [code-owners] invalid code owner config files:\n"
+ + "Change %d: [code-owners] invalid code owner config files"
+ + " (see %s for help):\n"
+ " ERROR: code owner email '%s' in '%s' cannot be resolved for %s",
r.getChange().getId().get(),
+ getHelpPage(),
unknownEmail,
codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
identifiedUserFactory.create(admin.id()).getLoggableName()));
@@ -181,9 +186,11 @@
.isEqualTo(
String.format(
"Failed to submit 1 change due to the following problems:\n"
- + "Change %d: [code-owners] invalid code owner config files:\n"
+ + "Change %d: [code-owners] invalid code owner config files"
+ + " (see %s for help):\n"
+ " ERROR: code owner email '%s' in '%s' cannot be resolved for %s",
r.getChange().getId().get(),
+ getHelpPage(),
admin.email(),
codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
identifiedUserFactory.create(user2.id()).getLoggableName()));
@@ -309,9 +316,11 @@
.isEqualTo(
String.format(
"Failed to submit 1 change due to the following problems:\n"
- + "Change %d: [code-owners] invalid code owner config files:\n"
+ + "Change %d: [code-owners] invalid code owner config files"
+ + " (see %s for help):\n"
+ " ERROR: code owner email '%s' in '%s' cannot be resolved for %s",
r.getChange().getId().get(),
+ getHelpPage(),
unknownEmail,
codeOwnerConfigOperations.codeOwnerConfig(codeOwnerConfigKey).getFilePath(),
identifiedUserFactory.create(admin.id()).getLoggableName()));
@@ -375,4 +384,10 @@
"unknown code owner backend: %s",
backendConfig.getDefaultBackend().getClass().getName()));
}
+
+ private String getHelpPage() {
+ return urlFormatter.get().getWebUrl().get()
+ + "plugins/code-owners/Documentation/validation.html"
+ + "#validation-checks-for-code-owner-config-files";
+ }
}