use of com.google.gerrit.server.git.CodeReviewCommit in project gerrit by GerritCodeReview.
the class RebaseSubmitStrategy method buildOps.
@Override
public ImmutableList<SubmitStrategyOp> buildOps(Collection<CodeReviewCommit> toMerge) {
List<CodeReviewCommit> sorted;
try {
sorted = args.rebaseSorter.sort(toMerge);
} catch (IOException | StorageException e) {
throw new StorageException("Commit sorting failed", e);
}
// We cannot rebase merge commits. This is why we integrate merge changes into the target branch
// the same way as if MERGE_IF_NECESSARY was the submit strategy. This means if needed we create
// a merge commit that integrates the merge change into the target branch.
// If we integrate a change series that consists out of a normal change and a merge change,
// where the merge change depends on the normal change, we must skip rebasing the normal change,
// because it already gets integrated by merging the merge change. If the rebasing of the normal
// change is not skipped, it would appear twice in the history after the submit is done (once
// through its rebased commit, and once through its original commit which is a parent of the
// merge change that was merged into the target branch. To skip the rebasing of the normal
// change, we call MergeUtil#reduceToMinimalMerge, as it excludes commits which will be
// implicitly integrated by merging the series. Then we use the MergeIfNecessaryOp to integrate
// the whole series.
// If on the other hand, we integrate a change series that consists out of a merge change and a
// normal change, where the normal change depends on the merge change, we can first integrate
// the merge change by a merge and then integrate the normal change by a rebase. In this case we
// do not want to call MergeUtil#reduceToMinimalMerge as we are not intending to integrate the
// whole series by a merge, but rather do the integration of the commits one by one.
boolean foundNonMerge = false;
for (CodeReviewCommit c : sorted) {
if (c.getParentCount() > 1) {
if (!foundNonMerge) {
// required to merge the whole series at once
continue;
}
// found a merge commit that depends on a normal change, this means we are required to merge
// the whole series at once
sorted = args.mergeUtil.reduceToMinimalMerge(args.mergeSorter, sorted);
return sorted.stream().map(n -> new MergeIfNecessaryOp(n)).collect(toImmutableList());
}
foundNonMerge = true;
}
ImmutableList.Builder<SubmitStrategyOp> ops = ImmutableList.builderWithExpectedSize(sorted.size());
boolean first = true;
while (!sorted.isEmpty()) {
CodeReviewCommit n = sorted.remove(0);
if (first && args.mergeTip.getInitialTip() == null) {
// TODO(tandrii): Cherry-Pick strategy does this too, but it's wrong
// and can be fixed.
ops.add(new FastForwardOp(args, n));
} else if (n.getParentCount() == 0) {
ops.add(new RebaseRootOp(n));
} else if (n.getParentCount() == 1) {
ops.add(new RebaseOneOp(n));
} else {
ops.add(new MergeIfNecessaryOp(n));
}
first = false;
}
return ops.build();
}
use of com.google.gerrit.server.git.CodeReviewCommit in project gerrit by GerritCodeReview.
the class SubmitStrategyOp method getAlreadyMergedCommit.
private CodeReviewCommit getAlreadyMergedCommit(RepoContext ctx) throws IOException {
CodeReviewCommit tip = args.mergeTip.getInitialTip();
if (tip == null) {
return null;
}
CodeReviewRevWalk rw = (CodeReviewRevWalk) ctx.getRevWalk();
Change.Id id = getId();
String refPrefix = id.toRefPrefix();
Map<String, ObjectId> refs = ctx.getRepoView().getRefs(refPrefix);
List<CodeReviewCommit> commits = new ArrayList<>(refs.size());
for (Map.Entry<String, ObjectId> e : refs.entrySet()) {
PatchSet.Id psId = PatchSet.Id.fromRef(refPrefix + e.getKey());
if (psId == null) {
continue;
}
try {
CodeReviewCommit c = rw.parseCommit(e.getValue());
c.setPatchsetId(psId);
commits.add(c);
} catch (MissingObjectException | IncorrectObjectTypeException ex) {
// Bogus ref, can't be merged into tip so we don't care.
continue;
}
}
commits.sort(comparing((CodeReviewCommit c) -> c.getPatchsetId().get()).reversed());
CodeReviewCommit result = MergeUtil.findAnyMergedInto(rw, commits, tip);
if (result == null) {
return null;
}
// Some patch set of this change is actually merged into the target
// branch, most likely because a previous run of MergeOp failed after
// updateRepo, during updateChange.
//
// Do the best we can to clean this up: mark the change as merged and set
// the current patch set. Don't touch the dest branch at all. This can
// lead to some odd situations like another change in the set merging in
// a different patch set of this change, but that's unavoidable at this
// point. At least the change will end up in the right state.
//
// TODO(dborowitz): Consider deleting later junk patch set refs. They
// presumably don't have PatchSets pointing to them.
rw.parseBody(result);
result.add(args.canMergeFlag);
PatchSet.Id psId = result.getPatchsetId();
result.copyFrom(toMerge);
// Got overwriten by copyFrom.
result.setPatchsetId(psId);
result.setStatusCode(CommitMergeStatus.ALREADY_MERGED);
args.commitStatus.put(result);
return result;
}
use of com.google.gerrit.server.git.CodeReviewCommit in project gerrit by GerritCodeReview.
the class SubmitStrategyOp method updateChange.
@Override
public final boolean updateChange(ChangeContext ctx) throws Exception {
logger.atFine().log("%s#updateChange for change %s", getClass().getSimpleName(), toMerge.change().getId());
// Update change and notes from ctx.
toMerge.setNotes(ctx.getNotes());
if (ctx.getChange().isMerged()) {
// repo failed with lock failure.
if (alreadyMergedCommit == null) {
logger.atFine().log("Change is already merged according to its status, but we were unable to find it" + " merged into the current tip (%s)", args.mergeTip.getCurrentTip().name());
} else {
logger.atFine().log("Change is already merged");
}
changeAlreadyMerged = true;
return false;
}
if (alreadyMergedCommit != null) {
alreadyMergedCommit.setNotes(ctx.getNotes());
mergedPatchSet = getOrCreateAlreadyMergedPatchSet(ctx);
} else {
PatchSet newPatchSet = updateChangeImpl(ctx);
PatchSet.Id oldPsId = requireNonNull(toMerge.getPatchsetId());
PatchSet.Id newPsId = requireNonNull(ctx.getChange().currentPatchSetId());
if (newPatchSet == null) {
checkState(oldPsId.equals(newPsId), "patch set advanced from %s to %s but updateChangeImpl did not" + " return new patch set instance", oldPsId, newPsId);
// Ok to use stale notes to get the old patch set, which didn't change
// during the submit strategy.
mergedPatchSet = requireNonNull(args.psUtil.get(ctx.getNotes(), oldPsId), () -> String.format("missing old patch set %s", oldPsId));
} else {
PatchSet.Id n = newPatchSet.id();
checkState(!n.equals(oldPsId) && n.equals(newPsId), "current patch was %s and is now %s, but updateChangeImpl returned" + " new patch set instance at %s", oldPsId, newPsId, n);
mergedPatchSet = newPatchSet;
}
}
Change c = ctx.getChange();
Change.Id id = c.getId();
CodeReviewCommit commit = args.commitStatus.get(id);
requireNonNull(commit, () -> String.format("missing commit for change %s", id));
CommitMergeStatus s = commit.getStatusCode();
requireNonNull(s, () -> String.format("status not set for change %s; expected to previously fail fast", id));
logger.atFine().log("Status of change %s (%s) on %s: %s", id, commit.name(), c.getDest(), s);
setApproval(ctx, args.caller);
mergeResultRev = alreadyMergedCommit == null ? args.mergeTip.getMergeResults().get(commit) : // ChangeMergedEvent in the fixup case, but we'll just live with that.
alreadyMergedCommit;
try {
setMerged(ctx, commit, message(ctx, commit, s));
} catch (StorageException err) {
String msg = "Error updating change status for " + id;
logger.atSevere().withCause(err).log("%s", msg);
args.commitStatus.logProblem(id, msg);
// It's possible this happened before updating anything in the db, but
// it's hard to know for sure, so just return true below to be safe.
}
updatedChange = c;
return true;
}
use of com.google.gerrit.server.git.CodeReviewCommit in project gerrit by GerritCodeReview.
the class SubmitStrategyOp method updateRepo.
@Override
public final void updateRepo(RepoContext ctx) throws Exception {
logger.atFine().log("%s#updateRepo for change %s", getClass().getSimpleName(), toMerge.change().getId());
checkState(ctx.getRevWalk() == args.rw, "SubmitStrategyOp requires callers to call BatchUpdate#setRepository with exactly the same" + " CodeReviewRevWalk instance from the SubmitStrategy.Arguments: %s != %s", ctx.getRevWalk(), args.rw);
// Run the submit strategy implementation and record the merge tip state so
// we can create the ref update.
CodeReviewCommit tipBefore = args.mergeTip.getCurrentTip();
alreadyMergedCommit = getAlreadyMergedCommit(ctx);
if (alreadyMergedCommit == null) {
updateRepoImpl(ctx);
} else {
logger.atFine().log("Already merged as %s", alreadyMergedCommit.name());
}
CodeReviewCommit tipAfter = args.mergeTip.getCurrentTip();
if (Objects.equals(tipBefore, tipAfter)) {
logger.atFine().log("Did not move tip");
return;
} else if (tipAfter == null) {
logger.atFine().log("No merge tip, no update to perform");
return;
}
logger.atFine().log("Moved tip from %s to %s", tipBefore, tipAfter);
checkProjectConfig(ctx, tipAfter);
// Needed by postUpdate, at which point mergeTip will have advanced further,
// so it's easier to just snapshot the command.
command = new ReceiveCommand(firstNonNull(tipBefore, ObjectId.zeroId()), tipAfter, getDest().branch());
ctx.addRefUpdate(command);
args.submoduleCommits.addBranchTip(getDest(), tipAfter);
}
use of com.google.gerrit.server.git.CodeReviewCommit in project gerrit by GerritCodeReview.
the class SubmoduleCommitsTest method amendGitlinksCommit_subprojectMoved.
@Test
public void amendGitlinksCommit_subprojectMoved() throws Exception {
createRepo(subProject, MASTER);
createRepo(superProject, MASTER);
when(mockProjectCache.get(any())).thenReturn(Optional.of(mockProjectState));
mergeOpRepoManager = new MergeOpRepoManager(repoManager, mockProjectCache, null, null);
ObjectId subprojectCommit = getTip(subProject, MASTER);
CodeReviewCommit superprojectTip = directUpdateSubmodule(superProject, MASTER, Project.nameKey("dir-x"), subprojectCommit);
assertThat(readGitLink(superProject, superprojectTip, "dir-x")).isEqualTo(subprojectCommit);
RevCommit newSubprojectCommit = addCommit(subProject, MASTER);
BranchNameKey superBranch = BranchNameKey.create(superProject, MASTER);
BranchNameKey subBranch = BranchNameKey.create(subProject, MASTER);
SubmoduleSubscription ss = new SubmoduleSubscription(superBranch, subBranch, "dir-x");
SubmoduleCommits helper = new SubmoduleCommits(mergeOpRepoManager, ident, new Config());
CodeReviewCommit amendedCommit = helper.amendGitlinksCommit(BranchNameKey.create(superProject, MASTER), superprojectTip, ImmutableList.of(ss));
assertThat(amendedCommit.getParent(0)).isEqualTo(superprojectTip.getParent(0));
assertThat(readGitLink(superProject, amendedCommit, "dir-x")).isEqualTo(newSubprojectCommit);
}
Aggregations