diff options
author | Mika Hamalainen <mika.hamalainen@accenture.com> | 2011-09-06 13:04:00 +0300 |
---|---|---|
committer | Mika Hamalainen <mika.hamalainen@accenture.com> | 2011-09-06 13:04:00 +0300 |
commit | bdea488805bf0ea2d797646b663eb7e0619e1e16 (patch) | |
tree | 9acf9b94ad2f6c4d77705e029ea9a7f2389ccdf2 | |
parent | a18cf2ff982a241d03527af0689bbc000cced4f2 (diff) |
Unstaging support for topics
Topics can be now removed from staging. The topic needs to
be in STAGED state and the current user must be able to
abandon the topic for the remove from staging button to be
visible.
Each change is separately set to NEW status and the staging
branch is rebuild.
Change-Id: If8ef39ba9d40e97bd3170a46047041b4939dc290
7 files changed, 213 insertions, 5 deletions
diff --git a/gerrit-common/src/main/java/com/google/gerrit/common/data/TopicManageService.java b/gerrit-common/src/main/java/com/google/gerrit/common/data/TopicManageService.java index a12d16dc04..697866ec54 100644 --- a/gerrit-common/src/main/java/com/google/gerrit/common/data/TopicManageService.java +++ b/gerrit-common/src/main/java/com/google/gerrit/common/data/TopicManageService.java @@ -40,4 +40,7 @@ public interface TopicManageService extends RemoteJsonService { @SignInRequired void stage(ChangeSet.Id changeSetId, AsyncCallback<TopicDetail> callback); + + @SignInRequired + void unstage(ChangeSet.Id changeSetId, AsyncCallback<TopicDetail> callback); } diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeSetComplexDisclosurePanel.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeSetComplexDisclosurePanel.java index ea09296e89..254876da95 100644 --- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeSetComplexDisclosurePanel.java +++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/changes/ChangeSetComplexDisclosurePanel.java @@ -259,6 +259,24 @@ class ChangeSetComplexDisclosurePanel extends CommonComplexDisclosurePanel { actionsPanel.add(b); } + if (topicDetail.canUnstage()) { + final Button b = new Button(Util.C.buttonUnstagingChange()); + b.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + b.setEnabled(false); + Util.T_MANAGE_SVC.unstage(changeSet.getId(), + new GerritCallback<TopicDetail>() { + @Override + public void onSuccess(TopicDetail result) { + topicScreen.update(result); + } + }); + } + }); + actionsPanel.add(b); + } + if (topicDetail.canRestore()) { final Button b = new Button(Util.TC.buttonRestoreTopicBegin()); b.addClickHandler(new ClickHandler() { diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/topic/TopicDetailFactory.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/topic/TopicDetailFactory.java index a7ed068b9e..4c77e899ae 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/topic/TopicDetailFactory.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/topic/TopicDetailFactory.java @@ -38,7 +38,6 @@ import com.google.gerrit.server.AnonymousUser; import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.account.AccountInfoCacheFactory; import com.google.gerrit.server.project.CanSubmitResult; -import com.google.gerrit.server.project.ChangeControl; import com.google.gerrit.server.project.NoSuchChangeException; import com.google.gerrit.server.project.NoSuchTopicException; import com.google.gerrit.server.project.TopicControl; @@ -64,7 +63,6 @@ public class TopicDetailFactory extends Handler<TopicDetail> { } private final ApprovalTypes approvalTypes; - private final ChangeControl.Factory changeControlFactory; private final TopicControl.Factory topicControlFactory; private final TopicFunctionState.Factory functionState; private final ChangeSetDetailFactory.Factory changeSetDetail; @@ -81,7 +79,6 @@ public class TopicDetailFactory extends Handler<TopicDetail> { TopicDetailFactory(final ApprovalTypes approvalTypes, final TopicFunctionState.Factory functionState, final ChangeSetDetailFactory.Factory changeSetDetail, final ReviewDb db, - final ChangeControl.Factory changeControlFactory, final TopicControl.Factory topicControlFactory, final AccountInfoCacheFactory.Factory accountInfoCacheFactory, final AnonymousUser anonymousUser, @@ -90,7 +87,6 @@ public class TopicDetailFactory extends Handler<TopicDetail> { this.functionState = functionState; this.changeSetDetail = changeSetDetail; this.db = db; - this.changeControlFactory = changeControlFactory; this.topicControlFactory = topicControlFactory; this.anonymousUser = anonymousUser; this.aic = accountInfoCacheFactory.create(); @@ -124,6 +120,7 @@ public class TopicDetailFactory extends Handler<TopicDetail> { detail.setCanRevert(topic.getStatus() == AbstractEntity.Status.MERGED && control.canAddChangeSet()); detail.setCanSubmit(canSubmitResult == CanSubmitResult.OK); detail.setCanStage(canStageResult == CanSubmitResult.OK); + detail.setCanUnstage(topic.getStatus() == AbstractEntity.Status.STAGED && control.canAbandon()); loadChangeSets(); loadMessages(); diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/topic/TopicManageServiceImpl.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/topic/TopicManageServiceImpl.java index 080f394d31..36ab6f5efc 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/topic/TopicManageServiceImpl.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/topic/TopicManageServiceImpl.java @@ -26,18 +26,21 @@ class TopicManageServiceImpl implements TopicManageService { private final RestoreTopic.Factory restoreTopicFactory; private final RevertTopic.Factory revertTopicFactory; private final StagingAction.Factory stagingActionFactory; + private final UnstageAction.Factory unstageActionFactory; @Inject TopicManageServiceImpl(final SubmitAction.Factory changeSetAction, final AbandonTopic.Factory abandonTopicFactory, final RestoreTopic.Factory restoreTopicFactory, final RevertTopic.Factory revertTopicFactory, - final StagingAction.Factory stagingActionFactory) { + final StagingAction.Factory stagingActionFactory, + final UnstageAction.Factory unstageActionFactory) { this.submitAction = changeSetAction; this.abandonTopicFactory = abandonTopicFactory; this.restoreTopicFactory = restoreTopicFactory; this.revertTopicFactory = revertTopicFactory; this.stagingActionFactory = stagingActionFactory; + this.unstageActionFactory = unstageActionFactory; } public void submit(final ChangeSet.Id csid, @@ -64,4 +67,9 @@ class TopicManageServiceImpl implements TopicManageService { AsyncCallback<TopicDetail> callback) { stagingActionFactory.create(changeSetId).to(callback); } + + public void unstage(ChangeSet.Id changeSetId, + AsyncCallback<TopicDetail> callback) { + unstageActionFactory.create(changeSetId).to(callback); + } } diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/topic/TopicModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/topic/TopicModule.java index 528c4b3b88..a75b41ed48 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/topic/TopicModule.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/topic/TopicModule.java @@ -40,6 +40,7 @@ public class TopicModule extends RpcServletModule { factory(SubmitAction.Factory.class); factory(IncludedInDetailHandler.Factory.class); factory(StagingAction.Factory.class); + factory(UnstageAction.Factory.class); } }); rpc(TopicDetailServiceImpl.class); diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/topic/UnstageAction.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/topic/UnstageAction.java new file mode 100644 index 0000000000..22e74db0af --- /dev/null +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/topic/UnstageAction.java @@ -0,0 +1,155 @@ +// Copyright (C) 2011 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.httpd.rpc.topic; + +import com.google.gerrit.common.ChangeHookRunner; +import com.google.gerrit.common.data.ApprovalTypes; +import com.google.gerrit.common.data.TopicDetail; +import com.google.gerrit.common.errors.NoSuchEntityException; +import com.google.gerrit.httpd.rpc.Handler; +import com.google.gerrit.reviewdb.Branch; +import com.google.gerrit.reviewdb.Change; +import com.google.gerrit.reviewdb.ChangeSet; +import com.google.gerrit.reviewdb.ChangeSetElement; +import com.google.gerrit.reviewdb.ReviewDb; +import com.google.gerrit.reviewdb.Topic; +import com.google.gerrit.server.ChangeUtil; +import com.google.gerrit.server.IdentifiedUser; +import com.google.gerrit.server.TopicUtil; +import com.google.gerrit.server.git.GitRepositoryManager; +import com.google.gerrit.server.git.MergeOp; +import com.google.gerrit.server.git.MergeQueue; +import com.google.gerrit.server.project.CanSubmitResult; +import com.google.gerrit.server.project.ChangeControl; +import com.google.gerrit.server.project.NoSuchChangeException; +import com.google.gerrit.server.project.NoSuchRefException; +import com.google.gerrit.server.project.NoSuchTopicException; +import com.google.gerrit.server.project.TopicControl; +import com.google.gerrit.server.workflow.TopicFunctionState; +import com.google.gwtorm.client.OrmException; +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; + +import org.eclipse.jgit.lib.Repository; + +import java.io.IOException; +import java.util.List; + + +class UnstageAction extends Handler<TopicDetail> { + interface Factory { + UnstageAction create(ChangeSet.Id changeSetId); + } + + private final ReviewDb db; + private final MergeQueue merger; + private final ApprovalTypes approvalTypes; + private final IdentifiedUser user; + private final TopicDetailFactory.Factory topicDetailFactory; + private final ChangeControl.Factory changeControlFactory; + private final TopicControl.Factory topicControlFactory; + private final TopicFunctionState.Factory topicFunctionState; + private final MergeOp.Factory opFactory; + private final GitRepositoryManager gitManager; + private final ChangeHookRunner hooks; + + private final ChangeSet.Id changeSetId; + + @Inject + UnstageAction(final ReviewDb db, final MergeQueue mq, + final IdentifiedUser user, + final ApprovalTypes approvalTypes, + final TopicDetailFactory.Factory topicDetailFactory, + final ChangeControl.Factory changeControlFactory, + final TopicControl.Factory topicControlFactory, + final TopicFunctionState.Factory topicFunctionState, + final MergeOp.Factory opFactory, + final GitRepositoryManager gitManager, + final ChangeHookRunner hooks, + @Assisted final ChangeSet.Id changeSetId) { + this.db = db; + this.merger = mq; + this.approvalTypes = approvalTypes; + this.user = user; + this.changeControlFactory = changeControlFactory; + this.topicControlFactory = topicControlFactory; + this.topicDetailFactory = topicDetailFactory; + this.topicFunctionState = topicFunctionState; + this.opFactory = opFactory; + this.gitManager = gitManager; + this.hooks = hooks; + + this.changeSetId = changeSetId; + } + + @Override + public TopicDetail call() throws OrmException, NoSuchEntityException, + IllegalStateException, ChangeSetInfoNotAvailableException, + NoSuchTopicException, NoSuchChangeException { + + final Topic.Id topicId = changeSetId.getParentKey(); + final TopicControl topicControl = + topicControlFactory.validateFor(topicId); + + CanSubmitResult result = topicControl.canStage(db, changeSetId, + changeControlFactory, approvalTypes, topicFunctionState); + + Repository git = null; + if (result == CanSubmitResult.OK) { + try { + // Open a handle to Git repository. + git = + gitManager.openRepository(topicControl.getProject().getNameKey()); + + // Set topic status to NEW + TopicUtil.rejectStagedTopic(changeSetId, user, db, opFactory, merger, + git, hooks); + + // Reject all changes. + final ChangeSet.Id changeSetId = + topicControl.getTopic().currChangeSetId(); + + final List<ChangeSetElement> changes = + db.changeSetElements().byChangeSet(changeSetId).toList(); + + for (ChangeSetElement changeSetElement: changes) { + final Change.Id changeId = changeSetElement.getChangeId(); + final Change change = db.changes().get(changeId); + ChangeUtil.rejectStagedChange(change.currentPatchSetId(), user, db); + } + + // Rebuild staging branch. + final Branch.NameKey branch = topicControl.getTopic().getDest(); + ChangeUtil.rebuildStaging(branch, user, db, git, opFactory, merger, + hooks); + } catch (IOException e) { + throw new IllegalStateException(e.getMessage()); + } catch (NoSuchRefException e) { + throw new IllegalStateException(e.getMessage()); + } finally { + // Make sure that access to Git repository is closed. + if (git != null) { + git.close(); + } + } + return topicDetailFactory.create(topicId).call(); + } else { + // Report error message to user. User cannot move this change to staging. + // The problem is caused because of illegal stage of missing access + // rights. + throw new IllegalStateException(result.getMessage()); + } + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/TopicUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/TopicUtil.java index 6aef58fb03..2befc26231 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/TopicUtil.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/TopicUtil.java @@ -146,6 +146,32 @@ public class TopicUtil { } } + public static void rejectStagedTopic(final ChangeSet.Id changeSetId, + final IdentifiedUser user, final ReviewDb db, + final MergeOp.Factory opFactory, final MergeQueue merger, + final Repository git, final ChangeHookRunner hooks) throws OrmException { + // Delete all STAGING approvals for the change set. + final ChangeSetApproval.Key stagingKey = + new ChangeSetApproval.Key(changeSetId, user.getAccountId(), STAGING); + db.changeSetApprovals().deleteKeys(Collections.singleton(stagingKey)); + + // Set topic state to NEW. + final Topic.Id topicId = changeSetId.getParentKey(); + AtomicUpdate<Topic> atomicUpdate = + new AtomicUpdate<Topic>() { + @Override + public Topic update(Topic topic) { + if (topic.getStatus() == AbstractEntity.Status.INTEGRATING + || topic.getStatus() == AbstractEntity.Status.STAGED) { + topic.setStatus(AbstractEntity.Status.NEW); + TopicUtil.updated(topic); + } + return topic; + } + }; + db.topics().atomicUpdate(topicId, atomicUpdate); + } + public static ChangeSetApproval createSubmitApproval( final ChangeSet.Id changeSetId, final IdentifiedUser user, final ReviewDb db ) throws OrmException { |