Rewrite AbstractChangeUpdate to not extend MetaDataUpdate
This was never a particularly good fit for ChangeUpdate, as evidenced
by all the methods we had to override to throw exceptions to say
"don't use this method, use this other method." Plus, the
BatchMetaDataUpdate interface was confusing, and moreover didn't allow
us to group draft updates into a single BatchRefUpdate.
Reduce the methods in AbstractChangeUpdate to what is actually
required. Add a new class, the somewhat clumsily named
NoteDbUpdateManager, that understands enough about ChangeUpdates to
batch both the change repo and All-Users repo changes together.
This allows us to replace:
BatchMetaDataUpdate batch = update1.openUpdate();
try {
update1.writeCommit(batch);
update2.writeCommit(batch);
batch.commit();
} finally {
batch.close();
}
With:
NoteDbUpdateManager manager = updateManagerFactory.create(project);
manager.add(update1);
manager.add(update2);
manager.execute();
The explicit creation of the update manager without having to call a
method on one of the update instances reduces one possibility of
error.
The changes to ChangeRebuilder are just enough to get it to compile;
there are still problems with this class that I identified when trying
to write tests, so a further rewrite (including tests) will be coming.
It is not a coincidence that the structure and API of
NoteDbUpdateManager are reminiscent of BatchUpdate. This will allow us
to eventually use a single NoteDbUpdateManager per BatchUpdate and
even update change and meta refs at the same time.
Change-Id: Ib163d2092b76066203b8bfd78ddc69376e0e441b
This commit is contained in:
@@ -121,9 +121,6 @@ public class RebuildNotedb extends SiteProgram {
|
||||
deleteRefs(RefNames.REFS_STARRED_CHANGES, allUsersRepo);
|
||||
for (final Project.NameKey project : changesByProject.keySet()) {
|
||||
try (Repository repo = repoManager.openMetadataRepository(project)) {
|
||||
final BatchRefUpdate bru = repo.getRefDatabase().newBatchUpdate();
|
||||
final BatchRefUpdate bruAllUsers =
|
||||
allUsersRepo.getRefDatabase().newBatchUpdate();
|
||||
List<ListenableFuture<?>> futures = Lists.newArrayList();
|
||||
|
||||
// Here, we elide the project name to 50 characters to ensure that
|
||||
@@ -136,8 +133,8 @@ public class RebuildNotedb extends SiteProgram {
|
||||
mpm.beginSubTask("failed", MultiProgressMonitor.UNKNOWN);
|
||||
|
||||
for (final Change c : changesByProject.get(project)) {
|
||||
final ListenableFuture<?> future = rebuilder.rebuildAsync(c,
|
||||
executor, bru, bruAllUsers, repo, allUsersRepo);
|
||||
final ListenableFuture<?> future =
|
||||
rebuilder.rebuildAsync(c, executor, repo);
|
||||
futures.add(future);
|
||||
future.addListener(
|
||||
new RebuildListener(c.getId(), future, ok, doneTask, failedTask),
|
||||
@@ -149,8 +146,6 @@ public class RebuildNotedb extends SiteProgram {
|
||||
@Override
|
||||
public ListenableFuture<Void> apply(List<?> input)
|
||||
throws Exception {
|
||||
execute(bru, repo);
|
||||
execute(bruAllUsers, allUsersRepo);
|
||||
mpm.end();
|
||||
return Futures.immediateFuture(null);
|
||||
}
|
||||
|
||||
@@ -36,11 +36,11 @@ import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.GerritPersonIdent;
|
||||
import com.google.gerrit.server.PatchLineCommentsUtil;
|
||||
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
|
||||
import com.google.gerrit.server.git.VersionedMetaData.BatchMetaDataUpdate;
|
||||
import com.google.gerrit.server.index.ChangeIndexer;
|
||||
import com.google.gerrit.server.notedb.ChangeDelete;
|
||||
import com.google.gerrit.server.notedb.ChangeNotes;
|
||||
import com.google.gerrit.server.notedb.ChangeUpdate;
|
||||
import com.google.gerrit.server.notedb.NoteDbUpdateManager;
|
||||
import com.google.gerrit.server.notedb.NotesMigration;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.gerrit.server.project.InvalidChangeOperationException;
|
||||
@@ -377,6 +377,7 @@ public class BatchUpdate implements AutoCloseable {
|
||||
private final ChangeControl.GenericFactory changeControlFactory;
|
||||
private final ChangeNotes.Factory changeNotesFactory;
|
||||
private final ChangeUpdate.Factory changeUpdateFactory;
|
||||
private final NoteDbUpdateManager.Factory updateManagerFactory;
|
||||
private final GitReferenceUpdated gitRefUpdated;
|
||||
private final NotesMigration notesMigration;
|
||||
private final PatchLineCommentsUtil plcUtil;
|
||||
@@ -406,6 +407,7 @@ public class BatchUpdate implements AutoCloseable {
|
||||
ChangeControl.GenericFactory changeControlFactory,
|
||||
ChangeNotes.Factory changeNotesFactory,
|
||||
ChangeUpdate.Factory changeUpdateFactory,
|
||||
NoteDbUpdateManager.Factory updateManagerFactory,
|
||||
GitReferenceUpdated gitRefUpdated,
|
||||
NotesMigration notesMigration,
|
||||
PatchLineCommentsUtil plcUtil,
|
||||
@@ -420,6 +422,7 @@ public class BatchUpdate implements AutoCloseable {
|
||||
this.changeControlFactory = changeControlFactory;
|
||||
this.changeNotesFactory = changeNotesFactory;
|
||||
this.changeUpdateFactory = changeUpdateFactory;
|
||||
this.updateManagerFactory = updateManagerFactory;
|
||||
this.gitRefUpdated = gitRefUpdated;
|
||||
this.notesMigration = notesMigration;
|
||||
this.plcUtil = plcUtil;
|
||||
@@ -579,16 +582,12 @@ public class BatchUpdate implements AutoCloseable {
|
||||
indexFutures.add(indexer.deleteAsync(id));
|
||||
} else {
|
||||
if (notesMigration.writeChanges()) {
|
||||
BatchMetaDataUpdate bmdu = null;
|
||||
NoteDbUpdateManager manager =
|
||||
updateManagerFactory.create(ctx.getProject());
|
||||
for (ChangeUpdate u : ctx.updates.values()) {
|
||||
if (bmdu == null) {
|
||||
bmdu = u.openUpdate();
|
||||
}
|
||||
u.writeCommit(bmdu);
|
||||
}
|
||||
if (bmdu != null) {
|
||||
bmdu.commit();
|
||||
manager.add(u);
|
||||
}
|
||||
manager.execute();
|
||||
}
|
||||
indexFutures.add(indexer.indexAsync(ctx.getProject(), id));
|
||||
}
|
||||
|
||||
@@ -15,11 +15,15 @@
|
||||
package com.google.gerrit.server.git;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import org.eclipse.jgit.lib.BatchRefUpdate;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -33,8 +37,8 @@ import java.util.Map;
|
||||
*/
|
||||
public class ChainedReceiveCommands {
|
||||
private final Map<String, ReceiveCommand> commands = new LinkedHashMap<>();
|
||||
private final Map<String, ObjectId> oldIds = new HashMap<>();
|
||||
|
||||
/** @return true if no commands have been added. */
|
||||
public boolean isEmpty() {
|
||||
return commands.isEmpty();
|
||||
}
|
||||
@@ -64,6 +68,34 @@ public class ChainedReceiveCommands {
|
||||
old.getOldId(), cmd.getNewId(), cmd.getRefName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the latest value of a ref according to this sequence of commands.
|
||||
* <p>
|
||||
* Once the value for a ref is read once, it is cached in this instance, so
|
||||
* that multiple callers using this instance for lookups see a single
|
||||
* consistent snapshot.
|
||||
*
|
||||
* @param repo repository to read from, if result is not cached.
|
||||
* @param refName name of the ref.
|
||||
* @return value of the ref, taking into account commands that have already
|
||||
* been added to this instance.
|
||||
*/
|
||||
public ObjectId getObjectId(Repository repo, String refName)
|
||||
throws IOException {
|
||||
ReceiveCommand cmd = commands.get(refName);
|
||||
if (cmd != null) {
|
||||
return cmd.getNewId();
|
||||
}
|
||||
ObjectId old = oldIds.get(refName);
|
||||
if (old != null) {
|
||||
return old;
|
||||
}
|
||||
Ref ref = repo.exactRef(refName);
|
||||
ObjectId id = ref != null ? ref.getObjectId() : null;
|
||||
oldIds.put(refName, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add commands from this instance to a native JGit batch update.
|
||||
* <p>
|
||||
@@ -74,7 +106,6 @@ public class ChainedReceiveCommands {
|
||||
* @param bru batch update
|
||||
*/
|
||||
public void addTo(BatchRefUpdate bru) {
|
||||
checkState(!isEmpty(), "no commands to add");
|
||||
for (ReceiveCommand cmd : commands.values()) {
|
||||
bru.addCommand(cmd);
|
||||
}
|
||||
|
||||
@@ -22,43 +22,40 @@ import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.git.VersionedMetaData;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.lib.BatchRefUpdate;
|
||||
import org.eclipse.jgit.lib.CommitBuilder;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectInserter;
|
||||
import org.eclipse.jgit.lib.PersonIdent;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
/** A single delta related to a specific patch-set of a change. */
|
||||
public abstract class AbstractChangeUpdate extends VersionedMetaData {
|
||||
public abstract class AbstractChangeUpdate {
|
||||
protected final NotesMigration migration;
|
||||
protected final GitRepositoryManager repoManager;
|
||||
protected final MetaDataUpdate.User updateFactory;
|
||||
protected final ChangeControl ctl;
|
||||
protected final String anonymousCowardName;
|
||||
protected final PersonIdent serverIdent;
|
||||
protected final Date when;
|
||||
protected PatchSet.Id psId;
|
||||
|
||||
AbstractChangeUpdate(NotesMigration migration,
|
||||
protected PatchSet.Id psId;
|
||||
private ObjectId result;
|
||||
|
||||
protected AbstractChangeUpdate(NotesMigration migration,
|
||||
GitRepositoryManager repoManager,
|
||||
MetaDataUpdate.User updateFactory, ChangeControl ctl,
|
||||
ChangeControl ctl,
|
||||
PersonIdent serverIdent,
|
||||
String anonymousCowardName,
|
||||
Date when) {
|
||||
this.migration = migration;
|
||||
this.repoManager = repoManager;
|
||||
this.updateFactory = updateFactory;
|
||||
this.ctl = ctl;
|
||||
this.serverIdent = serverIdent;
|
||||
this.anonymousCowardName = anonymousCowardName;
|
||||
@@ -90,96 +87,11 @@ public abstract class AbstractChangeUpdate extends VersionedMetaData {
|
||||
this.psId = psId;
|
||||
}
|
||||
|
||||
private void load() throws IOException {
|
||||
if (migration.writeChanges() && getRevision() == null) {
|
||||
try (Repository repo = repoManager.openMetadataRepository(getProjectName())) {
|
||||
load(repo);
|
||||
} catch (ConfigInvalidException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setInserter(ObjectInserter inserter) {
|
||||
this.inserter = inserter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BatchMetaDataUpdate openUpdate(MetaDataUpdate update) throws IOException {
|
||||
throw new UnsupportedOperationException("use openUpdate()");
|
||||
}
|
||||
|
||||
public BatchMetaDataUpdate openUpdate() throws IOException {
|
||||
return openUpdateInBatch(null);
|
||||
}
|
||||
|
||||
public BatchMetaDataUpdate openUpdateInBatch(BatchRefUpdate bru)
|
||||
throws IOException {
|
||||
if (migration.writeChanges()) {
|
||||
load();
|
||||
Project.NameKey p = getProjectName();
|
||||
MetaDataUpdate md = updateFactory.create(
|
||||
p, repoManager.openMetadataRepository(p), getUser(), bru);
|
||||
md.setAllowEmpty(true);
|
||||
return super.openUpdate(md);
|
||||
}
|
||||
return new BatchMetaDataUpdate() {
|
||||
@Override
|
||||
public void write(CommitBuilder commit) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(VersionedMetaData config, CommitBuilder commit) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public RevCommit createRef(String refName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRef(String refName) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public RevCommit commit() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RevCommit commitAt(ObjectId revision) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// Do nothing.
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public RevCommit commit(MetaDataUpdate md) throws IOException {
|
||||
throw new UnsupportedOperationException("use commit()");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoad() throws IOException, ConfigInvalidException {
|
||||
//Do nothing; just reads the current revision.
|
||||
}
|
||||
|
||||
protected PersonIdent newIdent(Account author, Date when) {
|
||||
return ChangeNoteUtil.newIdent(author, when, serverIdent,
|
||||
anonymousCowardName);
|
||||
}
|
||||
|
||||
/** Writes commit to a BatchMetaDataUpdate without committing the batch. */
|
||||
public abstract void writeCommit(BatchMetaDataUpdate batch)
|
||||
throws OrmException, IOException;
|
||||
|
||||
/** Whether no updates have been done. */
|
||||
public abstract boolean isEmpty();
|
||||
|
||||
@@ -188,4 +100,71 @@ public abstract class AbstractChangeUpdate extends VersionedMetaData {
|
||||
* which is not necessarily the same as the change's project.
|
||||
*/
|
||||
protected abstract Project.NameKey getProjectName();
|
||||
|
||||
protected abstract String getRefName();
|
||||
|
||||
/**
|
||||
* Apply this update to the given inserter.
|
||||
*
|
||||
* @param rw walk for reading back any objects needed for the update.
|
||||
* @param ins inserter to write to; callers should not flush.
|
||||
* @param curr the current tip of the branch prior to this update.
|
||||
* @return commit ID produced by inserting this update's commit, or null if
|
||||
* this update is a no-op and should be skipped. The zero ID is a valid
|
||||
* return value, and indicates the ref should be deleted.
|
||||
* @throws OrmException if a Gerrit-level error occurred.
|
||||
* @throws IOException if a lower-level error occurred.
|
||||
*/
|
||||
final ObjectId apply(RevWalk rw, ObjectInserter ins, ObjectId curr)
|
||||
throws OrmException, IOException {
|
||||
if (isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
ObjectId z = ObjectId.zeroId();
|
||||
CommitBuilder cb = applyImpl(ins);
|
||||
if (cb == null) {
|
||||
result = z;
|
||||
return z; // Impl intends to delete the ref.
|
||||
}
|
||||
if (!curr.equals(z)) {
|
||||
cb.setParentId(curr);
|
||||
} else {
|
||||
cb.setParentIds(); // Ref is currently nonexistent, commit has no parents.
|
||||
}
|
||||
if (cb.getTreeId() == null) {
|
||||
if (curr.equals(z)) {
|
||||
cb.setTreeId(emptyTree(ins)); // No parent, assume empty tree.
|
||||
} else {
|
||||
RevCommit p = rw.parseCommit(curr);
|
||||
cb.setTreeId(p.getTree()); // Copy tree from parent.
|
||||
}
|
||||
}
|
||||
result = ins.insert(cb);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a commit containing the contents of this update.
|
||||
*
|
||||
* @param ins inserter to write to; callers should not flush.
|
||||
* @return a new commit builder representing this commit, or null to indicate
|
||||
* the meta ref should be deleted as a result of this update. The parent
|
||||
* field in the return value is always overwritten. The tree ID may be
|
||||
* unset by this method, which indicates to the caller that it should be
|
||||
* copied from the parent commit.
|
||||
* @throws OrmException if a Gerrit-level error occurred.
|
||||
* @throws IOException if a lower-level error occurred.
|
||||
*/
|
||||
// TODO(dborowitz): ChangeUpdate needs to be able to reread its ChangeNotes at
|
||||
// the old SHA-1, which would imply passing curr here.
|
||||
protected abstract CommitBuilder applyImpl(ObjectInserter ins)
|
||||
throws OrmException, IOException;
|
||||
|
||||
ObjectId getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ObjectId emptyTree(ObjectInserter ins) throws IOException {
|
||||
return ins.insert(Constants.OBJ_TREE, new byte[] {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
package com.google.gerrit.server.notedb;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.gerrit.server.notedb.CommentsInNotesUtil.addCommentToMap;
|
||||
|
||||
@@ -23,7 +24,6 @@ import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.PatchLineComment;
|
||||
import com.google.gerrit.reviewdb.client.PatchLineComment.Status;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.RefNames;
|
||||
import com.google.gerrit.reviewdb.client.RevId;
|
||||
@@ -32,18 +32,16 @@ import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.config.AllUsersName;
|
||||
import com.google.gerrit.server.config.AnonymousCowardName;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import com.google.inject.assistedinject.AssistedInject;
|
||||
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.lib.CommitBuilder;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectInserter;
|
||||
import org.eclipse.jgit.lib.PersonIdent;
|
||||
import org.eclipse.jgit.notes.NoteMap;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@@ -83,14 +81,12 @@ public class ChangeDraftUpdate extends AbstractChangeUpdate {
|
||||
@AnonymousCowardName String anonymousCowardName,
|
||||
GitRepositoryManager repoManager,
|
||||
NotesMigration migration,
|
||||
MetaDataUpdate.User updateFactory,
|
||||
DraftCommentNotes.Factory draftNotesFactory,
|
||||
AllUsersName allUsers,
|
||||
CommentsInNotesUtil commentsUtil,
|
||||
@Assisted ChangeControl ctl,
|
||||
@Assisted Date when) throws OrmException {
|
||||
super(migration, repoManager, updateFactory, ctl, serverIdent,
|
||||
anonymousCowardName, when);
|
||||
super(migration, repoManager, ctl, serverIdent, anonymousCowardName, when);
|
||||
this.draftsProject = allUsers;
|
||||
this.commentsUtil = commentsUtil;
|
||||
checkState(ctl.getUser().isIdentifiedUser(),
|
||||
@@ -107,7 +103,7 @@ public class ChangeDraftUpdate extends AbstractChangeUpdate {
|
||||
|
||||
public void insertComment(PatchLineComment c) throws OrmException {
|
||||
verifyComment(c);
|
||||
checkArgument(c.getStatus() == Status.DRAFT,
|
||||
checkArgument(c.getStatus() == PatchLineComment.Status.DRAFT,
|
||||
"Cannot insert a published comment into a ChangeDraftUpdate");
|
||||
if (migration.readChanges()) {
|
||||
checkArgument(!changeNotes.containsComment(c),
|
||||
@@ -119,14 +115,14 @@ public class ChangeDraftUpdate extends AbstractChangeUpdate {
|
||||
|
||||
public void upsertComment(PatchLineComment c) {
|
||||
verifyComment(c);
|
||||
checkArgument(c.getStatus() == Status.DRAFT,
|
||||
checkArgument(c.getStatus() == PatchLineComment.Status.DRAFT,
|
||||
"Cannot upsert a published comment into a ChangeDraftUpdate");
|
||||
upsertComments.add(c);
|
||||
}
|
||||
|
||||
public void updateComment(PatchLineComment c) throws OrmException {
|
||||
verifyComment(c);
|
||||
checkArgument(c.getStatus() == Status.DRAFT,
|
||||
checkArgument(c.getStatus() == PatchLineComment.Status.DRAFT,
|
||||
"Cannot update a published comment into a ChangeDraftUpdate");
|
||||
// Here, we check to see if this comment existed previously as a draft.
|
||||
// However, this could cause a race condition if there is a delete and an
|
||||
@@ -178,12 +174,8 @@ public class ChangeDraftUpdate extends AbstractChangeUpdate {
|
||||
}
|
||||
|
||||
/** @return the tree id for the updated tree */
|
||||
private ObjectId storeCommentsInNotes(AtomicBoolean removedAllComments)
|
||||
throws OrmException, IOException {
|
||||
if (isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private ObjectId storeCommentsInNotes(ObjectInserter inserter,
|
||||
AtomicBoolean removedAllComments) throws OrmException, IOException {
|
||||
NoteMap noteMap = draftNotes.load().getNoteMap();
|
||||
if (noteMap == null) {
|
||||
noteMap = NoteMap.newEmptyMap();
|
||||
@@ -230,7 +222,7 @@ public class ChangeDraftUpdate extends AbstractChangeUpdate {
|
||||
// for the caller to delete the entire ref.
|
||||
boolean touchedAllRevs = updatedRevs.equals(existing.keySet());
|
||||
if (touchedAllRevs && !hasComments) {
|
||||
removedAllComments.set(touchedAllRevs && !hasComments);
|
||||
removedAllComments.set(true);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -238,32 +230,20 @@ public class ChangeDraftUpdate extends AbstractChangeUpdate {
|
||||
return noteMap.writeTree(inserter);
|
||||
}
|
||||
|
||||
public RevCommit commit() throws IOException {
|
||||
BatchMetaDataUpdate batch = openUpdate();
|
||||
try {
|
||||
writeCommit(batch);
|
||||
return batch.commit();
|
||||
} catch (OrmException e) {
|
||||
throw new IOException(e);
|
||||
} finally {
|
||||
batch.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCommit(BatchMetaDataUpdate batch)
|
||||
protected CommitBuilder applyImpl(ObjectInserter ins)
|
||||
throws OrmException, IOException {
|
||||
CommitBuilder builder = new CommitBuilder();
|
||||
if (migration.writeChanges()) {
|
||||
AtomicBoolean removedAllComments = new AtomicBoolean();
|
||||
ObjectId treeId = storeCommentsInNotes(removedAllComments);
|
||||
if (removedAllComments.get()) {
|
||||
batch.removeRef(getRefName());
|
||||
} else if (treeId != null) {
|
||||
builder.setTreeId(treeId);
|
||||
batch.write(builder);
|
||||
}
|
||||
CommitBuilder cb = new CommitBuilder();
|
||||
cb.setAuthor(newIdent(getUser().getAccount(), when));
|
||||
cb.setCommitter(new PersonIdent(serverIdent, when));
|
||||
cb.setMessage("Update draft comments");
|
||||
AtomicBoolean removedAllComments = new AtomicBoolean();
|
||||
ObjectId treeId = storeCommentsInNotes(ins, removedAllComments);
|
||||
if (removedAllComments.get()) {
|
||||
return null; // Delete ref.
|
||||
}
|
||||
cb.setTreeId(checkNotNull(treeId));
|
||||
return cb;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -276,18 +256,6 @@ public class ChangeDraftUpdate extends AbstractChangeUpdate {
|
||||
return RefNames.refsDraftComments(accountId, ctl.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onSave(CommitBuilder commit) throws IOException,
|
||||
ConfigInvalidException {
|
||||
if (isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
commit.setAuthor(newIdent(getUser().getAccount(), when));
|
||||
commit.setCommitter(new PersonIdent(serverIdent, when));
|
||||
commit.setMessage("Update draft comments");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return deleteComments.isEmpty()
|
||||
|
||||
@@ -42,7 +42,7 @@ import com.google.gerrit.reviewdb.client.StarredChange;
|
||||
import com.google.gerrit.reviewdb.server.ReviewDb;
|
||||
import com.google.gerrit.server.IdentifiedUser;
|
||||
import com.google.gerrit.server.PatchLineCommentsUtil;
|
||||
import com.google.gerrit.server.git.VersionedMetaData.BatchMetaDataUpdate;
|
||||
import com.google.gerrit.server.git.ChainedReceiveCommands;
|
||||
import com.google.gerrit.server.patch.PatchListCache;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.gerrit.server.project.NoSuchChangeException;
|
||||
@@ -50,7 +50,6 @@ import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
|
||||
import org.eclipse.jgit.lib.BatchRefUpdate;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectInserter;
|
||||
@@ -84,6 +83,7 @@ public class ChangeRebuilder {
|
||||
private final PatchListCache patchListCache;
|
||||
private final ChangeUpdate.Factory updateFactory;
|
||||
private final ChangeDraftUpdate.Factory draftUpdateFactory;
|
||||
private final NoteDbUpdateManager.Factory updateManagerFactory;
|
||||
|
||||
@Inject
|
||||
ChangeRebuilder(Provider<ReviewDb> dbProvider,
|
||||
@@ -91,37 +91,34 @@ public class ChangeRebuilder {
|
||||
IdentifiedUser.GenericFactory userFactory,
|
||||
PatchListCache patchListCache,
|
||||
ChangeUpdate.Factory updateFactory,
|
||||
ChangeDraftUpdate.Factory draftUpdateFactory) {
|
||||
ChangeDraftUpdate.Factory draftUpdateFactory,
|
||||
NoteDbUpdateManager.Factory updateManagerFactory) {
|
||||
this.dbProvider = dbProvider;
|
||||
this.controlFactory = controlFactory;
|
||||
this.userFactory = userFactory;
|
||||
this.patchListCache = patchListCache;
|
||||
this.updateFactory = updateFactory;
|
||||
this.draftUpdateFactory = draftUpdateFactory;
|
||||
this.updateManagerFactory = updateManagerFactory;
|
||||
}
|
||||
|
||||
public ListenableFuture<?> rebuildAsync(final Change change,
|
||||
ListeningExecutorService executor, final BatchRefUpdate bru,
|
||||
final BatchRefUpdate bruForDrafts, final Repository changeRepo,
|
||||
final Repository allUsersRepo) {
|
||||
ListeningExecutorService executor, final Repository changeRepo) {
|
||||
return executor.submit(new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
rebuild(change, bru, bruForDrafts, changeRepo, allUsersRepo);
|
||||
rebuild(change, changeRepo);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void rebuild(Change change, BatchRefUpdate bru,
|
||||
BatchRefUpdate bruAllUsers, Repository changeRepo,
|
||||
Repository allUsersRepo) throws NoSuchChangeException, IOException,
|
||||
OrmException {
|
||||
public void rebuild(Change change, Repository changeRepo)
|
||||
throws NoSuchChangeException, IOException, OrmException {
|
||||
ReviewDb db = dbProvider.get();
|
||||
Change.Id changeId = change.getId();
|
||||
// We will rebuild all events, except for draft comments, in buckets based
|
||||
// on author and timestamp. However, all draft comments for a given change
|
||||
// and author will be written as one commit in the notedb.
|
||||
// on author and timestamp.
|
||||
List<Event> events = Lists.newArrayList();
|
||||
Multimap<Account.Id, PatchLineCommentEvent> draftCommentEvents =
|
||||
ArrayListMultimap.create();
|
||||
@@ -156,63 +153,53 @@ public class ChangeRebuilder {
|
||||
|
||||
Collections.sort(events);
|
||||
events.add(new FinalUpdatesEvent(change, notedbChange));
|
||||
BatchMetaDataUpdate batch = null;
|
||||
// TODO(dborowitz): share manager across changes.
|
||||
NoteDbUpdateManager manager =
|
||||
updateManagerFactory.create(change.getProject());
|
||||
ChangeUpdate update = null;
|
||||
for (Event e : events) {
|
||||
if (!sameUpdate(e, update)) {
|
||||
writeToBatch(batch, update, changeRepo);
|
||||
if (update != null) {
|
||||
manager.add(update);
|
||||
}
|
||||
IdentifiedUser user = userFactory.create(dbProvider, e.who);
|
||||
update = updateFactory.create(
|
||||
controlFactory.controlFor(db, change, user), e.when);
|
||||
update.setPatchSetId(e.psId);
|
||||
if (batch == null) {
|
||||
batch = update.openUpdateInBatch(bru);
|
||||
}
|
||||
}
|
||||
e.apply(update);
|
||||
}
|
||||
if (batch != null) {
|
||||
writeToBatch(batch, update, changeRepo);
|
||||
|
||||
// Since the BatchMetaDataUpdates generated by all ChangeRebuilders on a
|
||||
// given project are backed by the same BatchRefUpdate, we need to
|
||||
// synchronize on the BatchRefUpdate. Therefore, since commit on a
|
||||
// BatchMetaDataUpdate is the only method that modifies a BatchRefUpdate,
|
||||
// we can just synchronize this call.
|
||||
synchronized (bru) {
|
||||
batch.commit();
|
||||
}
|
||||
}
|
||||
manager.add(update);
|
||||
|
||||
for (Account.Id author : draftCommentEvents.keys()) {
|
||||
IdentifiedUser user = userFactory.create(dbProvider, author);
|
||||
ChangeDraftUpdate draftUpdate = null;
|
||||
BatchMetaDataUpdate batchForDrafts = null;
|
||||
for (PatchLineCommentEvent e : draftCommentEvents.get(author)) {
|
||||
if (draftUpdate == null) {
|
||||
if (!sameUpdate(e, draftUpdate)) {
|
||||
if (draftUpdate != null) {
|
||||
manager.add(draftUpdate);
|
||||
}
|
||||
draftUpdate = draftUpdateFactory.create(
|
||||
controlFactory.controlFor(db, change, user), e.when);
|
||||
draftUpdate.setPatchSetId(e.psId);
|
||||
batchForDrafts = draftUpdate.openUpdateInBatch(bruAllUsers);
|
||||
}
|
||||
e.applyDraft(draftUpdate);
|
||||
}
|
||||
writeToBatch(batchForDrafts, draftUpdate, allUsersRepo);
|
||||
synchronized(bruAllUsers) {
|
||||
batchForDrafts.commit();
|
||||
}
|
||||
manager.add(draftUpdate);
|
||||
}
|
||||
|
||||
createStarredChangesRefs(changeId, bruAllUsers, allUsersRepo);
|
||||
createStarredChangesRefs(changeId, manager.getAllUsersCommands(),
|
||||
manager.getAllUsersRepo());
|
||||
manager.execute();
|
||||
}
|
||||
|
||||
private void createStarredChangesRefs(Change.Id changeId,
|
||||
BatchRefUpdate bruAllUsers, Repository allUsersRepo)
|
||||
ChainedReceiveCommands allUsersCmds, Repository allUsersRepo)
|
||||
throws IOException, OrmException {
|
||||
ObjectId emptyTree = emptyTree(allUsersRepo);
|
||||
for (StarredChange starred : dbProvider.get().starredChanges()
|
||||
.byChange(changeId)) {
|
||||
bruAllUsers.addCommand(new ReceiveCommand(ObjectId.zeroId(), emptyTree,
|
||||
allUsersCmds.add(new ReceiveCommand(ObjectId.zeroId(), emptyTree,
|
||||
RefNames.refsStarredChanges(starred.getAccountId(), changeId)));
|
||||
}
|
||||
}
|
||||
@@ -301,24 +288,11 @@ public class ChangeRebuilder {
|
||||
}
|
||||
}
|
||||
|
||||
private void writeToBatch(BatchMetaDataUpdate batch,
|
||||
AbstractChangeUpdate update, Repository repo) throws IOException,
|
||||
OrmException {
|
||||
if (update == null || update.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (ObjectInserter inserter = repo.newObjectInserter()) {
|
||||
update.setInserter(inserter);
|
||||
update.writeCommit(batch);
|
||||
}
|
||||
}
|
||||
|
||||
private static long round(Date when) {
|
||||
return when.getTime() / TS_WINDOW_MS;
|
||||
}
|
||||
|
||||
private static boolean sameUpdate(Event event, ChangeUpdate update) {
|
||||
private static boolean sameUpdate(Event event, AbstractChangeUpdate update) {
|
||||
return update != null
|
||||
&& round(event.when) == round(update.getWhen())
|
||||
&& event.who.equals(update.getUser().getAccountId())
|
||||
|
||||
@@ -46,14 +46,12 @@ import com.google.gerrit.common.data.SubmitRecord;
|
||||
import com.google.gerrit.reviewdb.client.Account;
|
||||
import com.google.gerrit.reviewdb.client.Change;
|
||||
import com.google.gerrit.reviewdb.client.PatchLineComment;
|
||||
import com.google.gerrit.reviewdb.client.PatchLineComment.Status;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.reviewdb.client.RevId;
|
||||
import com.google.gerrit.server.GerritPersonIdent;
|
||||
import com.google.gerrit.server.account.AccountCache;
|
||||
import com.google.gerrit.server.config.AnonymousCowardName;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gerrit.server.git.MetaDataUpdate;
|
||||
import com.google.gerrit.server.project.ChangeControl;
|
||||
import com.google.gerrit.server.project.ProjectCache;
|
||||
import com.google.gerrit.server.util.LabelVote;
|
||||
@@ -63,6 +61,7 @@ import com.google.inject.assistedinject.AssistedInject;
|
||||
|
||||
import org.eclipse.jgit.lib.CommitBuilder;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectInserter;
|
||||
import org.eclipse.jgit.lib.PersonIdent;
|
||||
import org.eclipse.jgit.notes.NoteMap;
|
||||
import org.eclipse.jgit.revwalk.FooterKey;
|
||||
@@ -99,16 +98,20 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
}
|
||||
|
||||
private final AccountCache accountCache;
|
||||
private String commitSubject;
|
||||
private String subject;
|
||||
private final CommentsInNotesUtil commentsUtil;
|
||||
private final ChangeDraftUpdate.Factory draftUpdateFactory;
|
||||
private final NoteDbUpdateManager.Factory updateManagerFactory;
|
||||
|
||||
private final Table<String, Account.Id, Optional<Short>> approvals;
|
||||
private final Map<Account.Id, ReviewerStateInternal> reviewers;
|
||||
|
||||
private String commitSubject;
|
||||
private String subject;
|
||||
private String changeId;
|
||||
private String branch;
|
||||
private Change.Status status;
|
||||
private List<SubmitRecord> submitRecords;
|
||||
private String submissionId;
|
||||
private final CommentsInNotesUtil commentsUtil;
|
||||
private List<PatchLineComment> comments;
|
||||
private String topic;
|
||||
private ObjectId commit;
|
||||
@@ -119,7 +122,6 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
private Iterable<String> groups;
|
||||
private String pushCert;
|
||||
|
||||
private final ChangeDraftUpdate.Factory draftUpdateFactory;
|
||||
private ChangeDraftUpdate draftUpdate;
|
||||
|
||||
@AssistedInject
|
||||
@@ -129,13 +131,13 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
GitRepositoryManager repoManager,
|
||||
NotesMigration migration,
|
||||
AccountCache accountCache,
|
||||
MetaDataUpdate.User updateFactory,
|
||||
NoteDbUpdateManager.Factory updateManagerFactory,
|
||||
ChangeDraftUpdate.Factory draftUpdateFactory,
|
||||
ProjectCache projectCache,
|
||||
@Assisted ChangeControl ctl,
|
||||
CommentsInNotesUtil commentsUtil) {
|
||||
this(serverIdent, anonymousCowardName, repoManager, migration, accountCache,
|
||||
updateFactory, draftUpdateFactory,
|
||||
updateManagerFactory, draftUpdateFactory,
|
||||
projectCache, ctl, serverIdent.getWhen(), commentsUtil);
|
||||
}
|
||||
|
||||
@@ -146,14 +148,14 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
GitRepositoryManager repoManager,
|
||||
NotesMigration migration,
|
||||
AccountCache accountCache,
|
||||
MetaDataUpdate.User updateFactory,
|
||||
NoteDbUpdateManager.Factory updateManagerFactory,
|
||||
ChangeDraftUpdate.Factory draftUpdateFactory,
|
||||
ProjectCache projectCache,
|
||||
@Assisted ChangeControl ctl,
|
||||
@Assisted Date when,
|
||||
CommentsInNotesUtil commentsUtil) {
|
||||
this(serverIdent, anonymousCowardName, repoManager, migration, accountCache,
|
||||
updateFactory, draftUpdateFactory, ctl,
|
||||
updateManagerFactory, draftUpdateFactory, ctl,
|
||||
when,
|
||||
projectCache.get(getProjectName(ctl)).getLabelTypes().nameComparator(),
|
||||
commentsUtil);
|
||||
@@ -170,17 +172,19 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
GitRepositoryManager repoManager,
|
||||
NotesMigration migration,
|
||||
AccountCache accountCache,
|
||||
MetaDataUpdate.User updateFactory,
|
||||
NoteDbUpdateManager.Factory updateManagerFactory,
|
||||
ChangeDraftUpdate.Factory draftUpdateFactory,
|
||||
@Assisted ChangeControl ctl,
|
||||
@Assisted Date when,
|
||||
@Assisted Comparator<String> labelNameComparator,
|
||||
CommentsInNotesUtil commentsUtil) {
|
||||
super(migration, repoManager, updateFactory, ctl, serverIdent,
|
||||
super(migration, repoManager, ctl, serverIdent,
|
||||
anonymousCowardName, when);
|
||||
this.draftUpdateFactory = draftUpdateFactory;
|
||||
this.accountCache = accountCache;
|
||||
this.commentsUtil = commentsUtil;
|
||||
this.draftUpdateFactory = draftUpdateFactory;
|
||||
this.updateManagerFactory = updateManagerFactory;
|
||||
|
||||
this.approvals = TreeBasedTable.create(
|
||||
labelNameComparator,
|
||||
Ordering.natural().onResultOf(new Function<Account.Id, Integer>() {
|
||||
@@ -193,6 +197,14 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
this.comments = Lists.newArrayList();
|
||||
}
|
||||
|
||||
public ObjectId commit() throws IOException, OrmException {
|
||||
NoteDbUpdateManager updateManager =
|
||||
updateManagerFactory.create(getProjectName());
|
||||
updateManager.add(this);
|
||||
updateManager.execute();
|
||||
return getResult();
|
||||
}
|
||||
|
||||
public void setChangeId(String changeId) throws OrmException {
|
||||
if (notes == null) {
|
||||
notes = getChangeNotes().load();
|
||||
@@ -259,7 +271,7 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
}
|
||||
|
||||
public void insertComment(PatchLineComment comment) throws OrmException {
|
||||
if (comment.getStatus() == Status.DRAFT) {
|
||||
if (comment.getStatus() == PatchLineComment.Status.DRAFT) {
|
||||
insertDraftComment(comment);
|
||||
} else {
|
||||
insertPublishedComment(comment);
|
||||
@@ -267,7 +279,7 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
}
|
||||
|
||||
public void upsertComment(PatchLineComment comment) throws OrmException {
|
||||
if (comment.getStatus() == Status.DRAFT) {
|
||||
if (comment.getStatus() == PatchLineComment.Status.DRAFT) {
|
||||
upsertDraftComment(comment);
|
||||
} else {
|
||||
deleteDraftCommentIfPresent(comment);
|
||||
@@ -276,7 +288,7 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
}
|
||||
|
||||
public void updateComment(PatchLineComment comment) throws OrmException {
|
||||
if (comment.getStatus() == Status.DRAFT) {
|
||||
if (comment.getStatus() == PatchLineComment.Status.DRAFT) {
|
||||
updateDraftComment(comment);
|
||||
} else {
|
||||
deleteDraftCommentIfPresent(comment);
|
||||
@@ -285,7 +297,7 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
}
|
||||
|
||||
public void deleteComment(PatchLineComment comment) throws OrmException {
|
||||
if (comment.getStatus() == Status.DRAFT) {
|
||||
if (comment.getStatus() == PatchLineComment.Status.DRAFT) {
|
||||
deleteDraftComment(comment);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Cannot delete a published comment.");
|
||||
@@ -369,7 +381,7 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
|
||||
private void verifyComment(PatchLineComment c) {
|
||||
checkArgument(c.getRevId() != null);
|
||||
checkArgument(c.getStatus() == Status.PUBLISHED,
|
||||
checkArgument(c.getStatus() == PatchLineComment.Status.PUBLISHED,
|
||||
"Cannot add a draft comment to a ChangeUpdate. Use a ChangeDraftUpdate"
|
||||
+ " for draft comments");
|
||||
checkArgument(c.getAuthor().equals(getUser().getAccountId()),
|
||||
@@ -418,7 +430,8 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
}
|
||||
|
||||
/** @return the tree id for the updated tree */
|
||||
private ObjectId storeRevisionNotes() throws OrmException, IOException {
|
||||
private ObjectId storeRevisionNotes(ObjectInserter inserter)
|
||||
throws OrmException, IOException {
|
||||
ChangeNotes notes = ctl.getNotes().load();
|
||||
NoteMap noteMap = notes.getNoteMap();
|
||||
if (noteMap == null) {
|
||||
@@ -457,45 +470,15 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
return b;
|
||||
}
|
||||
|
||||
public RevCommit commit() throws IOException {
|
||||
BatchMetaDataUpdate batch = openUpdate();
|
||||
try {
|
||||
writeCommit(batch);
|
||||
RevCommit c = batch.commit();
|
||||
return c;
|
||||
} catch (OrmException e) {
|
||||
throw new IOException(e);
|
||||
} finally {
|
||||
batch.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCommit(BatchMetaDataUpdate batch) throws OrmException,
|
||||
IOException {
|
||||
CommitBuilder builder = new CommitBuilder();
|
||||
if (migration.writeChanges()) {
|
||||
ObjectId treeId = storeRevisionNotes();
|
||||
if (treeId != null) {
|
||||
builder.setTreeId(treeId);
|
||||
}
|
||||
}
|
||||
batch.write(this, builder);
|
||||
if (draftUpdate != null) {
|
||||
draftUpdate.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getRefName() {
|
||||
return ChangeNoteUtil.changeRefName(ctl.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onSave(CommitBuilder cb) {
|
||||
if (getRevision() != null && isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
protected CommitBuilder applyImpl(ObjectInserter ins)
|
||||
throws OrmException, IOException {
|
||||
CommitBuilder cb = new CommitBuilder();
|
||||
cb.setAuthor(newIdent(getUser().getAccount(), when));
|
||||
cb.setCommitter(new PersonIdent(serverIdent, when));
|
||||
|
||||
@@ -599,7 +582,11 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
}
|
||||
|
||||
cb.setMessage(msg.toString());
|
||||
return true;
|
||||
ObjectId treeId = storeRevisionNotes(ins);
|
||||
if (treeId != null) {
|
||||
cb.setTreeId(treeId);
|
||||
}
|
||||
return cb;
|
||||
}
|
||||
|
||||
private void addPatchSetFooter(StringBuilder sb, int ps) {
|
||||
@@ -634,6 +621,10 @@ public class ChangeUpdate extends AbstractChangeUpdate {
|
||||
&& groups == null;
|
||||
}
|
||||
|
||||
ChangeDraftUpdate getDraftUpdate() {
|
||||
return draftUpdate;
|
||||
}
|
||||
|
||||
private static StringBuilder addFooter(StringBuilder sb, FooterKey footer) {
|
||||
return sb.append(footer.getName()).append(": ");
|
||||
}
|
||||
|
||||
@@ -21,5 +21,6 @@ public class NoteDbModule extends FactoryModule {
|
||||
public void configure() {
|
||||
factory(ChangeUpdate.Factory.class);
|
||||
factory(ChangeDraftUpdate.Factory.class);
|
||||
factory(NoteDbUpdateManager.Factory.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
// Copyright (C) 2016 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.notedb;
|
||||
|
||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.gerrit.reviewdb.client.Project;
|
||||
import com.google.gerrit.server.config.AllUsersName;
|
||||
import com.google.gerrit.server.git.ChainedReceiveCommands;
|
||||
import com.google.gerrit.server.git.GitRepositoryManager;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
import com.google.inject.assistedinject.AssistedInject;
|
||||
|
||||
import org.eclipse.jgit.lib.BatchRefUpdate;
|
||||
import org.eclipse.jgit.lib.NullProgressMonitor;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.ObjectInserter;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class NoteDbUpdateManager {
|
||||
public interface Factory {
|
||||
NoteDbUpdateManager create(Project.NameKey projectName);
|
||||
}
|
||||
|
||||
private static class OpenRepo implements AutoCloseable {
|
||||
final Repository repo;
|
||||
final RevWalk rw;
|
||||
final ObjectInserter ins;
|
||||
final ChainedReceiveCommands cmds;
|
||||
final boolean close;
|
||||
|
||||
OpenRepo(Repository repo, RevWalk rw, ObjectInserter ins,
|
||||
ChainedReceiveCommands cmds, boolean close) {
|
||||
this.repo = checkNotNull(repo);
|
||||
this.rw = checkNotNull(rw);
|
||||
this.ins = checkNotNull(ins);
|
||||
this.cmds = checkNotNull(cmds);
|
||||
this.close = close;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (close) {
|
||||
ins.close();
|
||||
rw.close();
|
||||
repo.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final GitRepositoryManager repoManager;
|
||||
private final NotesMigration migration;
|
||||
private final AllUsersName allUsersName;
|
||||
private final Project.NameKey projectName;
|
||||
private final ListMultimap<String, ChangeUpdate> changeUpdates;
|
||||
private final ListMultimap<String, ChangeDraftUpdate> draftUpdates;
|
||||
|
||||
private OpenRepo changeRepo;
|
||||
private OpenRepo allUsersRepo;
|
||||
|
||||
@AssistedInject
|
||||
NoteDbUpdateManager(GitRepositoryManager repoManager,
|
||||
NotesMigration migration,
|
||||
AllUsersName allUsersName,
|
||||
@Assisted Project.NameKey projectName) {
|
||||
this.repoManager = repoManager;
|
||||
this.migration = migration;
|
||||
this.allUsersName = allUsersName;
|
||||
this.projectName = projectName;
|
||||
changeUpdates = ArrayListMultimap.create();
|
||||
draftUpdates = ArrayListMultimap.create();
|
||||
}
|
||||
|
||||
public NoteDbUpdateManager setChangeRepo(Repository repo, RevWalk rw,
|
||||
ObjectInserter ins, ChainedReceiveCommands cmds) {
|
||||
checkState(changeRepo == null, "change repo already initialized");
|
||||
changeRepo = new OpenRepo(repo, rw, ins, cmds, false);
|
||||
return this;
|
||||
}
|
||||
|
||||
public NoteDbUpdateManager setAllUsersRepo(Repository repo, RevWalk rw,
|
||||
ObjectInserter ins, ChainedReceiveCommands cmds) {
|
||||
checkState(allUsersRepo == null, "allUsers repo already initialized");
|
||||
allUsersRepo = new OpenRepo(repo, rw, ins, cmds, false);
|
||||
return this;
|
||||
}
|
||||
|
||||
Repository getAllUsersRepo() throws IOException {
|
||||
initAllUsersRepo();
|
||||
return allUsersRepo.repo;
|
||||
}
|
||||
|
||||
ChainedReceiveCommands getAllUsersCommands() throws IOException {
|
||||
initAllUsersRepo();
|
||||
return allUsersRepo.cmds;
|
||||
}
|
||||
|
||||
private void initChangeRepo() throws IOException {
|
||||
if (changeRepo == null) {
|
||||
changeRepo = openRepo(projectName);
|
||||
}
|
||||
}
|
||||
|
||||
private void initAllUsersRepo() throws IOException {
|
||||
if (allUsersRepo == null) {
|
||||
allUsersRepo = openRepo(allUsersName);
|
||||
}
|
||||
}
|
||||
|
||||
private OpenRepo openRepo(Project.NameKey p) throws IOException {
|
||||
Repository repo = repoManager.openMetadataRepository(p);
|
||||
ObjectInserter ins = repo.newObjectInserter();
|
||||
return new OpenRepo(repo, new RevWalk(ins.newReader()), ins,
|
||||
new ChainedReceiveCommands(), true);
|
||||
}
|
||||
|
||||
private boolean isEmpty() {
|
||||
return !migration.writeChanges() || changeUpdates.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an update to the list of updates to execute.
|
||||
* <p>
|
||||
* Updates should only be added to the manager after all mutations have been
|
||||
* made, as this method may eagerly access the update.
|
||||
*
|
||||
* @param update the update to add.
|
||||
*/
|
||||
public void add(ChangeUpdate update) {
|
||||
checkArgument(update.getProjectName().equals(projectName),
|
||||
"update for project %s cannot be added to manager for project %s",
|
||||
update.getProjectName(), projectName);
|
||||
changeUpdates.put(update.getRefName(), update);
|
||||
ChangeDraftUpdate du = update.getDraftUpdate();
|
||||
if (du != null) {
|
||||
draftUpdates.put(du.getRefName(), du);
|
||||
}
|
||||
}
|
||||
|
||||
public void add(ChangeDraftUpdate draftUpdate) {
|
||||
draftUpdates.put(draftUpdate.getRefName(), draftUpdate);
|
||||
}
|
||||
|
||||
public void execute() throws OrmException, IOException {
|
||||
if (isEmpty()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
initChangeRepo();
|
||||
if (!draftUpdates.isEmpty()) {
|
||||
initAllUsersRepo();
|
||||
}
|
||||
addCommands();
|
||||
|
||||
execute(allUsersRepo);
|
||||
execute(changeRepo);
|
||||
} finally {
|
||||
if (allUsersRepo != null) {
|
||||
allUsersRepo.close();
|
||||
}
|
||||
if (changeRepo != null) {
|
||||
changeRepo.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void execute(OpenRepo or) throws IOException {
|
||||
if (or == null || or.cmds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
or.ins.flush();
|
||||
BatchRefUpdate bru = or.repo.getRefDatabase().newBatchUpdate();
|
||||
or.cmds.addTo(bru);
|
||||
bru.execute(or.rw, NullProgressMonitor.INSTANCE);
|
||||
for (ReceiveCommand cmd : bru.getCommands()) {
|
||||
if (cmd.getResult() != ReceiveCommand.Result.OK) {
|
||||
throw new IOException("Update failed: " + bru);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addCommands() throws OrmException, IOException {
|
||||
if (isEmpty()) {
|
||||
return;
|
||||
}
|
||||
checkState(changeRepo != null, "must set change repo");
|
||||
if (!draftUpdates.isEmpty()) {
|
||||
checkState(allUsersRepo != null, "must set all users repo");
|
||||
}
|
||||
addUpdates(changeUpdates, changeRepo);
|
||||
if (!draftUpdates.isEmpty()) {
|
||||
addUpdates(draftUpdates, allUsersRepo);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addUpdates(
|
||||
ListMultimap<String, ? extends AbstractChangeUpdate> updates, OpenRepo or)
|
||||
throws OrmException, IOException {
|
||||
for (String refName : updates.keySet()) {
|
||||
ObjectId old = firstNonNull(
|
||||
or.cmds.getObjectId(or.repo, refName), ObjectId.zeroId());
|
||||
ObjectId curr = old;
|
||||
|
||||
for (AbstractChangeUpdate u : updates.get(refName)) {
|
||||
ObjectId next = u.apply(or.rw, or.ins, curr);
|
||||
if (next == null) {
|
||||
continue;
|
||||
}
|
||||
curr = next;
|
||||
}
|
||||
if (!old.equals(curr)) {
|
||||
or.cmds.add(new ReceiveCommand(old, curr, refName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,6 @@ import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
|
||||
import org.eclipse.jgit.junit.TestRepository;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
import org.eclipse.jgit.lib.PersonIdent;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
@@ -94,6 +93,7 @@ public class AbstractChangeNotesTest extends GerritBaseTests {
|
||||
protected TestRepository<InMemoryRepository> tr;
|
||||
|
||||
@Inject protected IdentifiedUser.GenericFactory userFactory;
|
||||
@Inject protected NoteDbUpdateManager.Factory updateManagerFactory;
|
||||
|
||||
private Injector injector;
|
||||
private String systemTimeZone;
|
||||
@@ -126,6 +126,7 @@ public class AbstractChangeNotesTest extends GerritBaseTests {
|
||||
@Override
|
||||
public void configure() {
|
||||
install(new GitModule());
|
||||
factory(NoteDbUpdateManager.Factory.class);
|
||||
bind(AllUsersName.class).toProvider(AllUsersNameProvider.class);
|
||||
bind(NotesMigration.class).toInstance(MIGRATION);
|
||||
bind(GitRepositoryManager.class).toInstance(repoManager);
|
||||
@@ -183,9 +184,6 @@ public class AbstractChangeNotesTest extends GerritBaseTests {
|
||||
throws Exception {
|
||||
ChangeUpdate update = TestChanges.newUpdate(
|
||||
injector, repoManager, MIGRATION, c, allUsers, user);
|
||||
try (Repository repo = repoManager.openMetadataRepository(c.getProject())) {
|
||||
update.load(repo);
|
||||
}
|
||||
return update;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,18 +44,15 @@ import com.google.gerrit.reviewdb.client.PatchLineComment.Status;
|
||||
import com.google.gerrit.reviewdb.client.PatchSet;
|
||||
import com.google.gerrit.reviewdb.client.PatchSetApproval;
|
||||
import com.google.gerrit.reviewdb.client.RevId;
|
||||
import com.google.gerrit.server.git.VersionedMetaData.BatchMetaDataUpdate;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
|
||||
import org.eclipse.jgit.lib.BatchRefUpdate;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.NullProgressMonitor;
|
||||
import org.eclipse.jgit.lib.ObjectId;
|
||||
import org.eclipse.jgit.lib.Ref;
|
||||
import org.eclipse.jgit.notes.Note;
|
||||
import org.eclipse.jgit.notes.NoteMap;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.eclipse.jgit.revwalk.RevWalk;
|
||||
import org.eclipse.jgit.transport.ReceiveCommand;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
@@ -410,17 +407,16 @@ public class ChangeNotesTest extends AbstractChangeNotesTest {
|
||||
@Test
|
||||
public void emptyChangeUpdate() throws Exception {
|
||||
Change c = newChange();
|
||||
Ref initial = repo.exactRef(ChangeNoteUtil.changeRefName(c.getId()));
|
||||
assertThat(initial).isNotNull();
|
||||
|
||||
// The initial empty update creates a commit which is needed to track the
|
||||
// creation time of the change.
|
||||
// Empty update doesn't create a new commit.
|
||||
ChangeUpdate update = newUpdate(c, changeOwner);
|
||||
ObjectId revision = update.getRevision();
|
||||
assertThat(revision).isNotNull();
|
||||
|
||||
// Any further empty update doesn't create a new commit.
|
||||
update = newUpdate(c, changeOwner);
|
||||
update.commit();
|
||||
assertThat(update.getRevision()).isEqualTo(revision);
|
||||
assertThat(update.getResult()).isNull();
|
||||
|
||||
Ref updated = repo.exactRef(ChangeNoteUtil.changeRefName(c.getId()));
|
||||
assertThat(updated.getObjectId()).isEqualTo(initial.getObjectId());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -433,7 +429,7 @@ public class ChangeNotesTest extends AbstractChangeNotesTest {
|
||||
update.setHashtags(hashtags);
|
||||
update.commit();
|
||||
try (RevWalk walk = new RevWalk(repo)) {
|
||||
RevCommit commit = walk.parseCommit(update.getRevision());
|
||||
RevCommit commit = walk.parseCommit(update.getResult());
|
||||
walk.parseBody(commit);
|
||||
assertThat(commit.getFullMessage()).endsWith("Hashtags: tag1,tag2\n");
|
||||
}
|
||||
@@ -840,12 +836,11 @@ public class ChangeNotesTest extends AbstractChangeNotesTest {
|
||||
public void emptyExceptSubject() throws Exception {
|
||||
ChangeUpdate update = newUpdate(newChange(), changeOwner);
|
||||
update.setSubjectForCommit("Create change");
|
||||
update.commit();
|
||||
assertThat(update.getRevision()).isNotNull();
|
||||
assertThat(update.commit()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleUpdatesInBatch() throws Exception {
|
||||
public void multipleUpdatesInManager() throws Exception {
|
||||
Change c = newChange();
|
||||
ChangeUpdate update1 = newUpdate(c, changeOwner);
|
||||
update1.putApproval("Verified", (short) 1);
|
||||
@@ -853,14 +848,10 @@ public class ChangeNotesTest extends AbstractChangeNotesTest {
|
||||
ChangeUpdate update2 = newUpdate(c, otherUser);
|
||||
update2.putApproval("Code-Review", (short) 2);
|
||||
|
||||
BatchMetaDataUpdate batch = update1.openUpdate();
|
||||
try {
|
||||
update1.writeCommit(batch);
|
||||
update2.writeCommit(batch);
|
||||
batch.commit();
|
||||
} finally {
|
||||
batch.close();
|
||||
}
|
||||
NoteDbUpdateManager updateManager = updateManagerFactory.create(project);
|
||||
updateManager.add(update1);
|
||||
updateManager.add(update2);
|
||||
updateManager.execute();
|
||||
|
||||
ChangeNotes notes = newNotes(c);
|
||||
List<PatchSetApproval> psas =
|
||||
@@ -887,29 +878,24 @@ public class ChangeNotesTest extends AbstractChangeNotesTest {
|
||||
CommentRange range1 = new CommentRange(1, 1, 2, 1);
|
||||
Timestamp time1 = TimeUtil.nowTs();
|
||||
PatchSet.Id psId = c.currentPatchSetId();
|
||||
BatchRefUpdate bru = repo.getRefDatabase().newBatchUpdate();
|
||||
BatchMetaDataUpdate batch = update1.openUpdateInBatch(bru);
|
||||
NoteDbUpdateManager updateManager = updateManagerFactory.create(project);
|
||||
PatchLineComment comment1 = newPublishedComment(psId, "file1",
|
||||
uuid1, range1, range1.getEndLine(), otherUser, null, time1, message1,
|
||||
(short) 0, "abcd1234abcd1234abcd1234abcd1234abcd1234");
|
||||
update1.setPatchSetId(psId);
|
||||
update1.upsertComment(comment1);
|
||||
update1.writeCommit(batch);
|
||||
updateManager.add(update1);
|
||||
|
||||
ChangeUpdate update2 = newUpdate(c, otherUser);
|
||||
update2.putApproval("Code-Review", (short) 2);
|
||||
update2.writeCommit(batch);
|
||||
updateManager.add(update2);
|
||||
|
||||
RevCommit tipCommit;
|
||||
try (RevWalk rw = new RevWalk(repo)) {
|
||||
batch.commit();
|
||||
bru.execute(rw, NullProgressMonitor.INSTANCE);
|
||||
updateManager.execute();
|
||||
|
||||
ChangeNotes notes = newNotes(c);
|
||||
ObjectId tip = notes.getRevision();
|
||||
tipCommit = rw.parseCommit(tip);
|
||||
} finally {
|
||||
batch.close();
|
||||
}
|
||||
ChangeNotes notes = newNotes(c);
|
||||
ObjectId tip = notes.getRevision();
|
||||
tipCommit = rw.parseCommit(tip);
|
||||
|
||||
RevCommit commitWithApprovals = tipCommit;
|
||||
assertThat(commitWithApprovals).isNotNull();
|
||||
@@ -949,43 +935,30 @@ public class ChangeNotesTest extends AbstractChangeNotesTest {
|
||||
ChangeUpdate update2 = newUpdate(c2, otherUser);
|
||||
update2.putApproval("Code-Review", (short) 2);
|
||||
|
||||
BatchMetaDataUpdate batch1 = null;
|
||||
BatchMetaDataUpdate batch2 = null;
|
||||
Ref initial1 = repo.exactRef(update1.getRefName());
|
||||
assertThat(initial1).isNotNull();
|
||||
Ref initial2 = repo.exactRef(update2.getRefName());
|
||||
assertThat(initial2).isNotNull();
|
||||
|
||||
BatchRefUpdate bru = repo.getRefDatabase().newBatchUpdate();
|
||||
try {
|
||||
batch1 = update1.openUpdateInBatch(bru);
|
||||
update1.writeCommit(batch1);
|
||||
batch1.commit();
|
||||
assertThat(repo.exactRef(update1.getRefName())).isNotNull();
|
||||
NoteDbUpdateManager updateManager = updateManagerFactory.create(project);
|
||||
updateManager.add(update1);
|
||||
updateManager.add(update2);
|
||||
updateManager.execute();
|
||||
|
||||
batch2 = update2.openUpdateInBatch(bru);
|
||||
update2.writeCommit(batch2);
|
||||
batch2.commit();
|
||||
assertThat(repo.exactRef(update2.getRefName())).isNotNull();
|
||||
} finally {
|
||||
if (batch1 != null) {
|
||||
batch1.close();
|
||||
}
|
||||
if (batch2 != null) {
|
||||
batch2.close();
|
||||
}
|
||||
}
|
||||
Ref ref1 = repo.exactRef(update1.getRefName());
|
||||
assertThat(ref1.getObjectId()).isEqualTo(update1.getResult());
|
||||
assertThat(ref1.getObjectId()).isNotEqualTo(initial1.getObjectId());
|
||||
Ref ref2 = repo.exactRef(update2.getRefName());
|
||||
assertThat(ref2.getObjectId()).isEqualTo(update2.getResult());
|
||||
assertThat(ref2.getObjectId()).isNotEqualTo(initial2.getObjectId());
|
||||
|
||||
List<ReceiveCommand> cmds = bru.getCommands();
|
||||
assertThat(cmds).hasSize(2);
|
||||
assertThat(cmds.get(0).getRefName()).isEqualTo(update1.getRefName());
|
||||
assertThat(cmds.get(1).getRefName()).isEqualTo(update2.getRefName());
|
||||
PatchSetApproval approval1 = newNotes(c1).getApprovals()
|
||||
.get(c1.currentPatchSetId()).iterator().next();
|
||||
assertThat(approval1.getLabel()).isEqualTo("Verified");
|
||||
|
||||
try (RevWalk rw = new RevWalk(repo)) {
|
||||
bru.execute(rw, NullProgressMonitor.INSTANCE);
|
||||
}
|
||||
|
||||
assertThat(cmds.get(0).getResult()).isEqualTo(ReceiveCommand.Result.OK);
|
||||
assertThat(cmds.get(1).getResult()).isEqualTo(ReceiveCommand.Result.OK);
|
||||
|
||||
assertThat(repo.exactRef(update1.getRefName())).isNotNull();
|
||||
assertThat(repo.exactRef(update2.getRefName())).isNotNull();
|
||||
PatchSetApproval approval2 = newNotes(c2).getApprovals()
|
||||
.get(c2.currentPatchSetId()).iterator().next();
|
||||
assertThat(approval2.getLabel()).isEqualTo("Code-Review");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -45,7 +45,7 @@ public class CommitMessageOutputTest extends AbstractChangeNotesTest {
|
||||
update.commit();
|
||||
assertThat(update.getRefName()).isEqualTo("refs/changes/01/1/meta");
|
||||
|
||||
RevCommit commit = parseCommit(update.getRevision());
|
||||
RevCommit commit = parseCommit(update.getResult());
|
||||
assertBodyEquals("Update patch set 1\n"
|
||||
+ "\n"
|
||||
+ "Patch-set: 1\n"
|
||||
@@ -93,7 +93,7 @@ public class CommitMessageOutputTest extends AbstractChangeNotesTest {
|
||||
+ "Subject: Change subject\n"
|
||||
+ "Branch: refs/heads/master\n"
|
||||
+ "Commit: " + update.getCommit().name() + "\n",
|
||||
update.getRevision());
|
||||
update.getResult());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -115,7 +115,7 @@ public class CommitMessageOutputTest extends AbstractChangeNotesTest {
|
||||
+ "Subject: Subject\n"
|
||||
+ "Branch: refs/heads/master\n"
|
||||
+ "Commit: " + commit.name() + "\n",
|
||||
update.getRevision());
|
||||
update.getResult());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -129,7 +129,7 @@ public class CommitMessageOutputTest extends AbstractChangeNotesTest {
|
||||
+ "\n"
|
||||
+ "Patch-set: 1\n"
|
||||
+ "Label: -Code-Review\n",
|
||||
update.getRevision());
|
||||
update.getResult());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -147,7 +147,7 @@ public class CommitMessageOutputTest extends AbstractChangeNotesTest {
|
||||
submitLabel("Alternative-Code-Review", "NEED", null))));
|
||||
update.commit();
|
||||
|
||||
RevCommit commit = parseCommit(update.getRevision());
|
||||
RevCommit commit = parseCommit(update.getResult());
|
||||
assertBodyEquals("Submit patch set 1\n"
|
||||
+ "\n"
|
||||
+ "Patch-set: 1\n"
|
||||
@@ -185,7 +185,7 @@ public class CommitMessageOutputTest extends AbstractChangeNotesTest {
|
||||
update.setChangeMessage("Comment on the change.");
|
||||
update.commit();
|
||||
|
||||
RevCommit commit = parseCommit(update.getRevision());
|
||||
RevCommit commit = parseCommit(update.getResult());
|
||||
assertBodyEquals("Update patch set 1\n"
|
||||
+ "\n"
|
||||
+ "Comment on the change.\n"
|
||||
@@ -214,7 +214,7 @@ public class CommitMessageOutputTest extends AbstractChangeNotesTest {
|
||||
+ "Status: merged\n"
|
||||
+ "Submission-id: 1-1453387607626-96fabc25\n"
|
||||
+ "Submitted-with: RULE_ERROR Problem with patch set: 1\n",
|
||||
update.getRevision());
|
||||
update.getResult());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -228,7 +228,7 @@ public class CommitMessageOutputTest extends AbstractChangeNotesTest {
|
||||
+ "\n"
|
||||
+ "Patch-set: 1\n"
|
||||
+ "Reviewer: Change Owner <1@gerrit>\n",
|
||||
update.getRevision());
|
||||
update.getResult());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -246,7 +246,7 @@ public class CommitMessageOutputTest extends AbstractChangeNotesTest {
|
||||
+ "\n"
|
||||
+ "\n"
|
||||
+ "Patch-set: 1\n",
|
||||
update.getRevision());
|
||||
update.getResult());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -269,7 +269,7 @@ public class CommitMessageOutputTest extends AbstractChangeNotesTest {
|
||||
+ "Testing paragraph 3\n"
|
||||
+ "\n"
|
||||
+ "Patch-set: 1\n",
|
||||
update.getRevision());
|
||||
update.getResult());
|
||||
}
|
||||
|
||||
private RevCommit parseCommit(ObjectId id) throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user