diff --git a/Documentation/rest-api-changes.txt b/Documentation/rest-api-changes.txt index 97ce2a11fc..0e0a355389 100644 --- a/Documentation/rest-api-changes.txt +++ b/Documentation/rest-api-changes.txt @@ -932,6 +932,46 @@ message is contained in the response body. blocked by Verified ---- +[[publish-draft-change]] +Publish Draft Change +~~~~~~~~~~~~~~~~~~~~ +[verse] +'POST /changes/link:#change-id[\{change-id\}]/publish' + +Publishes a draft change. + +.Request +---- + POST /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/publish HTTP/1.0 + Content-Type: application/json;charset=UTF-8 +---- + +.Response +---- + HTTP/1.1 204 No Content +---- + +[[delete-draft-change]] +Delete Draft Change +~~~~~~~~~~~~~~~~~~~ +[verse] +'DELETE /changes/link:#change-id[\{change-id\}]' +or +'POST /changes/link:#change-id[\{change-id\}]/delete' + +Deletes a draft change. + +.Request +---- + DELETE /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940 HTTP/1.0 + Content-Type: application/json;charset=UTF-8 +---- + +.Response +---- + HTTP/1.1 204 No Content +---- + [[reviewer-endpoints]] Reviewer Endpoints ------------------ @@ -1504,6 +1544,46 @@ message is contained in the response body. "revision 674ac754f91e64a0efb8087e59a176484bd534d1 is not current revision" ---- +[[publish-draft-revision]] +Publish Draft Revision +~~~~~~~~~~~~~~~~~~~~~~ +[verse] +'POST /changes/link:#change-id[\{change-id\}]/revisions/link:#revision-id[\{revision-id\}]/publish' + +Publishes a draft revision. + +.Request +---- + POST /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/current/publish HTTP/1.0 + Content-Type: application/json;charset=UTF-8 +---- + +.Response +---- + HTTP/1.1 204 No Content +---- + +[[delete-draft-revision]] +Delete Draft Revision +~~~~~~~~~~~~~~~~~~~~~ +[verse] +'DELETE /changes/link:#change-id[\{change-id\}]/revisions/link:#revision-id[\{revision-id\}]' +or +'POST /changes/link:#change-id[\{change-id\}]/revisions/link:#revision-id[\{revision-id\}]/delete' + +Deletes a draft revision. + +.Request +---- + DELETE /changes/myProject~master~I8473b95934b5732ac55d26311a706c9c2bde9940/revisions/674ac754f91e64a0efb8087e59a176484bd534d1 HTTP/1.0 + Content-Type: application/json;charset=UTF-8 +---- + +.Response +---- + HTTP/1.1 204 No Content +---- + [[get-patch]] Get Patch ~~~~~~~~~ diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java index bdba433ed3..f79e05fc68 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/ChangeUtil.java @@ -397,6 +397,13 @@ public class ChangeUtil { final GitReferenceUpdated gitRefUpdated, final ReviewDb db) throws NoSuchChangeException, OrmException, IOException { final Change.Id changeId = patchSetId.getParentKey(); + deleteDraftChange(changeId, gitManager, gitRefUpdated, db); + } + + public static void deleteDraftChange(final Change.Id changeId, + GitRepositoryManager gitManager, + final GitReferenceUpdated gitRefUpdated, final ReviewDb db) + throws NoSuchChangeException, OrmException, IOException { final Change change = db.changes().get(changeId); if (change == null || change.getStatus() != Change.Status.DRAFT) { throw new NoSuchChangeException(changeId); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChange.java new file mode 100644 index 0000000000..f47c278478 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftChange.java @@ -0,0 +1,99 @@ +// Copyright (C) 2013 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.change; + +import com.google.gerrit.extensions.restapi.AuthException; +import com.google.gerrit.extensions.restapi.ResourceConflictException; +import com.google.gerrit.extensions.restapi.ResourceNotFoundException; +import com.google.gerrit.extensions.restapi.Response; +import com.google.gerrit.extensions.restapi.RestModifyView; +import com.google.gerrit.extensions.webui.UiAction; +import com.google.gerrit.reviewdb.client.Change.Status; +import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gerrit.server.ChangeUtil; +import com.google.gerrit.server.change.DeleteDraftChange.Input; +import com.google.gerrit.server.extensions.events.GitReferenceUpdated; +import com.google.gerrit.server.git.GitRepositoryManager; +import com.google.gerrit.server.patch.PatchSetInfoFactory; +import com.google.gerrit.server.project.NoSuchChangeException; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; +import com.google.inject.Provider; + +import java.io.IOException; + +public class DeleteDraftChange implements RestModifyView { + public static class Input { + } + + protected final Provider dbProvider; + private final GitRepositoryManager gitManager; + private final GitReferenceUpdated gitRefUpdated; + + @Inject + public DeleteDraftChange(Provider dbProvider, + GitRepositoryManager gitManager, + GitReferenceUpdated gitRefUpdated, + PatchSetInfoFactory patchSetInfoFactory) { + this.dbProvider = dbProvider; + this.gitManager = gitManager; + this.gitRefUpdated = gitRefUpdated; + } + + @Override + public Object apply(ChangeResource rsrc, Input input) + throws ResourceConflictException, AuthException, + ResourceNotFoundException, OrmException, IOException { + if (rsrc.getChange().getStatus() != Status.DRAFT) { + throw new ResourceConflictException("Change is not a draft"); + } + + if (!rsrc.getControl().canDeleteDraft(dbProvider.get())) { + throw new AuthException("Not permitted to delete this draft change"); + } + + try { + ChangeUtil.deleteDraftChange(rsrc.getChange().getId(), + gitManager, gitRefUpdated, dbProvider.get()); + } catch (NoSuchChangeException e) { + throw new ResourceNotFoundException(e.getMessage()); + } + + return Response.none(); + } + + static class Action extends DeleteDraftChange implements UiAction { + @Inject + public Action(Provider dbProvider, + GitRepositoryManager gitManager, + GitReferenceUpdated gitRefUpdated, + PatchSetInfoFactory patchSetInfoFactory) { + super(dbProvider, gitManager, gitRefUpdated, patchSetInfoFactory); + } + + @Override + public UiAction.Description getDescription(ChangeResource rsrc) { + try { + return new UiAction.Description() + .setTitle(String.format("Delete Draft Change %d", + rsrc.getChange().getChangeId())) + .setVisible(rsrc.getChange().getStatus() == Status.DRAFT + && rsrc.getControl().canDeleteDraft(dbProvider.get())); + } catch (OrmException e) { + throw new IllegalStateException(e); + } + } + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftPatchSet.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftPatchSet.java new file mode 100644 index 0000000000..dd20a38bec --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/DeleteDraftPatchSet.java @@ -0,0 +1,170 @@ +// Copyright (C) 2013 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.change; + +import com.google.gerrit.extensions.restapi.AuthException; +import com.google.gerrit.extensions.restapi.ResourceConflictException; +import com.google.gerrit.extensions.restapi.ResourceNotFoundException; +import com.google.gerrit.extensions.restapi.Response; +import com.google.gerrit.extensions.restapi.RestModifyView; +import com.google.gerrit.extensions.webui.UiAction; +import com.google.gerrit.reviewdb.client.Change; +import com.google.gerrit.reviewdb.client.PatchSet; +import com.google.gerrit.reviewdb.client.PatchSetInfo; +import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gerrit.server.ChangeUtil; +import com.google.gerrit.server.change.DeleteDraftPatchSet.Input; +import com.google.gerrit.server.extensions.events.GitReferenceUpdated; +import com.google.gerrit.server.git.GitRepositoryManager; +import com.google.gerrit.server.patch.PatchSetInfoFactory; +import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException; +import com.google.gerrit.server.project.NoSuchChangeException; +import com.google.gwtorm.server.AtomicUpdate; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; +import com.google.inject.Provider; + +import java.io.IOException; + +public class DeleteDraftPatchSet implements RestModifyView { + public static class Input { + } + + protected final Provider dbProvider; + private final GitRepositoryManager gitManager; + private final GitReferenceUpdated gitRefUpdated; + private final PatchSetInfoFactory patchSetInfoFactory; + + @Inject + public DeleteDraftPatchSet(Provider dbProvider, + GitRepositoryManager gitManager, + GitReferenceUpdated gitRefUpdated, + PatchSetInfoFactory patchSetInfoFactory) { + this.dbProvider = dbProvider; + this.gitManager = gitManager; + this.gitRefUpdated = gitRefUpdated; + this.patchSetInfoFactory = patchSetInfoFactory; + } + + @Override + public Object apply(RevisionResource rsrc, Input input) + throws ResourceNotFoundException, AuthException, OrmException, + IOException, ResourceConflictException { + PatchSet patchSet = rsrc.getPatchSet(); + PatchSet.Id patchSetId = patchSet.getId(); + Change change = rsrc.getChange(); + + if (!patchSet.isDraft()) { + throw new ResourceConflictException("Patch set is not a draft."); + } + + if (!rsrc.getControl().canDeleteDraft(dbProvider.get())) { + throw new AuthException("Not permitted to delete this draft patch set"); + } + + deleteDraftPatchSet(patchSet, change); + deleteOrUpdateDraftChange(patchSetId, change); + + return Response.none(); + } + + private void deleteDraftPatchSet(PatchSet patchSet, Change change) + throws ResourceNotFoundException, OrmException, IOException { + try { + ChangeUtil.deleteOnlyDraftPatchSet(patchSet, + change, gitManager, gitRefUpdated, dbProvider.get()); + } catch (NoSuchChangeException e) { + throw new ResourceNotFoundException(e.getMessage()); + } + } + + private void deleteOrUpdateDraftChange(PatchSet.Id patchSetId, + Change change) throws OrmException, ResourceNotFoundException, + IOException { + if (dbProvider.get() + .patchSets() + .byChange(change.getId()) + .toList().size() == 0) { + deleteDraftChange(patchSetId); + } else { + if (change.currentPatchSetId().equals(patchSetId)) { + updateCurrentPatchSet(dbProvider.get(), change, + previousPatchSetInfo(patchSetId)); + } + } + } + + private void deleteDraftChange(PatchSet.Id patchSetId) + throws OrmException, IOException, ResourceNotFoundException { + try { + ChangeUtil.deleteDraftChange(patchSetId, + gitManager, gitRefUpdated, dbProvider.get()); + } catch (NoSuchChangeException e) { + throw new ResourceNotFoundException(e.getMessage()); + } + } + + private PatchSetInfo previousPatchSetInfo(PatchSet.Id patchSetId) + throws ResourceNotFoundException { + try { + return patchSetInfoFactory.get(dbProvider.get(), + new PatchSet.Id(patchSetId.getParentKey(), + patchSetId.get() - 1)); + } catch (PatchSetInfoNotAvailableException e) { + throw new ResourceNotFoundException(e.getMessage()); + } + } + + private static void updateCurrentPatchSet(final ReviewDb db, + final Change change, final PatchSetInfo psInfo) + throws OrmException { + db.changes().atomicUpdate(change.getId(), new AtomicUpdate() { + @Override + public Change update(Change c) { + c.setCurrentPatchSet(psInfo); + ChangeUtil.updated(c); + return c; + } + }); + } + + static class Action extends DeleteDraftPatchSet implements UiAction { + @Inject + public Action(Provider dbProvider, + GitRepositoryManager gitManager, + GitReferenceUpdated gitRefUpdated, + PatchSetInfoFactory patchSetInfoFactory) { + super(dbProvider, gitManager, gitRefUpdated, patchSetInfoFactory); + } + + @Override + public UiAction.Description getDescription(RevisionResource rsrc) { + PatchSet.Id current = rsrc.getChange().currentPatchSetId(); + try { + int psCount = dbProvider.get().patchSets() + .byChange(rsrc.getChange().getId()).toList().size(); + return new UiAction.Description() + .setTitle(String.format("Delete Draft Revision %d", + rsrc.getPatchSet().getPatchSetId())) + .setVisible(rsrc.getPatchSet().isDraft() + && rsrc.getPatchSet().getId().equals(current) + && rsrc.getControl().canDeleteDraft(dbProvider.get()) + && psCount > 1); + } catch (OrmException e) { + throw new IllegalStateException(e); + } + } + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java index b96e296a78..d292880aaf 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Module.java @@ -49,7 +49,10 @@ public class Module extends RestApiModule { get(CHANGE_KIND, "topic").to(GetTopic.class); put(CHANGE_KIND, "topic").to(PutTopic.class); delete(CHANGE_KIND, "topic").to(PutTopic.class); + delete(CHANGE_KIND).to(DeleteDraftChange.class); + post(CHANGE_KIND, "delete").to(DeleteDraftChange.Action.class); post(CHANGE_KIND, "abandon").to(Abandon.class); + post(CHANGE_KIND, "publish").to(Publish.CurrentRevision.class); post(CHANGE_KIND, "restore").to(Restore.class); post(CHANGE_KIND, "revert").to(Revert.class); post(CHANGE_KIND, "submit").to(Submit.CurrentRevision.class); @@ -64,7 +67,10 @@ public class Module extends RestApiModule { child(CHANGE_KIND, "revisions").to(Revisions.class); post(REVISION_KIND, "cherrypick").to(CherryPick.class); get(REVISION_KIND, "commit").to(GetCommit.class); + delete(REVISION_KIND).to(DeleteDraftPatchSet.class); + post(REVISION_KIND, "delete").to(DeleteDraftPatchSet.Action.class); get(REVISION_KIND, "mergeable").to(Mergeable.class); + post(REVISION_KIND, "publish").to(Publish.class); get(REVISION_KIND, "related").to(GetRelated.class); get(REVISION_KIND, "review").to(GetReview.class); post(REVISION_KIND, "review").to(PostReview.class); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Publish.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Publish.java new file mode 100644 index 0000000000..7355ef317c --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Publish.java @@ -0,0 +1,161 @@ +// Copyright (C) 2013 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.change; + +import com.google.gerrit.common.ChangeHooks; +import com.google.gerrit.extensions.restapi.AuthException; +import com.google.gerrit.extensions.restapi.ResourceConflictException; +import com.google.gerrit.extensions.restapi.ResourceNotFoundException; +import com.google.gerrit.extensions.restapi.Response; +import com.google.gerrit.extensions.restapi.RestModifyView; +import com.google.gerrit.extensions.webui.UiAction; +import com.google.gerrit.reviewdb.client.Change; +import com.google.gerrit.reviewdb.client.PatchSet; +import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gerrit.server.ChangeUtil; +import com.google.gerrit.server.mail.PatchSetNotificationSender; +import com.google.gerrit.server.change.Publish.Input; +import com.google.gerrit.server.index.ChangeIndexer; +import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException; +import com.google.gwtorm.server.AtomicUpdate; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; +import com.google.inject.Provider; + +import java.io.IOException; + +public class Publish implements RestModifyView, + UiAction { + public static class Input { + } + + private final Provider dbProvider; + private final PatchSetNotificationSender sender; + private final ChangeHooks hooks; + private final ChangeIndexer indexer; + + @Inject + public Publish(Provider dbProvider, + PatchSetNotificationSender sender, + ChangeHooks hooks, + ChangeIndexer indexer) { + this.dbProvider = dbProvider; + this.sender = sender; + this.hooks = hooks; + this.indexer = indexer; + } + + @Override + public Object apply(RevisionResource rsrc, Input input) throws IOException, + ResourceNotFoundException, ResourceConflictException, + OrmException, AuthException { + if (!rsrc.getPatchSet().isDraft()) { + throw new ResourceConflictException("Patch set is not a draft"); + } + + if (!rsrc.getControl().canPublish(dbProvider.get())) { + throw new AuthException("Cannot publish this draft patch set"); + } + + PatchSet updatedPatchSet = updateDraftPatchSet(rsrc); + Change updatedChange = updateDraftChange(rsrc); + + try { + if (!updatedPatchSet.isDraft() + || updatedChange.getStatus() == Change.Status.NEW) { + indexer.index(updatedChange); + hooks.doDraftPublishedHook(updatedChange, updatedPatchSet, dbProvider.get()); + sender.send(rsrc.getChange().getStatus() == Change.Status.DRAFT, + rsrc.getUser(), updatedChange, updatedPatchSet, + rsrc.getControl().getLabelTypes()); + } + } catch (PatchSetInfoNotAvailableException e) { + throw new ResourceNotFoundException(e.getMessage()); + } + + return Response.none(); + } + + private Change updateDraftChange(RevisionResource rsrc) throws OrmException { + Change updatedChange = dbProvider.get().changes() + .atomicUpdate(rsrc.getChange().getId(), + new AtomicUpdate() { + @Override + public Change update(Change change) { + if (change.getStatus() == Change.Status.DRAFT) { + change.setStatus(Change.Status.NEW); + ChangeUtil.updated(change); + } + return change; + } + }); + return updatedChange; + } + + private PatchSet updateDraftPatchSet(RevisionResource rsrc) throws OrmException { + final PatchSet updatedPatchSet = dbProvider.get().patchSets() + .atomicUpdate(rsrc.getPatchSet().getId(), + new AtomicUpdate() { + @Override + public PatchSet update(PatchSet patchset) { + patchset.setDraft(false); + return patchset; + } + }); + return updatedPatchSet; + } + + @Override + public UiAction.Description getDescription(RevisionResource rsrc) { + PatchSet.Id current = rsrc.getChange().currentPatchSetId(); + try { + return new UiAction.Description() + .setTitle(String.format("Publish Revision %d", + rsrc.getPatchSet().getPatchSetId())) + .setVisible(rsrc.getPatchSet().isDraft() + && rsrc.getPatchSet().getId().equals(current) + && rsrc.getControl().canPublish(dbProvider.get())); + } catch (OrmException e) { + throw new IllegalStateException(e); + } + } + + public static class CurrentRevision implements + RestModifyView { + private final Provider dbProvider; + private final Publish publish; + + @Inject + CurrentRevision(Provider dbProvider, + Publish publish) { + this.dbProvider = dbProvider; + this.publish = publish; + } + + @Override + public Object apply(ChangeResource rsrc, Input input) throws AuthException, + ResourceConflictException, ResourceConflictException, IOException, + OrmException, ResourceNotFoundException, AuthException { + PatchSet ps = dbProvider.get().patchSets() + .get(rsrc.getChange().currentPatchSetId()); + if (ps == null) { + throw new ResourceConflictException("current revision is missing"); + } else if (!rsrc.getControl().isPatchVisible(ps, dbProvider.get())) { + throw new AuthException("current revision not accessible"); + } + return publish.apply(new RevisionResource(rsrc, ps), input); + } + } +} diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java index 714a6ad9c8..7af882ee15 100644 --- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java +++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/ReviewCommand.java @@ -31,11 +31,11 @@ import com.google.gerrit.reviewdb.client.RevId; import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.server.change.Abandon; import com.google.gerrit.server.change.ChangeResource; +import com.google.gerrit.server.change.DeleteDraftPatchSet; import com.google.gerrit.server.change.PostReview; import com.google.gerrit.server.change.Restore; import com.google.gerrit.server.change.RevisionResource; import com.google.gerrit.server.change.Submit; -import com.google.gerrit.server.changedetail.DeleteDraftPatchSet; import com.google.gerrit.server.changedetail.PublishDraft; import com.google.gerrit.server.config.AllProjectsName; import com.google.gerrit.server.project.ChangeControl; @@ -131,7 +131,7 @@ public class ReviewCommand extends SshCommand { private ReviewDb db; @Inject - private DeleteDraftPatchSet.Factory deleteDraftPatchSetFactory; + private DeleteDraftPatchSet deleteDraftPatchSetImpl; @Inject private ProjectControl.Factory projectControlFactory; @@ -285,6 +285,16 @@ public class ReviewCommand extends SshCommand { new ChangeResource(ctl), patchSet), input); } + + if (publishPatchSet) { + final ReviewResult result = + publishDraftFactory.create(patchSet.getId()).call(); + handleReviewResultErrors(result); + } else if (deleteDraftPatchSet) { + deleteDraftPatchSetImpl.apply(new RevisionResource( + new ChangeResource(ctl), patchSet), + new DeleteDraftPatchSet.Input()); + } } catch (InvalidChangeOperationException e) { throw error(e.getMessage()); } catch (IllegalStateException e) { @@ -296,16 +306,6 @@ public class ReviewCommand extends SshCommand { } catch (ResourceConflictException e) { throw error(e.getMessage()); } - - if (publishPatchSet) { - final ReviewResult result = - publishDraftFactory.create(patchSet.getId()).call(); - handleReviewResultErrors(result); - } else if (deleteDraftPatchSet) { - final ReviewResult result = - deleteDraftPatchSetFactory.create(patchSet.getId()).call(); - handleReviewResultErrors(result); - } } private void handleReviewResultErrors(final ReviewResult result) {