use of com.google.gerrit.server.update.BatchUpdate in project gerrit by GerritCodeReview.
the class Move method applyImpl.
@Override
protected ChangeInfo applyImpl(BatchUpdate.Factory updateFactory, ChangeResource rsrc, MoveInput input) throws RestApiException, OrmException, UpdateException, PermissionBackendException {
Change change = rsrc.getChange();
Project.NameKey project = rsrc.getProject();
IdentifiedUser caller = rsrc.getUser();
input.destinationBranch = RefNames.fullName(input.destinationBranch);
if (change.getStatus().isClosed()) {
throw new ResourceConflictException("Change is " + ChangeUtil.status(change));
}
Branch.NameKey newDest = new Branch.NameKey(project, input.destinationBranch);
if (change.getDest().equals(newDest)) {
throw new ResourceConflictException("Change is already destined for the specified branch");
}
// Move requires abandoning this change, and creating a new change.
try {
rsrc.permissions().database(dbProvider).check(ChangePermission.ABANDON);
permissionBackend.user(caller).database(dbProvider).ref(newDest).check(RefPermission.CREATE_CHANGE);
} catch (AuthException denied) {
throw new AuthException("move not permitted", denied);
}
try (BatchUpdate u = updateFactory.create(dbProvider.get(), project, caller, TimeUtil.nowTs())) {
u.addOp(change.getId(), new Op(input));
u.execute();
}
return json.noOptions().format(project, rsrc.getId());
}
use of com.google.gerrit.server.update.BatchUpdate in project gerrit by GerritCodeReview.
the class MailProcessor method processImpl.
private void processImpl(BatchUpdate.Factory buf, MailMessage message) throws OrmException, UpdateException, RestApiException {
for (DynamicMap.Entry<MailFilter> filter : mailFilters) {
if (!filter.getProvider().get().shouldProcessMessage(message)) {
log.warn(String.format("Message %s filtered by plugin %s %s. Will delete message.", message.id(), filter.getPluginName(), filter.getExportName()));
return;
}
}
MailMetadata metadata = MetadataParser.parse(message);
if (!metadata.hasRequiredFields()) {
log.error(String.format("Message %s is missing required metadata, have %s. Will delete message.", message.id(), metadata));
return;
}
Set<Account.Id> accounts = accountByEmailCache.get(metadata.author);
if (accounts.size() != 1) {
log.error(String.format("Address %s could not be matched to a unique account. It was matched to %s. Will delete message.", metadata.author, accounts));
return;
}
Account.Id account = accounts.iterator().next();
if (!accountCache.get(account).getAccount().isActive()) {
log.warn(String.format("Mail: Account %s is inactive. Will delete message.", account));
return;
}
try (ManualRequestContext ctx = oneOffRequestContext.openAs(account)) {
List<ChangeData> changeDataList = queryProvider.get().byKey(Change.Key.parse(metadata.changeId));
if (changeDataList.size() != 1) {
log.error(String.format("Message %s references unique change %s, but there are %d matching changes in the index. Will delete message.", message.id(), metadata.changeId, changeDataList.size()));
return;
}
ChangeData cd = changeDataList.get(0);
if (existingMessageIds(cd).contains(message.id())) {
log.info("Message " + message.id() + " was already processed. Will delete message.");
return;
}
// Get all comments; filter and sort them to get the original list of
// comments from the outbound email.
// TODO(hiesel) Also filter by original comment author.
Collection<Comment> comments = cd.publishedComments().stream().filter(c -> (c.writtenOn.getTime() / 1000) == (metadata.timestamp.getTime() / 1000)).sorted(CommentsUtil.COMMENT_ORDER).collect(toList());
Project.NameKey project = cd.project();
String changeUrl = canonicalUrl.get() + "#/c/" + cd.getId().get();
List<MailComment> parsedComments;
if (useHtmlParser(message)) {
parsedComments = HtmlParser.parse(message, comments, changeUrl);
} else {
parsedComments = TextParser.parse(message, comments, changeUrl);
}
if (parsedComments.isEmpty()) {
log.warn("Could not parse any comments from " + message.id() + ". Will delete message.");
return;
}
Op o = new Op(new PatchSet.Id(cd.getId(), metadata.patchSet), parsedComments, message.id());
BatchUpdate batchUpdate = buf.create(cd.db(), project, ctx.getUser(), TimeUtil.nowTs());
batchUpdate.addOp(cd.getId(), o);
batchUpdate.execute();
}
}
use of com.google.gerrit.server.update.BatchUpdate in project gerrit by GerritCodeReview.
the class ReceiveCommits method insertChangesAndPatchSets.
private void insertChangesAndPatchSets() {
ReceiveCommand magicBranchCmd = magicBranch != null ? magicBranch.cmd : null;
if (magicBranchCmd != null && magicBranchCmd.getResult() != NOT_ATTEMPTED) {
logWarn(String.format("Skipping change updates on %s because ref update failed: %s %s", project.getName(), magicBranchCmd.getResult(), Strings.nullToEmpty(magicBranchCmd.getMessage())));
return;
}
try (BatchUpdate bu = batchUpdateFactory.create(db, project.getNameKey(), user.materializedCopy(), TimeUtil.nowTs());
ObjectInserter ins = repo.newObjectInserter();
ObjectReader reader = ins.newReader();
RevWalk rw = new RevWalk(reader)) {
bu.setRepository(repo, rw, ins).updateChangesInParallel();
bu.setRequestId(receiveId);
bu.setRefLogMessage("push");
logDebug("Adding {} replace requests", newChanges.size());
for (ReplaceRequest replace : replaceByChange.values()) {
replace.addOps(bu, replaceProgress);
}
logDebug("Adding {} create requests", newChanges.size());
for (CreateRequest create : newChanges) {
create.addOps(bu);
}
logDebug("Adding {} group update requests", newChanges.size());
updateGroups.forEach(r -> r.addOps(bu));
logDebug("Adding {} additional ref updates", actualCommands.size());
actualCommands.forEach(c -> bu.addRepoOnlyOp(new UpdateOneRefOp(c)));
logDebug("Executing batch");
try {
bu.execute();
} catch (UpdateException e) {
throw INSERT_EXCEPTION.apply(e);
}
if (magicBranchCmd != null) {
magicBranchCmd.setResult(OK);
}
for (ReplaceRequest replace : replaceByChange.values()) {
String rejectMessage = replace.getRejectMessage();
if (rejectMessage == null) {
if (replace.inputCommand.getResult() == NOT_ATTEMPTED) {
// Not necessarily the magic branch, so need to set OK on the original value.
replace.inputCommand.setResult(OK);
}
} else {
logDebug("Rejecting due to message from ReplaceOp");
reject(replace.inputCommand, rejectMessage);
}
}
} catch (ResourceConflictException e) {
addMessage(e.getMessage());
reject(magicBranchCmd, "conflict");
} catch (RestApiException | IOException err) {
logError("Can't insert change/patch set for " + project.getName(), err);
reject(magicBranchCmd, "internal server error: " + err.getMessage());
}
if (magicBranch != null && magicBranch.submit) {
try {
submit(newChanges, replaceByChange.values());
} catch (ResourceConflictException e) {
addMessage(e.getMessage());
reject(magicBranchCmd, "conflict");
} catch (RestApiException | OrmException e) {
logError("Error submitting changes to " + project.getName(), e);
reject(magicBranchCmd, "error during submit");
}
}
}
use of com.google.gerrit.server.update.BatchUpdate in project gerrit by GerritCodeReview.
the class ReceiveCommits method autoCloseChanges.
private void autoCloseChanges(final ReceiveCommand cmd) {
logDebug("Starting auto-closing of changes");
String refName = cmd.getRefName();
checkState(!MagicBranch.isMagicBranch(refName), "shouldn't be auto-closing changes on magic branch %s", refName);
// insertChangesAndPatchSets.
try (BatchUpdate bu = batchUpdateFactory.create(db, projectControl.getProject().getNameKey(), user, TimeUtil.nowTs());
ObjectInserter ins = repo.newObjectInserter();
ObjectReader reader = ins.newReader();
RevWalk rw = new RevWalk(reader)) {
bu.setRepository(repo, rw, ins).updateChangesInParallel();
bu.setRequestId(receiveId);
// TODO(dborowitz): Teach BatchUpdate to ignore missing changes.
RevCommit newTip = rw.parseCommit(cmd.getNewId());
Branch.NameKey branch = new Branch.NameKey(project.getNameKey(), refName);
rw.reset();
rw.markStart(newTip);
if (!ObjectId.zeroId().equals(cmd.getOldId())) {
rw.markUninteresting(rw.parseCommit(cmd.getOldId()));
}
ListMultimap<ObjectId, Ref> byCommit = changeRefsById();
Map<Change.Key, ChangeNotes> byKey = null;
List<ReplaceRequest> replaceAndClose = new ArrayList<>();
int existingPatchSets = 0;
int newPatchSets = 0;
COMMIT: for (RevCommit c; (c = rw.next()) != null; ) {
rw.parseBody(c);
for (Ref ref : byCommit.get(c.copy())) {
existingPatchSets++;
PatchSet.Id psId = PatchSet.Id.fromRef(ref.getName());
bu.addOp(psId.getParentKey(), mergedByPushOpFactory.create(requestScopePropagator, psId, refName));
continue COMMIT;
}
for (String changeId : c.getFooterLines(CHANGE_ID)) {
if (byKey == null) {
byKey = openChangesByBranch(branch);
}
ChangeNotes onto = byKey.get(new Change.Key(changeId.trim()));
if (onto != null) {
newPatchSets++;
// Hold onto this until we're done with the walk, as the call to
// req.validate below calls isMergedInto which resets the walk.
ReplaceRequest req = new ReplaceRequest(onto.getChangeId(), c, cmd, false);
req.notes = onto;
replaceAndClose.add(req);
continue COMMIT;
}
}
}
for (final ReplaceRequest req : replaceAndClose) {
Change.Id id = req.notes.getChangeId();
if (!req.validate(true)) {
logDebug("Not closing {} because validation failed", id);
continue;
}
req.addOps(bu, null);
bu.addOp(id, mergedByPushOpFactory.create(requestScopePropagator, req.psId, refName).setPatchSetProvider(new Provider<PatchSet>() {
@Override
public PatchSet get() {
return req.replaceOp.getPatchSet();
}
}));
bu.addOp(id, new ChangeProgressOp(closeProgress));
}
logDebug("Auto-closing {} changes with existing patch sets and {} with new patch sets", existingPatchSets, newPatchSets);
bu.execute();
} catch (RestApiException e) {
logError("Can't insert patchset", e);
} catch (IOException | OrmException | UpdateException | PermissionBackendException e) {
logError("Can't scan for changes to close", e);
}
}
Aggregations