Skip to content

Commit 96c094f

Browse files
vs-systencessjujokini
authored andcommitted
Check parents of a merge commit before staging
Chech that parents of a merge commit are merged. If they are not, staging is not allowed. Fixes: QTQAINFRA-3341 Change-Id: I3e6f48e76bfb55a4a07c90afc9289c8d1a7ff07c Reviewed-by: Paul Wicking <[email protected]>
1 parent 5a30169 commit 96c094f

File tree

3 files changed

+77
-4
lines changed

3 files changed

+77
-4
lines changed

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

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
import com.google.gerrit.extensions.webui.UiAction;
1818
import com.google.gerrit.reviewdb.client.Branch;
1919
import com.google.gerrit.reviewdb.client.Change;
20+
import com.google.gerrit.reviewdb.client.PatchSet;
2021
import com.google.gerrit.reviewdb.client.Project;
2122
import com.google.gerrit.reviewdb.client.RevId;
23+
import com.google.gerrit.reviewdb.client.Change.Status;
2224
import com.google.gerrit.server.IdentifiedUser;
2325
import com.google.gerrit.server.ProjectUtil;
2426
import com.google.gerrit.server.account.AccountResolver;
@@ -33,19 +35,25 @@
3335
import com.google.gerrit.server.project.NoSuchRefException;
3436
import com.google.gerrit.server.project.ProjectCache;
3537
import com.google.gerrit.server.query.change.ChangeData;
38+
import com.google.gerrit.server.query.change.InternalChangeQuery;
3639
import com.google.gerrit.server.submit.IntegrationException;
3740
import com.google.gerrit.server.submit.MergeOp;
3841
import com.google.gerrit.server.update.UpdateException;
3942
import com.google.inject.Inject;
43+
import com.google.inject.Provider;
4044
import com.google.inject.Singleton;
45+
4146
import java.io.IOException;
47+
import java.util.List;
4248
import java.util.Map;
4349
import org.eclipse.jgit.errors.ConfigInvalidException;
4450
import org.eclipse.jgit.errors.RepositoryNotFoundException;
4551
import org.eclipse.jgit.lib.Config;
4652
import org.eclipse.jgit.lib.ObjectId;
4753
import org.eclipse.jgit.lib.RefUpdate.Result;
4854
import org.eclipse.jgit.lib.Repository;
55+
import org.eclipse.jgit.revwalk.RevCommit;
56+
import org.eclipse.jgit.revwalk.RevWalk;
4957

