Merge changes Ide146a98,Ic61022af
* changes:
Test that message on post review is extended if comments are added
Add capability that allows to call the CheckCodeOwner REST endpoint
diff --git a/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwner.java b/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwner.java
index 1bc41d7..86adb2b 100644
--- a/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwner.java
+++ b/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwner.java
@@ -37,7 +37,6 @@
import com.google.gerrit.plugins.codeowners.backend.PathCodeOwnersResult;
import com.google.gerrit.plugins.codeowners.config.CodeOwnersPluginConfiguration;
import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.project.BranchResource;
@@ -61,6 +60,7 @@
* /projects/<project-name>/branches/<branch-name>/code_owners.check} requests.
*/
public class CheckCodeOwner implements RestReadView<BranchResource> {
+ private final CheckCodeOwnerCapability checkCodeOwnerCapability;
private final PermissionBackend permissionBackend;
private final CodeOwnersPluginConfiguration codeOwnersPluginConfiguration;
private final CodeOwnerConfigHierarchy codeOwnerConfigHierarchy;
@@ -76,6 +76,7 @@
@Inject
public CheckCodeOwner(
+ CheckCodeOwnerCapability checkCodeOwnerCapability,
PermissionBackend permissionBackend,
CodeOwnersPluginConfiguration codeOwnersPluginConfiguration,
CodeOwnerConfigHierarchy codeOwnerConfigHierarchy,
@@ -83,6 +84,7 @@
Provider<CodeOwnerResolver> codeOwnerResolverProvider,
CodeOwners codeOwners,
AccountsCollection accountsCollection) {
+ this.checkCodeOwnerCapability = checkCodeOwnerCapability;
this.permissionBackend = permissionBackend;
this.codeOwnersPluginConfiguration = codeOwnersPluginConfiguration;
this.codeOwnerConfigHierarchy = codeOwnerConfigHierarchy;
@@ -115,7 +117,7 @@
public Response<CodeOwnerCheckInfo> apply(BranchResource branchResource)
throws BadRequestException, AuthException, IOException, ConfigInvalidException,
PermissionBackendException {
- permissionBackend.currentUser().check(GlobalPermission.ADMINISTRATE_SERVER);
+ permissionBackend.currentUser().check(checkCodeOwnerCapability.getPermission());
validateInput();
diff --git a/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwnerCapability.java b/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwnerCapability.java
new file mode 100644
index 0000000..a127815
--- /dev/null
+++ b/java/com/google/gerrit/plugins/codeowners/restapi/CheckCodeOwnerCapability.java
@@ -0,0 +1,43 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.plugins.codeowners.restapi;
+
+import com.google.gerrit.extensions.annotations.PluginName;
+import com.google.gerrit.extensions.api.access.PluginPermission;
+import com.google.gerrit.extensions.config.CapabilityDefinition;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/** Global capability that allows a user to call the {@link CheckCodeOwner} REST endpoint. */
+@Singleton
+public class CheckCodeOwnerCapability extends CapabilityDefinition {
+ public static final String ID = "checkCodeOwner";
+
+ private final String pluginName;
+
+ @Inject
+ CheckCodeOwnerCapability(@PluginName String pluginName) {
+ this.pluginName = pluginName;
+ }
+
+ @Override
+ public String getDescription() {
+ return "Check Code Owner";
+ }
+
+ public PluginPermission getPermission() {
+ return new PluginPermission(pluginName, ID);
+ }
+}
diff --git a/java/com/google/gerrit/plugins/codeowners/restapi/RestApiModule.java b/java/com/google/gerrit/plugins/codeowners/restapi/RestApiModule.java
index 68d057e..df4e6f7 100644
--- a/java/com/google/gerrit/plugins/codeowners/restapi/RestApiModule.java
+++ b/java/com/google/gerrit/plugins/codeowners/restapi/RestApiModule.java
@@ -19,6 +19,8 @@
import static com.google.gerrit.server.project.BranchResource.BRANCH_KIND;
import static com.google.gerrit.server.project.ProjectResource.PROJECT_KIND;
+import com.google.gerrit.extensions.annotations.Exports;
+import com.google.gerrit.extensions.config.CapabilityDefinition;
import com.google.gerrit.extensions.registration.DynamicMap;
/** Guice module that binds the REST API for the code-owners plugin. */
@@ -32,6 +34,10 @@
get(BRANCH_KIND, "code_owners.config_files").to(GetCodeOwnerConfigFiles.class);
get(BRANCH_KIND, "code_owners.branch_config").to(GetCodeOwnerBranchConfig.class);
post(BRANCH_KIND, "code_owners.rename").to(RenameEmail.class);
+
+ bind(CapabilityDefinition.class)
+ .annotatedWith(Exports.named(CheckCodeOwnerCapability.ID))
+ .to(CheckCodeOwnerCapability.class);
get(BRANCH_KIND, "code_owners.check").to(CheckCodeOwner.class);
factory(CodeOwnerJson.Factory.class);
diff --git a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CheckCodeOwnerIT.java b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CheckCodeOwnerIT.java
index ea4fc3a..fc5fddf 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CheckCodeOwnerIT.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CheckCodeOwnerIT.java
@@ -16,7 +16,9 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.TruthJUnit.assume;
+import static com.google.gerrit.acceptance.testsuite.project.TestProjectUpdate.allowCapability;
import static com.google.gerrit.plugins.codeowners.testing.CodeOwnerCheckInfoSubject.assertThat;
+import static com.google.gerrit.server.group.SystemGroupBackend.REGISTERED_USERS;
import static com.google.gerrit.testing.GerritJUnit.assertThrows;
import com.google.gerrit.acceptance.TestAccount;
@@ -40,6 +42,7 @@
import com.google.gerrit.plugins.codeowners.backend.findowners.FindOwnersBackend;
import com.google.gerrit.plugins.codeowners.backend.proto.ProtoBackend;
import com.google.gerrit.plugins.codeowners.config.BackendConfig;
+import com.google.gerrit.plugins.codeowners.restapi.CheckCodeOwnerCapability;
import com.google.gerrit.server.ServerInitiated;
import com.google.gerrit.server.account.AccountsUpdate;
import com.google.gerrit.server.account.externalids.ExternalId;
@@ -87,15 +90,33 @@
}
@Test
- public void requiresCallerToBeAdmin() throws Exception {
+ public void requiresCallerToBeAdminOrHaveTheCheckCodeOwnerCapability() throws Exception {
requestScopeOperations.setApiUser(user.id());
AuthException authException =
assertThrows(AuthException.class, () -> checkCodeOwner(ROOT_PATH, user.email()));
- assertThat(authException).hasMessageThat().isEqualTo("administrate server not permitted");
+ assertThat(authException)
+ .hasMessageThat()
+ .isEqualTo(
+ String.format("%s for plugin code-owners not permitted", CheckCodeOwnerCapability.ID));
}
@Test
- public void checkCodeOwner() throws Exception {
+ public void checkCodeOwner_byAdmin() throws Exception {
+ testCheckCodeOwner();
+ }
+
+ @Test
+ public void checkCodeOwner_byUserThatHasTheCheckCodeOwnerCapability() throws Exception {
+ projectOperations
+ .allProjectsForUpdate()
+ .add(allowCapability("code-owners-" + CheckCodeOwnerCapability.ID).group(REGISTERED_USERS))
+ .update();
+
+ requestScopeOperations.setApiUser(user.id());
+ testCheckCodeOwner();
+ }
+
+ private void testCheckCodeOwner() throws Exception {
TestAccount codeOwner =
accountCreator.create(
"codeOwner", "codeOwner@example.com", "Code Owner", /* displayName= */ null);
diff --git a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnersOnPostReviewIT.java b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnersOnPostReviewIT.java
index d899268..9160b32 100644
--- a/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnersOnPostReviewIT.java
+++ b/javatests/com/google/gerrit/plugins/codeowners/acceptance/api/CodeOwnersOnPostReviewIT.java
@@ -18,12 +18,14 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
import com.google.gerrit.acceptance.config.GerritConfig;
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.common.ChangeMessageInfo;
import com.google.gerrit.extensions.common.LabelDefinitionInput;
import com.google.gerrit.plugins.codeowners.acceptance.AbstractCodeOwnersIT;
import java.util.Collection;
+import java.util.HashMap;
import org.junit.Test;
/**
@@ -586,4 +588,39 @@
Collection<ChangeMessageInfo> messages = gApi.changes().id(changeId).get().messages;
assertThat(Iterables.getLast(messages).message).isEqualTo("Patch Set 1: Code-Review+1");
}
+
+ @Test
+ public void changeMessageListsNewlyApprovedPathsIfCommentsAreAddedOnPostReview()
+ throws Exception {
+ codeOwnerConfigOperations
+ .newCodeOwnerConfig()
+ .project(project)
+ .branch("master")
+ .folderPath("/foo/")
+ .addCodeOwnerEmail(admin.email())
+ .create();
+
+ String path = "foo/bar.baz";
+ String changeId = createChange("Test Change", path, "file content").getChangeId();
+
+ ReviewInput.CommentInput commentInput = new ReviewInput.CommentInput();
+ commentInput.line = 1;
+ commentInput.message = "some comment";
+ commentInput.path = path;
+ ReviewInput reviewInput = ReviewInput.recommend();
+ reviewInput.comments = reviewInput.comments = new HashMap<>();
+ reviewInput.comments.put(commentInput.path, Lists.newArrayList(commentInput));
+ gApi.changes().id(changeId).current().review(reviewInput);
+
+ Collection<ChangeMessageInfo> messages = gApi.changes().id(changeId).get().messages;
+ assertThat(Iterables.getLast(messages).message)
+ .isEqualTo(
+ String.format(
+ "Patch Set 1: Code-Review+1\n\n"
+ + "(1 comment)\n\n"
+ + "By voting Code-Review+1 the following files are now code-owner approved by"
+ + " %s:\n"
+ + "* %s\n",
+ admin.fullName(), path));
+ }
}
diff --git a/resources/Documentation/rest-api.md b/resources/Documentation/rest-api.md
index 8902d36..c93adc0 100644
--- a/resources/Documentation/rest-api.md
+++ b/resources/Documentation/rest-api.md
@@ -232,8 +232,8 @@
| `path` | mandatory | Path for which the code ownership should be checked.
| `user` | optional | User for which the code owner visibility should be checked. If not specified the code owner visibility is not checked. Can be used to investigate why a code owner is not shown/suggested to this user.
-Requires that the caller has the [Administrate
-Server](../../../Documentation/access-control.html#capability_administrateServer)
+Requires that the caller has the [Check Code Owner](#checkCodeOwner) or the
+[Administrate Server](../../../Documentation/access-control.html#capability_administrateServer)
global capability.
This REST endpoint is intended to investigate code owner configurations that do
@@ -841,6 +841,19 @@
---
+## <a id="capabilities">Capabilities
+
+### <a id="checkCodeOwner">Check Code Owner
+
+Global capability that allows a user to call the [Check Code
+Owner](#check-code-owner) REST endpoint.
+
+Assigning this capability allows users to inspect code ownerships. This may
+reveal accounts and secondary emails to the user that the user cannot see
+otherwise. Hence this capability should only ge granted to trusted users.
+
+Administrators have this capability implicitly assigned.
+
Back to [@PLUGIN@ documentation index](index.html)
Part of [Gerrit Code Review](../../../Documentation/index.html)