ReviewCommand: When available use project when identifying a change

Changes#id(String, int) is guaranteed to unambiguously identify exactly
one change if such a change is available. If project is provided in
CLI call use this method to get ChangeApi.
If project was not provided lookup the ChangeApi with only the
change-number through Changes#id(String) which may identify several
changes and throw an Exception (e.g. if changes have been imported
from another Gerrit instance so that two changes have the same
change-number).

Release-Notes: ReviewCommand identify change with project,change-number if project is provided in CLI call.
Change-Id: I04eb63949f7768f7e719f0d49ce4f7d64834e37f
diff --git a/java/com/google/gerrit/sshd/commands/ReviewCommand.java b/java/com/google/gerrit/sshd/commands/ReviewCommand.java
index c271676..e004940 100644
--- a/java/com/google/gerrit/sshd/commands/ReviewCommand.java
+++ b/java/com/google/gerrit/sshd/commands/ReviewCommand.java
@@ -254,10 +254,7 @@
             ActionType.CHANGE_UPDATE,
             "applyReview",
             () -> {
-              gApi.changes()
-                  .id(patchSet.id().changeId().get())
-                  .revision(patchSet.number())
-                  .review(review);
+              getRevisionApi(patchSet).review(review);
               return null;
             })
         .call();
@@ -295,11 +292,11 @@
         AbandonInput input = new AbandonInput();
         input.message = Strings.emptyToNull(changeComment);
         applyReview(patchSet, review);
-        changeApi(patchSet).abandon(input);
+        getChangeApi(patchSet).abandon(input);
       } else if (restoreChange) {
         RestoreInput input = new RestoreInput();
         input.message = Strings.emptyToNull(changeComment);
-        changeApi(patchSet).restore(input);
+        getChangeApi(patchSet).restore(input);
         applyReview(patchSet, review);
       } else {
         applyReview(patchSet, review);
@@ -309,15 +306,15 @@
         MoveInput moveInput = new MoveInput();
         moveInput.destinationBranch = moveToBranch;
         moveInput.message = Strings.emptyToNull(changeComment);
-        changeApi(patchSet).move(moveInput);
+        getChangeApi(patchSet).move(moveInput);
       }
 
       if (rebaseChange) {
-        revisionApi(patchSet).rebase();
+        getRevisionApi(patchSet).rebase();
       }
 
       if (submitChange) {
-        revisionApi(patchSet).submit();
+        getRevisionApi(patchSet).submit();
       }
 
     } catch (IllegalStateException | RestApiException e) {
@@ -325,12 +322,19 @@
     }
   }
 
-  private ChangeApi changeApi(PatchSet patchSet) throws RestApiException {
-    return gApi.changes().id(patchSet.id().changeId().get());
+  private ChangeApi getChangeApi(PatchSet patchSet) throws RestApiException {
+    if (projectState != null) {
+      return gApi.changes().id(projectState.getName(), patchSet.id().changeId().get());
+    }
+    /* Since we didn't get a project from the CLI we have to use the ambiguous
+     * Changes#id(String) that may fail to identify one single change and throw
+     * an exception.
+     */
+    return gApi.changes().id(String.valueOf(patchSet.id().changeId().get()));
   }
 
-  private RevisionApi revisionApi(PatchSet patchSet) throws RestApiException {
-    return changeApi(patchSet).revision(patchSet.commitId().name());
+  private RevisionApi getRevisionApi(PatchSet patchSet) throws RestApiException {
+    return getChangeApi(patchSet).revision(patchSet.commitId().name());
   }
 
   @Override