Allow editing of commit message from UI.

This change adds a small edit icon on the top right
corner of the commit message box on the change screen.

Clicking it lets the user edit the commit message and a
new patch set will be created.

Change-Id: I2c4d4a3ba520d4c12ade4bb3b47a55ce7f1b19df
This commit is contained in:
Gustaf Lundh
2012-11-16 14:59:02 -08:00
committed by Shawn O. Pearce
parent 5367b8bab5
commit be1636e870
13 changed files with 339 additions and 8 deletions

View File

@@ -19,6 +19,7 @@ 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.client.PatchSetAncestor;
import com.google.gerrit.reviewdb.client.PatchSetInfo;
import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.reviewdb.client.TrackingId;
import com.google.gerrit.reviewdb.server.ReviewDb;
@@ -31,7 +32,10 @@ import com.google.gerrit.server.mail.EmailException;
import com.google.gerrit.server.mail.ReplyToChangeSender;
import com.google.gerrit.server.mail.RevertedSender;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
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.OrmConcurrencyException;
import com.google.gwtorm.server.OrmException;
@@ -293,6 +297,154 @@ public class ChangeUtil {
}
}
public static Change.Id editCommitMessage(final PatchSet.Id patchSetId,
final IdentifiedUser user, final String message, final ReviewDb db,
final ChangeHooks hooks, GitRepositoryManager gitManager,
final PatchSetInfoFactory patchSetInfoFactory,
final GitReferenceUpdated replication, PersonIdent myIdent)
throws NoSuchChangeException, EmailException, OrmException,
MissingObjectException, IncorrectObjectTypeException, IOException,
InvalidChangeOperationException, PatchSetInfoNotAvailableException {
final Change.Id changeId = patchSetId.getParentKey();
final PatchSet patch = db.patchSets().get(patchSetId);
if (patch == null) {
throw new NoSuchChangeException(changeId);
}
if (message == null || message.length() == 0) {
throw new InvalidChangeOperationException("The commit message cannot be empty");
}
final Repository git;
try {
git = gitManager.openRepository(db.changes().get(changeId).getProject());
} catch (RepositoryNotFoundException e) {
throw new NoSuchChangeException(changeId, e);
}
try {
final RevWalk revWalk = new RevWalk(git);
try {
Change change = db.changes().get(changeId);
RevCommit commit =
revWalk.parseCommit(ObjectId.fromString(patch.getRevision().get()));
PersonIdent authorIdent =
user.newCommitterIdent(myIdent.getWhen(), myIdent.getTimeZone());
CommitBuilder commitBuilder = new CommitBuilder();
commitBuilder.addParentId(commit);
commitBuilder.setTreeId(commit.getTree());
commitBuilder.setAuthor(authorIdent);
commitBuilder.setCommitter(myIdent);
commitBuilder.setMessage(message);
RevCommit newCommit;
final ObjectInserter oi = git.newObjectInserter();
try {
ObjectId id = oi.insert(commitBuilder);
oi.flush();
newCommit = revWalk.parseCommit(id);
} finally {
oi.release();
}
change.nextPatchSetId();
final PatchSet originalPS = db.patchSets().get(patchSetId);
final PatchSet newPatchSet = new PatchSet(change.currPatchSetId());
newPatchSet.setCreatedOn(change.getCreatedOn());
newPatchSet.setUploader(change.getOwner());
newPatchSet.setRevision(new RevId(newCommit.name()));
newPatchSet.setDraft(originalPS.isDraft());
final PatchSetInfo info =
patchSetInfoFactory.get(newCommit, newPatchSet.getId());
final RefUpdate ru = git.updateRef(newPatchSet.getRefName());
ru.setExpectedOldObjectId(ObjectId.zeroId());
ru.setNewObjectId(newCommit);
ru.disableRefLog();
if (ru.update(revWalk) != RefUpdate.Result.NEW) {
throw new IOException(String.format(
"Failed to create ref %s in %s: %s", newPatchSet.getRefName(),
change.getDest().getParentKey().get(), ru.getResult()));
}
replication.fire(change.getProject(), ru.getName());
db.changes().beginTransaction(change.getId());
try {
Change updatedChange =
db.changes().atomicUpdate(change.getId(), new AtomicUpdate<Change>() {
@Override
public Change update(Change change) {
if (change.getStatus().isOpen()) {
change.updateNumberOfPatchSets(newPatchSet.getPatchSetId());
return change;
} else {
return null;
}
}
});
if (updatedChange != null) {
change = updatedChange;
} else {
throw new InvalidChangeOperationException(String.format(
"Change %s is closed", change.getId()));
}
ChangeUtil.insertAncestors(db, newPatchSet.getId(), commit);
db.patchSets().insert(Collections.singleton(newPatchSet));
updatedChange =
db.changes().atomicUpdate(change.getId(), new AtomicUpdate<Change>() {
@Override
public Change update(Change change) {
if (change.getStatus().isClosed()) {
return null;
}
if (!change.currentPatchSetId().equals(patchSetId)) {
return null;
}
if (change.getStatus() != Change.Status.DRAFT) {
change.setStatus(Change.Status.NEW);
}
change.setLastSha1MergeTested(null);
change.setCurrentPatchSet(info);
ChangeUtil.updated(change);
return change;
}
});
if (updatedChange != null) {
change = updatedChange;
} else {
throw new InvalidChangeOperationException(String.format(
"Change %s was modified", change.getId()));
}
final ChangeMessage cmsg =
new ChangeMessage(new ChangeMessage.Key(changeId,
ChangeUtil.messageUUID(db)), user.getAccountId(), patchSetId);
final String msg = "Patch Set " + newPatchSet.getPatchSetId() + ": Commit message was updated";
cmsg.setMessage(msg);
db.changeMessages().insert(Collections.singleton(cmsg));
db.commit();
} finally {
db.rollback();
}
hooks.doPatchsetCreatedHook(change, newPatchSet, db);
return change.getId();
} finally {
revWalk.release();
}
} finally {
git.close();
}
}
public static void deleteDraftChange(final PatchSet.Id patchSetId,
GitRepositoryManager gitManager,
final GitReferenceUpdated replication, final ReviewDb db)