Skip to content

Commit be31ec0

Browse files
jujokinigladhorn
authored andcommitted
Add UnStage functionality
Add UnStage button to UI and corresponding REST API. Fixes: QTBI-1403 Change-Id: Ibab2f37a16b907a3977edbd07e9e685373e7c9fe Reviewed-by: Frederik Gladhorn <[email protected]>
1 parent 765d16c commit be31ec0

File tree

6 files changed

+776
-0
lines changed

6 files changed

+776
-0
lines changed

qt-gerrit-ui-plugin/qt-gerrit-ui-plugin.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
'gerrit-plugin-qt-workflow~stage' : {
2525
header: 'Submit to staging?',
2626
action_name: 'stage'
27+
},
28+
'gerrit-plugin-qt-workflow~unstage' : {
29+
header: 'Unstage the change?',
30+
action_name: 'unstage'
2731
}
2832
};
2933

src/main/java/com/googlesource/gerrit/plugins/qtcodereview/QtModule.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ protected void configure() {
3434
post(CHANGE_KIND, "defer").to(QtDefer.class);
3535
post(CHANGE_KIND, "reopen").to(QtReOpen.class);
3636
post(REVISION_KIND, "stage").to(QtStage.class);
37+
post(REVISION_KIND, "unstage").to(QtUnStage.class);
3738
}
3839
}
3940
);
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
//
2+
// Copyright (C) 2019 The Qt Company
3+
//
4+
5+
6+
package com.googlesource.gerrit.plugins.qtcodereview;
7+
8+
import com.google.common.base.Strings;
9+
import com.google.common.flogger.FluentLogger;
10+
import com.google.gerrit.extensions.api.changes.SubmitInput;
11+
import com.google.gerrit.extensions.restapi.AuthException;
12+
import com.google.gerrit.extensions.restapi.ResourceConflictException;
13+
import com.google.gerrit.extensions.restapi.RestApiException;
14+
import com.google.gerrit.extensions.restapi.RestModifyView;
15+
import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
16+
import com.google.gerrit.extensions.webui.UiAction;
17+
import com.google.gerrit.reviewdb.client.Branch;
18+
import com.google.gerrit.reviewdb.client.Change;
19+
import com.google.gerrit.reviewdb.client.Project;
20+
import com.google.gerrit.reviewdb.server.ReviewDb;
21+
import com.google.gerrit.reviewdb.client.PatchSet;
22+
import com.google.gerrit.server.CurrentUser;
23+
import com.google.gerrit.server.IdentifiedUser;
24+
import com.google.gerrit.server.ProjectUtil;
25+
import com.google.gerrit.server.account.AccountResolver;
26+
import com.google.gerrit.server.change.RevisionResource;
27+
import com.google.gerrit.server.git.GitRepositoryManager;
28+
import com.google.gerrit.server.permissions.ChangePermission;
29+
import com.google.gerrit.server.permissions.PermissionBackend;
30+
import com.google.gerrit.server.permissions.PermissionBackendException;
31+
import com.google.gerrit.server.permissions.RefPermission;
32+
import com.google.gerrit.server.project.ProjectCache;
33+
import com.google.gerrit.server.query.change.InternalChangeQuery;
34+
import com.google.gerrit.server.update.BatchUpdate;
35+
import com.google.gerrit.server.update.UpdateException;
36+
import com.google.gerrit.server.util.time.TimeUtil;
37+
import com.google.gwtorm.server.OrmException;
38+
import com.google.inject.Inject;
39+
import com.google.inject.Provider;
40+
import java.io.IOException;
41+
import org.eclipse.jgit.errors.ConfigInvalidException;
42+
import org.eclipse.jgit.lib.Repository;
43+
import org.eclipse.jgit.lib.ObjectId;
44+
45+
46+
class QtUnStage implements RestModifyView<RevisionResource, SubmitInput>, UiAction<RevisionResource> {
47+
48+
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
49+
50+
public static class Output {
51+
transient Change change;
52+
53+
private Output(Change c) {
54+
change = c;
55+
}
56+
}
57+
58+
private final Provider<ReviewDb> dbProvider;
59+
private final GitRepositoryManager repoManager;
60+
private final PermissionBackend permissionBackend;
61+
private final BatchUpdate.Factory updateFactory;
62+
private final AccountResolver accountResolver;
63+
private final ProjectCache projectCache;
64+
65+
private final QtUtil qtUtil;
66+
private final QtChangeUpdateOp.Factory qtUpdateFactory;
67+
68+
private Change change;
69+
private Project.NameKey projectKey;
70+
private Branch.NameKey destBranchKey;
71+
private Branch.NameKey stagingBranchKey;
72+
73+
@Inject
74+
QtUnStage(
75+
Provider<ReviewDb> dbProvider,
76+
GitRepositoryManager repoManager,
77+
PermissionBackend permissionBackend,
78+
BatchUpdate.Factory updateFactory,
79+
AccountResolver accountResolver,
80+
ProjectCache projectCache,
81+
QtUtil qtUtil,
82+
QtChangeUpdateOp.Factory qtUpdateFactory) {
83+
this.dbProvider = dbProvider;
84+
this.repoManager = repoManager;
85+
this.permissionBackend = permissionBackend;
86+
this.updateFactory = updateFactory;
87+
this.accountResolver = accountResolver;
88+
this.projectCache = projectCache;
89+
this.qtUtil = qtUtil;
90+
this.qtUpdateFactory = qtUpdateFactory;
91+
}
92+
93+
@Override
94+
public Output apply(RevisionResource rsrc, SubmitInput input)
95+
throws RestApiException, IOException, OrmException, UpdateException,
96+
PermissionBackendException, ConfigInvalidException {
97+
98+
logger.atInfo().log("qtcodereview: unstage %s", rsrc.getChange().toString());
99+
100+
IdentifiedUser submitter = rsrc.getUser().asIdentifiedUser();
101+
102+
change = rsrc.getChange();
103+
projectKey = rsrc.getProject();
104+
destBranchKey = change.getDest();
105+
stagingBranchKey = QtUtil.getStagingBranch(destBranchKey);
106+
107+
rsrc.permissions().check(ChangePermission.QT_STAGE);
108+
109+
projectCache.checkedGet(rsrc.getProject()).checkStatePermitsWrite();
110+
111+
return new Output(removeChangeFromStaging(rsrc, submitter));
112+
}
113+
114+
private Change removeChangeFromStaging(RevisionResource rsrc, IdentifiedUser submitter)
115+
throws IOException, ResourceConflictException, RestApiException, UpdateException {
116+
117+
Repository git = null;
118+
final Project.NameKey projectKey = rsrc.getProject();
119+
PatchSet patchSet = rsrc.getPatchSet();
120+
121+
logger.atInfo().log("qtcodereview: unstage start for %s", change);
122+
123+
if (change.getStatus() != Change.Status.STAGED) {
124+
logger.atSevere().log("qtcodereview: unstage: change %s status wrong %s", change, change.getStatus());
125+
throw new ResourceConflictException("change is " + change.getStatus());
126+
} else if (!ProjectUtil.branchExists(repoManager, change.getDest())) {
127+
logger.atSevere().log("qtcodereview: unstage: change %s destination branch \"%s\" not found", change, change.getDest().get());
128+
throw new ResourceConflictException(String.format("destination branch \"%s\" not found.", change.getDest().get()));
129+
} else if (!rsrc.getPatchSet().getId().equals(change.currentPatchSetId())) {
130+
logger.atSevere().log("qtcodereview: unstage: change %s revision %s is not current revision", change, rsrc.getPatchSet().getRevision().get());
131+
throw new ResourceConflictException(String.format("revision %s is not current revision", rsrc.getPatchSet().getRevision().get()));
132+
}
133+
134+
final Branch.NameKey destBranchShortKey = QtUtil.getNameKeyShort(projectKey.get(), QtUtil.R_STAGING, stagingBranchKey.get());
135+
136+
try {
137+
git = repoManager.openRepository(projectKey);
138+
139+
ObjectId srcId = git.resolve(patchSet.getRevision().get());
140+
if (srcId == null) {
141+
logger.atSevere().log("qtcodereview: unstage merge: change %s has invalid revision %s", change, patchSet);
142+
throw new ResourceConflictException("Invalid Revision: " + patchSet);
143+
}
144+
145+
QtChangeUpdateOp op = qtUpdateFactory.create(Change.Status.NEW, "Unstaged", null, null, null);
146+
BatchUpdate u = updateFactory.create(dbProvider.get(), projectKey, submitter, TimeUtil.nowTs());
147+
u.addOp(rsrc.getChange().getId(), op).execute();
148+
149+
qtUtil.rebuildStagingBranch(git, submitter, projectKey, stagingBranchKey, destBranchShortKey);
150+
151+
change = op.getChange();
152+
logger.atInfo().log("qtcodereview: unstaged %s from %s", change, stagingBranchKey);
153+
154+
} catch (ResourceConflictException e) {
155+
logger.atSevere().log("qtcodereview: unstage resource conflict error %s", e);
156+
throw new ResourceConflictException(e.toString());
157+
} catch (QtUtil.MergeConflictException e) {
158+
logger.atSevere().log("qtcodereview: unstage merge conflict error %s", e);
159+
throw new IOException(e);
160+
} catch (IOException e) {
161+
logger.atSevere().log("qtcodereview: unstage IOException %s", e);
162+
throw new IOException(e);
163+
} finally {
164+
if (git != null) {
165+
git.close();
166+
}
167+
}
168+
169+
return change; // this doesn't return data to client, if needed use ChangeJson to convert it
170+
}
171+
172+
@Override
173+
public UiAction.Description getDescription(RevisionResource rsrc) {
174+
UiAction.Description description = new UiAction.Description()
175+
.setLabel("Unstage")
176+
.setTitle("Unstage the change")
177+
.setVisible(false);
178+
179+
Change change = rsrc.getChange();
180+
if (change.getStatus() != Change.Status.STAGED) {
181+
return description;
182+
}
183+
184+
try {
185+
change = rsrc.getChange();
186+
projectKey = rsrc.getProject();
187+
destBranchKey = change.getDest();
188+
stagingBranchKey = QtUtil.getStagingBranch(destBranchKey);
189+
rsrc.permissions().check(ChangePermission.QT_STAGE);
190+
} catch (AuthException | PermissionBackendException e) {
191+
return description;
192+
}
193+
194+
try {
195+
if (!projectCache.checkedGet(rsrc.getProject()).statePermitsWrite()) {
196+
return description;
197+
}
198+
} catch (IOException e) {
199+
logger.atSevere().withCause(e).log("Failed to check if project state permits write: %s", rsrc.getProject());
200+
return description;
201+
}
202+
203+
return description.setVisible(true);
204+
}
205+
206+
}

0 commit comments

Comments
 (0)