diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailFactory.java index 4ad072536c..568971d105 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailFactory.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/changedetail/ChangeDetailFactory.java @@ -14,7 +14,6 @@ package com.google.gerrit.httpd.rpc.changedetail; -import com.google.gerrit.common.data.Capable; import com.google.gerrit.common.data.ChangeDetail; import com.google.gerrit.common.data.ChangeInfo; import com.google.gerrit.common.data.SubmitRecord; @@ -136,9 +135,7 @@ public class ChangeDetailFactory extends Handler { changeId)); detail.setCanRevert(change.getStatus() == Change.Status.MERGED && control.canAddPatchSet()); - - detail.setCanCherryPick(control.getProjectControl().canPushToAtLeastOneRef() == Capable.OK); - + detail.setCanCherryPick(control.getProjectControl().canUpload()); detail.setCanEdit(control.getRefControl().canWrite()); detail.setCanEditCommitMessage(change.getStatus().isOpen() && control.canAddPatchSet()); detail.setCanEditTopicName(control.canEditTopicName()); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPick.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPick.java index 3fb85b483a..83a2b48d50 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPick.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/CherryPick.java @@ -18,11 +18,11 @@ 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.RestModifyView; +import com.google.gerrit.extensions.webui.UiCommand; 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.change.CherryPick.Input; -import com.google.gerrit.server.change.CherryPickChange; import com.google.gerrit.server.git.MergeException; import com.google.gerrit.server.project.ChangeControl; import com.google.gerrit.server.project.InvalidChangeOperationException; @@ -30,7 +30,11 @@ import com.google.gerrit.server.project.RefControl; import com.google.inject.Inject; import com.google.inject.Provider; -class CherryPick implements RestModifyView { +import java.util.EnumSet; +import java.util.Set; + +class CherryPick implements RestModifyView, + UiCommand { private final Provider dbProvider; private final Provider cherryPickChange; private final ChangeJson json; @@ -90,4 +94,34 @@ class CherryPick implements RestModifyView { throw new ResourceConflictException(e.getMessage()); } } + + @Override + public Set getPlaces() { + return EnumSet.of(Place.PATCHSET_ACTION_PANEL); + } + + @Override + public String getLabel(RevisionResource resource) { + return "Cherry Pick To"; + } + + @Override + public String getTitle(RevisionResource resource) { + return "Cherry pick change to a different branch"; + } + + @Override + public boolean isVisible(RevisionResource resource) { + return isEnabled(resource); + } + + @Override + public boolean isEnabled(RevisionResource resource) { + return resource.getControl().getProjectControl().canUpload(); + } + + @Override + public String getConfirmationMessage(RevisionResource resource) { + return null; + } } 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 c8c0b6bf25..ed296f0ff2 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 @@ -61,18 +61,17 @@ public class Module extends RestApiModule { delete(REVIEWER_KIND).to(DeleteReviewer.class); child(CHANGE_KIND, "revisions").to(Revisions.class); + post(REVISION_KIND, "cherrypick").to(CherryPick.class); get(REVISION_KIND, "commit").to(GetCommit.class); get(REVISION_KIND, "review").to(GetReview.class); post(REVISION_KIND, "review").to(PostReview.class); post(REVISION_KIND, "submit").to(Submit.class); post(REVISION_KIND, "rebase").to(Rebase.class); - get(REVISION_KIND, "submit_type").to(TestSubmitType.Get.class); get(REVISION_KIND, "patch").to(GetPatch.class); + get(REVISION_KIND, "submit_type").to(TestSubmitType.Get.class); post(REVISION_KIND, "test.submit_rule").to(TestSubmitRule.class); post(REVISION_KIND, "test.submit_type").to(TestSubmitType.class); - post(REVISION_KIND, "cherrypick").to(CherryPick.class); - child(REVISION_KIND, "drafts").to(Drafts.class); put(REVISION_KIND, "drafts").to(CreateDraft.class); get(DRAFT_KIND).to(GetDraft.class); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Rebase.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Rebase.java index 358e5fcdf9..7c8fc96ad7 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Rebase.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Rebase.java @@ -20,6 +20,7 @@ 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.RestModifyView; +import com.google.gerrit.extensions.webui.UiCommand; import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.server.ReviewDb; @@ -34,8 +35,11 @@ import com.google.inject.Inject; import com.google.inject.Provider; import java.io.IOException; +import java.util.EnumSet; +import java.util.Set; -public class Rebase implements RestModifyView { +public class Rebase implements RestModifyView, + UiCommand { public static class Input { } @@ -76,6 +80,38 @@ public class Rebase implements RestModifyView { return json.format(change.getId()); } + @Override + public Set getPlaces() { + return EnumSet.of(Place.PATCHSET_ACTION_PANEL); + } + + @Override + public String getLabel(RevisionResource resource) { + return "Rebase"; + } + + @Override + public String getTitle(RevisionResource resource) { + return "Rebase onto tip of branch or parent change"; + } + + @Override + public boolean isVisible(RevisionResource resource) { + return isEnabled(resource); + } + + @Override + public boolean isEnabled(RevisionResource resource) { + return resource.getChange().getStatus().isOpen() + && resource.getControl().canRebase() + && rebaseChange.get().canRebase(resource); + } + + @Override + public String getConfirmationMessage(RevisionResource resource) { + return null; + } + public static class CurrentRevision implements RestModifyView { private final Provider dbProvider; diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java index e236abbf23..df26c2e77b 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Submit.java @@ -24,6 +24,7 @@ import com.google.gerrit.common.data.SubmitRecord; import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.RestModifyView; +import com.google.gerrit.extensions.webui.UiCommand; import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.ChangeMessage; import com.google.gerrit.reviewdb.client.PatchSet; @@ -49,9 +50,12 @@ import java.io.IOException; import java.sql.Timestamp; import java.util.Collection; import java.util.Collections; +import java.util.EnumSet; import java.util.List; +import java.util.Set; -public class Submit implements RestModifyView { +public class Submit implements RestModifyView, + UiCommand { public static class Input { public boolean waitForMerge; } @@ -140,6 +144,44 @@ public class Submit implements RestModifyView { } } + @Override + public Set getPlaces() { + return EnumSet.of(Place.PATCHSET_ACTION_PANEL); + } + + @Override + public String getLabel(RevisionResource resource) { + return String.format( + "Submit Patch Set %d", + resource.getPatchSet().getPatchSetId()); + } + + @Override + public String getTitle(RevisionResource resource) { + return null; + } + + @Override + public boolean isVisible(RevisionResource resource) { + PatchSet.Id current = resource.getChange().currentPatchSetId(); + return resource.getChange().getStatus().isOpen() + && resource.getPatchSet().getId().equals(current) + && isEnabled(resource); + } + + @Override + public boolean isEnabled(RevisionResource resource) { + // Enable based on approximation. If the user has permission enable, + // even if the change has not reached as submittable state according + // to the project rules. + return resource.getControl().canSubmit(); + } + + @Override + public String getConfirmationMessage(RevisionResource resource) { + return null; + } + /** * If the merge was attempted and it failed the system usually writes a * comment as a ChangeMessage and sets status to NEW. Find the relevant diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java index 7f3472887a..1cd8e9c46a 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/RebaseChange.java @@ -27,6 +27,7 @@ import com.google.gerrit.server.ChangeUtil; import com.google.gerrit.server.GerritPersonIdent; import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.change.PatchSetInserter; +import com.google.gerrit.server.change.RevisionResource; import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.MergeUtil; import com.google.gerrit.server.project.ChangeControl; @@ -351,6 +352,34 @@ public class RebaseChange { return objectId; } + public boolean canRebase(RevisionResource r) { + Repository git; + try { + git = gitManager.openRepository(r.getChange().getProject()); + } catch (RepositoryNotFoundException err) { + return false; + } catch (IOException err) { + return false; + } + try { + findBaseRevision( + r.getPatchSet().getId(), + db, + r.getChange().getDest(), + git, + null, + null, + null); + return true; + } catch (IOException e) { + return false; + } catch (OrmException e) { + return false; + } finally { + git.close(); + } + } + public static boolean canDoRebase(final ReviewDb db, final Change change, final GitRepositoryManager gitManager, List patchSetAncestors, diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java index ed4346a416..b82c1b7e43 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/ProjectControl.java @@ -217,6 +217,20 @@ public class ProjectControl { || isOwnerAnyRef()); } + public boolean canUpload() { + for (SectionMatcher matcher : access()) { + AccessSection section = matcher.section; + if (section.getName().startsWith("refs/for/")) { + Permission permission = section.getPermission(Permission.PUSH); + if (permission != null + && controlForRef(section.getName()).canPerform(Permission.PUSH)) { + return true; + } + } + } + return false; + } + /** Can this user see all the refs in this projects? */ public boolean allRefsAreVisible() { return allRefsAreVisibleExcept(Collections. emptySet());