diff options
Diffstat (limited to 'gerrit-server/src/main/java/com/google/gerrit/server/changedetail/Submit.java')
-rw-r--r-- | gerrit-server/src/main/java/com/google/gerrit/server/changedetail/Submit.java | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/Submit.java b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/Submit.java new file mode 100644 index 0000000000..abd358292f --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/changedetail/Submit.java @@ -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.client.ApprovalCategory.SUBMIT; + +import com.google.gerrit.common.data.ReviewResult; +import com.google.gerrit.common.data.SubmitRecord; +import com.google.gerrit.reviewdb.client.Change; +import com.google.gerrit.reviewdb.client.PatchSet; +import com.google.gerrit.reviewdb.client.PatchSetApproval; +import com.google.gerrit.reviewdb.server.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.ChangeControl; +import com.google.gerrit.server.project.InvalidChangeOperationException; +import com.google.gerrit.server.project.NoSuchChangeException; +import com.google.gwtorm.server.AtomicUpdate; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; +import com.google.inject.assistedinject.Assisted; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Callable; + +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; + } +} |