Revision API: Add method to query if revision must be rebased

With canRebase() method plugins can figure out if a specific revision
can actually be rebased, if it's not based on the latest revision of
the dependent change.

  boolean canRebase = gApi.changes()
      .id(change)
      .revision(revision)
      .canRebase();

Change-Id: Ib64a6ed5a62f83639143088624ad72d93edae3cf
diff --git a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
index 50522cd..78b9a54 100644
--- a/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
+++ b/gerrit-acceptance-tests/src/test/java/com/google/gerrit/acceptance/api/revision/RevisionIT.java
@@ -14,6 +14,9 @@
 
 package com.google.gerrit.acceptance.api.revision;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
 import com.google.gerrit.acceptance.AbstractDaemonTest;
 import com.google.gerrit.acceptance.NoHttpd;
 import com.google.gerrit.acceptance.PushOneCommit;
@@ -21,6 +24,7 @@
 import com.google.gerrit.extensions.api.changes.ChangeApi;
 import com.google.gerrit.extensions.api.changes.CherryPickInput;
 import com.google.gerrit.extensions.api.changes.ReviewInput;
+import com.google.gerrit.extensions.api.changes.RevisionApi;
 import com.google.gerrit.extensions.api.changes.SubmitInput;
 import com.google.gerrit.extensions.api.projects.BranchInput;
 import com.google.gerrit.extensions.restapi.AuthException;
@@ -140,6 +144,42 @@
         .submit();
   }
 
+  @Test
+  public void canRebase()
+      throws GitAPIException, IOException, RestApiException, Exception {
+    PushOneCommit push = pushFactory.create(db, admin.getIdent());
+    PushOneCommit.Result r1 = push.to(git, "refs/for/master");
+    merge(r1);
+
+    push = pushFactory.create(db, admin.getIdent());
+    PushOneCommit.Result r2 = push.to(git, "refs/for/master");
+    assertFalse(gApi.changes()
+        .id(r2.getChangeId())
+        .revision(r2.getCommit().name())
+        .canRebase());
+    merge(r2);
+
+    git.checkout().setName(r1.getCommit().name()).call();
+    push = pushFactory.create(db, admin.getIdent());
+    PushOneCommit.Result r3 = push.to(git, "refs/for/master");
+
+    assertTrue(gApi.changes()
+        .id(r3.getChangeId())
+        .revision(r3.getCommit().name())
+        .canRebase());
+  }
+
+  protected RevisionApi revision(PushOneCommit.Result r) throws Exception {
+    return gApi.changes()
+        .id(r.getChangeId())
+        .current();
+  }
+
+  private void merge(PushOneCommit.Result r) throws Exception {
+    revision(r).review(ReviewInput.approve());
+    revision(r).submit();
+  }
+
   private PushOneCommit.Result updateChange(PushOneCommit.Result r,
       String content) throws GitAPIException, IOException {
     PushOneCommit push = pushFactory.create(db, admin.getIdent(),
diff --git a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
index 4f90be2..dc2a9a7 100644
--- a/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
+++ b/gerrit-extension-api/src/main/java/com/google/gerrit/extensions/api/changes/RevisionApi.java
@@ -26,4 +26,5 @@
   void publish() throws RestApiException;
   ChangeApi cherryPick(CherryPickInput in) throws RestApiException;
   ChangeApi rebase() throws RestApiException;
+  boolean canRebase();
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
index a9253c3..fb82b7e 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/api/changes/RevisionApiImpl.java
@@ -29,6 +29,7 @@
 import com.google.gerrit.server.change.Rebase;
 import com.google.gerrit.server.change.RevisionResource;
 import com.google.gerrit.server.change.Submit;
+import com.google.gerrit.server.changedetail.RebaseChange;
 import com.google.gwtorm.server.OrmException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
@@ -45,6 +46,7 @@
   private final Provider<CherryPick> cherryPick;
   private final Provider<DeleteDraftPatchSet> deleteDraft;
   private final Provider<Rebase> rebase;
+  private final Provider<RebaseChange> rebaseChange;
   private final Provider<PostReview> review;
   private final Provider<Submit> submit;
   private final Provider<Publish> publish;
@@ -55,6 +57,7 @@
       Provider<CherryPick> cherryPick,
       Provider<DeleteDraftPatchSet> deleteDraft,
       Provider<Rebase> rebase,
+      Provider<RebaseChange> rebaseChange,
       Provider<PostReview> review,
       Provider<Submit> submit,
       Provider<Publish> publish,
@@ -63,6 +66,7 @@
     this.cherryPick = cherryPick;
     this.deleteDraft = deleteDraft;
     this.rebase = rebase;
+    this.rebaseChange = rebaseChange;
     this.review = review;
     this.submit = submit;
     this.publish = publish;
@@ -122,6 +126,11 @@
   }
 
   @Override
+  public boolean canRebase() {
+    return rebaseChange.get().canRebase(revision);
+  }
+
+  @Override
   public ChangeApi cherryPick(CherryPickInput in) throws RestApiException {
     try {
       return changes.id(cherryPick.get().apply(revision, in)._number);