Merge changes from topic 'change-inserter-batch-update'

* changes:
  Convert ChangeInserter to BatchUpdate.Op
  BatchUpdate: Create ChangeControl inside transaction
  Create change ref from ChangeInserter
  CherryPickChange: Write change message using ChangeInserter
  Validate new commits in ChangeInserter rather than callers
  Move PatchSetInserter.ValidatePolicy to CommitValidators
  Clean up ChangeInserter similar to PatchSetInserter
This commit is contained in:
Edwin Kempin
2015-10-12 14:01:23 +00:00
committed by Gerrit Code Review
24 changed files with 567 additions and 548 deletions

View File

@@ -37,8 +37,11 @@ import com.google.gerrit.server.change.ChangeResource;
import com.google.gerrit.server.change.ChangesCollection; import com.google.gerrit.server.change.ChangesCollection;
import com.google.gerrit.server.change.PostReviewers; import com.google.gerrit.server.change.PostReviewers;
import com.google.gerrit.server.config.AllProjectsNameProvider; import com.google.gerrit.server.config.AllProjectsNameProvider;
import com.google.gerrit.server.git.BatchUpdate;
import com.google.gerrit.server.git.MetaDataUpdate; import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig; import com.google.gerrit.server.git.ProjectConfig;
import com.google.gerrit.server.git.UpdateException;
import com.google.gerrit.server.git.validators.CommitValidators;
import com.google.gerrit.server.group.SystemGroupBackend; import com.google.gerrit.server.group.SystemGroupBackend;
import com.google.gerrit.server.project.ProjectCache; import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectControl; import com.google.gerrit.server.project.ProjectControl;
@@ -49,7 +52,9 @@ import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@@ -70,6 +75,7 @@ public class ReviewProjectAccess extends ProjectAccessHandler<Change.Id> {
private final ProjectCache projectCache; private final ProjectCache projectCache;
private final ChangesCollection changes; private final ChangesCollection changes;
private final ChangeInserter.Factory changeInserterFactory; private final ChangeInserter.Factory changeInserterFactory;
private final BatchUpdate.Factory updateFactory;
@Inject @Inject
ReviewProjectAccess(final ProjectControl.Factory projectControlFactory, ReviewProjectAccess(final ProjectControl.Factory projectControlFactory,
@@ -81,6 +87,7 @@ public class ReviewProjectAccess extends ProjectAccessHandler<Change.Id> {
AllProjectsNameProvider allProjects, AllProjectsNameProvider allProjects,
ChangesCollection changes, ChangesCollection changes,
ChangeInserter.Factory changeInserterFactory, ChangeInserter.Factory changeInserterFactory,
BatchUpdate.Factory updateFactory,
Provider<SetParent> setParent, Provider<SetParent> setParent,
@Assisted("projectName") Project.NameKey projectName, @Assisted("projectName") Project.NameKey projectName,
@@ -97,6 +104,7 @@ public class ReviewProjectAccess extends ProjectAccessHandler<Change.Id> {
this.projectCache = projectCache; this.projectCache = projectCache;
this.changes = changes; this.changes = changes;
this.changeInserterFactory = changeInserterFactory; this.changeInserterFactory = changeInserterFactory;
this.updateFactory = updateFactory;
} }
@Override @Override
@@ -120,9 +128,21 @@ public class ReviewProjectAccess extends ProjectAccessHandler<Change.Id> {
config.getProject().getNameKey(), config.getProject().getNameKey(),
RefNames.REFS_CONFIG), RefNames.REFS_CONFIG),
TimeUtil.nowTs()); TimeUtil.nowTs());
ChangeInserter ins = try (RevWalk rw = new RevWalk(md.getRepository());
changeInserterFactory.create(ctl, change, commit); ObjectInserter objInserter = md.getRepository().newObjectInserter();
ins.insert(); BatchUpdate bu = updateFactory.create(
db, change.getProject(), ctl.getCurrentUser(),
change.getCreatedOn())) {
bu.setRepository(md.getRepository(), rw, objInserter);
bu.insertChange(
changeInserterFactory.create(
ctl.controlForRef(change.getDest().get()), change, commit)
.setValidatePolicy(CommitValidators.Policy.NONE)
.setUpdateRef(false)); // Created by commitToNewRef.
bu.execute();
} catch (UpdateException | RestApiException e) {
throw new IOException(e);
}
ChangeResource rsrc; ChangeResource rsrc;
try { try {

View File

@@ -22,8 +22,8 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Ordering; import com.google.common.collect.Ordering;
import com.google.gerrit.common.TimeUtil; import com.google.gerrit.common.TimeUtil;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Change; 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.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetAncestor; import com.google.gerrit.reviewdb.client.PatchSetAncestor;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
@@ -32,21 +32,18 @@ import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.change.ChangeInserter; import com.google.gerrit.server.change.ChangeInserter;
import com.google.gerrit.server.change.ChangeMessages; import com.google.gerrit.server.change.ChangeMessages;
import com.google.gerrit.server.change.ChangeTriplet; import com.google.gerrit.server.change.ChangeTriplet;
import com.google.gerrit.server.events.CommitReceivedEvent;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated; import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.BatchUpdate;
import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.validators.CommitValidationException; import com.google.gerrit.server.git.UpdateException;
import com.google.gerrit.server.git.validators.CommitValidators; import com.google.gerrit.server.git.validators.CommitValidators;
import com.google.gerrit.server.index.ChangeIndexer; import com.google.gerrit.server.index.ChangeIndexer;
import com.google.gerrit.server.mail.RevertedSender; import com.google.gerrit.server.mail.RevertedSender;
import com.google.gerrit.server.project.ChangeControl; 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.gerrit.server.project.RefControl; import com.google.gerrit.server.project.RefControl;
import com.google.gerrit.server.query.change.InternalChangeQuery; import com.google.gerrit.server.query.change.InternalChangeQuery;
import com.google.gerrit.server.ssh.SshInfo;
import com.google.gerrit.server.util.IdGenerator; import com.google.gerrit.server.util.IdGenerator;
import com.google.gerrit.server.util.MagicBranch;
import com.google.gwtorm.server.OrmConcurrencyException; import com.google.gwtorm.server.OrmConcurrencyException;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
@@ -194,7 +191,6 @@ public class ChangeUtil {
} }
private final Provider<CurrentUser> userProvider; private final Provider<CurrentUser> userProvider;
private final CommitValidators.Factory commitValidatorsFactory;
private final Provider<ReviewDb> db; private final Provider<ReviewDb> db;
private final Provider<InternalChangeQuery> queryProvider; private final Provider<InternalChangeQuery> queryProvider;
private final RevertedSender.Factory revertedSenderFactory; private final RevertedSender.Factory revertedSenderFactory;
@@ -202,19 +198,19 @@ public class ChangeUtil {
private final GitRepositoryManager gitManager; private final GitRepositoryManager gitManager;
private final GitReferenceUpdated gitRefUpdated; private final GitReferenceUpdated gitRefUpdated;
private final ChangeIndexer indexer; private final ChangeIndexer indexer;
private final BatchUpdate.Factory updateFactory;
@Inject @Inject
ChangeUtil(Provider<CurrentUser> userProvider, ChangeUtil(Provider<CurrentUser> userProvider,
CommitValidators.Factory commitValidatorsFactory,
Provider<ReviewDb> db, Provider<ReviewDb> db,
Provider<InternalChangeQuery> queryProvider, Provider<InternalChangeQuery> queryProvider,
RevertedSender.Factory revertedSenderFactory, RevertedSender.Factory revertedSenderFactory,
ChangeInserter.Factory changeInserterFactory, ChangeInserter.Factory changeInserterFactory,
GitRepositoryManager gitManager, GitRepositoryManager gitManager,
GitReferenceUpdated gitRefUpdated, GitReferenceUpdated gitRefUpdated,
ChangeIndexer indexer) { ChangeIndexer indexer,
BatchUpdate.Factory updateFactory) {
this.userProvider = userProvider; this.userProvider = userProvider;
this.commitValidatorsFactory = commitValidatorsFactory;
this.db = db; this.db = db;
this.queryProvider = queryProvider; this.queryProvider = queryProvider;
this.revertedSenderFactory = revertedSenderFactory; this.revertedSenderFactory = revertedSenderFactory;
@@ -222,13 +218,14 @@ public class ChangeUtil {
this.gitManager = gitManager; this.gitManager = gitManager;
this.gitRefUpdated = gitRefUpdated; this.gitRefUpdated = gitRefUpdated;
this.indexer = indexer; this.indexer = indexer;
this.updateFactory = updateFactory;
} }
public Change.Id revert(ChangeControl ctl, PatchSet.Id patchSetId, public Change.Id revert(ChangeControl ctl, PatchSet.Id patchSetId,
String message, PersonIdent myIdent, SshInfo sshInfo) String message, PersonIdent myIdent)
throws NoSuchChangeException, OrmException, throws NoSuchChangeException, OrmException,
MissingObjectException, IncorrectObjectTypeException, IOException, MissingObjectException, IncorrectObjectTypeException, IOException,
InvalidChangeOperationException { RestApiException, UpdateException {
Change.Id changeId = patchSetId.getParentKey(); Change.Id changeId = patchSetId.getParentKey();
PatchSet patch = db.get().patchSets().get(patchSetId); PatchSet patch = db.get().patchSets().get(patchSetId);
if (patch == null) { if (patch == null) {
@@ -267,11 +264,11 @@ public class ChangeUtil {
ChangeIdUtil.insertId(message, computedChangeId, true)); ChangeIdUtil.insertId(message, computedChangeId, true));
RevCommit revertCommit; RevCommit revertCommit;
ChangeInserter ins;
try (ObjectInserter oi = git.newObjectInserter()) { try (ObjectInserter oi = git.newObjectInserter()) {
ObjectId id = oi.insert(revertCommitBuilder); ObjectId id = oi.insert(revertCommitBuilder);
oi.flush(); oi.flush();
revertCommit = revWalk.parseCommit(id); revertCommit = revWalk.parseCommit(id);
}
RefControl refControl = ctl.getRefControl(); RefControl refControl = ctl.getRefControl();
Change change = new Change( Change change = new Change(
@@ -281,59 +278,35 @@ public class ChangeUtil {
changeToRevert.getDest(), changeToRevert.getDest(),
TimeUtil.nowTs()); TimeUtil.nowTs());
change.setTopic(changeToRevert.getTopic()); change.setTopic(changeToRevert.getTopic());
ChangeInserter ins = ins = changeInserterFactory.create(
changeInserterFactory.create(refControl.getProjectControl(), refControl, change, revertCommit)
change, revertCommit); .setValidatePolicy(CommitValidators.Policy.GERRIT);
PatchSet ps = ins.getPatchSet();
String ref = refControl.getRefName();
String cmdRef = MagicBranch.NEW_PUBLISH_CHANGE
+ ref.substring(ref.lastIndexOf('/') + 1);
CommitReceivedEvent commitReceivedEvent = new CommitReceivedEvent(
new ReceiveCommand(ObjectId.zeroId(), revertCommit.getId(), cmdRef),
refControl.getProjectControl().getProject(),
refControl.getRefName(), revertCommit, user());
try {
commitValidatorsFactory.create(refControl, sshInfo, git)
.validateForGerritCommits(commitReceivedEvent);
} catch (CommitValidationException e) {
throw new InvalidChangeOperationException(e.getMessage());
}
RefUpdate ru = git.updateRef(ps.getRefName());
ru.setExpectedOldObjectId(ObjectId.zeroId());
ru.setNewObjectId(revertCommit);
ru.disableRefLog();
if (ru.update(revWalk) != RefUpdate.Result.NEW) {
throw new IOException(String.format(
"Failed to create ref %s in %s: %s", ps.getRefName(),
change.getDest().getParentKey().get(), ru.getResult()));
}
ChangeMessage cmsg = new ChangeMessage(
new ChangeMessage.Key(changeId, messageUUID(db.get())),
user().getAccountId(), TimeUtil.nowTs(), patchSetId);
StringBuilder msgBuf = new StringBuilder(); StringBuilder msgBuf = new StringBuilder();
msgBuf.append("Patch Set ").append(patchSetId.get()).append(": Reverted"); msgBuf.append("Patch Set ").append(patchSetId.get()).append(": Reverted");
msgBuf.append("\n\n"); msgBuf.append("\n\n");
msgBuf.append("This patchset was reverted in change: ") msgBuf.append("This patchset was reverted in change: ")
.append(change.getKey().get()); .append(change.getKey().get());
cmsg.setMessage(msgBuf.toString()); ins.setMessage(msgBuf.toString());
try (BatchUpdate bu = updateFactory.create(
ins.setMessage(cmsg).insert(); db.get(), change.getProject(), refControl.getCurrentUser(),
change.getCreatedOn())) {
try { bu.setRepository(git, revWalk, oi);
RevertedSender cm = revertedSenderFactory.create(change.getId()); bu.insertChange(ins);
cm.setFrom(user().getAccountId()); bu.execute();
cm.setChangeMessage(cmsg); }
cm.send();
} catch (Exception err) {
log.error("Cannot send email for revert change " + change.getId(),
err);
} }
return change.getId(); Change.Id id = ins.getChange().getId();
try {
RevertedSender cm = revertedSenderFactory.create(id);
cm.setFrom(user().getAccountId());
cm.setChangeMessage(ins.getChangeMessage());
cm.send();
} catch (Exception err) {
log.error("Cannot send email for revert change " + id, err);
}
return id;
} catch (RepositoryNotFoundException e) { } catch (RepositoryNotFoundException e) {
throw new NoSuchChangeException(changeId, e); throw new NoSuchChangeException(changeId, e);
} }

View File

@@ -195,7 +195,7 @@ class ChangeApiImpl implements ChangeApi {
public ChangeApi revert(RevertInput in) throws RestApiException { public ChangeApi revert(RevertInput in) throws RestApiException {
try { try {
return changeApi.id(revert.apply(change, in)._number); return changeApi.id(revert.apply(change, in)._number);
} catch (OrmException | EmailException | IOException e) { } catch (OrmException | EmailException | IOException | UpdateException e) {
throw new RestApiException("Cannot revert change", e); throw new RestApiException("Cannot revert change", e);
} }
} }

View File

@@ -32,6 +32,7 @@ import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.change.ChangesCollection; import com.google.gerrit.server.change.ChangesCollection;
import com.google.gerrit.server.change.CreateChange; import com.google.gerrit.server.change.CreateChange;
import com.google.gerrit.server.git.UpdateException;
import com.google.gerrit.server.project.InvalidChangeOperationException; import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.query.change.QueryChanges; import com.google.gerrit.server.query.change.QueryChanges;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
@@ -95,7 +96,8 @@ class ChangesImpl implements Changes {
TopLevelResource.INSTANCE, in).value(); TopLevelResource.INSTANCE, in).value();
return api.create(changes.parse(TopLevelResource.INSTANCE, return api.create(changes.parse(TopLevelResource.INSTANCE,
IdString.fromUrl(out.changeId))); IdString.fromUrl(out.changeId)));
} catch (OrmException | IOException | InvalidChangeOperationException e) { } catch (OrmException | IOException | InvalidChangeOperationException
| UpdateException e) {
throw new RestApiException("Cannot create change", e); throw new RestApiException("Cannot create change", e);
} }
} }

View File

@@ -93,9 +93,10 @@ public class Abandon implements RestModifyView<ChangeResource, AbandonInput>,
final String msgTxt, final Account account) final String msgTxt, final Account account)
throws RestApiException, UpdateException { throws RestApiException, UpdateException {
Op op = new Op(msgTxt, account); Op op = new Op(msgTxt, account);
Change c = control.getChange();
try (BatchUpdate u = batchUpdateFactory.create(dbProvider.get(), try (BatchUpdate u = batchUpdateFactory.create(dbProvider.get(),
control.getChange().getProject(), TimeUtil.nowTs())) { c.getProject(), control.getCurrentUser(), TimeUtil.nowTs())) {
u.addOp(control, op).execute(); u.addOp(c.getId(), op).execute();
} }
return op.change; return op.change;
} }
@@ -116,7 +117,7 @@ public class Abandon implements RestModifyView<ChangeResource, AbandonInput>,
@Override @Override
public void updateChange(ChangeContext ctx) throws OrmException, public void updateChange(ChangeContext ctx) throws OrmException,
ResourceConflictException { ResourceConflictException {
change = ctx.readChange(); change = ctx.getChange();
if (change == null || !change.getStatus().isOpen()) { if (change == null || !change.getStatus().isOpen()) {
throw new ResourceConflictException("change is " + status(change)); throw new ResourceConflictException("change is " + status(change));
} else if (change.getStatus() == Change.Status.DRAFT) { } else if (change.getStatus() == Change.Status.DRAFT) {

View File

@@ -14,9 +14,11 @@
package com.google.gerrit.server.change; package com.google.gerrit.server.change;
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.reviewdb.client.Change.INITIAL_PATCH_SET_ID; import static com.google.gerrit.reviewdb.client.Change.INITIAL_PATCH_SET_ID;
import com.google.common.util.concurrent.CheckedFuture;
import com.google.gerrit.common.ChangeHooks; import com.google.gerrit.common.ChangeHooks;
import com.google.gerrit.common.data.LabelTypes; import com.google.gerrit.common.data.LabelTypes;
import com.google.gerrit.extensions.api.changes.HashtagsInput; import com.google.gerrit.extensions.api.changes.HashtagsInput;
@@ -31,25 +33,35 @@ import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.ApprovalsUtil; import com.google.gerrit.server.ApprovalsUtil;
import com.google.gerrit.server.ChangeMessagesUtil; import com.google.gerrit.server.ChangeMessagesUtil;
import com.google.gerrit.server.ChangeUtil; import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.AccountCache; import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated; import com.google.gerrit.server.events.CommitReceivedEvent;
import com.google.gerrit.server.git.BanCommit;
import com.google.gerrit.server.git.BatchUpdate;
import com.google.gerrit.server.git.BatchUpdate.ChangeContext;
import com.google.gerrit.server.git.BatchUpdate.Context;
import com.google.gerrit.server.git.BatchUpdate.RepoContext;
import com.google.gerrit.server.git.GroupCollector; import com.google.gerrit.server.git.GroupCollector;
import com.google.gerrit.server.git.WorkQueue; import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.index.ChangeIndexer; import com.google.gerrit.server.git.validators.CommitValidationException;
import com.google.gerrit.server.git.validators.CommitValidators;
import com.google.gerrit.server.mail.CreateChangeSender; import com.google.gerrit.server.mail.CreateChangeSender;
import com.google.gerrit.server.notedb.ChangeUpdate; import com.google.gerrit.server.notedb.ChangeUpdate;
import com.google.gerrit.server.patch.PatchSetInfoFactory; import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.project.ChangeControl; import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.ProjectControl; import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.RefControl;
import com.google.gerrit.server.ssh.NoSshInfo;
import com.google.gerrit.server.util.RequestScopePropagator; import com.google.gerrit.server.util.RequestScopePropagator;
import com.google.gerrit.server.validators.ValidationException; import com.google.gerrit.server.validators.ValidationException;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.notes.NoteMap;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.ReceiveCommand;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -58,33 +70,34 @@ import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
public class ChangeInserter { public class ChangeInserter extends BatchUpdate.InsertChangeOp {
public static interface Factory { public static interface Factory {
ChangeInserter create(ProjectControl ctl, Change c, RevCommit rc); ChangeInserter create(RefControl ctl, Change c, RevCommit rc);
} }
private static final Logger log = private static final Logger log =
LoggerFactory.getLogger(ChangeInserter.class); LoggerFactory.getLogger(ChangeInserter.class);
private final Provider<ReviewDb> dbProvider;
private final ChangeUpdate.Factory updateFactory;
private final GitReferenceUpdated gitRefUpdated;
private final ChangeHooks hooks; private final ChangeHooks hooks;
private final ApprovalsUtil approvalsUtil; private final ApprovalsUtil approvalsUtil;
private final ChangeMessagesUtil cmUtil; private final ChangeMessagesUtil cmUtil;
private final ChangeIndexer indexer;
private final CreateChangeSender.Factory createChangeSenderFactory; private final CreateChangeSender.Factory createChangeSenderFactory;
private final HashtagsUtil hashtagsUtil; private final HashtagsUtil hashtagsUtil;
private final AccountCache accountCache; private final AccountCache accountCache;
private final WorkQueue workQueue; private final WorkQueue workQueue;
private final CommitValidators.Factory commitValidatorsFactory;
private final ProjectControl projectControl; private final RefControl refControl;
private final IdentifiedUser user;
private final Change change; private final Change change;
private final PatchSet patchSet; private final PatchSet patchSet;
private final RevCommit commit; private final RevCommit commit;
private final PatchSetInfo patchSetInfo; private final PatchSetInfo patchSetInfo;
private ChangeMessage changeMessage; // Fields exposed as setters.
private String message;
private CommitValidators.Policy validatePolicy =
CommitValidators.Policy.GERRIT;
private Set<Account.Id> reviewers; private Set<Account.Id> reviewers;
private Set<Account.Id> extraCC; private Set<Account.Id> extraCC;
private Map<String, Short> approvals; private Map<String, Short> approvals;
@@ -92,35 +105,41 @@ public class ChangeInserter {
private RequestScopePropagator requestScopePropagator; private RequestScopePropagator requestScopePropagator;
private boolean runHooks; private boolean runHooks;
private boolean sendMail; private boolean sendMail;
private boolean updateRef;
// Fields set during the insertion process.
private ChangeMessage changeMessage;
@Inject @Inject
ChangeInserter(Provider<ReviewDb> dbProvider, ChangeInserter(PatchSetInfoFactory patchSetInfoFactory,
ChangeUpdate.Factory updateFactory,
PatchSetInfoFactory patchSetInfoFactory,
GitReferenceUpdated gitRefUpdated,
ChangeHooks hooks, ChangeHooks hooks,
ApprovalsUtil approvalsUtil, ApprovalsUtil approvalsUtil,
ChangeMessagesUtil cmUtil, ChangeMessagesUtil cmUtil,
ChangeIndexer indexer,
CreateChangeSender.Factory createChangeSenderFactory, CreateChangeSender.Factory createChangeSenderFactory,
HashtagsUtil hashtagsUtil, HashtagsUtil hashtagsUtil,
AccountCache accountCache, AccountCache accountCache,
WorkQueue workQueue, WorkQueue workQueue,
@Assisted ProjectControl projectControl, CommitValidators.Factory commitValidatorsFactory,
@Assisted RefControl refControl,
@Assisted Change change, @Assisted Change change,
@Assisted RevCommit commit) { @Assisted RevCommit commit) {
this.dbProvider = dbProvider; String projectName = refControl.getProjectControl().getProject().getName();
this.updateFactory = updateFactory; String refName = refControl.getRefName();
this.gitRefUpdated = gitRefUpdated; checkArgument(projectName.equals(change.getProject().get())
&& refName.equals(change.getDest().get()),
"RefControl for %s,%s does not match change destination %s",
projectName, refName, change.getDest());
this.hooks = hooks; this.hooks = hooks;
this.approvalsUtil = approvalsUtil; this.approvalsUtil = approvalsUtil;
this.cmUtil = cmUtil; this.cmUtil = cmUtil;
this.indexer = indexer;
this.createChangeSenderFactory = createChangeSenderFactory; this.createChangeSenderFactory = createChangeSenderFactory;
this.hashtagsUtil = hashtagsUtil; this.hashtagsUtil = hashtagsUtil;
this.accountCache = accountCache; this.accountCache = accountCache;
this.workQueue = workQueue; this.workQueue = workQueue;
this.projectControl = projectControl; this.commitValidatorsFactory = commitValidatorsFactory;
this.refControl = refControl;
this.change = change; this.change = change;
this.commit = commit; this.commit = commit;
this.reviewers = Collections.emptySet(); this.reviewers = Collections.emptySet();
@@ -129,7 +148,9 @@ public class ChangeInserter {
this.hashtags = Collections.emptySet(); this.hashtags = Collections.emptySet();
this.runHooks = true; this.runHooks = true;
this.sendMail = true; this.sendMail = true;
this.updateRef = true;
user = checkUser(refControl);
patchSet = patchSet =
new PatchSet(new PatchSet.Id(change.getId(), INITIAL_PATCH_SET_ID)); new PatchSet(new PatchSet.Id(change.getId(), INITIAL_PATCH_SET_ID));
patchSet.setCreatedOn(change.getCreatedOn()); patchSet.setCreatedOn(change.getCreatedOn());
@@ -139,12 +160,28 @@ public class ChangeInserter {
change.setCurrentPatchSet(patchSetInfo); change.setCurrentPatchSet(patchSetInfo);
} }
private static IdentifiedUser checkUser(RefControl ctl) {
checkArgument(ctl.getCurrentUser().isIdentifiedUser(),
"only IdentifiedUser may create change");
return (IdentifiedUser) ctl.getCurrentUser();
}
@Override
public Change getChange() { public Change getChange() {
return change; return change;
} }
public ChangeInserter setMessage(ChangeMessage changeMessage) { public IdentifiedUser getUser() {
this.changeMessage = changeMessage; return user;
}
public ChangeInserter setMessage(String message) {
this.message = message;
return this;
}
public ChangeInserter setValidatePolicy(CommitValidators.Policy validate) {
this.validatePolicy = checkNotNull(validate);
return this; return this;
} }
@@ -198,55 +235,76 @@ public class ChangeInserter {
return this; return this;
} }
public ChangeInserter setUpdateRef(boolean updateRef) {
this.updateRef = updateRef;
return this;
}
public PatchSetInfo getPatchSetInfo() { public PatchSetInfo getPatchSetInfo() {
return patchSetInfo; return patchSetInfo;
} }
public Change insert() throws OrmException, IOException { public ChangeMessage getChangeMessage() {
ReviewDb db = dbProvider.get(); if (message == null) {
ChangeControl ctl = projectControl.controlFor(change); return null;
ChangeUpdate update = updateFactory.create( }
ctl, checkState(changeMessage != null,
change.getCreatedOn()); "getChangeMessage() only valid after inserting change");
return changeMessage;
}
@Override
public void updateRepo(RepoContext ctx)
throws InvalidChangeOperationException, IOException {
validate(ctx);
if (!updateRef) {
return;
}
ctx.addRefUpdate(
new ReceiveCommand(ObjectId.zeroId(), commit, patchSet.getRefName()));
}
@Override
public void updateChange(ChangeContext ctx) throws OrmException, IOException {
ReviewDb db = ctx.getDb();
ChangeControl ctl = ctx.getChangeControl();
ChangeUpdate update = ctx.getChangeUpdate();
db.changes().beginTransaction(change.getId()); db.changes().beginTransaction(change.getId());
try {
ChangeUtil.insertAncestors(db, patchSet.getId(), commit); ChangeUtil.insertAncestors(db, patchSet.getId(), commit);
if (patchSet.getGroups() == null) { if (patchSet.getGroups() == null) {
patchSet.setGroups(GroupCollector.getDefaultGroups(patchSet)); patchSet.setGroups(GroupCollector.getDefaultGroups(patchSet));
} }
db.patchSets().insert(Collections.singleton(patchSet)); db.patchSets().insert(Collections.singleton(patchSet));
db.changes().insert(Collections.singleton(change)); db.changes().insert(Collections.singleton(change));
LabelTypes labelTypes = projectControl.getLabelTypes(); LabelTypes labelTypes = ctl.getProjectControl().getLabelTypes();
approvalsUtil.addReviewers(db, update, labelTypes, change, approvalsUtil.addReviewers(db, update, labelTypes, change,
patchSet, patchSetInfo, reviewers, Collections.<Account.Id> emptySet()); patchSet, patchSetInfo, reviewers, Collections.<Account.Id> emptySet());
approvalsUtil.addApprovals(db, update, labelTypes, patchSet, patchSetInfo, approvalsUtil.addApprovals(db, update, labelTypes, patchSet, patchSetInfo,
ctl, approvals); ctx.getChangeControl(), approvals);
if (messageIsForChange()) { if (message != null) {
changeMessage =
new ChangeMessage(new ChangeMessage.Key(change.getId(),
ChangeUtil.messageUUID(db)), user.getAccountId(),
patchSet.getCreatedOn(), patchSet.getId());
changeMessage.setMessage(message);
cmUtil.addChangeMessage(db, update, changeMessage); cmUtil.addChangeMessage(db, update, changeMessage);
} }
db.commit();
} finally {
db.rollback();
}
update.commit();
if (hashtags != null && hashtags.size() > 0) { if (hashtags != null && hashtags.size() > 0) {
try { try {
HashtagsInput input = new HashtagsInput(); HashtagsInput input = new HashtagsInput();
input.add = hashtags; input.add = hashtags;
// TODO(dborowitz): Migrate HashtagsUtil so it doesn't create another
// ChangeUpdate.
hashtagsUtil.setHashtags(ctl, input, false, false); hashtagsUtil.setHashtags(ctl, input, false, false);
} catch (ValidationException | AuthException e) { } catch (ValidationException | AuthException e) {
log.error("Cannot add hashtags to change " + change.getId(), e); log.error("Cannot add hashtags to change " + change.getId(), e);
} }
} }
CheckedFuture<?, IOException> f = indexer.indexAsync(change.getId());
if (!messageIsForChange()) {
commitMessageNotForChange();
} }
f.checkedGet();
@Override
public void postUpdate(Context ctx) throws OrmException {
if (sendMail) { if (sendMail) {
Runnable sender = new Runnable() { Runnable sender = new Runnable() {
@Override @Override
@@ -276,10 +334,8 @@ public class ChangeInserter {
} }
} }
gitRefUpdated.fire(change.getProject(), patchSet.getRefName(),
ObjectId.zeroId(), commit);
if (runHooks) { if (runHooks) {
ReviewDb db = ctx.getDb();
hooks.doPatchsetCreatedHook(change, patchSet, db); hooks.doPatchsetCreatedHook(change, patchSet, db);
if (hashtags != null && hashtags.size() > 0) { if (hashtags != null && hashtags.size() > 0) {
hooks.doHashtagsChangedHook(change, hooks.doHashtagsChangedHook(change,
@@ -287,32 +343,42 @@ public class ChangeInserter {
hashtags, null, hashtags, db); hashtags, null, hashtags, db);
} }
} }
return change;
} }
private void commitMessageNotForChange() throws OrmException, private void validate(RepoContext ctx)
IOException { throws IOException, InvalidChangeOperationException {
ReviewDb db = dbProvider.get(); if (validatePolicy == CommitValidators.Policy.NONE) {
if (changeMessage != null) { return;
Change otherChange =
db.changes().get(changeMessage.getPatchSetId().getParentKey());
ChangeUtil.bumpRowVersionNotLastUpdatedOn(
changeMessage.getKey().getParentKey(), db);
ChangeControl otherControl = projectControl.controlFor(otherChange);
ChangeUpdate updateForOtherChange =
updateFactory.create(otherControl, change.getLastUpdatedOn());
cmUtil.addChangeMessage(db, updateForOtherChange, changeMessage);
updateForOtherChange.commit();
}
} }
CommitValidators cv = commitValidatorsFactory.create(
refControl, new NoSshInfo(), ctx.getRepository());
private boolean messageIsForChange() { String refName = patchSet.getId().toRefName();
if (changeMessage == null) { CommitReceivedEvent event = new CommitReceivedEvent(
return false; new ReceiveCommand(
ObjectId.zeroId(),
commit.getId(),
refName),
refControl.getProjectControl().getProject(),
change.getDest().get(),
commit,
user);
try {
switch (validatePolicy) {
case RECEIVE_COMMITS:
NoteMap rejectCommits = BanCommit.loadRejectCommitsMap(
ctx.getRepository(), ctx.getRevWalk());
cv.validateForReceiveCommits(event, rejectCommits);
break;
case GERRIT:
cv.validateForGerritCommits(event);
break;
case NONE:
break;
}
} catch (CommitValidationException e) {
throw new InvalidChangeOperationException(e.getMessage());
} }
Change.Id id = change.getId();
Change.Id msgId = changeMessage.getKey().getParentKey();
return msgId.equals(id);
} }
} }

View File

@@ -30,7 +30,6 @@ import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.GerritPersonIdent; import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.events.CommitReceivedEvent;
import com.google.gerrit.server.git.BatchUpdate; import com.google.gerrit.server.git.BatchUpdate;
import com.google.gerrit.server.git.CodeReviewCommit; import com.google.gerrit.server.git.CodeReviewCommit;
import com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk; import com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk;
@@ -40,7 +39,6 @@ import com.google.gerrit.server.git.MergeException;
import com.google.gerrit.server.git.MergeIdenticalTreeException; import com.google.gerrit.server.git.MergeIdenticalTreeException;
import com.google.gerrit.server.git.MergeUtil; import com.google.gerrit.server.git.MergeUtil;
import com.google.gerrit.server.git.UpdateException; import com.google.gerrit.server.git.UpdateException;
import com.google.gerrit.server.git.validators.CommitValidationException;
import com.google.gerrit.server.git.validators.CommitValidators; import com.google.gerrit.server.git.validators.CommitValidators;
import com.google.gerrit.server.notedb.ChangeUpdate; import com.google.gerrit.server.notedb.ChangeUpdate;
import com.google.gerrit.server.project.ChangeControl; import com.google.gerrit.server.project.ChangeControl;
@@ -50,7 +48,6 @@ import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.project.RefControl; import com.google.gerrit.server.project.RefControl;
import com.google.gerrit.server.query.change.ChangeData; import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.InternalChangeQuery; import com.google.gerrit.server.query.change.InternalChangeQuery;
import com.google.gerrit.server.ssh.NoSshInfo;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
@@ -63,10 +60,8 @@ import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.ReceiveCommand;
import org.eclipse.jgit.util.ChangeIdUtil; import org.eclipse.jgit.util.ChangeIdUtil;
import java.io.IOException; import java.io.IOException;
@@ -81,7 +76,6 @@ public class CherryPickChange {
private final GitRepositoryManager gitManager; private final GitRepositoryManager gitManager;
private final TimeZone serverTimeZone; private final TimeZone serverTimeZone;
private final Provider<CurrentUser> currentUser; private final Provider<CurrentUser> currentUser;
private final CommitValidators.Factory commitValidatorsFactory;
private final ChangeInserter.Factory changeInserterFactory; private final ChangeInserter.Factory changeInserterFactory;
private final PatchSetInserter.Factory patchSetInserterFactory; private final PatchSetInserter.Factory patchSetInserterFactory;
private final MergeUtil.Factory mergeUtilFactory; private final MergeUtil.Factory mergeUtilFactory;
@@ -95,7 +89,6 @@ public class CherryPickChange {
@GerritPersonIdent PersonIdent myIdent, @GerritPersonIdent PersonIdent myIdent,
GitRepositoryManager gitManager, GitRepositoryManager gitManager,
Provider<CurrentUser> currentUser, Provider<CurrentUser> currentUser,
CommitValidators.Factory commitValidatorsFactory,
ChangeInserter.Factory changeInserterFactory, ChangeInserter.Factory changeInserterFactory,
PatchSetInserter.Factory patchSetInserterFactory, PatchSetInserter.Factory patchSetInserterFactory,
MergeUtil.Factory mergeUtilFactory, MergeUtil.Factory mergeUtilFactory,
@@ -107,7 +100,6 @@ public class CherryPickChange {
this.gitManager = gitManager; this.gitManager = gitManager;
this.serverTimeZone = myIdent.getTimeZone(); this.serverTimeZone = myIdent.getTimeZone();
this.currentUser = currentUser; this.currentUser = currentUser;
this.commitValidatorsFactory = commitValidatorsFactory;
this.changeInserterFactory = changeInserterFactory; this.changeInserterFactory = changeInserterFactory;
this.patchSetInserterFactory = patchSetInserterFactory; this.patchSetInserterFactory = patchSetInserterFactory;
this.mergeUtilFactory = mergeUtilFactory; this.mergeUtilFactory = mergeUtilFactory;
@@ -162,9 +154,6 @@ public class CherryPickChange {
cherryPickCommit = cherryPickCommit =
mergeUtilFactory.create(projectState).createCherryPickFromCommit(git, oi, mergeTip, mergeUtilFactory.create(projectState).createCherryPickFromCommit(git, oi, mergeTip,
commitToCherryPick, committerIdent, commitMessage, revWalk); commitToCherryPick, committerIdent, commitMessage, revWalk);
} catch (MergeIdenticalTreeException | MergeConflictException e) {
throw new MergeException("Cherry pick failed: " + e.getMessage());
}
Change.Key changeKey; Change.Key changeKey;
final List<String> idList = cherryPickCommit.getFooterLines( final List<String> idList = cherryPickCommit.getFooterLines(
@@ -197,18 +186,18 @@ public class CherryPickChange {
if (!Strings.isNullOrEmpty(change.getTopic())) { if (!Strings.isNullOrEmpty(change.getTopic())) {
newTopic = change.getTopic() + "-" + newDest.getShortName(); newTopic = change.getTopic() + "-" + newDest.getShortName();
} }
Change newChange = createNewChange(git, revWalk, changeKey, project, Change newChange = createNewChange(git, revWalk, oi, changeKey,
destRef, cherryPickCommit, refControl, project, destRef, cherryPickCommit, refControl, identifiedUser,
identifiedUser, newTopic); newTopic, change.getDest());
addMessageToSourceChange(change, patch.getId(), destinationBranch, addMessageToSourceChange(change, patch.getId(), destinationBranch,
cherryPickCommit, identifiedUser, refControl); cherryPickCommit, identifiedUser, refControl);
addMessageToDestinationChange(newChange, change.getDest().getShortName(),
identifiedUser, refControl);
return newChange.getId(); return newChange.getId();
} }
} catch (MergeIdenticalTreeException | MergeConflictException e) {
throw new MergeException("Cherry pick failed: " + e.getMessage());
}
} catch (RepositoryNotFoundException e) { } catch (RepositoryNotFoundException e) {
throw new NoSuchChangeException(change.getId(), e); throw new NoSuchChangeException(change.getId(), e);
} }
@@ -226,8 +215,9 @@ public class CherryPickChange {
PatchSet current = db.get().patchSets().get(change.currentPatchSetId()); PatchSet current = db.get().patchSets().get(change.currentPatchSetId());
try (BatchUpdate bu = batchUpdateFactory.create( try (BatchUpdate bu = batchUpdateFactory.create(
db.get(), change.getDest().getParentKey(), TimeUtil.nowTs())) { db.get(), change.getDest().getParentKey(), identifiedUser,
bu.addOp(changeControl, inserter TimeUtil.nowTs())) {
bu.addOp(change.getId(), inserter
.setMessage("Uploaded patch set " + newPatchSetId.get() + ".") .setMessage("Uploaded patch set " + newPatchSetId.get() + ".")
.setDraft(current.isDraft()) .setDraft(current.isDraft())
.setUploader(identifiedUser.getAccountId()) .setUploader(identifiedUser.getAccountId())
@@ -238,47 +228,28 @@ public class CherryPickChange {
} }
private Change createNewChange(Repository git, RevWalk revWalk, private Change createNewChange(Repository git, RevWalk revWalk,
Change.Key changeKey, Project.NameKey project, ObjectInserter oi, Change.Key changeKey, Project.NameKey project,
Ref destRef, CodeReviewCommit cherryPickCommit, RefControl refControl, Ref destRef, CodeReviewCommit cherryPickCommit, RefControl refControl,
IdentifiedUser identifiedUser, String topic) IdentifiedUser identifiedUser, String topic, Branch.NameKey sourceBranch)
throws OrmException, InvalidChangeOperationException, IOException { throws RestApiException, UpdateException, OrmException {
Change change = Change change =
new Change(changeKey, new Change.Id(db.get().nextChangeId()), new Change(changeKey, new Change.Id(db.get().nextChangeId()),
identifiedUser.getAccountId(), new Branch.NameKey(project, identifiedUser.getAccountId(), new Branch.NameKey(project,
destRef.getName()), TimeUtil.nowTs()); destRef.getName()), TimeUtil.nowTs());
change.setTopic(topic); change.setTopic(topic);
ChangeInserter ins = ChangeInserter ins = changeInserterFactory.create(
changeInserterFactory.create(refControl.getProjectControl(), change, refControl, change, cherryPickCommit)
cherryPickCommit); .setValidatePolicy(CommitValidators.Policy.GERRIT);
PatchSet newPatchSet = ins.getPatchSet();
CommitValidators commitValidators = ins.setMessage(
commitValidatorsFactory.create(refControl, new NoSshInfo(), git); messageForDestinationChange(ins.getPatchSet().getId(), sourceBranch));
CommitReceivedEvent commitReceivedEvent = try (BatchUpdate bu = batchUpdateFactory.create(
new CommitReceivedEvent(new ReceiveCommand(ObjectId.zeroId(), db.get(), change.getProject(), identifiedUser, TimeUtil.nowTs())) {
cherryPickCommit.getId(), newPatchSet.getRefName()), refControl bu.setRepository(git, revWalk, oi);
.getProjectControl().getProject(), refControl.getRefName(), bu.insertChange(ins);
cherryPickCommit, identifiedUser); bu.execute();
try {
commitValidators.validateForGerritCommits(commitReceivedEvent);
} catch (CommitValidationException e) {
throw new InvalidChangeOperationException(e.getMessage());
} }
return ins.getChange();
final RefUpdate ru = git.updateRef(newPatchSet.getRefName());
ru.setExpectedOldObjectId(ObjectId.zeroId());
ru.setNewObjectId(cherryPickCommit);
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()));
}
ins.insert();
return change;
} }
private void addMessageToSourceChange(Change change, PatchSet.Id patchSetId, private void addMessageToSourceChange(Change change, PatchSet.Id patchSetId,
@@ -303,24 +274,13 @@ public class CherryPickChange {
changeMessagesUtil.addChangeMessage(db.get(), update, changeMessage); changeMessagesUtil.addChangeMessage(db.get(), update, changeMessage);
} }
private void addMessageToDestinationChange(Change change, String sourceBranch, private String messageForDestinationChange(PatchSet.Id patchSetId,
IdentifiedUser identifiedUser, RefControl refControl) throws OrmException { Branch.NameKey sourceBranch) {
PatchSet.Id patchSetId = return new StringBuilder("Patch Set ")
db.get().patchSets().get(change.currentPatchSetId()).getId();
ChangeMessage changeMessage = new ChangeMessage(
new ChangeMessage.Key(
patchSetId.getParentKey(), ChangeUtil.messageUUID(db.get())),
identifiedUser.getAccountId(), TimeUtil.nowTs(), patchSetId);
StringBuilder sb = new StringBuilder("Patch Set ")
.append(patchSetId.get()) .append(patchSetId.get())
.append(": Cherry Picked from branch ") .append(": Cherry Picked from branch ")
.append(sourceBranch) .append(sourceBranch.getShortName())
.append("."); .append(".")
changeMessage.setMessage(sb.toString()); .toString();
ChangeControl ctl = refControl.getProjectControl().controlFor(change);
ChangeUpdate update = updateFactory.create(ctl, change.getCreatedOn());
changeMessagesUtil.addChangeMessage(db.get(), update, changeMessage);
} }
} }

View File

@@ -42,10 +42,10 @@ import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.GerritPersonIdent; import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.change.PatchSetInserter.ValidatePolicy;
import com.google.gerrit.server.git.BatchUpdate; import com.google.gerrit.server.git.BatchUpdate;
import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.UpdateException; import com.google.gerrit.server.git.UpdateException;
import com.google.gerrit.server.git.validators.CommitValidators;
import com.google.gerrit.server.patch.PatchSetInfoFactory; import com.google.gerrit.server.patch.PatchSetInfoFactory;
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.ChangeControl;
@@ -466,8 +466,10 @@ public class ConsistencyChecker {
PatchSetInserter inserter = PatchSetInserter inserter =
patchSetInserterFactory.create(repo, rw, ctl, commit); patchSetInserterFactory.create(repo, rw, ctl, commit);
try (BatchUpdate bu = updateFactory.create( try (BatchUpdate bu = updateFactory.create(
db.get(), change.getDest().getParentKey(), TimeUtil.nowTs())) { db.get(), change.getDest().getParentKey(), user.get(),
bu.addOp(ctl, inserter.setValidatePolicy(ValidatePolicy.NONE) TimeUtil.nowTs())) {
bu.addOp(change.getId(), inserter
.setValidatePolicy(CommitValidators.Policy.NONE)
.setRunHooks(false) .setRunHooks(false)
.setSendMail(false) .setSendMail(false)
.setAllowClosed(true) .setAllowClosed(true)

View File

@@ -24,15 +24,13 @@ import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException; import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException; import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.Response; import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.extensions.restapi.TopLevelResource; import com.google.gerrit.extensions.restapi.TopLevelResource;
import com.google.gerrit.extensions.restapi.UnprocessableEntityException; import com.google.gerrit.extensions.restapi.UnprocessableEntityException;
import com.google.gerrit.reviewdb.client.Branch; import com.google.gerrit.reviewdb.client.Branch;
import com.google.gerrit.reviewdb.client.Change; 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.PatchSet;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames; import com.google.gerrit.reviewdb.client.RefNames;
@@ -42,15 +40,14 @@ import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.GerritPersonIdent; import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.events.CommitReceivedEvent; import com.google.gerrit.server.git.BatchUpdate;
import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.validators.CommitValidationException; import com.google.gerrit.server.git.UpdateException;
import com.google.gerrit.server.git.validators.CommitValidators; import com.google.gerrit.server.git.validators.CommitValidators;
import com.google.gerrit.server.project.InvalidChangeOperationException; import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.ProjectResource; import com.google.gerrit.server.project.ProjectResource;
import com.google.gerrit.server.project.ProjectsCollection; import com.google.gerrit.server.project.ProjectsCollection;
import com.google.gerrit.server.project.RefControl; import com.google.gerrit.server.project.RefControl;
import com.google.gerrit.server.ssh.NoSshInfo;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
@@ -62,11 +59,9 @@ import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.transport.ReceiveCommand;
import org.eclipse.jgit.util.ChangeIdUtil; import org.eclipse.jgit.util.ChangeIdUtil;
import java.io.IOException; import java.io.IOException;
@@ -84,10 +79,10 @@ public class CreateChange implements
private final TimeZone serverTimeZone; private final TimeZone serverTimeZone;
private final Provider<CurrentUser> userProvider; private final Provider<CurrentUser> userProvider;
private final ProjectsCollection projectsCollection; private final ProjectsCollection projectsCollection;
private final CommitValidators.Factory commitValidatorsFactory;
private final ChangeInserter.Factory changeInserterFactory; private final ChangeInserter.Factory changeInserterFactory;
private final ChangeJson.Factory jsonFactory; private final ChangeJson.Factory jsonFactory;
private final ChangeUtil changeUtil; private final ChangeUtil changeUtil;
private final BatchUpdate.Factory updateFactory;
private final boolean allowDrafts; private final boolean allowDrafts;
@Inject @Inject
@@ -96,29 +91,28 @@ public class CreateChange implements
@GerritPersonIdent PersonIdent myIdent, @GerritPersonIdent PersonIdent myIdent,
Provider<CurrentUser> userProvider, Provider<CurrentUser> userProvider,
ProjectsCollection projectsCollection, ProjectsCollection projectsCollection,
CommitValidators.Factory commitValidatorsFactory,
ChangeInserter.Factory changeInserterFactory, ChangeInserter.Factory changeInserterFactory,
ChangeJson.Factory json, ChangeJson.Factory json,
ChangeUtil changeUtil, ChangeUtil changeUtil,
BatchUpdate.Factory updateFactory,
@GerritServerConfig Config config) { @GerritServerConfig Config config) {
this.db = db; this.db = db;
this.gitManager = gitManager; this.gitManager = gitManager;
this.serverTimeZone = myIdent.getTimeZone(); this.serverTimeZone = myIdent.getTimeZone();
this.userProvider = userProvider; this.userProvider = userProvider;
this.projectsCollection = projectsCollection; this.projectsCollection = projectsCollection;
this.commitValidatorsFactory = commitValidatorsFactory;
this.changeInserterFactory = changeInserterFactory; this.changeInserterFactory = changeInserterFactory;
this.jsonFactory = json; this.jsonFactory = json;
this.changeUtil = changeUtil; this.changeUtil = changeUtil;
this.updateFactory = updateFactory;
this.allowDrafts = config.getBoolean("change", "allowDrafts", true); this.allowDrafts = config.getBoolean("change", "allowDrafts", true);
} }
@Override @Override
public Response<ChangeInfo> apply(TopLevelResource parent, public Response<ChangeInfo> apply(TopLevelResource parent,
ChangeInfo input) throws AuthException, OrmException, ChangeInfo input)
BadRequestException, UnprocessableEntityException, IOException, throws AuthException, OrmException, IOException,
InvalidChangeOperationException, ResourceNotFoundException, InvalidChangeOperationException, RestApiException, UpdateException {
MethodNotAllowedException, ResourceConflictException {
if (Strings.isNullOrEmpty(input.project)) { if (Strings.isNullOrEmpty(input.project)) {
throw new BadRequestException("project must be non-empty"); throw new BadRequestException("project must be non-empty");
} }
@@ -195,7 +189,8 @@ public class CreateChange implements
mergeTip, author, author, input.subject); mergeTip, author, author, input.subject);
String commitMessage = ChangeIdUtil.insertId(input.subject, id); String commitMessage = ChangeIdUtil.insertId(input.subject, id);
RevCommit c = newCommit(git, rw, author, mergeTip, commitMessage); try (ObjectInserter oi = git.newObjectInserter()) {
RevCommit c = newCommit(oi, rw, author, mergeTip, commitMessage);
Change change = new Change( Change change = new Change(
getChangeId(id, c), getChangeId(id, c),
@@ -204,22 +199,11 @@ public class CreateChange implements
new Branch.NameKey(project, refName), new Branch.NameKey(project, refName),
now); now);
ChangeInserter ins = ChangeInserter ins = changeInserterFactory
changeInserterFactory.create(refControl.getProjectControl(), .create(refControl, change, c)
change, c); .setValidatePolicy(CommitValidators.Policy.GERRIT);
ins.setMessage(String.format("Uploaded patch set %s.",
ChangeMessage msg = new ChangeMessage(new ChangeMessage.Key(change.getId(),
ChangeUtil.messageUUID(db.get())),
me.getAccountId(),
ins.getPatchSet().getCreatedOn(),
ins.getPatchSet().getId());
msg.setMessage(String.format("Uploaded patch set %s.",
ins.getPatchSet().getPatchSetId())); ins.getPatchSet().getPatchSetId()));
ins.setMessage(msg);
validateCommit(git, refControl, c, me, ins);
updateRef(git, rw, c, change, ins.getPatchSet());
String topic = input.topic; String topic = input.topic;
if (topic != null) { if (topic != null) {
topic = Strings.emptyToNull(topic.trim()); topic = Strings.emptyToNull(topic.trim());
@@ -227,46 +211,16 @@ public class CreateChange implements
change.setTopic(topic); change.setTopic(topic);
ins.setDraft(input.status != null && input.status == ChangeStatus.DRAFT); ins.setDraft(input.status != null && input.status == ChangeStatus.DRAFT);
ins.setGroups(groups); ins.setGroups(groups);
ins.insert(); try (BatchUpdate bu = updateFactory.create(
db.get(), change.getProject(), me, now)) {
bu.setRepository(git, rw, oi);
bu.insertChange(ins);
bu.execute();
}
ChangeJson json = jsonFactory.create(ChangeJson.NO_OPTIONS); ChangeJson json = jsonFactory.create(ChangeJson.NO_OPTIONS);
return Response.created(json.format(change.getId())); return Response.created(json.format(change.getId()));
} }
}
private void validateCommit(Repository git, RefControl refControl,
RevCommit c, IdentifiedUser me, ChangeInserter ins)
throws ResourceConflictException {
PatchSet newPatchSet = ins.getPatchSet();
CommitValidators commitValidators =
commitValidatorsFactory.create(refControl, new NoSshInfo(), git);
CommitReceivedEvent commitReceivedEvent =
new CommitReceivedEvent(new ReceiveCommand(
ObjectId.zeroId(),
c.getId(),
newPatchSet.getRefName()),
refControl.getProjectControl().getProject(),
refControl.getRefName(),
c,
me);
try {
commitValidators.validateForGerritCommits(commitReceivedEvent);
} catch (CommitValidationException e) {
throw new ResourceConflictException(e.getMessage());
}
}
private static void updateRef(Repository git, RevWalk rw, RevCommit c,
Change change, PatchSet newPatchSet) throws IOException {
RefUpdate ru = git.updateRef(newPatchSet.getRefName());
ru.setExpectedOldObjectId(ObjectId.zeroId());
ru.setNewObjectId(c);
ru.disableRefLog();
if (ru.update(rw) != RefUpdate.Result.NEW) {
throw new IOException(String.format(
"Failed to create ref %s in %s: %s", newPatchSet.getRefName(),
change.getDest().getParentKey().get(), ru.getResult()));
} }
} }
@@ -279,20 +233,16 @@ public class CreateChange implements
return changeKey; return changeKey;
} }
private static RevCommit newCommit(Repository git, RevWalk rw, private static RevCommit newCommit(ObjectInserter oi, RevWalk rw,
PersonIdent authorIdent, RevCommit mergeTip, String commitMessage) PersonIdent authorIdent, RevCommit mergeTip, String commitMessage)
throws IOException { throws IOException {
RevCommit emptyCommit;
try (ObjectInserter oi = git.newObjectInserter()) {
CommitBuilder commit = new CommitBuilder(); CommitBuilder commit = new CommitBuilder();
commit.setTreeId(mergeTip.getTree().getId()); commit.setTreeId(mergeTip.getTree().getId());
commit.setParentId(mergeTip); commit.setParentId(mergeTip);
commit.setAuthor(authorIdent); commit.setAuthor(authorIdent);
commit.setCommitter(authorIdent); commit.setCommitter(authorIdent);
commit.setMessage(commitMessage); commit.setMessage(commitMessage);
emptyCommit = rw.parseCommit(insert(oi, commit)); return rw.parseCommit(insert(oi, commit));
}
return emptyCommit;
} }
private static ObjectId insert(ObjectInserter inserter, private static ObjectId insert(ObjectInserter inserter,

View File

@@ -76,15 +76,6 @@ public class PatchSetInserter extends BatchUpdate.Op {
RevCommit commit); RevCommit commit);
} }
/**
* Whether to use {@link CommitValidators#validateForGerritCommits},
* {@link CommitValidators#validateForReceiveCommits}, or no commit
* validation.
*/
public static enum ValidatePolicy {
GERRIT, RECEIVE_COMMITS, NONE
}
// Injected fields. // Injected fields.
private final ChangeHooks hooks; private final ChangeHooks hooks;
private final PatchSetInfoFactory patchSetInfoFactory; private final PatchSetInfoFactory patchSetInfoFactory;
@@ -108,7 +99,8 @@ public class PatchSetInserter extends BatchUpdate.Op {
// Fields exposed as setters. // Fields exposed as setters.
private SshInfo sshInfo; private SshInfo sshInfo;
private String message; private String message;
private ValidatePolicy validatePolicy = ValidatePolicy.GERRIT; private CommitValidators.Policy validatePolicy =
CommitValidators.Policy.GERRIT;
private boolean draft; private boolean draft;
private Iterable<String> groups; private Iterable<String> groups;
private boolean runHooks = true; private boolean runHooks = true;
@@ -176,7 +168,7 @@ public class PatchSetInserter extends BatchUpdate.Op {
return this; return this;
} }
public PatchSetInserter setValidatePolicy(ValidatePolicy validate) { public PatchSetInserter setValidatePolicy(CommitValidators.Policy validate) {
this.validatePolicy = checkNotNull(validate); this.validatePolicy = checkNotNull(validate);
return this; return this;
} }
@@ -228,7 +220,7 @@ public class PatchSetInserter extends BatchUpdate.Op {
@Override @Override
public void updateChange(ChangeContext ctx) throws OrmException, public void updateChange(ChangeContext ctx) throws OrmException,
InvalidChangeOperationException { InvalidChangeOperationException {
change = ctx.readChange(); change = ctx.getChange();
Change.Id id = change.getId(); Change.Id id = change.getId();
final PatchSet.Id currentPatchSetId = change.currentPatchSetId(); final PatchSet.Id currentPatchSetId = change.currentPatchSetId();
if (!change.getStatus().isOpen() && !allowClosed) { if (!change.getStatus().isOpen() && !allowClosed) {

View File

@@ -78,8 +78,8 @@ public class PutTopic implements RestModifyView<ChangeResource, Input>,
Op op = new Op(ctl, input != null ? input : new Input()); Op op = new Op(ctl, input != null ? input : new Input());
try (BatchUpdate u = batchUpdateFactory.create(dbProvider.get(), try (BatchUpdate u = batchUpdateFactory.create(dbProvider.get(),
req.getChange().getProject(), TimeUtil.nowTs())) { req.getChange().getProject(), ctl.getCurrentUser(), TimeUtil.nowTs())) {
u.addOp(ctl, op); u.addOp(req.getChange().getId(), op);
u.execute(); u.execute();
} }
return Strings.isNullOrEmpty(op.newTopicName) return Strings.isNullOrEmpty(op.newTopicName)
@@ -102,7 +102,7 @@ public class PutTopic implements RestModifyView<ChangeResource, Input>,
@Override @Override
public void updateChange(ChangeContext ctx) throws OrmException { public void updateChange(ChangeContext ctx) throws OrmException {
change = ctx.readChange(); change = ctx.getChange();
String newTopicName = Strings.nullToEmpty(input.topic); String newTopicName = Strings.nullToEmpty(input.topic);
String oldTopicName = Strings.nullToEmpty(change.getTopic()); String oldTopicName = Strings.nullToEmpty(change.getTopic());
if (oldTopicName.equals(newTopicName)) { if (oldTopicName.equals(newTopicName)) {

View File

@@ -26,12 +26,12 @@ import com.google.gerrit.reviewdb.client.RevId;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.GerritPersonIdent; import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.change.PatchSetInserter.ValidatePolicy;
import com.google.gerrit.server.git.BatchUpdate; import com.google.gerrit.server.git.BatchUpdate;
import com.google.gerrit.server.git.GitRepositoryManager; import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.MergeConflictException; import com.google.gerrit.server.git.MergeConflictException;
import com.google.gerrit.server.git.MergeUtil; import com.google.gerrit.server.git.MergeUtil;
import com.google.gerrit.server.git.UpdateException; import com.google.gerrit.server.git.UpdateException;
import com.google.gerrit.server.git.validators.CommitValidators;
import com.google.gerrit.server.project.ChangeControl; import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.InvalidChangeOperationException; import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.NoSuchChangeException; import com.google.gerrit.server.project.NoSuchChangeException;
@@ -141,7 +141,7 @@ public class RebaseChange {
rebase(git, rw, inserter, change, patchSet.getId(), rebase(git, rw, inserter, change, patchSet.getId(),
uploader, baseCommit, mergeUtilFactory.create( uploader, baseCommit, mergeUtilFactory.create(
rsrc.getControl().getProjectControl().getProjectState(), true), rsrc.getControl().getProjectControl().getProjectState(), true),
committerIdent, true, ValidatePolicy.GERRIT); committerIdent, true, CommitValidators.Policy.GERRIT);
} catch (MergeConflictException e) { } catch (MergeConflictException e) {
throw new ResourceConflictException(e.getMessage()); throw new ResourceConflictException(e.getMessage());
} }
@@ -259,7 +259,8 @@ public class RebaseChange {
public PatchSet rebase(Repository git, RevWalk rw, public PatchSet rebase(Repository git, RevWalk rw,
ObjectInserter inserter, Change change, PatchSet.Id patchSetId, ObjectInserter inserter, Change change, PatchSet.Id patchSetId,
IdentifiedUser uploader, RevCommit baseCommit, MergeUtil mergeUtil, IdentifiedUser uploader, RevCommit baseCommit, MergeUtil mergeUtil,
PersonIdent committerIdent, boolean runHooks, ValidatePolicy validate) PersonIdent committerIdent, boolean runHooks,
CommitValidators.Policy validate)
throws NoSuchChangeException, OrmException, IOException, throws NoSuchChangeException, OrmException, IOException,
InvalidChangeOperationException, MergeConflictException, UpdateException, InvalidChangeOperationException, MergeConflictException, UpdateException,
RestApiException { RestApiException {
@@ -287,8 +288,8 @@ public class RebaseChange {
.setRunHooks(runHooks); .setRunHooks(runHooks);
try (BatchUpdate bu = updateFactory.create( try (BatchUpdate bu = updateFactory.create(
db.get(), change.getDest().getParentKey(), TimeUtil.nowTs())) { db.get(), change.getProject(), uploader, TimeUtil.nowTs())) {
bu.addOp(changeControl, patchSetInserter.setMessage( bu.addOp(change.getId(), patchSetInserter.setMessage(
"Patch Set " + patchSetInserter.getPatchSetId().get() "Patch Set " + patchSetInserter.getPatchSetId().get()
+ ": Patch Set " + patchSetId.get() + " was rebased")); + ": Patch Set " + patchSetId.get() + " was rebased"));
bu.execute(); bu.execute();

View File

@@ -88,8 +88,8 @@ public class Restore implements RestModifyView<ChangeResource, RestoreInput>,
Op op = new Op(input); Op op = new Op(input);
try (BatchUpdate u = batchUpdateFactory.create(dbProvider.get(), try (BatchUpdate u = batchUpdateFactory.create(dbProvider.get(),
req.getChange().getProject(), TimeUtil.nowTs())) { req.getChange().getProject(), ctl.getCurrentUser(), TimeUtil.nowTs())) {
u.addOp(ctl, op).execute(); u.addOp(req.getChange().getId(), op).execute();
} }
return json.create(ChangeJson.NO_OPTIONS).format(op.change); return json.create(ChangeJson.NO_OPTIONS).format(op.change);
} }
@@ -110,7 +110,7 @@ public class Restore implements RestModifyView<ChangeResource, RestoreInput>,
public void updateChange(ChangeContext ctx) throws OrmException, public void updateChange(ChangeContext ctx) throws OrmException,
ResourceConflictException { ResourceConflictException {
caller = (IdentifiedUser) ctx.getUser(); caller = (IdentifiedUser) ctx.getUser();
change = ctx.readChange(); change = ctx.getChange();
if (change == null || change.getStatus() != Status.ABANDONED) { if (change == null || change.getStatus() != Status.ABANDONED) {
throw new ResourceConflictException("change is " + status(change)); throw new ResourceConflictException("change is " + status(change));
} }

View File

@@ -20,19 +20,18 @@ import com.google.gerrit.common.errors.EmailException;
import com.google.gerrit.extensions.api.changes.RevertInput; import com.google.gerrit.extensions.api.changes.RevertInput;
import com.google.gerrit.extensions.common.ChangeInfo; import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.extensions.webui.UiAction; import com.google.gerrit.extensions.webui.UiAction;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Change.Status; import com.google.gerrit.reviewdb.client.Change.Status;
import com.google.gerrit.server.ChangeUtil; import com.google.gerrit.server.ChangeUtil;
import com.google.gerrit.server.GerritPersonIdent; import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.git.UpdateException;
import com.google.gerrit.server.project.ChangeControl; 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.gerrit.server.ssh.NoSshInfo;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Singleton; import com.google.inject.Singleton;
@@ -59,8 +58,8 @@ public class Revert implements RestModifyView<ChangeResource, RevertInput>,
@Override @Override
public ChangeInfo apply(ChangeResource req, RevertInput input) public ChangeInfo apply(ChangeResource req, RevertInput input)
throws AuthException, BadRequestException, ResourceConflictException, throws IOException, OrmException, EmailException, RestApiException,
ResourceNotFoundException, IOException, OrmException, EmailException { UpdateException {
ChangeControl control = req.getControl(); ChangeControl control = req.getControl();
Change change = req.getChange(); Change change = req.getChange();
if (!control.canAddPatchSet()) { if (!control.canAddPatchSet()) {
@@ -74,10 +73,7 @@ public class Revert implements RestModifyView<ChangeResource, RevertInput>,
revertedChangeId = changeUtil.revert(control, revertedChangeId = changeUtil.revert(control,
change.currentPatchSetId(), change.currentPatchSetId(),
Strings.emptyToNull(input.message), Strings.emptyToNull(input.message),
new PersonIdent(myIdent, TimeUtil.nowTs()), new PersonIdent(myIdent, TimeUtil.nowTs()));
new NoSshInfo());
} catch (InvalidChangeOperationException e) {
throw new BadRequestException(e.getMessage());
} catch (NoSuchChangeException e) { } catch (NoSuchChangeException e) {
throw new ResourceNotFoundException(e.getMessage()); throw new ResourceNotFoundException(e.getMessage());
} }

View File

@@ -239,8 +239,9 @@ public class ChangeEditUtil {
} }
try (BatchUpdate bu = updateFactory.create( try (BatchUpdate bu = updateFactory.create(
db.get(), change.getDest().getParentKey(), TimeUtil.nowTs())) { db.get(), change.getProject(), ctl.getCurrentUser(),
bu.addOp(ctl, inserter TimeUtil.nowTs())) {
bu.addOp(change.getId(), inserter
.setDraft(change.getStatus() == Status.DRAFT || .setDraft(change.getStatus() == Status.DRAFT ||
basePatchSet.isDraft()) basePatchSet.isDraft())
.setMessage(message.toString())); .setMessage(message.toString()));

View File

@@ -31,7 +31,6 @@ import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.index.ChangeIndexer; import com.google.gerrit.server.index.ChangeIndexer;
import com.google.gerrit.server.notedb.ChangeUpdate; import com.google.gerrit.server.notedb.ChangeUpdate;
import com.google.gerrit.server.project.ChangeControl; import com.google.gerrit.server.project.ChangeControl;
import com.google.gwtorm.server.OrmException;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject; import com.google.inject.assistedinject.AssistedInject;
@@ -75,7 +74,7 @@ import java.util.Map;
public class BatchUpdate implements AutoCloseable { public class BatchUpdate implements AutoCloseable {
public interface Factory { public interface Factory {
public BatchUpdate create(ReviewDb db, Project.NameKey project, public BatchUpdate create(ReviewDb db, Project.NameKey project,
Timestamp when); CurrentUser user, Timestamp when);
} }
public class Context { public class Context {
@@ -118,18 +117,24 @@ public class BatchUpdate implements AutoCloseable {
} }
public class ChangeContext extends Context { public class ChangeContext extends Context {
private final ChangeControl ctl;
private final ChangeUpdate update; private final ChangeUpdate update;
private ChangeContext(ChangeUpdate update) { private ChangeContext(ChangeControl ctl) {
this.update = update; this.ctl = ctl;
this.update = changeUpdateFactory.create(ctl, when);
} }
public ChangeUpdate getChangeUpdate() { public ChangeUpdate getChangeUpdate() {
return update; return update;
} }
public Change readChange() throws OrmException { public ChangeControl getChangeControl() {
return db.changes().get(update.getChange().getId()); return ctl;
}
public Change getChange() {
return update.getChange();
} }
public CurrentUser getUser() { public CurrentUser getUser() {
@@ -152,17 +157,23 @@ public class BatchUpdate implements AutoCloseable {
} }
} }
public abstract static class InsertChangeOp extends Op {
public abstract Change getChange();
}
private final ReviewDb db; private final ReviewDb db;
private final GitRepositoryManager repoManager; private final GitRepositoryManager repoManager;
private final ChangeIndexer indexer; private final ChangeIndexer indexer;
private final ChangeControl.GenericFactory changeControlFactory;
private final ChangeUpdate.Factory changeUpdateFactory; private final ChangeUpdate.Factory changeUpdateFactory;
private final GitReferenceUpdated gitRefUpdated; private final GitReferenceUpdated gitRefUpdated;
private final Project.NameKey project; private final Project.NameKey project;
private final CurrentUser user;
private final Timestamp when; private final Timestamp when;
private final ListMultimap<Change.Id, Op> ops = ArrayListMultimap.create(); private final ListMultimap<Change.Id, Op> ops = ArrayListMultimap.create();
private final Map<Change.Id, ChangeControl> changeControls = new HashMap<>(); private final Map<Change.Id, Change> newChanges = new HashMap<>();
private final List<CheckedFuture<?, IOException>> indexFutures = private final List<CheckedFuture<?, IOException>> indexFutures =
new ArrayList<>(); new ArrayList<>();
@@ -175,17 +186,21 @@ public class BatchUpdate implements AutoCloseable {
@AssistedInject @AssistedInject
BatchUpdate(GitRepositoryManager repoManager, BatchUpdate(GitRepositoryManager repoManager,
ChangeIndexer indexer, ChangeIndexer indexer,
ChangeControl.GenericFactory changeControlFactory,
ChangeUpdate.Factory changeUpdateFactory, ChangeUpdate.Factory changeUpdateFactory,
GitReferenceUpdated gitRefUpdated, GitReferenceUpdated gitRefUpdated,
@Assisted ReviewDb db, @Assisted ReviewDb db,
@Assisted Project.NameKey project, @Assisted Project.NameKey project,
@Assisted CurrentUser user,
@Assisted Timestamp when) { @Assisted Timestamp when) {
this.db = db; this.db = db;
this.repoManager = repoManager; this.repoManager = repoManager;
this.indexer = indexer; this.indexer = indexer;
this.changeControlFactory = changeControlFactory;
this.changeUpdateFactory = changeUpdateFactory; this.changeUpdateFactory = changeUpdateFactory;
this.gitRefUpdated = gitRefUpdated; this.gitRefUpdated = gitRefUpdated;
this.project = project; this.project = project;
this.user = user;
this.when = when; this.when = when;
} }
@@ -232,14 +247,18 @@ public class BatchUpdate implements AutoCloseable {
return inserter; return inserter;
} }
public BatchUpdate addOp(ChangeControl ctl, Op op) { public BatchUpdate addOp(Change.Id id, Op op) {
Change.Id id = ctl.getChange().getId(); checkArgument(!(op instanceof InsertChangeOp), "use insertChange");
ChangeControl old = changeControls.get(id);
// TODO(dborowitz): Not sure this is guaranteed in general.
checkArgument(old == null || old == ctl,
"mismatched ChangeControls for change %s", id);
ops.put(id, op); ops.put(id, op);
changeControls.put(id, ctl); return this;
}
public BatchUpdate insertChange(InsertChangeOp op) {
Change c = op.getChange();
checkArgument(!newChanges.containsKey(c.getId()),
"only one op allowed to create change %s", c.getId());
newChanges.put(c.getId(), c);
ops.get(c.getId()).add(0, op);
return this; return this;
} }
@@ -303,18 +322,18 @@ public class BatchUpdate implements AutoCloseable {
try { try {
for (Map.Entry<Change.Id, Collection<Op>> e : ops.asMap().entrySet()) { for (Map.Entry<Change.Id, Collection<Op>> e : ops.asMap().entrySet()) {
Change.Id id = e.getKey(); Change.Id id = e.getKey();
ChangeUpdate update =
changeUpdateFactory.create(changeControls.get(id), when);
db.changes().beginTransaction(id); db.changes().beginTransaction(id);
ChangeContext ctx;
try { try {
ctx = newChangeContext(id);
for (Op op : e.getValue()) { for (Op op : e.getValue()) {
op.updateChange(new ChangeContext(update)); op.updateChange(ctx);
} }
db.commit(); db.commit();
} finally { } finally {
db.rollback(); db.rollback();
} }
update.commit(); ctx.getChangeUpdate().commit();
indexFutures.add(indexer.indexAsync(id)); indexFutures.add(indexer.indexAsync(id));
} }
} catch (Exception e) { } catch (Exception e) {
@@ -323,6 +342,18 @@ public class BatchUpdate implements AutoCloseable {
} }
} }
private ChangeContext newChangeContext(Change.Id id) throws Exception {
Change c = newChanges.get(id);
if (c == null) {
c = db.changes().get(id);
}
// Pass in preloaded change to controlFor, to avoid:
// - reading from a db that does not belong to this update
// - attempting to read a change that doesn't exist yet
return new ChangeContext(
changeControlFactory.controlFor(c, user));
}
private void reindexChanges() throws IOException { private void reindexChanges() throws IOException {
ChangeIndexer.allAsList(indexFutures).checkedGet(); ChangeIndexer.allAsList(indexFutures).checkedGet();
} }

View File

@@ -136,6 +136,7 @@ import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.BatchRefUpdate; import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Ref;
@@ -305,6 +306,7 @@ public class ReceiveCommits {
private final AllProjectsName allProjectsName; private final AllProjectsName allProjectsName;
private final ReceiveConfig receiveConfig; private final ReceiveConfig receiveConfig;
private final ChangeKindCache changeKindCache; private final ChangeKindCache changeKindCache;
private final BatchUpdate.Factory batchUpdateFactory;
private final ProjectControl projectControl; private final ProjectControl projectControl;
private final Project project; private final Project project;
@@ -381,7 +383,8 @@ public class ReceiveCommits {
final ChangeKindCache changeKindCache, final ChangeKindCache changeKindCache,
final DynamicMap<ProjectConfigEntry> pluginConfigEntries, final DynamicMap<ProjectConfigEntry> pluginConfigEntries,
final NotesMigration notesMigration, final NotesMigration notesMigration,
final ChangeEditUtil editUtil) throws IOException { final ChangeEditUtil editUtil,
final BatchUpdate.Factory batchUpdateFactory) throws IOException {
this.currentUser = (IdentifiedUser) projectControl.getCurrentUser(); this.currentUser = (IdentifiedUser) projectControl.getCurrentUser();
this.db = db; this.db = db;
this.queryProvider = queryProvider; this.queryProvider = queryProvider;
@@ -414,6 +417,7 @@ public class ReceiveCommits {
this.allProjectsName = allProjectsName; this.allProjectsName = allProjectsName;
this.receiveConfig = config; this.receiveConfig = config;
this.changeKindCache = changeKindCache; this.changeKindCache = changeKindCache;
this.batchUpdateFactory = batchUpdateFactory;
this.projectControl = projectControl; this.projectControl = projectControl;
this.labelTypes = projectControl.getLabelTypes(); this.labelTypes = projectControl.getLabelTypes();
@@ -1717,8 +1721,10 @@ public class ReceiveCommits {
magicBranch.dest, magicBranch.dest,
TimeUtil.nowTs()); TimeUtil.nowTs());
change.setTopic(magicBranch.topic); change.setTopic(magicBranch.topic);
ins = changeInserterFactory.create(ctl.getProjectControl(), change, c) ins = changeInserterFactory.create(ctl, change, c)
.setDraft(magicBranch.draft); .setDraft(magicBranch.draft)
// Changes already validated in validateNewCommits.
.setValidatePolicy(CommitValidators.Policy.NONE);
cmd = new ReceiveCommand(ObjectId.zeroId(), c, cmd = new ReceiveCommand(ObjectId.zeroId(), c,
ins.getPatchSet().getRefName()); ins.getPatchSet().getRefName());
} }
@@ -1726,19 +1732,12 @@ public class ReceiveCommits {
CheckedFuture<Void, RestApiException> insertChange() throws IOException { CheckedFuture<Void, RestApiException> insertChange() throws IOException {
rp.getRevWalk().parseBody(commit); rp.getRevWalk().parseBody(commit);
final Thread caller = Thread.currentThread();
ListenableFuture<Void> future = changeUpdateExector.submit( ListenableFuture<Void> future = changeUpdateExector.submit(
requestScopePropagator.wrap(new Callable<Void>() { requestScopePropagator.wrap(new Callable<Void>() {
@Override @Override
public Void call() throws OrmException, IOException, public Void call()
ResourceConflictException { throws OrmException, RestApiException, UpdateException {
if (caller == Thread.currentThread()) { insertChangeImpl();
insertChange(db);
} else {
try (ReviewDb db = schemaFactory.open()) {
insertChange(db);
}
}
synchronized (newProgress) { synchronized (newProgress) {
newProgress.update(1); newProgress.update(1);
} }
@@ -1748,8 +1747,8 @@ public class ReceiveCommits {
return Futures.makeChecked(future, INSERT_EXCEPTION); return Futures.makeChecked(future, INSERT_EXCEPTION);
} }
private void insertChange(ReviewDb db) throws OrmException, IOException, private void insertChangeImpl()
ResourceConflictException { throws OrmException, RestApiException, UpdateException {
final PatchSet ps = ins.setGroups(groups).getPatchSet(); final PatchSet ps = ins.setGroups(groups).getPatchSet();
final Account.Id me = currentUser.getAccountId(); final Account.Id me = currentUser.getAccountId();
final List<FooterLine> footerLines = commit.getFooterLines(); final List<FooterLine> footerLines = commit.getFooterLines();
@@ -1762,20 +1761,20 @@ public class ReceiveCommits {
} }
recipients.add(getRecipientsFromFooters(accountResolver, ps, footerLines)); recipients.add(getRecipientsFromFooters(accountResolver, ps, footerLines));
recipients.remove(me); recipients.remove(me);
try (ObjectInserter oi = repo.newObjectInserter();
ChangeMessage msg = BatchUpdate bu = batchUpdateFactory.create(
new ChangeMessage(new ChangeMessage.Key(change.getId(), db, change.getProject(), currentUser, change.getCreatedOn())) {
ChangeUtil.messageUUID(db)), me, ps.getCreatedOn(), ps.getId()); bu.setRepository(repo, rp.getRevWalk(), oi);
msg.setMessage("Uploaded patch set " + ps.getPatchSetId() + "."); bu.insertChange(ins
ins
.setReviewers(recipients.getReviewers()) .setReviewers(recipients.getReviewers())
.setExtraCC(recipients.getCcOnly()) .setExtraCC(recipients.getCcOnly())
.setApprovals(approvals) .setApprovals(approvals)
.setMessage(msg) .setMessage("Uploaded patch set " + ps.getPatchSetId() + ".")
.setRequestScopePropagator(requestScopePropagator) .setRequestScopePropagator(requestScopePropagator)
.setSendMail(true) .setSendMail(true)
.insert(); .setUpdateRef(false));
bu.execute();
}
created = true; created = true;
if (magicBranch != null && magicBranch.submit) { if (magicBranch != null && magicBranch.submit) {

View File

@@ -72,14 +72,15 @@ public class CherryPick extends SubmitStrategy {
try (BatchUpdate u = args.newBatchUpdate(TimeUtil.nowTs())) { try (BatchUpdate u = args.newBatchUpdate(TimeUtil.nowTs())) {
while (!sorted.isEmpty()) { while (!sorted.isEmpty()) {
CodeReviewCommit n = sorted.remove(0); CodeReviewCommit n = sorted.remove(0);
Change.Id cid = n.change().getId();
if (first && branchTip == null) { if (first && branchTip == null) {
u.addOp(n.getControl(), new CherryPickUnbornRootOp(mergeTip, n)); u.addOp(cid, new CherryPickUnbornRootOp(mergeTip, n));
} else if (n.getParentCount() == 0) { } else if (n.getParentCount() == 0) {
u.addOp(n.getControl(), new CherryPickRootOp(n)); u.addOp(cid, new CherryPickRootOp(n));
} else if (n.getParentCount() == 1) { } else if (n.getParentCount() == 1) {
u.addOp(n.getControl(), new CherryPickOneOp(mergeTip, n)); u.addOp(cid, new CherryPickOneOp(mergeTip, n));
} else { } else {
u.addOp(n.getControl(), new CherryPickMultipleParentsOp(mergeTip, n)); u.addOp(cid, new CherryPickMultipleParentsOp(mergeTip, n));
} }
first = false; first = false;
} }

View File

@@ -19,7 +19,6 @@ import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet; import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.PatchSetApproval; import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.server.change.PatchSetInserter.ValidatePolicy;
import com.google.gerrit.server.change.RebaseChange; import com.google.gerrit.server.change.RebaseChange;
import com.google.gerrit.server.git.CodeReviewCommit; import com.google.gerrit.server.git.CodeReviewCommit;
import com.google.gerrit.server.git.CommitMergeStatus; import com.google.gerrit.server.git.CommitMergeStatus;
@@ -28,6 +27,7 @@ import com.google.gerrit.server.git.MergeException;
import com.google.gerrit.server.git.MergeTip; import com.google.gerrit.server.git.MergeTip;
import com.google.gerrit.server.git.RebaseSorter; import com.google.gerrit.server.git.RebaseSorter;
import com.google.gerrit.server.git.UpdateException; import com.google.gerrit.server.git.UpdateException;
import com.google.gerrit.server.git.validators.CommitValidators;
import com.google.gerrit.server.patch.PatchSetInfoFactory; import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.project.InvalidChangeOperationException; import com.google.gerrit.server.project.InvalidChangeOperationException;
import com.google.gerrit.server.project.NoSuchChangeException; import com.google.gerrit.server.project.NoSuchChangeException;
@@ -90,7 +90,8 @@ public class RebaseIfNecessary extends SubmitStrategy {
rebaseChange.rebase(args.repo, args.rw, args.inserter, rebaseChange.rebase(args.repo, args.rw, args.inserter,
n.change(), n.getPatchsetId(), args.caller, n.change(), n.getPatchsetId(), args.caller,
mergeTip.getCurrentTip(), args.mergeUtil, mergeTip.getCurrentTip(), args.mergeUtil,
args.serverIdent.get(), false, ValidatePolicy.NONE); args.serverIdent.get(), false,
CommitValidators.Policy.NONE);
List<PatchSetApproval> approvals = Lists.newArrayList(); List<PatchSetApproval> approvals = Lists.newArrayList();
for (PatchSetApproval a : args.approvalsUtil.byPatchSet(args.db, for (PatchSetApproval a : args.approvalsUtil.byPatchSet(args.db,
n.getControl(), n.getPatchsetId())) { n.getControl(), n.getPatchsetId())) {

View File

@@ -100,7 +100,8 @@ public abstract class SubmitStrategy {
} }
BatchUpdate newBatchUpdate(Timestamp when) { BatchUpdate newBatchUpdate(Timestamp when) {
return batchUpdateFactory.create(db, destBranch.getParentKey(), when) return batchUpdateFactory
.create(db, destBranch.getParentKey(), caller, when)
.setRepository(repo, rw, inserter); .setRepository(repo, rw, inserter);
} }
} }

View File

@@ -60,6 +60,17 @@ public class CommitValidators {
private static final Logger log = LoggerFactory private static final Logger log = LoggerFactory
.getLogger(CommitValidators.class); .getLogger(CommitValidators.class);
public static enum Policy {
/** Use {@link #validateForGerritCommits}. */
GERRIT,
/** Use {@link #validateForReceiveCommits}. */
RECEIVE_COMMITS,
/** Do not validate commits. */
NONE
}
public interface Factory { public interface Factory {
CommitValidators create(RefControl refControl, SshInfo sshInfo, CommitValidators create(RefControl refControl, SshInfo sshInfo,
Repository repo); Repository repo);

View File

@@ -53,12 +53,13 @@ import com.google.gerrit.server.account.AuthRequest;
import com.google.gerrit.server.change.ChangeInserter; import com.google.gerrit.server.change.ChangeInserter;
import com.google.gerrit.server.change.ChangeTriplet; import com.google.gerrit.server.change.ChangeTriplet;
import com.google.gerrit.server.change.PatchSetInserter; import com.google.gerrit.server.change.PatchSetInserter;
import com.google.gerrit.server.change.PatchSetInserter.ValidatePolicy;
import com.google.gerrit.server.git.BatchUpdate; import com.google.gerrit.server.git.BatchUpdate;
import com.google.gerrit.server.git.validators.CommitValidators;
import com.google.gerrit.server.index.IndexCollection; import com.google.gerrit.server.index.IndexCollection;
import com.google.gerrit.server.notedb.NotesMigration; import com.google.gerrit.server.notedb.NotesMigration;
import com.google.gerrit.server.project.ChangeControl; import com.google.gerrit.server.project.ChangeControl;
import com.google.gerrit.server.project.ProjectControl; import com.google.gerrit.server.project.ProjectControl;
import com.google.gerrit.server.project.RefControl;
import com.google.gerrit.server.schema.SchemaCreator; import com.google.gerrit.server.schema.SchemaCreator;
import com.google.gerrit.server.util.RequestContext; import com.google.gerrit.server.util.RequestContext;
import com.google.gerrit.server.util.ThreadLocalRequestContext; import com.google.gerrit.server.util.ThreadLocalRequestContext;
@@ -212,8 +213,8 @@ public abstract class AbstractQueryChangesTest {
@Test @Test
public void byId() throws Exception { public void byId() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, null).insert(); Change change1 = insert(newChange(repo, null, null, null, null));
Change change2 = newChange(repo, null, null, null, null).insert(); Change change2 = insert(newChange(repo, null, null, null, null));
assertQuery("12345"); assertQuery("12345");
assertQuery(change1.getId().get(), change1); assertQuery(change1.getId().get(), change1);
@@ -223,7 +224,7 @@ public abstract class AbstractQueryChangesTest {
@Test @Test
public void byKey() throws Exception { public void byKey() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change = newChange(repo, null, null, null, null).insert(); Change change = insert(newChange(repo, null, null, null, null));
String key = change.getKey().get(); String key = change.getKey().get();
assertQuery("I0000000000000000000000000000000000000000"); assertQuery("I0000000000000000000000000000000000000000");
@@ -236,7 +237,7 @@ public abstract class AbstractQueryChangesTest {
@Test @Test
public void byTriplet() throws Exception { public void byTriplet() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change = newChange(repo, null, null, null, "branch").insert(); Change change = insert(newChange(repo, null, null, null, "branch"));
String k = change.getKey().get(); String k = change.getKey().get();
assertQuery("repo~branch~" + k, change); assertQuery("repo~branch~" + k, change);
@@ -262,11 +263,11 @@ public abstract class AbstractQueryChangesTest {
ChangeInserter ins1 = newChange(repo, null, null, null, null); ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.getChange(); Change change1 = ins1.getChange();
change1.setStatus(Change.Status.NEW); change1.setStatus(Change.Status.NEW);
ins1.insert(); insert(ins1);
ChangeInserter ins2 = newChange(repo, null, null, null, null); ChangeInserter ins2 = newChange(repo, null, null, null, null);
Change change2 = ins2.getChange(); Change change2 = ins2.getChange();
change2.setStatus(Change.Status.MERGED); change2.setStatus(Change.Status.MERGED);
ins2.insert(); insert(ins2);
assertQuery("status:new", change1); assertQuery("status:new", change1);
assertQuery("status:NEW", change1); assertQuery("status:NEW", change1);
@@ -281,15 +282,15 @@ public abstract class AbstractQueryChangesTest {
ChangeInserter ins1 = newChange(repo, null, null, null, null); ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.getChange(); Change change1 = ins1.getChange();
change1.setStatus(Change.Status.NEW); change1.setStatus(Change.Status.NEW);
ins1.insert(); insert(ins1);
ChangeInserter ins2 = newChange(repo, null, null, null, null); ChangeInserter ins2 = newChange(repo, null, null, null, null);
Change change2 = ins2.getChange(); Change change2 = ins2.getChange();
change2.setStatus(Change.Status.DRAFT); change2.setStatus(Change.Status.DRAFT);
ins2.insert(); insert(ins2);
ChangeInserter ins3 = newChange(repo, null, null, null, null); ChangeInserter ins3 = newChange(repo, null, null, null, null);
Change change3 = ins3.getChange(); Change change3 = ins3.getChange();
change3.setStatus(Change.Status.MERGED); change3.setStatus(Change.Status.MERGED);
ins3.insert(); insert(ins3);
Change[] expected = new Change[] {change2, change1}; Change[] expected = new Change[] {change2, change1};
assertQuery("status:open", expected); assertQuery("status:open", expected);
@@ -311,15 +312,15 @@ public abstract class AbstractQueryChangesTest {
ChangeInserter ins1 = newChange(repo, null, null, null, null); ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.getChange(); Change change1 = ins1.getChange();
change1.setStatus(Change.Status.MERGED); change1.setStatus(Change.Status.MERGED);
ins1.insert(); insert(ins1);
ChangeInserter ins2 = newChange(repo, null, null, null, null); ChangeInserter ins2 = newChange(repo, null, null, null, null);
Change change2 = ins2.getChange(); Change change2 = ins2.getChange();
change2.setStatus(Change.Status.ABANDONED); change2.setStatus(Change.Status.ABANDONED);
ins2.insert(); insert(ins2);
ChangeInserter ins3 = newChange(repo, null, null, null, null); ChangeInserter ins3 = newChange(repo, null, null, null, null);
Change change3 = ins3.getChange(); Change change3 = ins3.getChange();
change3.setStatus(Change.Status.NEW); change3.setStatus(Change.Status.NEW);
ins3.insert(); insert(ins3);
Change[] expected = new Change[] {change2, change1}; Change[] expected = new Change[] {change2, change1};
assertQuery("status:closed", expected); assertQuery("status:closed", expected);
@@ -339,11 +340,11 @@ public abstract class AbstractQueryChangesTest {
ChangeInserter ins1 = newChange(repo, null, null, null, null); ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.getChange(); Change change1 = ins1.getChange();
change1.setStatus(Change.Status.NEW); change1.setStatus(Change.Status.NEW);
ins1.insert(); insert(ins1);
ChangeInserter ins2 = newChange(repo, null, null, null, null); ChangeInserter ins2 = newChange(repo, null, null, null, null);
Change change2 = ins2.getChange(); Change change2 = ins2.getChange();
change2.setStatus(Change.Status.MERGED); change2.setStatus(Change.Status.MERGED);
ins2.insert(); insert(ins2);
assertQuery("status:n", change1); assertQuery("status:n", change1);
assertQuery("status:ne", change1); assertQuery("status:ne", change1);
@@ -359,7 +360,7 @@ public abstract class AbstractQueryChangesTest {
public void byCommit() throws Exception { public void byCommit() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins = newChange(repo, null, null, null, null); ChangeInserter ins = newChange(repo, null, null, null, null);
ins.insert(); insert(ins);
String sha = ins.getPatchSet().getRevision().get(); String sha = ins.getPatchSet().getRevision().get();
assertQuery("0000000000000000000000000000000000000000"); assertQuery("0000000000000000000000000000000000000000");
@@ -372,10 +373,10 @@ public abstract class AbstractQueryChangesTest {
@Test @Test
public void byOwner() throws Exception { public void byOwner() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, userId.get(), null).insert(); Change change1 = insert(newChange(repo, null, null, userId.get(), null));
int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser")) int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId().get(); .getAccountId().get();
Change change2 = newChange(repo, null, null, user2, null).insert(); Change change2 = insert(newChange(repo, null, null, user2, null));
assertQuery("owner:" + userId.get(), change1); assertQuery("owner:" + userId.get(), change1);
assertQuery("owner:" + user2, change2); assertQuery("owner:" + user2, change2);
@@ -384,7 +385,7 @@ public abstract class AbstractQueryChangesTest {
@Test @Test
public void byAuthor() throws Exception { public void byAuthor() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, userId.get(), null).insert(); Change change1 = insert(newChange(repo, null, null, userId.get(), null));
// By exact email address // By exact email address
assertQuery("author:jauthor@example.com", change1); assertQuery("author:jauthor@example.com", change1);
@@ -407,7 +408,7 @@ public abstract class AbstractQueryChangesTest {
@Test @Test
public void byCommitter() throws Exception { public void byCommitter() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, userId.get(), null).insert(); Change change1 = insert(newChange(repo, null, null, userId.get(), null));
// By exact email address // By exact email address
assertQuery("committer:jcommitter@example.com", change1); assertQuery("committer:jcommitter@example.com", change1);
@@ -430,10 +431,10 @@ public abstract class AbstractQueryChangesTest {
@Test @Test
public void byOwnerIn() throws Exception { public void byOwnerIn() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, userId.get(), null).insert(); Change change1 = insert(newChange(repo, null, null, userId.get(), null));
int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser")) int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId().get(); .getAccountId().get();
Change change2 = newChange(repo, null, null, user2, null).insert(); Change change2 = insert(newChange(repo, null, null, user2, null));
assertQuery("ownerin:Administrators", change1); assertQuery("ownerin:Administrators", change1);
assertQuery("ownerin:\"Registered Users\"", change2, change1); assertQuery("ownerin:\"Registered Users\"", change2, change1);
@@ -443,8 +444,8 @@ public abstract class AbstractQueryChangesTest {
public void byProject() throws Exception { public void byProject() throws Exception {
TestRepository<Repo> repo1 = createProject("repo1"); TestRepository<Repo> repo1 = createProject("repo1");
TestRepository<Repo> repo2 = createProject("repo2"); TestRepository<Repo> repo2 = createProject("repo2");
Change change1 = newChange(repo1, null, null, null, null).insert(); Change change1 = insert(newChange(repo1, null, null, null, null));
Change change2 = newChange(repo2, null, null, null, null).insert(); Change change2 = insert(newChange(repo2, null, null, null, null));
assertQuery("project:foo"); assertQuery("project:foo");
assertQuery("project:repo"); assertQuery("project:repo");
@@ -456,8 +457,8 @@ public abstract class AbstractQueryChangesTest {
public void byProjectPrefix() throws Exception { public void byProjectPrefix() throws Exception {
TestRepository<Repo> repo1 = createProject("repo1"); TestRepository<Repo> repo1 = createProject("repo1");
TestRepository<Repo> repo2 = createProject("repo2"); TestRepository<Repo> repo2 = createProject("repo2");
Change change1 = newChange(repo1, null, null, null, null).insert(); Change change1 = insert(newChange(repo1, null, null, null, null));
Change change2 = newChange(repo2, null, null, null, null).insert(); Change change2 = insert(newChange(repo2, null, null, null, null));
assertQuery("projects:foo"); assertQuery("projects:foo");
assertQuery("projects:repo1", change1); assertQuery("projects:repo1", change1);
@@ -468,8 +469,8 @@ public abstract class AbstractQueryChangesTest {
@Test @Test
public void byBranchAndRef() throws Exception { public void byBranchAndRef() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, "master").insert(); Change change1 = insert(newChange(repo, null, null, null, "master"));
Change change2 = newChange(repo, null, null, null, "branch").insert(); Change change2 = insert(newChange(repo, null, null, null, "branch"));
assertQuery("branch:foo"); assertQuery("branch:foo");
assertQuery("branch:master", change1); assertQuery("branch:master", change1);
@@ -489,24 +490,24 @@ public abstract class AbstractQueryChangesTest {
ChangeInserter ins1 = newChange(repo, null, null, null, null); ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.getChange(); Change change1 = ins1.getChange();
change1.setTopic("feature1"); change1.setTopic("feature1");
ins1.insert(); insert(ins1);
ChangeInserter ins2 = newChange(repo, null, null, null, null); ChangeInserter ins2 = newChange(repo, null, null, null, null);
Change change2 = ins2.getChange(); Change change2 = ins2.getChange();
change2.setTopic("feature2"); change2.setTopic("feature2");
ins2.insert(); insert(ins2);
ChangeInserter ins3 = newChange(repo, null, null, null, null); ChangeInserter ins3 = newChange(repo, null, null, null, null);
Change change3 = ins3.getChange(); Change change3 = ins3.getChange();
change3.setTopic("Cherrypick-feature2"); change3.setTopic("Cherrypick-feature2");
ins3.insert(); insert(ins3);
ChangeInserter ins4 = newChange(repo, null, null, null, null); ChangeInserter ins4 = newChange(repo, null, null, null, null);
Change change4 = ins4.getChange(); Change change4 = ins4.getChange();
change4.setTopic("feature2-fixup"); change4.setTopic("feature2-fixup");
ins4.insert(); insert(ins4);
Change change5 = newChange(repo, null, null, null, null).insert(); Change change5 = insert(newChange(repo, null, null, null, null));
assertQuery("intopic:foo"); assertQuery("intopic:foo");
assertQuery("intopic:feature1", change1); assertQuery("intopic:feature1", change1);
@@ -522,9 +523,9 @@ public abstract class AbstractQueryChangesTest {
public void byMessageExact() throws Exception { public void byMessageExact() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
RevCommit commit1 = repo.parseBody(repo.commit().message("one").create()); RevCommit commit1 = repo.parseBody(repo.commit().message("one").create());
Change change1 = newChange(repo, commit1, null, null, null).insert(); Change change1 = insert(newChange(repo, commit1, null, null, null));
RevCommit commit2 = repo.parseBody(repo.commit().message("two").create()); RevCommit commit2 = repo.parseBody(repo.commit().message("two").create());
Change change2 = newChange(repo, commit2, null, null, null).insert(); Change change2 = insert(newChange(repo, commit2, null, null, null));
assertQuery("message:foo"); assertQuery("message:foo");
assertQuery("message:one", change1); assertQuery("message:one", change1);
@@ -536,10 +537,10 @@ public abstract class AbstractQueryChangesTest {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
RevCommit commit1 = RevCommit commit1 =
repo.parseBody(repo.commit().message("12345 67890").create()); repo.parseBody(repo.commit().message("12345 67890").create());
Change change1 = newChange(repo, commit1, null, null, null).insert(); Change change1 = insert(newChange(repo, commit1, null, null, null));
RevCommit commit2 = RevCommit commit2 =
repo.parseBody(repo.commit().message("12346 67891").create()); repo.parseBody(repo.commit().message("12346 67891").create());
Change change2 = newChange(repo, commit2, null, null, null).insert(); Change change2 = insert(newChange(repo, commit2, null, null, null));
assertQuery("message:1234"); assertQuery("message:1234");
assertQuery("message:12345", change1); assertQuery("message:12345", change1);
@@ -551,7 +552,7 @@ public abstract class AbstractQueryChangesTest {
accountManager.authenticate(AuthRequest.forUser("anotheruser")); accountManager.authenticate(AuthRequest.forUser("anotheruser"));
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins = newChange(repo, null, null, null, null); ChangeInserter ins = newChange(repo, null, null, null, null);
Change change = ins.insert(); Change change = insert(ins);
gApi.changes().id(change.getId().get()).current() gApi.changes().id(change.getId().get()).current()
.review(new ReviewInput().label("Code-Review", 1)); .review(new ReviewInput().label("Code-Review", 1));
@@ -593,7 +594,7 @@ public abstract class AbstractQueryChangesTest {
Change last = null; Change last = null;
int n = 5; int n = 5;
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
last = newChange(repo, null, null, null, null).insert(); last = insert(newChange(repo, null, null, null, null));
} }
for (int i = 1; i <= n + 2; i++) { for (int i = 1; i <= n + 2; i++) {
@@ -620,7 +621,7 @@ public abstract class AbstractQueryChangesTest {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
List<Change> changes = Lists.newArrayList(); List<Change> changes = Lists.newArrayList();
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
changes.add(newChange(repo, null, null, null, null).insert()); changes.add(insert(newChange(repo, null, null, null, null)));
} }
assertQuery("status:new", changes.get(1), changes.get(0)); assertQuery("status:new", changes.get(1), changes.get(0));
@@ -634,7 +635,7 @@ public abstract class AbstractQueryChangesTest {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
List<Change> changes = Lists.newArrayList(); List<Change> changes = Lists.newArrayList();
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
changes.add(newChange(repo, null, null, null, null).insert()); changes.add(insert(newChange(repo, null, null, null, null)));
} }
assertQuery("status:new limit:2", changes.get(2), changes.get(1)); assertQuery("status:new limit:2", changes.get(2), changes.get(1));
@@ -648,7 +649,7 @@ public abstract class AbstractQueryChangesTest {
@Test @Test
public void maxPages() throws Exception { public void maxPages() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change = newChange(repo, null, null, null, null).insert(); Change change = insert(newChange(repo, null, null, null, null));
QueryRequest query = newQuery("status:new").withLimit(10); QueryRequest query = newQuery("status:new").withLimit(10);
assertQuery(query, change); assertQuery(query, change);
@@ -666,7 +667,7 @@ public abstract class AbstractQueryChangesTest {
List<Change> changes = Lists.newArrayList(); List<Change> changes = Lists.newArrayList();
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
inserters.add(newChange(repo, null, null, null, null)); inserters.add(newChange(repo, null, null, null, null));
changes.add(inserters.get(i).insert()); changes.add(insert(inserters.get(i)));
} }
for (int i : ImmutableList.of(2, 0, 1, 4, 3)) { for (int i : ImmutableList.of(2, 0, 1, 4, 3)) {
@@ -688,8 +689,8 @@ public abstract class AbstractQueryChangesTest {
clockStepMs = MILLISECONDS.convert(2, MINUTES); clockStepMs = MILLISECONDS.convert(2, MINUTES);
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null); ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.insert(); Change change1 = insert(ins1);
Change change2 = newChange(repo, null, null, null, null).insert(); Change change2 = insert(newChange(repo, null, null, null, null));
assertThat(lastUpdatedMs(change1)).isLessThan(lastUpdatedMs(change2)); assertThat(lastUpdatedMs(change1)).isLessThan(lastUpdatedMs(change2));
assertQuery("status:new", change2, change1); assertQuery("status:new", change2, change1);
@@ -710,8 +711,8 @@ public abstract class AbstractQueryChangesTest {
public void updatedOrderWithSubMinuteResolution() throws Exception { public void updatedOrderWithSubMinuteResolution() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins1 = newChange(repo, null, null, null, null); ChangeInserter ins1 = newChange(repo, null, null, null, null);
Change change1 = ins1.insert(); Change change1 = insert(ins1);
Change change2 = newChange(repo, null, null, null, null).insert(); Change change2 = insert(newChange(repo, null, null, null, null));
assertThat(lastUpdatedMs(change1)).isLessThan(lastUpdatedMs(change2)); assertThat(lastUpdatedMs(change1)).isLessThan(lastUpdatedMs(change2));
@@ -732,11 +733,11 @@ public abstract class AbstractQueryChangesTest {
@Test @Test
public void filterOutMoreThanOnePageOfResults() throws Exception { public void filterOutMoreThanOnePageOfResults() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change = newChange(repo, null, null, userId.get(), null).insert(); Change change = insert(newChange(repo, null, null, userId.get(), null));
int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser")) int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId().get(); .getAccountId().get();
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
newChange(repo, null, null, user2, null).insert(); insert(newChange(repo, null, null, user2, null));
} }
assertQuery("status:new ownerin:Administrators", change); assertQuery("status:new ownerin:Administrators", change);
@@ -749,7 +750,7 @@ public abstract class AbstractQueryChangesTest {
int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser")) int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId().get(); .getAccountId().get();
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
newChange(repo, null, null, user2, null).insert(); insert(newChange(repo, null, null, user2, null));
} }
assertQuery("status:new ownerin:Administrators"); assertQuery("status:new ownerin:Administrators");
@@ -763,7 +764,7 @@ public abstract class AbstractQueryChangesTest {
repo.commit().message("one") repo.commit().message("one")
.add("dir/file1", "contents1").add("dir/file2", "contents2") .add("dir/file1", "contents1").add("dir/file2", "contents2")
.create()); .create());
Change change = newChange(repo, commit, null, null, null).insert(); Change change = insert(newChange(repo, commit, null, null, null));
assertQuery("file:file"); assertQuery("file:file");
assertQuery("file:dir", change); assertQuery("file:dir", change);
@@ -780,7 +781,7 @@ public abstract class AbstractQueryChangesTest {
repo.commit().message("one") repo.commit().message("one")
.add("dir/file1", "contents1").add("dir/file2", "contents2") .add("dir/file1", "contents1").add("dir/file2", "contents2")
.create()); .create());
Change change = newChange(repo, commit, null, null, null).insert(); Change change = insert(newChange(repo, commit, null, null, null));
assertQuery("file:.*file.*"); assertQuery("file:.*file.*");
assertQuery("file:^file.*"); // Whole path only. assertQuery("file:^file.*"); // Whole path only.
@@ -794,7 +795,7 @@ public abstract class AbstractQueryChangesTest {
repo.commit().message("one") repo.commit().message("one")
.add("dir/file1", "contents1").add("dir/file2", "contents2") .add("dir/file1", "contents1").add("dir/file2", "contents2")
.create()); .create());
Change change = newChange(repo, commit, null, null, null).insert(); Change change = insert(newChange(repo, commit, null, null, null));
assertQuery("path:file"); assertQuery("path:file");
assertQuery("path:dir"); assertQuery("path:dir");
@@ -811,7 +812,7 @@ public abstract class AbstractQueryChangesTest {
repo.commit().message("one") repo.commit().message("one")
.add("dir/file1", "contents1").add("dir/file2", "contents2") .add("dir/file1", "contents1").add("dir/file2", "contents2")
.create()); .create());
Change change = newChange(repo, commit, null, null, null).insert(); Change change = insert(newChange(repo, commit, null, null, null));
assertQuery("path:.*file.*"); assertQuery("path:.*file.*");
assertQuery("path:^dir.file.*", change); assertQuery("path:^dir.file.*", change);
@@ -821,7 +822,7 @@ public abstract class AbstractQueryChangesTest {
public void byComment() throws Exception { public void byComment() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
ChangeInserter ins = newChange(repo, null, null, null, null); ChangeInserter ins = newChange(repo, null, null, null, null);
Change change = ins.insert(); Change change = insert(ins);
ReviewInput input = new ReviewInput(); ReviewInput input = new ReviewInput();
input.message = "toplevel"; input.message = "toplevel";
@@ -842,8 +843,8 @@ public abstract class AbstractQueryChangesTest {
long thirtyHours = MILLISECONDS.convert(30, HOURS); long thirtyHours = MILLISECONDS.convert(30, HOURS);
clockStepMs = thirtyHours; clockStepMs = thirtyHours;
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, null).insert(); Change change1 = insert(newChange(repo, null, null, null, null));
Change change2 = newChange(repo, null, null, null, null).insert(); Change change2 = insert(newChange(repo, null, null, null, null));
clockStepMs = 0; // Queried by AgePredicate constructor. clockStepMs = 0; // Queried by AgePredicate constructor.
long now = TimeUtil.nowMs(); long now = TimeUtil.nowMs();
assertThat(lastUpdatedMs(change2) - lastUpdatedMs(change1)) assertThat(lastUpdatedMs(change2) - lastUpdatedMs(change1))
@@ -864,8 +865,8 @@ public abstract class AbstractQueryChangesTest {
public void byBefore() throws Exception { public void byBefore() throws Exception {
clockStepMs = MILLISECONDS.convert(30, HOURS); clockStepMs = MILLISECONDS.convert(30, HOURS);
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, null).insert(); Change change1 = insert(newChange(repo, null, null, null, null));
Change change2 = newChange(repo, null, null, null, null).insert(); Change change2 = insert(newChange(repo, null, null, null, null));
clockStepMs = 0; clockStepMs = 0;
assertQuery("before:2009-09-29"); assertQuery("before:2009-09-29");
@@ -884,8 +885,8 @@ public abstract class AbstractQueryChangesTest {
public void byAfter() throws Exception { public void byAfter() throws Exception {
clockStepMs = MILLISECONDS.convert(30, HOURS); clockStepMs = MILLISECONDS.convert(30, HOURS);
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, null).insert(); Change change1 = insert(newChange(repo, null, null, null, null));
Change change2 = newChange(repo, null, null, null, null).insert(); Change change2 = insert(newChange(repo, null, null, null, null));
clockStepMs = 0; clockStepMs = 0;
assertQuery("after:2009-10-03"); assertQuery("after:2009-10-03");
@@ -906,8 +907,8 @@ public abstract class AbstractQueryChangesTest {
RevCommit commit2 = repo.parseBody( RevCommit commit2 = repo.parseBody(
repo.commit().parent(commit1).add("file1", "foo").create()); repo.commit().parent(commit1).add("file1", "foo").create());
Change change1 = newChange(repo, commit1, null, null, null).insert(); Change change1 = insert(newChange(repo, commit1, null, null, null));
Change change2 = newChange(repo, commit2, null, null, null).insert(); Change change2 = insert(newChange(repo, commit2, null, null, null));
assertQuery("added:>4"); assertQuery("added:>4");
assertQuery("-added:<=4"); assertQuery("-added:<=4");
@@ -956,8 +957,8 @@ public abstract class AbstractQueryChangesTest {
private List<Change> setUpHashtagChanges() throws Exception { private List<Change> setUpHashtagChanges() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, null).insert(); Change change1 = insert(newChange(repo, null, null, null, null));
Change change2 = newChange(repo, null, null, null, null).insert(); Change change2 = insert(newChange(repo, null, null, null, null));
HashtagsInput in = new HashtagsInput(); HashtagsInput in = new HashtagsInput();
in.add = ImmutableSet.of("foo"); in.add = ImmutableSet.of("foo");
@@ -999,20 +1000,20 @@ public abstract class AbstractQueryChangesTest {
public void byDefault() throws Exception { public void byDefault() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, null).insert(); Change change1 = insert(newChange(repo, null, null, null, null));
RevCommit commit2 = repo.parseBody( RevCommit commit2 = repo.parseBody(
repo.commit().message("foosubject").create()); repo.commit().message("foosubject").create());
Change change2 = newChange(repo, commit2, null, null, null).insert(); Change change2 = insert(newChange(repo, commit2, null, null, null));
RevCommit commit3 = repo.parseBody( RevCommit commit3 = repo.parseBody(
repo.commit() repo.commit()
.add("Foo.java", "foo contents") .add("Foo.java", "foo contents")
.create()); .create());
Change change3 = newChange(repo, commit3, null, null, null).insert(); Change change3 = insert(newChange(repo, commit3, null, null, null));
ChangeInserter ins4 = newChange(repo, null, null, null, null); ChangeInserter ins4 = newChange(repo, null, null, null, null);
Change change4 = ins4.insert(); Change change4 = insert(ins4);
ReviewInput ri4 = new ReviewInput(); ReviewInput ri4 = new ReviewInput();
ri4.message = "toplevel"; ri4.message = "toplevel";
ri4.labels = ImmutableMap.<String, Short> of("Code-Review", (short) 1); ri4.labels = ImmutableMap.<String, Short> of("Code-Review", (short) 1);
@@ -1021,9 +1022,9 @@ public abstract class AbstractQueryChangesTest {
ChangeInserter ins5 = newChange(repo, null, null, null, null); ChangeInserter ins5 = newChange(repo, null, null, null, null);
Change change5 = ins5.getChange(); Change change5 = ins5.getChange();
change5.setTopic("feature5"); change5.setTopic("feature5");
ins5.insert(); insert(ins5);
Change change6 = newChange(repo, null, null, null, "branch6").insert(); Change change6 = insert(newChange(repo, null, null, null, "branch6"));
assertQuery(change1.getId().get(), change1); assertQuery(change1.getId().get(), change1);
assertQuery(ChangeTriplet.format(change1), change1); assertQuery(ChangeTriplet.format(change1), change1);
@@ -1044,11 +1045,11 @@ public abstract class AbstractQueryChangesTest {
@Test @Test
public void implicitVisibleTo() throws Exception { public void implicitVisibleTo() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, userId.get(), null).insert(); Change change1 = insert(newChange(repo, null, null, userId.get(), null));
ChangeInserter ins2 = newChange(repo, null, null, userId.get(), null); ChangeInserter ins2 = newChange(repo, null, null, userId.get(), null);
Change change2 = ins2.getChange(); Change change2 = ins2.getChange();
change2.setStatus(Change.Status.DRAFT); change2.setStatus(Change.Status.DRAFT);
ins2.insert(); insert(ins2);
String q = "project:repo"; String q = "project:repo";
assertQuery(q, change2, change1); assertQuery(q, change2, change1);
@@ -1062,11 +1063,11 @@ public abstract class AbstractQueryChangesTest {
@Test @Test
public void explicitVisibleTo() throws Exception { public void explicitVisibleTo() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, userId.get(), null).insert(); Change change1 = insert(newChange(repo, null, null, userId.get(), null));
ChangeInserter ins2 = newChange(repo, null, null, userId.get(), null); ChangeInserter ins2 = newChange(repo, null, null, userId.get(), null);
Change change2 = ins2.getChange(); Change change2 = ins2.getChange();
change2.setStatus(Change.Status.DRAFT); change2.setStatus(Change.Status.DRAFT);
ins2.insert(); insert(ins2);
String q = "project:repo"; String q = "project:repo";
assertQuery(q, change2, change1); assertQuery(q, change2, change1);
@@ -1081,8 +1082,8 @@ public abstract class AbstractQueryChangesTest {
@Test @Test
public void byCommentBy() throws Exception { public void byCommentBy() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, null).insert(); Change change1 = insert(newChange(repo, null, null, null, null));
Change change2 = newChange(repo, null, null, null, null).insert(); Change change2 = insert(newChange(repo, null, null, null, null));
int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser")) int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId().get(); .getAccountId().get();
@@ -1107,12 +1108,12 @@ public abstract class AbstractQueryChangesTest {
@Test @Test
public void byFrom() throws Exception { public void byFrom() throws Exception {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, null).insert(); Change change1 = insert(newChange(repo, null, null, null, null));
int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser")) int user2 = accountManager.authenticate(AuthRequest.forUser("anotheruser"))
.getAccountId().get(); .getAccountId().get();
ChangeInserter ins2 = newChange(repo, null, null, user2, null); ChangeInserter ins2 = newChange(repo, null, null, user2, null);
Change change2 = ins2.insert(); Change change2 = insert(ins2);
ReviewInput input = new ReviewInput(); ReviewInput input = new ReviewInput();
input.message = "toplevel"; input.message = "toplevel";
@@ -1148,10 +1149,10 @@ public abstract class AbstractQueryChangesTest {
repo.commit() repo.commit()
.add("file4", "contents4") .add("file4", "contents4")
.create()); .create());
Change change1 = newChange(repo, commit1, null, null, null).insert(); Change change1 = insert(newChange(repo, commit1, null, null, null));
Change change2 = newChange(repo, commit2, null, null, null).insert(); Change change2 = insert(newChange(repo, commit2, null, null, null));
Change change3 = newChange(repo, commit3, null, null, null).insert(); Change change3 = insert(newChange(repo, commit3, null, null, null));
Change change4 = newChange(repo, commit4, null, null, null).insert(); Change change4 = insert(newChange(repo, commit4, null, null, null));
assertQuery("conflicts:" + change1.getId().get(), change3); assertQuery("conflicts:" + change1.getId().get(), change3);
assertQuery("conflicts:" + change2.getId().get()); assertQuery("conflicts:" + change2.getId().get());
@@ -1163,9 +1164,9 @@ public abstract class AbstractQueryChangesTest {
public void reviewedBy() throws Exception { public void reviewedBy() throws Exception {
clockStepMs = MILLISECONDS.convert(2, MINUTES); clockStepMs = MILLISECONDS.convert(2, MINUTES);
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, null).insert(); Change change1 = insert(newChange(repo, null, null, null, null));
Change change2 = newChange(repo, null, null, null, null).insert(); Change change2 = insert(newChange(repo, null, null, null, null));
Change change3 = newChange(repo, null, null, null, null).insert(); Change change3 = insert(newChange(repo, null, null, null, null));
gApi.changes() gApi.changes()
.id(change1.getId().get()) .id(change1.getId().get())
@@ -1221,7 +1222,7 @@ public abstract class AbstractQueryChangesTest {
Branch.NameKey dest = null; Branch.NameKey dest = null;
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
ChangeInserter ins = newChange(repo, null, null, null, null); ChangeInserter ins = newChange(repo, null, null, null, null);
ins.insert(); insert(ins);
if (dest == null) { if (dest == null) {
dest = ins.getChange().getDest(); dest = ins.getChange().getDest();
} }
@@ -1250,7 +1251,7 @@ public abstract class AbstractQueryChangesTest {
public void prepopulatedFields() throws Exception { public void prepopulatedFields() throws Exception {
assume().that(notesMigration.enabled()).isFalse(); assume().that(notesMigration.enabled()).isFalse();
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change = newChange(repo, null, null, null, null).insert(); Change change = insert(newChange(repo, null, null, null, null));
db = new DisabledReviewDb(); db = new DisabledReviewDb();
requestContext.setContext(newRequestContext(userId)); requestContext.setContext(newRequestContext(userId));
@@ -1311,10 +1312,20 @@ public abstract class AbstractQueryChangesTest {
Change change = new Change(new Change.Key(key), id, ownerId, Change change = new Change(new Change.Key(key), id, ownerId,
new Branch.NameKey(project, branch), TimeUtil.nowTs()); new Branch.NameKey(project, branch), TimeUtil.nowTs());
IdentifiedUser user = userFactory.create(Providers.of(db), ownerId); IdentifiedUser user = userFactory.create(Providers.of(db), ownerId);
return changeFactory.create( RefControl refControl = projectControlFactory.controlFor(project, user)
projectControlFactory.controlFor(project, user), .controlForRef(change.getDest());
change, return changeFactory.create(refControl, change, commit)
commit); .setValidatePolicy(CommitValidators.Policy.NONE);
}
protected Change insert(ChangeInserter ins) throws Exception {
try (BatchUpdate bu = updateFactory.create(
db, ins.getChange().getProject(), ins.getUser(),
ins.getChange().getCreatedOn())) {
bu.insertChange(ins);
bu.execute();
return ins.getChange();
}
} }
protected Change newPatchSet(TestRepository<Repo> repo, Change c) protected Change newPatchSet(TestRepository<Repo> repo, Change c)
@@ -1333,10 +1344,10 @@ public abstract class AbstractQueryChangesTest {
repo.getRepository(), repo.getRevWalk(), ctl, commit) repo.getRepository(), repo.getRevWalk(), ctl, commit)
.setSendMail(false) .setSendMail(false)
.setRunHooks(false) .setRunHooks(false)
.setValidatePolicy(ValidatePolicy.NONE); .setValidatePolicy(CommitValidators.Policy.NONE);
try (BatchUpdate bu = updateFactory.create( try (BatchUpdate bu = updateFactory.create(
db, c.getDest().getParentKey(), TimeUtil.nowTs())) { db, c.getDest().getParentKey(), user, TimeUtil.nowTs())) {
bu.addOp(ctl, inserter); bu.addOp(c.getId(), inserter);
bu.execute(); bu.execute();
} }

View File

@@ -38,10 +38,10 @@ public class LuceneQueryChangesTest extends AbstractQueryChangesTest {
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
RevCommit commit1 = RevCommit commit1 =
repo.parseBody(repo.commit().message("foo_bar_foo").create()); repo.parseBody(repo.commit().message("foo_bar_foo").create());
Change change1 = newChange(repo, commit1, null, null, null).insert(); Change change1 = insert(newChange(repo, commit1, null, null, null));
RevCommit commit2 = RevCommit commit2 =
repo.parseBody(repo.commit().message("one.two.three").create()); repo.parseBody(repo.commit().message("one.two.three").create());
Change change2 = newChange(repo, commit2, null, null, null).insert(); Change change2 = insert(newChange(repo, commit2, null, null, null));
assertQuery("message:foo_ba"); assertQuery("message:foo_ba");
assertQuery("message:bar", change1); assertQuery("message:bar", change1);

View File

@@ -82,9 +82,9 @@ public class LuceneQueryChangesV14Test extends LuceneQueryChangesTest {
public void isReviewed() throws Exception { public void isReviewed() throws Exception {
clockStepMs = MILLISECONDS.convert(2, MINUTES); clockStepMs = MILLISECONDS.convert(2, MINUTES);
TestRepository<Repo> repo = createProject("repo"); TestRepository<Repo> repo = createProject("repo");
Change change1 = newChange(repo, null, null, null, null).insert(); Change change1 = insert(newChange(repo, null, null, null, null));
Change change2 = newChange(repo, null, null, null, null).insert(); Change change2 = insert(newChange(repo, null, null, null, null));
Change change3 = newChange(repo, null, null, null, null).insert(); Change change3 = insert(newChange(repo, null, null, null, null));
gApi.changes() gApi.changes()
.id(change1.getId().get()) .id(change1.getId().get())