Search in sources :

Example 41 with CodeReviewCommit

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();
}
Also used : EMPTY_COMMIT(com.google.gerrit.server.submit.CommitMergeStatus.EMPTY_COMMIT) PermissionBackendException(com.google.gerrit.server.permissions.PermissionBackendException) RevCommit(org.eclipse.jgit.revwalk.RevCommit) RepoContext(com.google.gerrit.server.update.RepoContext) BadRequestException(com.google.gerrit.extensions.restapi.BadRequestException) RebaseChangeOp(com.google.gerrit.server.change.RebaseChangeOp) MergeConflictException(com.google.gerrit.extensions.restapi.MergeConflictException) ImmutableList(com.google.common.collect.ImmutableList) InvalidChangeOperationException(com.google.gerrit.server.project.InvalidChangeOperationException) PostUpdateContext(com.google.gerrit.server.update.PostUpdateContext) NoSuchChangeException(com.google.gerrit.server.project.NoSuchChangeException) PatchSet(com.google.gerrit.entities.PatchSet) RestApiException(com.google.gerrit.extensions.restapi.RestApiException) ChangeUtil(com.google.gerrit.server.ChangeUtil) MergeTip(com.google.gerrit.server.git.MergeTip) ChangeContext(com.google.gerrit.server.update.ChangeContext) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) StorageException(com.google.gerrit.exceptions.StorageException) Collection(java.util.Collection) IOException(java.io.IOException) CodeReviewCommit(com.google.gerrit.server.git.CodeReviewCommit) SKIPPED_IDENTICAL_TREE(com.google.gerrit.server.submit.CommitMergeStatus.SKIPPED_IDENTICAL_TREE) Preconditions.checkState(com.google.common.base.Preconditions.checkState) ObjectId(org.eclipse.jgit.lib.ObjectId) PersonIdent(org.eclipse.jgit.lib.PersonIdent) List(java.util.List) ResourceConflictException(com.google.gerrit.extensions.restapi.ResourceConflictException) BooleanProjectConfig(com.google.gerrit.entities.BooleanProjectConfig) Repository(org.eclipse.jgit.lib.Repository) ImmutableList(com.google.common.collect.ImmutableList) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) IOException(java.io.IOException) CodeReviewCommit(com.google.gerrit.server.git.CodeReviewCommit) StorageException(com.google.gerrit.exceptions.StorageException)

Example 42 with CodeReviewCommit

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;
}
Also used : ObjectId(org.eclipse.jgit.lib.ObjectId) ArrayList(java.util.ArrayList) CodeReviewRevWalk(com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk) PatchSet(com.google.gerrit.entities.PatchSet) IncorrectObjectTypeException(org.eclipse.jgit.errors.IncorrectObjectTypeException) Change(com.google.gerrit.entities.Change) CodeReviewCommit(com.google.gerrit.server.git.CodeReviewCommit) MissingObjectException(org.eclipse.jgit.errors.MissingObjectException) HashMap(java.util.HashMap) Map(java.util.Map)

Example 43 with CodeReviewCommit

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;
}
Also used : PatchSet(com.google.gerrit.entities.PatchSet) Change(com.google.gerrit.entities.Change) CodeReviewCommit(com.google.gerrit.server.git.CodeReviewCommit) StorageException(com.google.gerrit.exceptions.StorageException)

Example 44 with CodeReviewCommit

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);
}
Also used : ReceiveCommand(org.eclipse.jgit.transport.ReceiveCommand) CodeReviewCommit(com.google.gerrit.server.git.CodeReviewCommit)

Example 45 with CodeReviewCommit

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);
}
Also used : BranchNameKey(com.google.gerrit.entities.BranchNameKey) AnyObjectId(org.eclipse.jgit.lib.AnyObjectId) ObjectId(org.eclipse.jgit.lib.ObjectId) Config(org.eclipse.jgit.lib.Config) SubmoduleSubscription(com.google.gerrit.entities.SubmoduleSubscription) CodeReviewCommit(com.google.gerrit.server.git.CodeReviewCommit) RevCommit(org.eclipse.jgit.revwalk.RevCommit) Test(org.junit.Test)

Aggregations

CodeReviewCommit (com.google.gerrit.server.git.CodeReviewCommit)45 ArrayList (java.util.ArrayList)13 ObjectId (org.eclipse.jgit.lib.ObjectId)11 RevCommit (org.eclipse.jgit.revwalk.RevCommit)11 IOException (java.io.IOException)10 StorageException (com.google.gerrit.exceptions.StorageException)9 PersonIdent (org.eclipse.jgit.lib.PersonIdent)9 BranchNameKey (com.google.gerrit.entities.BranchNameKey)7 Change (com.google.gerrit.entities.Change)7 PatchSet (com.google.gerrit.entities.PatchSet)7 CodeReviewRevWalk (com.google.gerrit.server.git.CodeReviewCommit.CodeReviewRevWalk)7 ImmutableList (com.google.common.collect.ImmutableList)6 Repository (org.eclipse.jgit.lib.Repository)6 GerritPersonIdent (com.google.gerrit.server.GerritPersonIdent)5 IdentifiedUser (com.google.gerrit.server.IdentifiedUser)5 ProjectState (com.google.gerrit.server.project.ProjectState)5 OpenRepo (com.google.gerrit.server.submit.MergeOpRepoManager.OpenRepo)5 SubmoduleSubscription (com.google.gerrit.entities.SubmoduleSubscription)4 BadRequestException (com.google.gerrit.extensions.restapi.BadRequestException)4 MergeConflictException (com.google.gerrit.extensions.restapi.MergeConflictException)4