Refactor submit logic into gerrit-server
This change moves logic that was duplicated over the ssh command and the rpc handler into a Submit class in gerrit-server. Change-Id: I70cf5aa04d091e5652d8bc3e5a254339a80bd6fd
This commit is contained in:
committed by
Edwin Kempin
parent
c5635f2131
commit
6ada0d28c8
@@ -52,25 +52,59 @@ public class ReviewResult {
|
|||||||
ABANDON_NOT_PERMITTED,
|
ABANDON_NOT_PERMITTED,
|
||||||
|
|
||||||
/** Not permitted to restore this change. */
|
/** Not permitted to restore this change. */
|
||||||
RESTORE_NOT_PERMITTED
|
RESTORE_NOT_PERMITTED,
|
||||||
|
|
||||||
|
/** Not permitted to submit this change. */
|
||||||
|
SUBMIT_NOT_PERMITTED,
|
||||||
|
|
||||||
|
/** Approvals or dependencies are lacking for submission. */
|
||||||
|
SUBMIT_NOT_READY,
|
||||||
|
|
||||||
|
/** Review operation invalid because change is closed. */
|
||||||
|
CHANGE_IS_CLOSED,
|
||||||
|
|
||||||
|
/** Review operation not permitted by rule. */
|
||||||
|
RULE_ERROR
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Type type;
|
protected Type type;
|
||||||
|
protected String message;
|
||||||
|
|
||||||
protected Error() {
|
protected Error() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Error(final Type type) {
|
public Error(final Type type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.message = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Error(final Type type, final String message) {
|
||||||
|
this.type = type;
|
||||||
|
this.message = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getType() {
|
public Type getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMessageOrType() {
|
||||||
|
if (message != null) {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
return "" + type;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return type + "";
|
String ret = type + "";
|
||||||
|
if (message != null) {
|
||||||
|
ret += " " + message;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,109 +15,48 @@
|
|||||||
package com.google.gerrit.httpd.rpc.changedetail;
|
package com.google.gerrit.httpd.rpc.changedetail;
|
||||||
|
|
||||||
import com.google.gerrit.common.data.ChangeDetail;
|
import com.google.gerrit.common.data.ChangeDetail;
|
||||||
import com.google.gerrit.common.data.SubmitRecord;
|
import com.google.gerrit.common.data.ReviewResult;
|
||||||
import com.google.gerrit.common.errors.NoSuchEntityException;
|
import com.google.gerrit.common.errors.NoSuchEntityException;
|
||||||
import com.google.gerrit.httpd.rpc.Handler;
|
import com.google.gerrit.httpd.rpc.Handler;
|
||||||
import com.google.gerrit.reviewdb.Change;
|
|
||||||
import com.google.gerrit.reviewdb.PatchSet;
|
import com.google.gerrit.reviewdb.PatchSet;
|
||||||
import com.google.gerrit.reviewdb.ReviewDb;
|
import com.google.gerrit.server.changedetail.Submit;
|
||||||
import com.google.gerrit.server.ChangeUtil;
|
|
||||||
import com.google.gerrit.server.IdentifiedUser;
|
|
||||||
import com.google.gerrit.server.git.MergeOp;
|
|
||||||
import com.google.gerrit.server.git.MergeQueue;
|
|
||||||
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
|
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
|
||||||
import com.google.gerrit.server.project.ChangeControl;
|
import com.google.gerrit.server.project.InvalidChangeOperationException;
|
||||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||||
import com.google.gwtorm.client.OrmException;
|
import com.google.gwtorm.client.OrmException;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.assistedinject.Assisted;
|
import com.google.inject.assistedinject.Assisted;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
class SubmitAction extends Handler<ChangeDetail> {
|
class SubmitAction extends Handler<ChangeDetail> {
|
||||||
interface Factory {
|
interface Factory {
|
||||||
SubmitAction create(PatchSet.Id patchSetId);
|
SubmitAction create(PatchSet.Id patchSetId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final ReviewDb db;
|
private final Submit.Factory submitFactory;
|
||||||
private final MergeQueue merger;
|
|
||||||
private final IdentifiedUser user;
|
|
||||||
private final ChangeDetailFactory.Factory changeDetailFactory;
|
private final ChangeDetailFactory.Factory changeDetailFactory;
|
||||||
private final ChangeControl.Factory changeControlFactory;
|
|
||||||
private final MergeOp.Factory opFactory;
|
|
||||||
|
|
||||||
private final PatchSet.Id patchSetId;
|
private final PatchSet.Id patchSetId;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
SubmitAction(final ReviewDb db, final MergeQueue mq,
|
SubmitAction(final Submit.Factory submitFactory,
|
||||||
final IdentifiedUser user,
|
|
||||||
final ChangeDetailFactory.Factory changeDetailFactory,
|
final ChangeDetailFactory.Factory changeDetailFactory,
|
||||||
final ChangeControl.Factory changeControlFactory,
|
|
||||||
final MergeOp.Factory opFactory,
|
|
||||||
@Assisted final PatchSet.Id patchSetId) {
|
@Assisted final PatchSet.Id patchSetId) {
|
||||||
this.db = db;
|
this.submitFactory = submitFactory;
|
||||||
this.merger = mq;
|
|
||||||
this.user = user;
|
|
||||||
this.changeControlFactory = changeControlFactory;
|
|
||||||
this.changeDetailFactory = changeDetailFactory;
|
this.changeDetailFactory = changeDetailFactory;
|
||||||
this.opFactory = opFactory;
|
|
||||||
|
|
||||||
this.patchSetId = patchSetId;
|
this.patchSetId = patchSetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ChangeDetail call() throws OrmException, NoSuchEntityException,
|
public ChangeDetail call() throws OrmException, NoSuchEntityException,
|
||||||
IllegalStateException, PatchSetInfoNotAvailableException,
|
IllegalStateException, InvalidChangeOperationException,
|
||||||
NoSuchChangeException {
|
PatchSetInfoNotAvailableException, NoSuchChangeException {
|
||||||
|
final ReviewResult result =
|
||||||
final Change.Id changeId = patchSetId.getParentKey();
|
submitFactory.create(patchSetId).call();
|
||||||
final ChangeControl changeControl =
|
if (result.getErrors().size() > 0) {
|
||||||
changeControlFactory.validateFor(changeId);
|
throw new IllegalStateException(
|
||||||
|
"Cannot submit " + result.getErrors().get(0).getMessageOrType());
|
||||||
List<SubmitRecord> result = changeControl.canSubmit(db, patchSetId);
|
|
||||||
if (result.isEmpty()) {
|
|
||||||
throw new IllegalStateException("Cannot submit");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (result.get(0).status) {
|
|
||||||
case OK:
|
|
||||||
ChangeUtil.submit(patchSetId, user, db, opFactory, merger);
|
|
||||||
return changeDetailFactory.create(changeId).call();
|
|
||||||
|
|
||||||
case NOT_READY: {
|
|
||||||
for (SubmitRecord.Label lbl : result.get(0).labels) {
|
|
||||||
switch (lbl.status) {
|
|
||||||
case OK:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case REJECT:
|
|
||||||
throw new IllegalStateException("Blocked by " + lbl.label);
|
|
||||||
|
|
||||||
case NEED:
|
|
||||||
throw new IllegalStateException("Needs " + lbl.label);
|
|
||||||
|
|
||||||
case IMPOSSIBLE:
|
|
||||||
throw new IllegalStateException("Cannnot submit, check project access");
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Unknown status " + lbl.status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new IllegalStateException("Cannot submit");
|
|
||||||
}
|
|
||||||
|
|
||||||
case CLOSED:
|
|
||||||
throw new IllegalStateException("Change is closed");
|
|
||||||
|
|
||||||
case RULE_ERROR:
|
|
||||||
if (result.get(0).errorMessage != null) {
|
|
||||||
throw new IllegalStateException(result.get(0).errorMessage);
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Internal rule error");
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException("Uknown status " + result.get(0).status);
|
|
||||||
}
|
}
|
||||||
|
return changeDetailFactory.create(result.getChangeId()).call();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@
|
|||||||
|
|
||||||
package com.google.gerrit.server;
|
package com.google.gerrit.server;
|
||||||
|
|
||||||
import static com.google.gerrit.reviewdb.ApprovalCategory.SUBMIT;
|
|
||||||
|
|
||||||
import com.google.gerrit.common.ChangeHooks;
|
import com.google.gerrit.common.ChangeHooks;
|
||||||
import com.google.gerrit.reviewdb.Change;
|
import com.google.gerrit.reviewdb.Change;
|
||||||
import com.google.gerrit.reviewdb.ChangeMessage;
|
import com.google.gerrit.reviewdb.ChangeMessage;
|
||||||
@@ -29,7 +27,6 @@ import com.google.gerrit.server.config.TrackingFooter;
|
|||||||
import com.google.gerrit.server.config.TrackingFooters;
|
import com.google.gerrit.server.config.TrackingFooters;
|
||||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||||
import com.google.gerrit.server.git.MergeOp;
|
import com.google.gerrit.server.git.MergeOp;
|
||||||
import com.google.gerrit.server.git.MergeQueue;
|
|
||||||
import com.google.gerrit.server.git.ReplicationQueue;
|
import com.google.gerrit.server.git.ReplicationQueue;
|
||||||
import com.google.gerrit.server.mail.EmailException;
|
import com.google.gerrit.server.mail.EmailException;
|
||||||
import com.google.gerrit.server.mail.ReplyToChangeSender;
|
import com.google.gerrit.server.mail.ReplyToChangeSender;
|
||||||
@@ -59,7 +56,6 @@ import org.eclipse.jgit.util.Base64;
|
|||||||
import org.eclipse.jgit.util.NB;
|
import org.eclipse.jgit.util.NB;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -166,52 +162,6 @@ public class ChangeUtil {
|
|||||||
opFactory.create(change.getDest()).verifyMergeability(change);
|
opFactory.create(change.getDest()).verifyMergeability(change);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void submit(final PatchSet.Id patchSetId,
|
|
||||||
final IdentifiedUser user, final ReviewDb db,
|
|
||||||
final MergeOp.Factory opFactory, final MergeQueue merger)
|
|
||||||
throws OrmException {
|
|
||||||
final Change.Id changeId = patchSetId.getParentKey();
|
|
||||||
final PatchSetApproval approval = createSubmitApproval(patchSetId, user, db);
|
|
||||||
|
|
||||||
db.patchSetApprovals().upsert(Collections.singleton(approval));
|
|
||||||
|
|
||||||
final Change updatedChange = db.changes().atomicUpdate(changeId,
|
|
||||||
new AtomicUpdate<Change>() {
|
|
||||||
@Override
|
|
||||||
public Change update(Change change) {
|
|
||||||
if (change.getStatus() == Change.Status.NEW) {
|
|
||||||
change.setStatus(Change.Status.SUBMITTED);
|
|
||||||
ChangeUtil.updated(change);
|
|
||||||
}
|
|
||||||
return change;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (updatedChange.getStatus() == Change.Status.SUBMITTED) {
|
|
||||||
merger.merge(opFactory, updatedChange.getDest());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PatchSetApproval createSubmitApproval(
|
|
||||||
final PatchSet.Id patchSetId, final IdentifiedUser user, final ReviewDb db
|
|
||||||
) throws OrmException {
|
|
||||||
final List<PatchSetApproval> allApprovals =
|
|
||||||
new ArrayList<PatchSetApproval>(db.patchSetApprovals().byPatchSet(
|
|
||||||
patchSetId).toList());
|
|
||||||
|
|
||||||
final PatchSetApproval.Key akey =
|
|
||||||
new PatchSetApproval.Key(patchSetId, user.getAccountId(), SUBMIT);
|
|
||||||
|
|
||||||
for (final PatchSetApproval approval : allApprovals) {
|
|
||||||
if (akey.equals(approval.getKey())) {
|
|
||||||
approval.setValue((short) 1);
|
|
||||||
approval.setGranted();
|
|
||||||
return approval;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return new PatchSetApproval(akey, (short) 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Change.Id revert(final PatchSet.Id patchSetId,
|
public static Change.Id revert(final PatchSet.Id patchSetId,
|
||||||
final IdentifiedUser user, final String message, final ReviewDb db,
|
final IdentifiedUser user, final String message, final ReviewDb db,
|
||||||
final RevertedSender.Factory revertedSenderFactory,
|
final RevertedSender.Factory revertedSenderFactory,
|
||||||
|
|||||||
@@ -0,0 +1,189 @@
|
|||||||
|
// Copyright (C) 2012 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.server.changedetail;
|
||||||
|
|
||||||
|
import static com.google.gerrit.reviewdb.ApprovalCategory.SUBMIT;
|
||||||
|
|
||||||
|
import com.google.gerrit.common.data.ReviewResult;
|
||||||
|
import com.google.gerrit.common.data.SubmitRecord;
|
||||||
|
import com.google.gerrit.reviewdb.Change;
|
||||||
|
import com.google.gerrit.reviewdb.PatchSet;
|
||||||
|
import com.google.gerrit.reviewdb.PatchSetApproval;
|
||||||
|
import com.google.gerrit.reviewdb.ReviewDb;
|
||||||
|
import com.google.gerrit.server.ChangeUtil;
|
||||||
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
|
import com.google.gerrit.server.git.MergeOp;
|
||||||
|
import com.google.gerrit.server.git.MergeQueue;
|
||||||
|
import com.google.gerrit.server.project.InvalidChangeOperationException;
|
||||||
|
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||||
|
import com.google.gerrit.server.project.ChangeControl;
|
||||||
|
import com.google.gwtorm.client.AtomicUpdate;
|
||||||
|
import com.google.gwtorm.client.OrmException;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.assistedinject.Assisted;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Submit implements Callable<ReviewResult> {
|
||||||
|
|
||||||
|
public interface Factory {
|
||||||
|
Submit create(PatchSet.Id patchSetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ChangeControl.Factory changeControlFactory;
|
||||||
|
private final MergeOp.Factory opFactory;
|
||||||
|
private final MergeQueue merger;
|
||||||
|
private final ReviewDb db;
|
||||||
|
private final IdentifiedUser currentUser;
|
||||||
|
|
||||||
|
private final PatchSet.Id patchSetId;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
Submit(final ChangeControl.Factory changeControlFactory,
|
||||||
|
final MergeOp.Factory opFactory, final MergeQueue merger,
|
||||||
|
final ReviewDb db, final IdentifiedUser currentUser,
|
||||||
|
@Assisted final PatchSet.Id patchSetId) {
|
||||||
|
this.changeControlFactory = changeControlFactory;
|
||||||
|
this.opFactory = opFactory;
|
||||||
|
this.merger = merger;
|
||||||
|
this.db = db;
|
||||||
|
this.currentUser = currentUser;
|
||||||
|
|
||||||
|
this.patchSetId = patchSetId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ReviewResult call() throws IllegalStateException,
|
||||||
|
InvalidChangeOperationException, NoSuchChangeException, OrmException {
|
||||||
|
final ReviewResult result = new ReviewResult();
|
||||||
|
|
||||||
|
final PatchSet patch = db.patchSets().get(patchSetId);
|
||||||
|
final Change.Id changeId = patchSetId.getParentKey();
|
||||||
|
final ChangeControl control = changeControlFactory.validateFor(changeId);
|
||||||
|
result.setChangeId(changeId);
|
||||||
|
if (patch == null) {
|
||||||
|
throw new NoSuchChangeException(changeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SubmitRecord> submitResult = control.canSubmit(db, patchSetId);
|
||||||
|
if (submitResult.isEmpty()) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"ChangeControl.canSubmit returned empty list");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (SubmitRecord submitRecord : submitResult) {
|
||||||
|
switch (submitRecord.status) {
|
||||||
|
case OK:
|
||||||
|
if (!control.getRefControl().canSubmit()) {
|
||||||
|
result.addError(new ReviewResult.Error(
|
||||||
|
ReviewResult.Error.Type.SUBMIT_NOT_PERMITTED));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NOT_READY:
|
||||||
|
StringBuilder errMsg = new StringBuilder();
|
||||||
|
for (SubmitRecord.Label lbl : submitRecord.labels) {
|
||||||
|
switch (lbl.status) {
|
||||||
|
case OK:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case REJECT:
|
||||||
|
if (errMsg.length() > 0) errMsg.append("; ");
|
||||||
|
errMsg.append("change " + changeId + ": blocked by "
|
||||||
|
+ lbl.label);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NEED:
|
||||||
|
if (errMsg.length() > 0) errMsg.append("; ");
|
||||||
|
errMsg.append("change " + changeId + ": needs " + lbl.label);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IMPOSSIBLE:
|
||||||
|
if (errMsg.length() > 0) errMsg.append("; ");
|
||||||
|
errMsg.append("change " + changeId + ": needs " + lbl.label
|
||||||
|
+ " (check project access)");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Unsupported SubmitRecord.Label.status (" + lbl.status
|
||||||
|
+ ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.addError(new ReviewResult.Error(
|
||||||
|
ReviewResult.Error.Type.SUBMIT_NOT_READY, errMsg.toString()));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CLOSED:
|
||||||
|
result.addError(new ReviewResult.Error(
|
||||||
|
ReviewResult.Error.Type.CHANGE_IS_CLOSED));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RULE_ERROR:
|
||||||
|
result.addError(new ReviewResult.Error(
|
||||||
|
ReviewResult.Error.Type.RULE_ERROR,
|
||||||
|
submitResult.get(0).errorMessage));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Unsupported SubmitRecord.status + (" + submitRecord.status
|
||||||
|
+ ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Submit the change if we can
|
||||||
|
if (result.getErrors().isEmpty()) {
|
||||||
|
final List<PatchSetApproval> allApprovals =
|
||||||
|
new ArrayList<PatchSetApproval>(db.patchSetApprovals().byPatchSet(
|
||||||
|
patchSetId).toList());
|
||||||
|
|
||||||
|
final PatchSetApproval.Key akey =
|
||||||
|
new PatchSetApproval.Key(patchSetId, currentUser.getAccountId(),
|
||||||
|
SUBMIT);
|
||||||
|
|
||||||
|
PatchSetApproval approval = new PatchSetApproval(akey, (short) 1);
|
||||||
|
for (final PatchSetApproval candidateApproval : allApprovals) {
|
||||||
|
if (akey.equals(candidateApproval.getKey())) {
|
||||||
|
candidateApproval.setValue((short) 1);
|
||||||
|
candidateApproval.setGranted();
|
||||||
|
approval = candidateApproval;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db.patchSetApprovals().upsert(Collections.singleton(approval));
|
||||||
|
|
||||||
|
final Change updatedChange = db.changes().atomicUpdate(changeId,
|
||||||
|
new AtomicUpdate<Change>() {
|
||||||
|
@Override
|
||||||
|
public Change update(Change change) {
|
||||||
|
if (change.getStatus() == Change.Status.NEW) {
|
||||||
|
change.setStatus(Change.Status.SUBMITTED);
|
||||||
|
ChangeUtil.updated(change);
|
||||||
|
}
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (updatedChange.getStatus() == Change.Status.SUBMITTED) {
|
||||||
|
merger.merge(opFactory, updatedChange.getDest());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ import com.google.gerrit.server.account.PerformRenameGroup;
|
|||||||
import com.google.gerrit.server.account.VisibleGroups;
|
import com.google.gerrit.server.account.VisibleGroups;
|
||||||
import com.google.gerrit.server.changedetail.AbandonChange;
|
import com.google.gerrit.server.changedetail.AbandonChange;
|
||||||
import com.google.gerrit.server.changedetail.RestoreChange;
|
import com.google.gerrit.server.changedetail.RestoreChange;
|
||||||
|
import com.google.gerrit.server.changedetail.Submit;
|
||||||
import com.google.gerrit.server.git.CreateCodeReviewNotes;
|
import com.google.gerrit.server.git.CreateCodeReviewNotes;
|
||||||
import com.google.gerrit.server.git.MergeOp;
|
import com.google.gerrit.server.git.MergeOp;
|
||||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||||
@@ -101,5 +102,6 @@ public class GerritRequestModule extends FactoryModule {
|
|||||||
factory(GroupDetailFactory.Factory.class);
|
factory(GroupDetailFactory.Factory.class);
|
||||||
factory(GroupMembers.Factory.class);
|
factory(GroupMembers.Factory.class);
|
||||||
factory(CreateProject.Factory.class);
|
factory(CreateProject.Factory.class);
|
||||||
|
factory(Submit.Factory.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,8 @@ package com.google.gerrit.sshd.commands;
|
|||||||
import com.google.gerrit.common.data.ApprovalType;
|
import com.google.gerrit.common.data.ApprovalType;
|
||||||
import com.google.gerrit.common.data.ApprovalTypes;
|
import com.google.gerrit.common.data.ApprovalTypes;
|
||||||
import com.google.gerrit.common.data.ReviewResult;
|
import com.google.gerrit.common.data.ReviewResult;
|
||||||
import com.google.gerrit.common.data.SubmitRecord;
|
|
||||||
import com.google.gerrit.reviewdb.ApprovalCategory;
|
import com.google.gerrit.reviewdb.ApprovalCategory;
|
||||||
import com.google.gerrit.reviewdb.ApprovalCategoryValue;
|
import com.google.gerrit.reviewdb.ApprovalCategoryValue;
|
||||||
import com.google.gerrit.reviewdb.Branch;
|
|
||||||
import com.google.gerrit.reviewdb.Change;
|
import com.google.gerrit.reviewdb.Change;
|
||||||
import com.google.gerrit.reviewdb.PatchSet;
|
import com.google.gerrit.reviewdb.PatchSet;
|
||||||
import com.google.gerrit.reviewdb.PatchSetApproval;
|
import com.google.gerrit.reviewdb.PatchSetApproval;
|
||||||
@@ -30,9 +28,8 @@ import com.google.gerrit.server.ChangeUtil;
|
|||||||
import com.google.gerrit.server.IdentifiedUser;
|
import com.google.gerrit.server.IdentifiedUser;
|
||||||
import com.google.gerrit.server.changedetail.AbandonChange;
|
import com.google.gerrit.server.changedetail.AbandonChange;
|
||||||
import com.google.gerrit.server.changedetail.RestoreChange;
|
import com.google.gerrit.server.changedetail.RestoreChange;
|
||||||
|
import com.google.gerrit.server.changedetail.Submit;
|
||||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
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.git.ReplicationQueue;
|
import com.google.gerrit.server.git.ReplicationQueue;
|
||||||
import com.google.gerrit.server.mail.EmailException;
|
import com.google.gerrit.server.mail.EmailException;
|
||||||
import com.google.gerrit.server.patch.PatchSetInfoFactory;
|
import com.google.gerrit.server.patch.PatchSetInfoFactory;
|
||||||
@@ -61,7 +58,6 @@ import java.util.Collections;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public class ReviewCommand extends BaseCommand {
|
public class ReviewCommand extends BaseCommand {
|
||||||
private static final Logger log =
|
private static final Logger log =
|
||||||
@@ -120,12 +116,6 @@ public class ReviewCommand extends BaseCommand {
|
|||||||
@Inject
|
@Inject
|
||||||
private IdentifiedUser currentUser;
|
private IdentifiedUser currentUser;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private MergeQueue merger;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private MergeOp.Factory opFactory;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private ApprovalTypes approvalTypes;
|
private ApprovalTypes approvalTypes;
|
||||||
|
|
||||||
@@ -150,13 +140,14 @@ public class ReviewCommand extends BaseCommand {
|
|||||||
@Inject
|
@Inject
|
||||||
private ReplicationQueue replication;
|
private ReplicationQueue replication;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private Submit.Factory submitFactory;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private PatchSetInfoFactory patchSetInfoFactory;
|
private PatchSetInfoFactory patchSetInfoFactory;
|
||||||
|
|
||||||
private List<ApproveOption> optionList;
|
private List<ApproveOption> optionList;
|
||||||
|
|
||||||
private Set<PatchSet.Id> toSubmit = new HashSet<PatchSet.Id>();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void start(final Environment env) {
|
public final void start(final Environment env) {
|
||||||
startThread(new CommandRunnable() {
|
startThread(new CommandRunnable() {
|
||||||
@@ -210,36 +201,6 @@ public class ReviewCommand extends BaseCommand {
|
|||||||
+ " review output above");
|
+ " review output above");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!toSubmit.isEmpty()) {
|
|
||||||
final Set<Branch.NameKey> toMerge = new HashSet<Branch.NameKey>();
|
|
||||||
try {
|
|
||||||
for (PatchSet.Id patchSetId : toSubmit) {
|
|
||||||
ChangeUtil.submit(patchSetId, currentUser, db, opFactory,
|
|
||||||
new MergeQueue() {
|
|
||||||
@Override
|
|
||||||
public void merge(MergeOp.Factory mof, Branch.NameKey branch) {
|
|
||||||
toMerge.add(branch);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void schedule(Branch.NameKey branch) {
|
|
||||||
toMerge.add(branch);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void recheckAfter(Branch.NameKey branch, long delay,
|
|
||||||
TimeUnit delayUnit) {
|
|
||||||
toMerge.add(branch);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
for (Branch.NameKey branch : toMerge) {
|
|
||||||
merger.merge(opFactory, branch);
|
|
||||||
}
|
|
||||||
} catch (OrmException updateError) {
|
|
||||||
throw new Failure(1, "one or more submits failed", updateError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -249,7 +210,6 @@ public class ReviewCommand extends BaseCommand {
|
|||||||
|
|
||||||
final Change.Id changeId = patchSetId.getParentKey();
|
final Change.Id changeId = patchSetId.getParentKey();
|
||||||
|
|
||||||
ReviewResult result = null;
|
|
||||||
ChangeControl changeControl = changeControlFactory.validateFor(changeId);
|
ChangeControl changeControl = changeControlFactory.validateFor(changeId);
|
||||||
|
|
||||||
if (changeComment == null) {
|
if (changeComment == null) {
|
||||||
@@ -269,75 +229,24 @@ public class ReviewCommand extends BaseCommand {
|
|||||||
publishCommentsFactory.create(patchSetId, changeComment, aps, forceMessage).call();
|
publishCommentsFactory.create(patchSetId, changeComment, aps, forceMessage).call();
|
||||||
|
|
||||||
if (abandonChange) {
|
if (abandonChange) {
|
||||||
result = abandonChangeFactory.create(patchSetId, changeComment).call();
|
ReviewResult result = abandonChangeFactory.create(
|
||||||
|
patchSetId, changeComment).call();
|
||||||
|
handleReviewResultErrors(result);
|
||||||
} else if (restoreChange) {
|
} else if (restoreChange) {
|
||||||
result = restoreChangeFactory.create(patchSetId, changeComment).call();
|
ReviewResult result = restoreChangeFactory.create(
|
||||||
if (submitChange) {
|
patchSetId, changeComment).call();
|
||||||
changeControl = changeControlFactory.validateFor(changeId);
|
handleReviewResultErrors(result);
|
||||||
}
|
}
|
||||||
|
if (submitChange) {
|
||||||
|
ReviewResult result = submitFactory.create(patchSetId).call();
|
||||||
|
handleReviewResultErrors(result);
|
||||||
}
|
}
|
||||||
} catch (InvalidChangeOperationException e) {
|
} catch (InvalidChangeOperationException e) {
|
||||||
throw error(e.getMessage());
|
throw error(e.getMessage());
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
throw error(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (submitChange) {
|
|
||||||
List<SubmitRecord> submitResult = changeControl.canSubmit(db, patchSetId);
|
|
||||||
if (submitResult.isEmpty()) {
|
|
||||||
throw new Failure(1, "ChangeControl.canSubmit returned empty list");
|
|
||||||
}
|
|
||||||
switch (submitResult.get(0).status) {
|
|
||||||
case OK:
|
|
||||||
if (changeControl.getRefControl().canSubmit()) {
|
|
||||||
toSubmit.add(patchSetId);
|
|
||||||
} else {
|
|
||||||
throw error("change " + changeId + ": you do not have submit permission");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NOT_READY: {
|
|
||||||
StringBuilder msg = new StringBuilder();
|
|
||||||
for (SubmitRecord.Label lbl : submitResult.get(0).labels) {
|
|
||||||
switch (lbl.status) {
|
|
||||||
case OK:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case REJECT:
|
|
||||||
if (msg.length() > 0) msg.append("\n");
|
|
||||||
msg.append("change " + changeId + ": blocked by " + lbl.label);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case NEED:
|
|
||||||
if (msg.length() > 0) msg.append("\n");
|
|
||||||
msg.append("change " + changeId + ": needs " + lbl.label);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case IMPOSSIBLE:
|
|
||||||
if (msg.length() > 0) msg.append("\n");
|
|
||||||
msg.append("change " + changeId + ": needs " + lbl.label
|
|
||||||
+ " (check project access)");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Failure(1, "Unsupported label status " + lbl.status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw error(msg.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
case CLOSED:
|
|
||||||
throw error("change " + changeId + " is closed");
|
|
||||||
|
|
||||||
case RULE_ERROR:
|
|
||||||
if (submitResult.get(0).errorMessage != null) {
|
|
||||||
throw error("change " + changeId + ": " + submitResult.get(0).errorMessage);
|
|
||||||
} else {
|
|
||||||
throw error("change " + changeId + ": internal rule error");
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new Failure(1, "Unsupported status " + submitResult.get(0).status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (publishPatchSet) {
|
if (publishPatchSet) {
|
||||||
if (changeControl.isOwner() && changeControl.isVisible(db)) {
|
if (changeControl.isOwner() && changeControl.isVisible(db)) {
|
||||||
ChangeUtil.publishDraftPatchSet(db, patchSetId);
|
ChangeUtil.publishDraftPatchSet(db, patchSetId);
|
||||||
@@ -358,20 +267,37 @@ public class ReviewCommand extends BaseCommand {
|
|||||||
throw error("Not permitted to delete draft patchset");
|
throw error("Not permitted to delete draft patchset");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (result != null) {
|
private void handleReviewResultErrors(final ReviewResult result) {
|
||||||
for (ReviewResult.Error resultError : result.getErrors()) {
|
for (ReviewResult.Error resultError : result.getErrors()) {
|
||||||
|
String errMsg = "error: (change " + result.getChangeId() + ") ";
|
||||||
switch (resultError.getType()) {
|
switch (resultError.getType()) {
|
||||||
case ABANDON_NOT_PERMITTED:
|
case ABANDON_NOT_PERMITTED:
|
||||||
writeError("error: not permitted to abandon change");
|
errMsg += "not permitted to abandon change";
|
||||||
break;
|
break;
|
||||||
case RESTORE_NOT_PERMITTED:
|
case RESTORE_NOT_PERMITTED:
|
||||||
writeError("error: not permitted to restore change");
|
errMsg += "not permitted to restore change";
|
||||||
|
break;
|
||||||
|
case SUBMIT_NOT_PERMITTED:
|
||||||
|
errMsg += "not permitted to submit change";
|
||||||
|
break;
|
||||||
|
case SUBMIT_NOT_READY:
|
||||||
|
errMsg += "approvals or dependencies lacking";
|
||||||
|
break;
|
||||||
|
case CHANGE_IS_CLOSED:
|
||||||
|
errMsg += "change is closed";
|
||||||
|
break;
|
||||||
|
case RULE_ERROR:
|
||||||
|
errMsg += "rule error";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
writeError("error: failure in review");
|
errMsg += "failure in review";
|
||||||
}
|
}
|
||||||
|
if (resultError.getMessage() != null) {
|
||||||
|
errMsg += ": " + resultError.getMessage();
|
||||||
}
|
}
|
||||||
|
writeError(errMsg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user