5058
@Singleton
5159
public class QtStage
@@ -70,6 +78,7 @@ private Output(Change c) {
7078
private final GitReferenceUpdated referenceUpdated;
7179
private final QtCherryPickPatch qtCherryPickPatch;
7280
private final QtUtil qtUtil;
81+
private final Provider<InternalChangeQuery> queryProvider;
7382

7483
private final AccountResolver accountResolver;
7584
private final String label;
@@ -90,7 +99,8 @@ private Output(Change c) {
9099
ProjectCache projectCache,
91100
GitReferenceUpdated referenceUpdated,
92101
QtCherryPickPatch qtCherryPickPatch,
93-
QtUtil qtUtil) {
102+
QtUtil qtUtil,
103+
Provider<InternalChangeQuery> queryProvider) {
94104

95105
this.repoManager = repoManager;
96106
this.permissionBackend = permissionBackend;
@@ -105,6 +115,7 @@ private Output(Change c) {
105115
this.referenceUpdated = referenceUpdated;
106116
this.qtCherryPickPatch = qtCherryPickPatch;
107117
this.qtUtil = qtUtil;
118+
this.queryProvider = queryProvider;
108119
}
109120

110121
@Override
@@ -171,6 +182,8 @@ private Change changeToStaging(RevisionResource rsrc, IdentifiedUser submitter,
171182
if (sourceId == null)
172183
throw new NoSuchRefException("Invalid Revision: " + rsrc.getPatchSet().getRevision().get());
173184

185+
checkParents(git, rsrc);
186+
174187
changeData = changeDataFactory.create(change);
175188
MergeOp.checkSubmitRule(changeData, false);
176189

@@ -214,6 +227,36 @@ private Change changeToStaging(RevisionResource rsrc, IdentifiedUser submitter,
214227
}
215228
}
216229

230+
private void checkParents(RevisionResource resource) throws ResourceConflictException {
231+
try (final Repository repository = repoManager.openRepository(resource.getProject())) {
232+
checkParents(repository, resource);
233+
} catch (IOException e) {
234+
throw new ResourceConflictException("Can not read repository.", e);
235+
}
236+
}
237+
238+
private void checkParents(Repository repository, RevisionResource resource) throws ResourceConflictException {
239+
try (final RevWalk rw = new RevWalk(repository)) {
240+
final PatchSet ps = resource.getPatchSet();
241+
final RevCommit rc = rw.parseCommit(ObjectId.fromString(ps.getRevision().get()));
242+
if (rc.getParentCount() < 2) {
243+
return;
244+
}
245+
for (final RevCommit parent : rc.getParents()) {
246+
final List<ChangeData> changes =
247+
queryProvider.get().enforceVisibility(true).byProjectCommit(resource.getProject(), parent);
248+
for (ChangeData cd : changes) {
249+
final Change change = cd.change();
250+
if (change.getStatus() != Status.MERGED) {
251+
throw new ResourceConflictException(String.format("Can not stage: Parent \"%s\" of a merged commit is not merged.", parent.name()));
252+
}
253+
}
254+
}
255+
} catch (IOException e) {
256+
throw new ResourceConflictException("Can not read repository.", e);
257+
}
258+
}
259+
217260
@Override
218261
public UiAction.Description getDescription(RevisionResource resource) {
219262
Change change = resource.getChange();
@@ -223,6 +266,12 @@ public UiAction.Description getDescription(RevisionResource resource) {
223266
|| !resource.permissions().testOrFalse(ChangePermission.QT_STAGE)) {
224267
return null; // submit not visible
225268
}
269+
try {
270+
checkParents(resource);
271+
} catch (ResourceConflictException e) {
272+
logger.atWarning().log("Parent(s) check failed. %s", e.getMessage());
273+
return null;
274+
}
226275
try {
227276
if (!projectCache.checkedGet(resource.getProject()).statePermitsWrite()) {
228277
return null; // stage not visible

src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtCommandBuildApproveIT.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,16 @@ public void avoid_Double_Handling_Of_Change_On_Merge_Of_Merge() throws Exception
141141
final PushOneCommit.Result m1 = pushCommit("master", "m1-commitmsg", "m1-file", "m1-content");
142142
approve(m1.getChangeId());
143143

144+
// make another change on master branch
145+
final PushOneCommit.Result m2 = pushCommit("master", "m2-commitmsg", "m2-file", "m2-content");
146+
approve(m2.getChangeId());
147+
QtStage(m2);
148+
QtNewBuild("master", "merge-build-001");
149+
QtApproveBuild("master", "merge-build-001");
150+
144151
// merge feature branch into master
145152
final PushOneCommit mm = pushFactory.create(admin.newIdent(), testRepo);
146-
mm.setParents(ImmutableList.of(f1.getCommit(), m1.getCommit()));
153+
mm.setParents(ImmutableList.of(f1.getCommit(), m2.getCommit()));
147154
final PushOneCommit.Result m = mm.to("refs/for/master");
148155
m.assertOkStatus();
149156
approve(m.getChangeId());
@@ -154,12 +161,13 @@ public void avoid_Double_Handling_Of_Change_On_Merge_Of_Merge() throws Exception
154161
QtStage(m);
155162

156163
// Create build and approve it
157-
QtNewBuild("master", "merge-build-000");
158-
QtApproveBuild("master", "merge-build-000");
164+
QtNewBuild("master", "merge-build-002");
165+
QtApproveBuild("master", "merge-build-002");
159166

160167
final Changes changes = gApi.changes();
161168
assertThat(changes.id(project.get(), "feature", f1.getChangeId()).get(CURRENT_REVISION).status).isEqualTo(ChangeStatus.MERGED);
162169
assertThat(changes.id(project.get(), "master", m1.getChangeId()).get(CURRENT_REVISION).status).isEqualTo(ChangeStatus.MERGED);
170+
assertThat(changes.id(project.get(), "master", m2.getChangeId()).get(CURRENT_REVISION).status).isEqualTo(ChangeStatus.MERGED);
163171
assertThat(changes.id(project.get(), "master", m.getChangeId()).get(CURRENT_REVISION).status).isEqualTo(ChangeStatus.MERGED);
164172
}
165173

src/test/java/com/googlesource/gerrit/plugins/qtcodereview/QtStageIT.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,22 @@ public void errorStage_Not_Reviewed() throws Exception {
217217
assertThat(response.getEntityContent()).contains("needs Code-Review");
218218
}
219219

220+
@Test
221+
public void errorStage_Parent_Not_Merged() throws Exception {
222+
RevCommit initialHead = getRemoteHead();
223+
224+
// make a change on feature branch without submit
225+
final PushOneCommit.Result f1 = pushCommit("feature", "f1-commitmsg", "f1-file", "f1-content");
226+
227+
// merge feature branch into master
228+
final PushOneCommit mm = pushFactory.create(admin.newIdent(), testRepo);
229+
mm.setParents(ImmutableList.of(f1.getCommit(), initialHead));
230+
final PushOneCommit.Result m = mm.to("refs/for/master");
231+
approve(m.getChangeId());
232+
233+
qtStageExpectFail(m, initialHead, initialHead, HttpStatus.SC_CONFLICT);
234+
}
235+
220236
@Test
221237
public void errorAmend_Status_Staged() throws Exception {
222238
RevCommit initialHead = getRemoteHead();

0 commit comments

Comments
 (0)