Add the rest-api endpoint for creating a change for labels update. This change additionally refactor PostLabels class - the extracted code will be used for a similar endpoints for submit requirements. Release-Notes: a new endpoint for creating a change for labels update is added. Google-Bug-Id: b/330832714 Change-Id: I6614f4b437088116ff3609fc481bc7195aba338b
diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt index a21ed8e..8d30728 100644 --- a/Documentation/rest-api-projects.txt +++ b/Documentation/rest-api-projects.txt
@@ -3648,6 +3648,82 @@ HTTP/1.1 200 OK ---- +[[create-labels-change]] +=== Create Labels Change for review. +-- +'POST /projects/link:#project-name[\{project-name\}]/labels:review' +-- + +Creates/updates/deletes multiple label definitions in this project at once. + +This takes the same input as link:#batch-update-labels[Batch Updates Labels], +but creates a pending change for review. Like +link:#create-change[Create Change], it returns a link:#change-info[ChangeInfo] +entity describing the resulting change. + +.Request +---- + POST /projects/testproj/config:review HTTP/1.0 + Content-Type: application/json; charset=UTF-8 + + { + "commit_message": "Update Labels", + "delete": [ + "Old-Review", + "Unused-Review" + ], + "create": [ + { + "name": "Foo-Review", + "values": { + " 0": "No score", + "-1": "I would prefer this is not submitted as is", + "-2": "This shall not be submitted", + "+1": "Looks good to me, but someone else must approve", + "+2": "Looks good to me, approved" + } + ], + "update:" { + "Bar-Review": { + "function": "MaxWithBlock" + }, + "Baz-Review": { + "copy_condition": "is:MIN" + } + } + } +---- + +.Response +---- + HTTP/1.1 200 OK + Content-Type: application/json; charset=UTF-8 + + )]}' + { + "id": "testproj~refs%2Fmeta%2Fconfig~Ieaf185bf90a1fc3b58461e399385e158a20b31a2", + "project": "testproj", + "branch": "refs/meta/config", + "hashtags": [], + "change_id": "Ieaf185bf90a1fc3b58461e399385e158a20b31a2", + "subject": "Review access change", + "status": "NEW", + "created": "2017-09-07 14:31:11.852000000", + "updated": "2017-09-07 14:31:11.852000000", + "submit_type": "CHERRY_PICK", + "mergeable": true, + "insertions": 2, + "deletions": 0, + "unresolved_comment_count": 0, + "has_review_started": true, + "_number": 7, + "owner": { + "_account_id": 1000000 + } + } +---- + + [[submit-requirement-endpoints]] == Submit Requirement Endpoints
diff --git a/java/com/google/gerrit/extensions/api/projects/ProjectApi.java b/java/com/google/gerrit/extensions/api/projects/ProjectApi.java index 697561b..fa78fdb 100644 --- a/java/com/google/gerrit/extensions/api/projects/ProjectApi.java +++ b/java/com/google/gerrit/extensions/api/projects/ProjectApi.java
@@ -287,6 +287,10 @@ */ void labels(BatchLabelInput input) throws RestApiException; + /** Same as {@link #labels(BatchLabelInput)}, but creates a change with required updates. */ + @CanIgnoreReturnValue + ChangeInfo labelsReview(BatchLabelInput input) throws RestApiException; + /** * A default implementation which allows source compatibility when adding new methods to the * interface. @@ -497,5 +501,10 @@ public void labels(BatchLabelInput input) throws RestApiException { throw new NotImplementedException(); } + + @Override + public ChangeInfo labelsReview(BatchLabelInput input) throws RestApiException { + throw new NotImplementedException(); + } } }
diff --git a/java/com/google/gerrit/extensions/common/AbstractBatchInput.java b/java/com/google/gerrit/extensions/common/AbstractBatchInput.java new file mode 100644 index 0000000..b872b18 --- /dev/null +++ b/java/com/google/gerrit/extensions/common/AbstractBatchInput.java
@@ -0,0 +1,26 @@ +// Copyright (C) 2024 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.extensions.common; + +import java.util.List; +import java.util.Map; + +/** Input for the REST API that describes additions, updates and deletions items in a collection. */ +public abstract class AbstractBatchInput<T> { + public String commitMessage; + public List<String> delete; + public List<T> create; + public Map<String, T> update; +}
diff --git a/java/com/google/gerrit/extensions/common/BatchLabelInput.java b/java/com/google/gerrit/extensions/common/BatchLabelInput.java index eb4c581..aa91314 100644 --- a/java/com/google/gerrit/extensions/common/BatchLabelInput.java +++ b/java/com/google/gerrit/extensions/common/BatchLabelInput.java
@@ -14,13 +14,5 @@ package com.google.gerrit.extensions.common; -import java.util.List; -import java.util.Map; - /** Input for the REST API that describes additions, updates and deletions of label definitions. */ -public class BatchLabelInput { - public String commitMessage; - public List<String> delete; - public List<LabelDefinitionInput> create; - public Map<String, LabelDefinitionInput> update; -} +public class BatchLabelInput extends AbstractBatchInput<LabelDefinitionInput> {}
diff --git a/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java b/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java index 38b2d46..c817b93 100644 --- a/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java +++ b/java/com/google/gerrit/server/api/projects/ProjectApiImpl.java
@@ -86,6 +86,7 @@ import com.google.gerrit.server.restapi.project.ListSubmitRequirements; import com.google.gerrit.server.restapi.project.ListTags; import com.google.gerrit.server.restapi.project.PostLabels; +import com.google.gerrit.server.restapi.project.PostLabelsReview; import com.google.gerrit.server.restapi.project.ProjectsCollection; import com.google.gerrit.server.restapi.project.PutConfig; import com.google.gerrit.server.restapi.project.PutConfigReview; @@ -149,6 +150,7 @@ private final Provider<ListLabels> listLabels; private final Provider<ListSubmitRequirements> listSubmitRequirements; private final PostLabels postLabels; + private final PostLabelsReview postLabelsReview; private final LabelApiImpl.Factory labelApi; private final SubmitRequirementApiImpl.Factory submitRequirementApi; @@ -191,6 +193,7 @@ Provider<ListLabels> listLabels, Provider<ListSubmitRequirements> listSubmitRequirements, PostLabels postLabels, + PostLabelsReview postLabelsReview, LabelApiImpl.Factory labelApi, SubmitRequirementApiImpl.Factory submitRequirementApi, @Assisted ProjectResource project) { @@ -233,6 +236,7 @@ listLabels, listSubmitRequirements, postLabels, + postLabelsReview, labelApi, submitRequirementApi, null); @@ -277,6 +281,7 @@ Provider<ListLabels> listLabels, Provider<ListSubmitRequirements> listSubmitRequirements, PostLabels postLabels, + PostLabelsReview postLabelsReview, LabelApiImpl.Factory labelApi, SubmitRequirementApiImpl.Factory submitRequirementApi, @Assisted String name) { @@ -319,6 +324,7 @@ listLabels, listSubmitRequirements, postLabels, + postLabelsReview, labelApi, submitRequirementApi, name); @@ -363,6 +369,7 @@ Provider<ListLabels> listLabels, Provider<ListSubmitRequirements> listSubmitRequirements, PostLabels postLabels, + PostLabelsReview postLabelsReview, LabelApiImpl.Factory labelApi, SubmitRequirementApiImpl.Factory submitRequirementApi, String name) { @@ -405,6 +412,7 @@ this.listLabels = listLabels; this.listSubmitRequirements = listSubmitRequirements; this.postLabels = postLabels; + this.postLabelsReview = postLabelsReview; this.labelApi = labelApi; this.submitRequirementApi = submitRequirementApi; } @@ -831,4 +839,13 @@ throw asRestApiException("Cannot update labels", e); } } + + @Override + public ChangeInfo labelsReview(BatchLabelInput input) throws RestApiException { + try { + return postLabelsReview.apply(checkExists(), input).value(); + } catch (Exception e) { + throw asRestApiException("Cannot create change for labels update", e); + } + } }
diff --git a/java/com/google/gerrit/server/restapi/project/AbstractPostCollection.java b/java/com/google/gerrit/server/restapi/project/AbstractPostCollection.java new file mode 100644 index 0000000..aaf8d02 --- /dev/null +++ b/java/com/google/gerrit/server/restapi/project/AbstractPostCollection.java
@@ -0,0 +1,116 @@ +// Copyright (C) 2024 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.server.restapi.project; + +import com.google.common.base.Strings; +import com.google.gerrit.extensions.common.AbstractBatchInput; +import com.google.gerrit.extensions.restapi.AuthException; +import com.google.gerrit.extensions.restapi.BadRequestException; +import com.google.gerrit.extensions.restapi.ResourceConflictException; +import com.google.gerrit.extensions.restapi.Response; +import com.google.gerrit.extensions.restapi.RestCollectionModifyView; +import com.google.gerrit.extensions.restapi.RestResource; +import com.google.gerrit.extensions.restapi.UnprocessableEntityException; +import com.google.gerrit.server.CurrentUser; +import com.google.gerrit.server.permissions.PermissionBackendException; +import com.google.gerrit.server.project.ProjectConfig; +import com.google.gerrit.server.project.ProjectResource; +import com.google.inject.Provider; +import java.io.IOException; +import org.eclipse.jgit.errors.ConfigInvalidException; + +/** Base class for a rest API batch update. */ +public abstract class AbstractPostCollection< + TId, + TResource extends RestResource, + TItemInput, + TBatchInput extends AbstractBatchInput<TItemInput>> + implements RestCollectionModifyView<ProjectResource, TResource, TBatchInput> { + private final Provider<CurrentUser> user; + private final RepoMetaDataUpdater updater; + + public AbstractPostCollection(RepoMetaDataUpdater updater, Provider<CurrentUser> user) { + this.user = user; + this.updater = updater; + } + + @Override + public Response<?> apply(ProjectResource rsrc, TBatchInput input) + throws AuthException, UnprocessableEntityException, PermissionBackendException, IOException, + ConfigInvalidException, BadRequestException, ResourceConflictException { + if (!user.get().isIdentifiedUser()) { + throw new AuthException("Authentication required"); + } + if (input == null) { + return Response.ok(""); + } + + try (var configUpdater = + updater.configUpdater(rsrc.getNameKey(), input.commitMessage, defaultCommitMessage())) { + ProjectConfig config = configUpdater.getConfig(); + if (updateProjectConfig(config, input)) { + configUpdater.commitConfigUpdate(); + } + } + return Response.ok(""); + } + + public boolean updateProjectConfig(ProjectConfig config, AbstractBatchInput<TItemInput> input) + throws UnprocessableEntityException, ResourceConflictException, BadRequestException { + boolean configChanged = false; + if (input.delete != null && !input.delete.isEmpty()) { + for (String name : input.delete) { + if (Strings.isNullOrEmpty(name)) { + throw new BadRequestException("The delete property contains null or empty name"); + } + deleteItem(config, name.trim()); + } + configChanged = true; + } + if (input.create != null && !input.create.isEmpty()) { + for (TItemInput labelInput : input.create) { + if (labelInput == null) { + throw new BadRequestException("The create property contains a null item"); + } + createItem(config, labelInput); + } + configChanged = true; + } + if (input.update != null && !input.update.isEmpty()) { + for (var e : input.update.entrySet()) { + if (e.getKey() == null) { + throw new BadRequestException("The update property contains a null key"); + } + if (e.getValue() == null) { + throw new BadRequestException("The update property contains a null value"); + } + configChanged |= updateItem(config, e.getKey().trim(), e.getValue()); + } + } + return configChanged; + } + + /** Provides default commit message when user doesn't specify one in the input. */ + public abstract String defaultCommitMessage(); + + protected abstract boolean updateItem(ProjectConfig config, String name, TItemInput resource) + throws BadRequestException, ResourceConflictException, UnprocessableEntityException; + + protected abstract void createItem(ProjectConfig config, TItemInput resource) + throws BadRequestException, ResourceConflictException, UnprocessableEntityException; + + protected abstract void deleteItem(ProjectConfig config, String name) + throws BadRequestException, ResourceConflictException, UnprocessableEntityException; +}
diff --git a/java/com/google/gerrit/server/restapi/project/PostLabels.java b/java/com/google/gerrit/server/restapi/project/PostLabels.java index 3616f4b..7f502ff 100644 --- a/java/com/google/gerrit/server/restapi/project/PostLabels.java +++ b/java/com/google/gerrit/server/restapi/project/PostLabels.java
@@ -14,138 +14,76 @@ package com.google.gerrit.server.restapi.project; -import com.google.common.base.Strings; import com.google.gerrit.entities.LabelType; import com.google.gerrit.extensions.common.BatchLabelInput; import com.google.gerrit.extensions.common.LabelDefinitionInput; -import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.BadRequestException; import com.google.gerrit.extensions.restapi.ResourceConflictException; -import com.google.gerrit.extensions.restapi.Response; -import com.google.gerrit.extensions.restapi.RestCollectionModifyView; import com.google.gerrit.extensions.restapi.UnprocessableEntityException; import com.google.gerrit.server.CurrentUser; -import com.google.gerrit.server.git.meta.MetaDataUpdate; -import com.google.gerrit.server.permissions.PermissionBackend; -import com.google.gerrit.server.permissions.PermissionBackendException; -import com.google.gerrit.server.permissions.ProjectPermission; import com.google.gerrit.server.project.LabelResource; -import com.google.gerrit.server.project.ProjectCache; import com.google.gerrit.server.project.ProjectConfig; -import com.google.gerrit.server.project.ProjectResource; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; -import java.io.IOException; -import java.util.Map; -import org.eclipse.jgit.errors.ConfigInvalidException; /** REST endpoint that allows to add, update and delete label definitions in a batch. */ @Singleton public class PostLabels - implements RestCollectionModifyView<ProjectResource, LabelResource, BatchLabelInput> { - private final Provider<CurrentUser> user; - private final PermissionBackend permissionBackend; - private final MetaDataUpdate.User updateFactory; - private final ProjectConfig.Factory projectConfigFactory; + extends AbstractPostCollection<String, LabelResource, LabelDefinitionInput, BatchLabelInput> { private final DeleteLabel deleteLabel; private final CreateLabel createLabel; private final SetLabel setLabel; - private final ProjectCache projectCache; @Inject public PostLabels( Provider<CurrentUser> user, - PermissionBackend permissionBackend, - MetaDataUpdate.User updateFactory, - ProjectConfig.Factory projectConfigFactory, DeleteLabel deleteLabel, CreateLabel createLabel, SetLabel setLabel, - ProjectCache projectCache) { - this.user = user; - this.permissionBackend = permissionBackend; - this.updateFactory = updateFactory; - this.projectConfigFactory = projectConfigFactory; + RepoMetaDataUpdater updater) { + super(updater, user); this.deleteLabel = deleteLabel; this.createLabel = createLabel; this.setLabel = setLabel; - this.projectCache = projectCache; } @Override - public Response<?> apply(ProjectResource rsrc, BatchLabelInput input) - throws AuthException, UnprocessableEntityException, PermissionBackendException, IOException, - ConfigInvalidException, BadRequestException, ResourceConflictException { - if (!user.get().isIdentifiedUser()) { - throw new AuthException("Authentication required"); + public String defaultCommitMessage() { + return "Update labels"; + } + + @Override + protected boolean updateItem(ProjectConfig config, String name, LabelDefinitionInput resource) + throws BadRequestException, ResourceConflictException, UnprocessableEntityException { + LabelType labelType = config.getLabelSections().get(name); + if (labelType == null) { + throw new UnprocessableEntityException(String.format("label %s not found", name)); + } + if (resource.commitMessage != null) { + throw new BadRequestException("commit message on label definition input not supported"); } - permissionBackend - .currentUser() - .project(rsrc.getNameKey()) - .check(ProjectPermission.WRITE_CONFIG); + return setLabel.updateLabel(config, labelType, resource); + } - if (input == null) { - input = new BatchLabelInput(); + @Override + protected void createItem(ProjectConfig config, LabelDefinitionInput labelInput) + throws BadRequestException, ResourceConflictException { + if (labelInput.name == null || labelInput.name.trim().isEmpty()) { + throw new BadRequestException("label name is required for new label"); } - - try (MetaDataUpdate md = updateFactory.create(rsrc.getNameKey())) { - boolean dirty = false; - - ProjectConfig config = projectConfigFactory.read(md); - - if (input.delete != null && !input.delete.isEmpty()) { - for (String labelName : input.delete) { - if (!deleteLabel.deleteLabel(config, labelName.trim())) { - throw new UnprocessableEntityException(String.format("label %s not found", labelName)); - } - } - dirty = true; - } - - if (input.create != null && !input.create.isEmpty()) { - for (LabelDefinitionInput labelInput : input.create) { - if (labelInput.name == null || labelInput.name.trim().isEmpty()) { - throw new BadRequestException("label name is required for new label"); - } - if (labelInput.commitMessage != null) { - throw new BadRequestException("commit message on label definition input not supported"); - } - @SuppressWarnings("unused") - var unused = createLabel.createLabel(config, labelInput.name.trim(), labelInput); - } - dirty = true; - } - - if (input.update != null && !input.update.isEmpty()) { - for (Map.Entry<String, LabelDefinitionInput> e : input.update.entrySet()) { - LabelType labelType = config.getLabelSections().get(e.getKey().trim()); - if (labelType == null) { - throw new UnprocessableEntityException(String.format("label %s not found", e.getKey())); - } - if (e.getValue().commitMessage != null) { - throw new BadRequestException("commit message on label definition input not supported"); - } - - if (setLabel.updateLabel(config, labelType, e.getValue())) { - dirty = true; - } - } - } - - if (input.commitMessage != null) { - md.setMessage(Strings.emptyToNull(input.commitMessage.trim())); - } else { - md.setMessage("Update labels"); - } - - if (dirty) { - config.commit(md); - projectCache.evictAndReindex(rsrc.getProjectState().getProject()); - } + if (labelInput.commitMessage != null) { + throw new BadRequestException("commit message on label definition input not supported"); } + @SuppressWarnings("unused") + var unused = createLabel.createLabel(config, labelInput.name.trim(), labelInput); + } - return Response.ok(""); + @Override + protected void deleteItem(ProjectConfig config, String name) throws UnprocessableEntityException { + if (!deleteLabel.deleteLabel(config, name)) { + throw new UnprocessableEntityException(String.format("label %s not found", name)); + } } }
diff --git a/java/com/google/gerrit/server/restapi/project/PostLabelsReview.java b/java/com/google/gerrit/server/restapi/project/PostLabelsReview.java new file mode 100644 index 0000000..7c0936f --- /dev/null +++ b/java/com/google/gerrit/server/restapi/project/PostLabelsReview.java
@@ -0,0 +1,56 @@ +// Copyright (C) 2024 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.server.restapi.project; + +import com.google.gerrit.extensions.common.BatchLabelInput; +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.restapi.Response; +import com.google.gerrit.extensions.restapi.RestApiException; +import com.google.gerrit.extensions.restapi.RestModifyView; +import com.google.gerrit.server.permissions.PermissionBackendException; +import com.google.gerrit.server.project.ProjectConfig; +import com.google.gerrit.server.project.ProjectResource; +import com.google.gerrit.server.restapi.project.RepoMetaDataUpdater.ConfigChangeCreator; +import com.google.gerrit.server.update.UpdateException; +import com.google.inject.Inject; +import java.io.IOException; +import javax.inject.Singleton; +import org.eclipse.jgit.errors.ConfigInvalidException; + +@Singleton +public class PostLabelsReview implements RestModifyView<ProjectResource, BatchLabelInput> { + + private final RepoMetaDataUpdater repoMetaDataUpdater; + private final PostLabels postLabels; + + @Inject + PostLabelsReview(RepoMetaDataUpdater repoMetaDataUpdater, PostLabels postLabels) { + this.repoMetaDataUpdater = repoMetaDataUpdater; + this.postLabels = postLabels; + } + + @Override + public Response<ChangeInfo> apply(ProjectResource rsrc, BatchLabelInput input) + throws PermissionBackendException, IOException, ConfigInvalidException, UpdateException, + RestApiException { + try (ConfigChangeCreator creator = + repoMetaDataUpdater.configChangeCreator( + rsrc.getNameKey(), input.commitMessage, "Review labels change")) { + ProjectConfig config = creator.getConfig(); + var unused = postLabels.updateProjectConfig(config, input); + return creator.createChange(); + } + } +}
diff --git a/java/com/google/gerrit/server/restapi/project/ProjectRestApiModule.java b/java/com/google/gerrit/server/restapi/project/ProjectRestApiModule.java index c7b905e1d..07e1e72 100644 --- a/java/com/google/gerrit/server/restapi/project/ProjectRestApiModule.java +++ b/java/com/google/gerrit/server/restapi/project/ProjectRestApiModule.java
@@ -103,10 +103,11 @@ child(PROJECT_KIND, "labels").to(LabelsCollection.class); create(LABEL_KIND).to(CreateLabel.class); - postOnCollection(LABEL_KIND).to(PostLabels.class); get(LABEL_KIND).to(GetLabel.class); put(LABEL_KIND).to(SetLabel.class); delete(LABEL_KIND).to(DeleteLabel.class); + postOnCollection(LABEL_KIND).to(PostLabels.class); + post(PROJECT_KIND, "labels:review").to(PostLabelsReview.class); get(PROJECT_KIND, "parent").to(GetParent.class); put(PROJECT_KIND, "parent").to(SetParent.class);
diff --git a/javatests/com/google/gerrit/acceptance/api/project/LabelsReviewIT.java b/javatests/com/google/gerrit/acceptance/api/project/LabelsReviewIT.java new file mode 100644 index 0000000..8e64325 --- /dev/null +++ b/javatests/com/google/gerrit/acceptance/api/project/LabelsReviewIT.java
@@ -0,0 +1,85 @@ +// Copyright (C) 2024 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.acceptance.api.project; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.gerrit.acceptance.AbstractDaemonTest; +import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; +import com.google.gerrit.entities.Project; +import com.google.gerrit.extensions.common.BatchLabelInput; +import com.google.gerrit.extensions.common.ChangeInfo; +import com.google.gerrit.extensions.common.LabelDefinitionInput; +import com.google.inject.Inject; +import org.eclipse.jgit.lib.Config; +import org.junit.Test; + +public class LabelsReviewIT extends AbstractDaemonTest { + @Inject private ProjectOperations projectOperations; + + @Test + public void createLabelsChangeWithDefaultMessage() throws Exception { + Project.NameKey testProject = projectOperations.newProject().create(); + LabelDefinitionInput fooInput = new LabelDefinitionInput(); + fooInput.name = "Foo"; + fooInput.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad"); + BatchLabelInput input = new BatchLabelInput(); + input.create = ImmutableList.of(fooInput); + + ChangeInfo changeInfo = gApi.projects().name(testProject.get()).labelsReview(input); + + assertThat(changeInfo.subject).isEqualTo("Review labels change"); + Config config = new Config(); + config.fromText( + gApi.changes() + .id(changeInfo.changeId) + .revision(1) + .file("project.config") + .content() + .asString()); + assertThat(config.getStringList("label", "Foo", "value")) + .asList() + .containsExactly("+1 Looks Good", "0 Don't Know", "-1 Looks Bad"); + } + + @Test + public void createLabelsChangeWithCustomMessage() throws Exception { + Project.NameKey testProject = projectOperations.newProject().create(); + LabelDefinitionInput fooInput = new LabelDefinitionInput(); + fooInput.name = "Foo"; + fooInput.values = ImmutableMap.of("+1", "Looks Good", " 0", "Don't Know", "-1", "Looks Bad"); + BatchLabelInput input = new BatchLabelInput(); + input.create = ImmutableList.of(fooInput); + String customMessage = "test custom message"; + input.commitMessage = customMessage; + + ChangeInfo changeInfo = gApi.projects().name(testProject.get()).labelsReview(input); + + assertThat(changeInfo.subject).isEqualTo(customMessage); + Config config = new Config(); + config.fromText( + gApi.changes() + .id(changeInfo.changeId) + .revision(1) + .file("project.config") + .content() + .asString()); + assertThat(config.getStringList("label", "Foo", "value")) + .asList() + .containsExactly("+1 Looks Good", "0 Don't Know", "-1 Looks Bad"); + } +}
diff --git a/javatests/com/google/gerrit/acceptance/rest/binding/ProjectsRestApiBindingsIT.java b/javatests/com/google/gerrit/acceptance/rest/binding/ProjectsRestApiBindingsIT.java index f00804d..0cda3ba 100644 --- a/javatests/com/google/gerrit/acceptance/rest/binding/ProjectsRestApiBindingsIT.java +++ b/javatests/com/google/gerrit/acceptance/rest/binding/ProjectsRestApiBindingsIT.java
@@ -83,6 +83,7 @@ RestCall.post("/projects/%s/index.changes"), RestCall.get("/projects/%s/labels"), RestCall.post("/projects/%s/labels/"), + RestCall.post("/projects/%s/labels:review"), RestCall.put("/projects/%s/labels/new-label"), RestCall.get("/projects/%s/parent"), RestCall.put("/projects/%s/parent"),