From 74e93c20bbfaae0e583ae9d85987b7d7ac1ce1ce Mon Sep 17 00:00:00 2001 From: Gustaf Lundh Date: Thu, 9 May 2013 11:17:07 +0100 Subject: [PATCH] PatchSetInserter To allow Plugins, EditCommitMessage, Cherry-Pick and other features to add new PatchSets in a consistant and maintainable way. Change-Id: I6039cc43c4f664c5335b9d1b544de766f4b94a75 --- .../server/change/PatchSetInserter.java | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java new file mode 100644 index 0000000000..3c811211f0 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/PatchSetInserter.java @@ -0,0 +1,142 @@ +// Copyright (C) 2013 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.change; + +import com.google.gerrit.common.ChangeHooks; +import com.google.gerrit.reviewdb.client.Change; +import com.google.gerrit.reviewdb.client.ChangeMessage; +import com.google.gerrit.reviewdb.client.PatchSet; +import com.google.gerrit.reviewdb.server.ReviewDb; +import com.google.gerrit.server.ApprovalsUtil; +import com.google.gerrit.server.ChangeUtil; +import com.google.gerrit.server.IdentifiedUser; +import com.google.gerrit.server.config.TrackingFooters; +import com.google.gerrit.server.patch.PatchSetInfoFactory; +import com.google.gerrit.server.project.InvalidChangeOperationException; +import com.google.gerrit.server.project.NoSuchChangeException; +import com.google.gerrit.server.project.RefControl; +import com.google.gwtorm.server.AtomicUpdate; +import com.google.gwtorm.server.OrmException; +import com.google.inject.Inject; + +import org.eclipse.jgit.revwalk.FooterLine; +import org.eclipse.jgit.revwalk.RevCommit; + +import java.util.Collections; +import java.util.List; + +public class PatchSetInserter { + private final ChangeHooks hooks; + private final TrackingFooters trackingFooters; + private final PatchSetInfoFactory patchSetInfoFactory; + private final ReviewDb db; + private final IdentifiedUser user; + + @Inject + public PatchSetInserter(final ChangeHooks hooks, + final TrackingFooters trackingFooters, final ReviewDb db, + final PatchSetInfoFactory patchSetInfoFactory, final IdentifiedUser user) { + this.hooks = hooks; + this.trackingFooters = trackingFooters; + this.db = db; + this.patchSetInfoFactory = patchSetInfoFactory; + this.user = user; + } + + public Change insertPatchSet(Change change, final PatchSet patchSet, + final RevCommit commit, RefControl refControl, String message, + boolean copyLabels) throws OrmException, InvalidChangeOperationException, + NoSuchChangeException { + + final PatchSet.Id currentPatchSetId = change.currentPatchSetId(); + + if (patchSet.getId().get() <= currentPatchSetId.get()) { + throw new InvalidChangeOperationException("New Patch Set ID [" + + patchSet.getId().get() + + "] is not greater than the current Patch Set ID [" + + currentPatchSetId.get() + "]"); + } + + db.changes().beginTransaction(change.getId()); + try { + if (!db.changes().get(change.getId()).getStatus().isOpen()) { + throw new InvalidChangeOperationException(String.format( + "Change %s is closed", change.getId())); + } + + ChangeUtil.insertAncestors(db, patchSet.getId(), commit); + db.patchSets().insert(Collections.singleton(patchSet)); + + Change updatedChange = + db.changes().atomicUpdate(change.getId(), new AtomicUpdate() { + @Override + public Change update(Change change) { + if (change.getStatus().isClosed()) { + return null; + } + if (!change.currentPatchSetId().equals(currentPatchSetId)) { + return null; + } + if (change.getStatus() != Change.Status.DRAFT) { + change.setStatus(Change.Status.NEW); + } + change.setLastSha1MergeTested(null); + change.setCurrentPatchSet(patchSetInfoFactory.get(commit, + patchSet.getId())); + ChangeUtil.updated(change); + return change; + } + }); + if (updatedChange != null) { + change = updatedChange; + } else { + throw new ChangeModifiedException(String.format( + "Change %s was modified", change.getId())); + } + + if (copyLabels) { + ApprovalsUtil.copyLabels(db, refControl.getProjectControl() + .getLabelTypes(), currentPatchSetId, change.currentPatchSetId()); + } + + final List footerLines = commit.getFooterLines(); + ChangeUtil.updateTrackingIds(db, change, trackingFooters, footerLines); + + if (message != null) { + final ChangeMessage cmsg = + new ChangeMessage(new ChangeMessage.Key(change.getId(), + ChangeUtil.messageUUID(db)), user.getAccountId(), + patchSet.getId()); + + cmsg.setMessage(message); + db.changeMessages().insert(Collections.singleton(cmsg)); + } + db.commit(); + + hooks.doPatchsetCreatedHook(change, patchSet, db); + } finally { + db.rollback(); + } + return change; + } + + public class ChangeModifiedException extends InvalidChangeOperationException { + private static final long serialVersionUID = 1L; + + public ChangeModifiedException(String msg) { + super(msg); + } + } +}