use of com.google.gerrit.server.logging.TraceContext.TraceTimer in project gerrit by GerritCodeReview.
the class CommentPorter method loadMappings.
private ImmutableSet<Mapping> loadMappings(Project.NameKey project, Change change, PatchSet originalPatchset, PatchSet targetPatchset, short side) throws DiffNotAvailableException {
try (TraceTimer ignored = TraceContext.newTimer("Loading commit mappings", Metadata.builder().projectName(project.get()).changeId(change.getChangeId()).patchSetId(originalPatchset.number()).build())) {
ObjectId originalCommit = determineCommitId(change, originalPatchset, side);
ObjectId targetCommit = determineCommitId(change, targetPatchset, side);
return loadCommitMappings(project, originalCommit, targetCommit);
}
}
use of com.google.gerrit.server.logging.TraceContext.TraceTimer in project gerrit by GerritCodeReview.
the class CommentPorter method portComments.
/**
* Ports the given comments to the target patchset.
*
* <p>Not all given comments are ported. Only those fulfilling some criteria (e.g. before target
* patchset) are considered eligible for porting.
*
* <p>The returned comments represent the ported version. They don't bear any indication to which
* patchset they were ported. This is intentional as the target patchset should be obvious from
* the API or the used REST resources. The returned comments still have the patchset field filled.
* It contains the reference to the patchset on which the comment was originally left. That
* patchset number can vary among the returned comments as all comments before the target patchset
* are potentially eligible for porting.
*
* <p>The number of returned comments can be smaller (-> only eligible ones are ported!) or larger
* compared to the provided comments. The latter happens when files appear as copied in the target
* patchset. In such a situation, the same comment UUID will occur more than once in the returned
* comments.
*
* @param changeNotes the {@link ChangeNotes} of the change to which the comments belong
* @param targetPatchset the patchset to which the comments should be ported
* @param comments the original comments
* @param filters additional filters to apply to the comments before porting. Only the remaining
* comments will be ported.
* @return the ported comments, in no particular order
*/
public ImmutableList<HumanComment> portComments(ChangeNotes changeNotes, PatchSet targetPatchset, List<HumanComment> comments, List<HumanCommentFilter> filters) {
try (TraceTimer ignored = TraceContext.newTimer("Porting comments", Metadata.builder().patchSetId(targetPatchset.number()).build())) {
ImmutableList<HumanCommentFilter> allFilters = addDefaultFilters(filters, targetPatchset);
ImmutableList<HumanComment> relevantComments = filter(comments, allFilters);
return port(changeNotes, targetPatchset, relevantComments);
}
}
use of com.google.gerrit.server.logging.TraceContext.TraceTimer in project gerrit by GerritCodeReview.
the class ReceiveCommits method validateRegularPushCommits.
/**
* Validates the commits that a regular push brings in.
*
* <p>On validation failure, the command is rejected.
*/
private void validateRegularPushCommits(BranchNameKey branch, ReceiveCommand cmd) throws PermissionBackendException {
try (TraceTimer traceTimer = newTimer("validateRegularPushCommits", Metadata.builder().branchName(branch.branch()))) {
boolean skipValidation = !RefNames.REFS_CONFIG.equals(cmd.getRefName()) && !(MagicBranch.isMagicBranch(cmd.getRefName()) || NEW_PATCHSET_PATTERN.matcher(cmd.getRefName()).matches()) && pushOptions.containsKey(PUSH_OPTION_SKIP_VALIDATION);
if (skipValidation) {
if (projectState.is(BooleanProjectConfig.USE_SIGNED_OFF_BY)) {
reject(cmd, "requireSignedOffBy prevents option " + PUSH_OPTION_SKIP_VALIDATION);
return;
}
Optional<AuthException> err = checkRefPermission(permissions.ref(branch.branch()), RefPermission.SKIP_VALIDATION);
if (err.isPresent()) {
rejectProhibited(cmd, err.get());
return;
}
if (!Iterables.isEmpty(rejectCommits)) {
reject(cmd, "reject-commits prevents " + PUSH_OPTION_SKIP_VALIDATION);
}
}
BranchCommitValidator validator = commitValidatorFactory.create(projectState, branch, user);
RevWalk walk = receivePack.getRevWalk();
walk.reset();
walk.sort(RevSort.NONE);
try {
RevObject parsedObject = walk.parseAny(cmd.getNewId());
if (!(parsedObject instanceof RevCommit)) {
return;
}
walk.markStart((RevCommit) parsedObject);
markHeadsAsUninteresting(walk, cmd.getRefName());
int limit = receiveConfig.maxBatchCommits;
int n = 0;
for (RevCommit c; (c = walk.next()) != null; ) {
// we don't need to check the commit limit.
if (++n > limit && !skipValidation) {
logger.atFine().log("Number of new commits exceeds limit of %d", limit);
reject(cmd, String.format("more than %d commits, and %s not set", limit, PUSH_OPTION_SKIP_VALIDATION));
return;
}
if (!receivePackRefCache.patchSetIdsFromObjectId(c).isEmpty()) {
continue;
}
BranchCommitValidator.Result validationResult = validator.validateCommit(repo, walk.getObjectReader(), cmd, c, ImmutableListMultimap.copyOf(pushOptions), false, rejectCommits, null, skipValidation);
messages.addAll(validationResult.messages());
if (!validationResult.isValid()) {
break;
}
}
logger.atFine().log("Validated %d new commits", n);
} catch (IOException err) {
cmd.setResult(REJECTED_MISSING_OBJECT);
logger.atSevere().withCause(err).log("Invalid pack upload; one or more objects weren't sent");
}
}
}
use of com.google.gerrit.server.logging.TraceContext.TraceTimer in project gerrit by GerritCodeReview.
the class ReceiveCommits method autoCloseChanges.
private void autoCloseChanges(ReceiveCommand cmd, Task progress) {
try (TraceTimer traceTimer = newTimer("autoCloseChanges")) {
logger.atFine().log("Starting auto-closing of changes");
String refName = cmd.getRefName();
Set<Change.Id> ids = new HashSet<>();
// handleRegularCommands
try {
retryHelper.changeUpdate("autoCloseChanges", updateFactory -> {
try (BatchUpdate bu = updateFactory.create(projectState.getNameKey(), user, TimeUtil.now());
ObjectInserter ins = repo.newObjectInserter();
ObjectReader reader = ins.newReader();
RevWalk rw = new RevWalk(reader)) {
if (ObjectId.zeroId().equals(cmd.getOldId())) {
// potentially expensive computation that loop over all commits.
return null;
}
bu.setRepository(repo, rw, ins);
// TODO(dborowitz): Teach BatchUpdate to ignore missing changes.
RevCommit newTip = rw.parseCommit(cmd.getNewId());
BranchNameKey branch = BranchNameKey.create(project.getNameKey(), refName);
rw.reset();
rw.sort(RevSort.REVERSE);
rw.markStart(newTip);
rw.markUninteresting(rw.parseCommit(cmd.getOldId()));
Map<Change.Key, ChangeNotes> byKey = null;
List<ReplaceRequest> replaceAndClose = new ArrayList<>();
int existingPatchSets = 0;
int newPatchSets = 0;
SubmissionId submissionId = null;
COMMIT: for (RevCommit c; (c = rw.next()) != null; ) {
rw.parseBody(c);
// refs pointing to this commit.
for (PatchSet.Id psId : receivePackRefCache.patchSetIdsFromObjectId(c.copy())) {
Optional<ChangeNotes> notes = getChangeNotes(psId.changeId());
if (notes.isPresent() && notes.get().getChange().getDest().equals(branch)) {
if (submissionId == null) {
submissionId = new SubmissionId(notes.get().getChange());
}
existingPatchSets++;
bu.addOp(notes.get().getChangeId(), setPrivateOpFactory.create(false, null));
bu.addOp(psId.changeId(), mergedByPushOpFactory.create(requestScopePropagator, psId, submissionId, refName, newTip.getId().getName()));
continue COMMIT;
}
}
for (String changeId : ChangeUtil.getChangeIdsFromFooter(c, urlFormatter.get())) {
if (byKey == null) {
byKey = retryHelper.changeIndexQuery("queryOpenChangesByKeyByBranch", q -> openChangesByKeyByBranch(q, branch)).call();
}
ChangeNotes onto = byKey.get(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 (ReplaceRequest req : replaceAndClose) {
Change.Id id = req.notes.getChangeId();
if (!req.validateNewPatchSetForAutoClose()) {
logger.atFine().log("Not closing %s because validation failed", id);
continue;
}
if (submissionId == null) {
submissionId = new SubmissionId(req.notes.getChange());
}
req.addOps(bu, null);
bu.addOp(id, setPrivateOpFactory.create(false, null));
bu.addOp(id, mergedByPushOpFactory.create(requestScopePropagator, req.psId, submissionId, refName, newTip.getId().getName()).setPatchSetProvider(req.replaceOp::getPatchSet));
bu.addOp(id, new ChangeProgressOp(progress));
ids.add(id);
}
logger.atFine().log("Auto-closing %d changes with existing patch sets and %d with new patch" + " sets", existingPatchSets, newPatchSets);
bu.execute();
} catch (IOException | StorageException | PermissionBackendException e) {
throw new StorageException("Failed to auto-close changes", e);
}
// If we are here, we didn't throw UpdateException. Record the result.
// The ordering is indeterminate due to the HashSet; unfortunately, Change.Id
// doesn't
// fit into TreeSet.
ids.stream().forEach(id -> result.addChange(ReceiveCommitsResult.ChangeStatus.AUTOCLOSED, id));
return null;
}).defaultTimeoutMultiplier(5).call();
} catch (RestApiException e) {
logger.atSevere().withCause(e).log("Can't insert patchset");
} catch (UpdateException e) {
logger.atSevere().withCause(e).log("Failed to auto-close changes");
} finally {
logger.atFine().log("Done auto-closing changes");
}
}
}
use of com.google.gerrit.server.logging.TraceContext.TraceTimer in project gerrit by GerritCodeReview.
the class ReceiveCommits method insertChangesAndPatchSets.
private void insertChangesAndPatchSets(ImmutableList<CreateRequest> newChanges, Task replaceProgress) {
try (TraceTimer traceTimer = newTimer("insertChangesAndPatchSets", Metadata.builder().resourceCount(newChanges.size()))) {
ReceiveCommand magicBranchCmd = magicBranch != null ? magicBranch.cmd : null;
if (magicBranchCmd != null && magicBranchCmd.getResult() != NOT_ATTEMPTED) {
logger.atWarning().log("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(project.getNameKey(), user.materializedCopy(), TimeUtil.now());
ObjectInserter ins = repo.newObjectInserter();
ObjectReader reader = ins.newReader();
RevWalk rw = new RevWalk(reader)) {
bu.setRepository(repo, rw, ins);
bu.setRefLogMessage("push");
if (magicBranch != null) {
bu.setNotify(magicBranch.getNotifyForNewChange());
}
logger.atFine().log("Adding %d replace requests", newChanges.size());
for (ReplaceRequest replace : replaceByChange.values()) {
replace.addOps(bu, replaceProgress);
if (magicBranch != null) {
bu.setNotifyHandling(replace.ontoChange, magicBranch.getNotifyHandling(replace.notes));
if (magicBranch.shouldPublishComments()) {
bu.addOp(replace.notes.getChangeId(), publishCommentsOp.create(replace.psId, project.getNameKey()));
Optional<ChangeNotes> changeNotes = getChangeNotes(replace.notes.getChangeId());
if (!changeNotes.isPresent()) {
// If not present, no need to update attention set here since this is a new change.
continue;
}
List<HumanComment> drafts = commentsUtil.draftByChangeAuthor(changeNotes.get(), user.getAccountId());
if (drafts.isEmpty()) {
// If no comments, attention set shouldn't update since the user didn't reply.
continue;
}
replyAttentionSetUpdates.processAutomaticAttentionSetRulesOnReply(bu, changeNotes.get(), isReadyForReview(changeNotes.get()), user, drafts);
}
}
}
logger.atFine().log("Adding %d create requests", newChanges.size());
for (CreateRequest create : newChanges) {
create.addOps(bu);
}
logger.atFine().log("Adding %d group update requests", newChanges.size());
updateGroups.forEach(r -> r.addOps(bu));
logger.atFine().log("Executing batch");
try {
bu.execute();
} catch (UpdateException e) {
throw asRestApiException(e);
}
replaceByChange.values().stream().forEach(req -> result.addChange(ReceiveCommitsResult.ChangeStatus.REPLACED, req.ontoChange));
newChanges.stream().forEach(req -> result.addChange(ReceiveCommitsResult.ChangeStatus.CREATED, req.changeId));
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 {
logger.atFine().log("Rejecting due to message from ReplaceOp");
reject(replace.inputCommand, rejectMessage);
}
}
} catch (ResourceConflictException e) {
addError(e.getMessage());
reject(magicBranchCmd, "conflict");
} catch (BadRequestException | UnprocessableEntityException | AuthException e) {
logger.atFine().withCause(e).log("Rejecting due to client error");
reject(magicBranchCmd, e.getMessage());
} catch (RestApiException | IOException e) {
throw new StorageException("Can't insert change/patch set for " + project.getName(), e);
}
if (magicBranch != null && magicBranch.submit) {
try {
submit(newChanges, replaceByChange.values());
} catch (ResourceConflictException e) {
addError(e.getMessage());
reject(magicBranchCmd, "conflict");
} catch (RestApiException | StorageException | UpdateException | IOException | ConfigInvalidException | PermissionBackendException e) {
logger.atSevere().withCause(e).log("Error submitting changes to %s", project.getName());
reject(magicBranchCmd, "error during submit");
}
}
}
}
Aggregations